diff --git a/src/layout/aax_layout.c b/src/layout/aax_layout.c index 2e0834ae..9d14dc11 100644 --- a/src/layout/aax_layout.c +++ b/src/layout/aax_layout.c @@ -2,29 +2,51 @@ #include "../vgmstream.h" #include "../coding/coding.h" +aax_codec_data* init_layout_aax(int segment_count) { + aax_codec_data *data = NULL; + + if (segment_count <= 0 || segment_count > 255) + goto fail; + + data = calloc(1, sizeof(aax_codec_data)); + if (!data) goto fail; + + data->segment_count = segment_count; + data->current_segment = 0; + + data->segments = calloc(segment_count, sizeof(VGMSTREAM*)); + if (!data->segments) goto fail; + + return data; +fail: + free_layout_aax(data); + return NULL; +} + + void render_vgmstream_aax(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { int samples_written=0; aax_codec_data *data = vgmstream->codec_data; while (samples_writtensample_counts[data->current_segment]; + int samples_this_block = data->segments[data->current_segment]->num_samples; if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { int i; data->current_segment = data->loop_segment; - reset_vgmstream(data->adxs[data->current_segment]); + reset_vgmstream(data->segments[data->current_segment]); /* carry over the history from the loop point */ if (data->loop_segment > 0) { - for (i=0;iadxs[0]->channels;i++) + for (i=0;isegments[0]->channels;i++) { - data->adxs[data->loop_segment]->ch[i].adpcm_history1_32 = - data->adxs[data->loop_segment-1]->ch[i].adpcm_history1_32; - data->adxs[data->loop_segment]->ch[i].adpcm_history2_32 = - data->adxs[data->loop_segment-1]->ch[i].adpcm_history2_32; + data->segments[data->loop_segment]->ch[i].adpcm_history1_32 = + data->segments[data->loop_segment-1]->ch[i].adpcm_history1_32; + data->segments[data->loop_segment]->ch[i].adpcm_history2_32 = + data->segments[data->loop_segment-1]->ch[i].adpcm_history2_32; } } vgmstream->samples_into_block = 0; @@ -43,25 +65,55 @@ void render_vgmstream_aax(sample * buffer, int32_t sample_count, VGMSTREAM * vgm int i; data->current_segment++; /*printf("advance to %d at %d samples\n",data->current_segment,vgmstream->current_sample);*/ - reset_vgmstream(data->adxs[data->current_segment]); + reset_vgmstream(data->segments[data->current_segment]); /* carry over the history from the previous segment */ - for (i=0;iadxs[0]->channels;i++) + for (i=0;isegments[0]->channels;i++) { - data->adxs[data->current_segment]->ch[i].adpcm_history1_32 = - data->adxs[data->current_segment-1]->ch[i].adpcm_history1_32; - data->adxs[data->current_segment]->ch[i].adpcm_history2_32 = - data->adxs[data->current_segment-1]->ch[i].adpcm_history2_32; + data->segments[data->current_segment]->ch[i].adpcm_history1_32 = + data->segments[data->current_segment-1]->ch[i].adpcm_history1_32; + data->segments[data->current_segment]->ch[i].adpcm_history2_32 = + data->segments[data->current_segment-1]->ch[i].adpcm_history2_32; } vgmstream->samples_into_block = 0; continue; } - render_vgmstream(&buffer[samples_written*data->adxs[data->current_segment]->channels], - samples_to_do,data->adxs[data->current_segment]); + render_vgmstream(&buffer[samples_written*data->segments[data->current_segment]->channels], + samples_to_do,data->segments[data->current_segment]); samples_written += samples_to_do; vgmstream->current_sample += samples_to_do; vgmstream->samples_into_block+=samples_to_do; } } + + +void free_layout_aax(aax_codec_data *data) { + int i; + + if (!data) + return; + + if (data->segments) { + for (i = 0; i < data->segment_count; i++) { + /* note that the close_streamfile won't do anything but deallocate itself, + * there is only one open file in vgmstream->ch[0].streamfile */ + close_vgmstream(data->segments[i]); + } + free(data->segments); + } + free(data); +} + +void reset_layout_aax(aax_codec_data *data) { + int i; + + if (!data) + return; + + data->current_segment = 0; + for (i = 0; i < data->segment_count; i++) { + reset_vgmstream(data->segments[i]); + } +} diff --git a/src/layout/layout.h b/src/layout/layout.h index 3706c331..19c2b328 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -73,6 +73,9 @@ void render_vgmstream_mus_acm(sample * buffer, int32_t sample_count, VGMSTREAM * void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); void render_vgmstream_aax(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); +aax_codec_data* init_layout_aax(int segment_count); +void free_layout_aax(aax_codec_data *data); +void reset_layout_aax(aax_codec_data *data); void render_vgmstream_scd_int(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); diff --git a/src/meta/aax.c b/src/meta/aax.c index 04385792..b61fa57e 100644 --- a/src/meta/aax.c +++ b/src/meta/aax.c @@ -1,221 +1,180 @@ #include "meta.h" +#include "../layout/layout.h" +#include "../coding/coding.h" #include "aax_streamfile.h" #include "aax_utf.h" -/* AAX - segmented ADX [Bayonetta (PS3), Pandora's Tower (Wii), Catherine (X360)] */ +#define MAX_SEGMENTS 2 /* usually segment0=intro, segment1=loop/main */ + +/* AAX - segmented ADX [Bayonetta (PS3), Pandora's Tower (Wii), Catherine (X360), Binary Domain (PS3)] */ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - STREAMFILE * streamFileAAX = NULL; - STREAMFILE * streamFileADX = NULL; char filename[PATH_LIMIT]; - off_t *segment_offset = NULL; - off_t *segment_size = NULL; - int32_t sample_count; - int table_error = 0; + STREAMFILE * streamFileAAX = NULL; - int loop_flag = 0; - int32_t loop_start_sample=0; - int32_t loop_end_sample=0; - int loop_segment = 0; + int loop_flag = 0, channel_count = 0; + int32_t sample_count, loop_start_sample = 0, loop_end_sample = 0; + int segment_count, loop_segment = 0; aax_codec_data *data = NULL; - - const long AAX_offset = 0; - - int channel_count = 0, segment_count; - int sample_rate = 0; - + int table_error = 0; + const long top_offset = 0x00; + off_t segment_offset[MAX_SEGMENTS]; + size_t segment_size[MAX_SEGMENTS]; int i; - long aax_data_offset; + /* checks */ + if (!check_extensions(streamFile, "aax")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */ + goto fail; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("aax",filename_extension(filename))) goto fail; - - /* get AAX entry count, data offset */ + + /* get segment count, offsets and sizes */ { struct utf_query_result result; long aax_string_table_offset; long aax_string_table_size; - - result = query_utf_nofail(streamFile, AAX_offset, NULL, &table_error); + long aax_data_offset; + + result = query_utf_nofail(streamFile, top_offset, NULL, &table_error); if (table_error) goto fail; + segment_count = result.rows; - aax_string_table_offset = AAX_offset + 8 + result.string_table_offset; - aax_data_offset = AAX_offset + 8 + result.data_offset; + if (segment_count > MAX_SEGMENTS) goto fail; + + aax_string_table_offset = top_offset+0x08 + result.string_table_offset; + aax_data_offset = top_offset+0x08 + result.data_offset; aax_string_table_size = aax_data_offset - aax_string_table_offset; - if (result.name_offset+4 > aax_string_table_size) goto fail; - if (read_32bitBE(aax_string_table_offset + result.name_offset, - streamFile) != 0x41415800) /* "AAX\0" */ + if (result.name_offset+0x04 > aax_string_table_size) goto fail; + if (read_32bitBE(aax_string_table_offset + result.name_offset, streamFile) != 0x41415800) /* "AAX\0" */ + goto fail; + + /* get offsets of constituent segments */ + for (i = 0; i < segment_count; i++) { + struct offset_size_pair offset_size; + + offset_size = query_utf_data(streamFile, top_offset, i, "data", &table_error); + if (table_error) goto fail; + + segment_offset[i] = aax_data_offset + offset_size.offset; + segment_size[i] = offset_size.size; + } } - segment_offset = calloc(segment_count,sizeof(off_t)); - if (!segment_offset) - goto fail; - segment_size = calloc(segment_count,sizeof(off_t)); - if (!segment_size) - goto fail; - - /* get offsets of constituent ADXs */ - for (i = 0; i < segment_count; i++) - { - struct offset_size_pair offset_size; - offset_size = query_utf_data(streamFile, AAX_offset, i, "data", &table_error); - if (table_error) goto fail; - segment_offset[i] = aax_data_offset + offset_size.offset; - segment_size[i] = offset_size.size; - } + /* init layout */ + data = init_layout_aax(segment_count); + if (!data) goto fail; + /* get temp file */ + streamFile->get_name(streamFile,filename,sizeof(filename)); streamFileAAX = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!streamFileAAX) goto fail; - data = malloc(sizeof(aax_codec_data)); - if (!data) goto fail; - data->segment_count = segment_count; - data->adxs = malloc(sizeof(STREAMFILE *)*segment_count); - if (!data->adxs) goto fail; - for (i=0;iadxs[i] = NULL; - } - data->sample_counts = calloc(segment_count,sizeof(int32_t)); - if (!data->sample_counts) goto fail; + /* open each segment subfile */ + for (i = 0; i < segment_count; i++) { + STREAMFILE* temp_streamFile = open_aax_with_STREAMFILE(streamFileAAX,segment_offset[i],segment_size[i]); + if (!temp_streamFile) goto fail; - /* for each segment */ - for (i = 0; i < segment_count; i++) - { - VGMSTREAM *adx; - /*printf("try opening segment %d/%d %x\n",i,segment_count,segment_offset[i]);*/ - streamFileADX = open_aax_with_STREAMFILE(streamFileAAX,segment_offset[i],segment_size[i]); - if (!streamFileADX) goto fail; - adx = data->adxs[i] = init_vgmstream_adx(streamFileADX); - if (!adx) + data->segments[i] = init_vgmstream_adx(temp_streamFile); + + close_streamfile(temp_streamFile); + + if (!data->segments[i]) goto fail; - data->sample_counts[i] = adx->num_samples; - close_streamfile(streamFileADX); streamFileADX = NULL; - - if (i == 0) - { - channel_count = adx->channels; - sample_rate = adx->sample_rate; - } - else - { - if (channel_count != adx->channels) + if (data->segments[i]->loop_flag != 0) + goto fail; /* should never happen (could be simply disabled tho) */ + if (i > 0) { + if (data->segments[i]->channels != data->segments[i-1]->channels) goto fail; - if (sample_rate != adx->sample_rate) + if (data->segments[i]->sample_rate != data->segments[i-1]->sample_rate) + goto fail; + if (data->segments[i]->coding_type != data->segments[i-1]->coding_type) goto fail; } - if (adx->loop_flag != 0) - goto fail; - /* save start things so we can restart for seeking/looping */ - /* copy the channels */ - memcpy(adx->start_ch,adx->ch,sizeof(VGMSTREAMCHANNEL)*adx->channels); - /* copy the whole VGMSTREAM */ - memcpy(adx->start_vgmstream,adx,sizeof(VGMSTREAM)); - + memcpy(data->segments[i]->start_ch,data->segments[i]->ch,sizeof(VGMSTREAMCHANNEL)*data->segments[i]->channels); + memcpy(data->segments[i]->start_vgmstream,data->segments[i],sizeof(VGMSTREAM)); } + /* get looping and samples */ sample_count = 0; loop_flag = 0; - for (i = 0; i < segment_count; i++) - { - int segment_loop_flag = query_utf_1byte(streamFile, AAX_offset, i, - "lpflg", &table_error); + for (i = 0; i < segment_count; i++) { + int segment_loop_flag = query_utf_1byte(streamFile, top_offset, i, "lpflg", &table_error); if (table_error) segment_loop_flag = 0; - if (!loop_flag && segment_loop_flag) - { + if (!loop_flag && segment_loop_flag) { loop_start_sample = sample_count; loop_segment = i; } - sample_count += data->sample_counts[i]; + sample_count += data->segments[i]->num_samples; - if (!loop_flag && segment_loop_flag) - { + if (!loop_flag && segment_loop_flag) { loop_end_sample = sample_count; loop_flag = 1; } } + + channel_count = data->segments[0]->channels; + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + vgmstream->sample_rate = data->segments[0]->sample_rate; vgmstream->num_samples = sample_count; - vgmstream->sample_rate = sample_rate; - vgmstream->loop_start_sample = loop_start_sample; vgmstream->loop_end_sample = loop_end_sample; - vgmstream->coding_type = data->adxs[0]->coding_type; - vgmstream->layout_type = layout_aax; vgmstream->meta_type = meta_AAX; - - vgmstream->ch[0].streamfile = streamFileAAX; - data->current_segment = 0; - data->loop_segment = loop_segment; + vgmstream->coding_type = data->segments[0]->coding_type; + vgmstream->layout_type = layout_aax; vgmstream->codec_data = data; - free(segment_offset); - free(segment_size); + data->loop_segment = loop_segment; return vgmstream; - /* clean up anything we may have opened */ fail: - if (streamFileAAX) close_streamfile(streamFileAAX); - if (streamFileADX) close_streamfile(streamFileADX); - if (vgmstream) close_vgmstream(vgmstream); - if (segment_offset) free(segment_offset); - if (segment_size) free(segment_size); - if (data) { - if (data->adxs) - { - int i; - for (i=0;isegment_count;i++) - if (data->adxs) - close_vgmstream(data->adxs[i]); - free(data->adxs); - } - if (data->sample_counts) - { - free(data->sample_counts); - } - free(data); - } + close_streamfile(streamFileAAX); + close_vgmstream(vgmstream); + free_layout_aax(data); return NULL; } -/* CRI's UTF wrapper around DSP */ +/* CRI's UTF wrapper around DSP [Sonic Colors sfx (Wii), NiGHTS: Journey of Dreams sfx (Wii)] */ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int table_error = 0; + off_t start_offset; + size_t channel_size; - int loop_flag = 0; - - const long top_offset = 0; - - int channel_count; - int sample_rate; + int loop_flag = 0, channel_count, sample_rate; long sample_count; + int table_error = 0; + const long top_offset = 0x00; long top_data_offset, segment_count; long body_offset, body_size; long header_offset, header_size; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - //if (strcasecmp("aax",filename_extension(filename))) goto fail; - /* get entry count, data offset */ + /* checks */ + /* files don't have extension, we accept "" for CLI and .aax for plugins (they aren't exactly .aax though) */ + if (!check_extensions(streamFile, "aax,")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */ + goto fail; + + /* get segment count, offsets and sizes*/ { struct utf_query_result result; long top_string_table_offset; @@ -224,8 +183,10 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { result = query_utf_nofail(streamFile, top_offset, NULL, &table_error); if (table_error) goto fail; + segment_count = result.rows; - if (segment_count != 1) goto fail; // only simple stuff for now + if (segment_count != 1) goto fail; /* only simple stuff for now (multisegment not known) */ + top_string_table_offset = top_offset + 8 + result.string_table_offset; top_data_offset = top_offset + 8 + result.data_offset; top_string_table_size = top_data_offset - top_string_table_offset; @@ -233,12 +194,13 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { if (result.name_offset+10 > top_string_table_size) goto fail; name_offset = top_string_table_offset + result.name_offset; - if (read_32bitBE(name_offset, streamFile) != 0x41445043 ||// "ADPC" - read_32bitBE(name_offset+4, streamFile) != 0x4D5F5749 ||// "M_WI" - read_16bitBE(name_offset+8, streamFile) != 0x4900) // "I\0" + if (read_32bitBE(name_offset+0x00, streamFile) != 0x41445043 || /* "ADPC" */ + read_32bitBE(name_offset+0x04, streamFile) != 0x4D5F5749 || /* "M_WI" */ + read_16bitBE(name_offset+0x08, streamFile) != 0x4900) /* "I\0" */ goto fail; } + /* get sizes */ { struct offset_size_pair offset_size; @@ -260,36 +222,29 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { if (channel_count != 1 && channel_count != 2) goto fail; if (header_size != channel_count * 0x60) goto fail; + start_offset = body_offset; + channel_size = (body_size+7) / 8 * 8 / channel_count; + + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; - vgmstream->num_samples = sample_count; vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = sample_count; - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_UTF_DSP; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = channel_size; - { - int i,j; - long channel_size = (body_size+7)/8*8/channel_count; - for (i = 0; i < channel_count; i++) - { - vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[i].streamfile) goto fail; - vgmstream->ch[i].channel_start_offset = - vgmstream->ch[i].offset = body_offset + i * channel_size; - for (j=0;j<16;j++) - { - vgmstream->ch[i].adpcm_coef[j] = - read_16bitBE(header_offset + 0x60*i + 0x1c + j*2, streamFile); - } - } - } + dsp_read_coefs_be(vgmstream, streamFile, header_offset+0x1c, 0x60); + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/src/meta/aax_streamfile.h b/src/meta/aax_streamfile.h index 1490e7c4..bc1b3d60 100644 --- a/src/meta/aax_streamfile.h +++ b/src/meta/aax_streamfile.h @@ -28,7 +28,7 @@ static void close_aax(AAXSTREAMFILE *streamfile) { } static size_t get_size_aax(AAXSTREAMFILE *streamfile) { - return 0; + return get_streamfile_size(streamfile->real_file); } static size_t get_offset_aax(AAXSTREAMFILE *streamfile) { diff --git a/src/vgmstream.c b/src/vgmstream.c index 7a9ab724..b8d262c4 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -601,13 +601,7 @@ void reset_vgmstream(VGMSTREAM * vgmstream) { } if (vgmstream->layout_type==layout_aax) { - aax_codec_data *data = vgmstream->codec_data; - int i; - - data->current_segment = 0; - for (i=0;isegment_count;i++) { - reset_vgmstream(data->adxs[i]); - } + reset_layout_aax(vgmstream->codec_data); } if (vgmstream->layout_type==layout_scd_int) { @@ -825,24 +819,7 @@ void close_vgmstream(VGMSTREAM * vgmstream) { } if (vgmstream->layout_type==layout_aax) { - aax_codec_data *data = (aax_codec_data *) vgmstream->codec_data; - - if (data) { - if (data->adxs) { - int i; - for (i=0;isegment_count;i++) { - /* note that the close_streamfile won't do anything but deallocate itself, - * there is only one open file in vgmstream->ch[0].streamfile */ - close_vgmstream(data->adxs[i]); - } - free(data->adxs); - } - if (data->sample_counts) { - free(data->sample_counts); - } - - free(data); - } + free_layout_aax(vgmstream->codec_data); vgmstream->codec_data = NULL; } @@ -2458,6 +2435,11 @@ static STREAMFILE * get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM * { //AAX, AIX, ACM? + if (vgmstream->layout_type==layout_aax) { + aax_codec_data *data = (aax_codec_data *) vgmstream->codec_data; + return data->segments[0]->ch[channel].streamfile; //todo not correct with multifile segments (ex. .ACM Ogg) + } + if (vgmstream->layout_type==layout_scd_int) { scd_int_codec_data *data = (scd_int_codec_data *) vgmstream->codec_data; return data->intfiles[channel]; @@ -2557,7 +2539,7 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s int use_same_offset_per_channel = 0; - /* stream/offsets not needed, manages themselves */ + /* stream/offsets not needed, manage themselves */ if (vgmstream->layout_type == layout_aix || vgmstream->layout_type == layout_aax || vgmstream->layout_type == layout_scd_int) diff --git a/src/vgmstream.h b/src/vgmstream.h index 5c57fa6a..49a1ed75 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -1065,13 +1065,12 @@ typedef struct { VGMSTREAM **adxs; } aix_codec_data; +/* for files made of segments, each a full subfile (VGMSTREAM) */ typedef struct { int segment_count; int current_segment; int loop_segment; - /* one per segment */ - int32_t *sample_counts; - VGMSTREAM **adxs; + VGMSTREAM **segments; } aax_codec_data; /* for compressed NWA */