mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 01:30:49 +01:00
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
This commit is contained in:
parent
149b7a1bab
commit
ec94c0d3c5
@ -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 \
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_byte = mem[framesin*8+1+i/2];
|
||||
|
||||
#ifdef DEBUG
|
||||
if (hist1==stream->loop_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
|
||||
|
@ -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
|
||||
|
62
src/layout/interleave_byte.c
Normal file
62
src/layout/interleave_byte.c
Normal file
@ -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_written<sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
if (vgmstream->loop_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;j<vgmstream->channels;j++) {
|
||||
for (i=0;i<frame_size;i++) {
|
||||
sample_data[i] = read_8bit(vgmstream->ch[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;chan<vgmstream->channels;chan++)
|
||||
vgmstream->ch[chan].offset+=frame_size*vgmstream->channels;
|
||||
vgmstream->samples_into_block=0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -530,6 +530,10 @@
|
||||
RelativePath=".\layout\interleave.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\interleave_byte.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\nolayout.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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user