Add TXTH/GENH interleave_last option

This commit is contained in:
bnnm 2019-01-20 00:17:06 +01:00
parent 8f1ec86bda
commit 29bed4b1e0
3 changed files with 36 additions and 5 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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;