mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
Add .audio_data [Lego SW: The Skywalker Saga (PC)]
This commit is contained in:
parent
2a6dd8d782
commit
2c9b8e614b
@ -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;
|
||||
|
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",
|
||||
@ -781,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)"},
|
||||
@ -928,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[] = {
|
||||
@ -1394,6 +1397,7 @@ static const meta_info meta_info_list[] = {
|
||||
{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) {
|
||||
|
@ -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);
|
||||
|
@ -564,6 +564,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" />
|
||||
@ -722,6 +723,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" />
|
||||
|
@ -1159,6 +1159,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>
|
||||
@ -1606,6 +1609,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>
|
||||
|
@ -986,4 +986,6 @@ VGMSTREAM* init_vgmstream_esf(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_adm3(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_tt_ad(STREAMFILE* sf);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
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;
|
||||
}
|
@ -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:
|
||||
|
@ -524,6 +524,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
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,
|
||||
@ -1161,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) */
|
||||
@ -758,6 +760,7 @@ typedef enum {
|
||||
meta_S3V,
|
||||
meta_ESF,
|
||||
meta_ADM3,
|
||||
meta_TT_AD,
|
||||
|
||||
} meta_t;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user