Add TXTH first interleave, tweak dual stereo

This commit is contained in:
bnnm 2021-07-17 19:01:50 +02:00
parent 8094ce9ebd
commit 3741e021b3
3 changed files with 74 additions and 4 deletions

View File

@ -204,6 +204,20 @@ Special values:
interleave_last = (value)|auto
```
#### INTERLEAVE IN THE FIRST BLOCK
Similar to the above, in rare cases the file starts with a different interleave (bigger or smaller), then uses another value.
For example, file has `start_offset` at 0x100, first `interleave_first` of 0x800 then `interleave` of 0x400.
In trickier cases, file at 0x100 has 0x10 garbage (before each channel data), then data up to 0x800, then interleave of 0x800. So interleave sizes are consistent, but first block has less data. Here we need to set `interleave_first_skip = 0x10` so block sizes can be properly calculated and garbage skipped. Notice that if file was 4ch this means total garbage of 0x40 (`(0x10 garbage + 0x7F0 data) * 4`).
Be aware that certain features like autodetecting PS-ADPCM loop points may not handle interleave_first at the moment.
```
interleave_first = (value)
interleave_first_skip = (value)
```
#### ID VALUES
Validates that `id_value` (normally set as constant value) matches value read at `id_check`. The file will be rejected and won't play if values don't match.
@ -785,6 +799,24 @@ num_samples = data_size
interleave_last = auto
```
#### Kaiketsu Zorori: Mezase! Itazura King (PS2) .txth
```
codec = PSX
channels = @0x8 + 1
sample_rate = 48000
interleave = 0x1000
interleave_first = 0x2000
interleave_first_skip = 0x10
padding_size = auto-empty
num_samples = data_size
#@0x00 interleave?
#@0x04 number of 0x800 sectors
```
#### Colin McRae DiRT (PC) .wip.txth
```
# first check that value at 0x00 is really 0x00000000 (rarely needed though)

View File

@ -58,6 +58,8 @@ typedef struct {
uint32_t interleave;
uint32_t interleave_last;
uint32_t interleave_first;
uint32_t interleave_first_skip;
uint32_t channels;
uint32_t sample_rate;
@ -330,6 +332,8 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
/* high nibble or low nibble first */
vgmstream->codec_config = txth.codec_mode;
}
vgmstream->allow_dual_stereo = 1; /* AICA and PSX */
break;
case coding_PCFX:
@ -369,6 +373,8 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
vgmstream->interleave_block_size = txth.interleave;
vgmstream->layout_type = layout_none;
vgmstream->allow_dual_stereo = 1; //???
break;
case coding_MSADPCM:
@ -456,6 +462,7 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
}
}
vgmstream->allow_dual_stereo = 1;
break;
#ifdef VGM_USE_MPEG
@ -568,9 +575,19 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
}
#endif
if (vgmstream->interleave_block_size) {
if (txth.interleave_first_skip && !txth.interleave_first)
txth.interleave_first = txth.interleave;
if (txth.interleave_first > txth.interleave_first_skip)
txth.interleave_first -= txth.interleave_first_skip;
vgmstream->interleave_first_block_size = txth.interleave_first;
vgmstream->interleave_first_skip = txth.interleave_first_skip;
txth.start_offset += txth.interleave_first_skip;
}
vgmstream->coding_type = coding;
vgmstream->meta_type = meta_TXTH;
vgmstream->allow_dual_stereo = 1;
if (!vgmstream_open_stream(vgmstream, txth.sf_body, txth.start_offset))
@ -648,6 +665,10 @@ static VGMSTREAM* init_subfile(txth_header* txth) {
txth->interleave = vgmstream->interleave_block_size;
if (!txth->interleave_last)
txth->interleave_last = vgmstream->interleave_last_block_size;
if (!txth->interleave_first)
txth->interleave_first = vgmstream->interleave_first_block_size;
if (!txth->interleave_first_skip)
txth->interleave_first_skip = vgmstream->interleave_first_skip;
//if (!txth->loop_flag) //?
// txth->loop_flag = vgmstream->loop_flag;
/* sometimes headers set loop start but getting loop_end before subfile init is hard */
@ -965,6 +986,19 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha
if (!parse_num(txth->sf_head,txth,val, &txth->interleave_last)) goto fail;
}
}
else if (is_string(key,"interleave_first")) {
if (!parse_num(txth->sf_head,txth,val, &txth->interleave_first)) goto fail;
}
else if (is_string(key,"interleave_first_skip")) {
if (!parse_num(txth->sf_head,txth,val, &txth->interleave_first_skip)) goto fail;
/* apply */
if (!txth->data_size_set) {
int skip = txth->interleave_first_skip * txth->channels;
if (txth->data_size && txth->data_size > skip)
txth->data_size -= skip;
}
}
/* BASE CONFIG */
else if (is_string(key,"channels")) {
@ -978,7 +1012,6 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha
else if (is_string(key,"start_offset")) {
if (!parse_num(txth->sf_head,txth,val, &txth->start_offset)) goto fail;
/* apply */
if (!txth->data_size_set) {
@ -1805,6 +1838,8 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_
else { /* known field */
if ((n = is_string_field(val,"interleave"))) value = txth->interleave;
else if ((n = is_string_field(val,"interleave_last"))) value = txth->interleave_last;
else if ((n = is_string_field(val,"interleave_first"))) value = txth->interleave_first;
else if ((n = is_string_field(val,"interleave_first_skip")))value = txth->interleave_first_skip;
else if ((n = is_string_field(val,"channels"))) value = txth->channels;
else if ((n = is_string_field(val,"sample_rate"))) value = txth->sample_rate;
else if ((n = is_string_field(val,"start_offset"))) value = txth->start_offset;

View File

@ -1648,9 +1648,12 @@ int vgmstream_open_stream_bf(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t start_o
offset = start_offset;
} else if (is_stereo_codec) {
int ch_mod = (ch & 1) ? ch - 1 : ch; /* adjust odd channels (ch 0,1,2,3,4,5 > ch 0,0,2,2,4,4) */
offset = start_offset + vgmstream->interleave_block_size*ch_mod;
offset = start_offset + vgmstream->interleave_block_size * ch_mod;
} else if (vgmstream->interleave_first_block_size) {
/* start_offset assumes + vgmstream->interleave_first_block_size, maybe should do it here */
offset = start_offset + (vgmstream->interleave_first_block_size + vgmstream->interleave_first_skip) * ch;
} else {
offset = start_offset + vgmstream->interleave_block_size*ch;
offset = start_offset + vgmstream->interleave_block_size * ch;
}
/* open new one if needed, useful to avoid jumping around when each channel data is too apart