mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 01:30:49 +01:00
Fix .ssm subsongs [Kururin Squash! (GC)]
This commit is contained in:
parent
4c340d6956
commit
924b381691
@ -1125,7 +1125,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_ISH_ISD, "ISH+ISD DSP Header"},
|
||||
{meta_GSND, "Tecmo GSND Header"},
|
||||
{meta_YDSP, "Yuke's YDSP Header"},
|
||||
{meta_NGC_SSM, "SSM DSP Header"},
|
||||
{meta_SSM, "HAL Laboratory .SSM Header"},
|
||||
{meta_PS2_JOE, "Asobo Studio .JOE header"},
|
||||
{meta_VGS, "Guitar Hero VGS Header"},
|
||||
{meta_DCS_WAV, "In Utero DCS+WAV header"},
|
||||
|
@ -185,6 +185,7 @@
|
||||
<ClInclude Include="util\layout_utils.h" />
|
||||
<ClInclude Include="util\log.h" />
|
||||
<ClInclude Include="util\m2_psb.h" />
|
||||
<ClInclude Include="util\meta_utils.h" />
|
||||
<ClInclude Include="util\miniz.h" />
|
||||
<ClInclude Include="util\paths.h" />
|
||||
<ClInclude Include="util\reader_get.h" />
|
||||
@ -765,6 +766,7 @@
|
||||
<ClCompile Include="util\layout_utils.c" />
|
||||
<ClCompile Include="util\log.c" />
|
||||
<ClCompile Include="util\m2_psb.c" />
|
||||
<ClCompile Include="util\meta_utils.c" />
|
||||
<ClCompile Include="util\miniz.c" />
|
||||
<ClCompile Include="util\paths.c" />
|
||||
<ClCompile Include="util\reader.c" />
|
||||
|
@ -380,6 +380,9 @@
|
||||
<ClInclude Include="util\m2_psb.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\meta_utils.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\miniz.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -2116,6 +2119,9 @@
|
||||
<ClCompile Include="util\m2_psb.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\meta_utils.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\miniz.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -330,7 +330,7 @@ VGMSTREAM * init_vgmstream_ydsp(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM* init_vgmstream_gsnd(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_ssm(STREAMFILE * streamFile);
|
||||
VGMSTREAM* init_vgmstream_ssm(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE * streamFile);
|
||||
|
||||
|
@ -1,96 +1,85 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* SSM (Golden Gashbell Full Power GC) */
|
||||
VGMSTREAM * init_vgmstream_ngc_ssm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
int coef1_start;
|
||||
int coef2_start;
|
||||
int second_channel_start;
|
||||
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("ssm",filename_extension(filename)))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
#if 0
|
||||
if (read_32bitBE(0x00,streamFile) != 0x0)
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
loop_flag = (uint32_t)read_16bitBE(0x18,streamFile);
|
||||
channel_count = read_32bitBE(0x10,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = read_32bitBE(0x0,streamFile);
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x14,streamFile);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->num_samples = read_32bitBE(0x04,streamFile)*14/8/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x24,streamFile)*14/8/channel_count;
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x20,streamFile)*14/8/channel_count;
|
||||
}
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_NGC_SSM;
|
||||
|
||||
/* Retrieveing the coef tables and the start of the second channel*/
|
||||
coef1_start = 0x28;
|
||||
coef2_start = 0x68;
|
||||
second_channel_start = (read_32bitBE(0x04,streamFile)/2)+start_offset;
|
||||
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(coef1_start+i*2,streamFile);
|
||||
if (channel_count == 2) {
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(coef2_start+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
#include "../util/meta_utils.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
/* .SSM - from Hal Laboratory games [Smash Bros Melee! (GC), Konjiki no Gashbell: YnTB Full Power (GC), Kururin Squash! (GC)] */
|
||||
VGMSTREAM* init_vgmstream_ssm(STREAMFILE* sf) {
|
||||
meta_header_t h = {0};
|
||||
|
||||
/* The first channel */
|
||||
vgmstream->ch[0].channel_start_offset=
|
||||
vgmstream->ch[0].offset=start_offset;
|
||||
|
||||
/* The second channel */
|
||||
if (channel_count == 2) {
|
||||
vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
/* checks */
|
||||
h.head_size = read_u32be(0x00,sf);
|
||||
h.data_size = read_u32be(0x04,sf);
|
||||
h.total_subsongs = read_s32be(0x08,sf);
|
||||
int file_id = read_u32be(0x0c,sf);
|
||||
|
||||
if (!vgmstream->ch[1].streamfile) goto fail;
|
||||
/* extra tests + arbitrary maxes since no good header ID and values aren't exact */
|
||||
if (0x10 + h.head_size + h.data_size > get_streamfile_size(sf))
|
||||
return NULL;
|
||||
if (h.head_size < h.total_subsongs * 0x48 || h.total_subsongs <= 0 || h.total_subsongs > 0x1000 || file_id > 0x1000)
|
||||
return NULL;
|
||||
if (!check_extensions(sf, "ssm"))
|
||||
return NULL;
|
||||
|
||||
vgmstream->ch[1].channel_start_offset=
|
||||
vgmstream->ch[1].offset=second_channel_start;
|
||||
}
|
||||
}
|
||||
|
||||
h.target_subsong = sf->stream_index;
|
||||
if (!check_subsongs(&h.target_subsong, h.total_subsongs))
|
||||
return NULL;
|
||||
|
||||
/* sometimes there is padding after head_size, DSP's start ps matches this */
|
||||
h.data_offset = get_streamfile_size(sf) - h.data_size; //0x10 + h.head_size;
|
||||
|
||||
|
||||
uint32_t offset = 0x10;
|
||||
for (int i = 0; i < h.total_subsongs; i++) {
|
||||
int channels = read_u32be(offset + 0x00,sf);
|
||||
if (channels < 1 || channels > 2) return NULL;
|
||||
|
||||
if (i + 1 == h.target_subsong) {
|
||||
h.channels = read_u32be(offset + 0x00,sf);
|
||||
h.sample_rate = read_s32be(offset + 0x04,sf);
|
||||
|
||||
/* use first channel as base */
|
||||
h.loop_flag = read_s16be(offset + 0x08,sf);
|
||||
h.loop_start = read_u32be(offset + 0x0c,sf);
|
||||
h.chan_size = read_u32be(offset + 0x10,sf);
|
||||
h.stream_offset = read_s32be(offset + 0x14,sf);
|
||||
h.coefs_offset = offset + 0x18;
|
||||
h.coefs_spacing = 0x40;
|
||||
h.hists_offset = h.coefs_offset + 0x24;
|
||||
h.hists_spacing = h.coefs_spacing;
|
||||
if (h.channels >= 2) {
|
||||
h.interleave = read_s32be(offset + 0x54,sf); /* use 2nd channel offset as interleave */
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
offset += 0x08 + channels * 0x40;
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
/* oddly enough values are in absolute nibbles within the stream, adjust them here
|
||||
* rarely may even point to a nibble after the header one (ex. 0x1005), but it's adjusted to 0x00 here */
|
||||
h.loop_start -= h.stream_offset;
|
||||
h.chan_size -= h.stream_offset;
|
||||
if (h.interleave)
|
||||
h.interleave -= h.stream_offset;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
h.loop_start = dsp_nibbles_to_samples(h.loop_start);
|
||||
h.loop_end = dsp_nibbles_to_samples(h.chan_size);
|
||||
h.num_samples = h.loop_end;
|
||||
|
||||
h.stream_offset = (h.stream_offset / 0x10 * 0x08) + h.data_offset;
|
||||
h.stream_size = (h.chan_size / 0x10 * 0x08 + (h.chan_size % 0x08 ? 0x08 : 0x00)) * h.channels;
|
||||
h.interleave = h.interleave / 0x10 * 0x08;
|
||||
|
||||
h.coding = coding_NGC_DSP;
|
||||
h.layout = layout_interleave; //TODO layout flat + channel offset may be more appropriate
|
||||
h.meta = meta_SSM;
|
||||
|
||||
h.sf = sf;
|
||||
h.big_endian = true;
|
||||
h.open_stream = true;
|
||||
|
||||
return alloc_metastream(&h);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
48
src/util/meta_utils.c
Normal file
48
src/util/meta_utils.c
Normal file
@ -0,0 +1,48 @@
|
||||
#include "../vgmstream.h"
|
||||
#include "meta_utils.h"
|
||||
|
||||
|
||||
/* Allocate memory and setup a VGMSTREAM */
|
||||
VGMSTREAM* alloc_metastream(meta_header_t* h) {
|
||||
|
||||
if (h->sample_rate <= 0 || h->sample_rate > VGMSTREAM_MAX_SAMPLE_RATE)
|
||||
return NULL;
|
||||
if (h->num_samples <= 0 || h->num_samples > VGMSTREAM_MAX_NUM_SAMPLES)
|
||||
return NULL;
|
||||
|
||||
VGMSTREAM* vgmstream = allocate_vgmstream(h->channels, h->loop_flag);
|
||||
if (!vgmstream) return NULL;
|
||||
|
||||
//vgmstream->channels = h->channels;
|
||||
vgmstream->sample_rate = h->sample_rate;
|
||||
vgmstream->num_samples = h->num_samples;
|
||||
vgmstream->loop_start_sample = h->loop_start;
|
||||
vgmstream->loop_end_sample = h->loop_end;
|
||||
|
||||
vgmstream->coding_type = h->coding;
|
||||
vgmstream->layout_type = h->layout;
|
||||
vgmstream->meta_type = h->meta;
|
||||
|
||||
vgmstream->num_streams = h->total_subsongs;
|
||||
vgmstream->stream_size = h->stream_size;
|
||||
vgmstream->interleave_block_size = h->interleave;
|
||||
|
||||
|
||||
if (h->coding == coding_NGC_DSP && (h->sf || h->sf_head)) {
|
||||
if (h->coefs_offset || h->coefs_spacing)
|
||||
dsp_read_coefs(vgmstream, h->sf ? h->sf : h->sf_head, h->coefs_offset, h->coefs_spacing, h->big_endian);
|
||||
if (h->hists_offset || h->hists_spacing)
|
||||
dsp_read_hist (vgmstream, h->sf ? h->sf : h->sf_head, h->hists_offset, h->hists_spacing, h->big_endian);
|
||||
}
|
||||
|
||||
if (h->open_stream) {
|
||||
if (!vgmstream_open_stream(vgmstream, h->sf ? h->sf : h->sf_head, h->stream_offset))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
61
src/util/meta_utils.h
Normal file
61
src/util/meta_utils.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef _META_UTILS_H
|
||||
#define _META_UTILS_H
|
||||
|
||||
#include "../streamtypes.h"
|
||||
#include "reader_get.h"
|
||||
#include "reader_put.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* Helper struct for common numbers (no need to use all), to use with helper functions.
|
||||
* Preferably declare after validating header ID as it's faster (by a minuscule amount). */
|
||||
typedef struct {
|
||||
/* should be set */
|
||||
int channels;
|
||||
int sample_rate;
|
||||
int32_t num_samples;
|
||||
|
||||
/* optional info */
|
||||
bool loop_flag;
|
||||
int32_t loop_start;
|
||||
int32_t loop_end;
|
||||
|
||||
int target_subsong;
|
||||
int total_subsongs;
|
||||
|
||||
int32_t interleave;
|
||||
|
||||
/* common helpers */
|
||||
uint32_t stream_offset; /* where current stream starts */
|
||||
uint32_t stream_size; /* current stream size */
|
||||
uint32_t data_offset; /* where data (first stream) starts */
|
||||
uint32_t data_size; /* data for all streams */
|
||||
uint32_t head_size; /* size of some header part */
|
||||
uint32_t chan_offset;
|
||||
uint32_t chan_size;
|
||||
|
||||
uint32_t coefs_offset;
|
||||
uint32_t coefs_spacing;
|
||||
uint32_t hists_offset;
|
||||
uint32_t hists_spacing;
|
||||
|
||||
/* optional but can be used for some actions */
|
||||
bool big_endian;
|
||||
coding_t coding;
|
||||
layout_t layout;
|
||||
meta_t meta;
|
||||
|
||||
/* only sf_head is used to read coefs and such */
|
||||
STREAMFILE* sf;
|
||||
STREAMFILE* sf_head;
|
||||
STREAMFILE* sf_body;
|
||||
|
||||
bool open_stream;
|
||||
} meta_header_t;
|
||||
|
||||
VGMSTREAM* alloc_metastream(meta_header_t* h);
|
||||
|
||||
/* checks max subsongs and setups target */
|
||||
//bool check_subsongs(int* target_subsong, int total_subsongs);
|
||||
|
||||
#endif
|
@ -142,7 +142,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
|
||||
init_vgmstream_ish_isd,
|
||||
init_vgmstream_gsnd,
|
||||
init_vgmstream_ydsp,
|
||||
init_vgmstream_ngc_ssm,
|
||||
init_vgmstream_ssm,
|
||||
init_vgmstream_ps2_joe,
|
||||
init_vgmstream_vgs,
|
||||
init_vgmstream_dcs_wav,
|
||||
|
@ -364,7 +364,7 @@ typedef enum {
|
||||
meta_FFCC_STR, /* Final Fantasy: Crystal Chronicles */
|
||||
meta_UBI_JADE, /* Beyond Good & Evil, Rayman Raving Rabbids */
|
||||
meta_GCA, /* Metal Slug Anthology */
|
||||
meta_NGC_SSM, /* Golden Gashbell Full Power */
|
||||
meta_SSM,
|
||||
meta_PS2_JOE, /* Wall-E / Pixar games */
|
||||
meta_YMF,
|
||||
meta_SADL,
|
||||
|
Loading…
Reference in New Issue
Block a user