mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-24 23:10:10 +01:00
commit
e51f5dcd66
@ -92,6 +92,9 @@ as explained below, but often will use default values. Accepted codec strings:
|
||||
# * Variation with modified encoding
|
||||
# - PCM8_U_int PCM 8-bit unsigned (interleave block)
|
||||
# * Variation with modified encoding
|
||||
# - PCM_FLOAT_LE PCM 32-bit float little endian
|
||||
# * For few rare games [Ikinari Maou (Switch)]
|
||||
# * Interleave is multiple of 0x4 (default)
|
||||
# - IMA IMA ADPCM (mono/stereo)
|
||||
# * For some PC games, and rarely consoles
|
||||
# * Special interleave is multiple of 0x1, often +0x80
|
||||
|
@ -491,6 +491,7 @@ void free_mpeg(mpeg_codec_data* data);
|
||||
int mpeg_get_sample_rate(mpeg_codec_data* data);
|
||||
long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data* data);
|
||||
|
||||
uint32_t mpeg_get_tag_size(STREAMFILE* sf, uint32_t offset, uint32_t header);
|
||||
int mpeg_get_frame_info(STREAMFILE* sf, off_t offset, mpeg_frame_info* info);
|
||||
#endif
|
||||
|
||||
|
@ -563,21 +563,23 @@ void decode_blitz_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channels
|
||||
/* IMA with custom frame sizes, header and nibble layout. Outputs an odd number of samples per frame,
|
||||
* so to simplify calcs this decodes full frames, thus hist doesn't need to be mantained.
|
||||
* Officially defined in "Microsoft Multimedia Standards Update" doc (RIFFNEW.pdf). */
|
||||
void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_ms_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, samples_read = 0, samples_done = 0, max_samples;
|
||||
int32_t hist1;// = stream->adpcm_history1_32;
|
||||
int step_index;// = stream->adpcm_step_index;
|
||||
int frame_channels = vgmstream->codec_config ? 1 : vgmstream->channels; /* mono or mch modes */
|
||||
int frame_channel = vgmstream->codec_config ? 0 : channel;
|
||||
|
||||
/* internal interleave (configurable size), mixed channels */
|
||||
int block_samples = ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;
|
||||
int block_samples = ((vgmstream->frame_size - 0x04*frame_channels) * 2 / frame_channels) + 1;
|
||||
first_sample = first_sample % block_samples;
|
||||
|
||||
/* normal header (hist+step+reserved), per channel */
|
||||
{ //if (first_sample == 0) {
|
||||
off_t header_offset = stream->offset + 0x04*channel;
|
||||
off_t header_offset = stream->offset + 0x04*frame_channel;
|
||||
|
||||
hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
|
||||
step_index = read_8bit(header_offset+0x02,stream->streamfile); /* 0x03: reserved */
|
||||
hist1 = read_s16le(header_offset+0x00,stream->streamfile);
|
||||
step_index = read_u8(header_offset+0x02,stream->streamfile); /* 0x03: reserved */
|
||||
if (step_index < 0) step_index = 0;
|
||||
if (step_index > 88) step_index = 88;
|
||||
|
||||
@ -595,7 +597,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t *
|
||||
|
||||
/* decode nibbles (layout: alternates 4 bytes/4*2 nibbles per channel) */
|
||||
for (i = 0; i < max_samples; i++) {
|
||||
off_t byte_offset = stream->offset + 0x04*vgmstream->channels + 0x04*channel + 0x04*vgmstream->channels*(i/8) + (i%8)/2;
|
||||
off_t byte_offset = stream->offset + 0x04*frame_channels + 0x04*frame_channel + 0x04*frame_channels*(i/8) + (i%8)/2;
|
||||
int nibble_shift = (i&1?4:0); /* low nibble first */
|
||||
|
||||
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); /* original expand */
|
||||
@ -609,7 +611,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t *
|
||||
|
||||
/* internal interleave: increment offset on complete frame */
|
||||
if (first_sample + samples_done == block_samples) {
|
||||
stream->offset += vgmstream->interleave_block_size;
|
||||
stream->offset += vgmstream->frame_size;
|
||||
}
|
||||
|
||||
//stream->adpcm_history1_32 = hist1;
|
||||
|
@ -340,6 +340,37 @@ int mpeg_get_frame_info(STREAMFILE* sf, off_t offset, mpeg_frame_info* info) {
|
||||
return mpeg_get_frame_info_h(header, info);
|
||||
}
|
||||
|
||||
|
||||
uint32_t mpeg_get_tag_size(STREAMFILE* sf, uint32_t offset, uint32_t header) {
|
||||
if (!header)
|
||||
header = read_u32be(offset+0x00, sf);
|
||||
|
||||
/* skip ID3v2 */
|
||||
if ((header & 0xFFFFFF00) == get_id32be("ID3\0")) {
|
||||
size_t frame_size = 0;
|
||||
uint8_t flags = read_u8(offset+0x05, sf);
|
||||
/* this is how it's officially read :/ */
|
||||
frame_size += read_u8(offset+0x06, sf) << 21;
|
||||
frame_size += read_u8(offset+0x07, sf) << 14;
|
||||
frame_size += read_u8(offset+0x08, sf) << 7;
|
||||
frame_size += read_u8(offset+0x09, sf) << 0;
|
||||
frame_size += 0x0a;
|
||||
if (flags & 0x10) /* footer? */
|
||||
frame_size += 0x0a;
|
||||
|
||||
return frame_size;
|
||||
|
||||
}
|
||||
|
||||
/* skip ID3v1 */
|
||||
if ((header & 0xFFFFFF00) == get_id32be("TAG\0")) {
|
||||
;VGM_LOG("MPEG: ID3v1 at %x\n", offset);
|
||||
return 0x80;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) {
|
||||
off_t offset = start_offset;
|
||||
off_t max_offset = start_offset + bytes;
|
||||
@ -355,32 +386,13 @@ size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) {
|
||||
/* MPEG may use VBR so must read all frames */
|
||||
while (offset < max_offset) {
|
||||
uint32_t header = read_u32be(offset+0x00, sf);
|
||||
|
||||
/* skip ID3v2 */
|
||||
if ((header & 0xFFFFFF00) == 0x49443300) { /* "ID3\0" */
|
||||
size_t frame_size = 0;
|
||||
uint8_t flags = read_u8(offset+0x05, sf);
|
||||
/* this is how it's officially read :/ */
|
||||
frame_size += read_u8(offset+0x06, sf) << 21;
|
||||
frame_size += read_u8(offset+0x07, sf) << 14;
|
||||
frame_size += read_u8(offset+0x08, sf) << 7;
|
||||
frame_size += read_u8(offset+0x09, sf) << 0;
|
||||
frame_size += 0x0a;
|
||||
if (flags & 0x10) /* footer? */
|
||||
frame_size += 0x0a;
|
||||
|
||||
offset += frame_size;
|
||||
size_t tag_size = mpeg_get_tag_size(sf, offset, header);
|
||||
if (tag_size) {
|
||||
offset += tag_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip ID3v1 */
|
||||
if ((header & 0xFFFFFF00) == 0x54414700) { /* "TAG\0" */
|
||||
;VGM_LOG("MPEG: ID3v1 at %lx\n", offset);
|
||||
offset += 0x80;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* regular frame */
|
||||
/* regular frame (assumed) */
|
||||
if (!mpeg_get_frame_info_h(header, &info)) {
|
||||
VGM_LOG("MPEG: unknown frame at %lx\n", offset);
|
||||
break;
|
||||
@ -407,9 +419,13 @@ size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) {
|
||||
}
|
||||
/* other flags indicate seek table and stuff */
|
||||
|
||||
;VGM_LOG("MPEG: found Xing header\n");
|
||||
|
||||
/* vendor specific */
|
||||
if (info.frame_size > xing_offset + 0x78 + 0x24 &&
|
||||
read_u32be(offset + xing_offset + 0x78, sf) == 0x4C414D45) { /* "LAME" */
|
||||
if (info.frame_size > xing_offset + 0x78 + 0x24) {
|
||||
uint32_t sub_id = read_u32be(offset + xing_offset + 0x78, sf);
|
||||
if (sub_id == get_id32be("LAME") || /* LAME */
|
||||
sub_id == get_id32be("Lavc")) { /* FFmpeg */
|
||||
if (info.layer == 3) {
|
||||
uint32_t delays = read_u32be(offset + xing_offset + 0x8C, sf);
|
||||
encoder_delay = ((delays >> 12) & 0xFFF);
|
||||
@ -422,13 +438,12 @@ size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) {
|
||||
else {
|
||||
encoder_delay = 240 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* replay gain and stuff */
|
||||
}
|
||||
|
||||
/* there is also "iTunes" vendor with no apparent extra info, iTunes delays are in "iTunSMPB" ID3 tag */
|
||||
|
||||
;VGM_LOG("MPEG: found Xing header\n");
|
||||
break; /* we got samples */
|
||||
}
|
||||
}
|
||||
|
11
src/decode.c
11
src/decode.c
@ -428,7 +428,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
|
||||
return 64;
|
||||
case coding_MS_IMA:
|
||||
case coding_REF_IMA:
|
||||
return ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;
|
||||
return ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;/* +1 from header sample */
|
||||
case coding_MS_IMA_mono:
|
||||
return ((vgmstream->frame_size - 0x04) * 2) + 1; /* +1 from header sample */
|
||||
case coding_RAD_IMA:
|
||||
return (vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels;
|
||||
case coding_NDS_IMA:
|
||||
@ -628,12 +630,14 @@ int get_vgmstream_frame_size(VGMSTREAM* vgmstream) {
|
||||
case coding_OKI4S:
|
||||
case coding_MTF_IMA:
|
||||
return 0x01;
|
||||
case coding_MS_IMA:
|
||||
case coding_RAD_IMA:
|
||||
case coding_NDS_IMA:
|
||||
case coding_DAT4_IMA:
|
||||
case coding_REF_IMA:
|
||||
return vgmstream->interleave_block_size;
|
||||
case coding_MS_IMA:
|
||||
case coding_MS_IMA_mono:
|
||||
return vgmstream->frame_size;
|
||||
case coding_AWC_IMA:
|
||||
return 0x800;
|
||||
case coding_RAD_IMA_mono:
|
||||
@ -931,6 +935,9 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
|
||||
}
|
||||
break;
|
||||
case coding_MS_IMA:
|
||||
case coding_MS_IMA_mono:
|
||||
//TODO: improve
|
||||
vgmstream->codec_config = (vgmstream->coding_type == coding_MS_IMA_mono) || vgmstream->channels == 1; /* mono mode */
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_ms_ima(vgmstream,&vgmstream->ch[ch], buffer+ch,
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
|
||||
|
@ -82,6 +82,7 @@ static const char* extension_list[] = {
|
||||
"atx",
|
||||
"aud",
|
||||
"audio", //txth/reserved [Grimm Echoes (Android)]
|
||||
"audio_data",
|
||||
"aus",
|
||||
"awa", //txth/reserved [Missing Parts Side A (PS2)]
|
||||
"awb",
|
||||
@ -522,6 +523,7 @@ static const char* extension_list[] = {
|
||||
"swag",
|
||||
"swav",
|
||||
"swd",
|
||||
"switch", //txth/reserved (.m4a-x.switch) [Ikinari Maou (Switch)]
|
||||
"switch_audio",
|
||||
"sx",
|
||||
"sxd",
|
||||
@ -780,6 +782,7 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_MTF_IMA, "MT Framework 4-bit IMA ADPCM"},
|
||||
|
||||
{coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"},
|
||||
{coding_MS_IMA_mono, "Microsoft 4-bit IMA ADPCM (mono/interleave)"},
|
||||
{coding_XBOX_IMA, "XBOX 4-bit IMA ADPCM"},
|
||||
{coding_XBOX_IMA_mch, "XBOX 4-bit IMA ADPCM (multichannel)"},
|
||||
{coding_XBOX_IMA_int, "XBOX 4-bit IMA ADPCM (mono/interleave)"},
|
||||
@ -927,6 +930,7 @@ static const layout_info layout_info_list[] = {
|
||||
{layout_blocked_vs_square, "blocked (Square VS)"},
|
||||
{layout_blocked_vid1, "blocked (VID1)"},
|
||||
{layout_blocked_ubi_sce, "blocked (Ubi SCE)"},
|
||||
{layout_blocked_tt_ad, "blocked (TT AD)"},
|
||||
};
|
||||
|
||||
static const meta_info meta_info_list[] = {
|
||||
@ -1392,6 +1396,8 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_SSPF, "Konami SSPF header"},
|
||||
{meta_S3V, "Konami S3V header"},
|
||||
{meta_ESF, "Eurocom ESF header"},
|
||||
{meta_ADM3, "Crankcase ADM3 header"},
|
||||
{meta_TT_AD, "Traveller's Tales AUDIO_DATA header"},
|
||||
};
|
||||
|
||||
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {
|
||||
|
18
src/info.c
18
src/info.c
@ -358,7 +358,13 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t*
|
||||
* segments use only a few samples from a full file (like Wwise transitions), bitrates
|
||||
* become a bit high since its hard to detect only part of the file is needed. */
|
||||
|
||||
if (vgmstream->layout_type == layout_segmented) {
|
||||
if (vgmstream->stream_size != 0) {
|
||||
/* format may report full size for custom layouts that otherwise get odd values */
|
||||
bitrate += get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples);
|
||||
if (p_uniques)
|
||||
(*p_uniques)++;
|
||||
}
|
||||
else if (vgmstream->layout_type == layout_segmented) {
|
||||
int uniques = 0;
|
||||
segmented_layout_data *data = (segmented_layout_data *) vgmstream->layout_data;
|
||||
for (i = 0; i < data->segment_count; i++) {
|
||||
@ -400,20 +406,20 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t*
|
||||
}
|
||||
|
||||
if (is_unique) {
|
||||
size_t stream_size;
|
||||
size_t file_bitrate;
|
||||
|
||||
if (br->count >= br->count_max) goto fail;
|
||||
|
||||
if (vgmstream->stream_size) {
|
||||
/* stream_size applies to both channels but should add once and detect repeats (for current subsong) */
|
||||
stream_size = get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples);
|
||||
file_bitrate = get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples);
|
||||
}
|
||||
else {
|
||||
stream_size = get_vgmstream_file_bitrate_from_streamfile(sf_cur, vgmstream->sample_rate, vgmstream->num_samples);
|
||||
file_bitrate = get_vgmstream_file_bitrate_from_streamfile(sf_cur, vgmstream->sample_rate, vgmstream->num_samples);
|
||||
}
|
||||
|
||||
/* possible in cases like using silence codec */
|
||||
if (!stream_size)
|
||||
if (!file_bitrate)
|
||||
break;
|
||||
|
||||
br->hash[br->count] = hash_cur;
|
||||
@ -423,7 +429,7 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t*
|
||||
if (p_uniques)
|
||||
(*p_uniques)++;
|
||||
|
||||
bitrate += stream_size;
|
||||
bitrate += file_bitrate;
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -213,6 +213,9 @@ void block_update(off_t block_offset, VGMSTREAM* vgmstream) {
|
||||
case layout_blocked_ubi_sce:
|
||||
block_update_ubi_sce(block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_tt_ad:
|
||||
block_update_tt_ad(block_offset,vgmstream);
|
||||
break;
|
||||
default: /* not a blocked layout */
|
||||
break;
|
||||
}
|
||||
|
31
src/layout/blocked_tt_ad.c
Normal file
31
src/layout/blocked_tt_ad.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include "layout.h"
|
||||
|
||||
/* Traveller's Tales blocks (.AUDIO_DATA) */
|
||||
void block_update_tt_ad(off_t block_offset, VGMSTREAM* vgmstream) {
|
||||
STREAMFILE* sf = vgmstream->ch[0].streamfile;
|
||||
uint32_t header_id, block_size, header_size;
|
||||
int i;
|
||||
|
||||
header_size = 0x00;
|
||||
block_size = vgmstream->frame_size;
|
||||
|
||||
//TODO could be optimized?
|
||||
/* first chunk and last frame has an extra header:
|
||||
* 0x00: id
|
||||
* 0x04: 0 in FRST, left samples in LAST, others not seen (found in exe) */
|
||||
header_id = read_u32be(block_offset, sf);
|
||||
if (header_id == get_id32be("FRST") || header_id == get_id32be("LAST") ||
|
||||
header_id == get_id32be("LSRT") || header_id == get_id32be("LEND")) {
|
||||
header_size = 0x08;
|
||||
}
|
||||
VGM_ASSERT(header_id == get_id32be("LSRT") || header_id == get_id32be("LEND"), "TT-AD: loop found\n");
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = block_size /* * vgmstream->channels*/;
|
||||
vgmstream->next_block_offset = block_offset + block_size * vgmstream->channels + header_size;
|
||||
|
||||
/* MS-IMA = same offset per channel */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset + header_size + block_size * i;
|
||||
}
|
||||
}
|
@ -49,6 +49,7 @@ void block_update_xa_aiff(off_t block_offset, VGMSTREAM* vgmstream);
|
||||
void block_update_vs_square(off_t block_offset, VGMSTREAM* vgmstream);
|
||||
void block_update_vid1(off_t block_offset, VGMSTREAM* vgmstream);
|
||||
void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream);
|
||||
void block_update_tt_ad(off_t block_offset, VGMSTREAM* vgmstream);
|
||||
|
||||
/* other layouts */
|
||||
void render_vgmstream_interleave(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
|
||||
|
@ -110,7 +110,6 @@
|
||||
<ClInclude Include="meta\bar_streamfile.h" />
|
||||
<ClInclude Include="meta\bgw_streamfile.h" />
|
||||
<ClInclude Include="meta\bnsf_keys.h" />
|
||||
<ClInclude Include="meta\cri_utf.h" />
|
||||
<ClInclude Include="meta\deblock_streamfile.h" />
|
||||
<ClInclude Include="meta\ea_eaac_streamfile.h" />
|
||||
<ClInclude Include="meta\ea_eaac_opus_streamfile.h" />
|
||||
@ -172,6 +171,7 @@
|
||||
<ClInclude Include="coding\tac_decoder_lib_ops.h" />
|
||||
<ClInclude Include="layout\layout.h" />
|
||||
<ClInclude Include="util\chunks.h" />
|
||||
<ClInclude Include="util\cri_utf.h" />
|
||||
<ClInclude Include="util\endianness.h" />
|
||||
<ClInclude Include="util\log.h" />
|
||||
<ClInclude Include="util\m2_psb.h" />
|
||||
@ -310,6 +310,7 @@
|
||||
<ClCompile Include="meta\acb.c" />
|
||||
<ClCompile Include="meta\acm.c" />
|
||||
<ClCompile Include="meta\acx.c" />
|
||||
<ClCompile Include="meta\adm3.c" />
|
||||
<ClCompile Include="meta\adp_konami.c" />
|
||||
<ClCompile Include="meta\adpcm_capcom.c" />
|
||||
<ClCompile Include="meta\ads_midway.c" />
|
||||
@ -339,7 +340,6 @@
|
||||
<ClCompile Include="meta\ck.c" />
|
||||
<ClCompile Include="meta\compresswave.c" />
|
||||
<ClCompile Include="meta\cpk.c" />
|
||||
<ClCompile Include="meta\cri_utf.c" />
|
||||
<ClCompile Include="meta\csb.c" />
|
||||
<ClCompile Include="meta\csmp.c" />
|
||||
<ClCompile Include="meta\cstr.c" />
|
||||
@ -563,6 +563,7 @@
|
||||
<ClCompile Include="meta\ta_aac.c" />
|
||||
<ClCompile Include="meta\tac.c" />
|
||||
<ClCompile Include="meta\thp.c" />
|
||||
<ClCompile Include="meta\tt_ad.c" />
|
||||
<ClCompile Include="meta\vgs.c" />
|
||||
<ClCompile Include="meta\ubi_bao.c" />
|
||||
<ClCompile Include="meta\ubi_ckd.c" />
|
||||
@ -721,6 +722,7 @@
|
||||
<ClCompile Include="layout\blocked_hwas.c" />
|
||||
<ClCompile Include="layout\blocked_str_snds.c" />
|
||||
<ClCompile Include="layout\blocked_thp.c" />
|
||||
<ClCompile Include="layout\blocked_tt_ad.c" />
|
||||
<ClCompile Include="layout\blocked_vs.c" />
|
||||
<ClCompile Include="layout\blocked_ws_aud.c" />
|
||||
<ClCompile Include="layout\blocked_wsi.c" />
|
||||
@ -728,6 +730,7 @@
|
||||
<ClCompile Include="layout\blocked_xa_aiff.c" />
|
||||
<ClCompile Include="layout\blocked_xvas.c" />
|
||||
<ClCompile Include="util\chunks.c" />
|
||||
<ClCompile Include="util\cri_utf.c" />
|
||||
<ClCompile Include="util\log.c" />
|
||||
<ClCompile Include="util\m2_psb.c" />
|
||||
<ClCompile Include="util\text_reader.c" />
|
||||
|
@ -95,9 +95,6 @@
|
||||
<ClInclude Include="meta\bnsf_keys.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\cri_utf.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\deblock_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -314,6 +311,9 @@
|
||||
<ClInclude Include="util\chunks.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\cri_utf.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\endianness.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -415,6 +415,9 @@
|
||||
<ClCompile Include="meta\acx.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\adm3.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\adp_konami.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -487,9 +490,6 @@
|
||||
<ClCompile Include="meta\cpk.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\cri_utf.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\csb.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -1156,6 +1156,9 @@
|
||||
<ClCompile Include="meta\thp.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\tt_ad.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\vgs.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -1603,6 +1606,9 @@
|
||||
<ClCompile Include="layout\blocked_thp.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_tt_ad.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_vs.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -1966,6 +1972,9 @@
|
||||
<ClCompile Include="util\chunks.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\cri_utf.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\log.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1,31 +1,32 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "cri_utf.h"
|
||||
#include "../util/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;
|
||||
VGMSTREAM* init_vgmstream_aax(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
int loop_flag = 0, channels = 0;
|
||||
int32_t sample_count, loop_start_sample = 0, loop_end_sample = 0;
|
||||
|
||||
segmented_layout_data *data = NULL;
|
||||
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;
|
||||
utf_context* utf = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00,sf, "@UTF"))
|
||||
goto fail;
|
||||
|
||||
/* .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" */
|
||||
if (!check_extensions(sf, "aax,"))
|
||||
goto fail;
|
||||
|
||||
/* .aax contains a simple UTF table, each row being a segment pointing to a CRI audio format */
|
||||
@ -35,7 +36,7 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
|
||||
uint32_t table_offset = 0x00;
|
||||
|
||||
|
||||
utf = utf_open(streamFile, table_offset, &rows, &name);
|
||||
utf = utf_open(sf, table_offset, &rows, &name);
|
||||
if (!utf) goto fail;
|
||||
|
||||
if (strcmp(name, "AAX") == 0)
|
||||
@ -74,7 +75,7 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
|
||||
|
||||
/* 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"));
|
||||
STREAMFILE* temp_sf = setup_subfile_streamfile(sf, segment_offset[i],segment_size[i], (is_hca ? "hca" : "adx"));
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
data->segments[i] = is_hca ?
|
||||
@ -105,11 +106,11 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
|
||||
}
|
||||
}
|
||||
|
||||
channel_count = data->output_channels;
|
||||
channels = data->output_channels;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = data->segments[0]->sample_rate;
|
||||
@ -135,21 +136,22 @@ fail:
|
||||
|
||||
|
||||
/* 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;
|
||||
VGMSTREAM* init_vgmstream_utf_dsp(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
uint8_t loop_flag = 0, channel_count;
|
||||
uint8_t loop_flag = 0, channels;
|
||||
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;
|
||||
utf_context* utf = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00,sf, "@UTF"))
|
||||
goto fail;
|
||||
|
||||
/* .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" */
|
||||
if (!check_extensions(sf, "aax,"))
|
||||
goto fail;
|
||||
|
||||
/* .aax contains a simple UTF table with one row and various columns being header info */
|
||||
@ -159,7 +161,7 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
|
||||
uint32_t table_offset = 0x00;
|
||||
|
||||
|
||||
utf = utf_open(streamFile, table_offset, &rows, &name);
|
||||
utf = utf_open(sf, table_offset, &rows, &name);
|
||||
if (!utf) goto fail;
|
||||
|
||||
if (strcmp(name, "ADPCM_WII") != 0)
|
||||
@ -172,7 +174,7 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
if (!utf_query_u32(utf, 0, "nsmpl", &num_samples))
|
||||
goto fail;
|
||||
if (!utf_query_u8(utf, 0, "nch", &channel_count))
|
||||
if (!utf_query_u8(utf, 0, "nch", &channels))
|
||||
goto fail;
|
||||
if (!utf_query_u8(utf, 0, "lpflg", &loop_flag)) /* full loops */
|
||||
goto fail;
|
||||
@ -182,21 +184,21 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
|
||||
if (!utf_query_data(utf, 0, "header", &header_offset, &header_size))
|
||||
goto fail;
|
||||
|
||||
if (channel_count < 1 || channel_count > 2)
|
||||
if (channels < 1 || channels > 2)
|
||||
goto fail;
|
||||
if (header_size != channel_count * 0x60)
|
||||
if (header_size != channels * 0x60)
|
||||
goto fail;
|
||||
|
||||
start_offset = data_offset;
|
||||
interleave = (data_size+7) / 8 * 8 / channel_count;
|
||||
interleave = (data_size+7) / 8 * 8 / channels;
|
||||
|
||||
loop_start = read_32bitBE(header_offset + 0x10, streamFile);
|
||||
loop_end = read_32bitBE(header_offset + 0x14, streamFile);
|
||||
loop_start = read_32bitBE(header_offset + 0x10, sf);
|
||||
loop_end = read_32bitBE(header_offset + 0x14, sf);
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
@ -209,9 +211,9 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->meta_type = meta_UTF_DSP;
|
||||
|
||||
dsp_read_coefs_be(vgmstream, streamFile, header_offset+0x1c, 0x60);
|
||||
dsp_read_coefs_be(vgmstream, sf, header_offset+0x1c, 0x60);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "cri_utf.h"
|
||||
#include "../util/cri_utf.h"
|
||||
|
||||
|
||||
/* ACB (Atom Cue sheet Binary) - CRI container of memory audio, often together with a .awb wave bank */
|
||||
|
152
src/meta/adm3.c
Normal file
152
src/meta/adm3.c
Normal file
@ -0,0 +1,152 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
int total_subsongs;
|
||||
int target_subsong;
|
||||
|
||||
uint32_t stream_offset;
|
||||
uint32_t stream_size;
|
||||
|
||||
int loop_flag;
|
||||
int sample_rate;
|
||||
int channels;
|
||||
int32_t num_samples;
|
||||
} adm3_header_t;
|
||||
|
||||
static int parse_adm3(adm3_header_t* adm3, STREAMFILE* sf);
|
||||
|
||||
|
||||
/* ADM3 - Crankcase Audio REV plugin file [Cyberpunk 2077 (PC), MotoGP 21 (PC)] */
|
||||
VGMSTREAM* init_vgmstream_adm3(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
adm3_header_t adm3 = {0};
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00,sf, "ADM3"))
|
||||
goto fail;
|
||||
if (!check_extensions(sf, "wem"))
|
||||
goto fail;
|
||||
|
||||
adm3.target_subsong = sf->stream_index;
|
||||
if (adm3.target_subsong == 0) adm3.target_subsong = 1;
|
||||
|
||||
/* ADM3 are files used with the Wwise Crankaudio plugin, that simulate engine noises with
|
||||
* base internal samples and some internal RPM config (probably). Actual file seems to
|
||||
* define some combo of samples, this only plays those separate samples.
|
||||
* Decoder is basically Apple's IMA (internally just "ADPCMDecoder") but transforms to float
|
||||
* each sample during decode by multiplying by 0.000030518509 */
|
||||
|
||||
if (!parse_adm3(&adm3, sf))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(adm3.channels, adm3.loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_ADM3;
|
||||
vgmstream->sample_rate = adm3.sample_rate;
|
||||
vgmstream->num_samples = adm3.num_samples; /* slightly lower than bytes-to-samples */
|
||||
vgmstream->num_streams = adm3.total_subsongs;
|
||||
vgmstream->stream_size = adm3.stream_size;
|
||||
|
||||
vgmstream->coding_type = coding_APPLE_IMA4;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x22;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, adm3.stream_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int parse_type(adm3_header_t* adm3, STREAMFILE* sf, uint32_t offset) {
|
||||
|
||||
if (is_id32be(offset, sf, "RMP1")) {
|
||||
offset = read_u32le(offset + 0x1c, sf);
|
||||
if (!parse_type(adm3, sf, offset))
|
||||
goto fail;
|
||||
/* 0x24: offset to GRN1 */
|
||||
}
|
||||
else if (is_id32be(offset, sf, "SMB1")) {
|
||||
uint32_t table_count = read_u32le(offset + 0x10, sf);
|
||||
uint32_t table_offset = read_u32le(offset + 0x18, sf);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < table_count; i++) {
|
||||
uint32_t smp2_unk = read_u32le(table_offset + i * 0x08 + 0x00, sf);
|
||||
uint32_t smp2_offset = read_u32le(table_offset + i * 0x08 + 0x04, sf);
|
||||
|
||||
if (smp2_unk != 1)
|
||||
goto fail;
|
||||
|
||||
if (!parse_type(adm3, sf, smp2_offset)) /* SMP2 */
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else if (is_id32be(offset, sf, "SMP2")) {
|
||||
adm3->total_subsongs++;
|
||||
|
||||
if (adm3->target_subsong == adm3->total_subsongs) {
|
||||
/* 0x04 always 0 */
|
||||
/* 0x08 always 0x00040000 */
|
||||
adm3->channels = read_u32le(offset + 0x0c, sf);
|
||||
/* 0x10 float pitch? */
|
||||
/* 0x14 int pitch? */
|
||||
/* 0x18 0x0001? */
|
||||
/* 0x1a 0x0030? (header size?) */
|
||||
adm3->sample_rate = read_s32le(offset + 0x1c, sf);
|
||||
adm3->num_samples = read_s32le(offset + 0x20, sf);
|
||||
adm3->stream_size = read_u32le(offset + 0x24, sf);
|
||||
/* 0x28 1? */
|
||||
adm3->stream_offset = read_u32le(offset + 0x2c, sf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
VGM_LOG("ADM3: unknown at %x\n", offset);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_adm3(adm3_header_t* adm3, STREAMFILE* sf) {
|
||||
uint32_t offset;
|
||||
|
||||
/* 0x04: null */
|
||||
/* 0x08: version? */
|
||||
/* 0x0c: header size */
|
||||
/* 0x10: data start */
|
||||
/* rest unknown, looks mostly the same between files */
|
||||
|
||||
/* higher ramp, N samples from low to high */
|
||||
offset = read_u32le(0x0FC, sf);
|
||||
if (!parse_type(adm3, sf, offset)) goto fail; /* RMP1 */
|
||||
if (read_u32le(0x100, sf) != 1) goto fail;
|
||||
|
||||
/* lower ramp, also N samples */
|
||||
offset = read_u32le(0x104, sf);
|
||||
if (!parse_type(adm3, sf, offset)) goto fail; /* RMP1 */
|
||||
if (read_u32le(0x108, sf) != 1) goto fail;
|
||||
|
||||
/* idle engine */
|
||||
offset = read_u32le(0x10c, sf);
|
||||
if (!parse_type(adm3, sf, offset)) goto fail; /* SMP2 */
|
||||
if (read_u32le(0x110, sf) != 1) goto fail;
|
||||
|
||||
if (adm3->target_subsong < 0 || adm3->target_subsong > adm3->total_subsongs || adm3->total_subsongs < 1)
|
||||
goto fail;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "cri_utf.h"
|
||||
#include "../util/cri_utf.h"
|
||||
|
||||
|
||||
typedef enum { HCA, CWAV, ADX } cpk_type_t;
|
||||
@ -26,10 +26,11 @@ VGMSTREAM* init_vgmstream_cpk_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "awb"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x00,sf, "CPK "))
|
||||
goto fail;
|
||||
if (!check_extensions(sf, "awb"))
|
||||
goto fail;
|
||||
|
||||
if (!is_id32be(0x10,sf, "@UTF"))
|
||||
goto fail;
|
||||
/* 04: 0xFF? */
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "cri_utf.h"
|
||||
#include "../util/cri_utf.h"
|
||||
|
||||
|
||||
/* CSB (Cue Sheet Binary?) - CRI container of memory audio, often together with a .cpk wave bank */
|
||||
@ -9,8 +9,8 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) {
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
off_t subfile_offset;
|
||||
size_t subfile_size;
|
||||
utf_context *utf = NULL;
|
||||
utf_context *utf_sdl = NULL;
|
||||
utf_context* utf = NULL;
|
||||
utf_context* utf_sdl = NULL;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
uint8_t fmt = 0;
|
||||
const char* stream_name = NULL;
|
||||
|
@ -984,4 +984,8 @@ VGMSTREAM* init_vgmstream_s3v(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_esf(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_adm3(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_tt_ad(STREAMFILE* sf);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
@ -2,16 +2,33 @@
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* MPEG - standard MP1/2/3 audio MP3 */
|
||||
/* MPEG - standard MP1/2/3 audio */
|
||||
VGMSTREAM* init_vgmstream_mpeg(STREAMFILE* sf) {
|
||||
#ifdef VGM_USE_MPEG
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
uint32_t start_offset;
|
||||
int loop_flag = 0;
|
||||
mpeg_frame_info info = {0};
|
||||
uint32_t header_id;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!mpeg_get_frame_info(sf, 0x00, &info))
|
||||
header_id = read_u32be(0x00, sf);
|
||||
if ((header_id & 0xFFF00000) != 0xFFF00000 &&
|
||||
(header_id & 0xFFFFFF00) != get_id32be("ID3\0") &&
|
||||
(header_id & 0xFFFFFF00) != get_id32be("TAG\0"))
|
||||
goto fail;
|
||||
|
||||
//TODO: may try init_mpeg as-is, already skips tags
|
||||
start_offset = 0x00;
|
||||
while (start_offset < get_streamfile_size(sf)) {
|
||||
uint32_t tag_size = mpeg_get_tag_size(sf, start_offset, 0);
|
||||
if (tag_size == 0)
|
||||
break;
|
||||
start_offset += tag_size;
|
||||
}
|
||||
|
||||
if (!mpeg_get_frame_info(sf, start_offset, &info))
|
||||
goto fail;
|
||||
|
||||
/* .mp3/mp2: standard (is .mp1 ever used in games?)
|
||||
|
@ -654,8 +654,8 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
read_u32be(start_offset+0x3c, sf) == 0xFFFFFFFF)
|
||||
goto fail;
|
||||
|
||||
///* MSADPCM .ckd are parsed elsewhere, though they are valid so no big deal if parsed here (just that loops should be ignored) */
|
||||
if (!fmt.is_at9 && check_extensions(sf, "ckd"))
|
||||
/* MSADPCM .ckd are parsed elsewhere, though they are valid so no big deal if parsed here (just that loops should be ignored) */
|
||||
if (fmt.codec == 0x0002 && check_extensions(sf, "ckd"))
|
||||
goto fail;
|
||||
|
||||
/* ignore Gitaroo Man Live! (PSP) multi-RIFF (to allow chunked TXTH) */
|
||||
|
@ -21,7 +21,7 @@ VGMSTREAM* init_vgmstream_sspf(STREAMFILE* sf) {
|
||||
goto fail;
|
||||
|
||||
/* extra check to ignore .spc, that are a RAM pack of .ssp with a ~0x800 table at the end */
|
||||
file_size = read_u32be(0x08, sf) + 0x08; /* without padding */
|
||||
file_size = read_u32be(0x08, sf); /* without padding */
|
||||
pad_size = 0;
|
||||
if (file_size % 0x800) /* add padding */
|
||||
pad_size = 0x800 - (file_size % 0x800);
|
||||
|
@ -2,24 +2,36 @@
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* Tiger Game.com ADPCM file */
|
||||
VGMSTREAM * init_vgmstream_tgc(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM* init_vgmstream_tgc(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
uint16_t size;
|
||||
off_t start_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "4"))
|
||||
if (read_u8(0x00, sf) != 0)
|
||||
goto fail;
|
||||
|
||||
if (!check_extensions(sf, "4"))
|
||||
goto fail;
|
||||
|
||||
size = read_u16be(0x01, sf);
|
||||
if (size != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
start_offset = 0x03;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(1, 0);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = 8000;
|
||||
vgmstream->num_samples = ((uint16_t)read_16bitBE(1, streamFile) - 3) * 2;
|
||||
vgmstream->num_samples = (size - 0x03) * 2;
|
||||
vgmstream->meta_type = meta_TGC;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->coding_type = coding_TGC;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, 3))
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
94
src/meta/tt_ad.c
Normal file
94
src/meta/tt_ad.c
Normal file
@ -0,0 +1,94 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .AUDIO_DATA - Traveller's Tales "NTT" engine audio format [Lego Star Wars: The Skywalker Saga (PC/Switch)] */
|
||||
VGMSTREAM* init_vgmstream_tt_ad(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
uint32_t offset, stream_offset, stream_size;
|
||||
int loop_flag, channels, sample_rate, codec, frame_size = 0;
|
||||
int32_t num_samples;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00,sf, "FMT "))
|
||||
goto fail;
|
||||
|
||||
/* actual extension */
|
||||
if (!check_extensions(sf, "audio_data"))
|
||||
goto fail;
|
||||
|
||||
offset = 0x08;
|
||||
/* 0x00: null */
|
||||
codec = read_u16le(offset + 0x02,sf);
|
||||
sample_rate = read_s32le(offset + 0x04,sf);
|
||||
num_samples = read_s32le(offset + 0x08,sf);
|
||||
channels = read_u8(offset + 0x0c,sf);
|
||||
/* 0x0d: bps (16=IMA, 32=Ogg) */
|
||||
/* 0x10:
|
||||
Ogg = some size?
|
||||
IMA = frame size + flag? */
|
||||
if (codec == 0x0a)
|
||||
frame_size = read_u16le(offset + 0x10,sf);
|
||||
|
||||
|
||||
loop_flag = 0; /* music just repeats? */
|
||||
|
||||
offset += read_u32le(0x04, sf);
|
||||
|
||||
/* Ogg seek table*/
|
||||
if (is_id32be(offset, sf, "SEEK")) {
|
||||
offset += 0x08 + read_u32le(offset + 0x04, sf);
|
||||
}
|
||||
|
||||
/* found with some IMA */
|
||||
if (is_id32be(offset, sf, "RMS ")) {
|
||||
offset += 0x08 + read_u32le(offset + 0x04, sf);
|
||||
}
|
||||
|
||||
if (!is_id32be(offset, sf, "DATA"))
|
||||
goto fail;
|
||||
|
||||
stream_offset = offset + 0x08;
|
||||
stream_size = read_u32le(offset + 0x04, sf);
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_TT_AD;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
|
||||
switch(codec) {
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case 0x01: {
|
||||
vgmstream->codec_data = init_ogg_vorbis(sf, stream_offset, stream_size, NULL);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_OGG_VORBIS;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case 0x0a:
|
||||
vgmstream->coding_type = coding_MS_IMA_mono;
|
||||
vgmstream->layout_type = layout_blocked_tt_ad;
|
||||
vgmstream->frame_size = frame_size;
|
||||
vgmstream->interleave_block_size = frame_size;
|
||||
break;
|
||||
|
||||
default:
|
||||
vgm_logi("FMT: unsupported codec 0x%x\n", codec);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, stream_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -46,6 +46,7 @@ typedef enum {
|
||||
XA,
|
||||
XA_EA,
|
||||
CP_YM,
|
||||
PCM_FLOAT_LE,
|
||||
|
||||
UNKNOWN = 99,
|
||||
} txth_codec_t;
|
||||
@ -220,6 +221,7 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
|
||||
case PCM16BE: interleave = 0x02; break;
|
||||
case PCM8: interleave = 0x01; break;
|
||||
case PCM8_U: interleave = 0x01; break;
|
||||
case PCM_FLOAT_LE: interleave = 0x04; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -235,6 +237,7 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
|
||||
case PCM16BE: coding = coding_PCM16BE; break;
|
||||
case PCM16LE: coding = coding_PCM16LE; break;
|
||||
case PCM8: coding = coding_PCM8; break;
|
||||
case PCM_FLOAT_LE: coding = coding_PCMFLOAT; break;
|
||||
case SDX2: coding = coding_SDX2; break;
|
||||
case DVI_IMA: coding = coding_DVI_IMA; break;
|
||||
#ifdef VGM_USE_MPEG
|
||||
@ -305,6 +308,7 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
|
||||
case coding_PCM16BE:
|
||||
case coding_PCM8:
|
||||
case coding_PCM8_U:
|
||||
case coding_PCMFLOAT:
|
||||
case coding_PCM4:
|
||||
case coding_PCM4_U:
|
||||
case coding_SDX2:
|
||||
@ -963,6 +967,7 @@ static txth_codec_t parse_codec(txth_header* txth, const char* val) {
|
||||
else if (is_string(val,"XA")) return XA;
|
||||
else if (is_string(val,"XA_EA")) return XA_EA;
|
||||
else if (is_string(val,"CP_YM")) return CP_YM;
|
||||
else if (is_string(val,"PCM_FLOAT_LE")) return PCM_FLOAT_LE;
|
||||
/* special handling */
|
||||
else if (is_string(val,"name_value")) return txth->name_values[0];
|
||||
else if (is_string(val,"name_value1")) return txth->name_values[0];
|
||||
@ -2039,6 +2044,8 @@ static int get_bytes_to_samples(txth_header* txth, uint32_t bytes) {
|
||||
case PCM8_U_int:
|
||||
case PCM8_U:
|
||||
return pcm_bytes_to_samples(bytes, txth->channels, 8);
|
||||
case PCM_FLOAT_LE:
|
||||
return pcm_bytes_to_samples(bytes, txth->channels, 32);
|
||||
case PCM4:
|
||||
case PCM4_U:
|
||||
case TGC:
|
||||
|
@ -304,6 +304,7 @@ int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstream) {
|
||||
case layout_blocked_vs_square:
|
||||
case layout_blocked_vid1:
|
||||
case layout_blocked_ubi_sce:
|
||||
case layout_blocked_tt_ad:
|
||||
render_vgmstream_blocked(buf, sample_count, vgmstream);
|
||||
break;
|
||||
case layout_segmented:
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "cri_utf.h"
|
||||
#include "../util/log.h"
|
||||
#include "log.h"
|
||||
|
||||
#define UTF_MAX_SCHEMA_SIZE 0x8000 /* arbitrary max */
|
||||
#define COLUMN_BITMASK_FLAG 0xf0
|
@ -470,7 +470,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
init_vgmstream_csb,
|
||||
init_vgmstream_fwse,
|
||||
init_vgmstream_fda,
|
||||
init_vgmstream_tgc,
|
||||
init_vgmstream_kwb,
|
||||
init_vgmstream_lrmd,
|
||||
init_vgmstream_bkhd,
|
||||
@ -523,6 +522,8 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
init_vgmstream_opus_rsnd,
|
||||
init_vgmstream_s3v,
|
||||
init_vgmstream_esf,
|
||||
init_vgmstream_adm3,
|
||||
init_vgmstream_tt_ad,
|
||||
|
||||
/* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */
|
||||
init_vgmstream_mpeg,
|
||||
@ -536,6 +537,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
init_vgmstream_seb,
|
||||
init_vgmstream_ps2_pnb,
|
||||
init_vgmstream_sli_ogg,
|
||||
init_vgmstream_tgc,
|
||||
|
||||
/* 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 */
|
||||
@ -1160,9 +1162,10 @@ int vgmstream_open_stream_bf(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t start_o
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((vgmstream->coding_type == coding_MSADPCM ||
|
||||
vgmstream->coding_type == coding_MSADPCM_ck ||
|
||||
vgmstream->coding_type == coding_MSADPCM_int) &&
|
||||
if ((vgmstream->coding_type == coding_MSADPCM || vgmstream->coding_type == coding_MSADPCM_ck ||
|
||||
vgmstream->coding_type == coding_MSADPCM_int ||
|
||||
vgmstream->coding_type == coding_MS_IMA || vgmstream->coding_type == coding_MS_IMA_mono
|
||||
) &&
|
||||
vgmstream->frame_size == 0) {
|
||||
vgmstream->frame_size = vgmstream->interleave_block_size;
|
||||
}
|
||||
|
@ -114,6 +114,7 @@ typedef enum {
|
||||
coding_BLITZ_IMA, /* Blitz Games 4-bit IMA ADPCM */
|
||||
|
||||
coding_MS_IMA, /* Microsoft IMA ADPCM */
|
||||
coding_MS_IMA_mono, /* Microsoft IMA ADPCM (mono/interleave) */
|
||||
coding_XBOX_IMA, /* XBOX IMA ADPCM */
|
||||
coding_XBOX_IMA_mch, /* XBOX IMA ADPCM (multichannel) */
|
||||
coding_XBOX_IMA_int, /* XBOX IMA ADPCM (mono/interleave) */
|
||||
@ -277,6 +278,7 @@ typedef enum {
|
||||
layout_blocked_vs_square,
|
||||
layout_blocked_vid1,
|
||||
layout_blocked_ubi_sce,
|
||||
layout_blocked_tt_ad,
|
||||
|
||||
/* otherwise odd */
|
||||
layout_segmented, /* song divided in segments (song sections) */
|
||||
@ -757,6 +759,8 @@ typedef enum {
|
||||
meta_SSPF,
|
||||
meta_S3V,
|
||||
meta_ESF,
|
||||
meta_ADM3,
|
||||
meta_TT_AD,
|
||||
|
||||
} meta_t;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user