mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 09:40:51 +01:00
Add TXTH padding_size = (value|auto|auto-empty) to skip PS-ADPCM padding
This commit is contained in:
parent
4cf1db7fc1
commit
703c29775d
@ -84,6 +84,7 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing
|
||||
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
|
||||
int ps_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end);
|
||||
int ps_find_loop_offsets_full(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end);
|
||||
size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int discard_empty);
|
||||
size_t ps_bytes_to_samples(size_t bytes, int channels);
|
||||
size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels);
|
||||
|
||||
|
@ -176,6 +176,9 @@ static int ps_find_loop_offsets_internal(STREAMFILE *streamFile, off_t start_off
|
||||
int detect_full_loops = config & 1;
|
||||
|
||||
|
||||
if (data_size == 0 || channels == 0 || (channels > 0 && interleave == 0))
|
||||
return 0;
|
||||
|
||||
while (offset < max_offset) {
|
||||
uint8_t flag = (uint8_t)read_8bit(offset+0x01,streamFile) & 0x0F; /* lower nibble only (for HEVAG) */
|
||||
|
||||
@ -268,6 +271,63 @@ int ps_find_loop_offsets_full(STREAMFILE *streamFile, off_t start_offset, size_t
|
||||
return ps_find_loop_offsets_internal(streamFile, start_offset, data_size, channels, interleave, out_loop_start, out_loop_end, 1);
|
||||
}
|
||||
|
||||
size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int discard_empty) {
|
||||
off_t min_offset, offset;
|
||||
size_t frame_size = 0x10;
|
||||
size_t padding_size = 0;
|
||||
size_t interleave_consumed = 0;
|
||||
|
||||
|
||||
if (data_size == 0 || channels == 0 || (channels > 0 && interleave == 0))
|
||||
return 0;
|
||||
|
||||
offset = start_offset + data_size;
|
||||
min_offset = 0; //offset - interleave; /* some files have padding spanning multiple interleave blocks */
|
||||
|
||||
while (offset > min_offset) {
|
||||
uint32_t f1,f2,f3,f4;
|
||||
uint8_t flag;
|
||||
int is_empty = 0;
|
||||
|
||||
offset -= frame_size;
|
||||
|
||||
f1 = read_32bitBE(offset+0x00,streamFile);
|
||||
f2 = read_32bitBE(offset+0x04,streamFile);
|
||||
f3 = read_32bitBE(offset+0x08,streamFile);
|
||||
f4 = read_32bitBE(offset+0x0c,streamFile);
|
||||
flag = (f1 >> 16) & 0xFF;
|
||||
|
||||
if (f1 == 0 && f2 == 0 && f3 == 0 && f4 == 0)
|
||||
is_empty = 1;
|
||||
|
||||
if (!is_empty && discard_empty) {
|
||||
if (flag == 0x07 || flag == 0x77)
|
||||
is_empty = 1; /* 'discard frame' flag */
|
||||
else if ((f1 & 0xFF00FFFF) == 0 && f2 == 0 && f3 == 0 && f4 == 0)
|
||||
is_empty = 1; /* silent with flags (typical for looping files) */
|
||||
else if ((f1 & 0xFF00FFFF) == 0x0C000000 && f2 == 0 && f3 == 0 && f4 == 0)
|
||||
is_empty = 1; /* silent (maybe shouldn't ignore flag 0x03?) */
|
||||
else if ((f1 & 0x0000FFFF) == 0x00007777 && f2 == 0x77777777 && f3 ==0x77777777 && f4 == 0x77777777)
|
||||
is_empty = 1; /* silent-ish */
|
||||
}
|
||||
|
||||
if (!is_empty)
|
||||
break;
|
||||
|
||||
padding_size += frame_size * channels;
|
||||
|
||||
/* skip other channels */
|
||||
interleave_consumed += 0x10;
|
||||
if (interleave_consumed == interleave) {
|
||||
interleave_consumed = 0;
|
||||
offset -= interleave*(channels - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return padding_size;
|
||||
}
|
||||
|
||||
|
||||
size_t ps_bytes_to_samples(size_t bytes, int channels) {
|
||||
if (channels <= 0) return 0;
|
||||
return bytes / channels / 0x10 * 28;
|
||||
|
@ -57,6 +57,7 @@ typedef struct {
|
||||
uint32_t data_size;
|
||||
int data_size_set;
|
||||
uint32_t start_offset;
|
||||
uint32_t padding_size;
|
||||
|
||||
int sample_type;
|
||||
uint32_t num_samples;
|
||||
@ -616,6 +617,7 @@ static int parse_coef_table(STREAMFILE * streamFile, txth_header * txth, const c
|
||||
static int is_string(const char * val, const char * cmp);
|
||||
static int is_substring(const char * val, const char * cmp);
|
||||
static int get_bytes_to_samples(txth_header * txth, uint32_t bytes);
|
||||
static int get_padding_size(txth_header * txth, int discard_empty);
|
||||
|
||||
/* Simple text parser of "key = value" lines.
|
||||
* The code is meh and error handling not exactly the best. */
|
||||
@ -776,6 +778,8 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
|
||||
}
|
||||
else if (is_string(key,"start_offset")) {
|
||||
if (!parse_num(txth->streamHead,txth,val, &txth->start_offset)) goto fail;
|
||||
|
||||
/* apply */
|
||||
if (!txth->data_size_set) {
|
||||
uint32_t body_size = !txth->streamBody ? 0 : get_streamfile_size(txth->streamBody);
|
||||
|
||||
@ -795,6 +799,23 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
|
||||
txth->data_size = body_size - txth->start_offset; /* re-evaluate */
|
||||
}
|
||||
}
|
||||
else if (is_string(key,"padding_size")) {
|
||||
if (is_string(val,"auto")) {
|
||||
txth->padding_size = get_padding_size(txth, 0);
|
||||
}
|
||||
else if (is_string(val,"auto-empty")) {
|
||||
txth->padding_size = get_padding_size(txth, 1);
|
||||
}
|
||||
else {
|
||||
if (!parse_num(txth->streamHead,txth,val, &txth->padding_size)) goto fail;
|
||||
}
|
||||
|
||||
/* apply */
|
||||
if (!txth->data_size_set) {
|
||||
if (txth->padding_size < txth->data_size)
|
||||
txth->data_size -= txth->padding_size;
|
||||
}
|
||||
}
|
||||
else if (is_string(key,"data_size")) {
|
||||
if (!parse_num(txth->streamHead,txth,val, &txth->data_size)) goto fail;
|
||||
txth->data_size_set = 1;
|
||||
@ -1262,3 +1283,15 @@ static int get_bytes_to_samples(txth_header * txth, uint32_t bytes) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_padding_size(txth_header * txth, int discard_empty) {
|
||||
if (txth->data_size == 0 || txth->channels == 0)
|
||||
return 0;
|
||||
|
||||
switch(txth->codec) {
|
||||
case PSX:
|
||||
return ps_find_padding(txth->streamBody, txth->start_offset, txth->data_size, txth->channels, txth->interleave, discard_empty);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user