From c843c350d164affe6882ec1e6981fc5034214e8e Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 30 Mar 2018 21:28:32 +0200 Subject: [PATCH] Clean scd_int layout and rename to layered layout for later reuse --- src/formats.c | 4 +- src/layout/layout.h | 6 +- src/layout/scd_int_layout.c | 112 +++++++++++++++++++++++++++++++----- src/meta/sqex_scd.c | 62 ++++++++++---------- src/vgmstream.c | 47 +++++---------- src/vgmstream.h | 19 +++--- 6 files changed, 162 insertions(+), 88 deletions(-) diff --git a/src/formats.c b/src/formats.c index c34a45be..ecc09cd9 100644 --- a/src/formats.c +++ b/src/formats.c @@ -559,8 +559,8 @@ static const layout_info layout_info_list[] = { {layout_interleave, "interleave"}, {layout_segmented, "segmented"}, - {layout_aix, "AIX interleave, internally 18-byte interleaved"}, - {layout_scd_int, "SCD multistream interleave"}, + {layout_layered, "layered"}, + {layout_aix, "AIX"}, {layout_blocked_mxch, "blocked (MxCh)"}, {layout_blocked_ast, "blocked (AST)"}, diff --git a/src/layout/layout.h b/src/layout/layout.h index 743a3439..a8fc7834 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -57,6 +57,10 @@ int setup_layout_segmented(segmented_layout_data* data); void free_layout_segmented(segmented_layout_data *data); void reset_layout_segmented(segmented_layout_data *data); -void render_vgmstream_scd_int(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); +void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); +layered_layout_data* init_layout_layered(int layer_count); +int setup_layout_layered(layered_layout_data* data); +void free_layout_layered(layered_layout_data *data); +void reset_layout_layered(layered_layout_data *data); #endif diff --git a/src/layout/scd_int_layout.c b/src/layout/scd_int_layout.c index 1a2c5e8a..11fc468f 100644 --- a/src/layout/scd_int_layout.c +++ b/src/layout/scd_int_layout.c @@ -2,37 +2,121 @@ #include "../vgmstream.h" /* TODO: currently only properly handles mono substreams */ -/* TODO: there must be a reasonable way to respect the loop settings, as is - the substreams are in their own little world */ +/* TODO: there must be a reasonable way to respect the loop settings, as + the substreams are in their own little world. + Currently the VGMSTREAMs layers loop internally and the external/base VGMSTREAM + doesn't actually loop, and would ignore any altered values/loop_flag. */ #define INTERLEAVE_BUF_SIZE 512 -void render_vgmstream_scd_int(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { + + +void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { sample interleave_buf[INTERLEAVE_BUF_SIZE]; int32_t samples_done = 0; - scd_int_codec_data *data = vgmstream->codec_data; + layered_layout_data *data = vgmstream->layout_data; - while (samples_done < sample_count) - { + while (samples_done < sample_count) { int32_t samples_to_do = INTERLEAVE_BUF_SIZE; int c; if (samples_to_do > sample_count - samples_done) samples_to_do = sample_count - samples_done; - for (c=0; c < data->substream_count; c++) - { + for (c=0; c < data->layer_count; c++) { int32_t i; - render_vgmstream(interleave_buf, - samples_to_do, data->substreams[c]); + render_vgmstream(interleave_buf, samples_to_do, data->layers[c]); - for (i=0; i < samples_to_do; i++) - { - buffer[(samples_done+i)*data->substream_count + c] = interleave_buf[i]; + for (i=0; i < samples_to_do; i++) { + buffer[(samples_done+i)*data->layer_count + c] = interleave_buf[i]; } } samples_done += samples_to_do; - } } + +layered_layout_data* init_layout_layered(int layer_count) { + layered_layout_data *data = NULL; + + if (layer_count <= 0 || layer_count > 255) + goto fail; + + data = calloc(1, sizeof(layered_layout_data)); + if (!data) goto fail; + + data->layer_count = layer_count; + + data->layers = calloc(layer_count, sizeof(VGMSTREAM*)); + if (!data->layers) goto fail; + + return data; +fail: + free_layout_layered(data); + return NULL; +} + +int setup_layout_layered(layered_layout_data* data) { + int i; + + /* setup each VGMSTREAM (roughly equivalent to vgmstream.c's init_vgmstream_internal stuff) */ + for (i = 0; i < data->layer_count; i++) { + if (!data->layers[i]) + goto fail; + + if (data->layers[i]->num_samples <= 0) + goto fail; + + //todo only mono at the moment + if (data->layers[i]->channels != 1) + goto fail; + + if (i > 0) { + /* a bit weird, but no matter */ + if (data->layers[i]->sample_rate != data->layers[i-1]->sample_rate) { + VGM_LOG("layered layout: layer %i has different sample rate\n", i); + } + + /* also weird */ + if (data->layers[i]->coding_type != data->layers[i-1]->coding_type) { + VGM_LOG("layered layout: layer %i has different coding type\n", i); + } + } + + //todo could check if layers'd loop match vs main, etc + + /* save start things so we can restart for seeking/looping */ + memcpy(data->layers[i]->start_ch,data->layers[i]->ch,sizeof(VGMSTREAMCHANNEL)*data->layers[i]->channels); + memcpy(data->layers[i]->start_vgmstream,data->layers[i],sizeof(VGMSTREAM)); + } + + return 1; +fail: + return 0; /* caller is expected to free */ +} + +void free_layout_layered(layered_layout_data *data) { + int i; + + if (!data) + return; + + if (data->layers) { + for (i = 0; i < data->layer_count; i++) { + close_vgmstream(data->layers[i]); + } + free(data->layers); + } + free(data); +} + +void reset_layout_layered(layered_layout_data *data) { + int i; + + if (!data) + return; + + for (i = 0; i < data->layer_count; i++) { + reset_vgmstream(data->layers[i]); + } +} diff --git a/src/meta/sqex_scd.c b/src/meta/sqex_scd.c index 870e46c3..dd14dbf4 100644 --- a/src/meta/sqex_scd.c +++ b/src/meta/sqex_scd.c @@ -1,5 +1,6 @@ #include "meta.h" #include "../coding/coding.h" +#include "../layout/layout.h" #include "sqex_scd_streamfile.h" @@ -279,53 +280,54 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { case 0x0A: /* DSP ADPCM [Dragon Quest X (Wii)] */ case 0x15: { /* DSP ADPCM [Dragon Quest X (Wii U)] (no apparent differences except higher sample rate) */ - int i; const off_t interleave_size = 0x800; const off_t stride_size = interleave_size * channel_count; + int i; size_t total_size; - scd_int_codec_data * data = NULL; - + layered_layout_data * data = NULL; + /* interleaved DSPs including the header (so the first 0x800 is 0x60 header + 0x740 data) + * so interleave layout can't used; we'll setup de-interleaving streamfiles as layers/channels instead */ + //todo this could be simplified using a block layout or adding interleave_first_block vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_scd_int; + vgmstream->layout_type = layout_layered; - /* a normal DSP header... */ - total_size = (read_32bitBE(start_offset+0x04,streamFile)+1)/2; - vgmstream->num_samples = read_32bitBE(start_offset+0x00,streamFile); - if (loop_flag) { - vgmstream->loop_start_sample = loop_start; - vgmstream->loop_end_sample = loop_end+1; - } + /* read from the first DSP header and verify other channel headers */ + { + total_size = (read_32bitBE(start_offset+0x04,streamFile)+1)/2; /* rounded nibbles / 2 */ + vgmstream->num_samples = read_32bitBE(start_offset+0x00,streamFile); + if (loop_flag) { + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end+1; + } - /* verify other channel headers */ - for (i = 1; i < channel_count; i++) { - if (read_32bitBE(start_offset+interleave_size*i+0,streamFile) != vgmstream->num_samples || - (read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size) { - goto fail; + for (i = 1; i < channel_count; i++) { + if ((read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size || + read_32bitBE(start_offset+interleave_size*i+0x00,streamFile) != vgmstream->num_samples) { + goto fail; + } } } - data = malloc(sizeof(scd_int_codec_data)); - data->substream_count = channel_count; - data->substreams = calloc(channel_count, sizeof(VGMSTREAM *)); + /* init layout */ + data = init_layout_layered(channel_count); + if (!data) goto fail; + vgmstream->layout_data = data; - vgmstream->codec_data = data; - - for (i=0;isubstreams[i] = init_vgmstream_ngc_dsp_std(temp_streamFile); + data->layers[i] = init_vgmstream_ngc_dsp_std(temp_streamFile); close_streamfile(temp_streamFile); - if (!data->substreams[i]) goto fail; - - /* TODO: only handles mono substreams, though that's all we have with DSP */ - - /* save start things so we can restart for seeking/looping */ - memcpy(data->substreams[i]->start_ch,data->substreams[i]->ch,sizeof(VGMSTREAMCHANNEL)*1); - memcpy(data->substreams[i]->start_vgmstream,data->substreams[i],sizeof(VGMSTREAM)); + if (!data->layers[i]) goto fail; } + /* setup layered VGMSTREAMs */ + if (!setup_layout_layered(data)) + goto fail; + break; } diff --git a/src/vgmstream.c b/src/vgmstream.c index 9d560ebe..fd5c9f3d 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -603,13 +603,8 @@ void reset_vgmstream(VGMSTREAM * vgmstream) { reset_layout_segmented(vgmstream->layout_data); } - if (vgmstream->layout_type==layout_scd_int) { - scd_int_codec_data *data = vgmstream->codec_data; - int i; - - for (i=0;isubstream_count;i++) { - reset_vgmstream(data->substreams[i]); - } + if (vgmstream->layout_type==layout_layered) { + reset_layout_layered(vgmstream->layout_data); } } @@ -794,24 +789,12 @@ void close_vgmstream(VGMSTREAM * vgmstream) { if (vgmstream->layout_type==layout_segmented) { free_layout_segmented(vgmstream->layout_data); - vgmstream->codec_data = NULL; + vgmstream->layout_data = NULL; } - if (vgmstream->layout_type==layout_scd_int) { - scd_int_codec_data *data = (scd_int_codec_data *) vgmstream->codec_data; - - if (data) { - if (data->substreams) { - int i; - for (i=0;isubstream_count;i++) { - close_vgmstream(data->substreams[i]); - } - free(data->substreams); - } - - free(data); - } - vgmstream->codec_data = NULL; + if (vgmstream->layout_type==layout_layered) { + free_layout_layered(vgmstream->layout_data); + vgmstream->layout_data = NULL; } @@ -937,8 +920,8 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_segmented: render_vgmstream_segmented(buffer,sample_count,vgmstream); break; - case layout_scd_int: - render_vgmstream_scd_int(buffer,sample_count,vgmstream); + case layout_layered: + render_vgmstream_layered(buffer,sample_count,vgmstream); break; default: break; @@ -2366,9 +2349,9 @@ static int get_vgmstream_average_bitrate_channel_count(VGMSTREAM * vgmstream) { //AAX, AIX, ACM? - if (vgmstream->layout_type==layout_scd_int) { - scd_int_codec_data *data = (scd_int_codec_data *) vgmstream->codec_data; - return (data) ? data->substream_count : 0; + if (vgmstream->layout_type==layout_layered) { + layered_layout_data *data = (layered_layout_data *) vgmstream->layout_data; + return (data) ? data->layer_count : 0; } #ifdef VGM_USE_VORBIS if (vgmstream->coding_type==coding_OGG_VORBIS) { @@ -2400,9 +2383,9 @@ static STREAMFILE * get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM * { //AAX, AIX? - if (vgmstream->layout_type==layout_scd_int) { - scd_int_codec_data *data = (scd_int_codec_data *) vgmstream->codec_data; - return data->substreams[channel]->ch[0].streamfile; + if (vgmstream->layout_type==layout_layered) { + layered_layout_data *data = (layered_layout_data *) vgmstream->layout_data; + return data->layers[channel]->ch[0].streamfile; } if (vgmstream->coding_type==coding_NWA) { @@ -2525,7 +2508,7 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s /* stream/offsets not needed, manage themselves */ if (vgmstream->layout_type == layout_aix || vgmstream->layout_type == layout_segmented || - vgmstream->layout_type == layout_scd_int) + vgmstream->layout_type == layout_layered) return 1; #ifdef VGM_USE_FFMPEG diff --git a/src/vgmstream.h b/src/vgmstream.h index 25b2db5f..e42f9107 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -255,8 +255,8 @@ typedef enum { /* otherwise odd */ layout_aix, /* CRI AIX's wheels within wheels */ - layout_segmented, /* song divided in segments, each a complete VGMSTREAM */ - layout_scd_int, /* deinterleave done by the SCDINTSTREAMFILE */ + layout_segmented, /* song divided in segments (song sections) */ + layout_layered, /* song divided in layers (song channels) */ } layout_t; @@ -1056,24 +1056,25 @@ typedef struct { VGMSTREAM **adxs; } aix_codec_data; -/* for files made of segments, each a full subfile (VGMSTREAM) */ +/* for files made of "vertical" segments, one per section of a song (using a complete sub-VGMSTREAM) */ typedef struct { int segment_count; + VGMSTREAM **segments; int current_segment; int loop_segment; - VGMSTREAM **segments; } segmented_layout_data; +/* for files made of "horizontal" layers, one per group of channels (using a complete sub-VGMSTREAM) */ +typedef struct { + int layer_count; + VGMSTREAM **layers; +} layered_layout_data; + /* for compressed NWA */ typedef struct { NWAData *nwa; } nwa_codec_data; -/* SQEX SCD interleaved */ -typedef struct { - int substream_count; - VGMSTREAM **substreams; -} scd_int_codec_data; typedef struct { STREAMFILE *streamfile;