mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-06 14:44:25 +01:00
Fix TXTH base_offset chaining and other edge cases
- allow name_table when setting body_file - match paths in name_table (needs wildcard: *path/file.ext) - always apply base_offset to coefs/hist/name_offset
This commit is contained in:
parent
8d9dfaa9b0
commit
41dd45f455
94
doc/TXTH.md
94
doc/TXTH.md
@ -49,7 +49,7 @@ The following can be used in place of `(value)` for `(key) = (value)` commands.
|
|||||||
* `$1|2|3|4`: value has size of 8/16/24/32 bit (optional, defaults to 4)
|
* `$1|2|3|4`: value has size of 8/16/24/32 bit (optional, defaults to 4)
|
||||||
* Example: `@0x10:BE$2` means `get big endian 16b value at 0x10`
|
* Example: `@0x10:BE$2` means `get big endian 16b value at 0x10`
|
||||||
- `(field)`: uses current value of some fields. Accepted strings:
|
- `(field)`: uses current value of some fields. Accepted strings:
|
||||||
- `interleave, interleave_last, channels, sample_rate, start_offset, data_size, num_samples, loop_start_sample, loop_end_sample, subsong_count, subsong_offset, subfile_offset, subfile_size, name_valueX`
|
- `interleave, interleave_last, channels, sample_rate, start_offset, data_size, num_samples, loop_start_sample, loop_end_sample, subsong_count, subsong_offset, subfile_offset, subfile_size, base_offset, name_valueX`
|
||||||
- `(other)`: other special values for certain keys, described per key
|
- `(other)`: other special values for certain keys, described per key
|
||||||
|
|
||||||
|
|
||||||
@ -664,6 +664,19 @@ chunk_size = 0x8000
|
|||||||
num_samples = data_size
|
num_samples = data_size
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Base offset chaining
|
||||||
|
Some formats read an offset to another part of the file, then another offset, then other, etc.
|
||||||
|
|
||||||
|
You can simulate this chaining multiple `base_offset`
|
||||||
|
```
|
||||||
|
base_offset = @0x10 #sets at 0x1000
|
||||||
|
channels = @0x04 #reads at 0x1004
|
||||||
|
base_offset = base_offset + @0x10 #sets at 0x1000 + 0x200 = 0x1200
|
||||||
|
sample_rate = @0x04 #reads at 0x1204
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
**Colin McRae DiRT (PC) .wip.txth**
|
**Colin McRae DiRT (PC) .wip.txth**
|
||||||
@ -827,7 +840,7 @@ JIN003.XAG: 0x180
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
** Grandia (PS1) **
|
**Grandia (PS1) bgm.txth**
|
||||||
```
|
```
|
||||||
header_file = GM1.IDX
|
header_file = GM1.IDX
|
||||||
body_file = GM1.STZ
|
body_file = GM1.STZ
|
||||||
@ -839,3 +852,80 @@ subfile_offset = (@0x00 & 0xFFFFF) * 0x800
|
|||||||
subfile_extension = seb
|
subfile_extension = seb
|
||||||
subfile_size = ((@0x04 - @0x00) & 0xFFFFF) * 0x800
|
subfile_size = ((@0x04 - @0x00) & 0xFFFFF) * 0x800
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
**Zack & Wiki (Wii) .ssd.txth**
|
||||||
|
```
|
||||||
|
header_file = bgm_S01.srt
|
||||||
|
name_table = .names.txt
|
||||||
|
|
||||||
|
base_offset = @0x0c:BE
|
||||||
|
base_offset = base_offset + @0x08:BE + name_value
|
||||||
|
base_offset = base_offset + @0x00:BE
|
||||||
|
|
||||||
|
codec = NGC_DSP
|
||||||
|
channels = 2
|
||||||
|
interleave = half_size
|
||||||
|
sample_rate = @0x08:BE
|
||||||
|
loop_flag = @0x04:BE
|
||||||
|
|
||||||
|
sample_type = bytes
|
||||||
|
loop_start_sample = @0x10:BE
|
||||||
|
loop_end_sample = @0x14:BE
|
||||||
|
num_samples = @0x18:BE
|
||||||
|
|
||||||
|
coef_offset = 0x20
|
||||||
|
coef_spacing = 0x40
|
||||||
|
coef_endianness = BE
|
||||||
|
```
|
||||||
|
*.names.txt*
|
||||||
|
```
|
||||||
|
st_s01_00a.ssd: 0*0x04
|
||||||
|
st_s01_00b.ssd: 1*0x04
|
||||||
|
st_s01_00c.ssd: 2*0x04
|
||||||
|
st_s01_01a.ssd: 3*0x04
|
||||||
|
st_s01_01b.ssd: 4*0x04
|
||||||
|
st_s01_02a.ssd: 5*0x04
|
||||||
|
st_s01_02b.ssd: 6*0x04
|
||||||
|
st_s01_02c.ssd: 7*0x04
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
**Zack & Wiki (Wii) st_s01_00a.txth**
|
||||||
|
```
|
||||||
|
#alt from above with untouched folders
|
||||||
|
header_file = Sound/BGM/bgm_S01.srt
|
||||||
|
body_file = snd/stream/st_s01_00a.ssd
|
||||||
|
name_table = .names.txt
|
||||||
|
|
||||||
|
base_offset = @0x0c:BE
|
||||||
|
base_offset = base_offset + @0x08:BE + name_value
|
||||||
|
base_offset = base_offset + @0x00:BE
|
||||||
|
|
||||||
|
codec = NGC_DSP
|
||||||
|
channels = 2
|
||||||
|
interleave = half_size
|
||||||
|
sample_rate = @0x08:BE
|
||||||
|
loop_flag = @0x04:BE
|
||||||
|
|
||||||
|
sample_type = bytes
|
||||||
|
loop_start_sample = @0x10:BE
|
||||||
|
loop_end_sample = @0x14:BE
|
||||||
|
num_samples = @0x18:BE
|
||||||
|
|
||||||
|
coef_offset = 0x20
|
||||||
|
coef_spacing = 0x40
|
||||||
|
coef_endianness = BE
|
||||||
|
```
|
||||||
|
*.names.txt*
|
||||||
|
```
|
||||||
|
*snd/stream/st_s01_00a.ssd: 0*0x04
|
||||||
|
*snd/stream/st_s01_00b.ssd: 1*0x04
|
||||||
|
*snd/stream/st_s01_00c.ssd: 2*0x04
|
||||||
|
*snd/stream/st_s01_01a.ssd: 3*0x04
|
||||||
|
*snd/stream/st_s01_01b.ssd: 4*0x04
|
||||||
|
*snd/stream/st_s01_02a.ssd: 5*0x04
|
||||||
|
*snd/stream/st_s01_02b.ssd: 6*0x04
|
||||||
|
*snd/stream/st_s01_02c.ssd: 7*0x04
|
||||||
|
# uses wildcards for full paths from plugins
|
||||||
|
```
|
||||||
|
@ -1063,9 +1063,10 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
|
|||||||
/* COEFS */
|
/* COEFS */
|
||||||
else if (is_string(key,"coef_offset")) {
|
else if (is_string(key,"coef_offset")) {
|
||||||
if (!parse_num(txth->streamHead,txth,val, &txth->coef_offset)) goto fail;
|
if (!parse_num(txth->streamHead,txth,val, &txth->coef_offset)) goto fail;
|
||||||
/* special adjustment */
|
/* special adjustments */
|
||||||
|
txth->coef_offset += txth->base_offset;
|
||||||
if (txth->subsong_offset)
|
if (txth->subsong_offset)
|
||||||
txth->coef_offset = txth->base_offset + txth->coef_offset + txth->subsong_offset * (txth->target_subsong - 1);
|
txth->coef_offset += txth->subsong_offset * (txth->target_subsong - 1);
|
||||||
}
|
}
|
||||||
else if (is_string(key,"coef_spacing")) {
|
else if (is_string(key,"coef_spacing")) {
|
||||||
if (!parse_num(txth->streamHead,txth,val, &txth->coef_spacing)) goto fail;
|
if (!parse_num(txth->streamHead,txth,val, &txth->coef_spacing)) goto fail;
|
||||||
@ -1090,8 +1091,9 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
|
|||||||
if (!parse_num(txth->streamHead,txth,val, &txth->hist_offset)) goto fail;
|
if (!parse_num(txth->streamHead,txth,val, &txth->hist_offset)) goto fail;
|
||||||
txth->hist_set = 1;
|
txth->hist_set = 1;
|
||||||
/* special adjustment */
|
/* special adjustment */
|
||||||
|
txth->hist_offset += txth->hist_offset;
|
||||||
if (txth->subsong_offset)
|
if (txth->subsong_offset)
|
||||||
txth->hist_offset = txth->base_offset + txth->hist_offset + txth->subsong_offset * (txth->target_subsong - 1);
|
txth->hist_offset += txth->subsong_offset * (txth->target_subsong - 1);
|
||||||
}
|
}
|
||||||
else if (is_string(key,"hist_spacing")) {
|
else if (is_string(key,"hist_spacing")) {
|
||||||
if (!parse_num(txth->streamHead,txth,val, &txth->hist_spacing)) goto fail;
|
if (!parse_num(txth->streamHead,txth,val, &txth->hist_spacing)) goto fail;
|
||||||
@ -1115,8 +1117,9 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
|
|||||||
if (!parse_num(txth->streamHead,txth,val, &txth->name_offset)) goto fail;
|
if (!parse_num(txth->streamHead,txth,val, &txth->name_offset)) goto fail;
|
||||||
txth->name_offset_set = 1;
|
txth->name_offset_set = 1;
|
||||||
/* special adjustment */
|
/* special adjustment */
|
||||||
|
txth->name_offset += txth->base_offset;
|
||||||
if (txth->subsong_offset)
|
if (txth->subsong_offset)
|
||||||
txth->name_offset = txth->base_offset + txth->name_offset + txth->subsong_offset * (txth->target_subsong - 1);
|
txth->name_offset += txth->subsong_offset * (txth->target_subsong - 1);
|
||||||
}
|
}
|
||||||
else if (is_string(key,"name_size")) {
|
else if (is_string(key,"name_size")) {
|
||||||
if (!parse_num(txth->streamHead,txth,val, &txth->name_size)) goto fail;
|
if (!parse_num(txth->streamHead,txth,val, &txth->name_size)) goto fail;
|
||||||
@ -1314,6 +1317,8 @@ static uint16_t get_string_wchar(const char * val, int pos, int *csize) {
|
|||||||
|
|
||||||
if (wchar >= 0x41 && wchar <= 0x5a)
|
if (wchar >= 0x41 && wchar <= 0x5a)
|
||||||
wchar += 0x20;
|
wchar += 0x20;
|
||||||
|
if (wchar == '\\')
|
||||||
|
wchar = '/'; /* normalize paths */
|
||||||
}
|
}
|
||||||
|
|
||||||
return wchar;
|
return wchar;
|
||||||
@ -1408,11 +1413,12 @@ fail:
|
|||||||
static int parse_name_table(txth_header * txth, char * name_list) {
|
static int parse_name_table(txth_header * txth, char * name_list) {
|
||||||
STREAMFILE *nameFile = NULL;
|
STREAMFILE *nameFile = NULL;
|
||||||
off_t txt_offset, file_size;
|
off_t txt_offset, file_size;
|
||||||
|
char fullname[PATH_LIMIT];
|
||||||
char filename[PATH_LIMIT];
|
char filename[PATH_LIMIT];
|
||||||
char basename[PATH_LIMIT];
|
char basename[PATH_LIMIT];
|
||||||
|
|
||||||
/* just in case */
|
/* just in case */
|
||||||
if (txth->streamfile_is_txth || !txth->streamText || !txth->streamFile)
|
if (!txth->streamText || !txth->streamBody)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* trim name_list just in case */
|
/* trim name_list just in case */
|
||||||
@ -1426,15 +1432,16 @@ static int parse_name_table(txth_header * txth, char * name_list) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//;VGM_LOG("TXTH: name_list2='%s'\n", name_list);
|
//;VGM_LOG("TXTH: name_list='%s'\n", name_list);
|
||||||
|
|
||||||
/* open companion file near .txth */
|
/* open companion file near .txth */
|
||||||
nameFile = open_streamfile_by_filename(txth->streamText, name_list);
|
nameFile = open_streamfile_by_filename(txth->streamText, name_list);
|
||||||
if (!nameFile) goto fail;
|
if (!nameFile) goto fail;
|
||||||
|
|
||||||
get_streamfile_filename(txth->streamFile, filename, sizeof(filename));
|
get_streamfile_name(txth->streamBody, fullname, sizeof(filename));
|
||||||
get_streamfile_basename(txth->streamFile, basename, sizeof(basename));
|
get_streamfile_filename(txth->streamBody, filename, sizeof(filename));
|
||||||
//;VGM_LOG("TXTH: filename=%s, basename=%s\n", filename, basename);
|
get_streamfile_basename(txth->streamBody, basename, sizeof(basename));
|
||||||
|
//;VGM_LOG("TXTH: names full=%s, file=%s, base=%s\n", fullname, filename, basename);
|
||||||
|
|
||||||
txt_offset = 0x00;
|
txt_offset = 0x00;
|
||||||
file_size = get_streamfile_size(nameFile);
|
file_size = get_streamfile_size(nameFile);
|
||||||
@ -1477,7 +1484,10 @@ static int parse_name_table(txth_header * txth, char * name_list) {
|
|||||||
|
|
||||||
//;VGM_LOG("TXTH: compare name '%s'\n", key);
|
//;VGM_LOG("TXTH: compare name '%s'\n", key);
|
||||||
/* parse values if key (name) matches default ("") or filename with/without extension */
|
/* parse values if key (name) matches default ("") or filename with/without extension */
|
||||||
if (key[0]=='\0' || is_string_match(filename, key) || is_string_match(basename, key)) {
|
if (key[0]=='\0'
|
||||||
|
|| is_string_match(filename, key)
|
||||||
|
|| is_string_match(basename, key)
|
||||||
|
|| is_string_match(fullname, key)) {
|
||||||
int n;
|
int n;
|
||||||
char subval[TXT_LINE_MAX];
|
char subval[TXT_LINE_MAX];
|
||||||
const char *current = val;
|
const char *current = val;
|
||||||
@ -1615,7 +1625,8 @@ static int parse_num(STREAMFILE * streamFile, txth_header * txth, const char * v
|
|||||||
else if ((n = is_string_field(val,"subsong_count"))) value = txth->subsong_count;
|
else if ((n = is_string_field(val,"subsong_count"))) value = txth->subsong_count;
|
||||||
else if ((n = is_string_field(val,"subsong_offset"))) value = txth->subsong_offset;
|
else if ((n = is_string_field(val,"subsong_offset"))) value = txth->subsong_offset;
|
||||||
else if ((n = is_string_field(val,"subfile_offset"))) value = txth->subfile_offset;
|
else if ((n = is_string_field(val,"subfile_offset"))) value = txth->subfile_offset;
|
||||||
else if ((n = is_string_field(val,"subfile_size"))) value = txth->subfile_size;
|
else if ((n = is_string_field(val,"subfile_size"))) value = txth->subfile_size;
|
||||||
|
else if ((n = is_string_field(val,"base_offset"))) value = txth->base_offset;
|
||||||
//todo whatever, improve
|
//todo whatever, improve
|
||||||
else if ((n = is_string_field(val,"name_value"))) value = txth->name_values[0];
|
else if ((n = is_string_field(val,"name_value"))) value = txth->name_values[0];
|
||||||
else if ((n = is_string_field(val,"name_value1"))) value = txth->name_values[0];
|
else if ((n = is_string_field(val,"name_value1"))) value = txth->name_values[0];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user