SDL  2.0
SDL_wave.c File Reference
#include "../SDL_internal.h"
#include "SDL_hints.h"
#include "SDL_audio.h"
#include "SDL_wave.h"
#include "SDL_audio_c.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 INT_MAX   SDL_MAX_SINT32
 
#define SIZE_MAX   ((size_t)-1)
 
#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 int SafeMult (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

#define INT_MAX   SDL_MAX_SINT32

Definition at line 28 of file SDL_wave.c.

◆ SIZE_MAX

#define SIZE_MAX   ((size_t)-1)

Definition at line 31 of file SDL_wave.c.

◆ 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 1594 of file SDL_wave.c.

Function Documentation

◆ IMA_ADPCM_CalculateSampleFrames()

static int IMA_ADPCM_CalculateSampleFrames ( WaveFile file,
size_t  datalength 
)
static

Definition at line 740 of file SDL_wave.c.

741 {
742  WaveFormat *format = &file->format;
743  const size_t blockheadersize = (size_t)format->channels * 4;
744  const size_t subblockframesize = (size_t)format->channels * 4;
745  const size_t availableblocks = datalength / format->blockalign;
746  const size_t trailingdata = datalength % format->blockalign;
747 
748  if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
749  /* The size of the data chunk must be a multiple of the block size. */
750  if (datalength < blockheadersize || trailingdata > 0) {
751  return SDL_SetError("Truncated IMA ADPCM block");
752  }
753  }
754 
755  /* Calculate number of sample frames that will be decoded. */
756  file->sampleframes = (Uint64)availableblocks * format->samplesperblock;
757  if (trailingdata > 0) {
758  /* The last block is truncated. Check if we can get any samples out of it. */
759  if (file->trunchint == TruncDropFrame && trailingdata > blockheadersize - 2) {
760  /* The sample frame in the header of the truncated block is present.
761  * Drop incomplete sample frames.
762  */
763  size_t trailingsamples = 1;
764 
765  if (trailingdata > blockheadersize) {
766  /* More data following after the header. */
767  const size_t trailingblockdata = trailingdata - blockheadersize;
768  const size_t trailingsubblockdata = trailingblockdata % subblockframesize;
769  trailingsamples += (trailingblockdata / subblockframesize) * 8;
770  /* Due to the interleaved sub-blocks, the last 4 bytes determine
771  * how many samples of the truncated sub-block are lost.
772  */
773  if (trailingsubblockdata > subblockframesize - 4) {
774  trailingsamples += (trailingsubblockdata % 4) * 2;
775  }
776  }
777 
778  if (trailingsamples > format->samplesperblock) {
779  trailingsamples = format->samplesperblock;
780  }
781  file->sampleframes += trailingsamples;
782  }
783  }
784 
785  file->sampleframes = WaveAdjustToFactValue(file, file->sampleframes);
786  if (file->sampleframes < 0) {
787  return -1;
788  }
789 
790  return 0;
791 }
unsigned int size_t
#define SDL_SetError
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
uint64_t Uint64
Definition: SDL_stdinc.h:222
static Sint64 WaveAdjustToFactValue(WaveFile *file, Sint64 sampleframes)
Definition: SDL_wave.c:321
@ TruncVeryStrict
Definition: SDL_wave.h:115
@ TruncStrict
Definition: SDL_wave.h:116
@ TruncDropFrame
Definition: SDL_wave.h:117
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
WaveFormat format
Definition: SDL_wave.h:133
Sint64 sampleframes
Definition: SDL_wave.h:140
WaveTruncationHint trunchint
Definition: SDL_wave.h:145
Uint16 channels
Definition: SDL_wave.h:54

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

Referenced by IMA_ADPCM_Decode(), and IMA_ADPCM_Init().

◆ IMA_ADPCM_Decode()

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

Definition at line 1036 of file SDL_wave.c.

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

References WaveFormat::blockalign, WaveFormat::channels, WaveFile::chunk, WaveChunk::data, WaveFile::format, if, IMA_ADPCM_CalculateSampleFrames(), IMA_ADPCM_DecodeBlockData(), IMA_ADPCM_DecodeBlockHeader(), WaveChunk::length, NULL, SafeMult(), WaveFile::sampleframes, WaveFormat::samplesperblock, SDL_calloc, SDL_free, SDL_malloc, SDL_MAX_UINT32, SDL_OutOfMemory, SDL_SetError, SDL_zero, WaveChunk::size, SIZE_MAX, state, TruncDropFrame, WaveFile::trunchint, TruncStrict, and TruncVeryStrict.

Referenced by WaveLoad().

◆ IMA_ADPCM_DecodeBlockData()

static int IMA_ADPCM_DecodeBlockData ( ADPCM_DecoderState state)
static

Definition at line 966 of file SDL_wave.c.

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

References i, IMA_ADPCM_ProcessNibble(), retval, and state.

Referenced by IMA_ADPCM_Decode().

◆ IMA_ADPCM_DecodeBlockHeader()

static int IMA_ADPCM_DecodeBlockHeader ( ADPCM_DecoderState state)
static

Definition at line 926 of file SDL_wave.c.

927 {
928  Sint16 step;
929  Uint32 c;
930  Uint8 *cstate = (Uint8 *) state->cstate;
931 
932  for (c = 0; c < state->channels; c++) {
933  size_t o = state->block.pos + c * 4;
934 
935  /* Extract the sample from the header. */
936  Sint32 sample = state->block.data[o] | ((Sint32)state->block.data[o + 1] << 8);
937  if (sample >= 0x8000) {
938  sample -= 0x10000;
939  }
940  state->output.data[state->output.pos++] = (Sint16)sample;
941 
942  /* Channel step index. */
943  step = (Sint16)state->block.data[o + 2];
944  cstate[c] = (Sint8)(step > 0x80 ? step - 0x100 : step);
945 
946  /* Reserved byte in block header, should be 0. */
947  if (state->block.data[o + 3] != 0) {
948  /* Uh oh, corrupt data? Buggy code? */ ;
949  }
950  }
951 
952  state->block.pos += state->blockheadersize;
953 
954  /* Header provided one sample frame. */
955  state->framesleft--;
956 
957  return 0;
958 }
int32_t Sint32
Definition: SDL_stdinc.h:203

References state.

Referenced by IMA_ADPCM_Decode().

◆ IMA_ADPCM_Init()

static int IMA_ADPCM_Init ( WaveFile file,
size_t  datalength 
)
static

Definition at line 794 of file SDL_wave.c.

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

References WaveFile::chunk, WaveChunk::data, EXTENSIBLE_CODE, WaveFile::format, IMA_ADPCM_CalculateSampleFrames(), SDL_SetError, and WaveChunk::size.

Referenced by WaveCheckFormat().

◆ IMA_ADPCM_ProcessNibble()

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

Definition at line 860 of file SDL_wave.c.

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

Referenced by IMA_ADPCM_DecodeBlockData().

◆ LAW_Decode()

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

Definition at line 1169 of file SDL_wave.c.

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

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

Referenced by WaveLoad().

◆ LAW_Init()

static int LAW_Init ( WaveFile file,
size_t  datalength 
)
static

Definition at line 1140 of file SDL_wave.c.

1141 {
1142  WaveFormat *format = &file->format;
1143 
1144  /* Standards Update requires this to be 8. */
1145  if (format->bitspersample != 8) {
1146  return SDL_SetError("Invalid companded bits per sample of %u", (unsigned int)format->bitspersample);
1147  }
1148 
1149  /* Not going to bother with weird padding. */
1150  if (format->blockalign != format->channels) {
1151  return SDL_SetError("Unsupported block alignment");
1152  }
1153 
1154  if ((file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict)) {
1155  if (format->blockalign > 1 && datalength % format->blockalign) {
1156  return SDL_SetError("Truncated data chunk in WAVE file");
1157  }
1158  }
1159 
1160  file->sampleframes = WaveAdjustToFactValue(file, datalength / format->blockalign);
1161  if (file->sampleframes < 0) {
1162  return -1;
1163  }
1164 
1165  return 0;
1166 }

References WaveFile::format, WaveFile::sampleframes, SDL_SetError, WaveFile::trunchint, TruncStrict, TruncVeryStrict, and WaveAdjustToFactValue().

Referenced by WaveCheckFormat().

◆ MS_ADPCM_CalculateSampleFrames()

static int MS_ADPCM_CalculateSampleFrames ( WaveFile file,
size_t  datalength 
)
static

Definition at line 335 of file SDL_wave.c.

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

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

Referenced by MS_ADPCM_Decode(), and MS_ADPCM_Init().

◆ MS_ADPCM_Decode()

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

Definition at line 640 of file SDL_wave.c.

641 {
642  int result;
643  size_t bytesleft, outputsize;
644  WaveChunk *chunk = &file->chunk;
646  MS_ADPCM_ChannelState cstate[2];
647 
648  SDL_zero(state);
649  SDL_zeroa(cstate);
650 
651  if (chunk->size != chunk->length) {
652  /* Could not read everything. Recalculate number of sample frames. */
653  if (MS_ADPCM_CalculateSampleFrames(file, chunk->size) < 0) {
654  return -1;
655  }
656  }
657 
658  /* Nothing to decode, nothing to return. */
659  if (file->sampleframes == 0) {
660  *audio_buf = NULL;
661  *audio_len = 0;
662  return 0;
663  }
664 
665  state.blocksize = file->format.blockalign;
666  state.channels = file->format.channels;
667  state.blockheadersize = (size_t)state.channels * 7;
668  state.samplesperblock = file->format.samplesperblock;
669  state.framesize = state.channels * sizeof(Sint16);
670  state.ddata = file->decoderdata;
671  state.framestotal = file->sampleframes;
672  state.framesleft = state.framestotal;
673 
674  state.input.data = chunk->data;
675  state.input.size = chunk->size;
676  state.input.pos = 0;
677 
678  /* The output size in bytes. May get modified if data is truncated. */
679  outputsize = (size_t)state.framestotal;
680  if (SafeMult(&outputsize, state.framesize)) {
681  return SDL_OutOfMemory();
682  } else if (outputsize > SDL_MAX_UINT32 || state.framestotal > SIZE_MAX) {
683  return SDL_SetError("WAVE file too big");
684  }
685 
686  state.output.pos = 0;
687  state.output.size = outputsize / sizeof(Sint16);
688  state.output.data = (Sint16 *)SDL_malloc(outputsize);
689  if (state.output.data == NULL) {
690  return SDL_OutOfMemory();
691  }
692 
693  state.cstate = cstate;
694 
695  /* Decode block by block. A truncated block will stop the decoding. */
696  bytesleft = state.input.size - state.input.pos;
697  while (state.framesleft > 0 && bytesleft >= state.blockheadersize) {
698  state.block.data = state.input.data + state.input.pos;
699  state.block.size = bytesleft < state.blocksize ? bytesleft : state.blocksize;
700  state.block.pos = 0;
701 
702  if (state.output.size - state.output.pos < (Uint64)state.framesleft * state.channels) {
703  /* Somehow didn't allocate enough space for the output. */
704  SDL_free(state.output.data);
705  return SDL_SetError("Unexpected overflow in MS ADPCM decoder");
706  }
707 
708  /* Initialize decoder with the values from the block header. */
710  if (result == -1) {
711  SDL_free(state.output.data);
712  return -1;
713  }
714 
715  /* Decode the block data. It stores the samples directly in the output. */
717  if (result == -1) {
718  /* Unexpected end. Stop decoding and return partial data if necessary. */
719  if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
720  SDL_free(state.output.data);
721  return SDL_SetError("Truncated data chunk");
722  } else if (file->trunchint != TruncDropFrame) {
723  state.output.pos -= state.output.pos % (state.samplesperblock * state.channels);
724  }
725  outputsize = state.output.pos * sizeof(Sint16); /* Can't overflow, is always smaller. */
726  break;
727  }
728 
729  state.input.pos += state.block.size;
730  bytesleft = state.input.size - state.input.pos;
731  }
732 
733  *audio_buf = (Uint8 *)state.output.data;
734  *audio_len = (Uint32)outputsize;
735 
736  return 0;
737 }
#define SDL_zeroa(x)
Definition: SDL_stdinc.h:428
static int MS_ADPCM_DecodeBlockHeader(ADPCM_DecoderState *state)
Definition: SDL_wave.c:531
static int MS_ADPCM_DecodeBlockData(ADPCM_DecoderState *state)
Definition: SDL_wave.c:592
static int MS_ADPCM_CalculateSampleFrames(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:335
void * decoderdata
Definition: SDL_wave.h:142

References WaveFormat::blockalign, WaveFormat::channels, WaveFile::chunk, WaveChunk::data, WaveFile::decoderdata, WaveFile::format, if, WaveChunk::length, MS_ADPCM_CalculateSampleFrames(), MS_ADPCM_DecodeBlockData(), MS_ADPCM_DecodeBlockHeader(), NULL, SafeMult(), WaveFile::sampleframes, WaveFormat::samplesperblock, SDL_free, SDL_malloc, SDL_MAX_UINT32, SDL_OutOfMemory, SDL_SetError, SDL_zero, SDL_zeroa, WaveChunk::size, SIZE_MAX, state, TruncDropFrame, WaveFile::trunchint, TruncStrict, and TruncVeryStrict.

Referenced by WaveLoad().

◆ MS_ADPCM_DecodeBlockData()

static int MS_ADPCM_DecodeBlockData ( ADPCM_DecoderState state)
static

Definition at line 592 of file SDL_wave.c.

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

References if, MS_ADPCM_ProcessNibble(), and state.

Referenced by MS_ADPCM_Decode().

◆ MS_ADPCM_DecodeBlockHeader()

static int MS_ADPCM_DecodeBlockHeader ( ADPCM_DecoderState state)
static

Definition at line 531 of file SDL_wave.c.

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

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

Referenced by MS_ADPCM_Decode().

◆ MS_ADPCM_Init()

static int MS_ADPCM_Init ( WaveFile file,
size_t  datalength 
)
static

Definition at line 375 of file SDL_wave.c.

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

References MS_ADPCM_CoeffData::aligndummy, WaveFile::chunk, MS_ADPCM_CoeffData::coeff, MS_ADPCM_CoeffData::coeffcount, WaveChunk::data, WaveFile::decoderdata, EXTENSIBLE_CODE, WaveFile::format, i, MS_ADPCM_CalculateSampleFrames(), NULL, SDL_malloc, SDL_OutOfMemory, SDL_SetError, and WaveChunk::size.

Referenced by WaveCheckFormat().

◆ MS_ADPCM_ProcessNibble()

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

Definition at line 494 of file SDL_wave.c.

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

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

Referenced by MS_ADPCM_DecodeBlockData().

◆ PCM_ConvertSint24ToSint32()

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

Definition at line 1356 of file SDL_wave.c.

1357 {
1358  WaveFormat *format = &file->format;
1359  WaveChunk *chunk = &file->chunk;
1360  size_t i, expanded_len, sample_count;
1361  Uint8 *ptr;
1362 
1363  sample_count = (size_t)file->sampleframes;
1364  if (SafeMult(&sample_count, format->channels)) {
1365  return SDL_OutOfMemory();
1366  }
1367 
1368  expanded_len = sample_count;
1369  if (SafeMult(&expanded_len, sizeof(Sint32))) {
1370  return SDL_OutOfMemory();
1371  } else if (expanded_len > SDL_MAX_UINT32 || file->sampleframes > SIZE_MAX) {
1372  return SDL_SetError("WAVE file too big");
1373  }
1374 
1375  /* 1 to avoid allocating zero bytes, to keep static analysis happy. */
1376  ptr = (Uint8 *)SDL_realloc(chunk->data, expanded_len ? expanded_len : 1);
1377  if (ptr == NULL) {
1378  return SDL_OutOfMemory();
1379  }
1380 
1381  /* This pointer is now invalid. */
1382  chunk->data = NULL;
1383  chunk->size = 0;
1384 
1385  *audio_buf = ptr;
1386  *audio_len = (Uint32)expanded_len;
1387 
1388  /* work from end to start, since we're expanding in-place. */
1389  for (i = sample_count; i > 0; i--) {
1390  const size_t o = i - 1;
1391  uint8_t b[4];
1392 
1393  b[0] = 0;
1394  b[1] = ptr[o * 3];
1395  b[2] = ptr[o * 3 + 1];
1396  b[3] = ptr[o * 3 + 2];
1397 
1398  ptr[o * 4 + 0] = b[0];
1399  ptr[o * 4 + 1] = b[1];
1400  ptr[o * 4 + 2] = b[2];
1401  ptr[o * 4 + 3] = b[3];
1402  }
1403 
1404  return 0;
1405 }
unsigned char uint8_t
GLboolean GLboolean GLboolean b
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF ptr

References WaveFile::chunk, WaveChunk::data, WaveFile::format, i, if, NULL, ptr, SafeMult(), WaveFile::sampleframes, SDL_MAX_UINT32, SDL_OutOfMemory, SDL_realloc, SDL_SetError, WaveChunk::size, and SIZE_MAX.

Referenced by PCM_Decode().

◆ PCM_Decode()

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

Definition at line 1408 of file SDL_wave.c.

1409 {
1410  WaveFormat *format = &file->format;
1411  WaveChunk *chunk = &file->chunk;
1412  size_t outputsize;
1413 
1414  if (chunk->length != chunk->size) {
1415  file->sampleframes = WaveAdjustToFactValue(file, chunk->size / format->blockalign);
1416  if (file->sampleframes < 0) {
1417  return -1;
1418  }
1419  }
1420 
1421  /* Nothing to decode, nothing to return. */
1422  if (file->sampleframes == 0) {
1423  *audio_buf = NULL;
1424  *audio_len = 0;
1425  return 0;
1426  }
1427 
1428  /* 24-bit samples get shifted to 32 bits. */
1429  if (format->encoding == PCM_CODE && format->bitspersample == 24) {
1430  return PCM_ConvertSint24ToSint32(file, audio_buf, audio_len);
1431  }
1432 
1433  outputsize = (size_t)file->sampleframes;
1434  if (SafeMult(&outputsize, format->blockalign)) {
1435  return SDL_OutOfMemory();
1436  } else if (outputsize > SDL_MAX_UINT32 || file->sampleframes > SIZE_MAX) {
1437  return SDL_SetError("WAVE file too big");
1438  }
1439 
1440  *audio_buf = chunk->data;
1441  *audio_len = (Uint32)outputsize;
1442 
1443  /* This pointer is going to be returned to the caller. Prevent free in cleanup. */
1444  chunk->data = NULL;
1445  chunk->size = 0;
1446 
1447  return 0;
1448 }
static int PCM_ConvertSint24ToSint32(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
Definition: SDL_wave.c:1356
#define PCM_CODE
Definition: SDL_wave.h:39

References WaveFile::chunk, WaveChunk::data, WaveFile::format, if, WaveChunk::length, NULL, PCM_CODE, PCM_ConvertSint24ToSint32(), SafeMult(), WaveFile::sampleframes, SDL_MAX_UINT32, SDL_OutOfMemory, SDL_SetError, WaveChunk::size, SIZE_MAX, and WaveAdjustToFactValue().

Referenced by WaveLoad().

◆ PCM_Init()

static int PCM_Init ( WaveFile file,
size_t  datalength 
)
static

Definition at line 1312 of file SDL_wave.c.

1313 {
1314  WaveFormat *format = &file->format;
1315 
1316  if (format->encoding == PCM_CODE) {
1317  switch (format->bitspersample) {
1318  case 8:
1319  case 16:
1320  case 24:
1321  case 32:
1322  /* These are supported. */
1323  break;
1324  default:
1325  return SDL_SetError("%u-bit PCM format not supported", (unsigned int)format->bitspersample);
1326  }
1327  } else if (format->encoding == IEEE_FLOAT_CODE) {
1328  if (format->bitspersample != 32) {
1329  return SDL_SetError("%u-bit IEEE floating-point format not supported", (unsigned int)format->bitspersample);
1330  }
1331  }
1332 
1333  /* It wouldn't be that hard to support more exotic block sizes, but
1334  * the most common formats should do for now.
1335  */
1336  /* Make sure we're a multiple of the blockalign, at least. */
1337  if ((format->channels * format->bitspersample) % (format->blockalign * 8)) {
1338  return SDL_SetError("Unsupported block alignment");
1339  }
1340 
1341  if ((file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict)) {
1342  if (format->blockalign > 1 && datalength % format->blockalign) {
1343  return SDL_SetError("Truncated data chunk in WAVE file");
1344  }
1345  }
1346 
1347  file->sampleframes = WaveAdjustToFactValue(file, datalength / format->blockalign);
1348  if (file->sampleframes < 0) {
1349  return -1;
1350  }
1351 
1352  return 0;
1353 }
#define IEEE_FLOAT_CODE
Definition: SDL_wave.h:41

References WaveFile::format, IEEE_FLOAT_CODE, PCM_CODE, WaveFile::sampleframes, SDL_SetError, WaveFile::trunchint, TruncStrict, TruncVeryStrict, and WaveAdjustToFactValue().

Referenced by WaveCheckFormat().

◆ SafeMult()

static int SafeMult ( size_t f1,
size_t  f2 
)
static

Definition at line 47 of file SDL_wave.c.

48 {
49  if (*f1 > 0 && SIZE_MAX / *f1 <= f2) {
50  return -1;
51  }
52  *f1 *= f2;
53  return 0;
54 }

References SIZE_MAX.

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

◆ SDL_FreeWAV()

void SDL_FreeWAV ( Uint8 audio_buf)

This function frees data previously allocated with SDL_LoadWAV_RW()

Definition at line 2150 of file SDL_wave.c.

2151 {
2152  SDL_free(audio_buf);
2153 }

References 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, ...);
#define SDL_RWFromFile
#define SDL_LoadWAV_RW
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 2097 of file SDL_wave.c.

2098 {
2099  int result;
2100  WaveFile file;
2101 
2102  SDL_zero(file);
2103 
2104  /* Make sure we are passed a valid data source */
2105  if (src == NULL) {
2106  /* Error may come from RWops. */
2107  return NULL;
2108  } else if (spec == NULL) {
2109  SDL_InvalidParamError("spec");
2110  return NULL;
2111  } else if (audio_buf == NULL) {
2112  SDL_InvalidParamError("audio_buf");
2113  return NULL;
2114  } else if (audio_len == NULL) {
2115  SDL_InvalidParamError("audio_len");
2116  return NULL;
2117  }
2118 
2119  *audio_buf = NULL;
2120  *audio_len = 0;
2121 
2122  file.riffhint = WaveGetRiffSizeHint();
2124  file.facthint = WaveGetFactChunkHint();
2125 
2126  result = WaveLoad(src, &file, spec, audio_buf, audio_len);
2127  if (result < 0) {
2128  SDL_free(*audio_buf);
2129  spec = NULL;
2130  audio_buf = NULL;
2131  audio_len = 0;
2132  }
2133 
2134  /* Cleanup */
2135  if (freesrc) {
2136  SDL_RWclose(src);
2137  } else {
2139  }
2140  WaveFreeChunkData(&file.chunk);
2141  SDL_free(file.decoderdata);
2142 
2143  return spec;
2144 }
#define SDL_RWseek
#define SDL_RWclose
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:90
#define RW_SEEK_SET
Definition: SDL_rwops.h:166
static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
Definition: SDL_wave.c:1787
static WaveTruncationHint WaveGetTruncationHint()
Definition: SDL_wave.c:1471
static WaveRiffSizeHint WaveGetRiffSizeHint()
Definition: SDL_wave.c:1451
static void WaveFreeChunkData(WaveChunk *chunk)
Definition: SDL_wave.c:1511
static WaveFactChunkHint WaveGetFactChunkHint()
Definition: SDL_wave.c:1491
SDL_AudioSpec spec
Definition: loopwave.c:31
Sint64 position
Definition: SDL_wave.h:98
WaveFactChunkHint facthint
Definition: SDL_wave.h:146
WaveRiffSizeHint riffhint
Definition: SDL_wave.h:144

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

◆ WaveAdjustToFactValue()

static Sint64 WaveAdjustToFactValue ( WaveFile file,
Sint64  sampleframes 
)
static

Definition at line 321 of file SDL_wave.c.

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

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().

◆ WaveCheckFormat()

static int WaveCheckFormat ( WaveFile file,
size_t  datalength 
)
static

Definition at line 1679 of file SDL_wave.c.

1680 {
1681  WaveFormat *format = &file->format;
1682 
1683  /* Check for some obvious issues. */
1684 
1685  if (format->channels == 0) {
1686  return SDL_SetError("Invalid number of channels");
1687  } else if (format->channels > 255) {
1688  /* Limit given by SDL_AudioSpec.channels. */
1689  return SDL_SetError("Number of channels exceeds limit of 255");
1690  }
1691 
1692  if (format->frequency == 0) {
1693  return SDL_SetError("Invalid sample rate");
1694  } else if (format->frequency > INT_MAX) {
1695  /* Limit given by SDL_AudioSpec.freq. */
1696  return SDL_SetError("Sample rate exceeds limit of %d", INT_MAX);
1697  }
1698 
1699  /* Reject invalid fact chunks in strict mode. */
1700  if (file->facthint == FactStrict && file->fact.status == -1) {
1701  return SDL_SetError("Invalid fact chunk in WAVE file");
1702  }
1703 
1704  /* Check for issues common to all encodings. Some unsupported formats set
1705  * the bits per sample to zero. These fall through to the 'unsupported
1706  * format' error.
1707  */
1708  switch (format->encoding) {
1709  case IEEE_FLOAT_CODE:
1710  case ALAW_CODE:
1711  case MULAW_CODE:
1712  case MS_ADPCM_CODE:
1713  case IMA_ADPCM_CODE:
1714  /* These formats require a fact chunk. */
1715  if (file->facthint == FactStrict && file->fact.status <= 0) {
1716  return SDL_SetError("Missing fact chunk in WAVE file");
1717  }
1718  /* fallthrough */
1719  case PCM_CODE:
1720  /* All supported formats require a non-zero bit depth. */
1721  if (file->chunk.size < 16) {
1722  return SDL_SetError("Missing wBitsPerSample field in WAVE fmt chunk");
1723  } else if (format->bitspersample == 0) {
1724  return SDL_SetError("Invalid bits per sample");
1725  }
1726 
1727  /* All supported formats must have a proper block size. */
1728  if (format->blockalign == 0) {
1729  return SDL_SetError("Invalid block alignment");
1730  }
1731 
1732  /* If the fact chunk is valid and the appropriate hint is set, the
1733  * decoders will use the number of sample frames from the fact chunk.
1734  */
1735  if (file->fact.status == 1) {
1736  WaveFactChunkHint hint = file->facthint;
1737  Uint32 samples = file->fact.samplelength;
1738  if (hint == FactTruncate || hint == FactStrict || (hint == FactIgnoreZero && samples > 0)) {
1739  file->fact.status = 2;
1740  }
1741  }
1742  }
1743 
1744  /* Check the format for encoding specific issues and initialize decoders. */
1745  switch (format->encoding) {
1746  case PCM_CODE:
1747  case IEEE_FLOAT_CODE:
1748  if (PCM_Init(file, datalength) < 0) {
1749  return -1;
1750  }
1751  break;
1752  case ALAW_CODE:
1753  case MULAW_CODE:
1754  if (LAW_Init(file, datalength) < 0) {
1755  return -1;
1756  }
1757  break;
1758  case MS_ADPCM_CODE:
1759  if (MS_ADPCM_Init(file, datalength) < 0) {
1760  return -1;
1761  }
1762  break;
1763  case IMA_ADPCM_CODE:
1764  if (IMA_ADPCM_Init(file, datalength) < 0) {
1765  return -1;
1766  }
1767  break;
1768  case MPEG_CODE:
1769  case MPEGLAYER3_CODE:
1770  return SDL_SetError("MPEG formats not supported");
1771  default:
1772  if (format->formattag == EXTENSIBLE_CODE) {
1773  const char *errstr = "Unknown WAVE format GUID: %08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x";
1774  const Uint8 *g = format->subformat;
1775  const Uint32 g1 = g[0] | ((Uint32)g[1] << 8) | ((Uint32)g[2] << 16) | ((Uint32)g[3] << 24);
1776  const Uint32 g2 = g[4] | ((Uint32)g[5] << 8);
1777  const Uint32 g3 = g[6] | ((Uint32)g[7] << 8);
1778  return SDL_SetError(errstr, g1, g2, g3, g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15]);
1779  }
1780  return SDL_SetError("Unknown WAVE format tag: 0x%04x", (unsigned int)format->encoding);
1781  }
1782 
1783  return 0;
1784 }
GLsizei samples
GLboolean GLboolean g
static int IMA_ADPCM_Init(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:794
static int PCM_Init(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:1312
#define INT_MAX
Definition: SDL_wave.c:28
static int MS_ADPCM_Init(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:375
static int LAW_Init(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:1140
#define MPEG_CODE
Definition: SDL_wave.h:45
#define IMA_ADPCM_CODE
Definition: SDL_wave.h:44
#define MS_ADPCM_CODE
Definition: SDL_wave.h:40
#define MPEGLAYER3_CODE
Definition: SDL_wave.h:46
WaveFactChunkHint
Definition: SDL_wave.h:122
@ FactTruncate
Definition: SDL_wave.h:124
@ FactIgnoreZero
Definition: SDL_wave.h:126

References ALAW_CODE, WaveFile::chunk, EXTENSIBLE_CODE, WaveFile::fact, WaveFile::facthint, FactIgnoreZero, FactStrict, FactTruncate, WaveFile::format, 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, and WaveFact::status.

Referenced by WaveLoad().

◆ WaveFreeChunkData()

static void WaveFreeChunkData ( WaveChunk chunk)
static

Definition at line 1511 of file SDL_wave.c.

1512 {
1513  if (chunk->data != NULL) {
1514  SDL_free(chunk->data);
1515  chunk->data = NULL;
1516  }
1517  chunk->size = 0;
1518 }

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

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

◆ WaveGetFactChunkHint()

static WaveFactChunkHint WaveGetFactChunkHint ( )
static

Definition at line 1491 of file SDL_wave.c.

1492 {
1493  const char *hint = SDL_GetHint(SDL_HINT_WAVE_FACT_CHUNK);
1494 
1495  if (hint != NULL) {
1496  if (SDL_strcmp(hint, "truncate") == 0) {
1497  return FactTruncate;
1498  } else if (SDL_strcmp(hint, "strict") == 0) {
1499  return FactStrict;
1500  } else if (SDL_strcmp(hint, "ignorezero") == 0) {
1501  return FactIgnoreZero;
1502  } else if (SDL_strcmp(hint, "ignore") == 0) {
1503  return FactIgnore;
1504  }
1505  }
1506 
1507  return FactNoHint;
1508 }
#define SDL_strcmp
#define SDL_GetHint
#define SDL_HINT_WAVE_FACT_CHUNK
Controls how the fact chunk affects the loading of a WAVE file.
Definition: SDL_hints.h:1416
@ FactIgnore
Definition: SDL_wave.h:127
@ FactNoHint
Definition: SDL_wave.h:123

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

Referenced by SDL_LoadWAV_RW().

◆ WaveGetFormatGUIDEncoding()

static Uint16 WaveGetFormatGUIDEncoding ( WaveFormat format)
static

Definition at line 1605 of file SDL_wave.c.

1606 {
1607  size_t i;
1608  for (i = 0; i < SDL_arraysize(extensible_guids); i++) {
1609  if (SDL_memcmp(format->subformat, extensible_guids[i].guid, 16) == 0) {
1610  return extensible_guids[i].encoding;
1611  }
1612  }
1613  return UNKNOWN_CODE;
1614 }
#define SDL_memcmp
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:121
static WaveExtensibleGUID extensible_guids[]
Definition: SDL_wave.c:1595
#define UNKNOWN_CODE
Definition: SDL_wave.h:38
Uint8 guid[16]
Definition: SDL_wave.c:1590

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

Referenced by WaveReadFormat().

◆ WaveGetRiffSizeHint()

static WaveRiffSizeHint WaveGetRiffSizeHint ( )
static

Definition at line 1451 of file SDL_wave.c.

1452 {
1453  const char *hint = SDL_GetHint(SDL_HINT_WAVE_RIFF_CHUNK_SIZE);
1454 
1455  if (hint != NULL) {
1456  if (SDL_strcmp(hint, "force") == 0) {
1457  return RiffSizeForce;
1458  } else if (SDL_strcmp(hint, "ignore") == 0) {
1459  return RiffSizeIgnore;
1460  } else if (SDL_strcmp(hint, "ignorezero") == 0) {
1461  return RiffSizeIgnoreZero;
1462  } else if (SDL_strcmp(hint, "maximum") == 0) {
1463  return RiffSizeMaximum;
1464  }
1465  }
1466 
1467  return RiffSizeNoHint;
1468 }
#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:1373
@ RiffSizeNoHint
Definition: SDL_wave.h:105
@ RiffSizeForce
Definition: SDL_wave.h:106
@ RiffSizeMaximum
Definition: SDL_wave.h:109
@ RiffSizeIgnore
Definition: SDL_wave.h:108
@ RiffSizeIgnoreZero
Definition: SDL_wave.h:107

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

Referenced by SDL_LoadWAV_RW().

◆ WaveGetTruncationHint()

static WaveTruncationHint WaveGetTruncationHint ( )
static

Definition at line 1471 of file SDL_wave.c.

1472 {
1473  const char *hint = SDL_GetHint(SDL_HINT_WAVE_TRUNCATION);
1474 
1475  if (hint != NULL) {
1476  if (SDL_strcmp(hint, "verystrict") == 0) {
1477  return TruncVeryStrict;
1478  } else if (SDL_strcmp(hint, "strict") == 0) {
1479  return TruncStrict;
1480  } else if (SDL_strcmp(hint, "dropframe") == 0) {
1481  return TruncDropFrame;
1482  } else if (SDL_strcmp(hint, "dropblock") == 0) {
1483  return TruncDropBlock;
1484  }
1485  }
1486 
1487  return TruncNoHint;
1488 }
#define SDL_HINT_WAVE_TRUNCATION
Controls how a truncated WAVE file is handled.
Definition: SDL_hints.h:1389
@ TruncDropBlock
Definition: SDL_wave.h:118
@ TruncNoHint
Definition: SDL_wave.h:114

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

Referenced by SDL_LoadWAV_RW().

◆ WaveLoad()

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

Definition at line 1787 of file SDL_wave.c.

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

References ALAW_CODE, AUDIO_F32LSB, AUDIO_S16LSB, AUDIO_S16SYS, AUDIO_S32LSB, AUDIO_U8, SDL_AudioSpec::channels, WaveFile::chunk, DATA, FACT, WaveFile::fact, WaveFile::facthint, FactIgnore, FactNoHint, FMT, SDL_AudioSpec::format, WaveFile::format, WaveChunk::fourcc, SDL_AudioSpec::freq, IEEE_FLOAT_CODE, if, 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, RiffSizeForce, 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_SilenceValueForFormat(), SDL_sscanf, SDL_SwapLE32, SDL_TRUE, SDL_zero, SDL_zerop, SDL_AudioSpec::silence, WaveChunk::size, spec, WaveFact::status, WaveFile::trunchint, TruncStrict, TruncVeryStrict, WAVE, WaveCheckFormat(), WaveFreeChunkData(), WaveNextChunk(), WaveReadChunkData(), WaveReadFormat(), and WaveReadPartialChunkData().

Referenced by SDL_LoadWAV_RW().

◆ WaveNextChunk()

static int WaveNextChunk ( SDL_RWops src,
WaveChunk chunk 
)
static

Definition at line 1521 of file SDL_wave.c.

1522 {
1523  Uint32 chunkheader[2];
1524  Sint64 nextposition = chunk->position + chunk->length;
1525 
1526  /* Data is no longer valid after this function returns. */
1527  WaveFreeChunkData(chunk);
1528 
1529  /* Error on overflows. */
1530  if (SDL_MAX_SINT64 - chunk->length < chunk->position || SDL_MAX_SINT64 - 8 < nextposition) {
1531  return -1;
1532  }
1533 
1534  /* RIFF chunks have a 2-byte alignment. Skip padding byte. */
1535  if (chunk->length & 1) {
1536  nextposition++;
1537  }
1538 
1539  if (SDL_RWseek(src, nextposition, RW_SEEK_SET) != nextposition) {
1540  /* Not sure how we ended up here. Just abort. */
1541  return -2;
1542  } else if (SDL_RWread(src, chunkheader, 4, 2) != 2) {
1543  return -1;
1544  }
1545 
1546  chunk->fourcc = SDL_SwapLE32(chunkheader[0]);
1547  chunk->length = SDL_SwapLE32(chunkheader[1]);
1548  chunk->position = nextposition + 8;
1549 
1550  return 0;
1551 }

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

Referenced by WaveLoad().

◆ WaveReadChunkData()

static int WaveReadChunkData ( SDL_RWops src,
WaveChunk chunk 
)
static

Definition at line 1583 of file SDL_wave.c.

1584 {
1585  return WaveReadPartialChunkData(src, chunk, chunk->length);
1586 }

References WaveChunk::length, and WaveReadPartialChunkData().

Referenced by WaveLoad().

◆ WaveReadFormat()

static int WaveReadFormat ( WaveFile file)
static

Definition at line 1617 of file SDL_wave.c.

1618 {
1619  WaveChunk *chunk = &file->chunk;
1620  WaveFormat *format = &file->format;
1621  SDL_RWops *fmtsrc;
1622  size_t fmtlen = chunk->size;
1623 
1624  if (fmtlen > SDL_MAX_SINT32) {
1625  /* Limit given by SDL_RWFromConstMem. */
1626  return SDL_SetError("Data of WAVE fmt chunk too big");
1627  }
1628  fmtsrc = SDL_RWFromConstMem(chunk->data, (int)chunk->size);
1629  if (fmtsrc == NULL) {
1630  return SDL_OutOfMemory();
1631  }
1632 
1633  format->formattag = SDL_ReadLE16(fmtsrc);
1634  format->encoding = format->formattag;
1635  format->channels = SDL_ReadLE16(fmtsrc);
1636  format->frequency = SDL_ReadLE32(fmtsrc);
1637  format->byterate = SDL_ReadLE32(fmtsrc);
1638  format->blockalign = SDL_ReadLE16(fmtsrc);
1639 
1640  /* This is PCM specific in the first version of the specification. */
1641  if (fmtlen >= 16) {
1642  format->bitspersample = SDL_ReadLE16(fmtsrc);
1643  } else if (format->encoding == PCM_CODE) {
1644  SDL_RWclose(fmtsrc);
1645  return SDL_SetError("Missing wBitsPerSample field in WAVE fmt chunk");
1646  }
1647 
1648  /* The earlier versions also don't have this field. */
1649  if (fmtlen >= 18) {
1650  format->extsize = SDL_ReadLE16(fmtsrc);
1651  }
1652 
1653  if (format->formattag == EXTENSIBLE_CODE) {
1654  /* note that this ignores channel masks, smaller valid bit counts
1655  * inside a larger container, and most subtypes. This is just enough
1656  * to get things that didn't really _need_ WAVE_FORMAT_EXTENSIBLE
1657  * to be useful working when they use this format flag.
1658  */
1659 
1660  /* Extensible header must be at least 22 bytes. */
1661  if (fmtlen < 40 || format->extsize < 22) {
1662  SDL_RWclose(fmtsrc);
1663  return SDL_SetError("Extensible WAVE header too small");
1664  }
1665 
1666  format->validsamplebits = SDL_ReadLE16(fmtsrc);
1667  format->samplesperblock = format->validsamplebits;
1668  format->channelmask = SDL_ReadLE32(fmtsrc);
1669  SDL_RWread(fmtsrc, format->subformat, 1, 16);
1671  }
1672 
1673  SDL_RWclose(fmtsrc);
1674 
1675  return 0;
1676 }
#define SDL_RWFromConstMem
#define SDL_ReadLE16
#define SDL_ReadLE32
#define SDL_MAX_SINT32
A signed 32-bit integer type.
Definition: SDL_stdinc.h:201
static Uint16 WaveGetFormatGUIDEncoding(WaveFormat *format)
Definition: SDL_wave.c:1605

References WaveFile::chunk, WaveChunk::data, EXTENSIBLE_CODE, WaveFile::format, NULL, PCM_CODE, SDL_MAX_SINT32, SDL_OutOfMemory, SDL_ReadLE16, SDL_ReadLE32, SDL_RWclose, SDL_RWFromConstMem, SDL_RWread, SDL_SetError, WaveChunk::size, and WaveGetFormatGUIDEncoding().

Referenced by WaveLoad().

◆ WaveReadPartialChunkData()

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

Definition at line 1554 of file SDL_wave.c.

1555 {
1556  WaveFreeChunkData(chunk);
1557 
1558  if (length > chunk->length) {
1559  length = chunk->length;
1560  }
1561 
1562  if (length > 0) {
1563  chunk->data = (Uint8 *) SDL_malloc(length);
1564  if (chunk->data == NULL) {
1565  return SDL_OutOfMemory();
1566  }
1567 
1568  if (SDL_RWseek(src, chunk->position, RW_SEEK_SET) != chunk->position) {
1569  /* Not sure how we ended up here. Just abort. */
1570  return -2;
1571  }
1572 
1573  chunk->size = SDL_RWread(src, chunk->data, 1, length);
1574  if (chunk->size != length) {
1575  /* Expected to be handled by the caller. */
1576  }
1577  }
1578 
1579  return 0;
1580 }
GLuint GLsizei GLsizei * length

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().

Variable Documentation

◆ extensible_guids