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

◆ SIZE_MAX

#define SIZE_MAX   ((size_t)-1)

Definition at line 27 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 741 of file SDL_wave.c.

742{
743 WaveFormat *format = &file->format;
744 const size_t blockheadersize = (size_t)format->channels * 4;
745 const size_t subblockframesize = (size_t)format->channels * 4;
746 const size_t availableblocks = datalength / format->blockalign;
747 const size_t trailingdata = datalength % format->blockalign;
748
749 if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
750 /* The size of the data chunk must be a multiple of the block size. */
751 if (datalength < blockheadersize || trailingdata > 0) {
752 return SDL_SetError("Truncated IMA ADPCM block");
753 }
754 }
755
756 /* Calculate number of sample frames that will be decoded. */
757 file->sampleframes = (Uint64)availableblocks * format->samplesperblock;
758 if (trailingdata > 0) {
759 /* The last block is truncated. Check if we can get any samples out of it. */
760 if (file->trunchint == TruncDropFrame && trailingdata > blockheadersize - 2) {
761 /* The sample frame in the header of the truncated block is present.
762 * Drop incomplete sample frames.
763 */
764 size_t trailingsamples = 1;
765
766 if (trailingdata > blockheadersize) {
767 /* More data following after the header. */
768 const size_t trailingblockdata = trailingdata - blockheadersize;
769 const size_t trailingsubblockdata = trailingblockdata % subblockframesize;
770 trailingsamples += (trailingblockdata / subblockframesize) * 8;
771 /* Due to the interleaved sub-blocks, the last 4 bytes determine
772 * how many samples of the truncated sub-block are lost.
773 */
774 if (trailingsubblockdata > subblockframesize - 4) {
775 trailingsamples += (trailingsubblockdata % 4) * 2;
776 }
777 }
778
779 if (trailingsamples > format->samplesperblock) {
780 trailingsamples = format->samplesperblock;
781 }
782 file->sampleframes += trailingsamples;
783 }
784 }
785
787 if (file->sampleframes < 0) {
788 return -1;
789 }
790
791 return 0;
792}
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:216
static Sint64 WaveAdjustToFactValue(WaveFile *file, Sint64 sampleframes)
Definition: SDL_wave.c:322
@ TruncVeryStrict
Definition: SDL_wave.h:115
@ TruncStrict
Definition: SDL_wave.h:116
@ TruncDropFrame
Definition: SDL_wave.h:117
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, 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 1037 of file SDL_wave.c.

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

Referenced by WaveLoad().

◆ IMA_ADPCM_DecodeBlockData()

static int IMA_ADPCM_DecodeBlockData ( ADPCM_DecoderState state)
static

Definition at line 967 of file SDL_wave.c.

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

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

References state.

Referenced by IMA_ADPCM_Decode().

◆ IMA_ADPCM_Init()

static int IMA_ADPCM_Init ( WaveFile file,
size_t  datalength 
)
static

Definition at line 795 of file SDL_wave.c.

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

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

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

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

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

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

References WaveFormat::bitspersample, WaveFormat::blockalign, WaveFormat::channels, WaveFile::format, 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 641 of file SDL_wave.c.

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

References WaveFormat::blockalign, WaveFormat::channels, WaveFile::chunk, WaveChunk::data, WaveFile::decoderdata, WaveFile::format, 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, WaveChunk::size, SIZE_MAX, state, TruncDropFrame, WaveFile::trunchint, and TruncVeryStrict.

Referenced by WaveLoad().

◆ MS_ADPCM_DecodeBlockData()

static int MS_ADPCM_DecodeBlockData ( ADPCM_DecoderState state)
static

Definition at line 593 of file SDL_wave.c.

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

References 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 532 of file SDL_wave.c.

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

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

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

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

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

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

References WaveFile::chunk, WaveChunk::data, WaveFile::format, i, NULL, 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, 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 1313 of file SDL_wave.c.

1314{
1315 WaveFormat *format = &file->format;
1316
1317 if (format->encoding == PCM_CODE) {
1318 switch (format->bitspersample) {
1319 case 8:
1320 case 16:
1321 case 24:
1322 case 32:
1323 /* These are supported. */
1324 break;
1325 default:
1326 return SDL_SetError("%u-bit PCM format not supported", (unsigned int)format->bitspersample);
1327 }
1328 } else if (format->encoding == IEEE_FLOAT_CODE) {
1329 if (format->bitspersample != 32) {
1330 return SDL_SetError("%u-bit IEEE floating-point format not supported", (unsigned int)format->bitspersample);
1331 }
1332 }
1333
1334 /* It wouldn't be that hard to support more exotic block sizes, but
1335 * the most common formats should do for now.
1336 */
1337 if (format->blockalign * 8 != format->channels * format->bitspersample) {
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 48 of file SDL_wave.c.

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

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

2149{
2150 SDL_free(audio_buf);
2151}

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

2096{
2097 int result;
2098 WaveFile file;
2099
2100 SDL_zero(file);
2101
2102 /* Make sure we are passed a valid data source */
2103 if (src == NULL) {
2104 /* Error may come from RWops. */
2105 return NULL;
2106 } else if (spec == NULL) {
2107 SDL_InvalidParamError("spec");
2108 return NULL;
2109 } else if (audio_buf == NULL) {
2110 SDL_InvalidParamError("audio_buf");
2111 return NULL;
2112 } else if (audio_len == NULL) {
2113 SDL_InvalidParamError("audio_len");
2114 return NULL;
2115 }
2116
2117 *audio_buf = NULL;
2118 *audio_len = 0;
2119
2123
2124 result = WaveLoad(src, &file, spec, audio_buf, audio_len);
2125 if (result < 0) {
2126 SDL_free(*audio_buf);
2127 spec = NULL;
2128 audio_buf = NULL;
2129 audio_len = 0;
2130 }
2131
2132 /* Cleanup */
2133 if (freesrc) {
2135 } else {
2137 }
2138 WaveFreeChunkData(&file.chunk);
2139 SDL_free(file.decoderdata);
2140
2141 return spec;
2142}
#define SDL_RWseek
#define SDL_RWclose
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
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 322 of file SDL_wave.c.

323{
324 if (file->fact.status == 2) {
325 if (file->facthint == FactStrict && sampleframes < file->fact.samplelength) {
326 return SDL_SetError("Invalid number of sample frames in WAVE fact chunk (too many)");
327 } else if (sampleframes > file->fact.samplelength) {
328 return file->fact.samplelength;
329 }
330 }
331
332 return sampleframes;
333}
@ 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;
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:795
static int PCM_Init(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:1313
#define INT_MAX
Definition: SDL_wave.c:31
static int MS_ADPCM_Init(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:376
static int LAW_Init(WaveFile *file, size_t datalength)
Definition: SDL_wave.c:1141
#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:1175
@ 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:115
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:1132
@ 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:1148
@ 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
2084 /* Report the end position back to the cleanup code. */
2085 if (RIFFlengthknown) {
2086 chunk->position = RIFFend;
2087 } else {
2088 chunk->position = lastchunkpos;
2089 }
2090
2091 return 0;
2092}
#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:233
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
#define SDL_MAX_SINT64
A signed 64-bit integer type.
Definition: SDL_stdinc.h:208
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
static int MS_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
Definition: SDL_wave.c:641
static int LAW_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
Definition: SDL_wave.c:1170
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:1037
#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
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, 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_sscanf, SDL_SwapLE32, SDL_TRUE, SDL_zero, SDL_zerop, 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:195
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 = 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