mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 00:20:47 +01:00
STRM's IMA ADPCM added
git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@21 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
parent
2d3376e473
commit
39e4e02984
65
src/coding/ima_decoder.c
Normal file
65
src/coding/ima_decoder.c
Normal file
@ -0,0 +1,65 @@
|
||||
#include "../util.h"
|
||||
#include "ima_decoder.h"
|
||||
|
||||
const int32_t ADPCMTable[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
|
||||
|
||||
};
|
||||
|
||||
const int IMA_IndexTable[16] =
|
||||
|
||||
{
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
};
|
||||
|
||||
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i=first_sample;
|
||||
int32_t sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_16;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
if (first_sample==0) {
|
||||
step_index = read_16bitLE(stream->offset+2,stream->streamfile);
|
||||
hist1 = read_16bitLE(stream->offset,stream->streamfile);
|
||||
}
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_nibble =
|
||||
(read_8bit(stream->offset+4+i/2,stream->streamfile) >> (i&1?4:0))&0xf;
|
||||
int delta;
|
||||
int step = ADPCMTable[step_index];
|
||||
|
||||
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)
|
||||
outbuf[sample_count] = clamp16(hist1 - delta);
|
||||
else
|
||||
outbuf[sample_count] = clamp16(hist1 + delta);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
hist1 = outbuf[sample_count];
|
||||
}
|
||||
|
||||
stream->adpcm_history1_16 = hist1;
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
8
src/coding/ima_decoder.h
Normal file
8
src/coding/ima_decoder.h
Normal file
@ -0,0 +1,8 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
#ifndef _IMA_DECODER_H
|
||||
#define _IMA_DECODER_H
|
||||
|
||||
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
#endif
|
@ -5,25 +5,34 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA
|
||||
int samples_written=0;
|
||||
|
||||
int frame_size = get_vgmstream_frame_size(vgmstream);
|
||||
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);;
|
||||
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
int samples_this_block;
|
||||
|
||||
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
|
||||
|
||||
if (vgmstream->layout_type == layout_interleave_shortblock &&
|
||||
vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block> vgmstream->num_samples) {
|
||||
samples_this_block = vgmstream->interleave_smallblock_size / frame_size * samples_per_frame;
|
||||
frame_size = get_vgmstream_shortframe_size(vgmstream);
|
||||
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream);
|
||||
|
||||
samples_this_block = vgmstream->interleave_smallblock_size / frame_size * samples_per_frame;
|
||||
}
|
||||
|
||||
while (samples_written<sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
|
||||
/* we assume that the loop is not back into a short block */
|
||||
if (vgmstream->layout_type == layout_interleave_shortblock) {
|
||||
frame_size = get_vgmstream_frame_size(vgmstream);
|
||||
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
/*printf("vgmstream_samples_to_do(samples_this_block=%d,samples_per_frame=%d,vgmstream) returns %d\n",samples_this_block,samples_per_frame,samples_to_do);*/
|
||||
|
||||
if (samples_written+samples_to_do > sample_count)
|
||||
samples_to_do=sample_count-samples_written;
|
||||
@ -38,6 +47,8 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA
|
||||
int chan;
|
||||
if (vgmstream->layout_type == layout_interleave_shortblock &&
|
||||
vgmstream->current_sample + samples_this_block > vgmstream->num_samples) {
|
||||
frame_size = get_vgmstream_shortframe_size(vgmstream);
|
||||
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream);
|
||||
|
||||
samples_this_block = vgmstream->interleave_smallblock_size / frame_size * samples_per_frame;
|
||||
for (chan=0;chan<vgmstream->channels;chan++)
|
||||
|
@ -1,5 +1,4 @@
|
||||
/*
|
||||
* interleave.h - interleaved layouts
|
||||
*/
|
||||
#include "../streamtypes.h"
|
||||
#include "../vgmstream.h"
|
||||
|
@ -70,7 +70,7 @@ VGMSTREAM * init_vgmstream_nds_strm(const char * const filename) {
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x30,infile);
|
||||
vgmstream->interleave_smallblock_size = read_32bitLE(0x38,infile);
|
||||
|
||||
if (channel_count==1 || coding_type==coding_PCM8 || coding_type==coding_PCM16LE)
|
||||
if (coding_type==coding_PCM8 || coding_type==coding_PCM16LE)
|
||||
vgmstream->layout_type = layout_none;
|
||||
else
|
||||
vgmstream->layout_type = layout_interleave_shortblock;
|
||||
|
@ -127,11 +127,22 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
case coding_PCM16BE:
|
||||
case coding_PCM8:
|
||||
return 1;
|
||||
case coding_NDS_IMA:
|
||||
return (vgmstream->interleave_block_size-4)*2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int get_vgmstream_samples_per_shortframe(VGMSTREAM * vgmstream) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_NDS_IMA:
|
||||
return (vgmstream->interleave_smallblock_size-4)*2;
|
||||
default:
|
||||
return get_vgmstream_samples_per_frame(vgmstream);
|
||||
}
|
||||
}
|
||||
|
||||
int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_CRI_ADX:
|
||||
@ -143,11 +154,22 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
return 2;
|
||||
case coding_PCM8:
|
||||
return 1;
|
||||
case coding_NDS_IMA:
|
||||
return vgmstream->interleave_block_size;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int get_vgmstream_shortframe_size(VGMSTREAM * vgmstream) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_NDS_IMA:
|
||||
return vgmstream->interleave_smallblock_size;
|
||||
default:
|
||||
return get_vgmstream_frame_size(vgmstream);
|
||||
}
|
||||
}
|
||||
|
||||
void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer) {
|
||||
int chan;
|
||||
|
||||
@ -188,6 +210,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_NDS_IMA:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_nds_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
vgmstream->channels,vgmstream->samples_into_block,
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,6 +326,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream) {
|
||||
case coding_CRI_ADX:
|
||||
printf("CRI ADX 4-bit ADPCM");
|
||||
break;
|
||||
case coding_NDS_IMA:
|
||||
printf("NDS-style 4-bit IMA ADPCM");
|
||||
break;
|
||||
default:
|
||||
printf("CANNOT DECODE");
|
||||
}
|
||||
|
@ -80,6 +80,8 @@ typedef struct {
|
||||
int16_t adpcm_history2_16; /* previous previous sample */
|
||||
int32_t adpcm_history2_32;
|
||||
};
|
||||
|
||||
int adpcm_step_index; /* for IMA */
|
||||
} VGMSTREAMCHANNEL;
|
||||
|
||||
typedef struct {
|
||||
@ -149,6 +151,9 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
|
||||
int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream);
|
||||
/* number of bytes per frame */
|
||||
int get_vgmstream_frame_size(VGMSTREAM * vgmstream);
|
||||
/* in NDS IMA the frame size is the block size, so the last one is short */
|
||||
int get_vgmstream_samples_per_shortframe(VGMSTREAM * vgmstream);
|
||||
int get_vgmstream_shortframe_size(VGMSTREAM * vgmstream);
|
||||
|
||||
/* Assume that we have written samples_written into the buffer already, and we have samples_to_do consecutive
|
||||
* samples ahead of us. Decode those samples into the buffer. */
|
||||
|
@ -1,6 +1,6 @@
|
||||
CFLAGS=-lm -O3
|
||||
|
||||
test: test.c ../src/streamfile.c ../src/vgmstream.c ../src/util.c ../src/meta/adx_header.c ../src/coding/adx_decoder.c ../src/coding/gcdsp_decoder.c ../src/meta/brstm.c ../src/layout/interleave.c ../src/layout/nolayout.c ../src/coding/pcm_decoder.c ../src/meta/nds_strm.c
|
||||
test: test.c ../src/streamfile.c ../src/vgmstream.c ../src/util.c ../src/meta/adx_header.c ../src/coding/adx_decoder.c ../src/coding/gcdsp_decoder.c ../src/meta/brstm.c ../src/layout/interleave.c ../src/layout/nolayout.c ../src/coding/pcm_decoder.c ../src/meta/nds_strm.c ../src/coding/ima_decoder.c
|
||||
|
||||
clean:
|
||||
rm test
|
||||
|
Loading…
Reference in New Issue
Block a user