vgmstream/src/coding/ima_decoder.c

653 lines
23 KiB
C
Raw Normal View History

2014-06-02 02:19:05 +02:00
#include "../util.h"
#include "coding.h"
/**
* IMA ADPCM algorithms (expand one nibble to one sample, based on prev sample/history and step table).
* Nibbles are usually grouped in blocks/chunks, with a header, containing 1 or N channels
*
* All IMAs are mostly the same with these variations:
* - interleave: blocks and channels are handled externally (layouts) or internally (mixed channels)
* - block header: none (external), normal (4 bytes of history 16b + step 16b) or others; per channel/global
* - expand type: ms-ima style or others; low or high nibble first
*/
static const int32_t ADPCMTable[89] =
2014-06-02 02:19:05 +02:00
{
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
};
static const int IMA_IndexTable[16] =
2014-06-02 02:19:05 +02:00
{
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8
};
2014-06-02 02:19:05 +02:00
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
2014-06-02 02:19:05 +02:00
int step_index = stream->adpcm_step_index;
//external interleave
//normal header
if (first_sample == 0) {
off_t header_offset = stream->offset;
hist1 = read_16bitLE(header_offset,stream->streamfile);
step_index = read_16bitLE(header_offset+2,stream->streamfile);
//todo clip step_index?
2014-06-02 02:19:05 +02:00
}
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
off_t byte_offset = stream->offset + 4 + i/2;
nibble_shift = (i&1?4:0); //low nibble first
2014-06-02 02:19:05 +02:00
//normal ima nibble expansion
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
sample_decoded = hist1;
step = ADPCMTable[step_index];
2014-06-02 02:19:05 +02:00
delta = step >> 3;
if (sample_nibble & 1) delta += step >> 2;
if (sample_nibble & 2) delta += step >> 1;
if (sample_nibble & 4) delta += step;
if (sample_nibble & 8)
sample_decoded -= delta;
2014-06-02 02:19:05 +02:00
else
sample_decoded += delta;
2014-06-02 02:19:05 +02:00
hist1 = clamp16(sample_decoded);
2014-06-02 02:19:05 +02:00
step_index += IMA_IndexTable[sample_nibble];
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
outbuf[sample_count] = (short)(hist1);
2014-06-02 02:19:05 +02:00
}
stream->adpcm_history1_16 = hist1;
stream->adpcm_step_index = step_index;
}
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
2014-06-02 02:19:05 +02:00
int step_index = stream->adpcm_step_index;
//external interleave
//normal header
if (first_sample == 0) {
off_t header_offset = stream->offset;
hist1 = read_16bitLE(header_offset,stream->streamfile);
step_index = read_8bit(header_offset+2,stream->streamfile); //todo use 8bit in all MS IMA?
//todo clip step_index?
2014-06-02 02:19:05 +02:00
}
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
off_t byte_offset = stream->offset + 4 + i/2;
nibble_shift = (i&1?0:4); //high nibble first
2014-06-02 02:19:05 +02:00
//normal ima nibble expansion
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
sample_decoded = hist1;
step = ADPCMTable[step_index];
2014-06-02 02:19:05 +02:00
delta = step >> 3;
if (sample_nibble & 1) delta += step >> 2;
if (sample_nibble & 2) delta += step >> 1;
if (sample_nibble & 4) delta += step;
if (sample_nibble & 8)
sample_decoded -= delta;
2014-06-02 02:19:05 +02:00
else
sample_decoded += delta;
2014-06-02 02:19:05 +02:00
hist1 = clamp16(sample_decoded);
2014-06-02 02:19:05 +02:00
step_index += IMA_IndexTable[sample_nibble];
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
outbuf[sample_count] = (short)(hist1);
2014-06-02 02:19:05 +02:00
}
stream->adpcm_history1_16 = hist1;
stream->adpcm_step_index = step_index;
}
void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
2014-06-02 02:19:05 +02:00
int step_index = stream->adpcm_step_index;
//internal interleave (configurable size), mixed channels (4 byte per ch)
int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels;
2014-06-02 02:19:05 +02:00
first_sample = first_sample % block_samples;
//normal header (per channel)
2014-06-02 02:19:05 +02:00
if (first_sample == 0) {
off_t header_offset = stream->offset + 4*channel;
2014-06-02 02:19:05 +02:00
hist1 = read_16bitLE(header_offset,stream->streamfile);
step_index = read_8bit(header_offset+2,stream->streamfile);
2014-06-02 02:19:05 +02:00
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
}
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
2014-06-02 02:19:05 +02:00
off_t byte_offset = stream->offset + 4*channel + 4*vgmstream->channels + i/8*4*vgmstream->channels + (i%8)/2;
nibble_shift = (i&1?4:0); //low nibble first
2014-06-02 02:19:05 +02:00
//normal ima nibble expansion
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
sample_decoded = hist1;
step = ADPCMTable[step_index];
2014-06-02 02:19:05 +02:00
delta = step >> 3;
if (sample_nibble & 1) delta += step >> 2;
if (sample_nibble & 2) delta += step >> 1;
if (sample_nibble & 4) delta += step;
if (sample_nibble & 8)
sample_decoded -= delta;
else
sample_decoded += delta;
hist1 = clamp16(sample_decoded);
2014-06-02 02:19:05 +02:00
step_index += IMA_IndexTable[sample_nibble];
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
outbuf[sample_count] = (short)(hist1);
2014-06-02 02:19:05 +02:00
}
//internal interleave: increment offset on complete frame
2014-06-02 02:19:05 +02:00
if (i == block_samples) stream->offset += vgmstream->interleave_block_size;
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
2014-06-02 02:19:05 +02:00
}
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
2014-06-02 02:19:05 +02:00
int step_index = stream->adpcm_step_index;
//internal interleave (configurable size), mixed channels (4 byte per ch)
int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels;
2014-06-02 02:19:05 +02:00
first_sample = first_sample % block_samples;
//inverted header (per channel)
2014-06-02 02:19:05 +02:00
if (first_sample == 0) {
off_t header_offset = stream->offset + 4*channel;
2014-06-02 02:19:05 +02:00
step_index = read_16bitLE(header_offset,stream->streamfile);
hist1 = read_16bitLE(header_offset+2,stream->streamfile);
2014-06-02 02:19:05 +02:00
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
}
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
2014-06-02 02:19:05 +02:00
off_t byte_offset = stream->offset + 4*vgmstream->channels + channel + i/2*vgmstream->channels;
nibble_shift = (i&1?4:0); //low nibble first
2014-06-02 02:19:05 +02:00
//normal ima nibble expansion
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
sample_decoded = hist1;
step = ADPCMTable[step_index];
2014-06-02 02:19:05 +02:00
delta = step >> 3;
if (sample_nibble & 1) delta += step >> 2;
if (sample_nibble & 2) delta += step >> 1;
if (sample_nibble & 4) delta += step;
if (sample_nibble & 8)
sample_decoded -= delta;
else
sample_decoded += delta;
hist1 = clamp16(sample_decoded);
2014-06-02 02:19:05 +02:00
step_index += IMA_IndexTable[sample_nibble];
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
outbuf[sample_count] = (short)(hist1);
2014-06-02 02:19:05 +02:00
}
//internal interleave: increment offset on complete frame
2014-06-02 02:19:05 +02:00
if (i == block_samples) stream->offset += vgmstream->interleave_block_size;
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
2014-06-02 02:19:05 +02:00
}
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
2014-06-02 02:19:05 +02:00
int32_t hist1 = stream->adpcm_history1_32;
2014-06-02 02:19:05 +02:00
int step_index = stream->adpcm_step_index;
//semi-external interleave?
int block_samples = 0x14 * 2;
2014-06-02 02:19:05 +02:00
first_sample = first_sample % block_samples;
//inverted header
2014-06-02 02:19:05 +02:00
if (first_sample == 0) {
off_t header_offset = stream->offset;
2014-06-02 02:19:05 +02:00
step_index = read_16bitLE(header_offset,stream->streamfile);
hist1 = read_16bitLE(header_offset+2,stream->streamfile);
2014-06-02 02:19:05 +02:00
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
}
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
2014-06-02 02:19:05 +02:00
off_t byte_offset = stream->offset + 4 + i/2;
nibble_shift = (i&1?4:0); //low nibble first
2014-06-02 02:19:05 +02:00
//normal ima nibble expansion
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
sample_decoded = hist1;
step = ADPCMTable[step_index];
2014-06-02 02:19:05 +02:00
delta = step >> 3;
if (sample_nibble & 1) delta += step >> 2;
if (sample_nibble & 2) delta += step >> 1;
if (sample_nibble & 4) delta += step;
if (sample_nibble & 8)
sample_decoded -= delta;
else
sample_decoded += delta;
hist1 = clamp16(sample_decoded);
2014-06-02 02:19:05 +02:00
step_index += IMA_IndexTable[sample_nibble];
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
outbuf[sample_count] = (short)(hist1);
2014-06-02 02:19:05 +02:00
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
2014-06-02 02:19:05 +02:00
}
/* For multichannel the internal layout is (I think) mixed stereo channels (ex. 6ch: 2ch + 2ch + 2ch)
* Has extra support for EA blocks, probably could be simplified */
2014-06-02 02:19:05 +02:00
void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
int i, sample_count;
2014-06-02 02:19:05 +02:00
int32_t hist1 = stream->adpcm_history1_32;
2014-06-02 02:19:05 +02:00
int step_index = stream->adpcm_step_index;
off_t offset = stream->offset;
2014-06-02 02:19:05 +02:00
//internal interleave (0x20+4 size), mixed channels (4 byte per ch, mixed stereo)
int block_samples = (vgmstream->channels==1) ?
32 :
32*(vgmstream->channels&2);
first_sample = first_sample % block_samples;
2014-06-02 02:19:05 +02:00
//normal header (per channel)
if (first_sample == 0) {
off_t header_offset;
if(vgmstream->layout_type==layout_ea_blocked) {
header_offset = stream->offset;
} else {
header_offset = stream->offset + 4*(channel%2);
}
hist1 = read_16bitLE(header_offset,stream->streamfile);
step_index = read_16bitLE(header_offset+2,stream->streamfile);
2014-06-02 02:19:05 +02:00
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
}
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
if(vgmstream->layout_type==layout_ea_blocked)
offset = stream->offset + 4 + i/8*4 + (i%8)/2;
else {
offset = (channelspacing==1) ?
stream->offset + 4*(channel%2) + 4 + i/8*4 + (i%8)/2 :
stream->offset + 4*(channel%2) + 4*2 + i/8*4*2 + (i%8)/2;
}
nibble_shift = (i&1?4:0); //low nibble first
//normal ima nibble expansion
sample_nibble = (read_8bit(offset,stream->streamfile) >> nibble_shift)&0xf;
sample_decoded = hist1;
step = ADPCMTable[step_index];
2014-06-02 02:19:05 +02:00
delta = step >> 3;
if (sample_nibble & 1) delta += step >> 2;
if (sample_nibble & 2) delta += step >> 1;
if (sample_nibble & 4) delta += step;
if (sample_nibble & 8)
sample_decoded -= delta;
else
sample_decoded += delta;
hist1 = clamp16(sample_decoded);
2014-06-02 02:19:05 +02:00
step_index += IMA_IndexTable[sample_nibble];
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
outbuf[sample_count] = (short)(hist1);
}
//internal interleave: increment offset on complete frame
if(vgmstream->layout_type==layout_ea_blocked) {
if(offset-stream->offset==32+3) // ??
stream->offset+=36;
} else {
if(channelspacing==1) {
if(offset-stream->offset==32+3) // ??
stream->offset+=36;
} else {
if(offset-stream->offset==64+(4*(channel%2))+3) // ??
stream->offset+=36*channelspacing;
}
2014-06-02 02:19:05 +02:00
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
2014-06-02 02:19:05 +02:00
}
void decode_int_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
int i, sample_count;
2014-06-02 02:19:05 +02:00
int32_t hist1 = stream->adpcm_history1_32;
2014-06-02 02:19:05 +02:00
int step_index = stream->adpcm_step_index;
off_t offset = stream->offset;
//semi-internal interleave (0x24 size), mixed channels (4 byte per ch)?
int block_samples = (vgmstream->channels==1) ?
32 :
32*(vgmstream->channels&2);
first_sample = first_sample % block_samples;
2014-06-02 02:19:05 +02:00
//normal header
2014-06-02 02:19:05 +02:00
if (first_sample == 0) {
off_t header_offset = stream->offset;
2014-06-02 02:19:05 +02:00
hist1 = read_16bitLE(header_offset,stream->streamfile);
step_index = read_16bitLE(header_offset+2,stream->streamfile);
2014-06-02 02:19:05 +02:00
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
}
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
2014-06-02 02:19:05 +02:00
offset = stream->offset + 4 + i/8*4 + (i%8)/2;
nibble_shift = (i&1?4:0); //low nibble first
2014-06-02 02:19:05 +02:00
//normal ima nibble expansion
sample_nibble = (read_8bit(offset,stream->streamfile) >> nibble_shift)&0xf;
sample_decoded = hist1;
step = ADPCMTable[step_index];
2014-06-02 02:19:05 +02:00
delta = step >> 3;
if (sample_nibble & 1) delta += step >> 2;
if (sample_nibble & 2) delta += step >> 1;
if (sample_nibble & 4) delta += step;
if (sample_nibble & 8)
sample_decoded -= delta;
else
sample_decoded += delta;
hist1 = clamp16(sample_decoded);
2014-06-02 02:19:05 +02:00
step_index += IMA_IndexTable[sample_nibble];
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
outbuf[sample_count] = (short)(hist1);
2014-06-02 02:19:05 +02:00
}
//internal interleave: increment offset on complete frame
if(channelspacing==1) {
if(offset-stream->offset==32+3) // ??
stream->offset+=36;
} else {
if(offset-stream->offset==64+(4*(channel%2))+3) // ??
stream->offset+=36*channelspacing;
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
2014-06-02 02:19:05 +02:00
}
void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
2014-06-02 02:19:05 +02:00
int32_t hist1 = stream->adpcm_history1_32;
2014-06-02 02:19:05 +02:00
int step_index = stream->adpcm_step_index;
//external interleave
//no header
2014-06-02 02:19:05 +02:00
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
2014-06-02 02:19:05 +02:00
off_t byte_offset = stream->offset + i/2;
nibble_shift = (i&1?0:4); //high nibble first (old-style DVI)
2014-06-02 02:19:05 +02:00
//normal ima nibble expansion
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
2014-06-02 02:19:05 +02:00
sample_decoded = hist1;
step = ADPCMTable[step_index];
2014-06-02 02:19:05 +02:00
delta = step >> 3;
if (sample_nibble & 1) delta += step >> 2;
if (sample_nibble & 2) delta += step >> 1;
if (sample_nibble & 4) delta += step;
if (sample_nibble & 8)
sample_decoded -= delta;
else
sample_decoded += delta;
hist1 = clamp16(sample_decoded);
step_index += IMA_IndexTable[sample_nibble&0x7]; //todo unneeded &0x7?
2014-06-02 02:19:05 +02:00
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
outbuf[sample_count] = (short)(hist1);
2014-06-02 02:19:05 +02:00
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
2014-06-02 02:19:05 +02:00
}
void decode_eacs_ima(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]);//todo pass externally for consistency
int i, sample_count;
2014-06-02 02:19:05 +02:00
int32_t hist1 = stream->adpcm_history1_32;
2014-06-02 02:19:05 +02:00
int step_index = stream->adpcm_step_index;
//external interleave
//no header
2014-06-02 02:19:05 +02:00
//variable nibble order
vgmstream->get_high_nibble = !vgmstream->get_high_nibble;
if((first_sample) && (channelspacing==1))
vgmstream->get_high_nibble = !vgmstream->get_high_nibble;
2014-06-02 02:19:05 +02:00
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
2014-06-02 02:19:05 +02:00
off_t byte_offset = stream->offset + i;
nibble_shift = (vgmstream->get_high_nibble?0:4); //variable nibble order
2014-06-02 02:19:05 +02:00
//normal ima nibble expansion
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
2014-06-02 02:19:05 +02:00
sample_decoded = hist1;
step = ADPCMTable[step_index];
2014-06-02 02:19:05 +02:00
delta = step >> 3;
if (sample_nibble & 1) delta += step >> 2;
if (sample_nibble & 2) delta += step >> 1;
if (sample_nibble & 4) delta += step;
if (sample_nibble & 8)
sample_decoded -= delta;
else
sample_decoded += delta;
hist1 = clamp16(sample_decoded);
step_index += IMA_IndexTable[sample_nibble&0x7]; //todo unneeded &0x7?
2014-06-02 02:19:05 +02:00
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
outbuf[sample_count] = (short)(hist1);
2014-06-02 02:19:05 +02:00
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
2014-06-02 02:19:05 +02:00
}
void decode_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
2014-06-02 02:19:05 +02:00
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
2014-06-02 02:19:05 +02:00
//external interleave
2014-06-02 02:19:05 +02:00
//no header
2014-06-02 02:19:05 +02:00
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
2014-06-02 02:19:05 +02:00
off_t byte_offset = stream->offset + i/2;
nibble_shift = (i&1?4:0); //low nibble order
2014-06-02 02:19:05 +02:00
//"original" ima nibble expansion
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
sample_decoded = hist1 << 3;
step = ADPCMTable[step_index];
delta = step * (sample_nibble & 7) * 2 + step;
if (sample_nibble & 8)
sample_decoded -= delta;
else
sample_decoded += delta;
2014-06-02 02:19:05 +02:00
hist1 = clamp16(sample_decoded >> 3);
step_index += IMA_IndexTable[sample_nibble&0x7]; //todo unneeded &0x7?
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
2014-06-02 02:19:05 +02:00
outbuf[sample_count] = (short)(hist1);
}
2014-06-02 02:19:05 +02:00
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
2014-06-02 02:19:05 +02:00
}
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
2014-06-02 02:19:05 +02:00
int16_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
2014-06-02 02:19:05 +02:00
int step_index = stream->adpcm_step_index;
off_t packet_offset = stream->offset + first_sample/64*34;
//semi-internal interleave //todo what
int block_samples = 64;
first_sample = first_sample % block_samples;
2014-06-02 02:19:05 +02:00
//2-byte header
if (first_sample == 0) {
2014-06-02 02:19:05 +02:00
hist1 = (int16_t)((uint16_t)read_16bitBE(packet_offset,stream->streamfile) & 0xff80);
step_index = read_8bit(packet_offset+1,stream->streamfile) & 0x7f;
//todo no clamp
2014-06-02 02:19:05 +02:00
}
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
2014-06-02 02:19:05 +02:00
off_t byte_offset = packet_offset + 2 + i/2;
nibble_shift = (i&1?4:0); //low nibble first
2014-06-02 02:19:05 +02:00
//normal ima nibble expansion
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
2014-06-02 02:19:05 +02:00
sample_decoded = hist1;
step = ADPCMTable[step_index];
2014-06-02 02:19:05 +02:00
delta = step >> 3;
if (sample_nibble & 1) delta += step >> 2;
if (sample_nibble & 2) delta += step >> 1;
if (sample_nibble & 4) delta += step;
if (sample_nibble & 8)
sample_decoded -= delta;
else
sample_decoded += delta;
hist1 = clamp16(sample_decoded);
step_index += IMA_IndexTable[sample_nibble&0x7]; //todo unneeded &0x7?
2014-06-02 02:19:05 +02:00
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
outbuf[sample_count] = (short)(hist1);
2014-06-02 02:19:05 +02:00
}
stream->adpcm_history1_16 = hist1;
stream->adpcm_step_index = step_index;
2014-06-02 02:19:05 +02:00
}
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count;
2014-06-02 02:19:05 +02:00
int32_t hist1 = stream->adpcm_history1_32;
2014-06-02 02:19:05 +02:00
int step_index = stream->adpcm_step_index;
//external interleave
//no header
2014-06-02 02:19:05 +02:00
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift, sample_nibble, sample_decoded, step, delta;
off_t byte_offset = stream->offset + i;//one nibble per channel
nibble_shift = (channel==0?0:4); //high nibble first, based on channel
2014-06-02 02:19:05 +02:00
//snds nibble expansion (update step_index before doing current sample)
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
2014-06-02 02:19:05 +02:00
step_index += IMA_IndexTable[sample_nibble];
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
step = ADPCMTable[step_index];
2014-06-02 02:19:05 +02:00
delta = (sample_nibble & 7) * step / 4 + step / 8;
if (sample_nibble & 8) delta = -delta;
sample_decoded = hist1 + delta;
hist1 = clamp16(sample_decoded);
2014-06-02 02:19:05 +02:00
outbuf[sample_count] = (short)(hist1);
2014-06-02 02:19:05 +02:00
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
2014-06-02 02:19:05 +02:00
}