Clean scd_int layout and rename to layered layout for later reuse

This commit is contained in:
bnnm 2018-03-30 21:28:32 +02:00
parent 642c833fcd
commit c843c350d1
6 changed files with 162 additions and 88 deletions

View File

@ -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)"},

View File

@ -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

View File

@ -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]);
}
}

View File

@ -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;i<channel_count;i++) {
/* open each layer subfile */
for (i = 0; i < channel_count; i++) {
STREAMFILE* temp_streamFile = setup_scd_dsp_streamfile(streamFile, start_offset+interleave_size*i, interleave_size, stride_size, total_size);
if (!temp_streamFile) goto fail;
data->substreams[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;
}

View File

@ -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;i<data->substream_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;i<data->substream_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

View File

@ -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;