vgmstream/src/meta/rawi.c

179 lines
6.2 KiB
C
Raw Normal View History

2023-07-08 17:50:08 +02:00
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "../util/endianness.h"
/* RAWI - from Torus games "SqueakStream" samples */
VGMSTREAM* init_vgmstream_rawi(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sb = NULL;
STREAMFILE* sn = NULL;
uint32_t start_offset, name_offset, extn_offset, interleave;
int channels, loop_flag, codec, sample_rate;
int32_t num_samples, loop_start, loop_end;
/* checks */
bool big_endian = false;
if (is_id32be(0x00,sf, "RAWI"))
big_endian = false;
else if (is_id32be(0x00,sf, "IWAR"))
big_endian = true; /* Wii/PS3 */
else
return NULL;
//TODO: handle first version used in Scooby Doo! First Frights (similar but larger fields and no header ID)
/* (extensionless): no known extension */
if (!check_extensions(sf,""))
return NULL;
read_s32_t read_s32 = big_endian ? read_s32be : read_s32le;
read_u32_t read_u32 = big_endian ? read_u32be : read_u32le;
/* mini header with a string to the external asset; on Wii this string is also in a separate file */
if (read_u8(0x04,sf) != 0x01) /* version? */
return NULL;
codec = read_u8(0x05,sf);
channels = read_u8(0x06,sf);
/* 0x07: null */
num_samples = read_s32(0x08, sf);
sample_rate = read_s32(0x0c, sf);
loop_start = read_s32(0x10, sf);
loop_end = read_s32(0x14, sf);
//etbl_offset = read_u32(0x18, sf);
name_offset = read_u32(0x1c, sf);
/* 0x20: null, unknown values (sometimes floats) */
interleave = read_u32(0x38, sf);
/* extra values, then DSP coefs if needed, then asset name (header size is not exact) */
extn_offset = (name_offset >> 24) & 0xFF; /* if name is external, sub-offset inside that file */
name_offset = (name_offset >> 0) & 0xFFFFFF; /* if name is external, default/unused (same with etbl_offset) */
/* simplify as Wii defines both and uses a separate file, PS3 only defines extn and doesn't use separate */
if (extn_offset && !name_offset) {
name_offset = extn_offset;
extn_offset = 0;
}
loop_flag = loop_end > 0;
start_offset = 0x00;
/* open external asset */
{
char asset_name[0x20]; /* "(8-byte crc).raw", "MU(6-byte crc).raw" */
if (extn_offset) {
sn = open_streamfile_by_ext(sf, "asset"); /* unknown real extension, based on debug strings */
if (!sn) {
vgm_logi("RAWI: external name '.asset' not found (put together)\n");
goto fail;
}
read_string(asset_name, sizeof(asset_name), extn_offset, sn);
}
else {
read_string(asset_name, sizeof(asset_name), name_offset, sf);
}
/* try to open external asset in various ways, since this format is a bit hard to use */
/* "(asset name)": plain as found */
if (!sb){
sb = open_streamfile_by_filename(sf, asset_name);
}
/* "sound/(asset name)": most common way to store files */
char path_name[256];
snprintf(path_name, sizeof(path_name), "sound/%s", asset_name);
if (!sb){
sb = open_streamfile_by_filename(sf, path_name);
}
/* "(header name).raw": for renamed files */
if (!sb){
sb = open_streamfile_by_ext(sf, "raw");
}
if (!sb) {
vgm_logi("RAWI: external file '%s' not found (put together)\n", asset_name);
goto fail;
}
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_RAWI;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end + 1;
switch(codec) {
case 0x00: /* Turbo Super Stunt Squad (Wii/3DS), Penguins of Madagascar (Wii/U/3DS) */
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
//vgmstream->interleave_last_block_size = ...; /* apparently padded */
/* etbl_offset defines N coef offset per channel (with external name, etbl_offset is ignored and offsets start at 0x00 in .asset instead)
* but in practice this seem fixed */
dsp_read_coefs(vgmstream, sf, 0x40, 0x30, big_endian);
dsp_read_hist(vgmstream, sf, 0x40 + 0x24, 0x30, big_endian);
break;
case 0x01: /* Falling Skies The Game (PC) */
vgmstream->coding_type = coding_PCM16BE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave; /* not 0x02 */
case 0x02: /* Falling Skies The Game (X360) */
vgmstream->coding_type = coding_PCM16BE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave; /* not 0x02 */
/* etbl_offset may set offsets to RIFF fmts per channel) */
break;
case 0x03: /* How to Train Your Dragon 2 (PS3), Falling Skies The Game (PS3) */
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
break;
case 0x05: /* Scooby Doo and the Spooky Swamp (DS) */
vgmstream->coding_type = coding_PCM8;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
break;
case 0x09: /* Turbo Super Stunt Squad (DS) */
vgmstream->coding_type = coding_MS_IMA;
vgmstream->layout_type = layout_none;
//vgmstream->interleave_block_size = interleave; /* unused? (mono) */
vgmstream->frame_size = 0x20;
break;
default:
vgm_logi("RAWI: unknown codec %x (report)\n", codec);
goto fail;
}
if (!vgmstream_open_stream(vgmstream, sb, start_offset))
goto fail;
close_streamfile(sb);
close_streamfile(sn);
return vgmstream;
fail:
close_streamfile(sb);
close_streamfile(sn);
close_vgmstream(vgmstream);
return NULL;
}