mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 09:40:51 +01:00
Merge pull request #1357 from bnnm/csmp-cleanup
- Fix .CSMP loops [Metroid Prime Trilogy (Wii)] - Add .opu extension [Ys Memoire: The Oath in Felghana (Switch)] - Fix some MUSX loops - internal cleanup - vrts: add report-diffs option
This commit is contained in:
commit
c0e8fa4a4a
@ -16,7 +16,7 @@
|
||||
|
||||
extern "C" {
|
||||
#include "../src/vgmstream.h"
|
||||
#include "../src/plugins.h"
|
||||
#include "../src/api.h"
|
||||
}
|
||||
#include "plugin.h"
|
||||
#include "vfs.h"
|
||||
|
@ -52,8 +52,7 @@ def parse_args():
|
||||
ap.add_argument("-r","--recursive", help="search files in subfolders", action='store_true')
|
||||
ap.add_argument("-z","--fuzzy", help="fuzzy threshold of +-N PCM16LE", type=int, default=1)
|
||||
ap.add_argument("-nd","--no-delete", help="don't delete output", action='store_true')
|
||||
ap.add_argument("-rd","--result-diffs", help="only report full diffs", action='store_true')
|
||||
ap.add_argument("-rz","--result-fuzzy", help="only report full and fuzzy diffs", action='store_true')
|
||||
ap.add_argument("-rd","--report-diffs", help="only report full diffs", action='store_true')
|
||||
ap.add_argument("-p","--performance-both", help="compare decode performance", action='store_true')
|
||||
ap.add_argument("-pn","--performance-new", help="test performance of new CLI", action='store_true')
|
||||
ap.add_argument("-po","--performance-old", help="test performance of old CLI", action='store_true')
|
||||
@ -335,7 +334,15 @@ class VrtsPrinter:
|
||||
RESULT_MISSING_OLD: 'missing old',
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
REPORTS_DIFFS = [
|
||||
#RESULT_NONE,
|
||||
RESULT_SIZES,
|
||||
RESULT_MISSING_NEW,
|
||||
RESULT_MISSING_OLD
|
||||
]
|
||||
|
||||
def __init__(self, args):
|
||||
self._args = args
|
||||
try:
|
||||
os.system('color') #win only?
|
||||
except:
|
||||
@ -347,7 +354,7 @@ class VrtsPrinter:
|
||||
else:
|
||||
print(msg)
|
||||
|
||||
|
||||
|
||||
def result(self, msg, code, fuzzy_diff=0, fuzzy_offset=0):
|
||||
text = self.TEXT_RESULT.get(code)
|
||||
color = self.COLOR_RESULT.get(code)
|
||||
@ -356,7 +363,13 @@ class VrtsPrinter:
|
||||
msg = "%s: %s" % (msg, text)
|
||||
if fuzzy_diff != 0:
|
||||
msg += " (%s @0x%x)" % (fuzzy_diff, fuzzy_offset)
|
||||
self._print(msg, color)
|
||||
|
||||
report = True
|
||||
if self._args.report_diffs and code not in self.REPORTS_DIFFS:
|
||||
report = False
|
||||
|
||||
if report:
|
||||
self._print(msg, color)
|
||||
|
||||
|
||||
def info(self, msg):
|
||||
@ -471,7 +484,7 @@ class VrtsApp:
|
||||
self._args = args
|
||||
self._files = VrtsFiles(args)
|
||||
self._prc = VrtsProcess()
|
||||
self._p = VrtsPrinter()
|
||||
self._p = VrtsPrinter(args)
|
||||
self._cli_new = None
|
||||
self._cli_old = None
|
||||
self._temp_files = []
|
||||
|
@ -38,7 +38,7 @@
|
||||
#endif
|
||||
|
||||
#include "../src/vgmstream.h"
|
||||
#include "../src/plugins.h"
|
||||
#include "../src/api.h"
|
||||
#include "../src/util/samples_ops.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <getopt.h>
|
||||
#include "../src/vgmstream.h"
|
||||
#include "../src/plugins.h"
|
||||
#include "../src/api.h"
|
||||
#include "../src/util.h"
|
||||
#include "../src/util/samples_ops.h"
|
||||
//todo use <>?
|
||||
|
@ -10,7 +10,7 @@ vgmstream can be compiled using one of several build scripts that are available
|
||||
|
||||
Because each module has different quirks one can't use a single tool for everything. You should be able to build most using a standard *compiler* (GCC/MSVC/Clang) using common *build systems* (scripts/CMake/autotools) in any typical *OS* (Windows/Linux/macOS).
|
||||
|
||||
64-bit support should work but hasn't been throughly tested (may have subtle decoding bugs in some codecs), since most used components are plugins for 32-bit players. Windows libraries for extra codecs are included for 32-bit only at the moment.
|
||||
64-bit support should work but hasn't been as throughly tested, since most used components are plugins for 32-bit players. Windows libraries for extra codecs are included for 32-bit only at the moment.
|
||||
|
||||
Though it's rather flexible (like using Windows with GCC and autotools), some combos may be a bit more complex to get working depending on your system and other factors.
|
||||
|
||||
|
@ -122,7 +122,7 @@ Very simplified it goes like this:
|
||||
- layout prepares samples and offsets to read from the stream *[render_vgmstream_(layout)]*
|
||||
- decoder reads and decodes bytes into PCM samples *[decode_vgmstream_(coding)]*
|
||||
- player plays those samples, asks to fill sample buffer again, repeats (until total_samples)
|
||||
- layout moves offsets back to loop_start when loop_end is reached *[vgmstream_do_loop]*
|
||||
- layout moves offsets back to loop_start when loop_end is reached *[decode_do_loop]*
|
||||
- player closes the VGMSTREAM once the stream is finished
|
||||
|
||||
vgsmtream's main code (located in src) may be considered "libvgmstream", and plugins interface it through vgmstream.h, mainly the part commented as "vgmstream public API". There isn't a clean external API at the moment, this may be improved later.
|
||||
@ -201,10 +201,10 @@ If the decoder needs to keep state between calls it may use the VGMSTREAM for co
|
||||
Adding a new decoder involves:
|
||||
- *src/coding/(decoder-name).c*: create `decode_x` function that decodes stream data into the passed sample buffer. If the codec requires custom internals it may need `init/reset/seek/free_x`, or other helper functions.
|
||||
- *src/coding/coding.h*: define decoder's functions and type
|
||||
- *src/decode.c: get_vgmstream_samples_per_frame*: define so vgmstream only asks for N samples per decode_x call. May return 0 if variable/unknown/etc (decoder then must handle arbitrary number of samples)
|
||||
- *src/decode.c: get_vgmstream_frame_size*: define so vgmstream can do certain internal calculations. May return 0 if variable/unknown/etc, but blocked/interleave layouts will need to be used in a certain way.
|
||||
- *src/decode.c: decode_get_samples_per_frame*: define so vgmstream only asks for N samples per decode_x call. May return 0 if variable/unknown/etc (decoder then must handle arbitrary number of samples)
|
||||
- *src/decode.c: decode_get_frame_size*: define so vgmstream can do certain internal calculations. May return 0 if variable/unknown/etc, but blocked/interleave layouts will need to be used in a certain way.
|
||||
- *src/decode.c: decode_vgmstream*: call `decode_x`, possibly once per channel if the decoder works with a channel at a time.
|
||||
- *src/decode.c: add handling in `reset/seek/free_codec` if needed
|
||||
- *src/decode.c: add handling in `reset/seek/decode_free` if needed
|
||||
- *src/formats.c*: add coding type description
|
||||
- *src/libvgmstream.vcproj/vcxproj/filters*: add to compile new (decoder-name).c parser in VS
|
||||
- if the codec depends on a external library don't forget to mark parts with: *#ifdef VGM_USE_X ... #endif*
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
extern "C" {
|
||||
#include "../src/vgmstream.h"
|
||||
#include "../src/plugins.h"
|
||||
#include "../src/api.h"
|
||||
}
|
||||
#include "foo_vgmstream.h"
|
||||
#include "foo_filetypes.h"
|
||||
|
@ -270,8 +270,18 @@ function MakePackage
|
||||
Copy-Item $fb2kFiles32 bin/foobar2000/ -Recurse -Force
|
||||
Copy-Item $fb2kFiles64 bin/foobar2000/x64/ -Recurse -Force
|
||||
Remove-Item $fb2kFiles_remove -ErrorAction Ignore
|
||||
Compress-Archive -Path bin/foobar2000/* bin/foo_input_vgmstream.zip -Force
|
||||
Move-Item bin/foo_input_vgmstream.zip bin/foo_input_vgmstream.fb2k-component -Force
|
||||
|
||||
# workaround for a foobar 2.0 64-bit bug: (earlier?) powershell creates zip paths with '\' (which seem
|
||||
# non-standard), and apparently that confuses foobar when trying to unpack the zip
|
||||
try {
|
||||
# possibly available in github actions
|
||||
& '7z' a -tzip bin/foo_input_vgmstream.fb2k-component bin/foobar2000/*
|
||||
} catch {
|
||||
# works for 32-bit at least
|
||||
Compress-Archive -Path bin/foobar2000/* bin/foo_input_vgmstream.zip -Force
|
||||
Move-Item bin/foo_input_vgmstream.zip bin/foo_input_vgmstream.fb2k-component -Force
|
||||
}
|
||||
|
||||
Remove-Item -Path bin/foobar2000 -Recurse -ErrorAction Ignore
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
//possible future public/opaque API
|
||||
#ifndef _API_H_
|
||||
#define _API_H_
|
||||
|
||||
#include "base/plugins.h"
|
||||
|
||||
|
||||
//possible future public/opaque API
|
||||
#if 0
|
||||
|
||||
#include <stdint.h>
|
||||
|
@ -1,14 +1,14 @@
|
||||
#include "vgmstream.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "decode.h"
|
||||
#include "layout/layout.h"
|
||||
#include "coding/coding.h"
|
||||
#include "mixing.h"
|
||||
#include "plugins.h"
|
||||
|
||||
/* custom codec handling, not exactly "decode" stuff but here to simplify adding new codecs */
|
||||
|
||||
|
||||
void free_codec(VGMSTREAM* vgmstream) {
|
||||
void decode_free(VGMSTREAM* vgmstream) {
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
if (vgmstream->coding_type == coding_OGG_VORBIS) {
|
||||
@ -119,7 +119,7 @@ void free_codec(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
|
||||
|
||||
void seek_codec(VGMSTREAM* vgmstream) {
|
||||
void decode_seek(VGMSTREAM* vgmstream) {
|
||||
if (vgmstream->coding_type == coding_CIRCUS_VQ) {
|
||||
seek_circus_vq(vgmstream->codec_data, vgmstream->loop_current_sample);
|
||||
}
|
||||
@ -213,7 +213,7 @@ void seek_codec(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
|
||||
|
||||
void reset_codec(VGMSTREAM* vgmstream) {
|
||||
void decode_reset(VGMSTREAM* vgmstream) {
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
if (vgmstream->coding_type == coding_OGG_VORBIS) {
|
||||
@ -325,7 +325,7 @@ void reset_codec(VGMSTREAM* vgmstream) {
|
||||
|
||||
|
||||
/* Get the number of samples of a single frame (smallest self-contained sample group, 1/N channels) */
|
||||
int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
|
||||
int decode_get_samples_per_frame(VGMSTREAM* vgmstream) {
|
||||
/* Value returned here is the max (or less) that vgmstream will ask a decoder per
|
||||
* "decode_x" call. Decoders with variable samples per frame or internal discard
|
||||
* may return 0 here and handle arbitrary samples_to_do values internally
|
||||
@ -555,7 +555,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
|
||||
/* Get the number of bytes of a single frame (smallest self-contained byte group, 1/N channels) */
|
||||
int get_vgmstream_frame_size(VGMSTREAM* vgmstream) {
|
||||
int decode_get_frame_size(VGMSTREAM* vgmstream) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_SILENCE:
|
||||
return 0;
|
||||
@ -747,21 +747,21 @@ int get_vgmstream_frame_size(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
|
||||
/* In NDS IMA the frame size is the block size, so the last one is short */
|
||||
int get_vgmstream_samples_per_shortframe(VGMSTREAM* vgmstream) {
|
||||
int decode_get_samples_per_shortframe(VGMSTREAM* vgmstream) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_NDS_IMA:
|
||||
return (vgmstream->interleave_last_block_size-4)*2;
|
||||
default:
|
||||
return get_vgmstream_samples_per_frame(vgmstream);
|
||||
return decode_get_samples_per_frame(vgmstream);
|
||||
}
|
||||
}
|
||||
|
||||
int get_vgmstream_shortframe_size(VGMSTREAM* vgmstream) {
|
||||
int decode_get_shortframe_size(VGMSTREAM* vgmstream) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_NDS_IMA:
|
||||
return vgmstream->interleave_last_block_size;
|
||||
default:
|
||||
return get_vgmstream_frame_size(vgmstream);
|
||||
return decode_get_frame_size(vgmstream);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1488,7 +1488,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
|
||||
|
||||
/* Calculate number of consecutive samples we can decode. Takes into account hitting
|
||||
* a loop start or end, or going past a single frame. */
|
||||
int get_vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM* vgmstream) {
|
||||
int decode_get_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM* vgmstream) {
|
||||
int samples_to_do;
|
||||
int samples_left_this_block;
|
||||
|
||||
@ -1521,7 +1521,7 @@ int get_vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, V
|
||||
|
||||
/* Detect loop start and save values, or detect loop end and restore (loop back).
|
||||
* Returns 1 if loop was done. */
|
||||
int vgmstream_do_loop(VGMSTREAM* vgmstream) {
|
||||
int decode_do_loop(VGMSTREAM* vgmstream) {
|
||||
/*if (!vgmstream->loop_flag) return 0;*/
|
||||
|
||||
/* is this the loop end? = new loop, continue from loop_start_sample */
|
||||
@ -1557,7 +1557,7 @@ int vgmstream_do_loop(VGMSTREAM* vgmstream) {
|
||||
* - loop_ch[] is copied to ch[] (with custom value)
|
||||
* - then codec will use ch[]'s offset
|
||||
* regular codecs may use copied loop_ch[] offset without issue */
|
||||
seek_codec(vgmstream);
|
||||
decode_seek(vgmstream);
|
||||
|
||||
/* restore! */
|
||||
memcpy(vgmstream->ch, vgmstream->loop_ch, sizeof(VGMSTREAMCHANNEL) * vgmstream->channels);
|
@ -1,32 +1,32 @@
|
||||
#ifndef _DECODE_H
|
||||
#define _DECODE_H
|
||||
|
||||
#include "vgmstream.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
void free_codec(VGMSTREAM* vgmstream);
|
||||
void seek_codec(VGMSTREAM* vgmstream);
|
||||
void reset_codec(VGMSTREAM* vgmstream);
|
||||
void decode_free(VGMSTREAM* vgmstream);
|
||||
void decode_seek(VGMSTREAM* vgmstream);
|
||||
void decode_reset(VGMSTREAM* vgmstream);
|
||||
|
||||
/* Decode samples into the buffer. Assume that we have written samples_written into the
|
||||
* buffer already, and we have samples_to_do consecutive samples ahead of us. */
|
||||
void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_do, sample_t* buffer);
|
||||
|
||||
/* Detect loop start and save values, or detect loop end and restore (loop back). Returns 1 if loop was done. */
|
||||
int vgmstream_do_loop(VGMSTREAM* vgmstream);
|
||||
int decode_do_loop(VGMSTREAM* vgmstream);
|
||||
|
||||
/* Calculate number of consecutive samples to do (taking into account stopping for loop start and end) */
|
||||
int get_vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM* vgmstream);
|
||||
int decode_get_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM* vgmstream);
|
||||
|
||||
|
||||
/* Get the number of samples of a single frame (smallest self-contained sample group, 1/N channels) */
|
||||
int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream);
|
||||
int decode_get_samples_per_frame(VGMSTREAM* vgmstream);
|
||||
|
||||
/* Get the number of bytes of a single frame (smallest self-contained byte group, 1/N channels) */
|
||||
int get_vgmstream_frame_size(VGMSTREAM* vgmstream);
|
||||
int decode_get_frame_size(VGMSTREAM* vgmstream);
|
||||
|
||||
/* In NDS IMA the frame size is the block size, but last one is shorter */
|
||||
int get_vgmstream_samples_per_shortframe(VGMSTREAM* vgmstream);
|
||||
int get_vgmstream_shortframe_size(VGMSTREAM* vgmstream);
|
||||
int decode_get_samples_per_shortframe(VGMSTREAM* vgmstream);
|
||||
int decode_get_shortframe_size(VGMSTREAM* vgmstream);
|
||||
|
||||
|
||||
#endif
|
@ -1,7 +1,7 @@
|
||||
#include <ctype.h>
|
||||
#include "../vgmstream.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../mixing.h"
|
||||
#include "mixing.h"
|
||||
#include "../util/channel_mappings.h"
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "vgmstream.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../util/channel_mappings.h"
|
||||
#include "mixing.h"
|
||||
#include "plugins.h"
|
||||
#include "util/channel_mappings.h"
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef _MIXING_H_
|
||||
#define _MIXING_H_
|
||||
|
||||
#include "vgmstream.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* Applies mixing commands to the sample buffer. Mixing must be externally enabled and
|
||||
* outbuf must big enough to hold output_channels*samples_to_do */
|
@ -1,7 +1,9 @@
|
||||
#include "vgmstream.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../util/log.h"
|
||||
#include "../util/reader_sf.h"
|
||||
#include "../util/reader_text.h"
|
||||
#include "plugins.h"
|
||||
#include "mixing.h"
|
||||
#include "util/log.h"
|
||||
|
||||
|
||||
/* ****************************************** */
|
@ -4,8 +4,8 @@
|
||||
#ifndef _PLUGINS_H_
|
||||
#define _PLUGINS_H_
|
||||
|
||||
#include "streamfile.h"
|
||||
#include "vgmstream.h"
|
||||
#include "../streamfile.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
|
||||
/* ****************************************** */
|
@ -1,5 +1,5 @@
|
||||
#include "vgmstream.h"
|
||||
#include "layout/layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "render.h"
|
||||
#include "decode.h"
|
||||
#include "mixing.h"
|
||||
@ -222,7 +222,7 @@ void setup_state_vgmstream(VGMSTREAM* vgmstream) {
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void free_layout(VGMSTREAM* vgmstream) {
|
||||
void render_free(VGMSTREAM* vgmstream) {
|
||||
|
||||
if (vgmstream->layout_type == layout_segmented) {
|
||||
free_layout_segmented(vgmstream->layout_data);
|
||||
@ -233,7 +233,7 @@ void free_layout(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
}
|
||||
|
||||
void reset_layout(VGMSTREAM* vgmstream) {
|
||||
void render_reset(VGMSTREAM* vgmstream) {
|
||||
|
||||
if (vgmstream->layout_type == layout_segmented) {
|
||||
reset_layout_segmented(vgmstream->layout_data);
|
@ -1,10 +1,10 @@
|
||||
#ifndef _RENDER_H
|
||||
#define _RENDER_H
|
||||
|
||||
#include "vgmstream.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
void free_layout(VGMSTREAM* vgmstream);
|
||||
void reset_layout(VGMSTREAM* vgmstream);
|
||||
void render_free(VGMSTREAM* vgmstream);
|
||||
void render_reset(VGMSTREAM* vgmstream);
|
||||
int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstream);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "vgmstream.h"
|
||||
#include "layout/layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "render.h"
|
||||
#include "decode.h"
|
||||
#include "mixing.h"
|
||||
@ -14,7 +14,7 @@ static void seek_force_loop(VGMSTREAM* vgmstream, int loop_count) {
|
||||
/* pretend decoder reached loop end so state is set to loop start */
|
||||
vgmstream->loop_count = loop_count - 1; /* seeking to first loop must become ++ > 0 */
|
||||
vgmstream->current_sample = vgmstream->loop_end_sample;
|
||||
vgmstream_do_loop(vgmstream);
|
||||
decode_do_loop(vgmstream);
|
||||
}
|
||||
|
||||
static void seek_force_decode(VGMSTREAM* vgmstream, int samples) {
|
@ -2,6 +2,7 @@
|
||||
#define _CODING_H
|
||||
|
||||
#include "../vgmstream.h"
|
||||
#include "../util/reader_sf.h"
|
||||
#include "../util/reader_get_nibbles.h"
|
||||
//todo remove
|
||||
#include "hca_decoder_clhca.h"
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "coding.h"
|
||||
#include "../util/channel_mappings.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
|
||||
|
@ -1317,9 +1317,11 @@ size_t xbox_ima_bytes_to_samples(size_t bytes, int channels) {
|
||||
size_t dat4_ima_bytes_to_samples(size_t bytes, int channels) {
|
||||
int block_align = 0x20 * channels;
|
||||
if (channels <= 0) return 0;
|
||||
|
||||
int mod = bytes % block_align;
|
||||
/* DAT4 IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
|
||||
return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels
|
||||
+ ((bytes % block_align) ? ((bytes % block_align) - 4 * channels) * 2 / channels : 0); /* unlikely (encoder aligns) */
|
||||
+ ((mod > 0 && mod > 0x04*channels) ? (mod - 0x04*channels) * 2 / channels : 0); /* unlikely (encoder aligns) */
|
||||
}
|
||||
|
||||
size_t apple_ima4_bytes_to_samples(size_t bytes, int channels) {
|
||||
|
@ -61,7 +61,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "nwa_decoder.h"
|
||||
|
||||
#include "../util/reader_sf.h"
|
||||
|
||||
//NWAInfo::UseRunLength
|
||||
static int is_use_runlength(NWAData* nwa) {
|
||||
|
@ -1,8 +1,7 @@
|
||||
#include "vorbis_custom_decoder.h"
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
#define BITSTREAM_READ_ONLY /* config */
|
||||
#include "vorbis_bitreader.h"
|
||||
#include "../util/bitstream_lsb.h"
|
||||
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
@ -108,12 +107,12 @@ static int build_header_comment(uint8_t* buf, size_t bufsize) {
|
||||
|
||||
if (bytes > bufsize) return 0;
|
||||
|
||||
put_8bit (buf+0x00, 0x03); /* packet_type (comments) */
|
||||
memcpy (buf+0x01, "vorbis", 6); /* id */
|
||||
put_32bitLE(buf+0x07, 0x09); /* vendor_length */
|
||||
memcpy (buf+0x0b, "vgmstream", 9); /* vendor_string */
|
||||
put_32bitLE(buf+0x14, 0x00); /* user_comment_list_length */
|
||||
put_8bit (buf+0x18, 0x01); /* framing_flag (fixed) */
|
||||
put_u8 (buf+0x00, 0x03); /* packet_type (comments) */
|
||||
memcpy (buf+0x01, "vorbis", 6); /* id */
|
||||
put_u32le(buf+0x07, 0x09); /* vendor_length */
|
||||
memcpy (buf+0x0b, "vgmstream", 9); /* vendor_string */
|
||||
put_u32le(buf+0x14, 0x00); /* user_comment_list_length */
|
||||
put_u8 (buf+0x18, 0x01); /* framing_flag (fixed) */
|
||||
|
||||
return bytes;
|
||||
}
|
||||
@ -129,11 +128,11 @@ static int get_packet_header(STREAMFILE* sf, off_t* offset, size_t* size) {
|
||||
if (read_streamfile(ibuf,(*offset),ibufsize, sf) != ibufsize)
|
||||
goto fail;
|
||||
|
||||
init_bitstream(&ib, ibuf, ibufsize);
|
||||
bl_setup(&ib, ibuf, ibufsize);
|
||||
|
||||
/* read using Vorbis weird LSF */
|
||||
rv_bits(&ib, 4,&size_bits);
|
||||
rv_bits(&ib, (size_bits+1),(uint32_t*)size);
|
||||
bl_get(&ib, 4,&size_bits);
|
||||
bl_get(&ib, (size_bits+1),(uint32_t*)size);
|
||||
|
||||
/* special meaning, seen in silent frames */
|
||||
if (size_bits == 0 && *size == 0 && (uint8_t)read_8bit(*offset, sf) == 0x80) {
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "vorbis_custom_decoder.h"
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
#include "vorbis_bitreader.h"
|
||||
#include <vorbis/codec.h>
|
||||
#include "../util/bitstream_lsb.h"
|
||||
|
||||
#define WWISE_VORBIS_USE_PRECOMPILED_WVC 1 /* if enabled vgmstream weights ~150kb more but doesn't need external .wvc packets */
|
||||
#if WWISE_VORBIS_USE_PRECOMPILED_WVC
|
||||
@ -212,8 +212,8 @@ static size_t rebuild_packet(uint8_t* obuf, size_t obufsize, wpacket_t* wp, STRE
|
||||
ok = read_packet(wp, ibuf, ibufsize, sf, offset, data, 0);
|
||||
if (!ok) goto fail;
|
||||
|
||||
init_bitstream(&ow, obuf, obufsize);
|
||||
init_bitstream(&iw, ibuf, ibufsize);
|
||||
bl_setup(&ow, obuf, obufsize);
|
||||
bl_setup(&iw, ibuf, ibufsize);
|
||||
|
||||
ok = ww2ogg_generate_vorbis_packet(&ow, &iw, wp, data);
|
||||
if (!ok) goto fail;
|
||||
@ -242,8 +242,8 @@ static size_t rebuild_setup(uint8_t* obuf, size_t obufsize, wpacket_t* wp, STREA
|
||||
ok = read_packet(wp, ibuf, ibufsize, sf, offset, data, 1);
|
||||
if (!ok) goto fail;
|
||||
|
||||
init_bitstream(&ow, obuf, obufsize);
|
||||
init_bitstream(&iw, ibuf, ibufsize);
|
||||
bl_setup(&ow, obuf, obufsize);
|
||||
bl_setup(&iw, ibuf, ibufsize);
|
||||
|
||||
ok = ww2ogg_generate_vorbis_setup(&ow,&iw, data, wp->packet_size, sf);
|
||||
if (!ok) goto fail;
|
||||
@ -267,16 +267,16 @@ static size_t build_header_identification(uint8_t* buf, size_t bufsize, vorbis_c
|
||||
|
||||
blocksizes = (cfg->blocksize_0_exp << 4) | (cfg->blocksize_1_exp);
|
||||
|
||||
put_8bit (buf+0x00, 0x01); /* packet_type (id) */
|
||||
memcpy (buf+0x01, "vorbis", 6); /* id */
|
||||
put_32bitLE(buf+0x07, 0x00); /* vorbis_version (fixed) */
|
||||
put_8bit (buf+0x0b, cfg->channels); /* audio_channels */
|
||||
put_32bitLE(buf+0x0c, cfg->sample_rate);/* audio_sample_rate */
|
||||
put_32bitLE(buf+0x10, 0x00); /* bitrate_maximum (optional hint) */
|
||||
put_32bitLE(buf+0x14, 0x00); /* bitrate_nominal (optional hint) */
|
||||
put_32bitLE(buf+0x18, 0x00); /* bitrate_minimum (optional hint) */
|
||||
put_8bit (buf+0x1c, blocksizes); /* blocksize_0 + blocksize_1 nibbles */
|
||||
put_8bit (buf+0x1d, 0x01); /* framing_flag (fixed) */
|
||||
put_u8 (buf+0x00, 0x01); /* packet_type (id) */
|
||||
memcpy (buf+0x01, "vorbis", 6); /* id */
|
||||
put_u32le(buf+0x07, 0x00); /* vorbis_version (fixed) */
|
||||
put_u8 (buf+0x0b, cfg->channels); /* audio_channels */
|
||||
put_u32le(buf+0x0c, cfg->sample_rate);/* audio_sample_rate */
|
||||
put_u32le(buf+0x10, 0x00); /* bitrate_maximum (optional hint) */
|
||||
put_u32le(buf+0x14, 0x00); /* bitrate_nominal (optional hint) */
|
||||
put_u32le(buf+0x18, 0x00); /* bitrate_minimum (optional hint) */
|
||||
put_u8 (buf+0x1c, blocksizes); /* blocksize_0 + blocksize_1 nibbles */
|
||||
put_u8 (buf+0x1d, 0x01); /* framing_flag (fixed) */
|
||||
|
||||
return bytes;
|
||||
}
|
||||
@ -286,12 +286,12 @@ static size_t build_header_comment(uint8_t* buf, size_t bufsize) {
|
||||
|
||||
if (bytes > bufsize) return 0;
|
||||
|
||||
put_8bit (buf+0x00, 0x03); /* packet_type (comments) */
|
||||
memcpy (buf+0x01, "vorbis", 6); /* id */
|
||||
put_32bitLE(buf+0x07, 0x09); /* vendor_length */
|
||||
memcpy (buf+0x0b, "vgmstream", 9); /* vendor_string */
|
||||
put_32bitLE(buf+0x14, 0x00); /* user_comment_list_length */
|
||||
put_8bit (buf+0x18, 0x01); /* framing_flag (fixed) */
|
||||
put_u8 (buf+0x00, 0x03); /* packet_type (comments) */
|
||||
memcpy (buf+0x01, "vorbis", 6); /* id */
|
||||
put_u32le(buf+0x07, 0x09); /* vendor_length */
|
||||
memcpy (buf+0x0b, "vgmstream", 9); /* vendor_string */
|
||||
put_u32le(buf+0x14, 0x00); /* user_comment_list_length */
|
||||
put_u8 (buf+0x18, 0x01); /* framing_flag (fixed) */
|
||||
|
||||
return bytes;
|
||||
}
|
||||
@ -306,14 +306,14 @@ static int copy_bytes(bitstream_t* ob, bitstream_t* ib, uint32_t bytes) {
|
||||
for (i = 0; i < bytes / 4; i++) {
|
||||
uint32_t c = 0;
|
||||
|
||||
rv_bits(ib, 32, &c);
|
||||
wv_bits(ob, 32, c);
|
||||
bl_get(ib, 32, &c);
|
||||
bl_put(ob, 32, c);
|
||||
}
|
||||
for (i = 0; i < bytes % 4; i++) {
|
||||
uint32_t c = 0;
|
||||
|
||||
rv_bits(ib, 8, &c);
|
||||
wv_bits(ob, 8, c);
|
||||
bl_get(ib, 8, &c);
|
||||
bl_put(ob, 8, c);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -325,8 +325,8 @@ static int copy_bytes(bitstream_t* ob, bitstream_t* ib, uint32_t bytes) {
|
||||
for (i = 0; i < bytes; i++, iw_pos++) {
|
||||
uint32_t c = ib->buf[iw_pos];
|
||||
|
||||
//rv_bits(ib, 8, &c);
|
||||
wv_bits(ob, 8, c);
|
||||
//bl_get(ib, 8, &c);
|
||||
bl_put(ob, 8, c);
|
||||
}
|
||||
|
||||
ib->b_off += bytes * 8;
|
||||
@ -337,8 +337,8 @@ static int copy_bytes(bitstream_t* ob, bitstream_t* ib, uint32_t bytes) {
|
||||
for (i = 0; i < bytes; i++) {
|
||||
uint32_t c = 0;
|
||||
|
||||
rv_bits(ib, 8, &c);
|
||||
wv_bits(ob, 8, c);
|
||||
bl_get(ib, 8, &c);
|
||||
bl_put(ob, 8, c);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -369,13 +369,13 @@ static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpack
|
||||
|
||||
/* audio packet type */
|
||||
packet_type = 0;
|
||||
wv_bits(ow, 1, packet_type);
|
||||
bl_put(ow, 1, packet_type);
|
||||
|
||||
/* collect this packet mode from the first byte */
|
||||
rv_bits(iw, data->mode_bits,&mode_number); /* max 6b */
|
||||
wv_bits(ow, data->mode_bits, mode_number);
|
||||
bl_get(iw, data->mode_bits,&mode_number); /* max 6b */
|
||||
bl_put(ow, data->mode_bits, mode_number);
|
||||
|
||||
rv_bits(iw, 8-data->mode_bits,&remainder);
|
||||
bl_get(iw, 8-data->mode_bits,&remainder);
|
||||
|
||||
/* adjust window info */
|
||||
if (data->mode_blockflag[mode_number]) {
|
||||
@ -387,9 +387,9 @@ static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpack
|
||||
uint32_t next_mode_number;
|
||||
bitstream_t nw;
|
||||
|
||||
init_bitstream(&nw, wp->inxt, sizeof(wp->inxt));
|
||||
bl_setup(&nw, wp->inxt, sizeof(wp->inxt));
|
||||
|
||||
rv_bits(&nw, data->mode_bits,&next_mode_number); /* max 6b */
|
||||
bl_get(&nw, data->mode_bits,&next_mode_number); /* max 6b */
|
||||
|
||||
next_blockflag = data->mode_blockflag[next_mode_number];
|
||||
}
|
||||
@ -399,15 +399,15 @@ static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpack
|
||||
}
|
||||
|
||||
prev_window_type = data->prev_blockflag;
|
||||
wv_bits(ow, 1, prev_window_type);
|
||||
bl_put(ow, 1, prev_window_type);
|
||||
|
||||
next_window_type = next_blockflag;
|
||||
wv_bits(ow, 1, next_window_type);
|
||||
bl_put(ow, 1, next_window_type);
|
||||
}
|
||||
|
||||
data->prev_blockflag = data->mode_blockflag[mode_number]; /* save for next packet */
|
||||
|
||||
wv_bits(ow, 8-data->mode_bits, remainder);
|
||||
bl_put(ow, 8-data->mode_bits, remainder);
|
||||
|
||||
/* rest of the packet (input/output bytes aren't byte aligned here, so no memcpy) */
|
||||
copy_bytes(ow, iw, wp->packet_size - 1);
|
||||
@ -417,7 +417,7 @@ static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpack
|
||||
uint32_t padding = 0;
|
||||
int padding_bits = 8 - (ow->b_off % 8);
|
||||
|
||||
wv_bits(ow, padding_bits, padding);
|
||||
bl_put(ow, padding_bits, padding);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -480,12 +480,12 @@ static int ww2ogg_codebook_library_copy(bitstream_t* ow, bitstream_t* iw) {
|
||||
uint32_t id = 0, dimensions = 0, entries = 0;
|
||||
uint32_t ordered = 0, lookup_type = 0;
|
||||
|
||||
rv_bits(iw, 24,&id);
|
||||
wv_bits(ow, 24, id);
|
||||
rv_bits(iw, 16,&dimensions);
|
||||
wv_bits(ow, 16, dimensions);
|
||||
rv_bits(iw, 24,&entries);
|
||||
wv_bits(ow, 24, entries);
|
||||
bl_get(iw, 24,&id);
|
||||
bl_put(ow, 24, id);
|
||||
bl_get(iw, 16,&dimensions);
|
||||
bl_put(ow, 16, dimensions);
|
||||
bl_get(iw, 24,&entries);
|
||||
bl_put(ow, 24, entries);
|
||||
|
||||
if (0x564342 != id) { /* "VCB" */
|
||||
VGM_LOG("Wwise Vorbis: invalid codebook identifier\n");
|
||||
@ -493,21 +493,21 @@ static int ww2ogg_codebook_library_copy(bitstream_t* ow, bitstream_t* iw) {
|
||||
}
|
||||
|
||||
/* codeword lengths */
|
||||
rv_bits(iw, 1,&ordered);
|
||||
wv_bits(ow, 1, ordered);
|
||||
bl_get(iw, 1,&ordered);
|
||||
bl_put(ow, 1, ordered);
|
||||
if (ordered) {
|
||||
uint32_t initial_length = 0, current_entry = 0;
|
||||
|
||||
rv_bits(iw, 5,&initial_length);
|
||||
wv_bits(ow, 5, initial_length);
|
||||
bl_get(iw, 5,&initial_length);
|
||||
bl_put(ow, 5, initial_length);
|
||||
|
||||
current_entry = 0;
|
||||
while (current_entry < entries) {
|
||||
uint32_t number = 0;
|
||||
int numberv_bits = ww2ogg_tremor_ilog(entries-current_entry);
|
||||
int numbebl_get = ww2ogg_tremor_ilog(entries-current_entry);
|
||||
|
||||
rv_bits(iw, numberv_bits,&number);
|
||||
wv_bits(ow, numberv_bits, number);
|
||||
bl_get(iw, numbebl_get,&number);
|
||||
bl_put(ow, numbebl_get, number);
|
||||
current_entry += number;
|
||||
}
|
||||
if (current_entry > entries) {
|
||||
@ -518,8 +518,8 @@ static int ww2ogg_codebook_library_copy(bitstream_t* ow, bitstream_t* iw) {
|
||||
else {
|
||||
uint32_t sparse = 0;
|
||||
|
||||
rv_bits(iw, 1,&sparse);
|
||||
wv_bits(ow, 1, sparse);
|
||||
bl_get(iw, 1,&sparse);
|
||||
bl_put(ow, 1, sparse);
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
uint32_t present_bool = 0;
|
||||
@ -528,8 +528,8 @@ static int ww2ogg_codebook_library_copy(bitstream_t* ow, bitstream_t* iw) {
|
||||
if (sparse) {
|
||||
uint32_t present = 0;
|
||||
|
||||
rv_bits(iw, 1,&present);
|
||||
wv_bits(ow, 1, present);
|
||||
bl_get(iw, 1,&present);
|
||||
bl_put(ow, 1, present);
|
||||
|
||||
present_bool = (0 != present);
|
||||
}
|
||||
@ -537,16 +537,16 @@ static int ww2ogg_codebook_library_copy(bitstream_t* ow, bitstream_t* iw) {
|
||||
if (present_bool) {
|
||||
uint32_t codeword_length = 0;
|
||||
|
||||
rv_bits(iw, 5,&codeword_length);
|
||||
wv_bits(ow, 5, codeword_length);
|
||||
bl_get(iw, 5,&codeword_length);
|
||||
bl_put(ow, 5, codeword_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* lookup table */
|
||||
rv_bits(iw, 4,&lookup_type);
|
||||
wv_bits(ow, 4, lookup_type);
|
||||
bl_get(iw, 4,&lookup_type);
|
||||
bl_put(ow, 4, lookup_type);
|
||||
|
||||
if (0 == lookup_type) {
|
||||
//VGM_LOG("Wwise Vorbis: no lookup table\n");
|
||||
@ -556,22 +556,22 @@ static int ww2ogg_codebook_library_copy(bitstream_t* ow, bitstream_t* iw) {
|
||||
uint32_t quantvals = 0, min = 0, max = 0;
|
||||
uint32_t value_length = 0, sequence_flag = 0;
|
||||
|
||||
rv_bits(iw, 32,&min);
|
||||
wv_bits(ow, 32, min);
|
||||
rv_bits(iw, 32,&max);
|
||||
wv_bits(ow, 32, max);
|
||||
rv_bits(iw, 4,&value_length);
|
||||
wv_bits(ow, 4, value_length);
|
||||
rv_bits(iw, 1,&sequence_flag);
|
||||
wv_bits(ow, 1, sequence_flag);
|
||||
bl_get(iw, 32,&min);
|
||||
bl_put(ow, 32, min);
|
||||
bl_get(iw, 32,&max);
|
||||
bl_put(ow, 32, max);
|
||||
bl_get(iw, 4,&value_length);
|
||||
bl_put(ow, 4, value_length);
|
||||
bl_get(iw, 1,&sequence_flag);
|
||||
bl_put(ow, 1, sequence_flag);
|
||||
|
||||
quantvals = ww2ogg_tremor_book_maptype1_quantvals(entries, dimensions);
|
||||
for (i = 0; i < quantvals; i++) {
|
||||
uint32_t val = 0, val_bits = 0;
|
||||
val_bits = value_length+1;
|
||||
|
||||
rv_bits(iw, val_bits,&val);
|
||||
wv_bits(ow, val_bits, val);
|
||||
bl_get(iw, val_bits,&val);
|
||||
bl_put(ow, val_bits, val);
|
||||
}
|
||||
}
|
||||
else if (2 == lookup_type) {
|
||||
@ -596,28 +596,28 @@ static int ww2ogg_codebook_library_rebuild(bitstream_t* ow, bitstream_t* iw, siz
|
||||
|
||||
id = 0x564342; /* "VCB" */
|
||||
|
||||
wv_bits(ow, 24, id);
|
||||
rv_bits(iw, 4,&dimensions);
|
||||
wv_bits(ow, 16, dimensions); /* 4 to 16 */
|
||||
rv_bits(iw, 14,&entries);
|
||||
wv_bits(ow, 24, entries); /* 14 to 24*/
|
||||
bl_put(ow, 24, id);
|
||||
bl_get(iw, 4,&dimensions);
|
||||
bl_put(ow, 16, dimensions); /* 4 to 16 */
|
||||
bl_get(iw, 14,&entries);
|
||||
bl_put(ow, 24, entries); /* 14 to 24*/
|
||||
|
||||
/* codeword lengths */
|
||||
rv_bits(iw, 1,&ordered);
|
||||
wv_bits(ow, 1, ordered);
|
||||
bl_get(iw, 1,&ordered);
|
||||
bl_put(ow, 1, ordered);
|
||||
if (ordered) {
|
||||
uint32_t initial_length = 0, current_entry = 0;
|
||||
|
||||
rv_bits(iw, 5,&initial_length);
|
||||
wv_bits(ow, 5, initial_length);
|
||||
bl_get(iw, 5,&initial_length);
|
||||
bl_put(ow, 5, initial_length);
|
||||
|
||||
current_entry = 0;
|
||||
while (current_entry < entries) {
|
||||
uint32_t number = 0;
|
||||
int numberv_bits = ww2ogg_tremor_ilog(entries-current_entry);
|
||||
int numbebl_get = ww2ogg_tremor_ilog(entries-current_entry);
|
||||
|
||||
rv_bits(iw, numberv_bits,&number);
|
||||
wv_bits(ow, numberv_bits, number);
|
||||
bl_get(iw, numbebl_get,&number);
|
||||
bl_put(ow, numbebl_get, number);
|
||||
current_entry += number;
|
||||
}
|
||||
if (current_entry > entries) {
|
||||
@ -628,9 +628,9 @@ static int ww2ogg_codebook_library_rebuild(bitstream_t* ow, bitstream_t* iw, siz
|
||||
else {
|
||||
uint32_t codeword_length_length = 0, sparse = 0;
|
||||
|
||||
rv_bits(iw, 3,&codeword_length_length);
|
||||
rv_bits(iw, 1,&sparse);
|
||||
wv_bits(ow, 1, sparse);
|
||||
bl_get(iw, 3,&codeword_length_length);
|
||||
bl_get(iw, 1,&sparse);
|
||||
bl_put(ow, 1, sparse);
|
||||
|
||||
if (0 == codeword_length_length || 5 < codeword_length_length) {
|
||||
VGM_LOG("Wwise Vorbis: nonsense codeword length\n");
|
||||
@ -644,8 +644,8 @@ static int ww2ogg_codebook_library_rebuild(bitstream_t* ow, bitstream_t* iw, siz
|
||||
if (sparse) {
|
||||
uint32_t present = 0;
|
||||
|
||||
rv_bits(iw, 1,&present);
|
||||
wv_bits(ow, 1, present);
|
||||
bl_get(iw, 1,&present);
|
||||
bl_put(ow, 1, present);
|
||||
|
||||
present_bool = (0 != present);
|
||||
}
|
||||
@ -653,16 +653,16 @@ static int ww2ogg_codebook_library_rebuild(bitstream_t* ow, bitstream_t* iw, siz
|
||||
if (present_bool) {
|
||||
uint32_t codeword_length = 0;
|
||||
|
||||
rv_bits(iw, codeword_length_length,&codeword_length);
|
||||
wv_bits(ow, 5, codeword_length); /* max 7 (3b) to 5 */
|
||||
bl_get(iw, codeword_length_length,&codeword_length);
|
||||
bl_put(ow, 5, codeword_length); /* max 7 (3b) to 5 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* lookup table */
|
||||
rv_bits(iw, 1,&lookup_type);
|
||||
wv_bits(ow, 4, lookup_type); /* 1 to 4 */
|
||||
bl_get(iw, 1,&lookup_type);
|
||||
bl_put(ow, 4, lookup_type); /* 1 to 4 */
|
||||
|
||||
if (0 == lookup_type) {
|
||||
//VGM_LOG("Wwise Vorbis: no lookup table\n");
|
||||
@ -672,22 +672,22 @@ static int ww2ogg_codebook_library_rebuild(bitstream_t* ow, bitstream_t* iw, siz
|
||||
uint32_t quantvals = 0, min = 0, max = 0;
|
||||
uint32_t value_length = 0, sequence_flag = 0;
|
||||
|
||||
rv_bits(iw, 32,&min);
|
||||
wv_bits(ow, 32, min);
|
||||
rv_bits(iw, 32,&max);
|
||||
wv_bits(ow, 32, max);
|
||||
rv_bits(iw, 4,&value_length);
|
||||
wv_bits(ow, 4, value_length);
|
||||
rv_bits(iw, 1,&sequence_flag);
|
||||
wv_bits(ow, 1, sequence_flag);
|
||||
bl_get(iw, 32,&min);
|
||||
bl_put(ow, 32, min);
|
||||
bl_get(iw, 32,&max);
|
||||
bl_put(ow, 32, max);
|
||||
bl_get(iw, 4,&value_length);
|
||||
bl_put(ow, 4, value_length);
|
||||
bl_get(iw, 1,&sequence_flag);
|
||||
bl_put(ow, 1, sequence_flag);
|
||||
|
||||
quantvals = ww2ogg_tremor_book_maptype1_quantvals(entries, dimensions);
|
||||
for (i = 0; i < quantvals; i++) {
|
||||
uint32_t val = 0, val_bits = 0;
|
||||
val_bits = value_length+1;
|
||||
|
||||
rv_bits(iw, val_bits,&val);
|
||||
wv_bits(ow, val_bits, val);
|
||||
bl_get(iw, val_bits,&val);
|
||||
bl_put(ow, val_bits, val);
|
||||
}
|
||||
}
|
||||
else if (2 == lookup_type) {
|
||||
@ -722,7 +722,7 @@ static int ww2ogg_codebook_library_rebuild_by_id(bitstream_t* ow, uint32_t codeb
|
||||
cb_size = load_wvc(ibuf,ibufsize, codebook_id, setup_type, sf);
|
||||
if (cb_size == 0) goto fail;
|
||||
|
||||
init_bitstream(&iw, ibuf, ibufsize);
|
||||
bl_setup(&iw, ibuf, ibufsize);
|
||||
|
||||
return ww2ogg_codebook_library_rebuild(ow, &iw, cb_size, sf);
|
||||
fail:
|
||||
@ -746,8 +746,8 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
|
||||
|
||||
/* Codebooks */
|
||||
rv_bits(iw, 8,&codebook_count_less1);
|
||||
wv_bits(ow, 8, codebook_count_less1);
|
||||
bl_get(iw, 8,&codebook_count_less1);
|
||||
bl_put(ow, 8, codebook_count_less1);
|
||||
codebook_count = codebook_count_less1 + 1;
|
||||
|
||||
if (data->config.setup_type == WWV_FULL_SETUP) {
|
||||
@ -770,7 +770,7 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
int rc;
|
||||
uint32_t codebook_id = 0;
|
||||
|
||||
rv_bits(iw, 10,&codebook_id);
|
||||
bl_get(iw, 10,&codebook_id);
|
||||
|
||||
rc = ww2ogg_codebook_library_rebuild_by_id(ow, codebook_id, data->config.setup_type, sf);
|
||||
if (!rc) goto fail;
|
||||
@ -780,9 +780,9 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
|
||||
/* Time domain transforms */
|
||||
time_count_less1 = 0;
|
||||
wv_bits(ow, 6, time_count_less1);
|
||||
bl_put(ow, 6, time_count_less1);
|
||||
dummy_time_value = 0;
|
||||
wv_bits(ow, 16, dummy_time_value);
|
||||
bl_put(ow, 16, dummy_time_value);
|
||||
|
||||
|
||||
if (data->config.setup_type == WWV_FULL_SETUP) {
|
||||
@ -792,8 +792,8 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
uint32_t setup_packet_size_bits = packet_size * 8;
|
||||
|
||||
while (total_bits_read < setup_packet_size_bits) {
|
||||
rv_bits(iw, 1,&bitly);
|
||||
wv_bits(ow, 1, bitly);
|
||||
bl_get(iw, 1,&bitly);
|
||||
bl_put(ow, 1, bitly);
|
||||
total_bits_read = iw->b_off;
|
||||
}
|
||||
}
|
||||
@ -806,8 +806,8 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
|
||||
|
||||
/* Floors */
|
||||
rv_bits(iw, 6,&floor_count_less1);
|
||||
wv_bits(ow, 6, floor_count_less1);
|
||||
bl_get(iw, 6,&floor_count_less1);
|
||||
bl_put(ow, 6, floor_count_less1);
|
||||
floor_count = floor_count_less1 + 1;
|
||||
|
||||
for (i = 0; i < floor_count; i++) {
|
||||
@ -818,10 +818,10 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
|
||||
// Always floor type 1
|
||||
floor_type = 1;
|
||||
wv_bits(ow, 16, floor_type);
|
||||
bl_put(ow, 16, floor_type);
|
||||
|
||||
rv_bits(iw, 5,&floor1_partitions);
|
||||
wv_bits(ow, 5, floor1_partitions);
|
||||
bl_get(iw, 5,&floor1_partitions);
|
||||
bl_put(ow, 5, floor1_partitions);
|
||||
|
||||
memset(floor1_partition_class_list, 0, sizeof(uint32_t)*32);
|
||||
|
||||
@ -829,8 +829,8 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
for (j = 0; j < floor1_partitions; j++) {
|
||||
uint32_t floor1_partition_class = 0;
|
||||
|
||||
rv_bits(iw, 4,&floor1_partition_class);
|
||||
wv_bits(ow, 4, floor1_partition_class);
|
||||
bl_get(iw, 4,&floor1_partition_class);
|
||||
bl_put(ow, 4, floor1_partition_class);
|
||||
|
||||
floor1_partition_class_list[j] = floor1_partition_class;
|
||||
|
||||
@ -843,19 +843,19 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
for (j = 0; j <= maximum_class; j++) {
|
||||
uint32_t class_dimensions_less1 = 0, class_subclasses = 0;
|
||||
|
||||
rv_bits(iw, 3,&class_dimensions_less1);
|
||||
wv_bits(ow, 3, class_dimensions_less1);
|
||||
bl_get(iw, 3,&class_dimensions_less1);
|
||||
bl_put(ow, 3, class_dimensions_less1);
|
||||
|
||||
floor1_class_dimensions_list[j] = class_dimensions_less1 + 1;
|
||||
|
||||
rv_bits(iw, 2,&class_subclasses);
|
||||
wv_bits(ow, 2, class_subclasses);
|
||||
bl_get(iw, 2,&class_subclasses);
|
||||
bl_put(ow, 2, class_subclasses);
|
||||
|
||||
if (0 != class_subclasses) {
|
||||
uint32_t masterbook = 0;
|
||||
|
||||
rv_bits(iw, 8,&masterbook);
|
||||
wv_bits(ow, 8, masterbook);
|
||||
bl_get(iw, 8,&masterbook);
|
||||
bl_put(ow, 8, masterbook);
|
||||
|
||||
if (masterbook >= codebook_count) {
|
||||
VGM_LOG("Wwise Vorbis: invalid floor1 masterbook\n");
|
||||
@ -867,8 +867,8 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
uint32_t subclass_book_plus1 = 0;
|
||||
int subclass_book = 0; /* this MUST be int */
|
||||
|
||||
rv_bits(iw, 8,&subclass_book_plus1);
|
||||
wv_bits(ow, 8, subclass_book_plus1);
|
||||
bl_get(iw, 8,&subclass_book_plus1);
|
||||
bl_put(ow, 8, subclass_book_plus1);
|
||||
|
||||
subclass_book = subclass_book_plus1 - 1;
|
||||
if (subclass_book >= 0 && subclass_book >= codebook_count) {
|
||||
@ -878,11 +878,11 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
}
|
||||
}
|
||||
|
||||
rv_bits(iw, 2,&floor1_multiplier_less1);
|
||||
wv_bits(ow, 2, floor1_multiplier_less1);
|
||||
bl_get(iw, 2,&floor1_multiplier_less1);
|
||||
bl_put(ow, 2, floor1_multiplier_less1);
|
||||
|
||||
rv_bits(iw, 4,&rangebits);
|
||||
wv_bits(ow, 4, rangebits);
|
||||
bl_get(iw, 4,&rangebits);
|
||||
bl_put(ow, 4, rangebits);
|
||||
|
||||
for (j = 0; j < floor1_partitions; j++) {
|
||||
uint32_t current_class_number = 0;
|
||||
@ -891,16 +891,16 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
for (k = 0; k < floor1_class_dimensions_list[current_class_number]; k++) {
|
||||
uint32_t X = 0; /* max 4b (15) */
|
||||
|
||||
rv_bits(iw, rangebits,&X);
|
||||
wv_bits(ow, rangebits, X);
|
||||
bl_get(iw, rangebits,&X);
|
||||
bl_put(ow, rangebits, X);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Residues */
|
||||
rv_bits(iw, 6,&residue_count_less1);
|
||||
wv_bits(ow, 6, residue_count_less1);
|
||||
bl_get(iw, 6,&residue_count_less1);
|
||||
bl_put(ow, 6, residue_count_less1);
|
||||
residue_count = residue_count_less1 + 1;
|
||||
|
||||
for (i = 0; i < residue_count; i++) {
|
||||
@ -908,24 +908,24 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
uint32_t residue_begin = 0, residue_end = 0, residue_partition_size_less1 = 0, residue_classifications_less1 = 0, residue_classbook = 0;
|
||||
uint32_t residue_cascade[64+1]; /* 6b +1 */
|
||||
|
||||
rv_bits(iw, 2,&residue_type);
|
||||
wv_bits(ow, 16, residue_type); /* 2b to 16b */
|
||||
bl_get(iw, 2,&residue_type);
|
||||
bl_put(ow, 16, residue_type); /* 2b to 16b */
|
||||
|
||||
if (residue_type > 2) {
|
||||
VGM_LOG("Wwise Vorbis: invalid residue type\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rv_bits(iw, 24,&residue_begin);
|
||||
wv_bits(ow, 24, residue_begin);
|
||||
rv_bits(iw, 24,&residue_end);
|
||||
wv_bits(ow, 24, residue_end);
|
||||
rv_bits(iw, 24,&residue_partition_size_less1);
|
||||
wv_bits(ow, 24, residue_partition_size_less1);
|
||||
rv_bits(iw, 6,&residue_classifications_less1);
|
||||
wv_bits(ow, 6, residue_classifications_less1);
|
||||
rv_bits(iw, 8,&residue_classbook);
|
||||
wv_bits(ow, 8, residue_classbook);
|
||||
bl_get(iw, 24,&residue_begin);
|
||||
bl_put(ow, 24, residue_begin);
|
||||
bl_get(iw, 24,&residue_end);
|
||||
bl_put(ow, 24, residue_end);
|
||||
bl_get(iw, 24,&residue_partition_size_less1);
|
||||
bl_put(ow, 24, residue_partition_size_less1);
|
||||
bl_get(iw, 6,&residue_classifications_less1);
|
||||
bl_put(ow, 6, residue_classifications_less1);
|
||||
bl_get(iw, 8,&residue_classbook);
|
||||
bl_put(ow, 8, residue_classbook);
|
||||
residue_classifications = residue_classifications_less1 + 1;
|
||||
|
||||
if (residue_classbook >= codebook_count) {
|
||||
@ -936,21 +936,21 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
memset(residue_cascade, 0, sizeof(uint32_t)*(64+1));
|
||||
|
||||
for (j = 0; j < residue_classifications; j++) {
|
||||
uint32_t high_bits = 0, lowv_bits = 0, bitflag = 0;
|
||||
uint32_t high_bits = 0, lobl_put = 0, bitflag = 0;
|
||||
|
||||
high_bits = 0;
|
||||
|
||||
rv_bits(iw, 3,&lowv_bits);
|
||||
wv_bits(ow, 3, lowv_bits);
|
||||
bl_get(iw, 3,&lobl_put);
|
||||
bl_put(ow, 3, lobl_put);
|
||||
|
||||
rv_bits(iw, 1,&bitflag);
|
||||
wv_bits(ow, 1, bitflag);
|
||||
bl_get(iw, 1,&bitflag);
|
||||
bl_put(ow, 1, bitflag);
|
||||
if (bitflag) {
|
||||
rv_bits(iw, 5,&high_bits);
|
||||
wv_bits(ow, 5, high_bits);
|
||||
bl_get(iw, 5,&high_bits);
|
||||
bl_put(ow, 5, high_bits);
|
||||
}
|
||||
|
||||
residue_cascade[j] = high_bits * 8 + lowv_bits;
|
||||
residue_cascade[j] = high_bits * 8 + lobl_put;
|
||||
}
|
||||
|
||||
for (j = 0; j < residue_classifications; j++) {
|
||||
@ -958,8 +958,8 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
if (residue_cascade[j] & (1 << k)) {
|
||||
uint32_t residue_book = 0;
|
||||
|
||||
rv_bits(iw, 8,&residue_book);
|
||||
wv_bits(ow, 8, residue_book);
|
||||
bl_get(iw, 8,&residue_book);
|
||||
bl_put(ow, 8, residue_book);
|
||||
|
||||
if (residue_book >= codebook_count) {
|
||||
VGM_LOG("Wwise Vorbis: invalid residue book\n");
|
||||
@ -972,8 +972,8 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
|
||||
|
||||
/* Mappings */
|
||||
rv_bits(iw, 6,&mapping_count_less1);
|
||||
wv_bits(ow, 6, mapping_count_less1);
|
||||
bl_get(iw, 6,&mapping_count_less1);
|
||||
bl_put(ow, 6, mapping_count_less1);
|
||||
mapping_count = mapping_count_less1 + 1;
|
||||
|
||||
for (i = 0; i < mapping_count; i++) {
|
||||
@ -982,28 +982,28 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
|
||||
// always mapping type 0, the only one
|
||||
mapping_type = 0;
|
||||
wv_bits(ow, 16, mapping_type);
|
||||
bl_put(ow, 16, mapping_type);
|
||||
|
||||
rv_bits(iw, 1,&submaps_flag);
|
||||
wv_bits(ow, 1, submaps_flag);
|
||||
bl_get(iw, 1,&submaps_flag);
|
||||
bl_put(ow, 1, submaps_flag);
|
||||
|
||||
submaps = 1;
|
||||
if (submaps_flag) {
|
||||
uint32_t submaps_less1 = 0;
|
||||
|
||||
rv_bits(iw, 4,&submaps_less1);
|
||||
wv_bits(ow, 4, submaps_less1);
|
||||
bl_get(iw, 4,&submaps_less1);
|
||||
bl_put(ow, 4, submaps_less1);
|
||||
submaps = submaps_less1 + 1;
|
||||
}
|
||||
|
||||
rv_bits(iw, 1,&square_polar_flag);
|
||||
wv_bits(ow, 1, square_polar_flag);
|
||||
bl_get(iw, 1,&square_polar_flag);
|
||||
bl_put(ow, 1, square_polar_flag);
|
||||
|
||||
if (square_polar_flag) {
|
||||
uint32_t coupling_steps_less1 = 0, coupling_steps = 0;
|
||||
|
||||
rv_bits(iw, 8,&coupling_steps_less1);
|
||||
wv_bits(ow, 8, coupling_steps_less1);
|
||||
bl_get(iw, 8,&coupling_steps_less1);
|
||||
bl_put(ow, 8, coupling_steps_less1);
|
||||
coupling_steps = coupling_steps_less1 + 1;
|
||||
|
||||
for (j = 0; j < coupling_steps; j++) {
|
||||
@ -1011,10 +1011,10 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
int magnitude_bits = ww2ogg_tremor_ilog(channels-1);
|
||||
int angle_bits = ww2ogg_tremor_ilog(channels-1);
|
||||
|
||||
rv_bits(iw, magnitude_bits,&magnitude);
|
||||
wv_bits(ow, magnitude_bits, magnitude);
|
||||
rv_bits(iw, angle_bits,&angle);
|
||||
wv_bits(ow, angle_bits, angle);
|
||||
bl_get(iw, magnitude_bits,&magnitude);
|
||||
bl_put(ow, magnitude_bits, magnitude);
|
||||
bl_get(iw, angle_bits,&angle);
|
||||
bl_put(ow, angle_bits, angle);
|
||||
|
||||
if (angle == magnitude || magnitude >= channels || angle >= channels) {
|
||||
VGM_LOG("Wwise Vorbis: invalid coupling (angle=%i, mag=%i, ch=%i)\n", angle, magnitude,channels);
|
||||
@ -1024,8 +1024,8 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
}
|
||||
|
||||
// a rare reserved field not removed by Ak!
|
||||
rv_bits(iw, 2,&mapping_reserved);
|
||||
wv_bits(ow, 2, mapping_reserved);
|
||||
bl_get(iw, 2,&mapping_reserved);
|
||||
bl_put(ow, 2, mapping_reserved);
|
||||
if (0 != mapping_reserved) {
|
||||
VGM_LOG("Wwise Vorbis: mapping reserved field nonzero\n");
|
||||
goto fail;
|
||||
@ -1035,8 +1035,8 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
for (j = 0; j < channels; j++) {
|
||||
uint32_t mapping_mux = 0;
|
||||
|
||||
rv_bits(iw, 4,&mapping_mux);
|
||||
wv_bits(ow, 4, mapping_mux);
|
||||
bl_get(iw, 4,&mapping_mux);
|
||||
bl_put(ow, 4, mapping_mux);
|
||||
if (mapping_mux >= submaps) {
|
||||
VGM_LOG("Wwise Vorbis: mapping_mux >= submaps\n");
|
||||
goto fail;
|
||||
@ -1048,18 +1048,18 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
uint32_t time_config = 0, floor_number = 0, residue_number = 0;
|
||||
|
||||
// Another! Unused time domain transform configuration placeholder!
|
||||
rv_bits(iw, 8,&time_config);
|
||||
wv_bits(ow, 8, time_config);
|
||||
bl_get(iw, 8,&time_config);
|
||||
bl_put(ow, 8, time_config);
|
||||
|
||||
rv_bits(iw, 8,&floor_number);
|
||||
wv_bits(ow, 8, floor_number);
|
||||
bl_get(iw, 8,&floor_number);
|
||||
bl_put(ow, 8, floor_number);
|
||||
if (floor_number >= floor_count) {
|
||||
VGM_LOG("Wwise Vorbis: invalid floor mapping\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rv_bits(iw, 8,&residue_number);
|
||||
wv_bits(ow, 8, residue_number);
|
||||
bl_get(iw, 8,&residue_number);
|
||||
bl_put(ow, 8, residue_number);
|
||||
if (residue_number >= residue_count) {
|
||||
VGM_LOG("Wwise Vorbis: invalid residue mapping\n");
|
||||
goto fail;
|
||||
@ -1069,8 +1069,8 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
|
||||
|
||||
/* Modes */
|
||||
rv_bits(iw, 6,&mode_count_less1);
|
||||
wv_bits(ow, 6, mode_count_less1);
|
||||
bl_get(iw, 6,&mode_count_less1);
|
||||
bl_put(ow, 6, mode_count_less1);
|
||||
mode_count = mode_count_less1 + 1;
|
||||
|
||||
memset(data->mode_blockflag, 0, sizeof(uint8_t)*(64+1)); /* up to max mode_count */
|
||||
@ -1079,18 +1079,18 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
for (i = 0; i < mode_count; i++) {
|
||||
uint32_t block_flag = 0, windowtype = 0, transformtype = 0, mapping = 0;
|
||||
|
||||
rv_bits(iw, 1,&block_flag);
|
||||
wv_bits(ow, 1, block_flag);
|
||||
bl_get(iw, 1,&block_flag);
|
||||
bl_put(ow, 1, block_flag);
|
||||
|
||||
data->mode_blockflag[i] = (block_flag != 0); /* for mod_packets */
|
||||
|
||||
windowtype = 0;
|
||||
transformtype = 0;
|
||||
wv_bits(ow, 16, windowtype);
|
||||
wv_bits(ow, 16, transformtype);
|
||||
bl_put(ow, 16, windowtype);
|
||||
bl_put(ow, 16, transformtype);
|
||||
|
||||
rv_bits(iw, 8,&mapping);
|
||||
wv_bits(ow, 8, mapping);
|
||||
bl_get(iw, 8,&mapping);
|
||||
bl_put(ow, 8, mapping);
|
||||
if (mapping >= mapping_count) {
|
||||
VGM_LOG("Wwise Vorbis: invalid mode mapping\n");
|
||||
goto fail;
|
||||
@ -1104,7 +1104,7 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
uint32_t framing = 0;
|
||||
|
||||
framing = 1;
|
||||
wv_bits(ow, 1, framing);
|
||||
bl_put(ow, 1, framing);
|
||||
}
|
||||
|
||||
/* remove trailing garbage bits */
|
||||
@ -1112,7 +1112,7 @@ static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis
|
||||
uint32_t padding = 0;
|
||||
int padding_bits = 8 - (ow->b_off % 8);
|
||||
|
||||
wv_bits(ow, padding_bits, padding);
|
||||
bl_put(ow, padding_bits, padding);
|
||||
}
|
||||
|
||||
|
||||
|
@ -116,7 +116,7 @@ static const char* extension_list[] = {
|
||||
"bk2",
|
||||
"bkr", //txth/reserved [P.N.03 (GC), Viewtiful Joe (GC)]
|
||||
"blk",
|
||||
"bmdx",
|
||||
"bmdx", //fake extension (to be removed?)
|
||||
"bms",
|
||||
"bnk",
|
||||
"bnm",
|
||||
@ -393,6 +393,7 @@ static const char* extension_list[] = {
|
||||
"ogv",
|
||||
"oma", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
|
||||
"omu",
|
||||
"opu",
|
||||
//"opus", //common
|
||||
"opusx",
|
||||
"otm",
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../decode.h"
|
||||
#include "../base/decode.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
@ -11,13 +11,13 @@ void render_vgmstream_blocked(sample_t* buffer, int32_t sample_count, VGMSTREAM*
|
||||
int samples_written = 0;
|
||||
int frame_size, samples_per_frame, samples_this_block;
|
||||
|
||||
frame_size = get_vgmstream_frame_size(vgmstream);
|
||||
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
frame_size = decode_get_frame_size(vgmstream);
|
||||
samples_per_frame = decode_get_samples_per_frame(vgmstream);
|
||||
samples_this_block = 0;
|
||||
|
||||
if (vgmstream->current_block_samples) {
|
||||
samples_this_block = vgmstream->current_block_samples;
|
||||
} else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */
|
||||
} else if (frame_size == 0) { /* assume 4 bit */ //TODO: decode_get_frame_size() really should return bits... */
|
||||
samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame;
|
||||
} else {
|
||||
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
|
||||
@ -28,11 +28,11 @@ void render_vgmstream_blocked(sample_t* buffer, int32_t sample_count, VGMSTREAM*
|
||||
int samples_to_do;
|
||||
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
if (vgmstream->loop_flag && decode_do_loop(vgmstream)) {
|
||||
/* handle looping, readjust back to loop start values */
|
||||
if (vgmstream->current_block_samples) {
|
||||
samples_this_block = vgmstream->current_block_samples;
|
||||
} else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */
|
||||
} else if (frame_size == 0) { /* assume 4 bit */ //TODO: decode_get_frame_size() really should return bits... */
|
||||
samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame;
|
||||
} else {
|
||||
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
|
||||
@ -54,7 +54,7 @@ void render_vgmstream_blocked(sample_t* buffer, int32_t sample_count, VGMSTREAM*
|
||||
break;
|
||||
}
|
||||
|
||||
samples_to_do = get_vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
samples_to_do = decode_get_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
if (samples_to_do > sample_count - samples_written)
|
||||
samples_to_do = sample_count - samples_written;
|
||||
|
||||
@ -74,11 +74,11 @@ void render_vgmstream_blocked(sample_t* buffer, int32_t sample_count, VGMSTREAM*
|
||||
block_update(vgmstream->next_block_offset,vgmstream);
|
||||
|
||||
/* update since these may change each block */
|
||||
frame_size = get_vgmstream_frame_size(vgmstream);
|
||||
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
frame_size = decode_get_frame_size(vgmstream);
|
||||
samples_per_frame = decode_get_samples_per_frame(vgmstream);
|
||||
if (vgmstream->current_block_samples) {
|
||||
samples_this_block = vgmstream->current_block_samples;
|
||||
} else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */
|
||||
} else if (frame_size == 0) { /* assume 4 bit */ //TODO: decode_get_frame_size() really should return bits... */
|
||||
samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame;
|
||||
} else {
|
||||
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../decode.h"
|
||||
#include "../base/decode.h"
|
||||
|
||||
|
||||
/* Decodes samples for flat streams.
|
||||
@ -9,19 +9,19 @@ void render_vgmstream_flat(sample_t* outbuf, int32_t sample_count, VGMSTREAM* vg
|
||||
int samples_written = 0;
|
||||
int samples_per_frame, samples_this_block;
|
||||
|
||||
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
samples_per_frame = decode_get_samples_per_frame(vgmstream);
|
||||
samples_this_block = vgmstream->num_samples; /* do all samples if possible */
|
||||
|
||||
|
||||
while (samples_written < sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
if (vgmstream->loop_flag && decode_do_loop(vgmstream)) {
|
||||
/* handle looping */
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = get_vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
samples_to_do = decode_get_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
if (samples_to_do > sample_count - samples_written)
|
||||
samples_to_do = sample_count - samples_written;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../decode.h"
|
||||
#include "../base/decode.h"
|
||||
|
||||
|
||||
/* Decodes samples for interleaved streams.
|
||||
@ -19,20 +19,20 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
|
||||
|
||||
/* setup */
|
||||
{
|
||||
int frame_size_d = get_vgmstream_frame_size(vgmstream);
|
||||
samples_per_frame_d = get_vgmstream_samples_per_frame(vgmstream);
|
||||
int frame_size_d = decode_get_frame_size(vgmstream);
|
||||
samples_per_frame_d = decode_get_samples_per_frame(vgmstream);
|
||||
if (frame_size_d == 0 || samples_per_frame_d == 0) goto fail;
|
||||
samples_this_block_d = vgmstream->interleave_block_size / frame_size_d * samples_per_frame_d;
|
||||
}
|
||||
if (has_interleave_first) {
|
||||
int frame_size_f = get_vgmstream_frame_size(vgmstream);
|
||||
samples_per_frame_f = get_vgmstream_samples_per_frame(vgmstream); //todo samples per shortframe
|
||||
int frame_size_f = decode_get_frame_size(vgmstream);
|
||||
samples_per_frame_f = decode_get_samples_per_frame(vgmstream); //todo samples per shortframe
|
||||
if (frame_size_f == 0 || samples_per_frame_f == 0) goto fail;
|
||||
samples_this_block_f = vgmstream->interleave_first_block_size / frame_size_f * samples_per_frame_f;
|
||||
}
|
||||
if (has_interleave_last) {
|
||||
int frame_size_l = get_vgmstream_shortframe_size(vgmstream);
|
||||
samples_per_frame_l = get_vgmstream_samples_per_shortframe(vgmstream);
|
||||
int frame_size_l = decode_get_shortframe_size(vgmstream);
|
||||
samples_per_frame_l = decode_get_samples_per_shortframe(vgmstream);
|
||||
if (frame_size_l == 0 || samples_per_frame_l == 0) goto fail;
|
||||
samples_this_block_l = vgmstream->interleave_last_block_size / frame_size_l * samples_per_frame_l;
|
||||
}
|
||||
@ -62,7 +62,7 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
|
||||
while (samples_written < sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
if (vgmstream->loop_flag && decode_do_loop(vgmstream)) {
|
||||
/* handle looping, restore standard interleave sizes */
|
||||
|
||||
if (has_interleave_first &&
|
||||
@ -83,7 +83,7 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = get_vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
samples_to_do = decode_get_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
if (samples_to_do > sample_count - samples_written)
|
||||
samples_to_do = sample_count - samples_written;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../decode.h"
|
||||
#include "../mixing.h"
|
||||
#include "../plugins.h"
|
||||
#include "../base/decode.h"
|
||||
#include "../base/mixing.h"
|
||||
#include "../base/plugins.h"
|
||||
|
||||
#define VGMSTREAM_MAX_LAYERS 255
|
||||
#define VGMSTREAM_LAYER_SAMPLE_BUFFER 8192
|
||||
@ -25,12 +25,12 @@ void render_vgmstream_layered(sample_t* outbuf, int32_t sample_count, VGMSTREAM*
|
||||
int layer, ch;
|
||||
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
if (vgmstream->loop_flag && decode_do_loop(vgmstream)) {
|
||||
/* handle looping (loop_layout has been called below) */
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = get_vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
samples_to_do = decode_get_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
if (samples_to_do > sample_count - samples_written)
|
||||
samples_to_do = sample_count - samples_written;
|
||||
|
||||
@ -105,7 +105,7 @@ void loop_layout_layered(VGMSTREAM* vgmstream, int32_t loop_sample) {
|
||||
* calls to do_loop work (used in seek_vgmstream) */
|
||||
if (data->layers[layer]->loop_flag) { /* mixing looping and non-looping layers is allowed */
|
||||
data->layers[layer]->current_sample = data->layers[layer]->loop_end_sample; /* forces do loop */
|
||||
vgmstream_do_loop(data->layers[layer]); /* guaranteed to work should loop_layout be called */
|
||||
decode_do_loop(data->layers[layer]); /* guaranteed to work should loop_layout be called */
|
||||
}
|
||||
else {
|
||||
/* needed when mixing non-looping layers and installing loop externally */
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "../streamtypes.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../util/reader_sf.h"
|
||||
|
||||
/* blocked layouts */
|
||||
void render_vgmstream_blocked(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../decode.h"
|
||||
#include "../mixing.h"
|
||||
#include "../plugins.h"
|
||||
#include "../base/decode.h"
|
||||
#include "../base/mixing.h"
|
||||
#include "../base/plugins.h"
|
||||
|
||||
#define VGMSTREAM_MAX_SEGMENTS 1024
|
||||
#define VGMSTREAM_SEGMENT_SAMPLE_BUFFER 8192
|
||||
@ -34,7 +34,7 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
|
||||
while (samples_written < sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
if (vgmstream->loop_flag && decode_do_loop(vgmstream)) {
|
||||
/* handle looping (loop_layout has been called below, changes segments/state) */
|
||||
samples_this_block = vgmstream_get_samples(data->segments[data->current_segment]);
|
||||
mixing_info(data->segments[data->current_segment], NULL, ¤t_channels);
|
||||
@ -60,7 +60,7 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
|
||||
}
|
||||
|
||||
|
||||
samples_to_do = get_vgmstream_samples_to_do(samples_this_block, sample_count, vgmstream);
|
||||
samples_to_do = decode_get_samples_to_do(samples_this_block, sample_count, vgmstream);
|
||||
if (samples_to_do > sample_count - samples_written)
|
||||
samples_to_do = sample_count - samples_written;
|
||||
if (samples_to_do > VGMSTREAM_SEGMENT_SAMPLE_BUFFER /*&& use_internal_buffer*/) /* always for fade/etc mixes */
|
||||
|
@ -81,15 +81,15 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api.h" />
|
||||
<ClInclude Include="decode.h" />
|
||||
<ClInclude Include="mixing.h" />
|
||||
<ClInclude Include="plugins.h" />
|
||||
<ClInclude Include="render.h" />
|
||||
<ClInclude Include="streamfile.h" />
|
||||
<ClInclude Include="streamtypes.h" />
|
||||
<ClInclude Include="util.h" />
|
||||
<ClInclude Include="vgmstream.h" />
|
||||
<ClInclude Include="vgmstream_types.h" />
|
||||
<ClInclude Include="base\decode.h" />
|
||||
<ClInclude Include="base\mixing.h" />
|
||||
<ClInclude Include="base\plugins.h" />
|
||||
<ClInclude Include="base\render.h" />
|
||||
<ClInclude Include="coding\acm_decoder_libacm.h" />
|
||||
<ClInclude Include="coding\circus_decoder_lib.h" />
|
||||
<ClInclude Include="coding\circus_decoder_lib_data.h" />
|
||||
@ -110,7 +110,6 @@
|
||||
<ClInclude Include="coding\tac_decoder_lib.h" />
|
||||
<ClInclude Include="coding\tac_decoder_lib_data.h" />
|
||||
<ClInclude Include="coding\tac_decoder_lib_ops.h" />
|
||||
<ClInclude Include="coding\vorbis_bitreader.h" />
|
||||
<ClInclude Include="coding\vorbis_custom_data_fsb.h" />
|
||||
<ClInclude Include="coding\vorbis_custom_data_wwise.h" />
|
||||
<ClInclude Include="coding\vorbis_custom_decoder.h" />
|
||||
@ -168,32 +167,37 @@
|
||||
<ClInclude Include="meta\xwb_xsb.h" />
|
||||
<ClInclude Include="meta\xwma_konami_streamfile.h" />
|
||||
<ClInclude Include="meta\zsnd_streamfile.h" />
|
||||
<ClInclude Include="util\bitstream_lsb.h" />
|
||||
<ClInclude Include="util\bitstream_msb.h" />
|
||||
<ClInclude Include="util\channel_mappings.h" />
|
||||
<ClInclude Include="util\chunks.h" />
|
||||
<ClInclude Include="util\companion_files.h" />
|
||||
<ClInclude Include="util\cri_keys.h" />
|
||||
<ClInclude Include="util\cri_utf.h" />
|
||||
<ClInclude Include="util\endianness.h" />
|
||||
<ClInclude Include="util\log.h" />
|
||||
<ClInclude Include="util\m2_psb.h" />
|
||||
<ClInclude Include="util\miniz.h" />
|
||||
<ClInclude Include="util\paths.h" />
|
||||
<ClInclude Include="util\reader_get.h" />
|
||||
<ClInclude Include="util\reader_get_nibbles.h" />
|
||||
<ClInclude Include="util\reader_put.h" />
|
||||
<ClInclude Include="util\reader_sf.h" />
|
||||
<ClInclude Include="util\reader_text.h" />
|
||||
<ClInclude Include="util\samples_ops.h" />
|
||||
<ClInclude Include="util\text_reader.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="decode.c" />
|
||||
<ClCompile Include="formats.c" />
|
||||
<ClCompile Include="mixing.c" />
|
||||
<ClCompile Include="plugins.c" />
|
||||
<ClCompile Include="render.c" />
|
||||
<ClCompile Include="seek.c" />
|
||||
<ClCompile Include="streamfile.c" />
|
||||
<ClCompile Include="util.c" />
|
||||
<ClCompile Include="vgmstream.c" />
|
||||
<ClCompile Include="base\decode.c" />
|
||||
<ClCompile Include="base\info.c" />
|
||||
<ClCompile Include="base\mixing.c" />
|
||||
<ClCompile Include="base\plugins.c" />
|
||||
<ClCompile Include="base\render.c" />
|
||||
<ClCompile Include="base\seek.c" />
|
||||
<ClCompile Include="coding\acm_decoder.c" />
|
||||
<ClCompile Include="coding\acm_decoder_decode.c" />
|
||||
<ClCompile Include="coding\acm_decoder_util.c" />
|
||||
@ -736,12 +740,14 @@
|
||||
<ClCompile Include="meta\zwdsp.c" />
|
||||
<ClCompile Include="meta\zwv.c" />
|
||||
<ClCompile Include="util\chunks.c" />
|
||||
<ClCompile Include="util\companion_files.c" />
|
||||
<ClCompile Include="util\cri_keys.c" />
|
||||
<ClCompile Include="util\cri_utf.c" />
|
||||
<ClCompile Include="util\log.c" />
|
||||
<ClCompile Include="util\m2_psb.c" />
|
||||
<ClCompile Include="util\miniz.c" />
|
||||
<ClCompile Include="util\reader_put.c" />
|
||||
<ClCompile Include="util\paths.c" />
|
||||
<ClCompile Include="util\reader.c" />
|
||||
<ClCompile Include="util\samples_ops.c" />
|
||||
<ClCompile Include="util\text_reader.c" />
|
||||
</ItemGroup>
|
||||
|
@ -68,18 +68,6 @@
|
||||
<ClInclude Include="api.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="decode.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="mixing.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="plugins.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="render.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="streamfile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -95,6 +83,18 @@
|
||||
<ClInclude Include="vgmstream_types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base\decode.h">
|
||||
<Filter>base\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base\mixing.h">
|
||||
<Filter>base\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base\plugins.h">
|
||||
<Filter>base\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base\render.h">
|
||||
<Filter>base\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="coding\acm_decoder_libacm.h">
|
||||
<Filter>coding\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -155,9 +155,6 @@
|
||||
<ClInclude Include="coding\tac_decoder_lib_ops.h">
|
||||
<Filter>coding\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="coding\vorbis_bitreader.h">
|
||||
<Filter>coding\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="coding\vorbis_custom_data_fsb.h">
|
||||
<Filter>coding\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -329,6 +326,9 @@
|
||||
<ClInclude Include="meta\zsnd_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\bitstream_lsb.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\bitstream_msb.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -338,6 +338,9 @@
|
||||
<ClInclude Include="util\chunks.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\companion_files.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\cri_keys.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -356,6 +359,9 @@
|
||||
<ClInclude Include="util\miniz.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\paths.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\reader_get.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -365,6 +371,12 @@
|
||||
<ClInclude Include="util\reader_put.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\reader_sf.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\reader_text.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\samples_ops.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -373,24 +385,9 @@
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="decode.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="formats.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mixing.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="plugins.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="render.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="seek.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="streamfile.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -400,9 +397,24 @@
|
||||
<ClCompile Include="vgmstream.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\decode.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\info.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\mixing.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\plugins.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\render.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\seek.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\acm_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -2029,6 +2041,9 @@
|
||||
<ClCompile Include="util\chunks.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\companion_files.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\cri_keys.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -2044,7 +2059,10 @@
|
||||
<ClCompile Include="util\miniz.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\reader_put.c">
|
||||
<ClCompile Include="util\paths.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\reader.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\samples_ops.c">
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "adx_keys.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/cri_keys.h"
|
||||
#include "../util/companion_files.h"
|
||||
|
||||
|
||||
#ifdef VGM_DEBUG_OUTPUT
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "../coding/coding.h"
|
||||
#include "ahx_keys.h"
|
||||
#include "../util/cri_keys.h"
|
||||
#include "../util/companion_files.h"
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
static int find_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/companion_files.h"
|
||||
|
||||
//typedef enum { ADX, HCA, VAG, RIFF, CWAV, DSP, CWAC, M4A } awb_type_t;
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
|
||||
|
||||
/* .BAF - Bizarre Creations bank file [Blur (PS3), Project Gotham Racing 4 (X360), Geometry Wars (PC)] */
|
||||
VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
|
||||
@ -8,7 +10,7 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
|
||||
size_t stream_size;
|
||||
uint32_t channel_count, sample_rate, num_samples, version, codec, tracks;
|
||||
int loop_flag, total_subsongs, target_subsong = sf->stream_index;
|
||||
uint32_t (*read_u32)(off_t,STREAMFILE*);
|
||||
read_u32_t read_u32;
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00, sf, "BANK"))
|
||||
@ -18,7 +20,7 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
|
||||
goto fail;
|
||||
|
||||
/* use BANK size to check endianness */
|
||||
if (guess_endianness32bit(0x04,sf)) {
|
||||
if (guess_endian32(0x04,sf)) {
|
||||
read_u32 = read_u32be;
|
||||
} else {
|
||||
read_u32 = read_u32le;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
#include "../util/endianness.h"
|
||||
|
||||
|
||||
/* BKHD - Wwise soundbank container */
|
||||
@ -10,8 +11,8 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
|
||||
uint32_t subfile_offset, subfile_size, base_offset = 0;
|
||||
uint32_t subfile_id, version;
|
||||
int big_endian, is_dummy = 0, is_wmid = 0;
|
||||
uint32_t (*read_u32)(off_t,STREAMFILE*);
|
||||
float (*read_f32)(off_t,STREAMFILE*);
|
||||
read_u32_t read_u32;
|
||||
read_f32_t read_f32;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
int prefetch = 0;
|
||||
|
||||
@ -24,7 +25,7 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
|
||||
base_offset = 0x0c;
|
||||
if (!is_id32be(base_offset + 0x00, sf, "BKHD"))
|
||||
goto fail;
|
||||
big_endian = guess_endianness32bit(base_offset + 0x04, sf);
|
||||
big_endian = guess_endian32(base_offset + 0x04, sf);
|
||||
read_u32 = big_endian ? read_u32be : read_u32le;
|
||||
read_f32 = big_endian ? read_f32be : read_f32le;
|
||||
|
||||
@ -200,7 +201,7 @@ VGMSTREAM* init_vgmstream_bkhd_fx(STREAMFILE* sf) {
|
||||
/* .wem: used when (rarely) external */
|
||||
if (!check_extensions(sf,"wem,bnk"))
|
||||
goto fail;
|
||||
big_endian = guess_endianness32bit(0x00, sf);
|
||||
big_endian = guess_endian32(0x00, sf);
|
||||
read_u32 = big_endian ? read_u32be : read_u32le;
|
||||
|
||||
/* Not an actual stream but typically convolution reverb models and other FX plugin helpers.
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
#include "../util/companion_files.h"
|
||||
#include "bnsf_keys.h"
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/cri_utf.h"
|
||||
#include "../util/companion_files.h"
|
||||
|
||||
|
||||
typedef enum { HCA, CWAV, ADX } cpk_type_t;
|
||||
|
@ -1,8 +1,9 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
|
||||
/* CSMP - Retro Studios sample [Metroid Prime 3 (Wii), Donkey Kong Country Returns (Wii)] */
|
||||
/* CSMP - Retro Studios sample [Metroid Prime 3 (Wii)-sfx, Donkey Kong Country Returns (Wii)-sfx] */
|
||||
VGMSTREAM* init_vgmstream_csmp(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset, first_offset = 0x08, chunk_offset;
|
||||
@ -10,21 +11,20 @@ VGMSTREAM* init_vgmstream_csmp(STREAMFILE* sf) {
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "csmp"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x00, sf, "CSMP"))
|
||||
goto fail;
|
||||
if (read_u32be(0x04, sf) != 1)
|
||||
if (!check_extensions(sf, "csmp"))
|
||||
goto fail;
|
||||
if (read_u32be(0x04, sf) != 1) /* version? */
|
||||
goto fail;
|
||||
|
||||
if (!find_chunk(sf, 0x44415441,first_offset,0, &chunk_offset,NULL, 1, 0)) /*"DATA"*/
|
||||
/* INFO > PAD > DATA */
|
||||
if (!find_chunk(sf, get_id32be("DATA"),first_offset,0, &chunk_offset,NULL, 1, 0))
|
||||
goto fail;
|
||||
|
||||
/* contains standard DSP header, but somehow some validations (start/loop ps)
|
||||
* don't seem to work, so no point to handle as standard DSP */
|
||||
|
||||
channels = 1;
|
||||
loop_flag = read_s16be(chunk_offset+0x0c,sf);
|
||||
/* contains a not quite standard DSP header */
|
||||
channels = 1; /* also at INFO + 0x00? (in practice uses dual stereo in separate files) */
|
||||
loop_flag = read_s16be(chunk_offset+0x0c,sf); /* also at INFO + 0x01 */
|
||||
start_offset = chunk_offset + 0x60;
|
||||
|
||||
|
||||
@ -35,10 +35,8 @@ VGMSTREAM* init_vgmstream_csmp(STREAMFILE* sf) {
|
||||
vgmstream->meta_type = meta_CSMP;
|
||||
vgmstream->sample_rate = read_s32be(chunk_offset+0x08,sf);
|
||||
vgmstream->num_samples = read_s32be(chunk_offset+0x00,sf);
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_u32be(chunk_offset+0x10,sf));
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_u32be(chunk_offset+0x14,sf)) + 1;
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
vgmstream->loop_start_sample = read_s32be(chunk_offset+0x10,sf); /* unlike regular DSP's nibbles */
|
||||
vgmstream->loop_end_sample = read_s32be(chunk_offset+0x14,sf) + 1;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
#include "../util/companion_files.h"
|
||||
#include "ea_eaac_streamfile.h"
|
||||
|
||||
/* EAAudioCore (aka SND10) formats, EA's current audio middleware */
|
||||
@ -85,7 +87,7 @@ VGMSTREAM* init_vgmstream_ea_snu(STREAMFILE* sf) {
|
||||
* 0x0c(4): some sub-offset? (0x20, found when @0x01 is set) */
|
||||
|
||||
/* use start_offset as endianness flag */
|
||||
if (guess_endianness32bit(0x08,sf)) {
|
||||
if (guess_endian32(0x08,sf)) {
|
||||
read_32bit = read_32bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
@ -125,7 +127,7 @@ VGMSTREAM* init_vgmstream_ea_abk_eaac(STREAMFILE* sf) {
|
||||
goto fail;
|
||||
|
||||
/* use table offset to check endianness */
|
||||
if (guess_endianness32bit(0x1C, sf)) {
|
||||
if (guess_endian32(0x1C, sf)) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
#include "../util/companion_files.h"
|
||||
#include "ea_schl_streamfile.h"
|
||||
|
||||
/* header version */
|
||||
@ -222,7 +224,7 @@ VGMSTREAM* init_vgmstream_ea_schl_video(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
/* use block size to check endianness */
|
||||
if (guess_endianness32bit(0x04, sf)) {
|
||||
if (guess_endian32(0x04, sf)) {
|
||||
read_32bit = read_32bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
@ -329,7 +331,7 @@ VGMSTREAM* init_vgmstream_ea_abk(STREAMFILE* sf) {
|
||||
goto fail;
|
||||
|
||||
/* use table offset to check endianness */
|
||||
if (guess_endianness32bit(0x1C, sf)) {
|
||||
if (guess_endian32(0x1C, sf)) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
@ -1142,7 +1144,7 @@ static VGMSTREAM* parse_schl_block(STREAMFILE* sf, off_t offset) {
|
||||
ea.codec_config |= (header_id & 0xFFFF) << 16;
|
||||
}
|
||||
|
||||
if (guess_endianness32bit(offset + 0x04, sf)) { /* size is always LE, except in early SS/MAC */
|
||||
if (guess_endian32(offset + 0x04, sf)) { /* size is always LE, except in early SS/MAC */
|
||||
header_size = read_32bitBE(offset + 0x04, sf);
|
||||
ea.codec_config |= 0x02;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util/endianness.h"
|
||||
|
||||
/* EA WVE (Ad10) - from early Electronic Arts movies [Wing Commander 3/4 (PS1), Madden NHL 97 (PC)-w95] */
|
||||
VGMSTREAM* init_vgmstream_ea_wve_ad10(STREAMFILE* sf) {
|
||||
@ -22,7 +23,7 @@ VGMSTREAM* init_vgmstream_ea_wve_ad10(STREAMFILE* sf) {
|
||||
!is_id32be(0x00, sf, "Ad11")) /* last audio block, but could be first */
|
||||
goto fail;
|
||||
|
||||
big_endian = guess_endianness32bit(0x04, sf);
|
||||
big_endian = guess_endian32(0x04, sf);
|
||||
|
||||
if (is_id32be(0x00, sf, "AABB"))
|
||||
start_offset += big_endian ? read_u32be(0x04, sf) : read_u32le(0x04, sf);
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/companion_files.h"
|
||||
#include "../util/chunks.h"
|
||||
#include "ogg_vorbis_streamfile.h"
|
||||
#include "encrypted_bgm_streamfile.h"
|
||||
#include "encrypted_mc161_streamfile.h"
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
|
||||
static int get_subsongs(STREAMFILE* sf, off_t fsb5_offset, size_t fsb5_size);
|
||||
@ -16,13 +17,14 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00,sf, "RIFF"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x08,sf, "FEV "))
|
||||
goto fail;
|
||||
|
||||
if (!check_extensions(sf, "bank"))
|
||||
goto fail;
|
||||
|
||||
if (read_u32be(0x00,sf) != 0x52494646) /* "RIFF" */
|
||||
goto fail;
|
||||
if (read_u32be(0x08,sf) != 0x46455620) /* "FEV " */
|
||||
goto fail;
|
||||
version = read_u32le(0x14,sf); /* newer FEV have some kind of sub-version at 0x18 */
|
||||
|
||||
/* .fev is an event format referencing various external .fsb, but FMOD can bake .fev and .fsb to
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "meta.h"
|
||||
#include "../util/companion_files.h"
|
||||
#include "fsb_keys.h"
|
||||
#include "fsb_encrypted_streamfile.h"
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
/* GSP+GSB - from Tecmo's Super Swing Golf 1 & 2 (Wii), Quantum Theory (PS3/X360) */
|
||||
VGMSTREAM* init_vgmstream_gsp_gsb(STREAMFILE* sf) {
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "../coding/coding.h"
|
||||
#include "../coding/hca_decoder_clhca.h"
|
||||
#include "../util/channel_mappings.h"
|
||||
#include "../util/companion_files.h"
|
||||
|
||||
#ifdef VGM_DEBUG_OUTPUT
|
||||
//#define HCA_BRUTEFORCE
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
|
||||
/* LucasArts iMUSE (Interactive Music Streaming Engine) formats */
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
|
||||
typedef enum { PCM16, MSADPCM, DSP_HEAD, DSP_BODY, AT9, MSF_APEX, XMA2 } kwb_codec;
|
||||
|
||||
@ -594,7 +595,7 @@ static int parse_kwb(kwb_header* kwb, STREAMFILE* sf_h, STREAMFILE* sf_b) {
|
||||
head_offset = 0x00;
|
||||
body_offset = 0x00;
|
||||
|
||||
kwb->big_endian = guess_endianness32bit(head_offset + 0x08, sf_h);
|
||||
kwb->big_endian = guess_endian32(head_offset + 0x08, sf_h);
|
||||
|
||||
read_u32 = kwb->big_endian ? read_u32be : read_u32le;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
#define _META_H
|
||||
|
||||
#include "../vgmstream.h"
|
||||
#include "../util/reader_sf.h"
|
||||
#include "../util/reader_text.h"
|
||||
|
||||
typedef VGMSTREAM* (*init_vgmstream_t)(STREAMFILE* sf);
|
||||
|
||||
|
@ -33,7 +33,7 @@ VGMSTREAM* init_vgmstream_mul(STREAMFILE* sf) {
|
||||
read_u32be(0x1c,sf) != 0)
|
||||
goto fail;
|
||||
|
||||
big_endian = guess_endianness32bit(0x00, sf);
|
||||
big_endian = guess_endian32(0x00, sf);
|
||||
read_u32 = big_endian ? read_u32be : read_u32le;
|
||||
read_f32 = big_endian ? read_f32be : read_f32le;
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
|
||||
static void load_name(char* name, size_t name_size, STREAMFILE* sf, int big_endian, int total_subsongs, int target_subsong);
|
||||
@ -19,21 +21,21 @@ VGMSTREAM* init_vgmstream_nub(STREAMFILE* sf) {
|
||||
|
||||
|
||||
/* checks */
|
||||
version = read_u32be(0x00,sf);
|
||||
if (version != 0x00020000 && /* v2.0 (rare, ex. Ridge Race 6 (X360)) */
|
||||
version != 0x00020100 && /* v2.1 (common) */
|
||||
version != 0x01020100) /* same but LE (seen in PSP/PC games, except PS4) */
|
||||
goto fail;
|
||||
if (read_u32be(0x04,sf) != 0x00000000) /* null */
|
||||
goto fail;
|
||||
|
||||
/* .nub: standard
|
||||
* .nub2: rare [iDOLM@STER - Gravure For You (PS3)] */
|
||||
if (!check_extensions(sf, "nub,nub2"))
|
||||
goto fail;
|
||||
|
||||
version = read_32bitBE(0x00,sf);
|
||||
if (version != 0x00020000 && /* v2.0 (rare, ex. Ridge Race 6 (X360)) */
|
||||
version != 0x00020100 && /* v2.1 (common) */
|
||||
version != 0x01020100) /* same but LE (seen in PSP/PC games, except PS4) */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x04,sf) != 0x00000000) /* null */
|
||||
goto fail;
|
||||
|
||||
/* sometimes LE [Soul Calibur: Broken Destiny (PSP), Tales of Vesperia (PS4) */
|
||||
big_endian = guess_endianness32bit(0x18, sf);
|
||||
big_endian = guess_endian32(0x18, sf);
|
||||
if (big_endian) {
|
||||
read_32bit = read_32bitBE;
|
||||
} else{
|
||||
@ -249,7 +251,7 @@ VGMSTREAM* init_vgmstream_nub_wav(STREAMFILE* sf) {
|
||||
if (read_32bitBE(0x00,sf) != 0x77617600) /* "wav\0" "*/
|
||||
goto fail;
|
||||
|
||||
if (guess_endianness32bit(0x1c, sf)) {
|
||||
if (guess_endian32(0x1c, sf)) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
@ -313,7 +315,7 @@ VGMSTREAM* init_vgmstream_nub_vag(STREAMFILE* sf) {
|
||||
if (read_32bitBE(0x00,sf) != 0x76616700) /* "vag\0" */
|
||||
goto fail;
|
||||
|
||||
if (guess_endianness32bit(0x1c, sf)) {
|
||||
if (guess_endian32(0x1c, sf)) {
|
||||
read_32bit = read_32bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
@ -598,7 +600,7 @@ VGMSTREAM* init_vgmstream_nub_is14(STREAMFILE* sf) {
|
||||
if (read_32bitBE(0x00,sf) != 0x69733134) /* "is14" */
|
||||
goto fail;
|
||||
|
||||
if (guess_endianness32bit(0x1c, sf)) {
|
||||
if (guess_endian32(0x1c, sf)) {
|
||||
read_32bit = read_32bitBE;
|
||||
} else{
|
||||
read_32bit = read_32bitLE;
|
||||
|
@ -133,9 +133,10 @@ VGMSTREAM* init_vgmstream_opus_std(STREAMFILE* sf) {
|
||||
if (read_u32le(0x00,sf) != 0x80000001) /* 'basic info' chunk */
|
||||
goto fail;
|
||||
|
||||
/* .opus: standard
|
||||
* .bgm: Cotton Reboot (Switch) */
|
||||
if (!check_extensions(sf,"opus,lopus,bgm"))
|
||||
/* .opus: standard / .lopus: for plugins
|
||||
* .bgm: Cotton Reboot (Switch)
|
||||
* .opu: Ys Memoire: The Oath in Felghana (Switch) */
|
||||
if (!check_extensions(sf,"opus,lopus,bgm,opu"))
|
||||
goto fail;
|
||||
|
||||
offset = 0x00;
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
|
||||
/* .SBK - from Addiction Pinball (PC) */
|
||||
VGMSTREAM *init_vgmstream_sbk(STREAMFILE *sf) {
|
||||
@ -11,13 +13,12 @@ VGMSTREAM *init_vgmstream_sbk(STREAMFILE *sf) {
|
||||
int target_subsong = sf->stream_index, total_subsongs, loop_flag, is_streamed;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "sbk"))
|
||||
if (!is_id32be(0x00,sf, "RIFF"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x08,sf, "SBNK"))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_u32be(0x00, sf) != 0x52494646) /* "RIFF" */
|
||||
goto fail;
|
||||
if (read_u32be(0x08, sf) != 0x53424E4B) /* "SBNK" */
|
||||
if (!check_extensions(sf, "sbk"))
|
||||
goto fail;
|
||||
|
||||
if (!find_chunk_le(sf, 0x57415649, 0x0c, 0, &table_offset, &table_size)) /* "WAVI" */
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
|
||||
|
||||
/* SEG - from Stormfront games [Eragon (multi), Forgotten Realms: Demon Stone (multi) */
|
||||
VGMSTREAM* init_vgmstream_seg(STREAMFILE* sf) {
|
||||
@ -19,7 +21,7 @@ VGMSTREAM* init_vgmstream_seg(STREAMFILE* sf) {
|
||||
|
||||
codec = read_32bitBE(0x04,sf);
|
||||
/* 0x08: version? (2: Eragon, Spiderwick Chronicles Wii / 3: Spiderwick Chronicles X360 / 4: Spiderwick Chronicles PC) */
|
||||
if (guess_endianness32bit(0x08,sf)) {
|
||||
if (guess_endian32(0x08,sf)) {
|
||||
read_32bit = read_32bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
|
||||
/* SGXD - Sony/SCEI's format (SGB+SGH / SGD / SGX) */
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
|
||||
/* also see init_vgmstream_dsp_sps_n1 and init_vgmstream_opus_sps_n1 */
|
||||
|
||||
@ -21,7 +22,7 @@ VGMSTREAM* init_vgmstream_sps_n1(STREAMFILE* sf) {
|
||||
if (!check_extensions(sf,"sps"))
|
||||
goto fail;
|
||||
|
||||
if (guess_endianness32bit(0x00, sf)) { /* PS3 */
|
||||
if (guess_endian32(0x00, sf)) { /* PS3 */
|
||||
read_u32 = read_u32be;
|
||||
read_u16 = read_u16be;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
|
||||
/* SSPR - Capcom container [Sengoku Basara 4 (PS3/PS4), Mega Man Zero ZX Legacy Collection (PS4)] */
|
||||
VGMSTREAM* init_vgmstream_sspr(STREAMFILE* sf) {
|
||||
@ -21,7 +22,7 @@ VGMSTREAM* init_vgmstream_sspr(STREAMFILE* sf) {
|
||||
/* Simple (audio only) container used some Capcom games (common engine?).
|
||||
* Some files come with a .stqr with unknown data (cues?). */
|
||||
|
||||
big_endian = guess_endianness32bit(0x04, sf); /* 0x01 (version?) */
|
||||
big_endian = guess_endian32(0x04, sf); /* 0x01 (version?) */
|
||||
read_u32 = big_endian ? read_u32be : read_u32le;
|
||||
|
||||
total_subsongs = read_u32(0x08,sf);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
|
||||
/* SXD - Sony/SCE's SNDX lib format (cousin of SGXD) [Gravity Rush, Freedom Wars, Soul Sacrifice PSV] */
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "txth_streamfile.h"
|
||||
#include "../util/text_reader.h"
|
||||
#include "../util/endianness.h"
|
||||
#include "../util/paths.h"
|
||||
|
||||
#define TXT_LINE_MAX 2048 /* probably ~1000 would be ok */
|
||||
#define TXT_LINE_KEY_MAX 128
|
||||
|
@ -1,9 +1,10 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../mixing.h"
|
||||
#include "../plugins.h"
|
||||
#include "../base/mixing.h"
|
||||
#include "../base/plugins.h"
|
||||
#include "../util/text_reader.h"
|
||||
#include "../util/paths.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
#include "ubi_bao_streamfile.h"
|
||||
|
||||
#define BAO_MIN_VERSION 0x1B
|
||||
@ -1570,7 +1571,7 @@ static void config_bao_endian(ubi_bao_header* bao, off_t offset, STREAMFILE* sf)
|
||||
* This could be done once as all BAOs share endianness */
|
||||
|
||||
/* negate as fields looks like LE (0xN0000000) */
|
||||
bao->big_endian = !guess_endianness32bit(offset+bao->cfg.bao_class, sf);
|
||||
bao->big_endian = !guess_endian32(offset+bao->cfg.bao_class, sf);
|
||||
}
|
||||
|
||||
|
||||
@ -1714,7 +1715,7 @@ static int config_bao_version(ubi_bao_header* bao, STREAMFILE* sf) {
|
||||
|
||||
/* next BAO uses machine endianness, entry should always exist
|
||||
* (maybe should use project BAO to detect?) */
|
||||
if (guess_endianness32bit(header_size + 0x04, sf)) {
|
||||
if (guess_endian32(header_size + 0x04, sf)) {
|
||||
version |= 0xFF00; /* signal Wii=BE, but don't modify original */
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
|
||||
typedef enum { MSADPCM, DSP, MP3, XMA2 } ckd_codec;
|
||||
@ -30,7 +31,7 @@ VGMSTREAM* init_vgmstream_ubi_ckd(STREAMFILE* sf) {
|
||||
if (!is_id32be(0x0c,sf, "fmt "))
|
||||
goto fail;
|
||||
|
||||
big_endian = guess_endianness32bit(0x04, sf);
|
||||
big_endian = guess_endian32(0x04, sf);
|
||||
read_u32 = big_endian ? read_u32be : read_u32le;
|
||||
read_u16 = big_endian ? read_u16be : read_u16le;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
|
||||
typedef enum { PCM, UBI, PSX, DSP, XIMA, ATRAC3, XMA2, MP3, SILENCE } ubi_hx_codec;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
|
||||
/* VXN - from Gameloft mobile games */
|
||||
@ -11,11 +12,12 @@ VGMSTREAM* init_vgmstream_vxn(STREAMFILE* sf) {
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00,sf, "VoxN"))
|
||||
goto fail;
|
||||
|
||||
if (!check_extensions(sf,"vxn"))
|
||||
goto fail;
|
||||
|
||||
if (!is_id32be(0x00,sf, "VoxN"))
|
||||
goto fail;
|
||||
/* 0x04: chunk size */
|
||||
/* 0x08: ASCII version? ("0.0.1") */
|
||||
if (read_u32le(0x10,sf) != get_streamfile_size(sf))
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
//#include <ctype.h>
|
||||
|
||||
/* .WBK - seen in some Treyarch games [Spider-Man 2, Ultimate Spider-Man, Call of Duty 2: Big Red One] */
|
||||
|
@ -1,64 +1,65 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
/* XAU - XPEC Entertainment sound format (Beat Down PS2/Xbox, Spectral Force Chronicle [SLPM-65967]) */
|
||||
VGMSTREAM * init_vgmstream_xau(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
/* XAU - XPEC Entertainment sound format [Beat Down (PS2/Xbox), Spectral Force Chronicle (PS2)] */
|
||||
VGMSTREAM* init_vgmstream_xau(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, type, loop_start, loop_end;
|
||||
int loop_flag, channels, type, loop_start, loop_end;
|
||||
|
||||
|
||||
/* check extension */
|
||||
if (!check_extensions(streamFile, "xau"))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x58415500) /* "XAU\0" "*/
|
||||
if (!is_id32be(0x00,sf, "XAU\0"))
|
||||
goto fail;
|
||||
if (read_32bitLE(0x08,streamFile) != 0x40) /* header start */
|
||||
|
||||
if (!check_extensions(sf, "xau"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitLE(0x08,sf) != 0x40) /* header start */
|
||||
goto fail;
|
||||
|
||||
/* 0x04: version? (0x100) */
|
||||
type = read_32bitBE(0x0c, streamFile);
|
||||
loop_start = read_32bitLE(0x10, streamFile);
|
||||
loop_end = read_32bitLE(0x14, streamFile);
|
||||
loop_flag = (loop_end > 0);
|
||||
type = read_32bitBE(0x0c, sf);
|
||||
loop_start = read_32bitLE(0x10, sf);
|
||||
loop_end = read_32bitLE(0x14, sf);
|
||||
loop_flag = (loop_end > 0);
|
||||
|
||||
channel_count = read_8bit(0x18,streamFile);
|
||||
channels = read_8bit(0x18,sf);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->channels = channels;
|
||||
vgmstream->meta_type = meta_XAU;
|
||||
|
||||
/* miniheader over a common header with some tweaks, so we'll simplify parsing */
|
||||
switch(type) {
|
||||
case 0x50533200: /* "PS2\0" */
|
||||
if (read_32bitBE(0x40,streamFile) != 0x56414770) goto fail; /* mutant "VAGp" (long header size) */
|
||||
/* miniheader over a common header with some tweaks, so we'll simplify parsing */
|
||||
switch(type) {
|
||||
case 0x50533200: /* "PS2\0" */
|
||||
if (read_32bitBE(0x40,sf) != 0x56414770) goto fail; /* mutant "VAGp" (long header size) */
|
||||
|
||||
start_offset = 0x800;
|
||||
vgmstream->sample_rate = read_32bitBE(0x50, streamFile);
|
||||
vgmstream->num_samples = ps_bytes_to_samples(read_32bitBE(0x4C,streamFile) * channel_count, channel_count);
|
||||
start_offset = 0x800;
|
||||
vgmstream->sample_rate = read_32bitBE(0x50, sf);
|
||||
vgmstream->num_samples = ps_bytes_to_samples(read_32bitBE(0x4C,sf) * channels, channels);
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x8000;
|
||||
break;
|
||||
vgmstream->interleave_block_size = 0x8000;
|
||||
break;
|
||||
|
||||
case 0x58420000: /* "XB\0\0" */
|
||||
if (read_32bitBE(0x40,streamFile) != 0x52494646) goto fail; /* mutant "RIFF" (sometimes wrong RIFF size) */
|
||||
case 0x58420000: /* "XB\0\0" */
|
||||
if (read_32bitBE(0x40,sf) != 0x52494646) goto fail; /* mutant "RIFF" (sometimes wrong RIFF size) */
|
||||
|
||||
/* start offset: find "data" chunk, as sometimes there is a "smpl" chunk at the start or the end (same as loop_start/end) */
|
||||
if (!find_chunk_le(streamFile, 0x64617461, 0x4c, 0, &start_offset, NULL) )
|
||||
goto fail;
|
||||
/* start offset: find "data" chunk, as sometimes there is a "smpl" chunk at the start or the end (same as loop_start/end) */
|
||||
if (!find_chunk_le(sf, 0x64617461, 0x4c, 0, &start_offset, NULL) )
|
||||
goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(0x58, streamFile);
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bitLE(start_offset-4, streamFile), channel_count);
|
||||
vgmstream->sample_rate = read_32bitLE(0x58, sf);
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bitLE(start_offset-4, sf), channels);
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
|
||||
@ -66,13 +67,13 @@ VGMSTREAM * init_vgmstream_xau(STREAMFILE *streamFile) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
|
@ -2,17 +2,20 @@
|
||||
#define _XNB_STREAMFILE_H_
|
||||
|
||||
//#define XNB_ENABLE_LZX 1
|
||||
#include "../streamfile.h"
|
||||
#include "../util/log.h"
|
||||
|
||||
#include "xnb_lz4mg.h"
|
||||
|
||||
#ifdef XNB_ENABLE_LZX
|
||||
/* lib from https://github.com/sumatrapdfreader/chmlib
|
||||
/* can be safely enabled but useless since LZX isn't used for audio assets
|
||||
* lib from https://github.com/sumatrapdfreader/chmlib
|
||||
* which is a cleaned-up version of https://github.com/jedwing/CHMLib */
|
||||
#include "lzx.h"
|
||||
#include "../utils/lzx.h"
|
||||
|
||||
#define LZX_XNB_WINDOW_BITS 16
|
||||
#endif
|
||||
|
||||
#include "xnb_lz4mg.h"
|
||||
|
||||
|
||||
#define XNB_TYPE_LZX 1
|
||||
#define XNB_TYPE_LZ4 2
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "xvag_streamfile.h"
|
||||
#include "../util/chunks.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
@ -41,12 +42,13 @@ VGMSTREAM* init_vgmstream_xvag(STREAMFILE* sf) {
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00,sf, "XVAG"))
|
||||
goto fail;
|
||||
|
||||
/* .xvag: standard
|
||||
* (extensionless): The Last of Us (PS3) speech files */
|
||||
if (!check_extensions(sf,"xvag,"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x00,sf, "XVAG"))
|
||||
goto fail;
|
||||
|
||||
/* endian flag (XVAGs of the same game can use BE or LE, usually when reusing from other platforms) */
|
||||
xvag.big_endian = read_8bit(0x08,sf) & 0x01;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef _XWB_XSB_H_
|
||||
#define _XWB_XSB_H_
|
||||
#include "meta.h"
|
||||
#include "../util/companion_files.h"
|
||||
|
||||
#define XSB_XACT1_0_MAX 5 /* Unreal Championship (Xbox) */
|
||||
#define XSB_XACT1_1_MAX 8 /* Die Hard: Vendetta (Xbox) */
|
||||
|
351
src/streamfile.c
351
src/streamfile.c
@ -1,6 +1,8 @@
|
||||
#include "streamfile.h"
|
||||
#include "util.h"
|
||||
#include "vgmstream.h"
|
||||
#include "util/reader_sf.h"
|
||||
#include "util/paths.h"
|
||||
#include <string.h>
|
||||
|
||||
/* for dup/fdopen in some systems */
|
||||
@ -8,15 +10,6 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
//TODO: move
|
||||
#ifndef DIR_SEPARATOR
|
||||
#if defined (_WIN32) || defined (WIN32)
|
||||
#define DIR_SEPARATOR '\\'
|
||||
#else
|
||||
#define DIR_SEPARATOR '/'
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* For (rarely needed) +2GB file support we use fseek64/ftell64. Those are usually available
|
||||
* but may depend on compiler.
|
||||
* - MSVC: +VS2008 should work
|
||||
@ -1085,279 +1078,6 @@ STREAMFILE* reopen_streamfile(STREAMFILE* sf, size_t buffer_size) {
|
||||
return sf->open(sf, pathname, buffer_size);
|
||||
}
|
||||
|
||||
/* **************************************************** */
|
||||
|
||||
size_t read_line(char* buf, int buf_size, off_t offset, STREAMFILE* sf, int* p_line_ok) {
|
||||
int i;
|
||||
off_t file_size = get_streamfile_size(sf);
|
||||
int extra_bytes = 0; /* how many bytes over those put in the buffer were read */
|
||||
|
||||
if (p_line_ok) *p_line_ok = 0;
|
||||
|
||||
for (i = 0; i < buf_size-1 && offset+i < file_size; i++) {
|
||||
char in_char = read_8bit(offset+i, sf);
|
||||
/* check for end of line */
|
||||
if (in_char == 0x0d && read_8bit(offset+i+1, sf) == 0x0a) { /* CRLF */
|
||||
extra_bytes = 2;
|
||||
if (p_line_ok) *p_line_ok = 1;
|
||||
break;
|
||||
}
|
||||
else if (in_char == 0x0d || in_char == 0x0a) { /* CR or LF */
|
||||
extra_bytes = 1;
|
||||
if (p_line_ok) *p_line_ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
buf[i] = in_char;
|
||||
}
|
||||
|
||||
buf[i] = '\0';
|
||||
|
||||
/* did we fill the buffer? */
|
||||
if (i == buf_size) {
|
||||
char in_char = read_8bit(offset+i, sf);
|
||||
/* did the bytes we missed just happen to be the end of the line? */
|
||||
if (in_char == 0x0d && read_8bit(offset+i+1, sf) == 0x0a) { /* CRLF */
|
||||
extra_bytes = 2;
|
||||
if (p_line_ok) *p_line_ok = 1;
|
||||
}
|
||||
else if (in_char == 0x0d || in_char == 0x0a) { /* CR or LF */
|
||||
extra_bytes = 1;
|
||||
if (p_line_ok) *p_line_ok = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* did we hit the file end? */
|
||||
if (offset+i == file_size) {
|
||||
/* then we did in fact finish reading the last line */
|
||||
if (p_line_ok) *p_line_ok = 1;
|
||||
}
|
||||
|
||||
return i + extra_bytes;
|
||||
}
|
||||
|
||||
size_t read_bom(STREAMFILE* sf) {
|
||||
if (read_u16le(0x00, sf) == 0xFFFE ||
|
||||
read_u16le(0x00, sf) == 0xFEFF) {
|
||||
return 0x02;
|
||||
}
|
||||
|
||||
if ((read_u32be(0x00, sf) & 0xFFFFFF00) == 0xEFBBBF00) {
|
||||
return 0x03;
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
size_t read_string(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf) {
|
||||
size_t pos;
|
||||
|
||||
for (pos = 0; pos < buf_size; pos++) {
|
||||
uint8_t byte = read_u8(offset + pos, sf);
|
||||
char c = (char)byte;
|
||||
if (buf) buf[pos] = c;
|
||||
if (c == '\0')
|
||||
return pos;
|
||||
if (pos+1 == buf_size) { /* null at maxsize and don't validate (expected to be garbage) */
|
||||
if (buf) buf[pos] = '\0';
|
||||
return buf_size;
|
||||
}
|
||||
/* UTF-8 only goes to 0x7F, but allow a bunch of Windows-1252 codes that some games use */
|
||||
if (byte < 0x20 || byte > 0xF0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
if (buf) buf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t read_string_utf16(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf, int big_endian) {
|
||||
size_t pos, offpos;
|
||||
uint16_t (*read_u16)(off_t,STREAMFILE*) = big_endian ? read_u16be : read_u16le;
|
||||
|
||||
|
||||
for (pos = 0, offpos = 0; pos < buf_size; pos++, offpos += 2) {
|
||||
char c = read_u16(offset + offpos, sf) & 0xFF; /* lower byte for now */
|
||||
if (buf) buf[pos] = c;
|
||||
if (c == '\0')
|
||||
return pos;
|
||||
if (pos+1 == buf_size) { /* null at maxsize and don't validate (expected to be garbage) */
|
||||
if (buf) buf[pos] = '\0';
|
||||
return buf_size;
|
||||
}
|
||||
if (c < 0x20 || (uint8_t)c > 0xA5)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
if (buf) buf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t read_string_utf16le(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf) {
|
||||
return read_string_utf16(buf, buf_size, offset, sf, 0);
|
||||
}
|
||||
size_t read_string_utf16be(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf) {
|
||||
return read_string_utf16(buf, buf_size, offset, sf, 1);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf) {
|
||||
char keyname[PATH_LIMIT];
|
||||
char filename[PATH_LIMIT];
|
||||
const char *path, *ext;
|
||||
STREAMFILE* sf_key = NULL;
|
||||
size_t keysize;
|
||||
|
||||
get_streamfile_name(sf, filename, sizeof(filename));
|
||||
|
||||
if (strlen(filename)+4 > sizeof(keyname)) goto fail;
|
||||
|
||||
/* try to open a keyfile using variations */
|
||||
{
|
||||
ext = strrchr(filename,'.');
|
||||
if (ext!=NULL) ext = ext+1;
|
||||
|
||||
path = strrchr(filename, DIR_SEPARATOR);
|
||||
if (path!=NULL) path = path+1;
|
||||
|
||||
/* "(name.ext)key" */
|
||||
strcpy(keyname, filename);
|
||||
strcat(keyname, "key");
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
|
||||
/* "(name.ext)KEY" */
|
||||
/*
|
||||
strcpy(keyname+strlen(keyname)-3,"KEY");
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
*/
|
||||
|
||||
|
||||
/* "(.ext)key" */
|
||||
if (path) {
|
||||
strcpy(keyname, filename);
|
||||
keyname[path-filename] = '\0';
|
||||
strcat(keyname, ".");
|
||||
} else {
|
||||
strcpy(keyname, ".");
|
||||
}
|
||||
if (ext) strcat(keyname, ext);
|
||||
strcat(keyname, "key");
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
|
||||
/* "(.ext)KEY" */
|
||||
/*
|
||||
strcpy(keyname+strlen(keyname)-3,"KEY");
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
*/
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
found:
|
||||
keysize = get_streamfile_size(sf_key);
|
||||
if (keysize > buf_size) goto fail;
|
||||
|
||||
if (read_streamfile(buf, 0, keysize, sf_key) != keysize)
|
||||
goto fail;
|
||||
|
||||
close_streamfile(sf_key);
|
||||
return keysize;
|
||||
|
||||
fail:
|
||||
close_streamfile(sf_key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
STREAMFILE* read_filemap_file(STREAMFILE* sf, int file_num) {
|
||||
return read_filemap_file_pos(sf, file_num, NULL);
|
||||
}
|
||||
|
||||
STREAMFILE* read_filemap_file_pos(STREAMFILE* sf, int file_num, int* p_pos) {
|
||||
char filename[PATH_LIMIT];
|
||||
off_t txt_offset, file_size;
|
||||
STREAMFILE* sf_map = NULL;
|
||||
int file_pos = 0;
|
||||
|
||||
sf_map = open_streamfile_by_filename(sf, ".txtm");
|
||||
if (!sf_map) goto fail;
|
||||
|
||||
get_streamfile_filename(sf, filename, sizeof(filename));
|
||||
|
||||
txt_offset = read_bom(sf_map);
|
||||
file_size = get_streamfile_size(sf_map);
|
||||
|
||||
/* read lines and find target filename, format is (filename): value1, ... valueN */
|
||||
while (txt_offset < file_size) {
|
||||
char line[0x2000];
|
||||
char key[PATH_LIMIT] = { 0 }, val[0x2000] = { 0 };
|
||||
int ok, bytes_read, line_ok;
|
||||
|
||||
bytes_read = read_line(line, sizeof(line), txt_offset, sf_map, &line_ok);
|
||||
if (!line_ok) goto fail;
|
||||
|
||||
txt_offset += bytes_read;
|
||||
|
||||
/* get key/val (ignores lead/trailing spaces, stops at comment/separator) */
|
||||
ok = sscanf(line, " %[^\t#:] : %[^\t#\r\n] ", key, val);
|
||||
if (ok != 2) { /* ignore line if no key=val (comment or garbage) */
|
||||
/* better way? */
|
||||
if (strcmp(line, "#@reset-pos") == 0) {
|
||||
file_pos = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(key, filename) == 0) {
|
||||
int n;
|
||||
char subval[PATH_LIMIT];
|
||||
const char* current = val;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= file_num; i++) {
|
||||
if (current[0] == '\0')
|
||||
goto fail;
|
||||
|
||||
ok = sscanf(current, " %[^\t#\r\n,]%n ", subval, &n);
|
||||
if (ok != 1)
|
||||
goto fail;
|
||||
|
||||
if (i == file_num) {
|
||||
if (p_pos) *p_pos = file_pos;
|
||||
|
||||
close_streamfile(sf_map);
|
||||
return open_streamfile_by_filename(sf, subval);
|
||||
}
|
||||
|
||||
current += n;
|
||||
if (current[0] == ',')
|
||||
current++;
|
||||
}
|
||||
}
|
||||
file_pos++;
|
||||
}
|
||||
|
||||
fail:
|
||||
close_streamfile(sf_map);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fix_dir_separators(char* filename) {
|
||||
char c;
|
||||
int i = 0;
|
||||
while ((c = filename[i]) != '\0') {
|
||||
if ((c == '\\' && DIR_SEPARATOR == '/') || (c == '/' && DIR_SEPARATOR == '\\'))
|
||||
filename[i] = DIR_SEPARATOR;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
int check_extensions(STREAMFILE* sf, const char* cmp_exts) {
|
||||
@ -1392,73 +1112,6 @@ int check_extensions(STREAMFILE* sf, const char* cmp_exts) {
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
/**
|
||||
* Find a chunk starting from an offset, and save its offset/size (if not NULL), with offset after id/size.
|
||||
* Works for chunked headers in the form of "chunk_id chunk_size (data)"xN (ex. RIFF).
|
||||
* The start_offset should be the first actual chunk (not "RIFF" or "WAVE" but "fmt ").
|
||||
* "full_chunk_size" signals chunk_size includes 4+4+data.
|
||||
*
|
||||
* returns 0 on failure
|
||||
*/
|
||||
static int find_chunk_internal(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_type, int big_endian_size, int zero_size_end) {
|
||||
int32_t (*read_32bit_type)(off_t,STREAMFILE*) = big_endian_type ? read_32bitBE : read_32bitLE;
|
||||
int32_t (*read_32bit_size)(off_t,STREAMFILE*) = big_endian_size ? read_32bitBE : read_32bitLE;
|
||||
off_t offset, max_offset;
|
||||
size_t file_size = get_streamfile_size(sf);
|
||||
|
||||
if (max_size == 0)
|
||||
max_size = file_size;
|
||||
|
||||
offset = start_offset;
|
||||
max_offset = offset + max_size;
|
||||
if (max_offset > file_size)
|
||||
max_offset = file_size;
|
||||
|
||||
|
||||
/* read chunks */
|
||||
while (offset < max_offset) {
|
||||
uint32_t chunk_type = read_32bit_type(offset + 0x00,sf);
|
||||
uint32_t chunk_size = read_32bit_size(offset + 0x04,sf);
|
||||
|
||||
if (chunk_type == 0xFFFFFFFF || chunk_size == 0xFFFFFFFF)
|
||||
return 0;
|
||||
|
||||
if (chunk_type == chunk_id) {
|
||||
if (out_chunk_offset) *out_chunk_offset = offset + 0x08;
|
||||
if (out_chunk_size) *out_chunk_size = chunk_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */
|
||||
if (chunk_size == 0 && zero_size_end)
|
||||
return 0;
|
||||
|
||||
offset += full_chunk_size ? chunk_size : 0x08 + chunk_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int find_chunk_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk(sf, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 1, 0);
|
||||
}
|
||||
int find_chunk_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk(sf, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 0, 0);
|
||||
}
|
||||
int find_chunk(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_size, int zero_size_end) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, 0, full_chunk_size, out_chunk_offset, out_chunk_size, 1, big_endian_size, zero_size_end);
|
||||
}
|
||||
int find_chunk_riff_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 0, 0);
|
||||
}
|
||||
int find_chunk_riff_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 1, 0);
|
||||
}
|
||||
int find_chunk_riff_ve(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, big_endian, big_endian, 0);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
/* copies name as-is (may include full path included) */
|
||||
void get_streamfile_name(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
sf->get_name(sf, buffer, size);
|
||||
|
202
src/streamfile.h
202
src/streamfile.h
@ -161,214 +161,12 @@ static inline size_t get_streamfile_size(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
|
||||
/* Sometimes you just need an int, and we're doing the buffering.
|
||||
* Note, however, that if these fail to read they'll return -1,
|
||||
* so that should not be a valid value or there should be some backup. */
|
||||
static inline int16_t read_16bitLE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[2];
|
||||
|
||||
if (read_streamfile(buf,offset,2,sf)!=2) return -1;
|
||||
return get_16bitLE(buf);
|
||||
}
|
||||
static inline int16_t read_16bitBE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[2];
|
||||
|
||||
if (read_streamfile(buf,offset,2,sf)!=2) return -1;
|
||||
return get_16bitBE(buf);
|
||||
}
|
||||
static inline int32_t read_32bitLE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[4];
|
||||
|
||||
if (read_streamfile(buf,offset,4,sf)!=4) return -1;
|
||||
return get_32bitLE(buf);
|
||||
}
|
||||
static inline int32_t read_32bitBE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[4];
|
||||
|
||||
if (read_streamfile(buf,offset,4,sf)!=4) return -1;
|
||||
return get_32bitBE(buf);
|
||||
}
|
||||
static inline int64_t read_64bitLE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[8];
|
||||
|
||||
if (read_streamfile(buf,offset,8,sf)!=8) return -1;
|
||||
return get_64bitLE(buf);
|
||||
}
|
||||
static inline int64_t read_64bitBE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[8];
|
||||
|
||||
if (read_streamfile(buf,offset,8,sf)!=8) return -1;
|
||||
return get_64bitBE(buf);
|
||||
}
|
||||
static inline int8_t read_8bit(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[1];
|
||||
|
||||
if (read_streamfile(buf,offset,1,sf)!=1) return -1;
|
||||
return buf[0];
|
||||
}
|
||||
|
||||
/* alias of the above */
|
||||
static inline int8_t read_s8 (off_t offset, STREAMFILE* sf) { return read_8bit(offset, sf); }
|
||||
static inline uint8_t read_u8 (off_t offset, STREAMFILE* sf) { return (uint8_t) read_8bit(offset, sf); }
|
||||
static inline int16_t read_s16le(off_t offset, STREAMFILE* sf) { return read_16bitLE(offset, sf); }
|
||||
static inline uint16_t read_u16le(off_t offset, STREAMFILE* sf) { return (uint16_t)read_16bitLE(offset, sf); }
|
||||
static inline int16_t read_s16be(off_t offset, STREAMFILE* sf) { return read_16bitBE(offset, sf); }
|
||||
static inline uint16_t read_u16be(off_t offset, STREAMFILE* sf) { return (uint16_t)read_16bitBE(offset, sf); }
|
||||
static inline int32_t read_s32le(off_t offset, STREAMFILE* sf) { return read_32bitLE(offset, sf); }
|
||||
static inline uint32_t read_u32le(off_t offset, STREAMFILE* sf) { return (uint32_t)read_32bitLE(offset, sf); }
|
||||
static inline int32_t read_s32be(off_t offset, STREAMFILE* sf) { return read_32bitBE(offset, sf); }
|
||||
static inline uint32_t read_u32be(off_t offset, STREAMFILE* sf) { return (uint32_t)read_32bitBE(offset, sf); }
|
||||
static inline int64_t read_s64be(off_t offset, STREAMFILE* sf) { return read_64bitBE(offset, sf); }
|
||||
static inline uint64_t read_u64be(off_t offset, STREAMFILE* sf) { return (uint64_t)read_64bitBE(offset, sf); }
|
||||
static inline int64_t read_s64le(off_t offset, STREAMFILE* sf) { return read_64bitLE(offset, sf); }
|
||||
static inline uint64_t read_u64le(off_t offset, STREAMFILE* sf) { return (uint64_t)read_64bitLE(offset, sf); }
|
||||
|
||||
static inline float read_f32be(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[4];
|
||||
|
||||
if (read_streamfile(buf, offset, sizeof(buf), sf) != sizeof(buf))
|
||||
return -1;
|
||||
return get_f32be(buf);
|
||||
}
|
||||
static inline float read_f32le(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[4];
|
||||
|
||||
if (read_streamfile(buf, offset, sizeof(buf), sf) != sizeof(buf))
|
||||
return -1;
|
||||
return get_f32le(buf);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// on GCC, this reader will be correctly optimized out (as long as it's static/inline), would be same as declaring:
|
||||
// uintXX_t (*read_uXX)(off_t,uint8_t*) = be ? get_uXXbe : get_uXXle;
|
||||
// only for the functions actually used in code, and inlined if possible (like big_endian param being a constant).
|
||||
// on MSVC seems all read_X in sf_reader are compiled and included in the translation unit, plus ignores constants
|
||||
// so may result on bloatness?
|
||||
// (from godbolt tests, test more real cases)
|
||||
|
||||
/* collection of callbacks for quick access */
|
||||
typedef struct sf_reader {
|
||||
int32_t (*read_s32)(off_t,STREAMFILE*); //maybe r.s32
|
||||
float (*read_f32)(off_t,STREAMFILE*);
|
||||
/* ... */
|
||||
} sf_reader;
|
||||
|
||||
static inline void sf_reader_init(sf_reader* r, int big_endian) {
|
||||
memset(r, 0, sizeof(sf_reader));
|
||||
if (big_endian) {
|
||||
r->read_s32 = read_s32be;
|
||||
r->read_f32 = read_f32be;
|
||||
}
|
||||
else {
|
||||
r->read_s32 = read_s32le;
|
||||
r->read_f32 = read_f32le;
|
||||
}
|
||||
}
|
||||
|
||||
/* sf_reader r;
|
||||
* ...
|
||||
* sf_reader_init(&r, big_endian);
|
||||
* val = r.read_s32; //maybe r.s32?
|
||||
*/
|
||||
#endif
|
||||
#if 0 //todo improve + test + simplify code (maybe not inline?)
|
||||
static inline int read_s4h(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t byte = read_u8(offset, streamfile);
|
||||
return get_nibble_signed(byte, 1);
|
||||
}
|
||||
static inline int read_u4h(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t byte = read_u8(offset, streamfile);
|
||||
return (byte >> 4) & 0x0f;
|
||||
}
|
||||
static inline int read_s4l(off_t offset, STREAMFILE* sf) {
|
||||
...
|
||||
}
|
||||
static inline int read_u4l(off_t offset, STREAMFILE* sf) {
|
||||
...
|
||||
}
|
||||
static inline int max_s32(int32_t a, int32_t b) { return a > b ? a : b; }
|
||||
static inline int min_s32(int32_t a, int32_t b) { return a < b ? a : b; }
|
||||
//align32, align16, clamp16, etc
|
||||
#endif
|
||||
|
||||
/* fastest to compare would be read_u32x == (uint32), but should be pre-optimized (see get_id32x) */
|
||||
static inline /*const*/ int is_id32be(off_t offset, STREAMFILE* sf, const char* s) {
|
||||
return read_u32be(offset, sf) == get_id32be(s);
|
||||
}
|
||||
|
||||
static inline /*const*/ int is_id32le(off_t offset, STREAMFILE* sf, const char* s) {
|
||||
return read_u32le(offset, sf) == get_id32be(s);
|
||||
}
|
||||
|
||||
static inline /*const*/ int is_id64be(off_t offset, STREAMFILE* sf, const char* s) {
|
||||
return read_u64be(offset, sf) == get_id64be(s);
|
||||
}
|
||||
|
||||
|
||||
//TODO: maybe move to streamfile.c
|
||||
/* guess byte endianness from a given value, return true if big endian and false if little endian */
|
||||
static inline int guess_endianness16bit(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[0x02];
|
||||
if (read_streamfile(buf, offset, 0x02, sf) != 0x02) return -1; /* ? */
|
||||
return get_u16le(buf) > get_u16be(buf) ? 1 : 0;
|
||||
}
|
||||
static inline int guess_endianness32bit(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[0x04];
|
||||
if (read_streamfile(buf, offset, 0x04, sf) != 0x04) return -1; /* ? */
|
||||
return get_u32le(buf) > get_u32be(buf) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline size_t align_size_to_block(size_t value, size_t block_align) {
|
||||
size_t extra_size = value % block_align;
|
||||
if (extra_size == 0) return value;
|
||||
return (value + block_align - extra_size);
|
||||
}
|
||||
|
||||
/* various STREAMFILE helpers functions */
|
||||
|
||||
/* Read into dst a line delimited by CRLF (Windows) / LF (Unux) / CR (Mac) / EOF, null-terminated
|
||||
* and without line feeds. Returns bytes read (including CR/LF), *not* the same as string length.
|
||||
* p_line_ok is set to 1 if the complete line was read; pass NULL to ignore. */
|
||||
size_t read_line(char* buf, int buf_size, off_t offset, STREAMFILE* sf, int* p_line_ok);
|
||||
|
||||
/* skip BOM if needed */
|
||||
size_t read_bom(STREAMFILE* sf);
|
||||
|
||||
/* reads a c-string (ANSI only), up to bufsize or NULL, returning size. buf is optional (works as get_string_size). */
|
||||
size_t read_string(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf);
|
||||
/* reads a UTF16 string... but actually only as ANSI (discards the upper byte) */
|
||||
size_t read_string_utf16(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf, int big_endian);
|
||||
size_t read_string_utf16le(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf);
|
||||
size_t read_string_utf16be(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf);
|
||||
|
||||
/* Opens a file containing decryption keys and copies to buffer.
|
||||
* Tries "(name.ext)key" (per song), "(.ext)key" (per folder) keynames.
|
||||
* returns size of key if found and copied */
|
||||
size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf);
|
||||
|
||||
/* Opens .txtm file containing file:companion file(-s) mappings and tries to see if there's a match
|
||||
* then loads the associated companion file if one is found */
|
||||
STREAMFILE* read_filemap_file(STREAMFILE *sf, int file_num);
|
||||
STREAMFILE* read_filemap_file_pos(STREAMFILE *sf, int file_num, int* p_pos);
|
||||
|
||||
|
||||
/* hack to allow relative paths in various OSs */
|
||||
void fix_dir_separators(char* filename);
|
||||
|
||||
/* Checks if the stream filename is one of the extensions (comma-separated, ex. "adx" or "adx,aix").
|
||||
* Empty is ok to accept files without extension ("", "adx,,aix"). Returns 0 on failure */
|
||||
int check_extensions(STREAMFILE* sf, const char* cmp_exts);
|
||||
|
||||
/* chunk-style file helpers */
|
||||
int find_chunk_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size);
|
||||
int find_chunk_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size);
|
||||
int find_chunk(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size, int big_endian_size, int zero_size_end);
|
||||
/* find a RIFF-style chunk (with chunk_size not including id and size) */
|
||||
int find_chunk_riff_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size);
|
||||
int find_chunk_riff_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size);
|
||||
/* same with chunk ids in variable endianess (so instead of "fmt " has " tmf" */
|
||||
int find_chunk_riff_ve(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size, int big_endian);
|
||||
|
||||
/* filename helpers */
|
||||
void get_streamfile_name(STREAMFILE* sf, char* buf, size_t size);
|
||||
void get_streamfile_filename(STREAMFILE* sf, char* buf, size_t size);
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* streamtypes.h - widely used type definitions
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _STREAMTYPES_H
|
||||
#define _STREAMTYPES_H
|
||||
|
||||
#include <stddef.h> //size_t
|
||||
#include <stdbool.h> //bool
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* Common versions:
|
||||
* - 1500: VS2008
|
||||
@ -15,25 +16,24 @@
|
||||
* - 1900: VS2015
|
||||
* - 1920: VS2019 */
|
||||
|
||||
#if (_MSC_VER >= 1600)
|
||||
#if (_MSC_VER >= 1600)
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include <pstdint.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#if (_MSC_VER < 1800) && !defined(__cplusplus)
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
|
||||
#if (_MSC_VER < 1900)
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#else
|
||||
#include <pstdint.h>
|
||||
#endif
|
||||
|
||||
#if (_MSC_VER < 1800) && !defined(__cplusplus)
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
|
||||
#if (_MSC_VER < 1900)
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include <stdint.h>
|
||||
|
||||
#endif /* _MSC_VER */
|
||||
|
@ -42,3 +42,12 @@ void concatn(int length, char * dst, const char * src) {
|
||||
dst[i]=src[j];
|
||||
dst[i]='\0';
|
||||
}
|
||||
|
||||
size_t align_size_to_block(size_t value, size_t block_align) {
|
||||
if (!block_align)
|
||||
return 0;
|
||||
|
||||
size_t extra_size = value % block_align;
|
||||
if (extra_size == 0) return value;
|
||||
return (value + block_align - extra_size);
|
||||
}
|
||||
|
@ -51,4 +51,6 @@ const char* filename_extension(const char* pathname);
|
||||
|
||||
void concatn(int length, char * dst, const char * src);
|
||||
|
||||
size_t align_size_to_block(size_t value, size_t block_align);
|
||||
|
||||
#endif
|
||||
|
@ -1,8 +1,11 @@
|
||||
#ifndef _VORBIS_BITREADER_H
|
||||
#define _VORBIS_BITREADER_H
|
||||
#ifndef _BITSTREAM_LSB_H
|
||||
#define _BITSTREAM_LSB_H
|
||||
|
||||
/* Simple bitreader for Vorbis' bit format.
|
||||
* Kept in .h since it's slightly faster (compiler can optimize statics better) */
|
||||
#include "../streamtypes.h"
|
||||
|
||||
/* Simple bitreader for Vorbis' bit style, in 'least significant byte' (LSB) format.
|
||||
* Example: 0x12345678 is read as 12,34,56,78 (continuous).
|
||||
* Kept in .h since it's slightly faster (compiler can optimize statics better using default compile flags). */
|
||||
|
||||
|
||||
typedef struct {
|
||||
@ -12,7 +15,7 @@ typedef struct {
|
||||
} bitstream_t;
|
||||
|
||||
/* convenience util */
|
||||
static void init_bitstream(bitstream_t* b, uint8_t* buf, size_t bufsize) {
|
||||
static inline void bl_setup(bitstream_t* b, uint8_t* buf, size_t bufsize) {
|
||||
b->buf = buf;
|
||||
b->bufsize = bufsize;
|
||||
b->b_off = 0;
|
||||
@ -29,7 +32,7 @@ static const uint32_t MASK_TABLE[33] = {
|
||||
|
||||
/* Read bits (max 32) from buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
|
||||
* (ex. from 2 bytes 00100111 00000001 we can could read 4b=0111 and 6b=010010, 6b=remainder (second value is split into the 2nd byte) */
|
||||
static int rv_bits(bitstream_t* ib, uint32_t bits, uint32_t* value) {
|
||||
static inline int bl_get(bitstream_t* ib, uint32_t bits, uint32_t* value) {
|
||||
uint32_t shift, mask, pos, val;
|
||||
|
||||
if (bits > 32 || ib->b_off + bits > ib->bufsize * 8)
|
||||
@ -59,15 +62,14 @@ static int rv_bits(bitstream_t* ib, uint32_t bits, uint32_t* value) {
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
VGM_LOG_ONCE("BITREADER: read fail\n");
|
||||
//VGM_LOG_ONCE("BITREADER: read fail\n");
|
||||
*value = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef BITSTREAM_READ_ONLY
|
||||
/* Write bits (max 32) to buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
|
||||
* (ex. writing 1101011010 from b_off 2 we get 01101011 00001101 (value split, and 11 in the first byte skipped)*/
|
||||
static int wv_bits(bitstream_t* ob, uint32_t bits, uint32_t value) {
|
||||
static inline int bl_put(bitstream_t* ob, uint32_t bits, uint32_t value) {
|
||||
uint32_t shift, mask, pos;
|
||||
|
||||
if (bits > 32 || ob->b_off + bits > ob->bufsize*8)
|
||||
@ -95,9 +97,8 @@ static int wv_bits(bitstream_t* ob, uint32_t bits, uint32_t value) {
|
||||
ob->b_off += bits;
|
||||
return 1;
|
||||
fail:
|
||||
VGM_LOG_ONCE("BITREADER: write fail\n");
|
||||
//VGM_LOG_ONCE("BITREADER: write fail\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,10 +1,11 @@
|
||||
#ifndef _BITSTREAM_MSB_H
|
||||
#define _BITSTREAM_MSB_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../streamtypes.h"
|
||||
|
||||
/* Simple bitreader for MPEG/standard bit format.
|
||||
* Kept in .h since it's slightly faster (compiler can optimize better) */
|
||||
/* Simple bitreader for MPEG/standard bit style, in 'most significant byte' (MSB) format.
|
||||
* Example: 0x12345678 is read as 78,56,34,12 then each byte's bits.
|
||||
* Kept in .h since it's slightly faster (compiler can optimize statics better using default compile flags). */
|
||||
|
||||
typedef struct {
|
||||
uint8_t* buf; /* buffer to read/write */
|
||||
@ -70,6 +71,7 @@ static inline int bm_get(bitstream_t* ib, uint32_t bits, uint32_t* value) {
|
||||
pos = ib->b_off / 8; /* byte offset */
|
||||
shift = ib->b_off % 8; /* bit sub-offset */
|
||||
|
||||
#if 1 //naive approach
|
||||
val = 0;
|
||||
for (i = 0; i < bits; i++) {
|
||||
bit_buf = (1U << (8-1-shift)) & 0xFF; /* bit check for buf */
|
||||
@ -84,6 +86,35 @@ static inline int bm_get(bitstream_t* ib, uint32_t bits, uint32_t* value) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
#else //has bugs
|
||||
pos = ib->b_off / 8; /* byte offset */
|
||||
shift = ib->b_off % 8; /* bit sub-offset */
|
||||
uint32_t mask = MASK_TABLE[bits]; /* to remove upper in highest byte */
|
||||
|
||||
int left = 0;
|
||||
if (bits == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = ib->buf[pos+0];
|
||||
left = 8 - (bits + shift);
|
||||
if (bits + shift > 8) {
|
||||
val = (val << 8u) | ib->buf[pos+1];
|
||||
left = 16 - (bits + shift);
|
||||
if (bits + shift > 16) {
|
||||
val = (val << 8u) | ib->buf[pos+2];
|
||||
left = 32 - (bits + shift);
|
||||
if (bits + shift > 24) {
|
||||
val = (val << 8u) | ib->buf[pos+3];
|
||||
left = 32 - (bits + shift);
|
||||
if (bits + shift > 32) {
|
||||
val = (val << 8u) | ib->buf[pos+4]; /* upper bits are lost (shifting over 32) */ TO-DO
|
||||
left = 40 - (bits + shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val = ((val >> left) & mask);
|
||||
#endif
|
||||
|
||||
*value = val;
|
||||
ib->b_off += bits;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "chunks.h"
|
||||
//#include "log.h"
|
||||
#include "reader_sf.h"
|
||||
|
||||
|
||||
int next_chunk(chunk_t* chunk, STREAMFILE* sf) {
|
||||
@ -33,3 +33,71 @@ int next_chunk(chunk_t* chunk, STREAMFILE* sf) {
|
||||
/* more chunks remain */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
/**
|
||||
* Find a chunk starting from an offset, and save its offset/size (if not NULL), with offset after id/size.
|
||||
* Works for chunked headers in the form of "chunk_id chunk_size (data)"xN (ex. RIFF).
|
||||
* The start_offset should be the first actual chunk (not "RIFF" or "WAVE" but "fmt ").
|
||||
* "full_chunk_size" signals chunk_size includes 4+4+data.
|
||||
*
|
||||
* returns 0 on failure
|
||||
*/
|
||||
static int find_chunk_internal(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_type, int big_endian_size, int zero_size_end) {
|
||||
int32_t (*read_32bit_type)(off_t,STREAMFILE*) = big_endian_type ? read_32bitBE : read_32bitLE;
|
||||
int32_t (*read_32bit_size)(off_t,STREAMFILE*) = big_endian_size ? read_32bitBE : read_32bitLE;
|
||||
off_t offset, max_offset;
|
||||
size_t file_size = get_streamfile_size(sf);
|
||||
|
||||
if (max_size == 0)
|
||||
max_size = file_size;
|
||||
|
||||
offset = start_offset;
|
||||
max_offset = offset + max_size;
|
||||
if (max_offset > file_size)
|
||||
max_offset = file_size;
|
||||
|
||||
|
||||
/* read chunks */
|
||||
while (offset < max_offset) {
|
||||
uint32_t chunk_type = read_32bit_type(offset + 0x00,sf);
|
||||
uint32_t chunk_size = read_32bit_size(offset + 0x04,sf);
|
||||
|
||||
if (chunk_type == 0xFFFFFFFF || chunk_size == 0xFFFFFFFF)
|
||||
return 0;
|
||||
|
||||
if (chunk_type == chunk_id) {
|
||||
if (out_chunk_offset) *out_chunk_offset = offset + 0x08;
|
||||
if (out_chunk_size) *out_chunk_size = chunk_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */
|
||||
if (chunk_size == 0 && zero_size_end)
|
||||
return 0;
|
||||
|
||||
offset += full_chunk_size ? chunk_size : 0x08 + chunk_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int find_chunk_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk(sf, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 1, 0);
|
||||
}
|
||||
int find_chunk_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk(sf, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 0, 0);
|
||||
}
|
||||
int find_chunk(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_size, int zero_size_end) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, 0, full_chunk_size, out_chunk_offset, out_chunk_size, 1, big_endian_size, zero_size_end);
|
||||
}
|
||||
int find_chunk_riff_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 0, 0);
|
||||
}
|
||||
int find_chunk_riff_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 1, 0);
|
||||
}
|
||||
int find_chunk_riff_ve(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, big_endian, big_endian, 0);
|
||||
}
|
||||
|
@ -26,4 +26,16 @@ enum {
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/* chunk-style file helpers (the above is more performant, this is mainly for quick checks) */
|
||||
int find_chunk_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size);
|
||||
int find_chunk_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size);
|
||||
int find_chunk(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t* p_chunk_offset, size_t* p_chunk_size, int big_endian_size, int zero_size_end);
|
||||
/* find a RIFF-style chunk (with chunk_size not including id and size) */
|
||||
int find_chunk_riff_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size);
|
||||
int find_chunk_riff_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size);
|
||||
/* same with chunk ids in variable endianess (so instead of "fmt " has " tmf" */
|
||||
int find_chunk_riff_ve(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t* p_chunk_offset, size_t* p_chunk_size, int big_endian);
|
||||
|
||||
|
||||
#endif
|
||||
|
149
src/util/companion_files.c
Normal file
149
src/util/companion_files.c
Normal file
@ -0,0 +1,149 @@
|
||||
#include "companion_files.h"
|
||||
#include "paths.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../util/reader_text.h"
|
||||
|
||||
|
||||
size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf) {
|
||||
char keyname[PATH_LIMIT];
|
||||
char filename[PATH_LIMIT];
|
||||
const char *path, *ext;
|
||||
STREAMFILE* sf_key = NULL;
|
||||
size_t keysize;
|
||||
|
||||
get_streamfile_name(sf, filename, sizeof(filename));
|
||||
|
||||
if (strlen(filename)+4 > sizeof(keyname)) goto fail;
|
||||
|
||||
/* try to open a keyfile using variations */
|
||||
{
|
||||
ext = strrchr(filename,'.');
|
||||
if (ext!=NULL) ext = ext+1;
|
||||
|
||||
path = strrchr(filename, DIR_SEPARATOR);
|
||||
if (path!=NULL) path = path+1;
|
||||
|
||||
/* "(name.ext)key" */
|
||||
strcpy(keyname, filename);
|
||||
strcat(keyname, "key");
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
|
||||
/* "(name.ext)KEY" */
|
||||
/*
|
||||
strcpy(keyname+strlen(keyname)-3,"KEY");
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
*/
|
||||
|
||||
|
||||
/* "(.ext)key" */
|
||||
if (path) {
|
||||
strcpy(keyname, filename);
|
||||
keyname[path-filename] = '\0';
|
||||
strcat(keyname, ".");
|
||||
} else {
|
||||
strcpy(keyname, ".");
|
||||
}
|
||||
if (ext) strcat(keyname, ext);
|
||||
strcat(keyname, "key");
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
|
||||
/* "(.ext)KEY" */
|
||||
/*
|
||||
strcpy(keyname+strlen(keyname)-3,"KEY");
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
*/
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
found:
|
||||
keysize = get_streamfile_size(sf_key);
|
||||
if (keysize > buf_size) goto fail;
|
||||
|
||||
if (read_streamfile(buf, 0, keysize, sf_key) != keysize)
|
||||
goto fail;
|
||||
|
||||
close_streamfile(sf_key);
|
||||
return keysize;
|
||||
|
||||
fail:
|
||||
close_streamfile(sf_key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
STREAMFILE* read_filemap_file(STREAMFILE* sf, int file_num) {
|
||||
return read_filemap_file_pos(sf, file_num, NULL);
|
||||
}
|
||||
|
||||
STREAMFILE* read_filemap_file_pos(STREAMFILE* sf, int file_num, int* p_pos) {
|
||||
char filename[PATH_LIMIT];
|
||||
off_t txt_offset, file_size;
|
||||
STREAMFILE* sf_map = NULL;
|
||||
int file_pos = 0;
|
||||
|
||||
sf_map = open_streamfile_by_filename(sf, ".txtm");
|
||||
if (!sf_map) goto fail;
|
||||
|
||||
get_streamfile_filename(sf, filename, sizeof(filename));
|
||||
|
||||
txt_offset = read_bom(sf_map);
|
||||
file_size = get_streamfile_size(sf_map);
|
||||
|
||||
/* read lines and find target filename, format is (filename): value1, ... valueN */
|
||||
while (txt_offset < file_size) {
|
||||
char line[0x2000];
|
||||
char key[PATH_LIMIT] = { 0 }, val[0x2000] = { 0 };
|
||||
int ok, bytes_read, line_ok;
|
||||
|
||||
bytes_read = read_line(line, sizeof(line), txt_offset, sf_map, &line_ok);
|
||||
if (!line_ok) goto fail;
|
||||
|
||||
txt_offset += bytes_read;
|
||||
|
||||
/* get key/val (ignores lead/trailing spaces, stops at comment/separator) */
|
||||
ok = sscanf(line, " %[^\t#:] : %[^\t#\r\n] ", key, val);
|
||||
if (ok != 2) { /* ignore line if no key=val (comment or garbage) */
|
||||
/* better way? */
|
||||
if (strcmp(line, "#@reset-pos") == 0) {
|
||||
file_pos = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(key, filename) == 0) {
|
||||
int n;
|
||||
char subval[PATH_LIMIT];
|
||||
const char* current = val;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= file_num; i++) {
|
||||
if (current[0] == '\0')
|
||||
goto fail;
|
||||
|
||||
ok = sscanf(current, " %[^\t#\r\n,]%n ", subval, &n);
|
||||
if (ok != 1)
|
||||
goto fail;
|
||||
|
||||
if (i == file_num) {
|
||||
if (p_pos) *p_pos = file_pos;
|
||||
|
||||
close_streamfile(sf_map);
|
||||
return open_streamfile_by_filename(sf, subval);
|
||||
}
|
||||
|
||||
current += n;
|
||||
if (current[0] == ',')
|
||||
current++;
|
||||
}
|
||||
}
|
||||
file_pos++;
|
||||
}
|
||||
|
||||
fail:
|
||||
close_streamfile(sf_map);
|
||||
return NULL;
|
||||
}
|
16
src/util/companion_files.h
Normal file
16
src/util/companion_files.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef _COMPANION_FILES_H
|
||||
#define _COMPANION_FILES_H
|
||||
|
||||
#include "../streamfile.h"
|
||||
|
||||
/* Opens a file containing decryption keys and copies to buffer.
|
||||
* Tries "(name.ext)key" (per song), "(.ext)key" (per folder) keynames.
|
||||
* returns size of key if found and copied */
|
||||
size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf);
|
||||
|
||||
/* Opens .txtm file containing file:companion file(-s) mappings and tries to see if there's a match
|
||||
* then loads the associated companion file if one is found */
|
||||
STREAMFILE* read_filemap_file(STREAMFILE *sf, int file_num);
|
||||
STREAMFILE* read_filemap_file_pos(STREAMFILE *sf, int file_num, int* p_pos);
|
||||
|
||||
#endif
|
@ -1,5 +1,6 @@
|
||||
#include "cri_utf.h"
|
||||
#include "log.h"
|
||||
#include "reader_sf.h"
|
||||
|
||||
#define UTF_MAX_SCHEMA_SIZE 0x8000 /* arbitrary max */
|
||||
#define COLUMN_BITMASK_FLAG 0xf0
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define _UTIL_ENDIAN_H
|
||||
|
||||
#include "../streamfile.h"
|
||||
#include "reader_get.h"
|
||||
|
||||
typedef uint32_t (*read_u32_t)(off_t, STREAMFILE*);
|
||||
typedef int32_t (*read_s32_t)(off_t, STREAMFILE*);
|
||||
@ -11,8 +12,17 @@ typedef float (*read_f32_t)(off_t, STREAMFILE*);
|
||||
|
||||
typedef int16_t (*get_s16_t)(const uint8_t*);
|
||||
|
||||
//todo move here
|
||||
#define guess_endian32 guess_endianness32bit
|
||||
#define guess_endian16 guess_endianness16bit
|
||||
/* guess byte endianness from a given value, return true if big endian and false if little endian */
|
||||
static inline int guess_endian16(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[0x02];
|
||||
if (read_streamfile(buf, offset, 0x02, sf) != 0x02) return -1; /* ? */
|
||||
return get_u16le(buf) > get_u16be(buf) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline int guess_endian32(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[0x04];
|
||||
if (read_streamfile(buf, offset, 0x04, sf) != 0x04) return -1; /* ? */
|
||||
return get_u32le(buf) > get_u32be(buf) ? 1 : 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
11
src/util/paths.c
Normal file
11
src/util/paths.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include "paths.h"
|
||||
|
||||
void fix_dir_separators(char* filename) {
|
||||
char c;
|
||||
int i = 0;
|
||||
while ((c = filename[i]) != '\0') {
|
||||
if ((c == '\\' && DIR_SEPARATOR == '/') || (c == '/' && DIR_SEPARATOR == '\\'))
|
||||
filename[i] = DIR_SEPARATOR;
|
||||
i++;
|
||||
}
|
||||
}
|
17
src/util/paths.h
Normal file
17
src/util/paths.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef _PATHS_H
|
||||
#define _PATHS_H
|
||||
|
||||
#ifndef DIR_SEPARATOR
|
||||
#if defined (_WIN32) || defined (WIN32)
|
||||
#define DIR_SEPARATOR '\\'
|
||||
#else
|
||||
#define DIR_SEPARATOR '/'
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* hack to allow relative paths in various OSs */
|
||||
void fix_dir_separators(char* filename);
|
||||
|
||||
//const char* filename_extension(const char* pathname);
|
||||
|
||||
#endif
|
149
src/util/reader.c
Normal file
149
src/util/reader.c
Normal file
@ -0,0 +1,149 @@
|
||||
#include "reader_put.h"
|
||||
#include "reader_text.h"
|
||||
#include "reader_sf.h"
|
||||
#include "endianness.h"
|
||||
|
||||
void put_8bit(uint8_t* buf, int8_t i) {
|
||||
buf[0] = i;
|
||||
}
|
||||
|
||||
void put_16bitLE(uint8_t* buf, int16_t i) {
|
||||
buf[0] = (i & 0xFF);
|
||||
buf[1] = i >> 8;
|
||||
}
|
||||
|
||||
void put_32bitLE(uint8_t* buf, int32_t i) {
|
||||
buf[0] = (uint8_t)(i & 0xFF);
|
||||
buf[1] = (uint8_t)((i >> 8) & 0xFF);
|
||||
buf[2] = (uint8_t)((i >> 16) & 0xFF);
|
||||
buf[3] = (uint8_t)((i >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
void put_16bitBE(uint8_t* buf, int16_t i) {
|
||||
buf[0] = i >> 8;
|
||||
buf[1] = (i & 0xFF);
|
||||
}
|
||||
|
||||
void put_32bitBE(uint8_t* buf, int32_t i) {
|
||||
buf[0] = (uint8_t)((i >> 24) & 0xFF);
|
||||
buf[1] = (uint8_t)((i >> 16) & 0xFF);
|
||||
buf[2] = (uint8_t)((i >> 8) & 0xFF);
|
||||
buf[3] = (uint8_t)(i & 0xFF);
|
||||
}
|
||||
|
||||
/* **************************************************** */
|
||||
|
||||
size_t read_line(char* buf, int buf_size, off_t offset, STREAMFILE* sf, int* p_line_ok) {
|
||||
int i;
|
||||
off_t file_size = get_streamfile_size(sf);
|
||||
int extra_bytes = 0; /* how many bytes over those put in the buffer were read */
|
||||
|
||||
if (p_line_ok) *p_line_ok = 0;
|
||||
|
||||
for (i = 0; i < buf_size-1 && offset+i < file_size; i++) {
|
||||
char in_char = read_8bit(offset+i, sf);
|
||||
/* check for end of line */
|
||||
if (in_char == 0x0d && read_8bit(offset+i+1, sf) == 0x0a) { /* CRLF */
|
||||
extra_bytes = 2;
|
||||
if (p_line_ok) *p_line_ok = 1;
|
||||
break;
|
||||
}
|
||||
else if (in_char == 0x0d || in_char == 0x0a) { /* CR or LF */
|
||||
extra_bytes = 1;
|
||||
if (p_line_ok) *p_line_ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
buf[i] = in_char;
|
||||
}
|
||||
|
||||
buf[i] = '\0';
|
||||
|
||||
/* did we fill the buffer? */
|
||||
if (i == buf_size) {
|
||||
char in_char = read_8bit(offset+i, sf);
|
||||
/* did the bytes we missed just happen to be the end of the line? */
|
||||
if (in_char == 0x0d && read_8bit(offset+i+1, sf) == 0x0a) { /* CRLF */
|
||||
extra_bytes = 2;
|
||||
if (p_line_ok) *p_line_ok = 1;
|
||||
}
|
||||
else if (in_char == 0x0d || in_char == 0x0a) { /* CR or LF */
|
||||
extra_bytes = 1;
|
||||
if (p_line_ok) *p_line_ok = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* did we hit the file end? */
|
||||
if (offset+i == file_size) {
|
||||
/* then we did in fact finish reading the last line */
|
||||
if (p_line_ok) *p_line_ok = 1;
|
||||
}
|
||||
|
||||
return i + extra_bytes;
|
||||
}
|
||||
|
||||
size_t read_bom(STREAMFILE* sf) {
|
||||
if (read_u16le(0x00, sf) == 0xFFFE ||
|
||||
read_u16le(0x00, sf) == 0xFEFF) {
|
||||
return 0x02;
|
||||
}
|
||||
|
||||
if ((read_u32be(0x00, sf) & 0xFFFFFF00) == 0xEFBBBF00) {
|
||||
return 0x03;
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
size_t read_string(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf) {
|
||||
size_t pos;
|
||||
|
||||
for (pos = 0; pos < buf_size; pos++) {
|
||||
uint8_t byte = read_u8(offset + pos, sf);
|
||||
char c = (char)byte;
|
||||
if (buf) buf[pos] = c;
|
||||
if (c == '\0')
|
||||
return pos;
|
||||
if (pos+1 == buf_size) { /* null at maxsize and don't validate (expected to be garbage) */
|
||||
if (buf) buf[pos] = '\0';
|
||||
return buf_size;
|
||||
}
|
||||
/* UTF-8 only goes to 0x7F, but allow a bunch of Windows-1252 codes that some games use */
|
||||
if (byte < 0x20 || byte > 0xF0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
if (buf) buf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t read_string_utf16(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf, int big_endian) {
|
||||
size_t pos, offpos;
|
||||
read_u16_t read_u16 = big_endian ? read_u16be : read_u16le;
|
||||
|
||||
|
||||
for (pos = 0, offpos = 0; pos < buf_size; pos++, offpos += 2) {
|
||||
char c = read_u16(offset + offpos, sf) & 0xFF; /* lower byte for now */
|
||||
if (buf) buf[pos] = c;
|
||||
if (c == '\0')
|
||||
return pos;
|
||||
if (pos+1 == buf_size) { /* null at maxsize and don't validate (expected to be garbage) */
|
||||
if (buf) buf[pos] = '\0';
|
||||
return buf_size;
|
||||
}
|
||||
if (c < 0x20 || (uint8_t)c > 0xA5)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
if (buf) buf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t read_string_utf16le(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf) {
|
||||
return read_string_utf16(buf, buf_size, offset, sf, 0);
|
||||
}
|
||||
size_t read_string_utf16be(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf) {
|
||||
return read_string_utf16(buf, buf_size, offset, sf, 1);
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
#include "reader_put.h"
|
||||
|
||||
void put_8bit(uint8_t * buf, int8_t i) {
|
||||
buf[0] = i;
|
||||
}
|
||||
|
||||
void put_16bitLE(uint8_t * buf, int16_t i) {
|
||||
buf[0] = (i & 0xFF);
|
||||
buf[1] = i >> 8;
|
||||
}
|
||||
|
||||
void put_32bitLE(uint8_t * buf, int32_t i) {
|
||||
buf[0] = (uint8_t)(i & 0xFF);
|
||||
buf[1] = (uint8_t)((i >> 8) & 0xFF);
|
||||
buf[2] = (uint8_t)((i >> 16) & 0xFF);
|
||||
buf[3] = (uint8_t)((i >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
void put_16bitBE(uint8_t * buf, int16_t i) {
|
||||
buf[0] = i >> 8;
|
||||
buf[1] = (i & 0xFF);
|
||||
}
|
||||
|
||||
void put_32bitBE(uint8_t * buf, int32_t i) {
|
||||
buf[0] = (uint8_t)((i >> 24) & 0xFF);
|
||||
buf[1] = (uint8_t)((i >> 16) & 0xFF);
|
||||
buf[2] = (uint8_t)((i >> 8) & 0xFF);
|
||||
buf[3] = (uint8_t)(i & 0xFF);
|
||||
}
|
149
src/util/reader_sf.h
Normal file
149
src/util/reader_sf.h
Normal file
@ -0,0 +1,149 @@
|
||||
#ifndef _READER_SF_H
|
||||
#define _READER_SF_H
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
/* Sometimes you just need an int, and we're doing the buffering.
|
||||
* Note, however, that if these fail to read they'll return -1,
|
||||
* so that should not be a valid value or there should be some backup. */
|
||||
static inline int16_t read_16bitLE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[2];
|
||||
|
||||
if (read_streamfile(buf,offset,2,sf)!=2) return -1;
|
||||
return get_16bitLE(buf);
|
||||
}
|
||||
static inline int16_t read_16bitBE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[2];
|
||||
|
||||
if (read_streamfile(buf,offset,2,sf)!=2) return -1;
|
||||
return get_16bitBE(buf);
|
||||
}
|
||||
static inline int32_t read_32bitLE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[4];
|
||||
|
||||
if (read_streamfile(buf,offset,4,sf)!=4) return -1;
|
||||
return get_32bitLE(buf);
|
||||
}
|
||||
static inline int32_t read_32bitBE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[4];
|
||||
|
||||
if (read_streamfile(buf,offset,4,sf)!=4) return -1;
|
||||
return get_32bitBE(buf);
|
||||
}
|
||||
static inline int64_t read_64bitLE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[8];
|
||||
|
||||
if (read_streamfile(buf,offset,8,sf)!=8) return -1;
|
||||
return get_64bitLE(buf);
|
||||
}
|
||||
static inline int64_t read_64bitBE(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[8];
|
||||
|
||||
if (read_streamfile(buf,offset,8,sf)!=8) return -1;
|
||||
return get_64bitBE(buf);
|
||||
}
|
||||
static inline int8_t read_8bit(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[1];
|
||||
|
||||
if (read_streamfile(buf,offset,1,sf)!=1) return -1;
|
||||
return buf[0];
|
||||
}
|
||||
|
||||
/* alias of the above */
|
||||
static inline int8_t read_s8 (off_t offset, STREAMFILE* sf) { return read_8bit(offset, sf); }
|
||||
static inline uint8_t read_u8 (off_t offset, STREAMFILE* sf) { return (uint8_t) read_8bit(offset, sf); }
|
||||
static inline int16_t read_s16le(off_t offset, STREAMFILE* sf) { return read_16bitLE(offset, sf); }
|
||||
static inline uint16_t read_u16le(off_t offset, STREAMFILE* sf) { return (uint16_t)read_16bitLE(offset, sf); }
|
||||
static inline int16_t read_s16be(off_t offset, STREAMFILE* sf) { return read_16bitBE(offset, sf); }
|
||||
static inline uint16_t read_u16be(off_t offset, STREAMFILE* sf) { return (uint16_t)read_16bitBE(offset, sf); }
|
||||
static inline int32_t read_s32le(off_t offset, STREAMFILE* sf) { return read_32bitLE(offset, sf); }
|
||||
static inline uint32_t read_u32le(off_t offset, STREAMFILE* sf) { return (uint32_t)read_32bitLE(offset, sf); }
|
||||
static inline int32_t read_s32be(off_t offset, STREAMFILE* sf) { return read_32bitBE(offset, sf); }
|
||||
static inline uint32_t read_u32be(off_t offset, STREAMFILE* sf) { return (uint32_t)read_32bitBE(offset, sf); }
|
||||
static inline int64_t read_s64be(off_t offset, STREAMFILE* sf) { return read_64bitBE(offset, sf); }
|
||||
static inline uint64_t read_u64be(off_t offset, STREAMFILE* sf) { return (uint64_t)read_64bitBE(offset, sf); }
|
||||
static inline int64_t read_s64le(off_t offset, STREAMFILE* sf) { return read_64bitLE(offset, sf); }
|
||||
static inline uint64_t read_u64le(off_t offset, STREAMFILE* sf) { return (uint64_t)read_64bitLE(offset, sf); }
|
||||
|
||||
static inline float read_f32be(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[4];
|
||||
|
||||
if (read_streamfile(buf, offset, sizeof(buf), sf) != sizeof(buf))
|
||||
return -1;
|
||||
return get_f32be(buf);
|
||||
}
|
||||
static inline float read_f32le(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[4];
|
||||
|
||||
if (read_streamfile(buf, offset, sizeof(buf), sf) != sizeof(buf))
|
||||
return -1;
|
||||
return get_f32le(buf);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// on GCC, this reader will be correctly optimized out (as long as it's static/inline), would be same as declaring:
|
||||
// uintXX_t (*read_uXX)(off_t,uint8_t*) = be ? get_uXXbe : get_uXXle;
|
||||
// only for the functions actually used in code, and inlined if possible (like big_endian param being a constant).
|
||||
// on MSVC seems all read_X in sf_reader are compiled and included in the translation unit, plus ignores constants
|
||||
// so may result on bloatness?
|
||||
// (from godbolt tests, test more real cases)
|
||||
|
||||
/* collection of callbacks for quick access */
|
||||
typedef struct sf_reader {
|
||||
int32_t (*read_s32)(off_t,STREAMFILE*); //maybe r.s32
|
||||
float (*read_f32)(off_t,STREAMFILE*);
|
||||
/* ... */
|
||||
} sf_reader;
|
||||
|
||||
static inline void sf_reader_init(sf_reader* r, int big_endian) {
|
||||
memset(r, 0, sizeof(sf_reader));
|
||||
if (big_endian) {
|
||||
r->read_s32 = read_s32be;
|
||||
r->read_f32 = read_f32be;
|
||||
}
|
||||
else {
|
||||
r->read_s32 = read_s32le;
|
||||
r->read_f32 = read_f32le;
|
||||
}
|
||||
}
|
||||
|
||||
/* sf_reader r;
|
||||
* ...
|
||||
* sf_reader_init(&r, big_endian);
|
||||
* val = r.read_s32; //maybe r.s32?
|
||||
*/
|
||||
#endif
|
||||
#if 0 //todo improve + test + simplify code (maybe not inline?)
|
||||
static inline int read_s4h(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t byte = read_u8(offset, streamfile);
|
||||
return get_nibble_signed(byte, 1);
|
||||
}
|
||||
static inline int read_u4h(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t byte = read_u8(offset, streamfile);
|
||||
return (byte >> 4) & 0x0f;
|
||||
}
|
||||
static inline int read_s4l(off_t offset, STREAMFILE* sf) {
|
||||
...
|
||||
}
|
||||
static inline int read_u4l(off_t offset, STREAMFILE* sf) {
|
||||
...
|
||||
}
|
||||
static inline int max_s32(int32_t a, int32_t b) { return a > b ? a : b; }
|
||||
static inline int min_s32(int32_t a, int32_t b) { return a < b ? a : b; }
|
||||
//align32, align16, clamp16, etc
|
||||
#endif
|
||||
|
||||
/* fastest to compare would be read_u32x == (uint32), but should be pre-optimized (see get_id32x) */
|
||||
static inline /*const*/ int is_id32be(off_t offset, STREAMFILE* sf, const char* s) {
|
||||
return read_u32be(offset, sf) == get_id32be(s);
|
||||
}
|
||||
|
||||
static inline /*const*/ int is_id32le(off_t offset, STREAMFILE* sf, const char* s) {
|
||||
return read_u32le(offset, sf) == get_id32be(s);
|
||||
}
|
||||
|
||||
static inline /*const*/ int is_id64be(off_t offset, STREAMFILE* sf, const char* s) {
|
||||
return read_u64be(offset, sf) == get_id64be(s);
|
||||
}
|
||||
|
||||
#endif
|
21
src/util/reader_text.h
Normal file
21
src/util/reader_text.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef _READER_TEXT_H
|
||||
#define _READER_TEXT_H
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
/* Read into dst a line delimited by CRLF (Windows) / LF (Unux) / CR (Mac) / EOF, null-terminated
|
||||
* and without line feeds. Returns bytes read (including CR/LF), *not* the same as string length.
|
||||
* p_line_ok is set to 1 if the complete line was read; pass NULL to ignore. */
|
||||
size_t read_line(char* buf, int buf_size, off_t offset, STREAMFILE* sf, int* p_line_ok);
|
||||
|
||||
/* skip BOM if needed */
|
||||
size_t read_bom(STREAMFILE* sf);
|
||||
|
||||
/* reads a c-string (ANSI only), up to bufsize or NULL, returning size. buf is optional (works as get_string_size). */
|
||||
size_t read_string(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf);
|
||||
/* reads a UTF16 string... but actually only as ANSI (discards the upper byte) */
|
||||
size_t read_string_utf16(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf, int big_endian);
|
||||
size_t read_string_utf16le(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf);
|
||||
size_t read_string_utf16be(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf);
|
||||
|
||||
#endif
|
@ -9,15 +9,16 @@
|
||||
#include "meta/meta.h"
|
||||
#include "layout/layout.h"
|
||||
#include "coding/coding.h"
|
||||
#include "decode.h"
|
||||
#include "render.h"
|
||||
#include "mixing.h"
|
||||
#include "base/decode.h"
|
||||
#include "base/render.h"
|
||||
#include "base/mixing.h"
|
||||
|
||||
static void try_dual_file_stereo(VGMSTREAM* opened_vgmstream, STREAMFILE* sf, VGMSTREAM* (*init_vgmstream_function)(STREAMFILE*));
|
||||
typedef VGMSTREAM* (*init_vgmstream_t)(STREAMFILE*);
|
||||
|
||||
static void try_dual_file_stereo(VGMSTREAM* opened_vgmstream, STREAMFILE* sf, init_vgmstream_t init_vgmstream_function);
|
||||
|
||||
/* list of metadata parser functions that will recognize files, used on init */
|
||||
VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
init_vgmstream_t init_vgmstream_functions[] = {
|
||||
init_vgmstream_adx,
|
||||
init_vgmstream_brstm,
|
||||
init_vgmstream_brwav,
|
||||
@ -563,25 +564,25 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
#endif
|
||||
};
|
||||
|
||||
#define LOCAL_ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
|
||||
static const int init_vgmstream_count = LOCAL_ARRAY_LENGTH(init_vgmstream_functions);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* INIT/META */
|
||||
/*****************************************************************************/
|
||||
#define LOCAL_ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
|
||||
|
||||
/* internal version with all parameters */
|
||||
static VGMSTREAM* init_vgmstream_internal(STREAMFILE* sf) {
|
||||
int i, fcns_count;
|
||||
|
||||
if (!sf)
|
||||
return NULL;
|
||||
|
||||
fcns_count = LOCAL_ARRAY_LENGTH(init_vgmstream_functions);
|
||||
|
||||
/* try a series of formats, see which works */
|
||||
for (i = 0; i < fcns_count; i++) {
|
||||
for (int i = 0; i < init_vgmstream_count; i++) {
|
||||
init_vgmstream_t init_vgmstream_function = init_vgmstream_functions[i];
|
||||
|
||||
|
||||
/* call init function and see if valid VGMSTREAM was returned */
|
||||
VGMSTREAM* vgmstream = (init_vgmstream_functions[i])(sf);
|
||||
VGMSTREAM* vgmstream = init_vgmstream_function(sf);
|
||||
if (!vgmstream)
|
||||
continue;
|
||||
|
||||
@ -614,7 +615,7 @@ static VGMSTREAM* init_vgmstream_internal(STREAMFILE* sf) {
|
||||
|
||||
/* test if candidate for dual stereo */
|
||||
if (vgmstream->channels == 1 && vgmstream->allow_dual_stereo == 1) {
|
||||
try_dual_file_stereo(vgmstream, sf, init_vgmstream_functions[i]);
|
||||
try_dual_file_stereo(vgmstream, sf, init_vgmstream_function);
|
||||
}
|
||||
|
||||
/* clean as loops are readable metadata but loop fields may contain garbage
|
||||
@ -714,9 +715,9 @@ void reset_vgmstream(VGMSTREAM* vgmstream) {
|
||||
* Otherwise hit_loop will be 0 and it will be copied over anyway when we
|
||||
* really hit the loop start. */
|
||||
|
||||
reset_codec(vgmstream);
|
||||
decode_reset(vgmstream);
|
||||
|
||||
reset_layout(vgmstream);
|
||||
render_reset(vgmstream);
|
||||
|
||||
/* note that this does not reset the constituent STREAMFILES
|
||||
* (vgmstream->ch[N].streamfiles' internal state, like internal offset, though shouldn't matter) */
|
||||
@ -737,7 +738,7 @@ VGMSTREAM* allocate_vgmstream(int channel_count, int loop_flag) {
|
||||
* - ch: config+state per channel, also modified by those
|
||||
* - start_vgmstream: vgmstream clone copied on init_vgmstream and restored on reset_vgmstream
|
||||
* - start_ch: ch clone copied on init_vgmstream and restored on reset_vgmstream
|
||||
* - loop_ch: ch clone copied on loop start and restored on loop end (vgmstream_do_loop)
|
||||
* - loop_ch: ch clone copied on loop start and restored on loop end (decode_do_loop)
|
||||
* - codec/layout_data: custom state for complex codecs or layouts, handled externally
|
||||
*
|
||||
* Here we only create the basic structs to be filled, and only after init_vgmstream it
|
||||
@ -799,10 +800,10 @@ void close_vgmstream(VGMSTREAM* vgmstream) {
|
||||
if (!vgmstream)
|
||||
return;
|
||||
|
||||
free_codec(vgmstream);
|
||||
decode_free(vgmstream);
|
||||
vgmstream->codec_data = NULL;
|
||||
|
||||
free_layout(vgmstream);
|
||||
render_free(vgmstream);
|
||||
vgmstream->layout_data = NULL;
|
||||
|
||||
|
||||
@ -915,7 +916,7 @@ void vgmstream_set_loop_target(VGMSTREAM* vgmstream, int loop_target) {
|
||||
|
||||
/* See if there is a second file which may be the second channel, given an already opened mono vgmstream.
|
||||
* If a suitable file is found, open it and change opened_vgmstream to a stereo vgmstream. */
|
||||
static void try_dual_file_stereo(VGMSTREAM* opened_vgmstream, STREAMFILE* sf, VGMSTREAM*(*init_vgmstream_function)(STREAMFILE*)) {
|
||||
static void try_dual_file_stereo(VGMSTREAM* opened_vgmstream, STREAMFILE* sf, init_vgmstream_t init_vgmstream_function) {
|
||||
/* filename search pairs for dual file stereo */
|
||||
static const char* const dfs_pairs[][2] = {
|
||||
{"L","R"}, /* most common in .dsp and .vag */
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "../src/vgmstream.h"
|
||||
#include "../src/plugins.h"
|
||||
#include "../src/api.h"
|
||||
#include "sdk/in2.h"
|
||||
#include "sdk/wa_ipc.h"
|
||||
#include "sdk/ipc_pe.h"
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#include "xmpin.h"
|
||||
#include "../src/vgmstream.h"
|
||||
#include "../src/plugins.h"
|
||||
#include "../src/api.h"
|
||||
|
||||
|
||||
#include "../version.h"
|
||||
|
Loading…
Reference in New Issue
Block a user