Add interleave_first to fix some .vag/seg clicks

This commit is contained in:
bnnm 2019-08-12 19:23:49 +02:00
parent 01ac9377d4
commit b3a8f2b280
5 changed files with 106 additions and 36 deletions

View File

@ -8,19 +8,48 @@
* Incompatible with decoders that move offsets. */ * Incompatible with decoders that move offsets. */
void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written = 0; int samples_written = 0;
int frame_size, samples_per_frame, samples_this_block; int samples_per_frame, samples_this_block; /* used */
int samples_per_frame_d = 0, samples_this_block_d = 0; /* default */
int samples_per_frame_f = 0, samples_this_block_f = 0; /* first */
int samples_per_frame_l = 0, samples_this_block_l = 0; /* last */
int has_interleave_first = vgmstream->interleave_first_block_size && vgmstream->channels > 1;
int has_interleave_last = vgmstream->interleave_last_block_size && vgmstream->channels > 1; int has_interleave_last = vgmstream->interleave_last_block_size && vgmstream->channels > 1;
frame_size = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
if (has_interleave_last && /* setup */
vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block > vgmstream->num_samples) { {
/* adjust values again if inside last interleave */ int frame_size_d = get_vgmstream_frame_size(vgmstream);
frame_size = get_vgmstream_shortframe_size(vgmstream); samples_per_frame_d = get_vgmstream_samples_per_frame(vgmstream);
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream); if (frame_size_d == 0 || samples_per_frame_d == 0) goto fail;
samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame; samples_this_block_d = vgmstream->interleave_block_size / frame_size_d * samples_per_frame_d;
}
if (has_interleave_first) {
int frame_size_f = get_vgmstream_frame_size(vgmstream);
samples_per_frame_f = get_vgmstream_samples_per_frame(vgmstream); //todo samples per shortframe
if (frame_size_f == 0 || samples_per_frame_f == 0) goto fail;
samples_this_block_f = vgmstream->interleave_first_block_size / frame_size_f * samples_per_frame_f;
}
else if (has_interleave_last) {
int frame_size_l = get_vgmstream_shortframe_size(vgmstream);
samples_per_frame_l = get_vgmstream_samples_per_shortframe(vgmstream);
if (frame_size_l == 0 || samples_per_frame_l == 0) goto fail;
samples_this_block_l = vgmstream->interleave_last_block_size / frame_size_l * samples_per_frame_l;
}
/* set current values */
if (has_interleave_first &&
vgmstream->current_sample < samples_this_block_f) {
samples_per_frame = samples_per_frame_f;
samples_this_block = samples_this_block_f;
}
else if (has_interleave_last &&
vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block_d > vgmstream->num_samples) {
samples_per_frame = samples_per_frame_l;
samples_this_block = samples_this_block_l;
}
else {
samples_per_frame = samples_per_frame_d;
samples_this_block = samples_this_block_d;
} }
/* mono interleaved stream with no layout set, just behave like flat layout */ /* mono interleaved stream with no layout set, just behave like flat layout */
@ -28,18 +57,28 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
samples_this_block = vgmstream->num_samples; samples_this_block = vgmstream->num_samples;
/* write samples */
while (samples_written < sample_count) { while (samples_written < sample_count) {
int samples_to_do; int samples_to_do;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
/* handle looping, restore standard interleave sizes */ /* handle looping, restore standard interleave sizes */
if (has_interleave_last) { /* assumes that won't loop back into a interleave_last */
frame_size = get_vgmstream_frame_size(vgmstream); if (has_interleave_first &&
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); vgmstream->current_sample < samples_this_block_f) {
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame; /* use first interleave*/
samples_per_frame = samples_per_frame_f;
samples_this_block = samples_this_block_f;
if (samples_this_block == 0 && vgmstream->channels == 1) if (samples_this_block == 0 && vgmstream->channels == 1)
samples_this_block = vgmstream->num_samples; samples_this_block = vgmstream->num_samples;
} }
else if (has_interleave_last) { /* assumes that won't loop back into a interleave_last */
samples_per_frame = samples_per_frame_d;
samples_this_block = samples_this_block_d;
if (samples_this_block == 0 && vgmstream->channels == 1)
samples_this_block = vgmstream->num_samples;
}
continue; continue;
} }
@ -48,9 +87,7 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
samples_to_do = sample_count - samples_written; samples_to_do = sample_count - samples_written;
if (samples_to_do == 0) { /* happens when interleave is not set */ if (samples_to_do == 0) { /* happens when interleave is not set */
VGM_LOG("layout_interleave: wrong samples_to_do found\n"); goto fail;
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
break;
} }
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer); decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
@ -64,18 +101,34 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
if (vgmstream->samples_into_block == samples_this_block) { if (vgmstream->samples_into_block == samples_this_block) {
int ch; int ch;
if (has_interleave_last && if (has_interleave_first &&
vgmstream->current_sample + samples_this_block > vgmstream->num_samples) { vgmstream->current_sample == samples_this_block_f) {
/* adjust values again if inside last interleave */ /* restore standard frame size after going past first interleave */
frame_size = get_vgmstream_shortframe_size(vgmstream); samples_per_frame = samples_per_frame_d;
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream); samples_this_block = samples_this_block_d;
samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame;
if (samples_this_block == 0 && vgmstream->channels == 1) if (samples_this_block == 0 && vgmstream->channels == 1)
samples_this_block = vgmstream->num_samples; samples_this_block = vgmstream->num_samples;
for (ch = 0; ch < vgmstream->channels; ch++) { for (ch = 0; ch < vgmstream->channels; ch++) {
off_t skip = vgmstream->interleave_block_size*(vgmstream->channels-ch) + off_t skip =
vgmstream->interleave_last_block_size*ch;; vgmstream->interleave_first_skip*(vgmstream->channels-1-ch) +
vgmstream->interleave_first_block_size*(vgmstream->channels-ch) +
vgmstream->interleave_block_size*ch;
vgmstream->ch[ch].offset += skip;
}
}
else if (has_interleave_last &&
vgmstream->current_sample + samples_this_block > vgmstream->num_samples) {
/* adjust values again if inside last interleave */
samples_per_frame = samples_per_frame_l;
samples_this_block = samples_this_block_l;
if (samples_this_block == 0 && vgmstream->channels == 1)
samples_this_block = vgmstream->num_samples;
for (ch = 0; ch < vgmstream->channels; ch++) {
off_t skip =
vgmstream->interleave_block_size*(vgmstream->channels-ch) +
vgmstream->interleave_last_block_size*ch;
vgmstream->ch[ch].offset += skip; vgmstream->ch[ch].offset += skip;
} }
} }
@ -88,6 +141,9 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
vgmstream->samples_into_block = 0; vgmstream->samples_into_block = 0;
} }
} }
return;
fail:
VGM_LOG("layout_interleave: wrong values found\n");
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
} }

View File

@ -67,11 +67,14 @@ VGMSTREAM * init_vgmstream_seg(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_NGC_DSP; vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave; vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2000; vgmstream->interleave_block_size = 0x2000;
vgmstream->interleave_first_skip = 0x60;
vgmstream->interleave_first_block_size = vgmstream->interleave_block_size - vgmstream->interleave_first_skip;
/* standard dsp header at start_offset */ /* standard dsp header at start_offset */
dsp_read_coefs_be(vgmstream, streamFile, start_offset+0x1c, vgmstream->interleave_block_size); dsp_read_coefs_be(vgmstream, streamFile, start_offset+0x1c, vgmstream->interleave_block_size);
dsp_read_hist_be(vgmstream, streamFile, start_offset+0x40, vgmstream->interleave_block_size); dsp_read_hist_be(vgmstream, streamFile, start_offset+0x40, vgmstream->interleave_block_size);
//todo first_interleave: 0x2000 - 60
start_offset += vgmstream->interleave_first_skip;
break; break;
case 0x70635F00: /* "pc_\0" */ case 0x70635F00: /* "pc_\0" */

View File

@ -6,7 +6,7 @@
VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM * vgmstream = NULL;
off_t start_offset; off_t start_offset;
size_t file_size, channel_size, interleave; size_t file_size, channel_size, interleave, interleave_first = 0, interleave_first_skip = 0;
meta_t meta_type; meta_t meta_type;
int channel_count = 0, loop_flag, sample_rate; int channel_count = 0, loop_flag, sample_rate;
uint32_t vag_id, version; uint32_t vag_id, version;
@ -80,7 +80,7 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
case 0x70474156: /* pGAV (little endian / stereo) [Jak 3 (PS2), Jak X (PS2)] */ case 0x70474156: /* pGAV (little endian / stereo) [Jak 3 (PS2), Jak X (PS2)] */
meta_type = meta_PS2_pGAV; meta_type = meta_PS2_pGAV;
start_offset = 0x00; //todo 0x30, requires interleave_first start_offset = 0x30;
if (read_32bitBE(0x20,streamFile) == 0x53746572) { /* "Ster" */ if (read_32bitBE(0x20,streamFile) == 0x53746572) { /* "Ster" */
channel_count = 2; channel_count = 2;
@ -91,7 +91,8 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
interleave = 0x1000; /* Jak X interleave, includes header */ interleave = 0x1000; /* Jak X interleave, includes header */
else else
interleave = 0x2000; /* Jak 3 interleave in rare files, no header */ interleave = 0x2000; /* Jak 3 interleave in rare files, no header */
//todo interleave_first = interleave - start_offset; /* interleave includes header */ interleave_first = interleave - start_offset; /* interleave includes header */
interleave_first_skip = start_offset;
} }
else { else {
channel_count = 1; channel_count = 1;
@ -127,21 +128,21 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
} }
else if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */ else if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */
/* The Simpsons Wrestling (PS1) */ /* The Simpsons Wrestling (PS1) */
start_offset = 0x00; //todo 0x30, requires interleave_first start_offset = 0x30;
channel_count = 2; channel_count = 2;
interleave = 0x6000; interleave = 0x6000;
//todo interleave_first = interleave - start_offset; /* includes header */ interleave_first = interleave - start_offset; /* includes header */
channel_size += 0x30; interleave_first_skip = start_offset;
loop_flag = 0; loop_flag = 0;
} }
else if (read_32bitBE(0x1000,streamFile) == 0x56414770) { /* "VAGp" */ else if (read_32bitBE(0x1000,streamFile) == 0x56414770) { /* "VAGp" */
/* Shikigami no Shiro (PS2) */ /* Shikigami no Shiro (PS2) */
start_offset = 0x00; //todo 0x30, requires interleave_first start_offset = 0x30;
channel_count = 2; channel_count = 2;
interleave = 0x1000; interleave = 0x1000;
//todo interleave_first = interleave - start_offset; /* includes header */ interleave_first = interleave - start_offset; /* includes header */
channel_size += 0x30; interleave_first_skip = start_offset;
loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample);
} }
@ -244,6 +245,9 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_HEVAG; vgmstream->coding_type = coding_HEVAG;
vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave; vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
vgmstream->interleave_block_size = interleave; vgmstream->interleave_block_size = interleave;
vgmstream->interleave_first_block_size = interleave_first;
vgmstream->interleave_first_skip = interleave_first_skip;
read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); /* always, can be null */ read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); /* always, can be null */

View File

@ -2422,6 +2422,11 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
snprintf(temp,TEMPSIZE, "interleave: %#x bytes\n", (int32_t)vgmstream->interleave_block_size); snprintf(temp,TEMPSIZE, "interleave: %#x bytes\n", (int32_t)vgmstream->interleave_block_size);
concatn(length,desc,temp); concatn(length,desc,temp);
if (vgmstream->interleave_first) {
snprintf(temp,TEMPSIZE, "interleave first block: %#x bytes\n", (int32_t)vgmstream->interleave_first);
concatn(length,desc,temp);
}
if (vgmstream->interleave_last_block_size) { if (vgmstream->interleave_last_block_size) {
snprintf(temp,TEMPSIZE, "interleave last block: %#x bytes\n", (int32_t)vgmstream->interleave_last_block_size); snprintf(temp,TEMPSIZE, "interleave last block: %#x bytes\n", (int32_t)vgmstream->interleave_last_block_size);
concatn(length,desc,temp); concatn(length,desc,temp);

View File

@ -824,6 +824,8 @@ typedef struct {
/* layouts/block config */ /* layouts/block config */
size_t interleave_block_size; /* interleave, or block/frame size (depending on the codec) */ size_t interleave_block_size; /* interleave, or block/frame size (depending on the codec) */
size_t interleave_first_block_size; /* different interleave for first block */
size_t interleave_first_skip; /* data skipped before interleave first (needed to skip other channels) */
size_t interleave_last_block_size; /* smaller interleave for last block */ size_t interleave_last_block_size; /* smaller interleave for last block */
/* subsong config */ /* subsong config */