Merge pull request #577 from bnnm/txth

txth
This commit is contained in:
bnnm 2020-03-15 00:44:13 +01:00 committed by GitHub
commit 50cb942206
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 115 additions and 13 deletions

View File

@ -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)
* Example: `@0x10:BE$2` means `get big endian 16b value at 0x10`
- `(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
@ -664,6 +664,19 @@ chunk_size = 0x8000
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
**Colin McRae DiRT (PC) .wip.txth**
@ -827,7 +840,7 @@ JIN003.XAG: 0x180
```
** Grandia (PS1) **
**Grandia (PS1) bgm.txth**
```
header_file = GM1.IDX
body_file = GM1.STZ
@ -839,3 +852,80 @@ subfile_offset = (@0x00 & 0xFFFFF) * 0x800
subfile_extension = seb
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
```

View File

@ -461,6 +461,7 @@ static const char* extension_list[] = {
"spsd",
"spw",
"ss2",
"ssd", //txth/reserved [Zack & Wiki (Wii)]
"ssm",
"sss",
"ster",

View File

@ -1063,9 +1063,10 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
/* COEFS */
else if (is_string(key,"coef_offset")) {
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)
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")) {
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;
txth->hist_set = 1;
/* special adjustment */
txth->hist_offset += txth->hist_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")) {
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;
txth->name_offset_set = 1;
/* special adjustment */
txth->name_offset += txth->base_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")) {
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)
wchar += 0x20;
if (wchar == '\\')
wchar = '/'; /* normalize paths */
}
return wchar;
@ -1408,11 +1413,12 @@ fail:
static int parse_name_table(txth_header * txth, char * name_list) {
STREAMFILE *nameFile = NULL;
off_t txt_offset, file_size;
char fullname[PATH_LIMIT];
char filename[PATH_LIMIT];
char basename[PATH_LIMIT];
/* just in case */
if (txth->streamfile_is_txth || !txth->streamText || !txth->streamFile)
if (!txth->streamText || !txth->streamBody)
goto fail;
/* 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 */
nameFile = open_streamfile_by_filename(txth->streamText, name_list);
if (!nameFile) goto fail;
get_streamfile_filename(txth->streamFile, filename, sizeof(filename));
get_streamfile_basename(txth->streamFile, basename, sizeof(basename));
//;VGM_LOG("TXTH: filename=%s, basename=%s\n", filename, basename);
get_streamfile_name(txth->streamBody, fullname, sizeof(filename));
get_streamfile_filename(txth->streamBody, filename, sizeof(filename));
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;
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);
/* 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;
char subval[TXT_LINE_MAX];
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_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_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
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];