summarylogtreecommitdiffstats
path: root/sdl_sound-ima-adpcm.patch
diff options
context:
space:
mode:
Diffstat (limited to 'sdl_sound-ima-adpcm.patch')
-rw-r--r--sdl_sound-ima-adpcm.patch365
1 files changed, 365 insertions, 0 deletions
diff --git a/sdl_sound-ima-adpcm.patch b/sdl_sound-ima-adpcm.patch
new file mode 100644
index 000000000000..bf6ba7383810
--- /dev/null
+++ b/sdl_sound-ima-adpcm.patch
@@ -0,0 +1,365 @@
+diff -r 719dade41745 decoders/wav.c
+--- a/decoders/wav.c Wed Aug 15 23:52:18 2012 -0400
++++ b/decoders/wav.c Fri Sep 12 06:50:35 2014 +0200
+@@ -113,8 +113,9 @@
+
+ #define fmtID 0x20746D66 /* "fmt ", in ascii. */
+
+-#define FMT_NORMAL 0x0001 /* Uncompressed waveform data. */
+-#define FMT_ADPCM 0x0002 /* ADPCM compressed waveform data. */
++#define FMT_NORMAL 0x0001 /* Uncompressed waveform data. */
++#define FMT_ADPCM 0x0002 /* ADPCM compressed waveform data. */
++#define FMT_IMA 0x0011 /* IMA ADPCM compressed waveform data. */
+
+ typedef struct
+ {
+@@ -130,6 +131,12 @@
+ Sint16 iSamp2;
+ } ADPCMBLOCKHEADER;
+
++typedef struct
++{
++ Sint16 iPrevSamp;
++ Uint8 iStepIndex;
++} IMAADPCMDATA;
++
+ typedef struct S_WAV_FMT_T
+ {
+ Uint32 chunkID;
+@@ -166,6 +173,25 @@
+ Sint8 nibble;
+ } adpcm;
+
++ struct
++ {
++ /* per channel decoder state */
++ IMAADPCMDATA *d;
++ /* auxiliary buffer */
++ Uint8 *buf;
++
++ Uint16 block_frames;
++ Uint16 block_framesets;
++ Uint16 enc_frameset_size;
++ Uint16 headerset_size;
++ Uint16 dec_frame_size;
++ Uint16 dec_frameset_size;
++ Uint16 rem_block_framesets;
++
++ /* whether the next word(s) are the start of a new block */
++ int read_header;
++ } ima;
++
+ /* put other format-specific data here... */
+ } fmt;
+ } fmt_t;
+@@ -614,6 +640,296 @@
+
+
+ /*****************************************************************************
++ * IMA ADPCM compression handler... *
++ *****************************************************************************/
++
++static const int ima_index_table[16] =
++{
++ -1, -1, -1, -1, 2, 4, 6, 8,
++ -1, -1, -1, -1, 2, 4, 6, 8
++};
++
++static const int ima_step_table[89] =
++{
++ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
++ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
++ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
++ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
++ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
++ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
++ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
++ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
++ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
++};
++
++/* 1 frameset = 4 bytes (per channel) = 8 nibbles = 8 frames */
++#define FRAMESET_FRAMES 8
++
++
++static int read_ima_block_headers(SDL_RWops *rw, IMAADPCMDATA *d,
++ Uint16 chan_count, Sint16 *out)
++{
++ Uint16 i;
++ Uint8 dummy;
++
++ for (i = 0; i < chan_count; i++)
++ {
++ BAIL_IF_MACRO(!read_le16(rw, &d[i].iPrevSamp), NULL, 0);
++ BAIL_IF_MACRO(!read_uint8(rw, &d[i].iStepIndex), NULL, 0);
++ BAIL_IF_MACRO(!read_uint8(rw, &dummy), NULL, 0);
++
++ out[i] = d[i].iPrevSamp;
++ } /* for */
++
++ return(1);
++} /* read_ima_block_headers */
++
++
++static Sint16 decode_ima_nibble(Uint8 nibble, IMAADPCMDATA *state)
++{
++ int step = ima_step_table[state->iStepIndex];
++ int diff = 0;
++ int samp, index;
++
++ if (nibble & 0x4)
++ diff += step >> 0;
++ if (nibble & 0x2)
++ diff += step >> 1;
++ if (nibble & 0x1)
++ diff += step >> 2;
++
++ diff += step >> 3;
++
++ if (nibble & 0x8)
++ diff = -diff;
++
++ samp = state->iPrevSamp + diff;
++ samp = SDL_max(SDL_min(samp, 32767), -32768);
++ state->iPrevSamp = samp;
++
++ index = state->iStepIndex + ima_index_table[nibble];
++ state->iStepIndex = SDL_max(SDL_min(index, 88), 0);
++
++ return samp;
++} /* decode_ima_nibble */
++
++
++static int read_ima_frameset(SDL_RWops *rw, wav_t *wav, Sint16 *out)
++{
++ fmt_t *fmt = wav->fmt;
++ Uint16 i, j;
++ Uint8 *fs_buf = fmt->fmt.ima.buf;
++ Uint32 fs_buf_size = fmt->fmt.ima.enc_frameset_size;
++ Uint16 chan_count = fmt->wChannels;
++ IMAADPCMDATA *data = fmt->fmt.ima.d;
++
++ /* read encoded frameset into temp buffer */
++ BAIL_IF_MACRO(!SDL_RWread(rw, fs_buf, fs_buf_size, 1), NULL, 0);
++
++ for (i = 0; i < chan_count; i++)
++ {
++ for (j = 0; j < 4; j++)
++ {
++ Uint8 byte = fs_buf[i*4+j];
++ Sint16 *_out = out + j*chan_count*2+i;
++
++ /* low nibble */
++ *_out = decode_ima_nibble(byte & 0xF, &data[i]);
++
++ _out += chan_count;
++
++ /* high nibble */
++ *_out = decode_ima_nibble(byte >> 4, &data[i]);
++ }
++ } /* for */
++
++ return(1);
++} /* read_ima_frameset */
++
++
++static Uint32 read_sample_fmt_ima(Sound_Sample *sample)
++{
++ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
++ wav_t *w = (wav_t *) internal->decoder_private;
++ fmt_t *fmt = w->fmt;
++ void *const out_buf = internal->buffer;
++ Uint32 bw = 0;
++ int rc;
++
++ while (1)
++ {
++ if (fmt->fmt.ima.read_header)
++ {
++ if (w->bytesLeft < fmt->fmt.ima.headerset_size)
++ {
++ sample->flags |= SOUND_SAMPLEFLAG_EOF;
++ break;
++ } /* if */
++
++ if (bw+fmt->fmt.ima.dec_frame_size > internal->buffer_size)
++ break;
++
++ rc = read_ima_block_headers(internal->rw, fmt->fmt.ima.d,
++ fmt->wChannels, (Sint16*) (out_buf+bw));
++
++ if (!rc)
++ {
++ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
++ return 0;
++ } /* if */
++
++ w->bytesLeft -= fmt->fmt.ima.headerset_size;
++ bw += fmt->fmt.ima.dec_frame_size;
++
++ fmt->fmt.ima.read_header = 0;
++ fmt->fmt.ima.rem_block_framesets = fmt->fmt.ima.block_framesets;
++ } /* if */
++
++ if (w->bytesLeft < fmt->fmt.ima.enc_frameset_size)
++ {
++ sample->flags |= SOUND_SAMPLEFLAG_EOF;
++ break;
++ } /* if */
++
++ if (bw+fmt->fmt.ima.dec_frameset_size > internal->buffer_size)
++ break;
++
++ rc = read_ima_frameset(internal->rw, w, (Sint16*) (out_buf+bw));
++
++ if (!rc)
++ {
++ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
++ return 0;
++ } /* if */
++
++ bw += fmt->fmt.ima.dec_frameset_size;
++ w->bytesLeft -= fmt->fmt.ima.enc_frameset_size;
++
++ if (--fmt->fmt.ima.rem_block_framesets == 0)
++ fmt->fmt.ima.read_header = 1;
++ } /* while */
++
++ return(bw);
++} /* read_sample_fmt_ima */
++
++
++static void free_fmt_ima(fmt_t *fmt)
++{
++ free(fmt->fmt.ima.d);
++ free(fmt->fmt.ima.buf);
++} /* free_fmt_ima */
++
++
++static int rewind_sample_fmt_ima(Sound_Sample *sample)
++{
++ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
++ wav_t *w = (wav_t *) internal->decoder_private;
++ fmt_t *fmt = w->fmt;
++
++ fmt->fmt.ima.read_header = 1;
++
++ return(1);
++} /* rewind_sample_fmt_ima */
++
++
++static int seek_sample_fmt_ima(Sound_Sample *sample, Uint32 ms)
++{
++ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
++ wav_t *w = (wav_t *) internal->decoder_private;
++ fmt_t *fmt = w->fmt;
++ Sint16 *dummy_buf = (Sint16*) (fmt->fmt.ima.buf +
++ fmt->fmt.ima.enc_frameset_size);
++ Uint32 i;
++ int rc, pos;
++
++ Uint32 seek_frames = (fmt->dwSamplesPerSec * ms) / 1000;
++ Uint32 seek_blocks = seek_frames / fmt->fmt.ima.block_frames;
++ Uint32 seek_framesets;
++ seek_frames %= fmt->fmt.ima.block_frames;
++
++ w->bytesLeft = fmt->total_bytes;
++ pos = seek_blocks * fmt->wBlockAlign + fmt->data_starting_offset;
++ rc = SDL_RWseek(internal->rw, pos, SEEK_SET);
++ BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
++ w->bytesLeft -= seek_blocks * fmt->wBlockAlign;
++
++ fmt->fmt.ima.read_header = 0;
++
++ if (seek_frames == 0)
++ {
++ fmt->fmt.ima.read_header = 1;
++ return(1);
++ } /* if */
++
++ rc = read_ima_block_headers(internal->rw, fmt->fmt.ima.d,
++ fmt->wChannels, dummy_buf);
++ BAIL_IF_MACRO(!rc, NULL, 0);
++ w->bytesLeft -= fmt->fmt.ima.headerset_size;
++
++ if (w->bytesLeft < fmt->fmt.ima.headerset_size)
++ {
++ sample->flags |= SOUND_SAMPLEFLAG_EOF;
++ return(1);
++ } /* if */
++
++ seek_frames -= 1;
++ seek_framesets = seek_frames / FRAMESET_FRAMES;
++
++ for (i = 0; i < seek_framesets; i++)
++ {
++ rc = read_ima_frameset(internal->rw, w, dummy_buf);
++ BAIL_IF_MACRO(!rc, NULL, 0);
++ w->bytesLeft -= fmt->fmt.ima.enc_frameset_size;
++ } /* for */
++
++ fmt->fmt.ima.rem_block_framesets =
++ fmt->fmt.ima.block_framesets - seek_framesets;
++
++ if (w->bytesLeft < fmt->fmt.ima.enc_frameset_size)
++ sample->flags |= SOUND_SAMPLEFLAG_EOF;
++
++ return(1); /* success. */
++} /* seek_sample_fmt_ima */
++
++
++static int read_fmt_ima(SDL_RWops *rw, fmt_t *fmt)
++{
++ Uint16 chan = fmt->wChannels;
++ Sint16 extraBytes;
++ int rc;
++
++ /* setup function pointers */
++ fmt->free = free_fmt_ima;
++ fmt->read_sample = read_sample_fmt_ima;
++ fmt->rewind_sample = rewind_sample_fmt_ima;
++ fmt->seek_sample = seek_sample_fmt_ima;
++
++ BAIL_IF_MACRO(!read_le16(rw, &extraBytes), NULL, 0);
++ BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.ima.block_frames), NULL, 0);
++
++ /* skip to end of fmt chunk */
++ rc = SDL_RWseek(rw, extraBytes-2, SEEK_CUR);
++ BAIL_IF_MACRO(!rc, NULL, 0);
++
++ fmt->fmt.ima.block_framesets = (fmt->fmt.ima.block_frames-1) / FRAMESET_FRAMES;
++ fmt->fmt.ima.enc_frameset_size = 4 * chan;
++ fmt->fmt.ima.headerset_size = 4 * chan;
++ fmt->fmt.ima.dec_frame_size = sizeof(Uint16) * chan;
++ fmt->fmt.ima.dec_frameset_size = fmt->fmt.ima.dec_frame_size * FRAMESET_FRAMES;
++ fmt->fmt.ima.read_header = 1;
++
++ fmt->fmt.ima.d = malloc(sizeof(IMAADPCMDATA) * chan);
++
++ size_t buf_size = fmt->fmt.ima.enc_frameset_size +
++ fmt->fmt.ima.dec_frameset_size;
++ fmt->fmt.ima.buf = malloc(buf_size);
++
++ return(1);
++} /* read_fmt_ima */
++
++
++
++/*****************************************************************************
+ * Everything else... *
+ *****************************************************************************/
+
+@@ -642,6 +958,13 @@
+ SNDDBG(("WAV: Appears to be ADPCM compressed audio.\n"));
+ return(read_fmt_adpcm(rw, fmt));
+
++ case FMT_IMA:
++ if (fmt->wBitsPerSample == 4)
++ {
++ SNDDBG(("WAV: Appears to be 4bit IMA ADPCM compressed audio.\n"));
++ return(read_fmt_ima(rw, fmt));
++ }
++
+ /* add other types here. */
+
+ default: