diff --git a/README.md b/README.md
index 1de80a91..c82368f0 100644
--- a/README.md
+++ b/README.md
@@ -191,7 +191,7 @@ left together.
Similarly some formats split header and/or data in separate files (.sgh+sgd,
.wav.str+.wav, (file)_L.dsp+(file)_R.dsp, etc). vgmstream will also detect
-and use those as needed and must be tegether, even if only one of the two
+and use those as needed and must be together, even if only one of the two
will be used to play.
.pos is a small file with 32 bit little endian values: loop start sample
@@ -308,7 +308,7 @@ the format defined.
## Supported codec types
-Quick list of codecs vgmstream supports, including many obscure ones that
+Quick list of codecs vgmstream supports, including many obscure ones that
are used in few games.
- PCM 16-bit
@@ -322,7 +322,7 @@ are used in few games.
- Nintendo AFC ADPCM
- ITU-T G.721
- CD-ROM XA ADPCM
-- Sony PSX ADPCM a.k.a VAG (standard, badflags, configurable)
+- Sony PSX ADPCM a.k.a VAG (standard, badflags, configurable, Pivotal)
- Sony HEVAG
- Electronic Arts EA-XA (stereo, mono, Maxis)
- Electronic Arts EA-XAS (v0, v1)
diff --git a/src/coding/coding.h b/src/coding/coding.h
index 2707b2d8..cd2b542a 100644
--- a/src/coding/coding.h
+++ b/src/coding/coding.h
@@ -83,6 +83,7 @@ size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
/* psx_decoder */
void decode_psx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags);
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_pivotal(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);
diff --git a/src/coding/psx_decoder.c b/src/coding/psx_decoder.c
index 47c66ac7..f5e7ebd4 100644
--- a/src/coding/psx_decoder.c
+++ b/src/coding/psx_decoder.c
@@ -3,11 +3,11 @@
/* PS-ADPCM table, defined as rational numbers (as in the spec) */
static const double ps_adpcm_coefs_f[5][2] = {
- { 0.0 , 0.0 },
- { 60.0 / 64.0 , 0.0 },
- { 115.0 / 64.0 , -52.0 / 64.0 },
- { 98.0 / 64.0 , -55.0 / 64.0 },
- { 122.0 / 64.0 , -60.0 / 64.0 },
+ { 0.0 , 0.0 }, //{ 0.0 , 0.0 },
+ { 0.9375 , 0.0 }, //{ 60.0 / 64.0 , 0.0 },
+ { 1.796875 , -0.8125 }, //{ 115.0 / 64.0 , -52.0 / 64.0 },
+ { 1.53125 , -0.859375 }, //{ 98.0 / 64.0 , -55.0 / 64.0 },
+ { 1.90625 , -0.9375 }, //{ 122.0 / 64.0 , -60.0 / 64.0 },
};
/* PS-ADPCM table, defined as spec_coef*64 (for int implementations) */
@@ -101,7 +101,7 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing
/* PS-ADPCM with configurable frame size and no flag (int math version).
- * Found in some PC/PS3 games (FF XI in sizes 3/5/9/41, Afrika in size 4, Blur/James Bond in size 33, etc).
+ * Found in some PC/PS3 games (FF XI in sizes 0x3/0x5/0x9/0x41, Afrika in size 0x4, Blur/James Bond in size 0x33, etc).
*
* Uses int math to decode, which seems more likely (based on FF XI PC's code in Moogle Toolbox). */
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) {
@@ -114,7 +114,7 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int c
/* external interleave (variable size), mono */
bytes_per_frame = frame_size;
- samples_per_frame = (bytes_per_frame - 0x01) * 2; /* always 28 */
+ samples_per_frame = (bytes_per_frame - 0x01) * 2;
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame;
@@ -152,6 +152,56 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int c
stream->adpcm_history2_32 = hist2;
}
+/* PS-ADPCM from Pivotal games, exactly like psx_cfg but with float math (reverse engineered from the exe) */
+void decode_psx_pivotal(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) {
+ off_t frame_offset;
+ int i, frames_in, sample_count = 0;
+ size_t bytes_per_frame, samples_per_frame;
+ uint8_t coef_index, shift_factor;
+ int32_t hist1 = stream->adpcm_history1_32;
+ int32_t hist2 = stream->adpcm_history2_32;
+ float scale;
+
+ /* external interleave (variable size), mono */
+ bytes_per_frame = frame_size;
+ samples_per_frame = (bytes_per_frame - 0x01) * 2;
+ frames_in = first_sample / samples_per_frame;
+ first_sample = first_sample % samples_per_frame;
+
+ /* parse frame header */
+ frame_offset = stream->offset + bytes_per_frame*frames_in;
+ coef_index = ((uint8_t)read_8bit(frame_offset+0x00,stream->streamfile) >> 4) & 0xf;
+ shift_factor = ((uint8_t)read_8bit(frame_offset+0x00,stream->streamfile) >> 0) & 0xf;
+
+ VGM_ASSERT_ONCE(coef_index > 5 || shift_factor > 12, "PS-ADPCM: incorrect coefs/shift at %x\n", (uint32_t)frame_offset);
+ if (coef_index > 5) /* just in case */
+ coef_index = 5;
+ if (shift_factor > 12) /* same */
+ shift_factor = 12;
+ scale = (float)(1.0 / (double)(1 << shift_factor));
+
+ /* decode nibbles */
+ for (i = first_sample; i < first_sample + samples_to_do; i++) {
+ int32_t sample = 0;
+ uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x01+i/2,stream->streamfile);
+
+ sample = !(i&1) ? /* low nibble first */
+ (nibbles >> 0) & 0x0f :
+ (nibbles >> 4) & 0x0f;
+ sample = (int16_t)((sample << 12) & 0xf000); /* 16b sign extend + default scale */
+ sample = sample*scale + ps_adpcm_coefs_f[coef_index][0]*hist1 + ps_adpcm_coefs_f[coef_index][1]*hist2; /* actually substracts negative coefs but whatevs */
+
+ outbuf[sample_count] = clamp16(sample);
+ sample_count += channelspacing;
+
+ hist2 = hist1;
+ hist1 = sample; /* not clamped but no difference */
+ }
+
+ stream->adpcm_history1_32 = hist1;
+ stream->adpcm_history2_32 = hist2;
+}
+
/* Find loop samples in PS-ADPCM data and return if the file loops.
*
@@ -339,7 +389,8 @@ 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) {
- return bytes / channels / frame_size * 28;
+ int samples_per_frame = (frame_size - 0x01) * 2;
+ return bytes / channels / frame_size * samples_per_frame;
}
/* test PS-ADPCM frames for correctness */
diff --git a/src/formats.c b/src/formats.c
index 2c43467c..6ca3635e 100644
--- a/src/formats.c
+++ b/src/formats.c
@@ -333,6 +333,7 @@ static const char* extension_list[] = {
"pona",
"pos",
"ps2stm", //fake extension for .stm (renamed? to be removed?)
+ "psf",
"psh", //fake extension for .vsv (to be removed)
"psnd",
"psw", //fake extension for .wam (renamed, to be removed)
@@ -616,6 +617,7 @@ static const coding_info coding_info_list[] = {
{coding_PSX, "Playstation 4-bit ADPCM"},
{coding_PSX_badflags, "Playstation 4-bit ADPCM (bad flags)"},
{coding_PSX_cfg, "Playstation 4-bit ADPCM (configurable)"},
+ {coding_PSX_pivotal, "Playstation 4-bit ADPCM (Pivotal)"},
{coding_HEVAG, "Sony HEVAG 4-bit ADPCM"},
{coding_EA_XA, "Electronic Arts EA-XA 4-bit ADPCM v1"},
@@ -963,7 +965,6 @@ static const meta_info meta_info_list[] = {
{meta_PS2_VGV, "Rune: Viking Warlord VGV Header"},
{meta_NGC_GCUB, "GCub Header"},
{meta_NGC_SCK_DSP, "The Scorpion King SCK Header"},
- {meta_NGC_SWD, "PSF + Standard DSP Headers"},
{meta_CAFF, "Apple Core Audio Format File header"},
{meta_PC_MXST, "Lego Island MxSt Header"},
{meta_SAB, "Team17 SAB header"},
@@ -1187,6 +1188,7 @@ static const meta_info meta_info_list[] = {
{meta_SMACKER, "RAD Game Tools SMACKER header"},
{meta_MZRT, "id Software MZRT header"},
{meta_XAVS, "Reflections XAVS header"},
+ {meta_PSF, "Pivotal PSF header"},
};
diff --git a/src/layout/segmented.c b/src/layout/segmented.c
index 2c2e18c8..3477bf4c 100644
--- a/src/layout/segmented.c
+++ b/src/layout/segmented.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
#include "../mixing.h"
-#define VGMSTREAM_MAX_SEGMENTS 255
+#define VGMSTREAM_MAX_SEGMENTS 512
#define VGMSTREAM_SEGMENT_SAMPLE_BUFFER 8192
diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj
index aa7aa84e..e04fbe58 100644
--- a/src/libvgmstream.vcproj
+++ b/src/libvgmstream.vcproj
@@ -1366,10 +1366,14 @@
RelativePath=".\meta\mta2.c"
>
-
-
+
+
+
+
diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj
index 892a9e48..de48b9dc 100644
--- a/src/libvgmstream.vcxproj
+++ b/src/libvgmstream.vcxproj
@@ -195,6 +195,7 @@
+
diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters
index 454f77e6..0eecc019 100644
--- a/src/libvgmstream.vcxproj.filters
+++ b/src/libvgmstream.vcxproj.filters
@@ -1369,6 +1369,9 @@
meta\Source Files
+
+ meta\Source Files
+
meta\Source Files
diff --git a/src/meta/meta.h b/src/meta/meta.h
index 8f128e9c..dfd6ad77 100644
--- a/src/meta/meta.h
+++ b/src/meta/meta.h
@@ -31,7 +31,6 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_idsp_nus3(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sadf(STREAMFILE *streamFile);
-VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_idsp_nl(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile);
@@ -852,4 +851,7 @@ VGMSTREAM * init_vgmstream_mzrt(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_xavs(STREAMFILE * streamFile);
+VGMSTREAM * init_vgmstream_psf_single(STREAMFILE * streamFile);
+VGMSTREAM * init_vgmstream_psf_segmented(STREAMFILE * streamFile);
+
#endif /*_META_H*/
diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c
index f00024c4..e336e495 100644
--- a/src/meta/ngc_dsp_std.c
+++ b/src/meta/ngc_dsp_std.c
@@ -690,33 +690,6 @@ fail:
return NULL;
}
-/* SWD - PSF chunks + interleaved dsps [Conflict: Desert Storm 1 & 2] */
-VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE *streamFile) {
- dsp_meta dspm = {0};
-
- /* checks */
- if (!check_extensions(streamFile, "swd"))
- goto fail;
-
- //todo blocked layout when first chunk is 0x50534631 (count + table of 0x0c with offset/sizes)
-
- if (read_32bitBE(0x00,streamFile) != 0x505346d1) /* PSF\0xd1 */
- goto fail;
-
- dspm.channel_count = 2;
- dspm.max_channels = 2;
-
- dspm.header_offset = 0x08;
- dspm.header_spacing = 0x60;
- dspm.start_offset = dspm.header_offset + 0x60 * dspm.channel_count;
- dspm.interleave = 0x08;
-
- dspm.meta_type = meta_NGC_SWD;
- return init_vgmstream_dsp_common(streamFile, &dspm);
-fail:
- return NULL;
-}
-
/* IDSP - Traveller's Tales header + interleaved dsps [Lego Batman (Wii), Lego Dimensions (Wii U)] */
VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile) {
dsp_meta dspm = {0};
diff --git a/src/meta/psf.c b/src/meta/psf.c
new file mode 100644
index 00000000..a7f79ef4
--- /dev/null
+++ b/src/meta/psf.c
@@ -0,0 +1,242 @@
+#include "meta.h"
+#include "../layout/layout.h"
+#include "../coding/coding.h"
+
+
+/* PSF single - Pivotal games single segment (external in some PC/Xbox or inside bigfiles) [The Great Escape, Conflict series] */
+VGMSTREAM * init_vgmstream_psf_single(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int loop_flag, channel_count, sample_rate, rate_value, interleave;
+ uint32_t psf_config;
+ uint8_t flags;
+ size_t data_size;
+ coding_t codec;
+
+
+ /* checks */
+ /* .psf: actual extension
+ * .swd: bigfile extension */
+ if (!check_extensions(streamFile, "psf,swd"))
+ goto fail;
+ if ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x50534600) /* "PSF\00" */
+ goto fail;
+
+ flags = read_8bit(0x03,streamFile);
+ switch(flags) {
+ case 0xC0: /* [The Great Escape (PS2), Conflict: Desert Storm (PS2)] */
+ case 0xA1: /* [Conflict: Desert Storm 2 (PS2)] */
+ case 0x21: /* [Conflict: Desert Storm 2 (PS2), Conflict: Global Storm (PS2)] */
+ //case 0x22: /* [Conflict: Vietman (PS2)] */ //todo weird size value, stereo, only one found
+ channel_count = 2;
+ if (flags == 0x21)
+ channel_count = 1;
+ interleave = 0x10;
+ codec = coding_PSX;
+ start_offset = 0x08;
+ break;
+
+ case 0x80: /* [The Great Escape (PC/Xbox), Conflict: Desert Storm (Xbox/GC), Conflict: Desert Storm 2 (Xbox)] */
+ case 0x81: /* [Conflict: Desert Storm 2 (Xbox), Conflict: Vietnam (Xbox)] */
+ case 0x01: /* [Conflict: Global Storm (Xbox)] */
+ channel_count = 2;
+ if (flags == 0x01)
+ channel_count = 1;
+ interleave = 0x10;
+ codec = coding_PSX_pivotal;
+ start_offset = 0x08;
+ break;
+
+ case 0xD1: /* [Conflict: Desert Storm 2 (GC)] */
+ channel_count = 2;
+ interleave = 0x08;
+ codec = coding_NGC_DSP;
+ start_offset = 0x08 + 0x60 * channel_count;
+ break;
+
+ default:
+ goto fail;
+ }
+
+ loop_flag = 0;
+
+ psf_config = read_32bitLE(0x04, streamFile);
+
+ /* pitch/cents? */
+ rate_value = (psf_config >> 20) & 0xFFF;
+ switch(rate_value) {
+ //case 0xEB5:
+ //case 0xEB4:
+ case 0xEB3: sample_rate = 44100; break;
+ case 0x555: sample_rate = 16000; break;
+ case 0x355: sample_rate = 11050; break;
+ case 0x1d5: sample_rate = 6000; break; /* ? */
+ case 0x1cc: sample_rate = 5000; break;
+ default:
+ VGM_LOG("PSF: unknown rate value %x\n", rate_value);
+ goto fail;
+ }
+
+ data_size = (psf_config & 0xFFFFF) * (interleave * channel_count); /* in blocks */
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->meta_type = meta_PSF;
+ vgmstream->sample_rate = sample_rate;
+
+ switch(codec) {
+ case coding_PSX:
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = interleave;
+
+ vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
+ break;
+
+ case coding_PSX_pivotal:
+ vgmstream->coding_type = coding_PSX_pivotal;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = interleave;
+
+ vgmstream->num_samples = ps_cfg_bytes_to_samples(data_size, 0x10, channel_count);
+ break;
+
+ case coding_NGC_DSP:
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = interleave;
+ /* has standard DSP headers at 0x08 */
+ dsp_read_coefs_be(vgmstream,streamFile,0x08+0x1c,0x60);
+ dsp_read_hist_be (vgmstream,streamFile,0x08+0x40,0x60);
+
+ vgmstream->num_samples = read_32bitBE(0x08, streamFile);//dsp_bytes_to_samples(data_size, channel_count);
+ break;
+
+ default:
+ goto fail;
+ }
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+/* PSF segmented - Pivotal games multiple segments (external in some PC/Xbox or inside bigfiles) [The Great Escape, Conflict series] */
+VGMSTREAM * init_vgmstream_psf_segmented(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ STREAMFILE* temp_streamFile = NULL;
+ segmented_layout_data *data = NULL;
+ int i, segment_count, loop_flag = 0, loop_start = 0, loop_end = 0;
+ off_t offset;
+
+
+ /* checks */
+ /* .psf: actual extension
+ * .swd: bigfile extension */
+ if (!check_extensions(streamFile, "psf,swd"))
+ goto fail;
+
+ if (read_32bitBE(0x00,streamFile) != 0x50534660 && /* "PSF\60" [The Great Escape (PC/Xbox/PS2), Conflict: Desert Storm (Xbox/GC)] */
+ read_32bitBE(0x00,streamFile) != 0x50534631) /* "PSF\31" [Conflict: Desert Storm 2 (Xbox/GC/PS2)] */
+ goto fail;
+
+ segment_count = read_32bitLE(0x04, streamFile);
+ loop_flag = 0;
+
+ offset = 0x08;
+ offset += 0x0c; /* first segment points to itself? */
+ segment_count--;
+
+ /* build segments */
+ data = init_layout_segmented(segment_count);
+ if (!data) goto fail;
+
+ for (i = 0; i < segment_count; i++) {
+ off_t psf_offset;
+ size_t psf_size;
+ uint32_t psf_id;
+
+ /* mini table */
+ psf_offset = read_32bitLE(offset + 0x00, streamFile);
+ /* 0x04-0c: 0x02*4 transition segments (possibly to 4 song variations) */
+
+ /* use last section transition as loop */
+ if (i + 1 == segment_count) {
+ loop_flag = 1;
+ loop_start = read_16bitLE(offset + 0x0a, streamFile) - 1; /* also ignore first segment */
+ loop_end = i;
+ }
+
+ /* multiple segment can point to the same PSF offset (for repeated song sections) */
+ //todo reuse repeated VGMSTREAMs to improve memory a bit
+
+ psf_id = read_32bitBE(psf_offset + 0x00, streamFile);
+ psf_size = read_32bitLE(psf_offset + 0x04, streamFile);
+ if (psf_id == 0x505346D1) //todo improve
+ psf_size = (psf_size & 0xFFFFF) * 0x10;
+ else
+ psf_size = (psf_size & 0xFFFFF) * 0x20;
+ //;VGM_LOG("PSF: offset=%lx, size=%x\n", psf_offset, psf_size);
+
+ temp_streamFile = setup_subfile_streamfile(streamFile, psf_offset, psf_size, "psf");
+ if (!temp_streamFile) goto fail;
+
+ data->segments[i] = init_vgmstream_psf_single(temp_streamFile);
+ if (!data->segments[i]) goto fail;
+
+ offset += 0x0c;
+ }
+
+ /* setup VGMSTREAMs */
+ if (!setup_layout_segmented(data))
+ goto fail;
+ vgmstream = allocate_segmented_vgmstream(data,loop_flag, loop_start, loop_end);
+ if (!vgmstream) goto fail;
+
+ vgmstream->stream_size = get_streamfile_size(streamFile);
+
+ return vgmstream;
+fail:
+ if (!vgmstream) free_layout_segmented(data);
+ close_streamfile(temp_streamFile);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+#if 0
+VGMSTREAM * init_vgmstream_sch(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int loop_flag, channel_count;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "sch"))
+ goto fail;
+
+ /* chunked format (id+size, GC pads to 0x20 and uses BE/inverted ids):
+ * - SCH\0: start
+ * - IMUS: points to a external .psf + segment table (same as in .psf, TGE only?)
+ * - BANK: volume/etc info? points to something?
+ * - PFSM: single .psf-like file (larger header)
+ * - PFST: points to single PSF offset (.psf in TGE, or STREAMS.SWD); may be chained to next PFST?
+ *
+ * no other info so total subsongs would be count of usable chunks
+ * in later games, segmented .psf seems to be removed and PFST is used instead
+ */
+
+ return vgmstream;
+fail:
+ if (!vgmstream) free_layout_layered(data);
+ close_streamfile(temp_streamFile);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+#endif
diff --git a/src/vgmstream.c b/src/vgmstream.c
index 5781ca97..b5afd745 100644
--- a/src/vgmstream.c
+++ b/src/vgmstream.c
@@ -123,7 +123,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_sdt,
init_vgmstream_aix,
init_vgmstream_ngc_tydsp,
- init_vgmstream_ngc_swd,
init_vgmstream_capdsp,
init_vgmstream_xbox_wvs,
init_vgmstream_ngc_wvs,
@@ -467,6 +466,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_smk,
init_vgmstream_mzrt,
init_vgmstream_xavs,
+ init_vgmstream_psf_single,
+ init_vgmstream_psf_segmented,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
@@ -1171,7 +1172,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_HEVAG:
return 28;
case coding_PSX_cfg:
- return (vgmstream->interleave_block_size - 1) * 2; /* decodes 1 byte into 2 bytes */
+ case coding_PSX_pivotal:
+ return (vgmstream->interleave_block_size - 0x01) * 2; /* size 0x01 header */
case coding_EA_XA:
case coding_EA_XA_int:
@@ -1359,6 +1361,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_HEVAG:
return 0x10;
case coding_PSX_cfg:
+ case coding_PSX_pivotal:
return vgmstream->interleave_block_size;
case coding_EA_XA:
@@ -1674,6 +1677,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->interleave_block_size);
}
break;
+ case coding_PSX_pivotal:
+ for (ch = 0; ch < vgmstream->channels; ch++) {
+ decode_psx_pivotal(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
+ vgmstream->channels,vgmstream->samples_into_block,samples_to_do,
+ vgmstream->interleave_block_size);
+ }
+ break;
case coding_HEVAG:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_hevag(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
diff --git a/src/vgmstream.h b/src/vgmstream.h
index 89c02e7e..bce2237d 100644
--- a/src/vgmstream.h
+++ b/src/vgmstream.h
@@ -104,7 +104,8 @@ typedef enum {
coding_XA, /* CD-ROM XA */
coding_PSX, /* Sony PS ADPCM (VAG) */
coding_PSX_badflags, /* Sony PS ADPCM with custom flag byte */
- coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (FF XI, SGXD type 5, Bizarre Creations) */
+ coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (int math) */
+ coding_PSX_pivotal, /* Sony PS ADPCM with configurable frame size (float math) */
coding_HEVAG, /* Sony PSVita ADPCM */
coding_EA_XA, /* Electronic Arts EA-XA ADPCM v1 (stereo) aka "EA ADPCM" */
@@ -389,7 +390,6 @@ typedef enum {
meta_PS2_ENTH, /* Enthusia */
meta_SDT, /* Baldur's Gate - Dark Alliance */
meta_NGC_TYDSP, /* Ty - The Tasmanian Tiger */
- meta_NGC_SWD, /* Conflict - Desert Storm 1 & 2 */
meta_CAPDSP, /* Capcom DSP Header [no header_id] */
meta_DC_STR, /* SEGA Stream Asset Builder */
meta_DC_STR_V2, /* variant of SEGA Stream Asset Builder */
@@ -712,6 +712,7 @@ typedef enum {
meta_SMACKER,
meta_MZRT,
meta_XAVS,
+ meta_PSF,
} meta_t;