mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 01:30:49 +01:00
Fix PSH/VSV loops and glitches [Romancing SaGa (PS2)]
This commit is contained in:
parent
d7c2249358
commit
9ad2f578e6
@ -248,6 +248,10 @@
|
||||
RelativePath=".\meta\ppst_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ps2_psh_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\sqex_scd_streamfile.h"
|
||||
>
|
||||
|
@ -103,6 +103,7 @@
|
||||
<ClInclude Include="meta\fsb_interleave_streamfile.h" />
|
||||
<ClInclude Include="meta\fsb5_interleave_streamfile.h" />
|
||||
<ClInclude Include="meta\ppst_streamfile.h" />
|
||||
<ClInclude Include="meta\ps2_psh_streamfile.h" />
|
||||
<ClInclude Include="meta\opus_interleave_streamfile.h" />
|
||||
<ClInclude Include="meta\sqex_scd_streamfile.h" />
|
||||
<ClInclude Include="meta\ubi_lyn_ogg_streamfile.h" />
|
||||
|
@ -92,6 +92,9 @@
|
||||
<ClInclude Include="meta\ppst_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\ps2_psh_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\sqex_scd_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -1,75 +1,72 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "ps2_psh_streamfile.h"
|
||||
|
||||
/* PSH (from Dawn of Mana - Seiken Densetsu 4, Kingdom Hearts Re:Chain of Memories) */
|
||||
/* probably Square Vag Stream */
|
||||
|
||||
/* PSH/VSV - from Square Enix games [Dawn of Mana: Seiken Densetsu 4 (PS2), Kingdom Hearts Re:Chain of Memories (PS2)] */
|
||||
VGMSTREAM * init_vgmstream_ps2_psh(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
off_t start_offset;
|
||||
uint8_t testBuffer[0x10];
|
||||
off_t loopEnd = 0;
|
||||
off_t readOffset = 0;
|
||||
size_t fileLength;
|
||||
int loop_flag, channel_count;
|
||||
size_t loop_start, adjust, data_size, interleave;
|
||||
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile, "psh,vsv")) // vsv seems to be official extension
|
||||
/* checks */
|
||||
/* .psh: assumed? [Romancing SaGa: Minstrel's Song (PS2)]
|
||||
* .vsv: official? [Kingdom Hearts HD I.5 + II.5 ReMIX (PS4)] */
|
||||
if (!check_extensions(streamFile, "psh,vsv"))
|
||||
goto fail;
|
||||
/* 0x00(2): 0x0000 (RS:MS) / 0x6440 (KH:RCoM) / varies (DoM) */
|
||||
if ((uint16_t)read_16bitBE(0x02,streamFile) != 0x6400)
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_16bitBE(0x02,streamFile) != 0x6400)
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_16bitLE(0x06,streamFile)!=0);
|
||||
channel_count = 2;
|
||||
|
||||
start_offset = 0x00; /* correct, but needs some tricks to fix sound (see below) */
|
||||
interleave = 0x800;
|
||||
|
||||
adjust = (uint16_t)read_16bitLE(0x04,streamFile) & 0x7FF; /* upper bits = ??? */
|
||||
data_size = (uint16_t)read_16bitLE(0x0c,streamFile) * interleave;
|
||||
/* 0x0e: ? (may be 0x0001, or a low-ish value, not related to looping?) */
|
||||
loop_start = ((uint16_t)read_16bitLE(0x06,streamFile) & 0x7FFF) * interleave; /* uper bit == loop flag? */
|
||||
loop_flag = (loop_start != 0); /* (no known files loop from beginning to end) */
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x08,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = (uint16_t)read_16bitLE(0x0C,streamFile)*0x800*28/16/channel_count;
|
||||
|
||||
// loop end is set by the loop marker which we need to find ...
|
||||
// there's some extra data on unloop files, so we calculate
|
||||
// the sample count with loop marker on this files
|
||||
fileLength = get_streamfile_size(streamFile);
|
||||
do {
|
||||
readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile);
|
||||
|
||||
// Loop End ...
|
||||
if(testBuffer[0x01]==0x03) {
|
||||
if(loopEnd==0) loopEnd = readOffset-0x10;
|
||||
break;
|
||||
}
|
||||
} while (streamFile->get_offset(streamFile)<(int32_t)fileLength);
|
||||
|
||||
if(loopEnd!=0)
|
||||
vgmstream->num_samples = loopEnd*28/16/channel_count;
|
||||
|
||||
if(loop_flag) {
|
||||
vgmstream->loop_start_sample =
|
||||
((uint16_t)read_16bitLE(0x06,streamFile)-0x8000)*0x400*28/16;
|
||||
vgmstream->loop_end_sample=vgmstream->num_samples;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x800;
|
||||
vgmstream->meta_type = meta_PS2_PSH;
|
||||
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x08,streamFile);
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size,channel_count);
|
||||
|
||||
/* open the file for reading */
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start,channel_count);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
/* loops are odd, but comparing the audio wave with the OSTs these values seem correct */
|
||||
if (adjust == 0) { /* Romancing SaGa (PS2) */
|
||||
vgmstream->loop_start_sample -= ps_bytes_to_samples(channel_count*interleave,channel_count); /* maybe *before* loop block? */
|
||||
vgmstream->loop_start_sample -= ps_bytes_to_samples(0x200*channel_count,channel_count); /* maybe default adjust? */
|
||||
}
|
||||
else { /* all others */
|
||||
vgmstream->loop_end_sample -= ps_bytes_to_samples((0x800 - adjust)*channel_count,channel_count); /* at last block + adjust is a 0x03 flag */
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
|
||||
temp_streamFile = setup_ps2_psh_streamfile(streamFile, start_offset, data_size);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, temp_streamFile, start_offset))
|
||||
goto fail;
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
48
src/meta/ps2_psh_streamfile.h
Normal file
48
src/meta/ps2_psh_streamfile.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef _PS2_PSH_STREAMFILE_H_
|
||||
#define _PS2_PSH_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
typedef struct {
|
||||
off_t null_offset;
|
||||
} ps2_psh_io_data;
|
||||
|
||||
static size_t ps2_psh_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, ps2_psh_io_data* data) {
|
||||
size_t bytes_read;
|
||||
int i;
|
||||
|
||||
bytes_read = streamfile->read(streamfile, dest, offset, length);
|
||||
|
||||
/* PSHs do start at 0x00, but first line is also the header; must null it to avoid clicks */
|
||||
if (offset < data->null_offset) {
|
||||
for (i = 0; i < data->null_offset - offset; i++) {
|
||||
dest[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static STREAMFILE* setup_ps2_psh_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t data_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
ps2_psh_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(ps2_psh_io_data);
|
||||
|
||||
io_data.null_offset = 0x10;
|
||||
|
||||
/* setup custom streamfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, ps2_psh_io_read,NULL);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _PS2_PSH_STREAMFILE_H_ */
|
Loading…
Reference in New Issue
Block a user