SDL  2.0
SDL_wave.c File Reference
#include "../SDL_internal.h"
#include "SDL_log.h"
#include "SDL_hints.h"
#include "SDL_audio.h"
#include "SDL_wave.h"
+ Include dependency graph for SDL_wave.c:

Go to the source code of this file.

Data Structures

struct  ADPCM_DecoderState
 
struct  MS_ADPCM_CoeffData
 
struct  MS_ADPCM_ChannelState
 
struct  WaveExtensibleGUID
 

Macros

#define SIZE_MAX   ((size_t)-1)
 
#define INT_MAX   (SDL_MAX_SINT32)
 
#define WAVE_FORMATTAG_GUID(tag)   {(tag) & 0xff, (tag) >> 8, 0, 0, 0, 0, 16, 0, 128, 0, 0, 170, 0, 56, 155, 113}
 

Functions

static SDL_bool MultiplySize (size_t *f1, size_t f2)
 
static Sint64 WaveAdjustToFactValue (WaveFile *file, Sint64 sampleframes)
 
static int MS_ADPCM_CalculateSampleFrames (WaveFile *file, size_t datalength)
 
static int MS_ADPCM_Init (WaveFile *file, size_t datalength)
 
static Sint16 MS_ADPCM_ProcessNibble (MS_ADPCM_ChannelState *cstate, Sint32 sample1, Sint32 sample2, Uint8 nybble)
 
static int MS_ADPCM_DecodeBlockHeader (ADPCM_DecoderState *state)
 
static int MS_ADPCM_DecodeBlockData (ADPCM_DecoderState *state)
 
static int MS_ADPCM_Decode (WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
 
static int IMA_ADPCM_CalculateSampleFrames (WaveFile *file, size_t datalength)
 
static int IMA_ADPCM_Init (WaveFile *file, size_t datalength)
 
static Sint16 IMA_ADPCM_ProcessNibble (Sint8 *cindex, Sint16 lastsample, Uint8 nybble)
 
static int IMA_ADPCM_DecodeBlockHeader (ADPCM_DecoderState *state)
 
static int IMA_ADPCM_DecodeBlockData (ADPCM_DecoderState *state)
 
static int IMA_ADPCM_Decode (WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
 
static int LAW_Init (WaveFile *file, size_t datalength)
 
static int LAW_Decode (WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
 
static int PCM_Init (WaveFile *file, size_t datalength)
 
static int PCM_ConvertSint24ToSint32 (WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
 
static int PCM_Decode (WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
 
static WaveRiffSizeHint WaveGetRiffSizeHint ()
 
static WaveTruncationHint WaveGetTruncationHint ()
 
static WaveFactChunkHint WaveGetFactChunkHint ()
 
static void WaveFreeChunkData (WaveChunk *chunk)
 
static int WaveNextChunk (SDL_RWops *src, WaveChunk *chunk)
 
static int WaveReadPartialChunkData (SDL_RWops *src, WaveChunk *chunk, size_t length)
 
static int WaveReadChunkData (SDL_RWops *src, WaveChunk *chunk)
 
static Uint16 WaveGetFormatGUIDEncoding (WaveFormat *format)
 
static int WaveReadFormat (WaveFile *file)
 
static int WaveCheckFormat (WaveFile *file, size_t datalength)
 
static int WaveLoad (SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
 
SDL_AudioSpecSDL_LoadWAV_RW (SDL_RWops *src, int freesrc, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
 Load the audio data of a WAVE file into memory. More...
 
void SDL_FreeWAV (Uint8 *audio_buf)
 

Variables

static WaveExtensibleGUID extensible_guids []
 

Macro Definition Documentation

◆ INT_MAX

◆ SIZE_MAX

#define SIZE_MAX   ((size_t)-1)

◆ WAVE_FORMATTAG_GUID

#define WAVE_FORMATTAG_GUID (   tag)    {(tag) & 0xff, (tag) >> 8, 0, 0, 0, 0, 16, 0, 128, 0, 0, 170, 0, 56, 155, 113}

Definition at line 1578 of file SDL_wave.c.

Function Documentation

◆ IMA_ADPCM_CalculateSampleFrames()

static int IMA_ADPCM_CalculateSampleFrames ( WaveFile file,
size_t  datalength 
)
static

Definition at line 735 of file SDL_wave.c.

References WaveFormat::blockalign, ADPCM_DecoderState::blockheadersize, WaveFormat::channels, WaveFile::format, WaveFile::sampleframes, WaveFormat::samplesperblock, SDL_SetError, TruncDropFrame, WaveFile::trunchint, TruncStrict, TruncVeryStrict, and WaveAdjustToFactValue().

Referenced by IMA_ADPCM_Decode(), and IMA_ADPCM_Init().

736 {
737  WaveFormat *format = &file->format;
738  const size_t blockheadersize = format->channels * 4;
739  const size_t subblockframesize = format->channels * 4;
740  const size_t availableblocks = datalength / format->blockalign;
741  const size_t trailingdata = datalength % format->blockalign;
742 
743  if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
744  /* The size of the data chunk must be a multiple of the block size. */
745  if (datalength < blockheadersize || trailingdata > 0) {
746  return SDL_SetError("Truncated IMA ADPCM block");
747  }
748  }
749 
750  /* Calculate number of sample frames that will be decoded. */
751  file->sampleframes = (Uint64)availableblocks * format->samplesperblock;
752  if (trailingdata > 0) {
753  /* The last block is truncated. Check if we can get any samples out of it. */
754  if (file->trunchint == TruncDropFrame && trailingdata > blockheadersize - 2) {
755  /* The sample frame in the header of the truncated block is present.
756  * Drop incomplete sample frames.
757  */
758  size_t trailingsamples = 1;
759 
760  if (trailingdata > blockheadersize) {
761  /* More data following after the header. */
762  const size_t trailingblockdata = trailingdata - blockheadersize;
763  const size_t trailingsubblockdata = trailingblockdata % subblockframesize;
764  trailingsamples += (trailingblockdata / subblockframesize) * 8;
765  /* Due to the interleaved sub-blocks, the last 4 bytes determine
766  * how many samples of the truncated sub-block are lost.
767  */
768  if (trailingsubblockdata > subblockframesize - 4) {
769  trailingsamples += (trailingsubblockdata % 4) * 2;
770  }
771  }
772 
773  if (trailingsamples > format->samplesperblock) {
774  trailingsamples = format->samplesperblock;
775  }
776  file->sampleframes += trailingsamples;
777  }
778  }
779 
780  file->sampleframes = WaveAdjustToFactValue(file, file->sampleframes);
781  if (file->sampleframes < 0) {
782  return -1;
783  }
784 
785  return 0;
786 }
Uint16 channels
Definition: SDL_wave.h:54
uint64_t Uint64
Definition: SDL_stdinc.h:216
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
WaveTruncationHint trunchint
Definition: SDL_wave.h:145
Uint16 blockalign
Definition: SDL_wave.h:57
Sint64 sampleframes
Definition: SDL_wave.h:140
#define SDL_SetError
static Sint64 WaveAdjustToFactValue(WaveFile *file, Sint64 sampleframes)
Definition: SDL_wave.c:319
WaveFormat format
Definition: SDL_wave.h:133
Uint32 samplesperblock
Definition: SDL_wave.h:67

◆ IMA_ADPCM_Decode()

static int IMA_ADPCM_Decode ( WaveFile file,
Uint8 **  audio_buf,
Uint32 audio_len 
)
static

Definition at line 1031 of file SDL_wave.c.

References ADPCM_DecoderState::block, WaveFormat::blockalign, ADPCM_DecoderState::blockheadersize, ADPCM_DecoderState::blocksize, WaveFormat::channels, ADPCM_DecoderState::channels, WaveFile::chunk, ADPCM_DecoderState::cstate, ADPCM_DecoderState::data, WaveChunk::data, WaveFile::format, ADPCM_DecoderState::framesize, ADPCM_DecoderState::framesleft, ADPCM_DecoderState::framestotal, IMA_ADPCM_CalculateSampleFrames(), IMA_ADPCM_DecodeBlockData(), IMA_ADPCM_DecodeBlockHeader(), ADPCM_DecoderState::input, WaveChunk::length, MultiplySize(), NULL, ADPCM_DecoderState::output, ADPCM_DecoderState::pos, WaveFile::sampleframes, ADPCM_DecoderState::samplesperblock, WaveFormat::samplesperblock, SDL_calloc, SDL_free, SDL_malloc, SDL_MAX_UINT32, SDL_OutOfMemory, SDL_SetError, ADPCM_DecoderState::size, WaveChunk::size, SIZE_MAX, state, TruncDropFrame, WaveFile::trunchint, and TruncVeryStrict.

Referenced by WaveLoad().

1032 {
1033  int result;
1034  size_t bytesleft, outputsize;
1035  WaveChunk *chunk = &file->chunk;
1036  ADPCM_DecoderState state = {0};
1037  Sint8 *cstate;
1038 
1039  if (chunk->size != chunk->length) {
1040  /* Could not read everything. Recalculate number of sample frames. */
1041  if (IMA_ADPCM_CalculateSampleFrames(file, chunk->size) < 0) {
1042  return -1;
1043  }
1044  }
1045 
1046  /* Nothing to decode, nothing to return. */
1047  if (file->sampleframes == 0) {
1048  *audio_buf = NULL;
1049  *audio_len = 0;
1050  return 0;
1051  }
1052 
1053  state.channels = file->format.channels;
1054  state.blocksize = file->format.blockalign;
1055  state.blockheadersize = state.channels * 4;
1056  state.samplesperblock = file->format.samplesperblock;
1057  state.framesize = state.channels * sizeof(Sint16);
1058  state.framestotal = file->sampleframes;
1059  state.framesleft = state.framestotal;
1060 
1061  state.input.data = chunk->data;
1062  state.input.size = chunk->size;
1063  state.input.pos = 0;
1064 
1065  /* The output size in bytes. May get modified if data is truncated. */
1066  outputsize = (size_t)state.framestotal;
1067  if (MultiplySize(&outputsize, state.framesize)) {
1068  return SDL_OutOfMemory();
1069  } else if (outputsize > SDL_MAX_UINT32 || state.framestotal > SIZE_MAX) {
1070  return SDL_SetError("WAVE file too big");
1071  }
1072 
1073  state.output.pos = 0;
1074  state.output.size = outputsize / sizeof(Sint16);
1075  state.output.data = (Sint16 *)SDL_malloc(outputsize);
1076  if (state.output.data == NULL) {
1077  return SDL_OutOfMemory();
1078  }
1079 
1080  cstate = (Sint8 *)SDL_calloc(state.channels, sizeof(Sint8));
1081  if (cstate == NULL) {
1082  SDL_free(state.output.data);
1083  return SDL_OutOfMemory();
1084  }
1085  state.cstate = cstate;
1086 
1087  /* Decode block by block. A truncated block will stop the decoding. */
1088  bytesleft = state.input.size - state.input.pos;
1089  while (state.framesleft > 0 && bytesleft >= state.blockheadersize) {
1090  state.block.data = state.input.data + state.input.pos;
1091  state.block.size = bytesleft < state.blocksize ? bytesleft : state.blocksize;
1092  state.block.pos = 0;
1093 
1094  if (state.output.size - state.output.pos < (Uint64)state.framesleft * state.channels) {
1095  /* Somehow didn't allocate enough space for the output. */
1096  SDL_free(state.output.data);
1097  SDL_free(cstate);
1098  return SDL_SetError("Unexpected overflow in IMA ADPCM decoder");
1099  }
1100 
1101  /* Initialize decoder with the values from the block header. */
1102  result = IMA_ADPCM_DecodeBlockHeader(&state);
1103 
1104  /* Decode the block data. It stores the samples directly in the output. */
1105  result = IMA_ADPCM_DecodeBlockData(&state);
1106  if (result == -1) {
1107  /* Unexpected end. Stop decoding and return partial data if necessary. */
1108  if (file->trunchint == TruncVeryStrict || file->trunchint == TruncVeryStrict) {
1109  SDL_free(state.output.data);
1110  SDL_free(cstate);
1111  return SDL_SetError("Truncated data chunk");
1112  } else if (file->trunchint != TruncDropFrame) {
1113  state.output.pos -= state.output.pos % (state.samplesperblock * state.channels);
1114  }
1115  outputsize = state.output.pos * sizeof(Sint16); /* Can't overflow, is always smaller. */
1116  break;
1117  }
1118 
1119  state.input.pos += state.block.size;
1120  bytesleft = state.input.size - state.input.pos;
1121  }
1122 
1123  *audio_buf = (Uint8 *)state.output.data;
1124  *audio_len = (Uint32)outputsize;
1125 
1126  SDL_free(cstate);
1127 
1128  return 0;
1129 }
static int IMA_ADPCM_DecodeBlockHeader(ADPCM_DecoderState *state)
Definition: SDL_wave.c:921
GLuint64EXT * result
static int IMA_ADPCM_DecodeBlockData(ADPCM_DecoderState *state)
Definition: SDL_wave.c:961
Uint16 channels
Definition: SDL_wave.h:54
struct ADPCM_DecoderState::@23 output
#define SDL_MAX_UINT32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:201
struct xkb_state * state
size_t blocksize
Definition: SDL_wave.c:59
static int IMA_ADPCM_CalculateSampleFrames(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:735
uint64_t Uint64
Definition: SDL_stdinc.h:216
unsigned int size_t
static SDL_bool MultiplySize(size_t *f1, size_t f2)
Definition: SDL_wave.c:47
size_t framesize
Definition: SDL_wave.c:62
WaveTruncationHint trunchint
Definition: SDL_wave.h:145
int8_t Sint8
Definition: SDL_stdinc.h:173
uint8_t Uint8
Definition: SDL_stdinc.h:179
#define SDL_free
size_t size
Definition: SDL_wave.h:100
Uint16 blockalign
Definition: SDL_wave.h:57
Sint64 sampleframes
Definition: SDL_wave.h:140
WaveChunk chunk
Definition: SDL_wave.h:132
#define SIZE_MAX
Definition: SDL_wave.c:27
struct ADPCM_DecoderState::@22 block
Uint8 * data
Definition: SDL_wave.h:99
Sint64 framesleft
Definition: SDL_wave.c:64
struct ADPCM_DecoderState::@21 input
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_SetError
#define SDL_calloc
Sint64 framestotal
Definition: SDL_wave.c:63
size_t samplesperblock
Definition: SDL_wave.c:61
uint32_t Uint32
Definition: SDL_stdinc.h:203
size_t blockheadersize
Definition: SDL_wave.c:60
#define SDL_malloc
Uint32 length
Definition: SDL_wave.h:97
int16_t Sint16
Definition: SDL_stdinc.h:185
WaveFormat format
Definition: SDL_wave.h:133
Uint32 samplesperblock
Definition: SDL_wave.h:67

◆ IMA_ADPCM_DecodeBlockData()

static int IMA_ADPCM_DecodeBlockData ( ADPCM_DecoderState state)
static

Definition at line 961 of file SDL_wave.c.

References ADPCM_DecoderState::block, ADPCM_DecoderState::blocksize, ADPCM_DecoderState::channels, ADPCM_DecoderState::cstate, ADPCM_DecoderState::data, ADPCM_DecoderState::framesleft, i, IMA_ADPCM_ProcessNibble(), ADPCM_DecoderState::output, ADPCM_DecoderState::pos, retval, ADPCM_DecoderState::samplesperblock, and ADPCM_DecoderState::size.

Referenced by IMA_ADPCM_Decode().

962 {
963  size_t i;
964  int retval = 0;
965  const Uint32 channels = state->channels;
966  const size_t subblockframesize = channels * 4;
967  Uint64 bytesrequired;
968  Uint32 c;
969 
970  size_t blockpos = state->block.pos;
971  size_t blocksize = state->block.size;
972  size_t blockleft = blocksize - blockpos;
973 
974  size_t outpos = state->output.pos;
975 
976  Sint64 blockframesleft = state->samplesperblock - 1;
977  if (blockframesleft > state->framesleft) {
978  blockframesleft = state->framesleft;
979  }
980 
981  bytesrequired = (blockframesleft + 7) / 8 * subblockframesize;
982  if (blockleft < bytesrequired) {
983  /* Data truncated. Calculate how many samples we can get out if it. */
984  const size_t guaranteedframes = blockleft / subblockframesize;
985  const size_t remainingbytes = blockleft % subblockframesize;
986  blockframesleft = guaranteedframes;
987  if (remainingbytes > subblockframesize - 4) {
988  blockframesleft += (remainingbytes % 4) * 2;
989  }
990  /* Signal the truncation. */
991  retval = -1;
992  }
993 
994  /* Each channel has their nibbles packed into 32-bit blocks. These blocks
995  * are interleaved and make up the data part of the ADPCM block. This loop
996  * decodes the samples as they come from the input data and puts them at
997  * the appropriate places in the output data.
998  */
999  while (blockframesleft > 0) {
1000  const size_t subblocksamples = blockframesleft < 8 ? (size_t)blockframesleft : 8;
1001 
1002  for (c = 0; c < channels; c++) {
1003  Uint8 nybble = 0;
1004  /* Load previous sample which may come from the block header. */
1005  Sint16 sample = state->output.data[outpos + c - channels];
1006 
1007  for (i = 0; i < subblocksamples; i++) {
1008  if (i & 1) {
1009  nybble >>= 4;
1010  } else {
1011  nybble = state->block.data[blockpos++];
1012  }
1013 
1014  sample = IMA_ADPCM_ProcessNibble((Sint8 *)state->cstate + c, sample, nybble & 0x0f);
1015  state->output.data[outpos + c + i * channels] = sample;
1016  }
1017  }
1018 
1019  outpos += channels * subblocksamples;
1020  state->framesleft -= subblocksamples;
1021  blockframesleft -= subblocksamples;
1022  }
1023 
1024  state->block.pos = blockpos;
1025  state->output.pos = outpos;
1026 
1027  return retval;
1028 }
static Sint16 IMA_ADPCM_ProcessNibble(Sint8 *cindex, Sint16 lastsample, Uint8 nybble)
Definition: SDL_wave.c:855
struct ADPCM_DecoderState::@23 output
uint64_t Uint64
Definition: SDL_stdinc.h:216
unsigned int size_t
SDL_bool retval
int8_t Sint8
Definition: SDL_stdinc.h:173
uint8_t Uint8
Definition: SDL_stdinc.h:179
const GLubyte * c
struct ADPCM_DecoderState::@22 block
Sint64 framesleft
Definition: SDL_wave.c:64
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
size_t samplesperblock
Definition: SDL_wave.c:61
uint32_t Uint32
Definition: SDL_stdinc.h:203
int64_t Sint64
Definition: SDL_stdinc.h:210
int16_t Sint16
Definition: SDL_stdinc.h:185

◆ IMA_ADPCM_DecodeBlockHeader()

static int IMA_ADPCM_DecodeBlockHeader ( ADPCM_DecoderState state)
static

Definition at line 921 of file SDL_wave.c.

References ADPCM_DecoderState::block, ADPCM_DecoderState::blockheadersize, ADPCM_DecoderState::channels, ADPCM_DecoderState::cstate, ADPCM_DecoderState::data, ADPCM_DecoderState::framesleft, ADPCM_DecoderState::output, and ADPCM_DecoderState::pos.

Referenced by IMA_ADPCM_Decode().

922 {
923  Sint16 step;
924  Uint32 c;
925  Uint8 *cstate = state->cstate;
926 
927  for (c = 0; c < state->channels; c++) {
928  size_t o = state->block.pos + c * 4;
929 
930  /* Extract the sample from the header. */
931  Sint32 sample = state->block.data[o] | ((Sint32)state->block.data[o + 1] << 8);
932  if (sample >= 0x8000) {
933  sample -= 0x10000;
934  }
935  state->output.data[state->output.pos++] = (Sint16)sample;
936 
937  /* Channel step index. */
938  step = (Sint16)state->block.data[o + 2];
939  cstate[c] = (Sint8)(step > 0x80 ? step - 0x100 : step);
940 
941  /* Reserved byte in block header, should be 0. */
942  if (state->block.data[o + 3] != 0) {
943  /* Uh oh, corrupt data? Buggy code? */ ;
944  }
945  }
946 
947  state->block.pos += state->blockheadersize;
948 
949  /* Header provided one sample frame. */
950  state->framesleft--;
951 
952  return 0;
953 }
struct ADPCM_DecoderState::@23 output
int8_t Sint8
Definition: SDL_stdinc.h:173
uint8_t Uint8
Definition: SDL_stdinc.h:179
const GLubyte * c
int32_t Sint32
Definition: SDL_stdinc.h:197
struct ADPCM_DecoderState::@22 block
Sint64 framesleft
Definition: SDL_wave.c:64
uint32_t Uint32
Definition: SDL_stdinc.h:203
size_t blockheadersize
Definition: SDL_wave.c:60
int16_t Sint16
Definition: SDL_stdinc.h:185

◆ IMA_ADPCM_Init()

static int IMA_ADPCM_Init ( WaveFile file,
size_t  datalength 
)
static

Definition at line 789 of file SDL_wave.c.

References WaveFormat::bitspersample, WaveFormat::blockalign, ADPCM_DecoderState::blockheadersize, WaveFormat::channels, WaveFile::chunk, WaveChunk::data, EXTENSIBLE_CODE, WaveFormat::extsize, WaveFile::format, WaveFormat::formattag, IMA_ADPCM_CalculateSampleFrames(), ADPCM_DecoderState::samplesperblock, WaveFormat::samplesperblock, SDL_SetError, and WaveChunk::size.

Referenced by WaveCheckFormat().

790 {
791  WaveFormat *format = &file->format;
792  WaveChunk *chunk = &file->chunk;
793  const size_t blockheadersize = format->channels * 4;
794  const size_t blockdatasize = (size_t)format->blockalign - blockheadersize;
795  const size_t blockframebitsize = format->bitspersample * format->channels;
796  const size_t blockdatasamples = (blockdatasize * 8) / blockframebitsize;
797 
798  /* Sanity checks. */
799 
800  /* IMA ADPCAM can also have 3-bit samples, but it's not supported by SDL at this time. */
801  if (format->bitspersample == 3) {
802  return SDL_SetError("3-bit IMA ADPCM currently not supported");
803  } else if (format->bitspersample != 4) {
804  return SDL_SetError("Invalid IMA ADPCM bits per sample of %d", (int)format->bitspersample);
805  }
806 
807  /* The block size is required to be a multiple of 4 and it must be able to
808  * hold a block header.
809  */
810  if (format->blockalign < blockheadersize || format->blockalign % 4) {
811  return SDL_SetError("Invalid IMA ADPCM block size (nBlockAlign)");
812  }
813 
814  if (format->formattag == EXTENSIBLE_CODE) {
815  /* There's no specification for this, but it's basically the same
816  * format because the extensible header has wSampePerBlocks too.
817  */
818  } else {
819  /* The Standards Update says there 'should' be 2 bytes for wSamplesPerBlock. */
820  if (chunk->size >= 20 && format->extsize >= 2) {
821  format->samplesperblock = chunk->data[18] | ((Uint16)chunk->data[19] << 8);
822  }
823  }
824 
825  if (format->samplesperblock == 0) {
826  /* Field zero? No problem. We just assume the encoder packed the block.
827  * The specification calculates it this way:
828  *
829  * x = Block size (in bits) minus header size (in bits)
830  * y = Bit depth multiplied by channel count
831  * z = Number of samples per channel in header
832  * wSamplesPerBlock = x / y + z
833  */
834  format->samplesperblock = (Uint32)blockdatasamples + 1;
835  }
836 
837  /* nBlockAlign can be in conflict with wSamplesPerBlock. For example, if
838  * the number of samples doesn't fit into the block. The Standards Update
839  * also describes wSamplesPerBlock with a formula that makes it necessary
840  * to always fill the block with the maximum amount of samples, but this is
841  * not enforced here as there are no compatibility issues.
842  */
843  if (blockdatasamples < format->samplesperblock - 1) {
844  return SDL_SetError("Invalid number of samples per IMA ADPCM block (wSamplesPerBlock)");
845  }
846 
847  if (IMA_ADPCM_CalculateSampleFrames(file, datalength) < 0) {
848  return -1;
849  }
850 
851  return 0;
852 }
Uint16 extsize
Definition: SDL_wave.h:63
Uint16 bitspersample
Definition: SDL_wave.h:58
Uint16 channels
Definition: SDL_wave.h:54
uint16_t Uint16
Definition: SDL_stdinc.h:191
static int IMA_ADPCM_CalculateSampleFrames(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:735
unsigned int size_t
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
#define EXTENSIBLE_CODE
Definition: SDL_wave.h:47
size_t size
Definition: SDL_wave.h:100
Uint16 blockalign
Definition: SDL_wave.h:57
WaveChunk chunk
Definition: SDL_wave.h:132
Uint8 * data
Definition: SDL_wave.h:99
#define SDL_SetError
uint32_t Uint32
Definition: SDL_stdinc.h:203
Uint16 formattag
Definition: SDL_wave.h:52
WaveFormat format
Definition: SDL_wave.h:133
Uint32 samplesperblock
Definition: SDL_wave.h:67

◆ IMA_ADPCM_ProcessNibble()

static Sint16 IMA_ADPCM_ProcessNibble ( Sint8 cindex,
Sint16  lastsample,
Uint8  nybble 
)
static

Definition at line 855 of file SDL_wave.c.

Referenced by IMA_ADPCM_DecodeBlockData().

856 {
857  const Sint32 max_audioval = 32767;
858  const Sint32 min_audioval = -32768;
859  const Sint8 index_table_4b[16] = {
860  -1, -1, -1, -1,
861  2, 4, 6, 8,
862  -1, -1, -1, -1,
863  2, 4, 6, 8
864  };
865  const Uint16 step_table[89] = {
866  7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31,
867  34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130,
868  143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408,
869  449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
870  1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
871  3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630,
872  9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350,
873  22385, 24623, 27086, 29794, 32767
874  };
875  Uint32 step;
876  Sint32 sample, delta;
877  Sint8 index = *cindex;
878 
879  /* Clamp index into valid range. */
880  if (index > 88) {
881  index = 88;
882  } else if (index < 0) {
883  index = 0;
884  }
885 
886  /* explicit cast to avoid gcc warning about using 'char' as array index */
887  step = step_table[(size_t)index];
888 
889  /* Update index value */
890  *cindex = index + index_table_4b[nybble];
891 
892  /* This calculation uses shifts and additions because multiplications were
893  * much slower back then. Sadly, this can't just be replaced with an actual
894  * multiplication now as the old algorithm drops some bits. The closest
895  * approximation I could find is something like this:
896  * (nybble & 0x8 ? -1 : 1) * ((nybble & 0x7) * step / 4 + step / 8)
897  */
898  delta = step >> 3;
899  if (nybble & 0x04)
900  delta += step;
901  if (nybble & 0x02)
902  delta += step >> 1;
903  if (nybble & 0x01)
904  delta += step >> 2;
905  if (nybble & 0x08)
906  delta = -delta;
907 
908  sample = lastsample + delta;
909 
910  /* Clamp output sample */
911  if (sample > max_audioval) {
912  sample = max_audioval;
913  } else if (sample < min_audioval) {
914  sample = min_audioval;
915  }
916 
917  return (Sint16)sample;
918 }
uint16_t Uint16
Definition: SDL_stdinc.h:191
unsigned int size_t
int8_t Sint8
Definition: SDL_stdinc.h:173
int32_t Sint32
Definition: SDL_stdinc.h:197
GLuint index
uint32_t Uint32
Definition: SDL_stdinc.h:203
int16_t Sint16
Definition: SDL_stdinc.h:185

◆ LAW_Decode()

static int LAW_Decode ( WaveFile file,
Uint8 **  audio_buf,
Uint32 audio_len 
)
static

Definition at line 1161 of file SDL_wave.c.

References ALAW_CODE, WaveFormat::blockalign, WaveFormat::channels, WaveFile::chunk, WaveChunk::data, WaveFormat::encoding, WaveFile::format, i, WaveChunk::length, MULAW_CODE, MultiplySize(), nibble(), NULL, WaveFile::sampleframes, SDL_free, SDL_MAX_UINT32, SDL_OutOfMemory, SDL_realloc, SDL_SetError, WaveChunk::size, SIZE_MAX, and WaveAdjustToFactValue().

Referenced by WaveLoad().

1162 {
1163 #ifdef SDL_WAVE_LAW_LUT
1164  const Sint16 alaw_lut[256] = {
1165  -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, -2752,
1166  -2624, -3008, -2880, -2240, -2112, -2496, -2368, -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, -22016,
1167  -20992, -24064, -23040, -17920, -16896, -19968, -18944, -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, -11008,
1168  -10496, -12032, -11520, -8960, -8448, -9984, -9472, -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, -344,
1169  -328, -376, -360, -280, -264, -312, -296, -472, -456, -504, -488, -408, -392, -440, -424, -88,
1170  -72, -120, -104, -24, -8, -56, -40, -216, -200, -248, -232, -152, -136, -184, -168, -1376,
1171  -1312, -1504, -1440, -1120, -1056, -1248, -1184, -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, -688,
1172  -656, -752, -720, -560, -528, -624, -592, -944, -912, -1008, -976, -816, -784, -880, -848, 5504,
1173  5248, 6016, 5760, 4480, 4224, 4992, 4736, 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 2752,
1174  2624, 3008, 2880, 2240, 2112, 2496, 2368, 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 22016,
1175  20992, 24064, 23040, 17920, 16896, 19968, 18944, 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 11008,
1176  10496, 12032, 11520, 8960, 8448, 9984, 9472, 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, 344,
1177  328, 376, 360, 280, 264, 312, 296, 472, 456, 504, 488, 408, 392, 440, 424, 88,
1178  72, 120, 104, 24, 8, 56, 40, 216, 200, 248, 232, 152, 136, 184, 168, 1376,
1179  1312, 1504, 1440, 1120, 1056, 1248, 1184, 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 688,
1180  656, 752, 720, 560, 528, 624, 592, 944, 912, 1008, 976, 816, 784, 880, 848
1181  };
1182  const Sint16 mulaw_lut[256] = {
1183  -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, -15996,
1184  -15484, -14972, -14460, -13948, -13436, -12924, -12412, -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, -7932,
1185  -7676, -7420, -7164, -6908, -6652, -6396, -6140, -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, -3900,
1186  -3772, -3644, -3516, -3388, -3260, -3132, -3004, -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, -1884,
1187  -1820, -1756, -1692, -1628, -1564, -1500, -1436, -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, -876,
1188  -844, -812, -780, -748, -716, -684, -652, -620, -588, -556, -524, -492, -460, -428, -396, -372,
1189  -356, -340, -324, -308, -292, -276, -260, -244, -228, -212, -196, -180, -164, -148, -132, -120,
1190  -112, -104, -96, -88, -80, -72, -64, -56, -48, -40, -32, -24, -16, -8, 0, 32124,
1191  31100, 30076, 29052, 28028, 27004, 25980, 24956, 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, 15996,
1192  15484, 14972, 14460, 13948, 13436, 12924, 12412, 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, 7932,
1193  7676, 7420, 7164, 6908, 6652, 6396, 6140, 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, 3900,
1194  3772, 3644, 3516, 3388, 3260, 3132, 3004, 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, 1884,
1195  1820, 1756, 1692, 1628, 1564, 1500, 1436, 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, 876,
1196  844, 812, 780, 748, 716, 684, 652, 620, 588, 556, 524, 492, 460, 428, 396, 372,
1197  356, 340, 324, 308, 292, 276, 260, 244, 228, 212, 196, 180, 164, 148, 132, 120,
1198  112, 104, 96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0
1199  };
1200 #endif
1201 
1202  WaveFormat *format = &file->format;
1203  WaveChunk *chunk = &file->chunk;
1204  size_t i, sample_count, expanded_len;
1205  Uint8 *src;
1206  Sint16 *dst;
1207 
1208  if (chunk->length != chunk->size) {
1209  file->sampleframes = WaveAdjustToFactValue(file, chunk->size / format->blockalign);
1210  if (file->sampleframes < 0) {
1211  return -1;
1212  }
1213  }
1214 
1215  /* Nothing to decode, nothing to return. */
1216  if (file->sampleframes == 0) {
1217  *audio_buf = NULL;
1218  *audio_len = 0;
1219  return 0;
1220  }
1221 
1222  sample_count = (size_t)file->sampleframes;
1223  if (MultiplySize(&sample_count, format->channels)) {
1224  return SDL_OutOfMemory();
1225  }
1226 
1227  expanded_len = sample_count;
1228  if (MultiplySize(&expanded_len, sizeof(Sint16))) {
1229  return SDL_OutOfMemory();
1230  } else if (expanded_len > SDL_MAX_UINT32 || file->sampleframes > SIZE_MAX) {
1231  return SDL_SetError("WAVE file too big");
1232  }
1233 
1234  src = (Uint8 *)SDL_realloc(chunk->data, expanded_len);
1235  if (src == NULL) {
1236  return SDL_OutOfMemory();
1237  }
1238  chunk->data = NULL;
1239  chunk->size = 0;
1240 
1241  dst = (Sint16 *)src;
1242 
1243  /* Work backwards, since we're expanding in-place. SDL_AudioSpec.format will
1244  * inform the caller about the byte order.
1245  */
1246  i = sample_count;
1247  switch (file->format.encoding) {
1248 #ifdef SDL_WAVE_LAW_LUT
1249  case ALAW_CODE:
1250  while (i--) {
1251  dst[i] = alaw_lut[src[i]];
1252  }
1253  break;
1254  case MULAW_CODE:
1255  while (i--) {
1256  dst[i] = mulaw_lut[src[i]];
1257  }
1258  break;
1259 #else
1260  case ALAW_CODE:
1261  while (i--) {
1262  Uint8 nibble = src[i];
1263  Uint8 exponent = (nibble & 0x7f) ^ 0x55;
1264  Sint16 mantissa = exponent & 0xf;
1265 
1266  exponent >>= 4;
1267  if (exponent > 0) {
1268  mantissa |= 0x10;
1269  }
1270  mantissa = mantissa << 4 | 0x8;
1271  if (exponent > 1) {
1272  mantissa <<= exponent - 1;
1273  }
1274 
1275  dst[i] = nibble & 0x80 ? mantissa : -mantissa;
1276  }
1277  break;
1278  case MULAW_CODE:
1279  while (i--) {
1280  Uint8 nibble = ~src[i];
1281  Sint16 mantissa = nibble & 0xf;
1282  Uint8 exponent = nibble >> 4 & 0x7;
1283  Sint16 step = 4 << (exponent + 1);
1284 
1285  mantissa = (0x80 << exponent) + step * mantissa + step / 2 - 132;
1286 
1287  dst[i] = nibble & 0x80 ? -mantissa : mantissa;
1288  }
1289  break;
1290 #endif
1291  default:
1292  SDL_free(src);
1293  return SDL_SetError("Unknown companded encoding");
1294  }
1295 
1296  *audio_buf = src;
1297  *audio_len = (Uint32)expanded_len;
1298 
1299  return 0;
1300 }
#define MULAW_CODE
Definition: SDL_wave.h:43
Uint16 channels
Definition: SDL_wave.h:54
GLenum GLenum dst
#define SDL_MAX_UINT32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:201
#define SDL_realloc
GLenum src
unsigned int size_t
static SDL_bool MultiplySize(size_t *f1, size_t f2)
Definition: SDL_wave.c:47
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
#define ALAW_CODE
Definition: SDL_wave.h:42
uint8_t Uint8
Definition: SDL_stdinc.h:179
#define SDL_free
size_t size
Definition: SDL_wave.h:100
Uint16 blockalign
Definition: SDL_wave.h:57
Sint64 sampleframes
Definition: SDL_wave.h:140
WaveChunk chunk
Definition: SDL_wave.h:132
#define SIZE_MAX
Definition: SDL_wave.c:27
Uint8 * data
Definition: SDL_wave.h:99
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_SetError
static unsigned char nibble(char c)
GLint * exponent
uint32_t Uint32
Definition: SDL_stdinc.h:203
static Sint64 WaveAdjustToFactValue(WaveFile *file, Sint64 sampleframes)
Definition: SDL_wave.c:319
Uint32 length
Definition: SDL_wave.h:97
int16_t Sint16
Definition: SDL_stdinc.h:185
Uint16 encoding
Definition: SDL_wave.h:53
WaveFormat format
Definition: SDL_wave.h:133

◆ LAW_Init()

static int LAW_Init ( WaveFile file,
size_t  datalength 
)
static

Definition at line 1132 of file SDL_wave.c.

References WaveFormat::bitspersample, WaveFormat::blockalign, WaveFormat::channels, WaveFile::format, WaveFile::sampleframes, SDL_SetError, WaveFile::trunchint, TruncStrict, TruncVeryStrict, and WaveAdjustToFactValue().

Referenced by WaveCheckFormat().

1133 {
1134  WaveFormat *format = &file->format;
1135 
1136  /* Standards Update requires this to be 8. */
1137  if (format->bitspersample != 8) {
1138  return SDL_SetError("Invalid companded bits per sample of %d", (int)format->bitspersample);
1139  }
1140 
1141  /* Not going to bother with weird padding. */
1142  if (format->blockalign != format->channels) {
1143  return SDL_SetError("Unsupported block alignment");
1144  }
1145 
1146  if ((file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict)) {
1147  if (format->blockalign > 1 && datalength % format->blockalign) {
1148  return SDL_SetError("Truncated data chunk in WAVE file");
1149  }
1150  }
1151 
1152  file->sampleframes = WaveAdjustToFactValue(file, datalength / format->blockalign);
1153  if (file->sampleframes < 0) {
1154  return -1;
1155  }
1156 
1157  return 0;
1158 }
Uint16 bitspersample
Definition: SDL_wave.h:58
Uint16 channels
Definition: SDL_wave.h:54
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
WaveTruncationHint trunchint
Definition: SDL_wave.h:145
Uint16 blockalign
Definition: SDL_wave.h:57
Sint64 sampleframes
Definition: SDL_wave.h:140
#define SDL_SetError
static Sint64 WaveAdjustToFactValue(WaveFile *file, Sint64 sampleframes)
Definition: SDL_wave.c:319
WaveFormat format
Definition: SDL_wave.h:133

◆ MS_ADPCM_CalculateSampleFrames()

static int MS_ADPCM_CalculateSampleFrames ( WaveFile file,
size_t  datalength 
)
static

Definition at line 333 of file SDL_wave.c.

References WaveFormat::bitspersample, WaveFormat::blockalign, ADPCM_DecoderState::blockheadersize, WaveFormat::channels, WaveFile::format, WaveFile::sampleframes, WaveFormat::samplesperblock, SDL_SetError, TruncDropFrame, WaveFile::trunchint, TruncStrict, TruncVeryStrict, and WaveAdjustToFactValue().

Referenced by MS_ADPCM_Decode(), and MS_ADPCM_Init().

334 {
335  WaveFormat *format = &file->format;
336  const size_t blockheadersize = file->format.channels * 7;
337  const size_t availableblocks = datalength / file->format.blockalign;
338  const size_t blockframebitsize = file->format.bitspersample * file->format.channels;
339  const size_t trailingdata = datalength % file->format.blockalign;
340 
341  if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
342  /* The size of the data chunk must be a multiple of the block size. */
343  if (datalength < blockheadersize || trailingdata > 0) {
344  return SDL_SetError("Truncated MS ADPCM block");
345  }
346  }
347 
348  /* Calculate number of sample frames that will be decoded. */
349  file->sampleframes = (Sint64)availableblocks * format->samplesperblock;
350  if (trailingdata > 0) {
351  /* The last block is truncated. Check if we can get any samples out of it. */
352  if (file->trunchint == TruncDropFrame) {
353  /* Drop incomplete sample frame. */
354  if (trailingdata >= blockheadersize) {
355  size_t trailingsamples = 2 + (trailingdata - blockheadersize) * 8 / blockframebitsize;
356  if (trailingsamples > format->samplesperblock) {
357  trailingsamples = format->samplesperblock;
358  }
359  file->sampleframes += trailingsamples;
360  }
361  }
362  }
363 
364  file->sampleframes = WaveAdjustToFactValue(file, file->sampleframes);
365  if (file->sampleframes < 0) {
366  return -1;
367  }
368 
369  return 0;
370 }
Uint16 bitspersample
Definition: SDL_wave.h:58
Uint16 channels
Definition: SDL_wave.h:54
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
WaveTruncationHint trunchint
Definition: SDL_wave.h:145
Uint16 blockalign
Definition: SDL_wave.h:57
Sint64 sampleframes
Definition: SDL_wave.h:140
#define SDL_SetError
static Sint64 WaveAdjustToFactValue(WaveFile *file, Sint64 sampleframes)
Definition: SDL_wave.c:319
int64_t Sint64
Definition: SDL_stdinc.h:210
WaveFormat format
Definition: SDL_wave.h:133
Uint32 samplesperblock
Definition: SDL_wave.h:67

◆ MS_ADPCM_Decode()

static int MS_ADPCM_Decode ( WaveFile file,
Uint8 **  audio_buf,
Uint32 audio_len 
)
static

Definition at line 638 of file SDL_wave.c.

References ADPCM_DecoderState::block, WaveFormat::blockalign, ADPCM_DecoderState::blockheadersize, ADPCM_DecoderState::blocksize, WaveFormat::channels, ADPCM_DecoderState::channels, WaveFile::chunk, ADPCM_DecoderState::cstate, ADPCM_DecoderState::data, WaveChunk::data, ADPCM_DecoderState::ddata, WaveFile::decoderdata, WaveFile::format, ADPCM_DecoderState::framesize, ADPCM_DecoderState::framesleft, ADPCM_DecoderState::framestotal, ADPCM_DecoderState::input, WaveChunk::length, MS_ADPCM_CalculateSampleFrames(), MS_ADPCM_DecodeBlockData(), MS_ADPCM_DecodeBlockHeader(), MultiplySize(), NULL, ADPCM_DecoderState::output, ADPCM_DecoderState::pos, WaveFile::sampleframes, ADPCM_DecoderState::samplesperblock, WaveFormat::samplesperblock, SDL_free, SDL_malloc, SDL_MAX_UINT32, SDL_OutOfMemory, SDL_SetError, ADPCM_DecoderState::size, WaveChunk::size, SIZE_MAX, state, TruncDropFrame, WaveFile::trunchint, and TruncVeryStrict.

Referenced by WaveLoad().

639 {
640  int result;
641  size_t bytesleft, outputsize;
642  WaveChunk *chunk = &file->chunk;
644  MS_ADPCM_ChannelState cstate[2] = {0};
645 
646  if (chunk->size != chunk->length) {
647  /* Could not read everything. Recalculate number of sample frames. */
648  if (MS_ADPCM_CalculateSampleFrames(file, chunk->size) < 0) {
649  return -1;
650  }
651  }
652 
653  /* Nothing to decode, nothing to return. */
654  if (file->sampleframes == 0) {
655  *audio_buf = NULL;
656  *audio_len = 0;
657  return 0;
658  }
659 
660  state.blocksize = file->format.blockalign;
661  state.channels = file->format.channels;
662  state.blockheadersize = state.channels * 7;
663  state.samplesperblock = file->format.samplesperblock;
664  state.framesize = state.channels * sizeof(Sint16);
665  state.ddata = file->decoderdata;
666  state.framestotal = file->sampleframes;
667  state.framesleft = state.framestotal;
668 
669  state.input.data = chunk->data;
670  state.input.size = chunk->size;
671  state.input.pos = 0;
672 
673  /* The output size in bytes. May get modified if data is truncated. */
674  outputsize = (size_t)state.framestotal;
675  if (MultiplySize(&outputsize, state.framesize)) {
676  return SDL_OutOfMemory();
677  } else if (outputsize > SDL_MAX_UINT32 || state.framestotal > SIZE_MAX) {
678  return SDL_SetError("WAVE file too big");
679  }
680 
681  state.output.pos = 0;
682  state.output.size = outputsize / sizeof(Sint16);
683  state.output.data = (Sint16 *)SDL_malloc(outputsize);
684  if (state.output.data == NULL) {
685  return SDL_OutOfMemory();
686  }
687 
688  state.cstate = &cstate;
689 
690  /* Decode block by block. A truncated block will stop the decoding. */
691  bytesleft = state.input.size - state.input.pos;
692  while (state.framesleft > 0 && bytesleft >= state.blockheadersize) {
693  state.block.data = state.input.data + state.input.pos;
694  state.block.size = bytesleft < state.blocksize ? bytesleft : state.blocksize;
695  state.block.pos = 0;
696 
697  if (state.output.size - state.output.pos < (Uint64)state.framesleft * state.channels) {
698  /* Somehow didn't allocate enough space for the output. */
699  SDL_free(state.output.data);
700  return SDL_SetError("Unexpected overflow in MS ADPCM decoder");
701  }
702 
703  /* Initialize decoder with the values from the block header. */
704  result = MS_ADPCM_DecodeBlockHeader(&state);
705  if (result == -1) {
706  SDL_free(state.output.data);
707  return -1;
708  }
709 
710  /* Decode the block data. It stores the samples directly in the output. */
711  result = MS_ADPCM_DecodeBlockData(&state);
712  if (result == -1) {
713  /* Unexpected end. Stop decoding and return partial data if necessary. */
714  if (file->trunchint == TruncVeryStrict || file->trunchint == TruncVeryStrict) {
715  SDL_free(state.output.data);
716  return SDL_SetError("Truncated data chunk");
717  } else if (file->trunchint != TruncDropFrame) {
718  state.output.pos -= state.output.pos % (state.samplesperblock * state.channels);
719  }
720  outputsize = state.output.pos * sizeof(Sint16); /* Can't overflow, is always smaller. */
721  break;
722  }
723 
724  state.input.pos += state.block.size;
725  bytesleft = state.input.size - state.input.pos;
726  }
727 
728  *audio_buf = (Uint8 *)state.output.data;
729  *audio_len = (Uint32)outputsize;
730 
731  return 0;
732 }
GLuint64EXT * result
Uint16 channels
Definition: SDL_wave.h:54
struct ADPCM_DecoderState::@23 output
static int MS_ADPCM_CalculateSampleFrames(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:333
#define SDL_MAX_UINT32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:201
struct xkb_state * state
size_t blocksize
Definition: SDL_wave.c:59
uint64_t Uint64
Definition: SDL_stdinc.h:216
unsigned int size_t
static SDL_bool MultiplySize(size_t *f1, size_t f2)
Definition: SDL_wave.c:47
static int MS_ADPCM_DecodeBlockHeader(ADPCM_DecoderState *state)
Definition: SDL_wave.c:529
size_t framesize
Definition: SDL_wave.c:62
WaveTruncationHint trunchint
Definition: SDL_wave.h:145
uint8_t Uint8
Definition: SDL_stdinc.h:179
#define SDL_free
size_t size
Definition: SDL_wave.h:100
Uint16 blockalign
Definition: SDL_wave.h:57
Sint64 sampleframes
Definition: SDL_wave.h:140
WaveChunk chunk
Definition: SDL_wave.h:132
#define SIZE_MAX
Definition: SDL_wave.c:27
struct ADPCM_DecoderState::@22 block
Uint8 * data
Definition: SDL_wave.h:99
Sint64 framesleft
Definition: SDL_wave.c:64
struct ADPCM_DecoderState::@21 input
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_SetError
Sint64 framestotal
Definition: SDL_wave.c:63
size_t samplesperblock
Definition: SDL_wave.c:61
uint32_t Uint32
Definition: SDL_stdinc.h:203
void * decoderdata
Definition: SDL_wave.h:142
size_t blockheadersize
Definition: SDL_wave.c:60
#define SDL_malloc
Uint32 length
Definition: SDL_wave.h:97
static int MS_ADPCM_DecodeBlockData(ADPCM_DecoderState *state)
Definition: SDL_wave.c:590
int16_t Sint16
Definition: SDL_stdinc.h:185
WaveFormat format
Definition: SDL_wave.h:133
Uint32 samplesperblock
Definition: SDL_wave.h:67

◆ MS_ADPCM_DecodeBlockData()

static int MS_ADPCM_DecodeBlockData ( ADPCM_DecoderState state)
static

Definition at line 590 of file SDL_wave.c.

References ADPCM_DecoderState::block, ADPCM_DecoderState::blocksize, ADPCM_DecoderState::channels, ADPCM_DecoderState::cstate, ADPCM_DecoderState::data, ADPCM_DecoderState::framesleft, MS_ADPCM_ProcessNibble(), ADPCM_DecoderState::output, ADPCM_DecoderState::pos, ADPCM_DecoderState::samplesperblock, and ADPCM_DecoderState::size.

Referenced by MS_ADPCM_Decode().

591 {
592  Uint16 nybble = 0;
593  Sint16 sample1, sample2;
594  const Uint32 channels = state->channels;
595  Uint32 c;
597 
598  size_t blockpos = state->block.pos;
599  size_t blocksize = state->block.size;
600 
601  size_t outpos = state->output.pos;
602 
603  Sint64 blockframesleft = state->samplesperblock - 2;
604  if (blockframesleft > state->framesleft) {
605  blockframesleft = state->framesleft;
606  }
607 
608  while (blockframesleft > 0) {
609  for (c = 0; c < channels; c++) {
610  if (nybble & 0x8000) {
611  nybble <<= 4;
612  } else if (blockpos < blocksize) {
613  nybble = state->block.data[blockpos++] | 0x8000;
614  } else {
615  /* Out of input data. Drop the incomplete frame and return. */
616  state->output.pos = outpos - c;
617  return -1;
618  }
619 
620  /* Load previous samples which may come from the block header. */
621  sample1 = state->output.data[outpos - channels];
622  sample2 = state->output.data[outpos - channels * 2];
623 
624  sample1 = MS_ADPCM_ProcessNibble(cstate + c, sample1, sample2, (nybble >> 4) & 0x0f);
625  state->output.data[outpos++] = sample1;
626  }
627 
628  state->framesleft--;
629  blockframesleft--;
630  }
631 
632  state->output.pos = outpos;
633 
634  return 0;
635 }
struct ADPCM_DecoderState::@23 output
uint16_t Uint16
Definition: SDL_stdinc.h:191
const GLubyte * c
static Sint16 MS_ADPCM_ProcessNibble(MS_ADPCM_ChannelState *cstate, Sint32 sample1, Sint32 sample2, Uint8 nybble)
Definition: SDL_wave.c:492
struct ADPCM_DecoderState::@22 block
Sint64 framesleft
Definition: SDL_wave.c:64
size_t samplesperblock
Definition: SDL_wave.c:61
uint32_t Uint32
Definition: SDL_stdinc.h:203
int64_t Sint64
Definition: SDL_stdinc.h:210
int16_t Sint16
Definition: SDL_stdinc.h:185

◆ MS_ADPCM_DecodeBlockHeader()

static int MS_ADPCM_DecodeBlockHeader ( ADPCM_DecoderState state)
static

Definition at line 529 of file SDL_wave.c.

References ADPCM_DecoderState::block, ADPCM_DecoderState::blockheadersize, ADPCM_DecoderState::channels, MS_ADPCM_ChannelState::coeff1, MS_ADPCM_ChannelState::coeff2, ADPCM_DecoderState::cstate, ADPCM_DecoderState::data, ADPCM_DecoderState::ddata, MS_ADPCM_ChannelState::delta, ADPCM_DecoderState::framesleft, ADPCM_DecoderState::output, ADPCM_DecoderState::pos, and SDL_SetError.

Referenced by MS_ADPCM_Decode().

530 {
531  Uint8 coeffindex;
532  const Uint32 channels = state->channels;
533  Sint32 sample;
534  Uint32 c;
536  MS_ADPCM_CoeffData *ddata = (MS_ADPCM_CoeffData *)state->ddata;
537 
538  for (c = 0; c < channels; c++) {
539  size_t o = c;
540 
541  /* Load the coefficient pair into the channel state. */
542  coeffindex = state->block.data[o];
543  if (coeffindex > ddata->coeffcount) {
544  return SDL_SetError("Invalid MS ADPCM coefficient index in block header");
545  }
546  cstate[c].coeff1 = ddata->coeff[coeffindex * 2];
547  cstate[c].coeff2 = ddata->coeff[coeffindex * 2 + 1];
548 
549  /* Initial delta value. */
550  o = channels + c * 2;
551  cstate[c].delta = state->block.data[o] | ((Uint16)state->block.data[o + 1] << 8);
552 
553  /* Load the samples from the header. Interestingly, the sample later in
554  * the output stream comes first.
555  */
556  o = channels * 3 + c * 2;
557  sample = state->block.data[o] | ((Sint32)state->block.data[o + 1] << 8);
558  if (sample >= 0x8000) {
559  sample -= 0x10000;
560  }
561  state->output.data[state->output.pos + channels] = (Sint16)sample;
562 
563  o = channels * 5 + c * 2;
564  sample = state->block.data[o] | ((Sint32)state->block.data[o + 1] << 8);
565  if (sample >= 0x8000) {
566  sample -= 0x10000;
567  }
568  state->output.data[state->output.pos] = (Sint16)sample;
569 
570  state->output.pos++;
571  }
572 
573  state->block.pos += state->blockheadersize;
574 
575  /* Skip second sample frame that came from the header. */
576  state->output.pos += state->channels;
577 
578  /* Header provided two sample frames. */
579  state->framesleft -= 2;
580 
581  return 0;
582 }
struct ADPCM_DecoderState::@23 output
uint16_t Uint16
Definition: SDL_stdinc.h:191
uint8_t Uint8
Definition: SDL_stdinc.h:179
const GLubyte * c
int32_t Sint32
Definition: SDL_stdinc.h:197
struct ADPCM_DecoderState::@22 block
Sint64 framesleft
Definition: SDL_wave.c:64
#define SDL_SetError
uint32_t Uint32
Definition: SDL_stdinc.h:203
size_t blockheadersize
Definition: SDL_wave.c:60
int16_t Sint16
Definition: SDL_stdinc.h:185

◆ MS_ADPCM_Init()

static int MS_ADPCM_Init ( WaveFile file,
size_t  datalength 
)
static

Definition at line 373 of file SDL_wave.c.

References MS_ADPCM_CoeffData::aligndummy, WaveFormat::bitspersample, WaveFormat::blockalign, ADPCM_DecoderState::blockheadersize, WaveFormat::channels, WaveFile::chunk, MS_ADPCM_CoeffData::coeff, MS_ADPCM_CoeffData::coeffcount, WaveChunk::data, WaveFile::decoderdata, EXTENSIBLE_CODE, WaveFormat::extsize, WaveFile::format, WaveFormat::formattag, i, MS_ADPCM_CalculateSampleFrames(), NULL, ADPCM_DecoderState::samplesperblock, WaveFormat::samplesperblock, SDL_malloc, SDL_OutOfMemory, SDL_SetError, and WaveChunk::size.

Referenced by WaveCheckFormat().

374 {
375  WaveFormat *format = &file->format;
376  WaveChunk *chunk = &file->chunk;
377  const size_t blockheadersize = format->channels * 7;
378  const size_t blockdatasize = (size_t)format->blockalign - blockheadersize;
379  const size_t blockframebitsize = format->bitspersample * format->channels;
380  const size_t blockdatasamples = (blockdatasize * 8) / blockframebitsize;
381  const Sint16 presetcoeffs[14] = {256, 0, 512, -256, 0, 0, 192, 64, 240, 0, 460, -208, 392, -232};
382  size_t i, coeffcount;
383  MS_ADPCM_CoeffData *coeffdata;
384 
385  /* Sanity checks. */
386 
387  /* While it's clear how IMA ADPCM handles more than two channels, the nibble
388  * order of MS ADPCM makes it awkward. The Standards Update does not talk
389  * about supporting more than stereo anyway.
390  */
391  if (format->channels > 2) {
392  return SDL_SetError("Invalid number of channels");
393  }
394 
395  if (format->bitspersample != 4) {
396  return SDL_SetError("Invalid MS ADPCM bits per sample of %d", (int)format->bitspersample);
397  }
398 
399  /* The block size must be big enough to contain the block header. */
400  if (format->blockalign < blockheadersize) {
401  return SDL_SetError("Invalid MS ADPCM block size (nBlockAlign)");
402  }
403 
404  if (format->formattag == EXTENSIBLE_CODE) {
405  /* Does have a GUID (like all format tags), but there's no specification
406  * for how the data is packed into the extensible header. Making
407  * assumptions here could lead to new formats nobody wants to support.
408  */
409  return SDL_SetError("MS ADPCM with the extensible header is not supported");
410  }
411 
412  /* There are wSamplesPerBlock, wNumCoef, and at least 7 coefficient pairs in
413  * the extended part of the header.
414  */
415  if (chunk->size < 22) {
416  return SDL_SetError("Could not read MS ADPCM format header");
417  }
418 
419  format->samplesperblock = chunk->data[18] | ((Uint16)chunk->data[19] << 8);
420  /* Number of coefficient pairs. A pair has two 16-bit integers. */
421  coeffcount = chunk->data[20] | ((size_t)chunk->data[21] << 8);
422  /* bPredictor, the integer offset into the coefficients array, is only
423  * 8 bits. It can only address the first 256 coefficients. Let's limit
424  * the count number here.
425  */
426  if (coeffcount > 256) {
427  coeffcount = 256;
428  }
429 
430  if (chunk->size < 22 + coeffcount * 4) {
431  return SDL_SetError("Could not read custom coefficients in MS ADPCM format header");
432  } else if (format->extsize < 4 + coeffcount * 4) {
433  return SDL_SetError("Invalid MS ADPCM format header (too small)");
434  } else if (coeffcount < 7) {
435  return SDL_SetError("Missing required coefficients in MS ADPCM format header");
436  }
437 
438  coeffdata = (MS_ADPCM_CoeffData *)SDL_malloc(sizeof(MS_ADPCM_CoeffData) + coeffcount * 4);
439  file->decoderdata = coeffdata; /* Freed in cleanup. */
440  if (coeffdata == NULL) {
441  return SDL_OutOfMemory();
442  }
443  coeffdata->coeff = &coeffdata->aligndummy;
444  coeffdata->coeffcount = (Uint16)coeffcount;
445 
446  /* Copy the 16-bit pairs. */
447  for (i = 0; i < coeffcount * 2; i++) {
448  Sint32 c = chunk->data[22 + i * 2] | ((Sint32)chunk->data[23 + i * 2] << 8);
449  if (c >= 0x8000) {
450  c -= 0x10000;
451  }
452  if (i < 14 && c != presetcoeffs[i]) {
453  return SDL_SetError("Wrong preset coefficients in MS ADPCM format header");
454  }
455  coeffdata->coeff[i] = (Sint16)c;
456  }
457 
458  /* Technically, wSamplesPerBlock is required, but we have all the
459  * information in the other fields to calculate it, if it's zero.
460  */
461  if (format->samplesperblock == 0) {
462  /* Let's be nice to the encoders that didn't know how to fill this.
463  * The Standards Update calculates it this way:
464  *
465  * x = Block size (in bits) minus header size (in bits)
466  * y = Bit depth multiplied by channel count
467  * z = Number of samples per channel in block header
468  * wSamplesPerBlock = x / y + z
469  */
470  format->samplesperblock = (Uint32)blockdatasamples + 2;
471  }
472 
473  /* nBlockAlign can be in conflict with wSamplesPerBlock. For example, if
474  * the number of samples doesn't fit into the block. The Standards Update
475  * also describes wSamplesPerBlock with a formula that makes it necessary to
476  * always fill the block with the maximum amount of samples, but this is not
477  * enforced here as there are no compatibility issues.
478  * A truncated block header with just one sample is not supported.
479  */
480  if (format->samplesperblock == 1 || blockdatasamples < format->samplesperblock - 2) {
481  return SDL_SetError("Invalid number of samples per MS ADPCM block (wSamplesPerBlock)");
482  }
483 
484  if (MS_ADPCM_CalculateSampleFrames(file, datalength) < 0) {
485  return -1;
486  }
487 
488  return 0;
489 }
Uint16 extsize
Definition: SDL_wave.h:63
Uint16 bitspersample
Definition: SDL_wave.h:58
Uint16 channels
Definition: SDL_wave.h:54
static int MS_ADPCM_CalculateSampleFrames(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:333
uint16_t Uint16
Definition: SDL_stdinc.h:191
unsigned int size_t
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
Sint16 * coeff
Definition: SDL_wave.c:93
#define EXTENSIBLE_CODE
Definition: SDL_wave.h:47
size_t size
Definition: SDL_wave.h:100
Uint16 blockalign
Definition: SDL_wave.h:57
const GLubyte * c
WaveChunk chunk
Definition: SDL_wave.h:132
Sint16 aligndummy
Definition: SDL_wave.c:94
int32_t Sint32
Definition: SDL_stdinc.h:197
Uint8 * data
Definition: SDL_wave.h:99
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_SetError
uint32_t Uint32
Definition: SDL_stdinc.h:203
void * decoderdata
Definition: SDL_wave.h:142
#define SDL_malloc
Uint16 formattag
Definition: SDL_wave.h:52
Uint16 coeffcount
Definition: SDL_wave.c:92
int16_t Sint16
Definition: SDL_stdinc.h:185
WaveFormat format
Definition: SDL_wave.h:133
Uint32 samplesperblock
Definition: SDL_wave.h:67

◆ MS_ADPCM_ProcessNibble()

static Sint16 MS_ADPCM_ProcessNibble ( MS_ADPCM_ChannelState cstate,
Sint32  sample1,
Sint32  sample2,
Uint8  nybble 
)
static

Definition at line 492 of file SDL_wave.c.

References MS_ADPCM_ChannelState::coeff1, MS_ADPCM_ChannelState::coeff2, and MS_ADPCM_ChannelState::delta.

Referenced by MS_ADPCM_DecodeBlockData().

493 {
494  const Sint32 max_audioval = 32767;
495  const Sint32 min_audioval = -32768;
496  const Uint16 max_deltaval = 65535;
497  const Uint16 adaptive[] = {
498  230, 230, 230, 230, 307, 409, 512, 614,
499  768, 614, 512, 409, 307, 230, 230, 230
500  };
501  Sint32 new_sample;
502  Sint32 errordelta;
503  Uint32 delta = cstate->delta;
504 
505  new_sample = (sample1 * cstate->coeff1 + sample2 * cstate->coeff2) / 256;
506  /* The nibble is a signed 4-bit error delta. */
507  errordelta = (Sint32)nybble - (nybble >= 0x08 ? 0x10 : 0);
508  new_sample += (Sint32)delta * errordelta;
509  if (new_sample < min_audioval) {
510  new_sample = min_audioval;
511  } else if (new_sample > max_audioval) {
512  new_sample = max_audioval;
513  }
514  delta = (delta * adaptive[nybble]) / 256;
515  if (delta < 16) {
516  delta = 16;
517  } else if (delta > max_deltaval) {
518  /* This issue is not described in the Standards Update and therefore
519  * undefined. It seems sensible to prevent overflows with a limit.
520  */
521  delta = max_deltaval;
522  }
523 
524  cstate->delta = (Uint16)delta;
525  return (Sint16)new_sample;
526 }
uint16_t Uint16
Definition: SDL_stdinc.h:191
int32_t Sint32
Definition: SDL_stdinc.h:197
uint32_t Uint32
Definition: SDL_stdinc.h:203
int16_t Sint16
Definition: SDL_stdinc.h:185

◆ MultiplySize()

static SDL_bool MultiplySize ( size_t f1,
size_t  f2 
)
static

Definition at line 47 of file SDL_wave.c.

References SDL_FALSE, SDL_TRUE, and SIZE_MAX.

Referenced by IMA_ADPCM_Decode(), LAW_Decode(), MS_ADPCM_Decode(), PCM_ConvertSint24ToSint32(), and PCM_Decode().

48 {
49  if (*f1 > 0 && SIZE_MAX / *f1 <= f2) {
50  return SDL_TRUE;
51  }
52  *f1 *= f2;
53  return SDL_FALSE;
54 }
#define SIZE_MAX
Definition: SDL_wave.c:27

◆ PCM_ConvertSint24ToSint32()

static int PCM_ConvertSint24ToSint32 ( WaveFile file,
Uint8 **  audio_buf,
Uint32 audio_len 
)
static

Definition at line 1346 of file SDL_wave.c.

References WaveFormat::channels, WaveFile::chunk, WaveChunk::data, WaveFile::format, i, MultiplySize(), NULL, WaveFile::sampleframes, SDL_MAX_UINT32, SDL_OutOfMemory, SDL_realloc, SDL_SetError, WaveChunk::size, and SIZE_MAX.

Referenced by PCM_Decode().

1347 {
1348  WaveFormat *format = &file->format;
1349  WaveChunk *chunk = &file->chunk;
1350  size_t i, expanded_len, sample_count;
1351  Uint8 *ptr;
1352 
1353  sample_count = (size_t)file->sampleframes;
1354  if (MultiplySize(&sample_count, format->channels)) {
1355  return SDL_OutOfMemory();
1356  }
1357 
1358  expanded_len = sample_count;
1359  if (MultiplySize(&expanded_len, sizeof(Sint32))) {
1360  return SDL_OutOfMemory();
1361  } else if (expanded_len > SDL_MAX_UINT32 || file->sampleframes > SIZE_MAX) {
1362  return SDL_SetError("WAVE file too big");
1363  }
1364 
1365  ptr = (Uint8 *)SDL_realloc(chunk->data, expanded_len);
1366  if (ptr == NULL) {
1367  return SDL_OutOfMemory();
1368  }
1369 
1370  /* This pointer is now invalid. */
1371  chunk->data = NULL;
1372  chunk->size = 0;
1373 
1374  *audio_buf = ptr;
1375  *audio_len = (Uint32)expanded_len;
1376 
1377  /* work from end to start, since we're expanding in-place. */
1378  for (i = sample_count; i > 0; i--) {
1379  const size_t o = i - 1;
1380  uint8_t b[4];
1381 
1382  b[0] = 0;
1383  b[1] = ptr[o * 3];
1384  b[2] = ptr[o * 3 + 1];
1385  b[3] = ptr[o * 3 + 2];
1386 
1387  ptr[o * 4 + 0] = b[0];
1388  ptr[o * 4 + 1] = b[1];
1389  ptr[o * 4 + 2] = b[2];
1390  ptr[o * 4 + 3] = b[3];
1391  }
1392 
1393  return 0;
1394 }
Uint16 channels
Definition: SDL_wave.h:54
#define SDL_MAX_UINT32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:201
#define SDL_realloc
unsigned int size_t
static SDL_bool MultiplySize(size_t *f1, size_t f2)
Definition: SDL_wave.c:47
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
uint8_t Uint8
Definition: SDL_stdinc.h:179
size_t size
Definition: SDL_wave.h:100
Sint64 sampleframes
Definition: SDL_wave.h:140
WaveChunk chunk
Definition: SDL_wave.h:132
#define SIZE_MAX
Definition: SDL_wave.c:27
int32_t Sint32
Definition: SDL_stdinc.h:197
Uint8 * data
Definition: SDL_wave.h:99
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
unsigned char uint8_t
#define SDL_SetError
uint32_t Uint32
Definition: SDL_stdinc.h:203
GLboolean GLboolean GLboolean b
WaveFormat format
Definition: SDL_wave.h:133

◆ PCM_Decode()

static int PCM_Decode ( WaveFile file,
Uint8 **  audio_buf,
Uint32 audio_len 
)
static

Definition at line 1397 of file SDL_wave.c.

References WaveFormat::bitspersample, WaveFormat::blockalign, WaveFile::chunk, WaveChunk::data, WaveFormat::encoding, WaveFile::format, WaveChunk::length, MultiplySize(), NULL, PCM_CODE, PCM_ConvertSint24ToSint32(), WaveFile::sampleframes, SDL_MAX_UINT32, SDL_OutOfMemory, SDL_SetError, WaveChunk::size, SIZE_MAX, and WaveAdjustToFactValue().

Referenced by WaveLoad().

1398 {
1399  WaveFormat *format = &file->format;
1400  WaveChunk *chunk = &file->chunk;
1401  size_t outputsize;
1402 
1403  if (chunk->length != chunk->size) {
1404  file->sampleframes = WaveAdjustToFactValue(file, chunk->size / format->blockalign);
1405  if (file->sampleframes < 0) {
1406  return -1;
1407  }
1408  }
1409 
1410  /* Nothing to decode, nothing to return. */
1411  if (file->sampleframes == 0) {
1412  *audio_buf = NULL;
1413  *audio_len = 0;
1414  return 0;
1415  }
1416 
1417  /* 24-bit samples get shifted to 32 bits. */
1418  if (format->encoding == PCM_CODE && format->bitspersample == 24) {
1419  return PCM_ConvertSint24ToSint32(file, audio_buf, audio_len);
1420  }
1421 
1422  outputsize = (size_t)file->sampleframes;
1423  if (MultiplySize(&outputsize, format->blockalign)) {
1424  return SDL_OutOfMemory();
1425  } else if (outputsize > SDL_MAX_UINT32 || file->sampleframes > SIZE_MAX) {
1426  return SDL_SetError("WAVE file too big");
1427  }
1428 
1429  *audio_buf = chunk->data;
1430  *audio_len = (Uint32)outputsize;
1431 
1432  /* This pointer is going to be returned to the caller. Prevent free in cleanup. */
1433  chunk->data = NULL;
1434  chunk->size = 0;
1435 
1436  return 0;
1437 }
#define PCM_CODE
Definition: SDL_wave.h:39
Uint16 bitspersample
Definition: SDL_wave.h:58
#define SDL_MAX_UINT32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:201
unsigned int size_t
static SDL_bool MultiplySize(size_t *f1, size_t f2)
Definition: SDL_wave.c:47
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
size_t size
Definition: SDL_wave.h:100
Uint16 blockalign
Definition: SDL_wave.h:57
Sint64 sampleframes
Definition: SDL_wave.h:140
WaveChunk chunk
Definition: SDL_wave.h:132
#define SIZE_MAX
Definition: SDL_wave.c:27
Uint8 * data
Definition: SDL_wave.h:99
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_SetError
uint32_t Uint32
Definition: SDL_stdinc.h:203
static Sint64 WaveAdjustToFactValue(WaveFile *file, Sint64 sampleframes)
Definition: SDL_wave.c:319
Uint32 length
Definition: SDL_wave.h:97
Uint16 encoding
Definition: SDL_wave.h:53
static int PCM_ConvertSint24ToSint32(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
Definition: SDL_wave.c:1346
WaveFormat format
Definition: SDL_wave.h:133

◆ PCM_Init()

static int PCM_Init ( WaveFile file,
size_t  datalength 
)
static

Definition at line 1303 of file SDL_wave.c.

References WaveFormat::bitspersample, WaveFormat::blockalign, WaveFormat::channels, WaveFormat::encoding, WaveFile::format, IEEE_FLOAT_CODE, PCM_CODE, WaveFile::sampleframes, SDL_SetError, WaveFile::trunchint, TruncStrict, TruncVeryStrict, and WaveAdjustToFactValue().

Referenced by WaveCheckFormat().

1304 {
1305  WaveFormat *format = &file->format;
1306 
1307  if (format->encoding == PCM_CODE) {
1308  switch (format->bitspersample) {
1309  case 8:
1310  case 16:
1311  case 24:
1312  case 32:
1313  /* These are supported. */
1314  break;
1315  default:
1316  return SDL_SetError("%d-bit PCM format not supported", (int)format->bitspersample);
1317  }
1318  } else if (format->encoding == IEEE_FLOAT_CODE) {
1319  if (format->bitspersample != 32) {
1320  return SDL_SetError("%d-bit IEEE floating-point format not supported", (int)format->bitspersample);
1321  }
1322  }
1323 
1324  /* It wouldn't be that hard to support more exotic block sizes, but
1325  * the most common formats should do for now.
1326  */
1327  if (format->blockalign * 8 != format->channels * format->bitspersample) {
1328  return SDL_SetError("Unsupported block alignment");
1329  }
1330 
1331  if ((file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict)) {
1332  if (format->blockalign > 1 && datalength % format->blockalign) {
1333  return SDL_SetError("Truncated data chunk in WAVE file");
1334  }
1335  }
1336 
1337  file->sampleframes = WaveAdjustToFactValue(file, datalength / format->blockalign);
1338  if (file->sampleframes < 0) {
1339  return -1;
1340  }
1341 
1342  return 0;
1343 }
#define PCM_CODE
Definition: SDL_wave.h:39
Uint16 bitspersample
Definition: SDL_wave.h:58
Uint16 channels
Definition: SDL_wave.h:54
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
WaveTruncationHint trunchint
Definition: SDL_wave.h:145
Uint16 blockalign
Definition: SDL_wave.h:57
Sint64 sampleframes
Definition: SDL_wave.h:140
#define IEEE_FLOAT_CODE
Definition: SDL_wave.h:41
#define SDL_SetError
static Sint64 WaveAdjustToFactValue(WaveFile *file, Sint64 sampleframes)
Definition: SDL_wave.c:319
Uint16 encoding
Definition: SDL_wave.h:53
WaveFormat format
Definition: SDL_wave.h:133

◆ SDL_FreeWAV()

void SDL_FreeWAV ( Uint8 audio_buf)

This function frees data previously allocated with SDL_LoadWAV_RW()

Definition at line 2126 of file SDL_wave.c.

References SDL_free.

2127 {
2128  SDL_free(audio_buf);
2129 }
#define SDL_free

◆ SDL_LoadWAV_RW()

SDL_AudioSpec* SDL_LoadWAV_RW ( SDL_RWops src,
int  freesrc,
SDL_AudioSpec spec,
Uint8 **  audio_buf,
Uint32 audio_len 
)

Load the audio data of a WAVE file into memory.

Loading a WAVE file requires src, spec, audio_buf and audio_len to be valid pointers. The entire data portion of the file is then loaded into memory and decoded if necessary.

If freesrc is non-zero, the data source gets automatically closed and freed before the function returns.

Supported are RIFF WAVE files with the formats PCM (8, 16, 24, and 32 bits), IEEE Float (32 bits), Microsoft ADPCM and IMA ADPCM (4 bits), and A-law and µ-law (8 bits). Other formats are currently unsupported and cause an error.

If this function succeeds, the pointer returned by it is equal to spec and the pointer to the audio data allocated by the function is written to audio_buf and its length in bytes to audio_len. The SDL_AudioSpec members freq, channels, and format are set to the values of the audio data in the buffer. The samples member is set to a sane default and all others are set to zero.

It's necessary to use SDL_FreeWAV() to free the audio data returned in audio_buf when it is no longer used.

Because of the underspecification of the Waveform format, there are many problematic files in the wild that cause issues with strict decoders. To provide compatibility with these files, this decoder is lenient in regards to the truncation of the file, the fact chunk, and the size of the RIFF chunk. The hints SDL_HINT_WAVE_RIFF_CHUNK_SIZE, SDL_HINT_WAVE_TRUNCATION, and SDL_HINT_WAVE_FACT_CHUNK can be used to tune the behavior of the loading process.

Any file that is invalid (due to truncation, corruption, or wrong values in the headers), too big, or unsupported causes an error. Additionally, any critical I/O error from the data source will terminate the loading process with an error. The function returns NULL on error and in all cases (with the exception of src being NULL), an appropriate error message will be set.

It is required that the data source supports seeking.

Example:

SDL_LoadWAV_RW(SDL_RWFromFile("sample.wav", "rb"), 1, ...);
Parameters
srcThe data source with the WAVE data
freesrcA integer value that makes the function close the data source if non-zero
specA pointer filled with the audio format of the audio data
audio_bufA pointer filled with the audio data allocated by the function
audio_lenA pointer filled with the length of the audio data buffer in bytes
Returns
NULL on error, or non-NULL on success.

Definition at line 2075 of file SDL_wave.c.

References WaveFile::chunk, WaveFile::decoderdata, WaveFile::facthint, NULL, WaveChunk::position, WaveFile::riffhint, RW_SEEK_SET, SDL_free, SDL_InvalidParamError, SDL_RWclose, SDL_RWseek, spec, WaveFile::trunchint, WaveFreeChunkData(), WaveGetFactChunkHint(), WaveGetRiffSizeHint(), WaveGetTruncationHint(), and WaveLoad().

2076 {
2077  int result;
2078  WaveFile file = {0};
2079 
2080  /* Make sure we are passed a valid data source */
2081  if (src == NULL) {
2082  /* Error may come from RWops. */
2083  return NULL;
2084  } else if (spec == NULL) {
2085  SDL_InvalidParamError("spec");
2086  return NULL;
2087  } else if (audio_buf == NULL) {
2088  SDL_InvalidParamError("audio_buf");
2089  return NULL;
2090  } else if (audio_len == NULL) {
2091  SDL_InvalidParamError("audio_len");
2092  return NULL;
2093  }
2094 
2095  *audio_buf = NULL;
2096  *audio_len = 0;
2097 
2098  file.riffhint = WaveGetRiffSizeHint();
2100  file.facthint = WaveGetFactChunkHint();
2101 
2102  result = WaveLoad(src, &file, spec, audio_buf, audio_len);
2103  if (result < 0) {
2104  SDL_free(*audio_buf);
2105  spec = NULL;
2106  audio_buf = NULL;
2107  audio_len = 0;
2108  }
2109 
2110  /* Cleanup */
2111  if (freesrc) {
2112  SDL_RWclose(src);
2113  } else {
2114  SDL_RWseek(src, file.chunk.position, RW_SEEK_SET);
2115  }
2116  WaveFreeChunkData(&file.chunk);
2117  SDL_free(file.decoderdata);
2118 
2119  return spec;
2120 }
GLuint64EXT * result
static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
Definition: SDL_wave.c:1771
WaveRiffSizeHint riffhint
Definition: SDL_wave.h:144
static void WaveFreeChunkData(WaveChunk *chunk)
Definition: SDL_wave.c:1500
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
WaveFactChunkHint facthint
Definition: SDL_wave.h:146
#define SDL_RWseek(ctx, offset, whence)
Definition: SDL_rwops.h:185
SDL_AudioSpec spec
Definition: loopwave.c:31
WaveTruncationHint trunchint
Definition: SDL_wave.h:145
static WaveTruncationHint WaveGetTruncationHint()
Definition: SDL_wave.c:1460
#define SDL_free
WaveChunk chunk
Definition: SDL_wave.h:132
#define NULL
Definition: begin_code.h:164
static WaveRiffSizeHint WaveGetRiffSizeHint()
Definition: SDL_wave.c:1440
#define SDL_RWclose(ctx)
Definition: SDL_rwops.h:189
Sint64 position
Definition: SDL_wave.h:98
static WaveFactChunkHint WaveGetFactChunkHint()
Definition: SDL_wave.c:1480
void * decoderdata
Definition: SDL_wave.h:142
#define RW_SEEK_SET
Definition: SDL_rwops.h:174

◆ WaveAdjustToFactValue()

static Sint64 WaveAdjustToFactValue ( WaveFile file,
Sint64  sampleframes 
)
static

Definition at line 319 of file SDL_wave.c.

References WaveFile::fact, WaveFile::facthint, FactStrict, WaveFact::samplelength, SDL_SetError, and WaveFact::status.

Referenced by IMA_ADPCM_CalculateSampleFrames(), LAW_Decode(), LAW_Init(), MS_ADPCM_CalculateSampleFrames(), PCM_Decode(), and PCM_Init().

320 {
321  if (file->fact.status == 2) {
322  if (file->facthint == FactStrict && sampleframes < file->fact.samplelength) {
323  return SDL_SetError("Invalid number of sample frames in WAVE fact chunk (too many)");
324  } else if (sampleframes > file->fact.samplelength) {
325  return file->fact.samplelength;
326  }
327  }
328 
329  return sampleframes;
330 }
Uint32 samplelength
Definition: SDL_wave.h:90
WaveFactChunkHint facthint
Definition: SDL_wave.h:146
Sint32 status
Definition: SDL_wave.h:80
WaveFact fact
Definition: SDL_wave.h:134
#define SDL_SetError

◆ WaveCheckFormat()

static int WaveCheckFormat ( WaveFile file,
size_t  datalength 
)
static

Definition at line 1663 of file SDL_wave.c.

References ALAW_CODE, WaveFormat::bitspersample, WaveFormat::blockalign, WaveFormat::channels, WaveFile::chunk, WaveFormat::encoding, EXTENSIBLE_CODE, WaveFile::fact, WaveFile::facthint, FactIgnoreZero, FactStrict, FactTruncate, WaveFile::format, WaveFormat::formattag, WaveFormat::frequency, IEEE_FLOAT_CODE, IMA_ADPCM_CODE, IMA_ADPCM_Init(), INT_MAX, LAW_Init(), MPEG_CODE, MPEGLAYER3_CODE, MS_ADPCM_CODE, MS_ADPCM_Init(), MULAW_CODE, PCM_CODE, PCM_Init(), WaveFact::samplelength, SDL_SetError, WaveChunk::size, WaveFact::status, and WaveFormat::subformat.

Referenced by WaveLoad().

1664 {
1665  WaveFormat *format = &file->format;
1666 
1667  /* Check for some obvious issues. */
1668 
1669  if (format->channels == 0) {
1670  return SDL_SetError("Invalid number of channels");
1671  } else if (format->channels > 255) {
1672  /* Limit given by SDL_AudioSpec.channels. */
1673  return SDL_SetError("Number of channels exceeds limit of 255");
1674  }
1675 
1676  if (format->frequency == 0) {
1677  return SDL_SetError("Invalid sample rate");
1678  } else if (format->frequency > INT_MAX) {
1679  /* Limit given by SDL_AudioSpec.freq. */
1680  return SDL_SetError("Sample rate exceeds limit of %d", INT_MAX);
1681  }
1682 
1683  /* Reject invalid fact chunks in strict mode. */
1684  if (file->facthint == FactStrict && file->fact.status == -1) {
1685  return SDL_SetError("Invalid fact chunk in WAVE file");
1686  }
1687 
1688  /* Check the issues common to all encodings. Some unsupported formats set
1689  * the bits per sample to zero. These fall through to the 'unsupported
1690  * format' error.
1691  */
1692  switch (format->encoding) {
1693  case IEEE_FLOAT_CODE:
1694  case ALAW_CODE:
1695  case MULAW_CODE:
1696  case MS_ADPCM_CODE:
1697  case IMA_ADPCM_CODE:
1698  /* These formats require a fact chunk. */
1699  if (file->facthint == FactStrict && file->fact.status <= 0) {
1700  return SDL_SetError("Missing fact chunk in WAVE file");
1701  }
1702  /* fallthrough */
1703  case PCM_CODE:
1704  /* All supported formats require a non-zero bit depth. */
1705  if (file->chunk.size < 16) {
1706  return SDL_SetError("Missing wBitsPerSample field in WAVE fmt chunk");
1707  } else if (format->bitspersample == 0) {
1708  return SDL_SetError("Invalid bits per sample");
1709  }
1710 
1711  /* All supported formats must have a proper block size. */
1712  if (format->blockalign == 0) {
1713  return SDL_SetError("Invalid block alignment");
1714  }
1715 
1716  /* If the fact chunk is valid and the appropriate hint is set, the
1717  * decoders will use the number of sample frames from the fact chunk.
1718  */
1719  if (file->fact.status == 1) {
1720  WaveFactChunkHint hint = file->facthint;
1721  Uint32 samples = file->fact.samplelength;
1722  if (hint == FactTruncate || hint == FactStrict || (hint == FactIgnoreZero && samples > 0)) {
1723  file->fact.status = 2;
1724  }
1725  }
1726  }
1727 
1728  /* Check the format for encoding specific issues and initialize decoders. */
1729  switch (format->encoding) {
1730  case PCM_CODE:
1731  case IEEE_FLOAT_CODE:
1732  if (PCM_Init(file, datalength) < 0) {
1733  return -1;
1734  }
1735  break;
1736  case ALAW_CODE:
1737  case MULAW_CODE:
1738  if (LAW_Init(file, datalength) < 0) {
1739  return -1;
1740  }
1741  break;
1742  case MS_ADPCM_CODE:
1743  if (MS_ADPCM_Init(file, datalength) < 0) {
1744  return -1;
1745  }
1746  break;
1747  case IMA_ADPCM_CODE:
1748  if (IMA_ADPCM_Init(file, datalength) < 0) {
1749  return -1;
1750  }
1751  break;
1752  case MPEG_CODE:
1753  case MPEGLAYER3_CODE:
1754  return SDL_SetError("MPEG formats not supported");
1755  default:
1756  if (format->formattag == EXTENSIBLE_CODE) {
1757  const char *errstr = "Unknown WAVE format GUID: %08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x";
1758  const Uint8 *g = format->subformat;
1759  const Uint32 g1 = g[0] | ((Uint32)g[1] << 8) | ((Uint32)g[2] << 16) | ((Uint32)g[3] << 24);
1760  const Uint32 g2 = g[4] | ((Uint32)g[5] << 8);
1761  const Uint32 g3 = g[6] | ((Uint32)g[7] << 8);
1762  return SDL_SetError(errstr, g1, g2, g3, g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15]);
1763  }
1764  return SDL_SetError("Unknown WAVE format tag: 0x%04x", (int)format->encoding);
1765  }
1766 
1767  return 0;
1768 }
#define PCM_CODE
Definition: SDL_wave.h:39
#define MULAW_CODE
Definition: SDL_wave.h:43
Uint16 bitspersample
Definition: SDL_wave.h:58
Uint16 channels
Definition: SDL_wave.h:54
#define MPEGLAYER3_CODE
Definition: SDL_wave.h:46
static int IMA_ADPCM_Init(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:789
static int MS_ADPCM_Init(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:373
Uint32 samplelength
Definition: SDL_wave.h:90
WaveFactChunkHint facthint
Definition: SDL_wave.h:146
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
#define ALAW_CODE
Definition: SDL_wave.h:42
WaveFactChunkHint
Definition: SDL_wave.h:122
static int LAW_Init(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:1132
#define EXTENSIBLE_CODE
Definition: SDL_wave.h:47
uint8_t Uint8
Definition: SDL_stdinc.h:179
size_t size
Definition: SDL_wave.h:100
Sint32 status
Definition: SDL_wave.h:80
Uint16 blockalign
Definition: SDL_wave.h:57
WaveChunk chunk
Definition: SDL_wave.h:132
WaveFact fact
Definition: SDL_wave.h:134
static int PCM_Init(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:1303
#define MPEG_CODE
Definition: SDL_wave.h:45
#define IEEE_FLOAT_CODE
Definition: SDL_wave.h:41
#define IMA_ADPCM_CODE
Definition: SDL_wave.h:44
#define SDL_SetError
uint32_t Uint32
Definition: SDL_stdinc.h:203
Uint8 subformat[16]
Definition: SDL_wave.h:69
Uint32 frequency
Definition: SDL_wave.h:55
Uint16 formattag
Definition: SDL_wave.h:52
GLsizei samples
GLboolean GLboolean g
#define INT_MAX
Definition: SDL_wave.c:31
Uint16 encoding
Definition: SDL_wave.h:53
#define MS_ADPCM_CODE
Definition: SDL_wave.h:40
WaveFormat format
Definition: SDL_wave.h:133

◆ WaveFreeChunkData()

static void WaveFreeChunkData ( WaveChunk chunk)
static

Definition at line 1500 of file SDL_wave.c.

References WaveChunk::data, NULL, SDL_free, and WaveChunk::size.

Referenced by SDL_LoadWAV_RW(), WaveLoad(), WaveNextChunk(), and WaveReadPartialChunkData().

1501 {
1502  if (chunk->data != NULL) {
1503  SDL_free(chunk->data);
1504  chunk->data = NULL;
1505  }
1506  chunk->size = 0;
1507 }
#define SDL_free
size_t size
Definition: SDL_wave.h:100
Uint8 * data
Definition: SDL_wave.h:99
#define NULL
Definition: begin_code.h:164

◆ WaveGetFactChunkHint()

static WaveFactChunkHint WaveGetFactChunkHint ( )
static

Definition at line 1480 of file SDL_wave.c.

References FactIgnore, FactIgnoreZero, FactNoHint, FactStrict, FactTruncate, NULL, SDL_GetHint, SDL_HINT_WAVE_FACT_CHUNK, and SDL_strcmp.

Referenced by SDL_LoadWAV_RW().

1481 {
1482  const char *hint = SDL_GetHint(SDL_HINT_WAVE_FACT_CHUNK);
1483 
1484  if (hint != NULL) {
1485  if (SDL_strcmp(hint, "truncate") == 0) {
1486  return FactTruncate;
1487  } else if (SDL_strcmp(hint, "strict") == 0) {
1488  return FactStrict;
1489  } else if (SDL_strcmp(hint, "ignorezero") == 0) {
1490  return FactIgnoreZero;
1491  } else if (SDL_strcmp(hint, "ignore") == 0) {
1492  return FactIgnore;
1493  }
1494  }
1495 
1496  return FactNoHint;
1497 }
#define SDL_GetHint
#define NULL
Definition: begin_code.h:164
#define SDL_HINT_WAVE_FACT_CHUNK
Controls how the fact chunk affects the loading of a WAVE file.
Definition: SDL_hints.h:1181
#define SDL_strcmp

◆ WaveGetFormatGUIDEncoding()

static Uint16 WaveGetFormatGUIDEncoding ( WaveFormat format)
static

Definition at line 1589 of file SDL_wave.c.

References WaveExtensibleGUID::encoding, WaveExtensibleGUID::guid, i, SDL_arraysize, SDL_memcmp, WaveFormat::subformat, and UNKNOWN_CODE.

Referenced by WaveReadFormat().

1590 {
1591  size_t i;
1592  for (i = 0; i < SDL_arraysize(extensible_guids); i++) {
1593  if (SDL_memcmp(format->subformat, extensible_guids[i].guid, 16) == 0) {
1594  return extensible_guids[i].encoding;
1595  }
1596  }
1597  return UNKNOWN_CODE;
1598 }
Uint8 guid[16]
Definition: SDL_wave.c:1574
#define UNKNOWN_CODE
Definition: SDL_wave.h:38
#define SDL_memcmp
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
Uint8 subformat[16]
Definition: SDL_wave.h:69
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
static WaveExtensibleGUID extensible_guids[]
Definition: SDL_wave.c:1579

◆ WaveGetRiffSizeHint()

static WaveRiffSizeHint WaveGetRiffSizeHint ( )
static

Definition at line 1440 of file SDL_wave.c.

References NULL, RiffSizeChunkSearch, RiffSizeIgnore, RiffSizeIgnoreZero, RiffSizeMaximum, RiffSizeNoHint, SDL_GetHint, SDL_HINT_WAVE_RIFF_CHUNK_SIZE, and SDL_strcmp.

Referenced by SDL_LoadWAV_RW().

1441 {
1442  const char *hint = SDL_GetHint(SDL_HINT_WAVE_RIFF_CHUNK_SIZE);
1443 
1444  if (hint != NULL) {
1445  if (SDL_strcmp(hint, "chunksearch") == 0) {
1446  return RiffSizeChunkSearch;
1447  } else if (SDL_strcmp(hint, "ignore") == 0) {
1448  return RiffSizeIgnore;
1449  } else if (SDL_strcmp(hint, "ignorezero") == 0) {
1450  return RiffSizeIgnoreZero;
1451  } else if (SDL_strcmp(hint, "maximum") == 0) {
1452  return RiffSizeMaximum;
1453  }
1454  }
1455 
1456  return RiffSizeNoHint;
1457 }
#define SDL_GetHint
#define NULL
Definition: begin_code.h:164
#define SDL_HINT_WAVE_RIFF_CHUNK_SIZE
Controls how the size of the RIFF chunk affects the loading of a WAVE file.
Definition: SDL_hints.h:1138
#define SDL_strcmp

◆ WaveGetTruncationHint()

static WaveTruncationHint WaveGetTruncationHint ( )
static

Definition at line 1460 of file SDL_wave.c.

References NULL, SDL_GetHint, SDL_HINT_WAVE_TRUNCATION, SDL_strcmp, TruncDropBlock, TruncDropFrame, TruncNoHint, TruncStrict, and TruncVeryStrict.

Referenced by SDL_LoadWAV_RW().

1461 {
1462  const char *hint = SDL_GetHint(SDL_HINT_WAVE_TRUNCATION);
1463 
1464  if (hint != NULL) {
1465  if (SDL_strcmp(hint, "verystrict") == 0) {
1466  return TruncVeryStrict;
1467  } else if (SDL_strcmp(hint, "strict") == 0) {
1468  return TruncStrict;
1469  } else if (SDL_strcmp(hint, "dropframe") == 0) {
1470  return TruncDropFrame;
1471  } else if (SDL_strcmp(hint, "dropblock") == 0) {
1472  return TruncDropBlock;
1473  }
1474  }
1475 
1476  return TruncNoHint;
1477 }
#define SDL_GetHint
#define NULL
Definition: begin_code.h:164
#define SDL_HINT_WAVE_TRUNCATION
Controls how a truncated WAVE file is handled.
Definition: SDL_hints.h:1154
#define SDL_strcmp

◆ WaveLoad()

static int WaveLoad ( SDL_RWops src,
WaveFile file,
SDL_AudioSpec spec,
Uint8 **  audio_buf,
Uint32 audio_len 
)
static

Definition at line 1771 of file SDL_wave.c.

References ALAW_CODE, AUDIO_F32LSB, AUDIO_S16LSB, AUDIO_S16SYS, AUDIO_S32LSB, AUDIO_U8, WaveFormat::bitspersample, WaveFormat::channels, SDL_AudioSpec::channels, WaveFile::chunk, DATA, WaveFormat::encoding, FACT, WaveFile::fact, WaveFile::facthint, FactIgnore, FactNoHint, FMT, WaveFile::format, SDL_AudioSpec::format, WaveChunk::fourcc, SDL_AudioSpec::freq, WaveFormat::frequency, IEEE_FLOAT_CODE, IMA_ADPCM_CODE, IMA_ADPCM_Decode(), LAW_Decode(), WaveChunk::length, MS_ADPCM_CODE, MS_ADPCM_Decode(), MULAW_CODE, NULL, PCM_CODE, PCM_Decode(), WaveChunk::position, RIFF, WaveFile::riffhint, RiffSizeChunkSearch, RiffSizeIgnore, RiffSizeIgnoreZero, RiffSizeMaximum, RW_SEEK_SET, WaveFact::samplelength, SDL_AudioSpec::samples, SDL_FALSE, SDL_getenv, SDL_MAX_SINT64, SDL_MAX_UINT32, SDL_RWread, SDL_RWseek, SDL_RWtell, SDL_SetError, SDL_sscanf, SDL_SwapLE32, SDL_TRUE, SDL_zerop, WaveChunk::size, WaveFact::status, WaveFile::trunchint, TruncStrict, TruncVeryStrict, WAVE, WaveCheckFormat(), WaveFreeChunkData(), WaveNextChunk(), WaveReadChunkData(), WaveReadFormat(), and WaveReadPartialChunkData().

Referenced by SDL_LoadWAV_RW().

1772 {
1773  int result;
1774  Uint32 chunkcount = 0;
1775  Uint32 chunkcountlimit = 10000;
1776  char *envchunkcountlimit;
1777  Sint64 RIFFstart, RIFFend, lastchunkpos;
1778  SDL_bool RIFFlengthknown = SDL_FALSE;
1779  WaveFormat *format = &file->format;
1780  WaveChunk *chunk = &file->chunk;
1781  WaveChunk RIFFchunk = {0};
1782  WaveChunk fmtchunk = {0};
1783  WaveChunk datachunk = {0};
1784 
1785  envchunkcountlimit = SDL_getenv("SDL_WAVE_CHUNK_LIMIT");
1786  if (envchunkcountlimit != NULL) {
1787  unsigned int count;
1788  if (SDL_sscanf(envchunkcountlimit, "%u", &count) == 1) {
1789  chunkcountlimit = count <= SDL_MAX_UINT32 ? count : SDL_MAX_UINT32;
1790  }
1791  }
1792 
1793  RIFFstart = SDL_RWtell(src);
1794  if (RIFFstart < 0) {
1795  return SDL_SetError("Could not seek in file");
1796  }
1797 
1798  RIFFchunk.position = RIFFstart;
1799  if (WaveNextChunk(src, &RIFFchunk) < 0) {
1800  return SDL_SetError("Could not read RIFF header");
1801  }
1802 
1803  /* Check main WAVE file identifiers. */
1804  if (RIFFchunk.fourcc == RIFF) {
1805  Uint32 formtype;
1806  /* Read the form type. "WAVE" expected. */
1807  if (SDL_RWread(src, &formtype, sizeof(Uint32), 1) != 1) {
1808  return SDL_SetError("Could not read RIFF form type");
1809  } else if (SDL_SwapLE32(formtype) != WAVE) {
1810  return SDL_SetError("RIFF form type is not WAVE (not a Waveform file)");
1811  }
1812  } else if (RIFFchunk.fourcc == WAVE) {
1813  /* RIFF chunk missing or skipped. Length unknown. */
1814  RIFFchunk.position = 0;
1815  RIFFchunk.length = 0;
1816  } else {
1817  return SDL_SetError("Could not find RIFF or WAVE identifiers (not a Waveform file)");
1818  }
1819 
1820  /* The 4-byte form type is immediately followed by the first chunk.*/
1821  chunk->position = RIFFchunk.position + 4;
1822 
1823  /* Use the RIFF chunk size to limit the search for the chunks. This is not
1824  * always reliable and the hint can be used to tune the behavior. By
1825  * default, it will never search past 4 GiB.
1826  */
1827  switch (file->riffhint) {
1828  case RiffSizeIgnore:
1829  RIFFend = RIFFchunk.position + SDL_MAX_UINT32;
1830  break;
1831  default:
1832  case RiffSizeIgnoreZero:
1833  if (RIFFchunk.length == 0) {
1834  RIFFend = RIFFchunk.position + SDL_MAX_UINT32;
1835  break;
1836  }
1837  /* fallthrough */
1838  case RiffSizeChunkSearch:
1839  RIFFend = RIFFchunk.position + RIFFchunk.length;
1840  RIFFlengthknown = SDL_TRUE;
1841  break;
1842  case RiffSizeMaximum:
1843  RIFFend = SDL_MAX_SINT64;
1844  break;
1845  }
1846 
1847  /* Step through all chunks and save information on the fmt, data, and fact
1848  * chunks. Ignore the chunks we don't know as per specification. This
1849  * currently also ignores cue, list, and slnt chunks.
1850  */
1851  while (RIFFend > chunk->position + chunk->length + (chunk->length & 1)) {
1852  /* Abort after too many chunks or else corrupt files may waste time. */
1853  if (chunkcount++ >= chunkcountlimit) {
1854  return SDL_SetError("Chunk count in WAVE file exceeds limit of %u", chunkcountlimit);
1855  }
1856 
1857  result = WaveNextChunk(src, chunk);
1858  if (result == -1) {
1859  /* Unexpected EOF. Corrupt file or I/O issues. */
1860  if (file->trunchint == TruncVeryStrict) {
1861  return SDL_SetError("Unexpected end of WAVE file");
1862  }
1863  /* Let the checks after this loop sort this issue out. */
1864  break;
1865  } else if (result == -2) {
1866  return SDL_SetError("Could not seek to WAVE chunk header");
1867  }
1868 
1869  if (chunk->fourcc == FMT) {
1870  if (fmtchunk.fourcc == FMT) {
1871  /* Multiple fmt chunks. Ignore or error? */
1872  } else {
1873  /* The fmt chunk must occur before the data chunk. */
1874  if (datachunk.fourcc == DATA) {
1875  return SDL_SetError("fmt chunk after data chunk in WAVE file");
1876  }
1877  fmtchunk = *chunk;
1878  }
1879  } else if (chunk->fourcc == DATA) {
1880  /* Only use the first data chunk. Handling the wavl list madness
1881  * may require a different approach.
1882  */
1883  if (datachunk.fourcc != DATA) {
1884  datachunk = *chunk;
1885  }
1886  } else if (chunk->fourcc == FACT) {
1887  /* The fact chunk data must be at least 4 bytes for the
1888  * dwSampleLength field. Ignore all fact chunks after the first one.
1889  */
1890  if (file->fact.status == 0) {
1891  if (chunk->length < 4) {
1892  file->fact.status = -1;
1893  } else {
1894  /* Let's use src directly, it's just too convenient. */
1895  Sint64 position = SDL_RWseek(src, chunk->position, RW_SEEK_SET);
1896  Uint32 samplelength;
1897  if (position == chunk->position && SDL_RWread(src, &samplelength, sizeof(Uint32), 1) == 1) {
1898  file->fact.status = 1;
1899  file->fact.samplelength = SDL_SwapLE32(samplelength);
1900  } else {
1901  file->fact.status = -1;
1902  }
1903  }
1904  }
1905  }
1906 
1907  /* Go through all chunks in verystrict mode or stop the search early if
1908  * all required chunks were found.
1909  */
1910  if (file->trunchint == TruncVeryStrict) {
1911  if (RIFFend < chunk->position + chunk->length) {
1912  return SDL_SetError("RIFF size truncates chunk");
1913  }
1914  } else if (fmtchunk.fourcc == FMT && datachunk.fourcc == DATA) {
1915  if (file->fact.status == 1 || file->facthint == FactIgnore || file->facthint == FactNoHint) {
1916  break;
1917  }
1918  }
1919  }
1920 
1921  /* Save the position after the last chunk. This position will be used if the
1922  * RIFF length is unknown.
1923  */
1924  lastchunkpos = chunk->position + chunk->length;
1925 
1926  /* The fmt chunk is mandatory. */
1927  if (fmtchunk.fourcc != FMT) {
1928  return SDL_SetError("Missing fmt chunk in WAVE file");
1929  }
1930  /* A data chunk must be present. */
1931  if (datachunk.fourcc != DATA) {
1932  return SDL_SetError("Missing data chunk in WAVE file");
1933  }
1934  /* Check if the last chunk has all of its data in verystrict mode. */
1935  if (file->trunchint == TruncVeryStrict) {
1936  /* data chunk is handled later. */
1937  if (chunk->fourcc != DATA && chunk->length > 0) {
1938  Uint8 tmp;
1939  Sint64 position = chunk->position + chunk->length - 1;
1940  if (SDL_RWseek(src, position, RW_SEEK_SET) != position) {
1941  return SDL_SetError("Could not seek to WAVE chunk data");
1942  } else if (SDL_RWread(src, &tmp, 1, 1) != 1) {
1943  return SDL_SetError("RIFF size truncates chunk");
1944  }
1945  }
1946  }
1947 
1948  /* Process fmt chunk. */
1949  *chunk = fmtchunk;
1950 
1951  /* No need to read more than 1046 bytes of the fmt chunk data with the
1952  * formats that are currently supported. (1046 because of MS ADPCM coefficients)
1953  */
1954  if (WaveReadPartialChunkData(src, chunk, 1046) < 0) {
1955  return SDL_SetError("Could not read data of WAVE fmt chunk");
1956  }
1957 
1958  /* The fmt chunk data must be at least 14 bytes to include all common fields.
1959  * It usually is 16 and larger depending on the header and encoding.
1960  */
1961  if (chunk->length < 14) {
1962  return SDL_SetError("Invalid WAVE fmt chunk length (too small)");
1963  } else if (chunk->size < 14) {
1964  return SDL_SetError("Could not read data of WAVE fmt chunk");
1965  } else if (WaveReadFormat(file) < 0) {
1966  return -1;
1967  } else if (WaveCheckFormat(file, (size_t)datachunk.length) < 0) {
1968  return -1;
1969  }
1970 
1971 #ifdef SDL_WAVE_DEBUG_LOG_FORMAT
1972  WaveDebugLogFormat(file);
1973 #endif
1974 #ifdef SDL_WAVE_DEBUG_DUMP_FORMAT
1975  WaveDebugDumpFormat(file, RIFFchunk.length, fmtchunk.length, datachunk.length);
1976 #endif
1977 
1978  WaveFreeChunkData(chunk);
1979 
1980  /* Process data chunk. */
1981  *chunk = datachunk;
1982 
1983  if (chunk->length > 0) {
1984  result = WaveReadChunkData(src, chunk);
1985  if (result == -1) {
1986  return -1;
1987  } else if (result == -2) {
1988  return SDL_SetError("Could not seek data of WAVE data chunk");
1989  }
1990  }
1991 
1992  if (chunk->length != chunk->size) {
1993  /* I/O issues or corrupt file. */
1994  if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
1995  return SDL_SetError("Could not read data of WAVE data chunk");
1996  }
1997  /* The decoders handle this truncation. */
1998  }
1999 
2000  /* Decode or convert the data if necessary. */
2001  switch (format->encoding) {
2002  case PCM_CODE:
2003  case IEEE_FLOAT_CODE:
2004  if (PCM_Decode(file, audio_buf, audio_len) < 0) {
2005  return -1;
2006  }
2007  break;
2008  case ALAW_CODE:
2009  case MULAW_CODE:
2010  if (LAW_Decode(file, audio_buf, audio_len) < 0) {
2011  return -1;
2012  }
2013  break;
2014  case MS_ADPCM_CODE:
2015  if (MS_ADPCM_Decode(file, audio_buf, audio_len) < 0) {
2016  return -1;
2017  }
2018  break;
2019  case IMA_ADPCM_CODE:
2020  if (IMA_ADPCM_Decode(file, audio_buf, audio_len) < 0) {
2021  return -1;
2022  }
2023  break;
2024  }
2025 
2026  /* Setting up the SDL_AudioSpec. All unsupported formats were filtered out
2027  * by checks earlier in this function.
2028  */
2029  SDL_zerop(spec);
2030  spec->freq = format->frequency;
2031  spec->channels = (Uint8)format->channels;
2032  spec->samples = 4096; /* Good default buffer size */
2033 
2034  switch (format->encoding) {
2035  case MS_ADPCM_CODE:
2036  case IMA_ADPCM_CODE:
2037  case ALAW_CODE:
2038  case MULAW_CODE:
2039  /* These can be easily stored in the byte order of the system. */
2040  spec->format = AUDIO_S16SYS;
2041  break;
2042  case IEEE_FLOAT_CODE:
2043  spec->format = AUDIO_F32LSB;
2044  break;
2045  case PCM_CODE:
2046  switch (format->bitspersample) {
2047  case 8:
2048  spec->format = AUDIO_U8;
2049  break;
2050  case 16:
2051  spec->format = AUDIO_S16LSB;
2052  break;
2053  case 24: /* Has been shifted to 32 bits. */
2054  case 32:
2055  spec->format = AUDIO_S32LSB;
2056  break;
2057  default:
2058  /* Just in case something unexpected happened in the checks. */
2059  return SDL_SetError("Unexpected %d-bit PCM data format", format->bitspersample);
2060  }
2061  break;
2062  }
2063 
2064  /* Report the end position back to the cleanup code. */
2065  if (RIFFlengthknown) {
2066  chunk->position = RIFFend;
2067  } else {
2068  chunk->position = lastchunkpos;
2069  }
2070 
2071  return 0;
2072 }
static int IMA_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
Definition: SDL_wave.c:1031
#define SDL_MAX_SINT64
A signed 64-bit integer type.
Definition: SDL_stdinc.h:208
#define PCM_CODE
Definition: SDL_wave.h:39
#define MULAW_CODE
Definition: SDL_wave.h:43
#define RIFF
Definition: SDL_wave.h:29
Uint16 bitspersample
Definition: SDL_wave.h:58
GLuint64EXT * result
Uint16 channels
Definition: SDL_wave.h:54
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
#define SDL_MAX_UINT32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:201
WaveRiffSizeHint riffhint
Definition: SDL_wave.h:144
#define SDL_RWread(ctx, ptr, size, n)
Definition: SDL_rwops.h:187
Uint16 samples
Definition: SDL_audio.h:184
static void WaveFreeChunkData(WaveChunk *chunk)
Definition: SDL_wave.c:1500
static int WaveReadPartialChunkData(SDL_RWops *src, WaveChunk *chunk, size_t length)
Definition: SDL_wave.c:1538
static int WaveReadChunkData(SDL_RWops *src, WaveChunk *chunk)
Definition: SDL_wave.c:1567
#define AUDIO_S16SYS
Definition: SDL_audio.h:123
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
static int WaveNextChunk(SDL_RWops *src, WaveChunk *chunk)
Definition: SDL_wave.c:1510
Uint32 samplelength
Definition: SDL_wave.h:90
WaveFactChunkHint facthint
Definition: SDL_wave.h:146
#define FMT
Definition: SDL_wave.h:35
#define SDL_RWseek(ctx, offset, whence)
Definition: SDL_rwops.h:185
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
static int MS_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
Definition: SDL_wave.c:638
#define AUDIO_U8
Definition: SDL_audio.h:89
#define ALAW_CODE
Definition: SDL_wave.h:42
#define DATA
Definition: SDL_wave.h:36
WaveTruncationHint trunchint
Definition: SDL_wave.h:145
#define FACT
Definition: SDL_wave.h:31
Uint8 channels
Definition: SDL_audio.h:182
Uint32 fourcc
Definition: SDL_wave.h:96
uint8_t Uint8
Definition: SDL_stdinc.h:179
size_t size
Definition: SDL_wave.h:100
Sint32 status
Definition: SDL_wave.h:80
#define SDL_SwapLE32(X)
Definition: SDL_endian.h:233
#define AUDIO_F32LSB
Definition: SDL_audio.h:112
#define WAVE
Definition: SDL_wave.h:30
#define AUDIO_S32LSB
Definition: SDL_audio.h:103
#define SDL_sscanf
WaveChunk chunk
Definition: SDL_wave.h:132
WaveFact fact
Definition: SDL_wave.h:134
#define SDL_getenv
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:161
#define IEEE_FLOAT_CODE
Definition: SDL_wave.h:41
Sint64 position
Definition: SDL_wave.h:98
#define IMA_ADPCM_CODE
Definition: SDL_wave.h:44
#define SDL_SetError
SDL_AudioFormat format
Definition: SDL_audio.h:181
uint32_t Uint32
Definition: SDL_stdinc.h:203
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
Uint32 frequency
Definition: SDL_wave.h:55
Uint32 length
Definition: SDL_wave.h:97
int64_t Sint64
Definition: SDL_stdinc.h:210
static int WaveCheckFormat(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:1663
static int LAW_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
Definition: SDL_wave.c:1161
static int PCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
Definition: SDL_wave.c:1397
#define SDL_RWtell(ctx)
Definition: SDL_rwops.h:186
static int WaveReadFormat(WaveFile *file)
Definition: SDL_wave.c:1601
Uint16 encoding
Definition: SDL_wave.h:53
#define MS_ADPCM_CODE
Definition: SDL_wave.h:40
WaveFormat format
Definition: SDL_wave.h:133

◆ WaveNextChunk()

static int WaveNextChunk ( SDL_RWops src,
WaveChunk chunk 
)
static

Definition at line 1510 of file SDL_wave.c.

References WaveChunk::fourcc, WaveChunk::length, WaveChunk::position, RW_SEEK_SET, SDL_RWread, SDL_RWseek, SDL_SwapLE32, and WaveFreeChunkData().

Referenced by WaveLoad().

1511 {
1512  Uint32 chunkheader[2];
1513  Sint64 nextposition = chunk->position + chunk->length;
1514 
1515  /* Data is no longer valid after this function returns. */
1516  WaveFreeChunkData(chunk);
1517 
1518  /* RIFF chunks have a 2-byte alignment. Skip padding byte. */
1519  if (chunk->length & 1) {
1520  nextposition++;
1521  }
1522 
1523  if (SDL_RWseek(src, nextposition, RW_SEEK_SET) != nextposition) {
1524  /* Not sure how we ended up here. Just abort. */
1525  return -2;
1526  } else if (SDL_RWread(src, chunkheader, 4, 2) != 2) {
1527  return -1;
1528  }
1529 
1530  chunk->fourcc = SDL_SwapLE32(chunkheader[0]);
1531  chunk->length = SDL_SwapLE32(chunkheader[1]);
1532  chunk->position = nextposition + 8;
1533 
1534  return 0;
1535 }
#define SDL_RWread(ctx, ptr, size, n)
Definition: SDL_rwops.h:187
static void WaveFreeChunkData(WaveChunk *chunk)
Definition: SDL_wave.c:1500
#define SDL_RWseek(ctx, offset, whence)
Definition: SDL_rwops.h:185
Uint32 fourcc
Definition: SDL_wave.h:96
#define SDL_SwapLE32(X)
Definition: SDL_endian.h:233
Sint64 position
Definition: SDL_wave.h:98
uint32_t Uint32
Definition: SDL_stdinc.h:203
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
Uint32 length
Definition: SDL_wave.h:97
int64_t Sint64
Definition: SDL_stdinc.h:210

◆ WaveReadChunkData()

static int WaveReadChunkData ( SDL_RWops src,
WaveChunk chunk 
)
static

Definition at line 1567 of file SDL_wave.c.

References WaveChunk::length, and WaveReadPartialChunkData().

Referenced by WaveLoad().

1568 {
1569  return WaveReadPartialChunkData(src, chunk, chunk->length);
1570 }
static int WaveReadPartialChunkData(SDL_RWops *src, WaveChunk *chunk, size_t length)
Definition: SDL_wave.c:1538
Uint32 length
Definition: SDL_wave.h:97

◆ WaveReadFormat()

static int WaveReadFormat ( WaveFile file)
static

Definition at line 1601 of file SDL_wave.c.

References WaveFormat::bitspersample, WaveFormat::blockalign, WaveFormat::byterate, WaveFormat::channelmask, WaveFormat::channels, WaveFile::chunk, WaveChunk::data, WaveFormat::encoding, EXTENSIBLE_CODE, WaveFormat::extsize, WaveFile::format, WaveFormat::formattag, WaveFormat::frequency, NULL, PCM_CODE, WaveFormat::samplesperblock, SDL_MAX_SINT32, SDL_OutOfMemory, SDL_ReadLE16, SDL_ReadLE32, SDL_RWclose, SDL_RWFromConstMem, SDL_RWread, SDL_SetError, WaveChunk::size, WaveFormat::subformat, WaveFormat::validsamplebits, and WaveGetFormatGUIDEncoding().

Referenced by WaveLoad().

1602 {
1603  WaveChunk *chunk = &file->chunk;
1604  WaveFormat *format = &file->format;
1605  SDL_RWops *fmtsrc;
1606  size_t fmtlen = chunk->size;
1607 
1608  if (fmtlen > SDL_MAX_SINT32) {
1609  /* Limit given by SDL_RWFromConstMem. */
1610  return SDL_SetError("Data of WAVE fmt chunk too big");
1611  }
1612  fmtsrc = SDL_RWFromConstMem(chunk->data, (int)chunk->size);
1613  if (fmtsrc == NULL) {
1614  return SDL_OutOfMemory();
1615  }
1616 
1617  format->formattag = SDL_ReadLE16(fmtsrc);
1618  format->encoding = format->formattag;
1619  format->channels = SDL_ReadLE16(fmtsrc);
1620  format->frequency = SDL_ReadLE32(fmtsrc);
1621  format->byterate = SDL_ReadLE32(fmtsrc);
1622  format->blockalign = SDL_ReadLE16(fmtsrc);
1623 
1624  /* This is PCM specific in the first version of the specification. */
1625  if (fmtlen >= 16) {
1626  format->bitspersample = SDL_ReadLE16(fmtsrc);
1627  } else if (format->encoding == PCM_CODE) {
1628  SDL_RWclose(fmtsrc);
1629  return SDL_SetError("Missing wBitsPerSample field in WAVE fmt chunk");
1630  }
1631 
1632  /* The earlier versions also don't have this field. */
1633  if (fmtlen >= 18) {
1634  format->extsize = SDL_ReadLE16(fmtsrc);
1635  }
1636 
1637  if (format->formattag == EXTENSIBLE_CODE) {
1638  /* note that this ignores channel masks, smaller valid bit counts
1639  * inside a larger container, and most subtypes. This is just enough
1640  * to get things that didn't really _need_ WAVE_FORMAT_EXTENSIBLE
1641  * to be useful working when they use this format flag.
1642  */
1643 
1644  /* Extensible header must be at least 22 bytes. */
1645  if (fmtlen < 40 || format->extsize < 22) {
1646  SDL_RWclose(fmtsrc);
1647  return SDL_SetError("Extensible WAVE header too small");
1648  }
1649 
1650  format->validsamplebits = SDL_ReadLE16(fmtsrc);
1651  format->samplesperblock = format->validsamplebits;
1652  format->channelmask = SDL_ReadLE32(fmtsrc);
1653  SDL_RWread(fmtsrc, format->subformat, 1, 16);
1654  format->encoding = WaveGetFormatGUIDEncoding(format);
1655  }
1656 
1657  SDL_RWclose(fmtsrc);
1658 
1659  return 0;
1660 }
#define PCM_CODE
Definition: SDL_wave.h:39
Uint16 extsize
Definition: SDL_wave.h:63
Uint32 channelmask
Definition: SDL_wave.h:68
Uint16 bitspersample
Definition: SDL_wave.h:58
Uint16 validsamplebits
Definition: SDL_wave.h:66
Uint16 channels
Definition: SDL_wave.h:54
#define SDL_ReadLE32
#define SDL_RWread(ctx, ptr, size, n)
Definition: SDL_rwops.h:187
#define SDL_MAX_SINT32
A signed 32-bit integer type.
Definition: SDL_stdinc.h:195
Uint32 byterate
Definition: SDL_wave.h:56
#define SDL_ReadLE16
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
#define EXTENSIBLE_CODE
Definition: SDL_wave.h:47
size_t size
Definition: SDL_wave.h:100
Uint16 blockalign
Definition: SDL_wave.h:57
WaveChunk chunk
Definition: SDL_wave.h:132
Uint8 * data
Definition: SDL_wave.h:99
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_RWclose(ctx)
Definition: SDL_rwops.h:189
#define SDL_SetError
static Uint16 WaveGetFormatGUIDEncoding(WaveFormat *format)
Definition: SDL_wave.c:1589
Uint8 subformat[16]
Definition: SDL_wave.h:69
Uint32 frequency
Definition: SDL_wave.h:55
#define SDL_RWFromConstMem
Uint16 formattag
Definition: SDL_wave.h:52
Uint16 encoding
Definition: SDL_wave.h:53
WaveFormat format
Definition: SDL_wave.h:133
Uint32 samplesperblock
Definition: SDL_wave.h:67

◆ WaveReadPartialChunkData()

static int WaveReadPartialChunkData ( SDL_RWops src,
WaveChunk chunk,
size_t  length 
)
static

Definition at line 1538 of file SDL_wave.c.

References WaveChunk::data, WaveChunk::length, NULL, WaveChunk::position, RW_SEEK_SET, SDL_malloc, SDL_OutOfMemory, SDL_RWread, SDL_RWseek, WaveChunk::size, and WaveFreeChunkData().

Referenced by WaveLoad(), and WaveReadChunkData().

1539 {
1540  WaveFreeChunkData(chunk);
1541 
1542  if (length > chunk->length) {
1543  length = chunk->length;
1544  }
1545 
1546  if (length > 0) {
1547  chunk->data = SDL_malloc(length);
1548  if (chunk->data == NULL) {
1549  return SDL_OutOfMemory();
1550  }
1551 
1552  if (SDL_RWseek(src, chunk->position, RW_SEEK_SET) != chunk->position) {
1553  /* Not sure how we ended up here. Just abort. */
1554  return -2;
1555  }
1556 
1557  chunk->size = SDL_RWread(src, chunk->data, 1, length);
1558  if (chunk->size != length) {
1559  /* Expected to be handled by the caller. */
1560  }
1561  }
1562 
1563  return 0;
1564 }
#define SDL_RWread(ctx, ptr, size, n)
Definition: SDL_rwops.h:187
static void WaveFreeChunkData(WaveChunk *chunk)
Definition: SDL_wave.c:1500
#define SDL_RWseek(ctx, offset, whence)
Definition: SDL_rwops.h:185
size_t size
Definition: SDL_wave.h:100
Uint8 * data
Definition: SDL_wave.h:99
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
Sint64 position
Definition: SDL_wave.h:98
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
#define SDL_malloc
Uint32 length
Definition: SDL_wave.h:97
GLuint GLsizei GLsizei * length

Variable Documentation

◆ extensible_guids

WaveExtensibleGUID extensible_guids[]
static
Initial value:
= {
}
#define PCM_CODE
Definition: SDL_wave.h:39
#define MULAW_CODE
Definition: SDL_wave.h:43
#define ALAW_CODE
Definition: SDL_wave.h:42
#define IEEE_FLOAT_CODE
Definition: SDL_wave.h:41
#define IMA_ADPCM_CODE
Definition: SDL_wave.h:44
#define WAVE_FORMATTAG_GUID(tag)
Definition: SDL_wave.c:1578
#define MS_ADPCM_CODE
Definition: SDL_wave.h:40

Definition at line 1579 of file SDL_wave.c.