From ec94c0d3c55d4480ee01954487fe411a0fbe0959 Mon Sep 17 00:00:00 2001 From: halleyscometsw Date: Mon, 14 Jul 2008 13:30:26 +0000 Subject: [PATCH] add support for Wii fsb from Metroid Prime 2, required a new layout type git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@316 51a99a44-fe44-0410-b1ba-c3e57ba2b86b --- src/Makefile | 3 +- src/coding/coding.h | 1 + src/coding/ngc_dsp_decoder.c | 41 ++++++++++++++++++++++++ src/layout/Makefile.unix.am | 2 +- src/layout/interleave_byte.c | 62 ++++++++++++++++++++++++++++++++++++ src/layout/layout.h | 2 ++ src/libvgmstream.vcproj | 4 +++ src/meta/ps2_fsb.c | 39 ++++++++++++++++++----- src/vgmstream.c | 17 ++++++++++ src/vgmstream.h | 4 +++ 10 files changed, 165 insertions(+), 10 deletions(-) create mode 100644 src/layout/interleave_byte.c diff --git a/src/Makefile b/src/Makefile index 557a183c..b3390a90 100644 --- a/src/Makefile +++ b/src/Makefile @@ -23,7 +23,8 @@ LAYOUT_OBJS=layout/ast_blocked.o \ layout/ea_block.o \ layout/wsi_blocked.o \ layout/str_snds_blocked.o \ - layout/ws_aud_blocked.o + layout/ws_aud_blocked.o \ + layout/interleave_byte.o META_OBJS=meta/adx_header.o \ meta/afc_header.o \ diff --git a/src/coding/coding.h b/src/coding/coding.h index 77e9f9dc..5fd516eb 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -16,6 +16,7 @@ void decode_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, void decode_ngc_afc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_ngc_dsp_mem(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem); int32_t dsp_nibbles_to_samples(int32_t nibbles); diff --git a/src/coding/ngc_dsp_decoder.c b/src/coding/ngc_dsp_decoder.c index f58cfc59..27825ae9 100644 --- a/src/coding/ngc_dsp_decoder.c +++ b/src/coding/ngc_dsp_decoder.c @@ -41,6 +41,47 @@ void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci stream->adpcm_history2_16 = hist2; } +/* read from memory rather than a file */ +void decode_ngc_dsp_mem(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem) { + int i=first_sample; + int32_t sample_count; + + int framesin = first_sample/14; + + int8_t header = mem[framesin*8]; + int32_t scale = 1 << (header & 0xf); + int coef_index = (header >> 4) & 0xf; + int32_t hist1 = stream->adpcm_history1_16; + int32_t hist2 = stream->adpcm_history2_16; + int coef1 = stream->adpcm_coef[coef_index*2]; + int coef2 = stream->adpcm_coef[coef_index*2+1]; + + first_sample = first_sample%14; + + for (i=first_sample,sample_count=0; iloop_history1 && hist2==stream->loop_history2) fprintf(stderr,"yo! %#x (start %#x) %d\n",stream->offset+framesin*8+i/2,stream->channel_start_offset,stream->samples_done); + stream->samples_done++; +#endif + + outbuf[sample_count] = clamp16(( + (((i&1? + get_low_nibble_signed(sample_byte): + get_high_nibble_signed(sample_byte) + ) * scale)<<11) + 1024 + + (coef1 * hist1 + coef2 * hist2))>>11 + ); + + hist2 = hist1; + hist1 = outbuf[sample_count]; + } + + stream->adpcm_history1_16 = hist1; + stream->adpcm_history2_16 = hist2; +} + /* * The original DSP spec uses nibble counts for loop points, and some * variants don't have a proper sample count, so we (who are interested diff --git a/src/layout/Makefile.unix.am b/src/layout/Makefile.unix.am index 24933bdf..6035c3a3 100644 --- a/src/layout/Makefile.unix.am +++ b/src/layout/Makefile.unix.am @@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir) AM_MAKEFLAGS=-f Makefile.unix liblayout_la_LDFLAGS = -liblayout_la_SOURCES = ast_blocked.c blocked.c caf_blocked.c ea_block.c halpst_blocked.c interleave.c nolayout.c xa_blocked.c wsi_blocked.c str_snds_blocked.c ws_aud_blocked.c +liblayout_la_SOURCES = ast_blocked.c blocked.c caf_blocked.c ea_block.c halpst_blocked.c interleave.c nolayout.c xa_blocked.c wsi_blocked.c str_snds_blocked.c ws_aud_blocked.c interleave_byte.c EXTRA_DIST = layout.h diff --git a/src/layout/interleave_byte.c b/src/layout/interleave_byte.c new file mode 100644 index 00000000..c9f8eb08 --- /dev/null +++ b/src/layout/interleave_byte.c @@ -0,0 +1,62 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* for formats where the interleave is smaller than a frame, so we need to + * deinterleave in memory before passing it along to a specialized decoder which + * reads from memory + */ + +/* just do one frame at a time */ + +void render_vgmstream_interleave_byte(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { + /* frame sizes are much smaller than this */ + uint8_t sample_data[0x400]; + int samples_written=0; + + int frame_size = get_vgmstream_frame_size(vgmstream); + int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); + int samples_this_block; + + samples_this_block = samples_per_frame; + + while (samples_writtenloop_flag && vgmstream_do_loop(vgmstream)) { + continue; + } + + samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); + + if (samples_written+samples_to_do > sample_count) + samples_to_do=sample_count-samples_written; + + { + int i,j; + for (j=0;jchannels;j++) { + for (i=0;ich[j].offset+ + i/vgmstream->interleave_block_size* + vgmstream->interleave_block_size* + vgmstream->channels+ + i%vgmstream->interleave_block_size, + vgmstream->ch[j].streamfile); + } + decode_vgmstream_mem(vgmstream, samples_written, + samples_to_do, buffer, sample_data, j); + } + } + + samples_written += samples_to_do; + vgmstream->current_sample += samples_to_do; + vgmstream->samples_into_block+=samples_to_do; + + if (vgmstream->samples_into_block==samples_this_block) { + int chan; + for (chan=0;chanchannels;chan++) + vgmstream->ch[chan].offset+=frame_size*vgmstream->channels; + vgmstream->samples_into_block=0; + } + + } +} diff --git a/src/layout/layout.h b/src/layout/layout.h index 749994cd..86cce6a7 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -26,4 +26,6 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); +void render_vgmstream_interleave_byte(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); + #endif diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 1eec3f73..ae423a32 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -530,6 +530,10 @@ RelativePath=".\layout\interleave.c" > + + diff --git a/src/meta/ps2_fsb.c b/src/meta/ps2_fsb.c index 2ff381dc..51a316ce 100644 --- a/src/meta/ps2_fsb.c +++ b/src/meta/ps2_fsb.c @@ -20,7 +20,11 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) { if (read_32bitBE(0x00,streamFile) != 0x46534233) /* "FSB3\0" */ goto fail; - loop_flag = 0; /* (read_32bitLE(0x08,streamFile)!=0); */ + if (read_32bitBE(0x48,streamFile) == 0x02000806) { + loop_flag = 1; + } else { + loop_flag = 0; /* (read_32bitLE(0x08,streamFile)!=0); */ + } channel_count = 2; /* build the VGMSTREAM */ @@ -33,6 +37,7 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) { case 0x40008800: /* PS2 (Agent Hugo, Flat Out 2) */ vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*28/16/channel_count; if (loop_flag) { vgmstream->loop_start_sample = 0; @@ -42,6 +47,7 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) { case 0x41008800: /* PS2 (Flat Out) */ vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*28/16/channel_count; if (loop_flag) { vgmstream->loop_start_sample = 0; @@ -50,32 +56,49 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) { break; case 0x02000806: /* WII (Metroid Prime) */ + case 0x01000806: /* WII (Metroid Prime) */ + vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*14/8/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x40,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x44,streamFile); + } vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_interleave_byte; + vgmstream->interleave_block_size = 2; + break; case 0x40000802: /* WII () */ vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; vgmstream->num_samples = (read_32bitLE(0x0C,streamFile)); if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = (read_32bitLE(0x0C,streamFile)); + vgmstream->loop_start_sample = read_32bitLE(0x40,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x44,streamFile); } break; default: goto fail; } /* fill in the vital statistics */ - start_offset = (read_32bitLE(0x08,streamFile))+fsb3_headerlen; + start_offset = (read_32bitLE(0x08,streamFile))+fsb3_headerlen; vgmstream->channels = read_16bitLE(0x56,streamFile); vgmstream->sample_rate = read_32bitLE(0x4C,streamFile); - - - - vgmstream->interleave_block_size = 0x10; vgmstream->meta_type = meta_FSB; + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x68+i*2,streamFile); + } + if (vgmstream->channels) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x96+i*2,streamFile); + } + } + } + /* open the file for reading */ { int i; diff --git a/src/vgmstream.c b/src/vgmstream.c index e7e1da25..4d09765d 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -326,6 +326,9 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_ws_aud_blocked: render_vgmstream_blocked(buffer,sample_count,vgmstream); break; + case layout_interleave_byte: + render_vgmstream_interleave_byte(buffer,sample_count,vgmstream); + break; } } @@ -438,6 +441,20 @@ int get_vgmstream_shortframe_size(VGMSTREAM * vgmstream) { } } +void decode_vgmstream_mem(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer, uint8_t * data, int channel) { + + switch (vgmstream->coding_type) { + case coding_NGC_DSP: + decode_ngc_dsp_mem(&vgmstream->ch[channel], + buffer+samples_written*vgmstream->channels+channel, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do, data); + break; + default: + break; + } +} + void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer) { int chan; diff --git a/src/vgmstream.h b/src/vgmstream.h index 785e0105..2f2d901e 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -349,6 +349,10 @@ int get_vgmstream_shortframe_size(VGMSTREAM * vgmstream); * samples ahead of us. Decode those samples into the buffer. */ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer); +/* Assume additionally that we have samples_to_do consecutive samples in "data", + * and this this is for channel number "channel" */ +void decode_vgmstream_mem(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer, uint8_t * data, int channel); + /* calculate number of consecutive samples to do (taking into account stopping for loop start and end) */ int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM * vgmstream);