mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-21 10:55:53 +01:00
222 lines
6.6 KiB
C
222 lines
6.6 KiB
C
#include "meta.h"
|
|
#include "../layout/layout.h"
|
|
#include "../coding/coding.h"
|
|
#include "cri_utf.h"
|
|
|
|
|
|
#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;
|
|
int loop_flag = 0, channel_count = 0;
|
|
int32_t sample_count, loop_start_sample = 0, loop_end_sample = 0;
|
|
|
|
segmented_layout_data *data = NULL;
|
|
int segment_count, loop_segment = 0, is_hca;
|
|
off_t segment_offset[MAX_SEGMENTS];
|
|
size_t segment_size[MAX_SEGMENTS];
|
|
int i;
|
|
utf_context *utf = NULL;
|
|
|
|
|
|
/* checks */
|
|
/* .aax: often with extension (with either HCA or AAX tables)
|
|
* (extensionless): sometimes without [PES 2013 (PC)] */
|
|
if (!check_extensions(streamFile, "aax,"))
|
|
goto fail;
|
|
if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */
|
|
goto fail;
|
|
|
|
/* .aax contains a simple UTF table, each row being a segment pointing to a CRI audio format */
|
|
{
|
|
int rows;
|
|
const char* name;
|
|
uint32_t table_offset = 0x00;
|
|
|
|
|
|
utf = utf_open(streamFile, table_offset, &rows, &name);
|
|
if (!utf) goto fail;
|
|
|
|
if (strcmp(name, "AAX") == 0)
|
|
is_hca = 0;
|
|
else if (strcmp(name, "HCA") == 0)
|
|
is_hca = 1;
|
|
else
|
|
goto fail;
|
|
|
|
segment_count = rows;
|
|
if (segment_count > MAX_SEGMENTS) goto fail;
|
|
|
|
|
|
/* get offsets of constituent segments */
|
|
for (i = 0; i < segment_count; i++) {
|
|
uint32_t offset, size;
|
|
uint8_t segment_loop_flag = 0;
|
|
|
|
if (!utf_query_u8(utf, i, "lpflg", &segment_loop_flag)) /* usually in last segment */
|
|
goto fail;
|
|
if (!utf_query_data(utf, i, "data", &offset, &size))
|
|
goto fail;
|
|
|
|
segment_offset[i] = table_offset + offset;
|
|
segment_size[i] = size;
|
|
if (segment_loop_flag) {
|
|
loop_flag = 1;
|
|
loop_segment = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* init layout */
|
|
data = init_layout_segmented(segment_count);
|
|
if (!data) goto fail;
|
|
|
|
/* open each segment subfile */
|
|
for (i = 0; i < segment_count; i++) {
|
|
STREAMFILE* temp_sf = setup_subfile_streamfile(streamFile, segment_offset[i],segment_size[i], (is_hca ? "hca" : "adx"));
|
|
if (!temp_sf) goto fail;
|
|
|
|
data->segments[i] = is_hca ?
|
|
init_vgmstream_hca(temp_sf) :
|
|
init_vgmstream_adx(temp_sf);
|
|
|
|
close_streamfile(temp_sf);
|
|
|
|
if (!data->segments[i]) goto fail;
|
|
}
|
|
|
|
/* setup segmented VGMSTREAMs */
|
|
if (!setup_layout_segmented(data))
|
|
goto fail;
|
|
|
|
/* get looping and samples */
|
|
sample_count = 0;
|
|
for (i = 0; i < segment_count; i++) {
|
|
|
|
if (loop_flag && loop_segment == i) {
|
|
loop_start_sample = sample_count;
|
|
}
|
|
|
|
sample_count += data->segments[i]->num_samples;
|
|
|
|
if (loop_flag && loop_segment == i) {
|
|
loop_end_sample = sample_count;
|
|
}
|
|
}
|
|
|
|
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->loop_start_sample = loop_start_sample;
|
|
vgmstream->loop_end_sample = loop_end_sample;
|
|
|
|
vgmstream->meta_type = meta_AAX;
|
|
vgmstream->coding_type = data->segments[0]->coding_type;
|
|
vgmstream->layout_type = layout_segmented;
|
|
|
|
vgmstream->layout_data = data;
|
|
|
|
utf_close(utf);
|
|
return vgmstream;
|
|
|
|
fail:
|
|
utf_close(utf);
|
|
close_vgmstream(vgmstream);
|
|
free_layout_segmented(data);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* 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;
|
|
off_t start_offset;
|
|
uint8_t loop_flag = 0, channel_count;
|
|
uint32_t sample_rate, num_samples, loop_start, loop_end, interleave;
|
|
uint32_t data_offset, data_size, header_offset, header_size;
|
|
utf_context *utf = NULL;
|
|
|
|
|
|
/* checks */
|
|
/* .aax: assumed
|
|
* (extensionless): extracted names inside csb/cpk often don't have extensions */
|
|
if (!check_extensions(streamFile, "aax,"))
|
|
goto fail;
|
|
if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */
|
|
goto fail;
|
|
|
|
/* .aax contains a simple UTF table with one row and various columns being header info */
|
|
{
|
|
int rows;
|
|
const char* name;
|
|
uint32_t table_offset = 0x00;
|
|
|
|
|
|
utf = utf_open(streamFile, table_offset, &rows, &name);
|
|
if (!utf) goto fail;
|
|
|
|
if (strcmp(name, "ADPCM_WII") != 0)
|
|
goto fail;
|
|
|
|
if (rows != 1)
|
|
goto fail;
|
|
|
|
if (!utf_query_u32(utf, 0, "sfreq", &sample_rate))
|
|
goto fail;
|
|
if (!utf_query_u32(utf, 0, "nsmpl", &num_samples))
|
|
goto fail;
|
|
if (!utf_query_u8(utf, 0, "nch", &channel_count))
|
|
goto fail;
|
|
if (!utf_query_u8(utf, 0, "lpflg", &loop_flag)) /* full loops */
|
|
goto fail;
|
|
/* for some reason data is stored before header */
|
|
if (!utf_query_data(utf, 0, "data", &data_offset, &data_size))
|
|
goto fail;
|
|
if (!utf_query_data(utf, 0, "header", &header_offset, &header_size))
|
|
goto fail;
|
|
|
|
if (channel_count < 1 || channel_count > 2)
|
|
goto fail;
|
|
if (header_size != channel_count * 0x60)
|
|
goto fail;
|
|
|
|
start_offset = data_offset;
|
|
interleave = (data_size+7) / 8 * 8 / channel_count;
|
|
|
|
loop_start = read_32bitBE(header_offset + 0x10, streamFile);
|
|
loop_end = read_32bitBE(header_offset + 0x14, streamFile);
|
|
}
|
|
|
|
|
|
/* build the VGMSTREAM */
|
|
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
|
if (!vgmstream) goto fail;
|
|
|
|
vgmstream->sample_rate = sample_rate;
|
|
vgmstream->num_samples = num_samples;
|
|
vgmstream->loop_start_sample = dsp_nibbles_to_samples(loop_start);
|
|
vgmstream->loop_end_sample = dsp_nibbles_to_samples(loop_end) + 1;
|
|
|
|
vgmstream->coding_type = coding_NGC_DSP;
|
|
vgmstream->layout_type = layout_interleave;
|
|
vgmstream->interleave_block_size = interleave;
|
|
vgmstream->meta_type = meta_UTF_DSP;
|
|
|
|
dsp_read_coefs_be(vgmstream, streamFile, header_offset+0x1c, 0x60);
|
|
|
|
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
|
goto fail;
|
|
return vgmstream;
|
|
|
|
fail:
|
|
close_vgmstream(vgmstream);
|
|
return NULL;
|
|
}
|