mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-11 16:43:11 +01:00
Add 9TAV [Metal Gear Solid 2/3 HD (Vita)]
This commit is contained in:
parent
0d7af1b9e5
commit
80ae4f2ed3
@ -9,7 +9,7 @@ struct atrac9_codec_data {
|
|||||||
uint8_t *data_buffer;
|
uint8_t *data_buffer;
|
||||||
size_t data_buffer_size;
|
size_t data_buffer_size;
|
||||||
|
|
||||||
sample *sample_buffer;
|
sample_t *sample_buffer;
|
||||||
size_t samples_filled; /* number of samples in the buffer */
|
size_t samples_filled; /* number of samples in the buffer */
|
||||||
size_t samples_used; /* number of samples extracted from the buffer */
|
size_t samples_used; /* number of samples extracted from the buffer */
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ atrac9_codec_data *init_atrac9(atrac9_config *cfg) {
|
|||||||
|
|
||||||
status = Atrac9GetCodecInfo(data->handle, &data->info);
|
status = Atrac9GetCodecInfo(data->handle, &data->info);
|
||||||
if (status < 0) goto fail;
|
if (status < 0) goto fail;
|
||||||
//;VGM_LOG("ATRAC9: config=%x, sf-size=%x, sub-frames=%i x %i samples\n", cfg->config_data, info.superframeSize, info.framesInSuperframe, info.frameSamples);
|
//;VGM_LOG("ATRAC9: config=%x, sf-size=%x, sub-frames=%i x %i samples\n", cfg->config_data, data->info.superframeSize, data->info.framesInSuperframe, data->info.frameSamples);
|
||||||
|
|
||||||
if (cfg->channels && cfg->channels != data->info.channels) {
|
if (cfg->channels && cfg->channels != data->info.channels) {
|
||||||
VGM_LOG("ATRAC9: channels in header %i vs config %i don't match\n", cfg->channels, data->info.channels);
|
VGM_LOG("ATRAC9: channels in header %i vs config %i don't match\n", cfg->channels, data->info.channels);
|
||||||
@ -50,7 +50,7 @@ atrac9_codec_data *init_atrac9(atrac9_config *cfg) {
|
|||||||
/* must hold at least one superframe and its samples */
|
/* must hold at least one superframe and its samples */
|
||||||
data->data_buffer_size = data->info.superframeSize;
|
data->data_buffer_size = data->info.superframeSize;
|
||||||
data->data_buffer = calloc(sizeof(uint8_t), data->data_buffer_size);
|
data->data_buffer = calloc(sizeof(uint8_t), data->data_buffer_size);
|
||||||
data->sample_buffer = calloc(sizeof(sample), data->info.channels * data->info.frameSamples * data->info.framesInSuperframe);
|
data->sample_buffer = calloc(sizeof(sample_t), data->info.channels * data->info.frameSamples * data->info.framesInSuperframe);
|
||||||
|
|
||||||
data->samples_to_discard = cfg->encoder_delay;
|
data->samples_to_discard = cfg->encoder_delay;
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ fail:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_atrac9(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
|
void decode_atrac9(VGMSTREAM *vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) {
|
||||||
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
|
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
|
||||||
atrac9_codec_data * data = vgmstream->codec_data;
|
atrac9_codec_data * data = vgmstream->codec_data;
|
||||||
int samples_done = 0;
|
int samples_done = 0;
|
||||||
@ -220,20 +220,20 @@ void free_atrac9(atrac9_codec_data *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data) {
|
static int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size, size_t *out_samples_per_frame) {
|
||||||
return bytes / data->info.superframeSize * (data->info.frameSamples * data->info.framesInSuperframe);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0 //not needed (for now)
|
|
||||||
int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size) {
|
|
||||||
static const int sample_rate_table[16] = {
|
static const int sample_rate_table[16] = {
|
||||||
11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
|
11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
|
||||||
44100, 48000, 64000, 88200, 96000,128000,176400,192000
|
44100, 48000, 64000, 88200, 96000,128000,176400,192000
|
||||||
};
|
};
|
||||||
|
static const int samples_power_table[16] = {
|
||||||
|
6, 6, 7, 7, 7, 8, 8, 8,
|
||||||
|
6, 6, 7, 7, 7, 8, 8, 8
|
||||||
|
};
|
||||||
static const int channel_table[8] = {
|
static const int channel_table[8] = {
|
||||||
1, 2, 2, 6, 8, 4, 0, 0
|
1, 2, 2, 6, 8, 4, 0, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int superframe_size, frames_per_superframe, samples_per_frame, samples_per_superframe;
|
||||||
uint32_t sync = (atrac9_config >> 24) & 0xff; /* 8b */
|
uint32_t sync = (atrac9_config >> 24) & 0xff; /* 8b */
|
||||||
uint8_t sample_rate_index = (atrac9_config >> 20) & 0x0f; /* 4b */
|
uint8_t sample_rate_index = (atrac9_config >> 20) & 0x0f; /* 4b */
|
||||||
uint8_t channels_index = (atrac9_config >> 17) & 0x07; /* 3b */
|
uint8_t channels_index = (atrac9_config >> 17) & 0x07; /* 3b */
|
||||||
@ -242,6 +242,11 @@ int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_c
|
|||||||
size_t superframe_index = (atrac9_config >> 3) & 0x3; /* 2b */
|
size_t superframe_index = (atrac9_config >> 3) & 0x3; /* 2b */
|
||||||
/* uint8_t unused = (atrac9_config >> 0) & 0x7);*/ /* 3b */
|
/* uint8_t unused = (atrac9_config >> 0) & 0x7);*/ /* 3b */
|
||||||
|
|
||||||
|
superframe_size = ((frame_size+1) << superframe_index);
|
||||||
|
frames_per_superframe = (1 << superframe_index);
|
||||||
|
samples_per_frame = 1 << samples_power_table[sample_rate_index];
|
||||||
|
samples_per_superframe = samples_per_frame * frames_per_superframe;
|
||||||
|
|
||||||
if (sync != 0xFE)
|
if (sync != 0xFE)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (out_sample_rate)
|
if (out_sample_rate)
|
||||||
@ -249,11 +254,23 @@ int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_c
|
|||||||
if (out_channels)
|
if (out_channels)
|
||||||
*out_channels = channel_table[channels_index];
|
*out_channels = channel_table[channels_index];
|
||||||
if (out_frame_size)
|
if (out_frame_size)
|
||||||
*out_frame_size = (frame_size+1) * (1 << superframe_index);
|
*out_frame_size = superframe_size;
|
||||||
|
if (out_samples_per_frame)
|
||||||
|
*out_samples_per_frame = samples_per_superframe;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
fail:
|
fail:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data) {
|
||||||
|
return bytes / data->info.superframeSize * (data->info.frameSamples * data->info.framesInSuperframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t atrac9_config) {
|
||||||
|
size_t frame_size, samples_per_frame;
|
||||||
|
if (!atrac9_parse_config(atrac9_config, NULL, NULL, &frame_size, &samples_per_frame))
|
||||||
|
return 0;
|
||||||
|
return bytes / frame_size * samples_per_frame;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -260,12 +260,12 @@ void free_at3plus(maiatrac3plus_codec_data *data);
|
|||||||
#ifdef VGM_USE_ATRAC9
|
#ifdef VGM_USE_ATRAC9
|
||||||
/* atrac9_decoder */
|
/* atrac9_decoder */
|
||||||
atrac9_codec_data *init_atrac9(atrac9_config *cfg);
|
atrac9_codec_data *init_atrac9(atrac9_config *cfg);
|
||||||
void decode_atrac9(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
|
void decode_atrac9(VGMSTREAM *vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels);
|
||||||
void reset_atrac9(VGMSTREAM *vgmstream);
|
void reset_atrac9(VGMSTREAM *vgmstream);
|
||||||
void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample);
|
void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample);
|
||||||
void free_atrac9(atrac9_codec_data *data);
|
void free_atrac9(atrac9_codec_data *data);
|
||||||
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data);
|
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data);
|
||||||
//int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size);
|
size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t atrac9_config);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef VGM_USE_CELT
|
#ifdef VGM_USE_CELT
|
||||||
|
@ -18,6 +18,7 @@ static const char* extension_list[] = {
|
|||||||
"2dx9",
|
"2dx9",
|
||||||
"2pfs",
|
"2pfs",
|
||||||
"800",
|
"800",
|
||||||
|
"9tav",
|
||||||
|
|
||||||
//"aac", //common
|
//"aac", //common
|
||||||
"aa3", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
|
"aa3", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
|
||||||
@ -1177,6 +1178,7 @@ static const meta_info meta_info_list[] = {
|
|||||||
{meta_STRM_ABYLIGHT, "Abylight STRM header"},
|
{meta_STRM_ABYLIGHT, "Abylight STRM header"},
|
||||||
{meta_MSF_KONAMI, "Konami MSF header"},
|
{meta_MSF_KONAMI, "Konami MSF header"},
|
||||||
{meta_XWMA_KONAMI, "Konami XWMA header"},
|
{meta_XWMA_KONAMI, "Konami XWMA header"},
|
||||||
|
{meta_9TAV, "Konami 9TAV header"},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -224,6 +224,10 @@
|
|||||||
RelativePath=".\meta\aax_utf.h"
|
RelativePath=".\meta\aax_utf.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\meta\9tav_streamfile.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\meta\aix_streamfile.h"
|
RelativePath=".\meta\aix_streamfile.h"
|
||||||
>
|
>
|
||||||
@ -312,6 +316,10 @@
|
|||||||
RelativePath=".\meta\208.c"
|
RelativePath=".\meta\208.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\meta\9tav.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\meta\2dx9.c"
|
RelativePath=".\meta\2dx9.c"
|
||||||
>
|
>
|
||||||
|
@ -99,6 +99,7 @@
|
|||||||
<ClInclude Include="vgmstream.h" />
|
<ClInclude Include="vgmstream.h" />
|
||||||
<ClInclude Include="meta\adx_keys.h" />
|
<ClInclude Include="meta\adx_keys.h" />
|
||||||
<ClInclude Include="meta\aax_utf.h" />
|
<ClInclude Include="meta\aax_utf.h" />
|
||||||
|
<ClInclude Include="meta\9tav_streamfile.h" />
|
||||||
<ClInclude Include="meta\aix_streamfile.h" />
|
<ClInclude Include="meta\aix_streamfile.h" />
|
||||||
<ClInclude Include="meta\awc_xma_streamfile.h" />
|
<ClInclude Include="meta\awc_xma_streamfile.h" />
|
||||||
<ClInclude Include="meta\bar_streamfile.h" />
|
<ClInclude Include="meta\bar_streamfile.h" />
|
||||||
@ -207,6 +208,7 @@
|
|||||||
<ClCompile Include="util.c" />
|
<ClCompile Include="util.c" />
|
||||||
<ClCompile Include="vgmstream.c" />
|
<ClCompile Include="vgmstream.c" />
|
||||||
<ClCompile Include="meta\208.c" />
|
<ClCompile Include="meta\208.c" />
|
||||||
|
<ClCompile Include="meta\9tav.c" />
|
||||||
<ClCompile Include="meta\2dx9.c" />
|
<ClCompile Include="meta\2dx9.c" />
|
||||||
<ClCompile Include="meta\a2m.c" />
|
<ClCompile Include="meta\a2m.c" />
|
||||||
<ClCompile Include="meta\ahv.c" />
|
<ClCompile Include="meta\ahv.c" />
|
||||||
|
@ -68,6 +68,9 @@
|
|||||||
<ClInclude Include="meta\aax_utf.h">
|
<ClInclude Include="meta\aax_utf.h">
|
||||||
<Filter>meta\Header Files</Filter>
|
<Filter>meta\Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="meta\9tav_streamfile.h">
|
||||||
|
<Filter>meta\Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="meta\aix_streamfile.h">
|
<ClInclude Include="meta\aix_streamfile.h">
|
||||||
<Filter>meta\Header Files</Filter>
|
<Filter>meta\Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@ -196,6 +199,9 @@
|
|||||||
<ClCompile Include="meta\208.c">
|
<ClCompile Include="meta\208.c">
|
||||||
<Filter>meta\Source Files</Filter>
|
<Filter>meta\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="meta\9tav.c">
|
||||||
|
<Filter>meta\Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="meta\2dx9.c">
|
<ClCompile Include="meta\2dx9.c">
|
||||||
<Filter>meta\Source Files</Filter>
|
<Filter>meta\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
118
src/meta/9tav.c
Normal file
118
src/meta/9tav.c
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#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;
|
||||||
|
}
|
182
src/meta/9tav_streamfile.h
Normal file
182
src/meta/9tav_streamfile.h
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
#ifndef _9TAV_STREAMFILE_H_
|
||||||
|
#define _9TAV_STREAMFILE_H_
|
||||||
|
#include "../streamfile.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* config */
|
||||||
|
off_t stream_offset;
|
||||||
|
size_t stream_size;
|
||||||
|
size_t track_size;
|
||||||
|
int track_number;
|
||||||
|
int track_count;
|
||||||
|
int skip_count;
|
||||||
|
int read_count;
|
||||||
|
size_t frame_size;
|
||||||
|
size_t interleave_count;
|
||||||
|
size_t interleave_last_count;
|
||||||
|
|
||||||
|
/* state */
|
||||||
|
off_t logical_offset; /* fake offset */
|
||||||
|
off_t physical_offset; /* actual offset */
|
||||||
|
size_t block_size; /* current size */
|
||||||
|
size_t skip_size; /* size from block start to reach data */
|
||||||
|
size_t data_size; /* usable size in a block */
|
||||||
|
|
||||||
|
size_t logical_size;
|
||||||
|
} ntav_io_data;
|
||||||
|
|
||||||
|
|
||||||
|
static size_t ntav_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, ntav_io_data* data) {
|
||||||
|
size_t total_read = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* re-start when previous offset (can't map logical<>physical offsets) */
|
||||||
|
if (data->logical_offset < 0 || offset < data->logical_offset) {
|
||||||
|
data->physical_offset = data->stream_offset;
|
||||||
|
data->logical_offset = 0x00;
|
||||||
|
data->data_size = 0;
|
||||||
|
data->skip_size = 0;
|
||||||
|
data->read_count = 0;
|
||||||
|
data->skip_count = data->interleave_count * data->track_number;
|
||||||
|
//VGM_LOG("0 o=%lx, sc=%i\n", data->physical_offset, data->skip_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read blocks */
|
||||||
|
while (length > 0) {
|
||||||
|
//VGM_LOG("1 of=%lx, so=%lx, sz=%x, of2=%lx, log=%lx\n", data->physical_offset, data->stream_offset, data->stream_size, offset, data->logical_offset);
|
||||||
|
|
||||||
|
/* ignore EOF */
|
||||||
|
if (offset < 0 || data->physical_offset >= data->stream_offset + data->stream_size) {
|
||||||
|
//VGM_LOG("9 o=%lx, so=%lx, sz=%x, of2=%lx, log=%lx\n", data->physical_offset, data->stream_offset, data->stream_size, offset, data->logical_offset);
|
||||||
|
//VGM_LOG("eof\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* process new block */
|
||||||
|
if (data->data_size == 0) {
|
||||||
|
/* not very exact compared to real blocks but ok enough */
|
||||||
|
if (read_32bitLE(data->physical_offset, streamfile) == 0x00) {
|
||||||
|
data->block_size = 0x10;
|
||||||
|
//VGM_LOG("1 o=%lx, lo=%lx skip\n", data->physical_offset, data->logical_offset);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data->block_size = data->frame_size;
|
||||||
|
|
||||||
|
//VGM_LOG("2 o=%lx, lo=%lx, skip=%i, read=%i\n", data->physical_offset, data->logical_offset, data->skip_count, data->read_count);
|
||||||
|
|
||||||
|
/* each track interleaves NTAV_INTERLEAVE frames, but can contain padding in between,
|
||||||
|
* so must read one by one up to max */
|
||||||
|
|
||||||
|
if (data->skip_count == 0 && data->read_count == 0) {
|
||||||
|
data->read_count = data->interleave_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->skip_count) {
|
||||||
|
data->skip_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->read_count) {
|
||||||
|
data->data_size = data->block_size;
|
||||||
|
data->read_count--;
|
||||||
|
|
||||||
|
if (data->read_count == 0) {
|
||||||
|
if (data->logical_offset + data->interleave_count * data->frame_size > data->track_size)
|
||||||
|
data->skip_count = data->interleave_last_count * (data->track_count - 1);
|
||||||
|
else
|
||||||
|
data->skip_count = data->interleave_count * (data->track_count - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move to next block */
|
||||||
|
if (data->data_size == 0 || offset >= data->logical_offset + data->data_size) {
|
||||||
|
data->physical_offset += data->block_size;
|
||||||
|
data->logical_offset += data->data_size;
|
||||||
|
data->data_size = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read data */
|
||||||
|
{
|
||||||
|
size_t bytes_consumed, bytes_done, to_read;
|
||||||
|
|
||||||
|
bytes_consumed = offset - data->logical_offset;
|
||||||
|
to_read = data->data_size - bytes_consumed;
|
||||||
|
if (to_read > length)
|
||||||
|
to_read = length;
|
||||||
|
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
||||||
|
|
||||||
|
total_read += bytes_done;
|
||||||
|
dest += bytes_done;
|
||||||
|
offset += bytes_done;
|
||||||
|
length -= bytes_done;
|
||||||
|
|
||||||
|
if (bytes_done != to_read || bytes_done == 0) {
|
||||||
|
break; /* error/EOF */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t ntav_io_size(STREAMFILE *streamfile, ntav_io_data* data) {
|
||||||
|
uint8_t buf[1];
|
||||||
|
|
||||||
|
if (data->logical_size)
|
||||||
|
return data->logical_size;
|
||||||
|
|
||||||
|
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
|
||||||
|
ntav_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
|
||||||
|
data->logical_size = data->logical_offset;
|
||||||
|
|
||||||
|
return data->logical_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handles deinterleaving of 9TAV blocked streams. Unlike other games using .sdt,
|
||||||
|
* KCEJ blocks have a data_size field and rest is padding. Even after that all blocks start
|
||||||
|
* with 0 (skipped) and there are padding blocks that start with LE 0xDEADBEEF.
|
||||||
|
* This streamfile handles 9tav extracted like regular sdt and remove padding manually. */
|
||||||
|
static STREAMFILE* setup_9tav_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t track_size, int track_number, int track_count) {
|
||||||
|
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||||
|
ntav_io_data io_data = {0};
|
||||||
|
size_t io_data_size = sizeof(ntav_io_data);
|
||||||
|
size_t last_size;
|
||||||
|
|
||||||
|
io_data.stream_offset = stream_offset;
|
||||||
|
io_data.stream_size = get_streamfile_size(streamFile) - stream_offset;
|
||||||
|
io_data.track_size = track_size;
|
||||||
|
io_data.track_number = track_number;
|
||||||
|
io_data.track_count = track_count;
|
||||||
|
io_data.frame_size = 0x40;
|
||||||
|
io_data.interleave_count = 256;
|
||||||
|
last_size = track_size % (io_data.interleave_count * io_data.frame_size);
|
||||||
|
if (last_size)
|
||||||
|
io_data.interleave_last_count = last_size / io_data.frame_size;
|
||||||
|
io_data.logical_offset = -1; /* force state reset */
|
||||||
|
|
||||||
|
/* setup subfile */
|
||||||
|
new_streamFile = open_wrap_streamfile(streamFile);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_io_streamfile(new_streamFile, &io_data,io_data_size, ntav_io_read,ntav_io_size);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
return temp_streamFile;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _9TAV_STREAMFILE_H_ */
|
@ -845,4 +845,6 @@ VGMSTREAM * init_vgmstream_msf_konami(STREAMFILE* streamFile);
|
|||||||
|
|
||||||
VGMSTREAM * init_vgmstream_xwma_konami(STREAMFILE* streamFile);
|
VGMSTREAM * init_vgmstream_xwma_konami(STREAMFILE* streamFile);
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_9tav(STREAMFILE* streamFile);
|
||||||
|
|
||||||
#endif /*_META_H*/
|
#endif /*_META_H*/
|
||||||
|
@ -476,6 +476,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
|||||||
init_vgmstream_ea_schl_video,
|
init_vgmstream_ea_schl_video,
|
||||||
init_vgmstream_msf_konami,
|
init_vgmstream_msf_konami,
|
||||||
init_vgmstream_xwma_konami,
|
init_vgmstream_xwma_konami,
|
||||||
|
init_vgmstream_9tav,
|
||||||
|
|
||||||
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
||||||
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
||||||
@ -2343,20 +2344,20 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
|||||||
seconds = (double)vgmstream->loop_start_sample / vgmstream->sample_rate;
|
seconds = (double)vgmstream->loop_start_sample / vgmstream->sample_rate;
|
||||||
time_mm = (int)(seconds / 60.0);
|
time_mm = (int)(seconds / 60.0);
|
||||||
time_ss = seconds - time_mm * 60.0f;
|
time_ss = seconds - time_mm * 60.0f;
|
||||||
snprintf(temp,TEMPSIZE, "loop start: %d samples (%1.0f:%2.3f seconds)\n", vgmstream->loop_start_sample, time_mm, time_ss);
|
snprintf(temp,TEMPSIZE, "loop start: %d samples (%1.0f:%06.3f seconds)\n", vgmstream->loop_start_sample, time_mm, time_ss);
|
||||||
concatn(length,desc,temp);
|
concatn(length,desc,temp);
|
||||||
|
|
||||||
seconds = (double)vgmstream->loop_end_sample / vgmstream->sample_rate;
|
seconds = (double)vgmstream->loop_end_sample / vgmstream->sample_rate;
|
||||||
time_mm = (int)(seconds / 60.0);
|
time_mm = (int)(seconds / 60.0);
|
||||||
time_ss = seconds - time_mm * 60.0f;
|
time_ss = seconds - time_mm * 60.0f;
|
||||||
snprintf(temp,TEMPSIZE, "loop end: %d samples (%1.0f:%2.3f seconds)\n", vgmstream->loop_end_sample, time_mm, time_ss);
|
snprintf(temp,TEMPSIZE, "loop end: %d samples (%1.0f:%06.3f seconds)\n", vgmstream->loop_end_sample, time_mm, time_ss);
|
||||||
concatn(length,desc,temp);
|
concatn(length,desc,temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
seconds = (double)vgmstream->num_samples / vgmstream->sample_rate;
|
seconds = (double)vgmstream->num_samples / vgmstream->sample_rate;
|
||||||
time_mm = (int)(seconds / 60.0);
|
time_mm = (int)(seconds / 60.0);
|
||||||
time_ss = seconds - time_mm * 60.0;
|
time_ss = seconds - time_mm * 60.0;
|
||||||
snprintf(temp,TEMPSIZE, "stream total samples: %d (%1.0f:%2.3f seconds)\n", vgmstream->num_samples, time_mm, time_ss);
|
snprintf(temp,TEMPSIZE, "stream total samples: %d (%1.0f:%06.3f seconds)\n", vgmstream->num_samples, time_mm, time_ss);
|
||||||
concatn(length,desc,temp);
|
concatn(length,desc,temp);
|
||||||
|
|
||||||
snprintf(temp,TEMPSIZE, "encoding: ");
|
snprintf(temp,TEMPSIZE, "encoding: ");
|
||||||
|
@ -729,6 +729,7 @@ typedef enum {
|
|||||||
meta_STRM_ABYLIGHT,
|
meta_STRM_ABYLIGHT,
|
||||||
meta_MSF_KONAMI,
|
meta_MSF_KONAMI,
|
||||||
meta_XWMA_KONAMI,
|
meta_XWMA_KONAMI,
|
||||||
|
meta_9TAV,
|
||||||
|
|
||||||
} meta_t;
|
} meta_t;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user