diff --git a/patches/SDL_sound/ima-adpcm.patch b/patches/SDL_sound/ima-adpcm.patch new file mode 100644 index 0000000..62585e0 --- /dev/null +++ b/patches/SDL_sound/ima-adpcm.patch @@ -0,0 +1,353 @@ +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:37:52 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,284 @@ + + + /***************************************************************************** ++ * 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; ++ ++ 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; ++ ++ int samp = state->iPrevSamp + diff; ++ samp = SDL_max(SDL_min(samp, 32767), -32768); ++ state->iPrevSamp = samp; ++ ++ int 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; ++ ++ 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; ++ ++ read_ima_block_headers(internal->rw, fmt->fmt.ima.d, ++ fmt->wChannels, (Sint16*) (out_buf+bw)); ++ ++ 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; ++ ++ int 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; ++ 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; ++ ++ Sint16 extraBytes; ++ 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 +946,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: