mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
Add TXTH/GENH interleave_last option
This commit is contained in:
parent
8f1ec86bda
commit
29bed4b1e0
10
doc/TXTH.md
10
doc/TXTH.md
@ -51,7 +51,7 @@ A text file with the above commands must be saved as ".vag.txth" or ".txth", not
|
||||
# * $1|2|3|4: value has size of 8/16/24/32 bit (optional, defaults to 4)
|
||||
# Examples: @0x10:BE$2 (get big endian 16b value at 0x10)
|
||||
# - (field): uses current value of a field. Accepted strings:
|
||||
# - interleave, channels, sample_rate
|
||||
# - interleave, interleave_last, channels, sample_rate
|
||||
# - start_offset, data_size
|
||||
# - num_samples, loop_start_sample, loop_end_sample
|
||||
# - subsong_count, subsong_offset
|
||||
@ -116,6 +116,14 @@ value_sub|value_- = (number)|(offset)|(field)
|
||||
# Interleave 0 means "stereo mode" for some codecs (IMA, AICA, etc).
|
||||
interleave = (number)|(offset)|(field)|half_size
|
||||
|
||||
# Interleave in the last block [OPTIONAL]
|
||||
# - auto: calculate based on channels, interleave and data_size/start_offset
|
||||
# In some files with interleaved data the last block is smaller than interleave,
|
||||
# so interleave must be smaller in the last block. This fixes decoding glitches
|
||||
# for those files. Note that this doesn't affect files with padding data in the
|
||||
# last block (as the interleave itself is constant).
|
||||
interleave_last = (number)|(auto)
|
||||
|
||||
# Validate that id_value matches value at id_offset [OPTIONAL]
|
||||
# Can be redefined several times, it's checked whenever a new id_offset is found.
|
||||
id_value = (number)|(offset)|(field)
|
||||
|
@ -39,8 +39,9 @@ typedef enum {
|
||||
typedef struct {
|
||||
genh_type codec;
|
||||
int codec_mode;
|
||||
size_t interleave;
|
||||
|
||||
size_t interleave;
|
||||
size_t interleave_last;
|
||||
int channels;
|
||||
int32_t sample_rate;
|
||||
|
||||
@ -153,6 +154,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
case coding_AICA:
|
||||
case coding_APPLE_IMA4:
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
vgmstream->interleave_last_block_size = genh.interleave_last;
|
||||
if (vgmstream->channels > 1)
|
||||
{
|
||||
if (coding == coding_SDX2) {
|
||||
@ -202,6 +204,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
case coding_PCFX:
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_last_block_size = genh.interleave_last;
|
||||
if (genh.codec_mode >= 0 && genh.codec_mode <= 3)
|
||||
vgmstream->codec_config = genh.codec_mode;
|
||||
break;
|
||||
@ -227,11 +230,13 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
if (genh.codec_mode == 1) { /* mono interleave */
|
||||
coding = coding_XBOX_IMA_int;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_last_block_size = genh.interleave_last;
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
}
|
||||
else { /* 1ch mono, or stereo interleave */
|
||||
vgmstream->layout_type = genh.interleave ? layout_interleave : layout_none;
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
vgmstream->interleave_last_block_size = genh.interleave_last;
|
||||
if (vgmstream->channels > 2 && vgmstream->channels % 2 != 0)
|
||||
goto fail; /* only 2ch+..+2ch layout is known */
|
||||
}
|
||||
@ -245,6 +250,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
if (!genh.interleave) goto fail;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
vgmstream->interleave_last_block_size = genh.interleave_last;
|
||||
} else if (genh.coef_interleave_type == 1) {
|
||||
if (!genh.interleave) goto fail;
|
||||
coding = coding_NGC_DSP_subint;
|
||||
@ -419,8 +425,8 @@ static int parse_genh(STREAMFILE * streamFile, genh_header * genh) {
|
||||
genh->coef_split_spacing = read_32bitLE(0x38,streamFile);
|
||||
}
|
||||
|
||||
/* extended fields */
|
||||
if (header_size >= 0x54) {
|
||||
/* extended + reserved fields */
|
||||
if (header_size >= 0x100) {
|
||||
genh->num_samples = read_32bitLE(0x40,streamFile);
|
||||
genh->skip_samples = read_32bitLE(0x44,streamFile); /* for FFmpeg based codecs */
|
||||
genh->skip_samples_mode = read_8bit(0x48,streamFile); /* 0=autodetect, 1=force manual value @ 0x44 */
|
||||
@ -430,6 +436,7 @@ static int parse_genh(STREAMFILE * streamFile, genh_header * genh) {
|
||||
if ((genh->codec == XMA1 || genh->codec == XMA2) && genh->codec_mode==0)
|
||||
genh->codec_mode = read_8bit(0x4a,streamFile);
|
||||
genh->data_size = read_32bitLE(0x50,streamFile);
|
||||
genh->interleave_last = read_32bitLE(0x54,streamFile);
|
||||
}
|
||||
|
||||
if (genh->data_size == 0)
|
||||
|
@ -49,6 +49,7 @@ typedef struct {
|
||||
uint32_t id_offset;
|
||||
|
||||
uint32_t interleave;
|
||||
uint32_t interleave_last;
|
||||
uint32_t channels;
|
||||
uint32_t sample_rate;
|
||||
|
||||
@ -228,6 +229,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
case coding_AICA:
|
||||
case coding_APPLE_IMA4:
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
if (vgmstream->channels > 1)
|
||||
{
|
||||
if (coding == coding_SDX2) {
|
||||
@ -277,6 +279,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
|
||||
case coding_PCFX:
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
if (txth.codec_mode >= 0 && txth.codec_mode <= 3)
|
||||
vgmstream->codec_config = txth.codec_mode;
|
||||
@ -304,10 +307,12 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
coding = coding_XBOX_IMA_int;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
}
|
||||
else { /* 1ch mono, or stereo interleave */
|
||||
vgmstream->layout_type = txth.interleave ? layout_interleave : layout_none;
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
if (vgmstream->channels > 2 && vgmstream->channels % 2 != 0)
|
||||
goto fail; /* only 2ch+..+2ch layout is known */
|
||||
}
|
||||
@ -320,6 +325,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
if (txth.channels > 1 && txth.codec_mode == 0) {
|
||||
if (!txth.interleave) goto fail;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
} else if (txth.channels > 1 && txth.codec_mode == 1) {
|
||||
if (!txth.interleave) goto fail;
|
||||
@ -655,6 +661,15 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
|
||||
if (!parse_num(txth->streamHead,txth,val, &txth->interleave)) goto fail;
|
||||
}
|
||||
}
|
||||
else if (0==strcmp(key,"interleave_last")) {
|
||||
if (0==strcmp(val,"auto")) {
|
||||
if (txth->channels > 0 && txth->interleave > 0)
|
||||
txth->interleave_last = (txth->data_size % (txth->interleave * txth->channels)) / txth->channels;
|
||||
}
|
||||
else {
|
||||
if (!parse_num(txth->streamHead,txth,val, &txth->interleave_last)) goto fail;
|
||||
}
|
||||
}
|
||||
else if (0==strcmp(key,"channels")) {
|
||||
if (!parse_num(txth->streamHead,txth,val, &txth->channels)) goto fail;
|
||||
}
|
||||
@ -901,6 +916,7 @@ static int parse_num(STREAMFILE * streamFile, txth_header * txth, const char * v
|
||||
}
|
||||
else { /* known field */
|
||||
if (0==strcmp(val,"interleave")) *out_value = txth->interleave;
|
||||
if (0==strcmp(val,"interleave_last")) *out_value = txth->interleave_last;
|
||||
else if (0==strcmp(val,"channels")) *out_value = txth->channels;
|
||||
else if (0==strcmp(val,"sample_rate")) *out_value = txth->sample_rate;
|
||||
else if (0==strcmp(val,"start_offset")) *out_value = txth->start_offset;
|
||||
|
Loading…
Reference in New Issue
Block a user