mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-21 08:43:40 +01:00
Merge pull request #1312 from bnnm/etc-fixes
- Fix MSVC Winamp text/path issues - Fix .fsbkey - Add FSB keys - Fix seek to 0 in non-libopus Opus - Cleanup
This commit is contained in:
commit
87034988dd
30
.github/uploader.py
vendored
30
.github/uploader.py
vendored
@ -22,6 +22,8 @@ import urllib.request, json, argparse, glob, subprocess, os
|
||||
#
|
||||
# API: https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28
|
||||
# https://docs.github.com/en/rest/releases/assets?apiVersion=2022-11-28
|
||||
#
|
||||
# Github's API has some limits but hopefully not reached by current token
|
||||
|
||||
RELEASE_TAG = 'nightly'
|
||||
# gives info about release (public)
|
||||
@ -32,6 +34,8 @@ URL_DELETE = 'https://api.github.com/repos/vgmstream/vgmstream-releases/releases
|
||||
URL_UPLOAD = 'https://uploads.github.com/repos/vgmstream/vgmstream-releases/releases/%s/assets?name=%s'
|
||||
# change release info
|
||||
URL_UPDATE = 'https://api.github.com/repos/vgmstream/vgmstream-releases/releases/%s'
|
||||
# gives info about last vgmstream tag
|
||||
URL_VGMSTREAM = 'https://api.github.com/repos/vgmstream/vgmstream/releases?per_page=1'
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
@ -40,6 +44,12 @@ def get_release():
|
||||
data = json.loads(contents)
|
||||
return data
|
||||
|
||||
def get_vgmstream_tag():
|
||||
# TODO could use local git tag
|
||||
contents = urllib.request.urlopen(URL_VGMSTREAM).read()
|
||||
data = json.loads(contents)
|
||||
return data[0]['tag_name']
|
||||
|
||||
def update_release(release, token, debug, body):
|
||||
release_id = release['id']
|
||||
|
||||
@ -117,7 +127,7 @@ def generate_changelog(release, token, debug):
|
||||
# writes in work dir and gets lines
|
||||
lines = changelog.main()
|
||||
|
||||
current_tag = 'r1810' #TODO get from some API maybe
|
||||
current_tag = get_vgmstream_tag()
|
||||
body = [
|
||||
'Automated releases ([full diffs here](https://github.com/vgmstream/vgmstream/compare/%s...master)).' % (current_tag),
|
||||
'',
|
||||
@ -159,17 +169,27 @@ def main(args):
|
||||
#if not files:
|
||||
# raise ValueError("no files found")
|
||||
|
||||
# shouldn't happen (points to non-existing files)
|
||||
if args.files and not files:
|
||||
raise ValueError("no files found, expected: %s" % (args.files))
|
||||
|
||||
# this token usually only exists in env on merges, but allow passing for tests
|
||||
token = args.token
|
||||
if not token:
|
||||
token = os.environ.get('UPLOADER_GITHUB_TOKEN')
|
||||
if not token:
|
||||
print("token not defined")
|
||||
raise ValueError("token not defined")
|
||||
|
||||
release = get_release()
|
||||
for file in files:
|
||||
delete_asset(release, token, args.debug, file)
|
||||
upload_asset(release, token, args.debug, file)
|
||||
print("handling %s files" % (len(files)))
|
||||
try:
|
||||
release = get_release()
|
||||
for file in files:
|
||||
delete_asset(release, token, args.debug, file)
|
||||
upload_asset(release, token, args.debug, file)
|
||||
except Exception as e:
|
||||
print("error during process: %s" % (e))
|
||||
raise ValueError("could't upload")
|
||||
|
||||
# this should be invoked separately so release doesn't change per artifact
|
||||
if args.changelog:
|
||||
|
1
.github/workflows/vs-win.yml
vendored
1
.github/workflows/vs-win.yml
vendored
@ -65,6 +65,7 @@ jobs:
|
||||
# uploads current assets to vgmstream-releases (token only works on merges)
|
||||
- name: Upload artifacts to vgmstream-releases
|
||||
if: github.event_name != 'pull_request'
|
||||
shell: cmd
|
||||
working-directory: ${{github.workspace}}
|
||||
env:
|
||||
UPLOADER_GITHUB_TOKEN: ${{ secrets.UPLOADER_GITHUB_TOKEN }}
|
||||
|
@ -63,6 +63,7 @@ def parse_args():
|
||||
ap.add_argument("-cn","--cli-new", help="sets name of new CLI (can be a path)")
|
||||
ap.add_argument("-co","--cli-old", help="sets name of old CLI (can be a path)")
|
||||
ap.add_argument("-m","--multiprocesses", help="uses N multiprocesses to compare for performance\n(note that pypy w/ single process is faster than multiprocesses)", type=int, default=1)
|
||||
ap.add_argument("-d","--diffs", help="compares input files directly (won't decode)", action='store_true')
|
||||
|
||||
args = ap.parse_args()
|
||||
|
||||
@ -385,10 +386,11 @@ class VrtsFiles:
|
||||
if not os.path.isfile(file):
|
||||
continue
|
||||
|
||||
# ignores non useful files
|
||||
_, ext = os.path.splitext(file)
|
||||
if ext.lower() in IGNORED_EXTENSIONS:
|
||||
continue
|
||||
# ignores non useful files, except on diffs mode that uses them directly
|
||||
if not self._args.diffs:
|
||||
_, ext = os.path.splitext(file)
|
||||
if ext.lower() in IGNORED_EXTENSIONS:
|
||||
continue
|
||||
|
||||
self.filenames.append(file)
|
||||
|
||||
@ -497,6 +499,9 @@ class VrtsApp:
|
||||
# - can be passed a dir or file for old/new
|
||||
# - old is optional in performance mode
|
||||
def _detect_cli(self):
|
||||
if self._args.diffs:
|
||||
return
|
||||
|
||||
cli = self._find_cli(self._args.cli_new, DEFAULT_CLI_NEW)
|
||||
if cli:
|
||||
self._cli_new = cli
|
||||
@ -626,10 +631,28 @@ class VrtsApp:
|
||||
pass
|
||||
self._temp_files = []
|
||||
|
||||
def _diffs(self):
|
||||
|
||||
files = self._files.filenames
|
||||
print(files)
|
||||
for i in range(len(files) - 1):
|
||||
curr = files[i]
|
||||
next = files[i+1]
|
||||
print(curr, next)
|
||||
|
||||
fuzzy = self._args.fuzzy
|
||||
cmp = VrtsComparator(curr, next, fuzzy_max=fuzzy, concurrency=self._args.multiprocesses)
|
||||
code = cmp.compare()
|
||||
|
||||
self._p.result(curr, code)
|
||||
|
||||
def start(self):
|
||||
self._detect_cli()
|
||||
self._files.prepare()
|
||||
if self._args.performance:
|
||||
|
||||
if self._args.diffs:
|
||||
self._diffs()
|
||||
elif self._args.performance:
|
||||
self._performance()
|
||||
else:
|
||||
self._compare()
|
||||
|
@ -778,10 +778,16 @@ static ffmpeg_codec_data* init_ffmpeg_custom_opus_config(STREAMFILE* sf, off_t s
|
||||
ffmpeg_data = init_ffmpeg_offset(temp_sf, 0x00, get_streamfile_size(temp_sf));
|
||||
if (!ffmpeg_data) goto fail;
|
||||
|
||||
/* FFmpeg + libopus: skips samples, notifies skip in codecCtx->delay (not in stream->skip_samples)
|
||||
* FFmpeg + opus: *doesn't* skip, also notifies skip in codecCtx->delay, hurray (possibly fixed in recent versions)
|
||||
* FFmpeg + opus is audibly buggy with some low bitrate SSB Ultimate files */
|
||||
//ffmpeg_set_skip_samples(ffmpeg_data, skip);
|
||||
/* FFmpeg + libopus: skips samples, notifies skip in codecCtx->delay/initial_padding (not in stream->skip_samples)
|
||||
* FFmpeg + opus: skip samples but loses them on reset/seek to 0, also notifies skip in codecCtx->delay/initial_padding */
|
||||
{
|
||||
/* quick fix for non-libopus (not sure how to detect better since both share AV_CODEC_ID_OPUS)*/
|
||||
const char* name = ffmpeg_get_codec_name(ffmpeg_data);
|
||||
if (name && (name[0] == 'O' || name[0] == 'o')) { /* "Opus" vs "libopus" */
|
||||
//ffmpeg_set_skip_samples(ffmpeg_data, cfg->skip); /* can't overwrite internal decoder skip */
|
||||
ffmpeg_set_force_seek(ffmpeg_data);
|
||||
}
|
||||
}
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
return ffmpeg_data;
|
||||
|
@ -25,7 +25,10 @@ VGMSTREAM* init_vgmstream_fsb_encrypted(STREAMFILE* sf) {
|
||||
uint8_t key[FSB_KEY_MAX];
|
||||
size_t key_size = read_key_file(key, FSB_KEY_MAX, sf);
|
||||
|
||||
test_fsbkey(sf, key, key_size, MODE_FSBS_ALL);
|
||||
if (key_size) {
|
||||
vgmstream = test_fsbkey(sf, key, key_size, MODE_FSBS_ALL);
|
||||
return vgmstream;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -65,22 +68,22 @@ static VGMSTREAM* test_fsbkey(STREAMFILE* sf, const uint8_t* key, size_t key_siz
|
||||
if (!vc && test_std) {
|
||||
temp_sf = setup_fsb_streamfile(sf, key, key_size, 0);
|
||||
if (!temp_sf) return NULL;
|
||||
//;dump_streamfile(temp_sf, 0);
|
||||
|
||||
if (!vc && test_fsb4) vc = init_vgmstream_fsb(temp_sf);
|
||||
if (!vc && test_fsb5) vc = init_vgmstream_fsb5(temp_sf);
|
||||
|
||||
//;if (vgmstream) dump_streamfile(temp_sf, 0);
|
||||
close_streamfile(temp_sf);
|
||||
}
|
||||
|
||||
if (!vc && test_alt) {
|
||||
temp_sf = setup_fsb_streamfile(sf, key, key_size, 1);
|
||||
if (!temp_sf) return NULL;
|
||||
//;dump_streamfile(temp_sf, 1);
|
||||
|
||||
if (!vc && test_fsb4) vc = init_vgmstream_fsb(temp_sf);
|
||||
if (!vc && test_fsb5) vc = init_vgmstream_fsb5(temp_sf);
|
||||
|
||||
//;if (vgmstream) dump_streamfile(temp_sf, 0);
|
||||
close_streamfile(temp_sf);
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,8 @@ static const fsbkey_info fsbkey_list[] = {
|
||||
{ MODE_FSB5_STD, FSBKEY_ADD("4FB8CC894515617939F4E1B7D50972D27213B8E6") }, // Cult of the Lamb Demo (PC)
|
||||
{ MODE_FSB5_STD, FSBKEY_ADD("X3EK%Bbga-%Y9HZZ%gkc*C512*$$DhRxWTGgjUG@=rUD") }, // Signalis (PC)
|
||||
{ MODE_FSB5_STD, FSBKEY_ADD("281ad163160cfc16f9a22c6755a64fad") }, // Ash Echoes beta (Android)
|
||||
|
||||
{ MODE_FSB5_STD, FSBKEY_ADD("Aurogon666") }, // Afterimage demo (PC)
|
||||
{ MODE_FSB5_STD, FSBKEY_ADD("IfYouLikeThosesSoundsWhyNotRenumerateTheir2Authors?") }, // Blanc (PC/Switch)
|
||||
};
|
||||
static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]);
|
||||
|
||||
|
469
src/meta/rfrm.c
469
src/meta/rfrm.c
@ -1,234 +1,235 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* RFTM - Retro Studios format [Metroid Prime Remastered] */
|
||||
VGMSTREAM *init_vgmstream_rfrm_mpr(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
off_t fmta_offset = 0, data_offset = 0, ras3_offset = 0, header_offset, start_offset;
|
||||
size_t data_size = 0, interleave;
|
||||
int loop_flag, channel_count;
|
||||
int loop_start, loop_end, padding;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "csmp"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, streamFile) != 0x5246524D) /* "RFRM" */
|
||||
goto fail;
|
||||
/* 0x08: file size but not exact */
|
||||
if (read_32bitBE(0x14, streamFile) != 0x43534D50) /* "CSMP" */
|
||||
goto fail;
|
||||
|
||||
if (read_32bitLE(0x18,streamFile) != 0x1F) /* assumed, also at 0x1c */
|
||||
goto fail;
|
||||
|
||||
|
||||
/* parse chunks (always BE) */
|
||||
{
|
||||
off_t chunk_offset = 0x20;
|
||||
off_t file_size = get_streamfile_size(streamFile);
|
||||
|
||||
while (chunk_offset < file_size) {
|
||||
uint32_t chunk_type = read_32bitBE(chunk_offset + 0x00,streamFile);
|
||||
size_t chunk_size = read_32bitLE(chunk_offset + 0x08,streamFile);
|
||||
|
||||
switch(chunk_type) {
|
||||
case 0x464D5441: /* "FMTA" */
|
||||
fmta_offset = chunk_offset + 0x18;
|
||||
chunk_offset += 5 + 0x18 + chunk_size;
|
||||
break;
|
||||
case 0x44415441: /* "DATA" */
|
||||
data_offset = chunk_offset + 0x18;
|
||||
data_size = read_32bitLE(chunk_offset + 0x04, streamFile);
|
||||
/* we're done here, DATA is the last chunk */
|
||||
chunk_offset = file_size;
|
||||
break;
|
||||
case 0x52415333: /* "RAS3" */
|
||||
ras3_offset = chunk_offset + 0x18;
|
||||
chunk_offset += 60;
|
||||
break;
|
||||
case 0x43524D53: /* CRMS */
|
||||
chunk_offset += 9 + 0x18 + chunk_size + read_32bitLE(chunk_offset + 0x18 + chunk_size + 5, streamFile);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fmta_offset || !data_offset || !data_size)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* parse FMTA / DATA (fully interleaved standard DSPs) */
|
||||
channel_count = read_8bit(fmta_offset + 0x00, streamFile);
|
||||
/* FMTA 0x08: channel mapping */
|
||||
|
||||
header_offset = data_offset;
|
||||
start_offset = header_offset + 0x80 * channel_count;
|
||||
loop_flag = read_16bitLE(header_offset + 0x0C, streamFile);
|
||||
interleave = data_size / channel_count;
|
||||
|
||||
if (ras3_offset) {
|
||||
int block_size = read_32bitLE(ras3_offset + 0x00, streamFile);
|
||||
int block_samples = read_32bitLE(ras3_offset + 0x8, streamFile);
|
||||
int loop_start_block = read_32bitLE(ras3_offset + 0x14, streamFile);
|
||||
int loop_start_sample = read_32bitLE(ras3_offset + 0x18, streamFile);
|
||||
int loop_end_block = read_32bitLE(ras3_offset + 0x1C, streamFile);
|
||||
int loop_end_sample = read_32bitLE(ras3_offset + 0x20, streamFile);
|
||||
padding = read_32bitLE(ras3_offset + 0x0C, streamFile);
|
||||
|
||||
loop_start = loop_start_block * block_samples + loop_start_sample - padding;
|
||||
loop_end = loop_end_block * block_samples + loop_end_sample - padding;
|
||||
if ((loop_start || loop_end) && (loop_start < loop_end))
|
||||
loop_flag = 1;
|
||||
|
||||
interleave = block_size / channel_count;
|
||||
} else {
|
||||
loop_start = dsp_nibbles_to_samples(read_32bitLE(header_offset + 0x10, streamFile));
|
||||
loop_end = dsp_nibbles_to_samples(read_32bitLE(header_offset + 0x14, streamFile)) + 1;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RFRM;
|
||||
vgmstream->sample_rate = read_32bitLE(header_offset + 0x08, streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(header_offset + 0x00, streamFile);
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
if (ras3_offset) {
|
||||
int padding_bytes = padding / 14 * 8; /* round to frames */
|
||||
vgmstream->interleave_first_block_size = interleave - padding_bytes;
|
||||
vgmstream->interleave_first_skip = padding_bytes;
|
||||
start_offset += padding_bytes;
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
dsp_read_coefs(vgmstream, streamFile, header_offset + 0x1C, 0x80, 0);
|
||||
dsp_read_hist (vgmstream, streamFile, header_offset + 0x40, 0x80, 0);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* RFTM - Retro Studios format [Donkey Kong Country Tropical Freeze (WiiU/Switch)] */
|
||||
VGMSTREAM *init_vgmstream_rfrm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
off_t fmta_offset = 0, data_offset = 0, header_offset, start_offset;
|
||||
size_t data_size = 0, interleave;
|
||||
int loop_flag, channel_count, version;
|
||||
int big_endian;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "csmp"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, streamFile) != 0x5246524D) /* "RFRM" */
|
||||
goto fail;
|
||||
/* 0x08: file size but not exact */
|
||||
if (read_32bitBE(0x14, streamFile) != 0x43534D50) /* "CSMP" */
|
||||
goto fail;
|
||||
version = read_32bitBE(0x18,streamFile); /* assumed, also at 0x1c */
|
||||
|
||||
if (version == 0x0a) { /* Wii U */
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
big_endian = 1;
|
||||
}
|
||||
else if (version == 0x12) { /* Switch */
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
big_endian = 0;
|
||||
}
|
||||
else if (version == 0x1F000000) { /* Metroid Prime Remastered */
|
||||
return init_vgmstream_rfrm_mpr(streamFile);
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* parse chunks (always BE) */
|
||||
{
|
||||
off_t chunk_offset = 0x20;
|
||||
off_t file_size = get_streamfile_size(streamFile);
|
||||
|
||||
while (chunk_offset < file_size) {
|
||||
uint32_t chunk_type = read_32bitBE(chunk_offset+0x00,streamFile);
|
||||
size_t chunk_size = read_32bitBE(chunk_offset+0x08,streamFile); /* maybe 64b from 0x04? */
|
||||
|
||||
switch(chunk_type) {
|
||||
case 0x464D5441: /* "FMTA" */
|
||||
fmta_offset = chunk_offset + 0x18;
|
||||
break;
|
||||
case 0x44415441: /* "DATA" */
|
||||
data_offset = chunk_offset + 0x18;
|
||||
data_size = chunk_size;
|
||||
break;
|
||||
default: /* known: "LABL" (usually before "FMTA"), "META" (usually after "DATA") */
|
||||
break;
|
||||
}
|
||||
|
||||
chunk_offset += 0x18 + chunk_size;
|
||||
}
|
||||
|
||||
if (!fmta_offset || !data_offset || !data_size)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* parse FMTA / DATA (fully interleaved standard DSPs) */
|
||||
channel_count = read_8bit(fmta_offset+0x00, streamFile);
|
||||
/* FMTA 0x08: channel mapping */
|
||||
|
||||
header_offset = data_offset;
|
||||
if (version == 0x0a) {
|
||||
size_t align = 0x03; /* possibly 32b align */
|
||||
header_offset += align;
|
||||
data_size -= align;
|
||||
}
|
||||
start_offset = header_offset + 0x60;
|
||||
loop_flag = read_16bit(header_offset + 0x0C, streamFile);
|
||||
interleave = data_size / channel_count;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RFRM;
|
||||
vgmstream->sample_rate = read_32bit(header_offset + 0x08, streamFile);
|
||||
vgmstream->num_samples = read_32bit(header_offset + 0x00, streamFile);
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bit(header_offset + 0x10, streamFile));
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bit(header_offset + 0x14, streamFile)) + 1;
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
dsp_read_coefs(vgmstream, streamFile, header_offset + 0x1C, interleave, big_endian);
|
||||
dsp_read_hist (vgmstream, streamFile, header_offset + 0x40, interleave, big_endian);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* RFTM - Retro Studios format [Metroid Prime Remastered] */
|
||||
static VGMSTREAM* init_vgmstream_rfrm_mpr(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t fmta_offset = 0, data_offset = 0, ras3_offset = 0, header_offset, start_offset;
|
||||
size_t data_size = 0, interleave;
|
||||
int loop_flag, channels;
|
||||
int loop_start, loop_end, padding;
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00, sf, "RFRM"))
|
||||
goto fail;
|
||||
/* 0x08: file size but not exact */
|
||||
if (!is_id32be(0x14, sf, "CSMP"))
|
||||
goto fail;
|
||||
|
||||
if (!check_extensions(sf, "csmp"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitLE(0x18,sf) != 0x1F) /* assumed, also at 0x1c */
|
||||
goto fail;
|
||||
|
||||
|
||||
/* parse chunks (always BE) */
|
||||
{
|
||||
off_t chunk_offset = 0x20;
|
||||
off_t file_size = get_streamfile_size(sf);
|
||||
|
||||
while (chunk_offset < file_size) {
|
||||
uint32_t chunk_type = read_32bitBE(chunk_offset + 0x00,sf);
|
||||
size_t chunk_size = read_32bitLE(chunk_offset + 0x08,sf);
|
||||
|
||||
switch(chunk_type) {
|
||||
case 0x464D5441: /* "FMTA" */
|
||||
fmta_offset = chunk_offset + 0x18;
|
||||
chunk_offset += 5 + 0x18 + chunk_size;
|
||||
break;
|
||||
case 0x44415441: /* "DATA" */
|
||||
data_offset = chunk_offset + 0x18;
|
||||
data_size = read_32bitLE(chunk_offset + 0x04, sf);
|
||||
/* we're done here, DATA is the last chunk */
|
||||
chunk_offset = file_size;
|
||||
break;
|
||||
case 0x52415333: /* "RAS3" */
|
||||
ras3_offset = chunk_offset + 0x18;
|
||||
chunk_offset += 60;
|
||||
break;
|
||||
case 0x43524D53: /* CRMS */
|
||||
chunk_offset += 9 + 0x18 + chunk_size + read_32bitLE(chunk_offset + 0x18 + chunk_size + 5, sf);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fmta_offset || !data_offset || !data_size)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* parse FMTA / DATA (fully interleaved standard DSPs) */
|
||||
channels = read_8bit(fmta_offset + 0x00, sf);
|
||||
if (channels == 0) goto fail; /* div by zero */
|
||||
/* FMTA 0x08: channel mapping */
|
||||
|
||||
header_offset = data_offset;
|
||||
start_offset = header_offset + 0x80 * channels;
|
||||
loop_flag = read_16bitLE(header_offset + 0x0C, sf);
|
||||
interleave = data_size / channels;
|
||||
|
||||
if (ras3_offset) {
|
||||
int block_size = read_32bitLE(ras3_offset + 0x00, sf);
|
||||
int block_samples = read_32bitLE(ras3_offset + 0x8, sf);
|
||||
int loop_start_block = read_32bitLE(ras3_offset + 0x14, sf);
|
||||
int loop_start_sample = read_32bitLE(ras3_offset + 0x18, sf);
|
||||
int loop_end_block = read_32bitLE(ras3_offset + 0x1C, sf);
|
||||
int loop_end_sample = read_32bitLE(ras3_offset + 0x20, sf);
|
||||
padding = read_32bitLE(ras3_offset + 0x0C, sf);
|
||||
|
||||
loop_start = loop_start_block * block_samples + loop_start_sample - padding;
|
||||
loop_end = loop_end_block * block_samples + loop_end_sample - padding;
|
||||
if ((loop_start || loop_end) && (loop_start < loop_end))
|
||||
loop_flag = 1;
|
||||
|
||||
interleave = block_size / channels;
|
||||
} else {
|
||||
loop_start = dsp_nibbles_to_samples(read_32bitLE(header_offset + 0x10, sf));
|
||||
loop_end = dsp_nibbles_to_samples(read_32bitLE(header_offset + 0x14, sf)) + 1;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RFRM;
|
||||
vgmstream->sample_rate = read_32bitLE(header_offset + 0x08, sf);
|
||||
vgmstream->num_samples = read_32bitLE(header_offset + 0x00, sf);
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
if (ras3_offset) {
|
||||
int padding_bytes = padding / 14 * 8; /* round to frames */
|
||||
vgmstream->interleave_first_block_size = interleave - padding_bytes;
|
||||
vgmstream->interleave_first_skip = padding_bytes;
|
||||
start_offset += padding_bytes;
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
dsp_read_coefs(vgmstream, sf, header_offset + 0x1C, 0x80, 0);
|
||||
dsp_read_hist (vgmstream, sf, header_offset + 0x40, 0x80, 0);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* RFTM - Retro Studios format [Donkey Kong Country Tropical Freeze (WiiU/Switch)] */
|
||||
VGMSTREAM* init_vgmstream_rfrm(STREAMFILE* sf) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
off_t fmta_offset = 0, data_offset = 0, header_offset, start_offset;
|
||||
size_t data_size = 0, interleave;
|
||||
int loop_flag, channels, version;
|
||||
int big_endian;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00, sf, "RFRM"))
|
||||
goto fail;
|
||||
/* 0x08: file size but not exact */
|
||||
if (!is_id32be(0x14, sf, "CSMP"))
|
||||
goto fail;
|
||||
|
||||
if (!check_extensions(sf, "csmp"))
|
||||
goto fail;
|
||||
|
||||
version = read_32bitBE(0x18,sf); /* assumed, also at 0x1c */
|
||||
if (version == 0x0a) { /* Wii U */
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
big_endian = 1;
|
||||
}
|
||||
else if (version == 0x12) { /* Switch */
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
big_endian = 0;
|
||||
}
|
||||
else if (version == 0x1F000000) { /* Metroid Prime Remastered */
|
||||
return init_vgmstream_rfrm_mpr(sf);
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* parse chunks (always BE) */
|
||||
{
|
||||
off_t chunk_offset = 0x20;
|
||||
off_t file_size = get_streamfile_size(sf);
|
||||
|
||||
while (chunk_offset < file_size) {
|
||||
uint32_t chunk_type = read_32bitBE(chunk_offset+0x00,sf);
|
||||
size_t chunk_size = read_32bitBE(chunk_offset+0x08,sf); /* maybe 64b from 0x04? */
|
||||
|
||||
switch(chunk_type) {
|
||||
case 0x464D5441: /* "FMTA" */
|
||||
fmta_offset = chunk_offset + 0x18;
|
||||
break;
|
||||
case 0x44415441: /* "DATA" */
|
||||
data_offset = chunk_offset + 0x18;
|
||||
data_size = chunk_size;
|
||||
break;
|
||||
default: /* known: "LABL" (usually before "FMTA"), "META" (usually after "DATA") */
|
||||
break;
|
||||
}
|
||||
|
||||
chunk_offset += 0x18 + chunk_size;
|
||||
}
|
||||
|
||||
if (!fmta_offset || !data_offset || !data_size)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* parse FMTA / DATA (fully interleaved standard DSPs) */
|
||||
channels = read_8bit(fmta_offset+0x00, sf);
|
||||
/* FMTA 0x08: channel mapping */
|
||||
|
||||
header_offset = data_offset;
|
||||
if (version == 0x0a) {
|
||||
size_t align = 0x03; /* possibly 32b align */
|
||||
header_offset += align;
|
||||
data_size -= align;
|
||||
}
|
||||
start_offset = header_offset + 0x60;
|
||||
loop_flag = read_16bit(header_offset + 0x0C, sf);
|
||||
interleave = data_size / channels;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RFRM;
|
||||
vgmstream->sample_rate = read_32bit(header_offset + 0x08, sf);
|
||||
vgmstream->num_samples = read_32bit(header_offset + 0x00, sf);
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bit(header_offset + 0x10, sf));
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bit(header_offset + 0x14, sf)) + 1;
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
dsp_read_coefs(vgmstream, sf, header_offset + 0x1C, interleave, big_endian);
|
||||
dsp_read_hist (vgmstream, sf, header_offset + 0x40, interleave, big_endian);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
@ -52,7 +52,7 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(VCmdAdditionalIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;$(VWmpPreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;VGM_WINAMP_UNICODE;$(VWmpPreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
Loading…
x
Reference in New Issue
Block a user