mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +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);
|
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(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);
|
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_bytes_to_samples(size_t bytes, int channels);
|
||||||
size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, 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;
|
int detect_full_loops = config & 1;
|
||||||
|
|
||||||
|
|
||||||
|
if (data_size == 0 || channels == 0 || (channels > 0 && interleave == 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
while (offset < max_offset) {
|
while (offset < max_offset) {
|
||||||
uint8_t flag = (uint8_t)read_8bit(offset+0x01,streamFile) & 0x0F; /* lower nibble only (for HEVAG) */
|
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);
|
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) {
|
size_t ps_bytes_to_samples(size_t bytes, int channels) {
|
||||||
if (channels <= 0) return 0;
|
if (channels <= 0) return 0;
|
||||||
return bytes / channels / 0x10 * 28;
|
return bytes / channels / 0x10 * 28;
|
||||||
|
@ -57,6 +57,7 @@ typedef struct {
|
|||||||
uint32_t data_size;
|
uint32_t data_size;
|
||||||
int data_size_set;
|
int data_size_set;
|
||||||
uint32_t start_offset;
|
uint32_t start_offset;
|
||||||
|
uint32_t padding_size;
|
||||||
|
|
||||||
int sample_type;
|
int sample_type;
|
||||||
uint32_t num_samples;
|
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_string(const char * val, const char * cmp);
|
||||||
static int is_substring(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_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.
|
/* Simple text parser of "key = value" lines.
|
||||||
* The code is meh and error handling not exactly the best. */
|
* 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")) {
|
else if (is_string(key,"start_offset")) {
|
||||||
if (!parse_num(txth->streamHead,txth,val, &txth->start_offset)) goto fail;
|
if (!parse_num(txth->streamHead,txth,val, &txth->start_offset)) goto fail;
|
||||||
|
|
||||||
|
/* apply */
|
||||||
if (!txth->data_size_set) {
|
if (!txth->data_size_set) {
|
||||||
uint32_t body_size = !txth->streamBody ? 0 : get_streamfile_size(txth->streamBody);
|
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 */
|
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")) {
|
else if (is_string(key,"data_size")) {
|
||||||
if (!parse_num(txth->streamHead,txth,val, &txth->data_size)) goto fail;
|
if (!parse_num(txth->streamHead,txth,val, &txth->data_size)) goto fail;
|
||||||
txth->data_size_set = 1;
|
txth->data_size_set = 1;
|
||||||
@ -1262,3 +1283,15 @@ static int get_bytes_to_samples(txth_header * txth, uint32_t bytes) {
|
|||||||
return 0;
|
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…
x
Reference in New Issue
Block a user