cog/Frameworks/vgmstream/vgmstream/src/meta/9tav.c

119 lines
3.8 KiB
C

#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#include "9tav_streamfile.h"
/* 9TAV - from Metal Gear Solid 2/3 HD (Vita) */
VGMSTREAM * init_vgmstream_9tav(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate, track_count;
int32_t num_samples, loop_start, loop_end;
size_t track_size;
uint32_t config_data;
int i, is_padded;
layered_layout_data * data = NULL;
STREAMFILE* temp_streamFile = NULL;
/* checks */
/* .9tav: header id */
if (!check_extensions(streamFile, "9tav"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x39544156) /* "9TAV" */
goto fail;
/* 0x04: always 0x09 */
channel_count = read_16bitLE(0x08,streamFile);
track_count = read_16bitLE(0x0a,streamFile); /* MGS3 uses multitracks */
sample_rate = read_32bitLE(0x0c,streamFile);
track_size = read_32bitLE(0x10,streamFile); /* without padding */
//data_size = read_32bitLE(0x14,streamFile); /* without padding */
num_samples = read_32bitLE(0x18,streamFile);
config_data = read_32bitBE(0x1c,streamFile);
if (read_32bitBE(0x20,streamFile) == 0x4D544146) { /* "MTAF" */
/* MGS3 has a MTAF header (data size and stuff don't match, probably for track info) */
loop_start = read_32bitLE(0x78, streamFile);
loop_end = read_32bitLE(0x7c, streamFile);
loop_flag = read_32bitLE(0x90, streamFile) & 1;
is_padded = 1; /* data also has padding and other oddities */
start_offset = 0x00;
}
else {
/* MGS2 doesn't */
loop_start = 0;
loop_end = 0;
loop_flag = 0;
is_padded = 0;
start_offset = 0x20;
}
/* init layout */
data = init_layout_layered(track_count);
if (!data) goto fail;
/* open each layer subfile */
for (i = 0; i < data->layer_count; i++) {
data->layers[i] = allocate_vgmstream(channel_count, loop_flag);
if (!data->layers[i]) goto fail;
data->layers[i]->meta_type = meta_9TAV;
data->layers[i]->sample_rate = sample_rate;
data->layers[i]->num_samples = num_samples;
data->layers[i]->loop_start_sample = loop_start;
data->layers[i]->loop_end_sample = loop_end;
#ifdef VGM_USE_ATRAC9
{
atrac9_config cfg = {0};
cfg.channels = channel_count;
cfg.config_data = config_data;
cfg.encoder_delay = atrac9_bytes_to_samples_cfg(track_size, cfg.config_data) - num_samples; /* seems ok */
if (cfg.encoder_delay > 4096) /* doesn't seem too normal */
cfg.encoder_delay = 0;
data->layers[i]->codec_data = init_atrac9(&cfg);
if (!data->layers[i]->codec_data) goto fail;
data->layers[i]->coding_type = coding_ATRAC9;
data->layers[i]->layout_type = layout_none;
}
#else
goto fail;
#endif
if (is_padded) {
temp_streamFile = setup_9tav_streamfile(streamFile, 0xFE4, track_size, i, track_count);
if (!temp_streamFile) goto fail;
}
if (!vgmstream_open_stream(data->layers[i],temp_streamFile == NULL ? streamFile : temp_streamFile,start_offset))
goto fail;
close_streamfile(temp_streamFile);
temp_streamFile = NULL;
}
/* setup layered VGMSTREAMs */
if (!setup_layout_layered(data))
goto fail;
/* build the layered VGMSTREAM */
vgmstream = allocate_layered_vgmstream(data);
if (!vgmstream) goto fail;
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
if (!vgmstream)
free_layout_layered(data);
return NULL;
}