Add TXTH logical AND (&) operator for bitmasks

This commit is contained in:
bnnm 2019-10-06 23:47:25 +02:00
parent 786c75aa73
commit 122622252a
2 changed files with 25 additions and 7 deletions

View File

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

View File

@ -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 */