diff --git a/src/layout/interleave.c b/src/layout/interleave.c index d61cc3e2..a376b5f2 100644 --- a/src/layout/interleave.c +++ b/src/layout/interleave.c @@ -8,19 +8,48 @@ * Incompatible with decoders that move offsets. */ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { 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; - 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 && - vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block > vgmstream->num_samples) { - /* adjust values again if inside last interleave */ - frame_size = get_vgmstream_shortframe_size(vgmstream); - samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream); - samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame; + /* setup */ + { + int frame_size_d = get_vgmstream_frame_size(vgmstream); + samples_per_frame_d = get_vgmstream_samples_per_frame(vgmstream); + if (frame_size_d == 0 || samples_per_frame_d == 0) goto fail; + 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 */ @@ -28,18 +57,28 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR samples_this_block = vgmstream->num_samples; + /* write samples */ while (samples_written < sample_count) { int samples_to_do; if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { /* 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); - samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); - samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame; + + if (has_interleave_first && + vgmstream->current_sample < samples_this_block_f) { + /* 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) 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; } @@ -48,9 +87,7 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR samples_to_do = sample_count - samples_written; if (samples_to_do == 0) { /* happens when interleave is not set */ - VGM_LOG("layout_interleave: wrong samples_to_do found\n"); - memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t)); - break; + goto fail; } 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) { int ch; - if (has_interleave_last && - vgmstream->current_sample + samples_this_block > vgmstream->num_samples) { - /* adjust values again if inside last interleave */ - frame_size = get_vgmstream_shortframe_size(vgmstream); - samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream); - samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame; + if (has_interleave_first && + vgmstream->current_sample == samples_this_block_f) { + /* restore standard frame size after going past first interleave */ + 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; for (ch = 0; ch < vgmstream->channels; ch++) { - off_t skip = vgmstream->interleave_block_size*(vgmstream->channels-ch) + - vgmstream->interleave_last_block_size*ch;; + off_t skip = + 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; } } @@ -88,6 +141,9 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR 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)); } diff --git a/src/meta/seg.c b/src/meta/seg.c index 9a09210a..87e6f85b 100644 --- a/src/meta/seg.c +++ b/src/meta/seg.c @@ -67,11 +67,14 @@ VGMSTREAM * init_vgmstream_seg(STREAMFILE *streamFile) { vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_interleave; 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 */ 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); - //todo first_interleave: 0x2000 - 60 + + start_offset += vgmstream->interleave_first_skip; break; case 0x70635F00: /* "pc_\0" */ diff --git a/src/meta/vag.c b/src/meta/vag.c index bc351c80..a34c632e 100644 --- a/src/meta/vag.c +++ b/src/meta/vag.c @@ -6,7 +6,7 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; 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; int channel_count = 0, loop_flag, sample_rate; 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)] */ meta_type = meta_PS2_pGAV; - start_offset = 0x00; //todo 0x30, requires interleave_first + start_offset = 0x30; if (read_32bitBE(0x20,streamFile) == 0x53746572) { /* "Ster" */ channel_count = 2; @@ -91,7 +91,8 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { interleave = 0x1000; /* Jak X interleave, includes header */ else 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 { channel_count = 1; @@ -127,21 +128,21 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { } else if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */ /* The Simpsons Wrestling (PS1) */ - start_offset = 0x00; //todo 0x30, requires interleave_first + start_offset = 0x30; channel_count = 2; interleave = 0x6000; - //todo interleave_first = interleave - start_offset; /* includes header */ - channel_size += 0x30; + interleave_first = interleave - start_offset; /* includes header */ + interleave_first_skip = start_offset; loop_flag = 0; } else if (read_32bitBE(0x1000,streamFile) == 0x56414770) { /* "VAGp" */ /* Shikigami no Shiro (PS2) */ - start_offset = 0x00; //todo 0x30, requires interleave_first + start_offset = 0x30; channel_count = 2; interleave = 0x1000; - //todo interleave_first = interleave - start_offset; /* includes header */ - channel_size += 0x30; + interleave_first = interleave - start_offset; /* includes header */ + 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); } @@ -244,6 +245,9 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { vgmstream->coding_type = coding_HEVAG; vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_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 */ diff --git a/src/vgmstream.c b/src/vgmstream.c index 90ab3f16..6af00f02 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -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); 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) { snprintf(temp,TEMPSIZE, "interleave last block: %#x bytes\n", (int32_t)vgmstream->interleave_last_block_size); concatn(length,desc,temp); diff --git a/src/vgmstream.h b/src/vgmstream.h index bce2237d..0dfe363f 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -824,6 +824,8 @@ typedef struct { /* layouts/block config */ 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 */ /* subsong config */