diff --git a/doc/TXTH.md b/doc/TXTH.md index 49cca054..6c694878 100644 --- a/doc/TXTH.md +++ b/doc/TXTH.md @@ -53,7 +53,7 @@ The following can be used in place of `(value)` for `(key) = (value)` commands. - `(other)`: other special values for certain keys, described per key -The above may be combined with math operations (+-*/): `(key) = (number) (op) (offset) (op) (field) (...)` +The above may be combined with math operations (+-*/&): `(key) = (number) (op) (offset) (op) (field) (...)` ### KEYS @@ -240,7 +240,7 @@ Modifies the meaning of sample fields when set *before* them. Accepted values: - `samples`: exact sample (default) -- `bytes`: automatically converts bytes/offset to samples (applies after */+- modifiers) +- `bytes`: automatically converts bytes/offset to samples (applies after */+-& modifiers) - `blocks`: same as bytes, but value is given in blocks/frames * Value is internally converted from blocks to bytes first: `bytes = (value * interleave*channels)` @@ -520,13 +520,13 @@ sample_rate = 0x04 # sample rate is the same for all subsongs ``` ### Math -Sometimes header values are in "sectors" or similar concepts (typical in DVD games), and need to be adjusted to a real value. +Sometimes header values are in "sectors" or similar concepts (typical in DVD games), and need to be adjusted to a real value using some complex math: ``` sample_type = bytes start_offset = @0x10 * 0x800 # 0x15 * DVD sector size, for example ``` -You can also use certain fields' values: +You can use `+-*/&` operators, and also certain fields' values: ``` num_samples = @0x10 * channels # byte-to-samples of channel_size ``` @@ -825,3 +825,17 @@ PAD.XAG : 0x150 JIN002.XAG: 0x168 JIN003.XAG: 0x180 ``` + + +** Grandia (PS1) ** +``` +header_file = GM1.IDX +body_file = GM1.STZ + +subsong_count = 394 #last doesn't have size though +subsong_offset = 0x04 + +subfile_offset = (@0x00 & 0xFFFFF) * 0x800 +subfile_extension = seb +subfile_size = ((@0x04 - @0x00) & 0xFFFFF) * 0x800 +``` diff --git a/src/meta/txth.c b/src/meta/txth.c index 8c85bda7..6b0d0ae6 100644 --- a/src/meta/txth.c +++ b/src/meta/txth.c @@ -593,7 +593,8 @@ static VGMSTREAM *init_subfile(txth_header * txth) { vgmstream_force_loop(vgmstream, 0, 0, 0); } - if (txth->chunk_count && txth->subsong_count) { + /* assumes won't point to subfiles with subsongs */ + if (/*txth->chunk_count &&*/ txth->subsong_count) { vgmstream->num_streams = txth->subsong_count; } //todo: other combos with subsongs + subfile? @@ -1256,7 +1257,7 @@ static int is_substring(const char * val, const char * cmp, int inline_field) { chr = val[len]; /* "val" can end with math for inline fields (like interleave*0x10) */ - if (inline_field && (chr == '+' || chr == '-' || chr == '*' || chr == '/')) + if (inline_field && (chr == '+' || chr == '-' || chr == '*' || chr == '/' || chr == '&')) return len; /* otherwise "val" ends in space or eof (to tell "interleave" and "interleave_last" apart) */ @@ -1532,7 +1533,7 @@ static int parse_num(STREAMFILE * streamFile, txth_header * txth, const char * v brackets--; n = 1; } - else if (type == '+' || type == '-' || type == '/' || type == '*') { /* op */ + else if (type == '+' || type == '-' || type == '/' || type == '*' || type == '&') { /* op */ op = type; n = 1; } @@ -1600,6 +1601,8 @@ static int parse_num(STREAMFILE * streamFile, txth_header * txth, const char * v else if ((n = is_string_field(val,"loop_end_sample"))) value = txth->loop_end_sample; 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; //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]; @@ -1631,6 +1634,7 @@ static int parse_num(STREAMFILE * streamFile, txth_header * txth, const char * v case '-': value = result - value; break; case '*': value = result * value; break; case '/': if (value == 0) goto fail; value = result / value; break; + case '&': value = result & value; break; default: break; } op = ' '; /* consume */