Merge pull request #1561 from bnnm/api-misc3

- Fix some .agsc [Metroid Prime (GC)]
- Remove fake .b1s format (use .txth)
- Remove fake format .ffw (use .txth)
- cleanup
This commit is contained in:
bnnm 2024-07-21 22:27:46 +02:00 committed by GitHub
commit ae16779577
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 551 additions and 518 deletions

View File

@ -1,7 +1,7 @@
# CLI
add_executable(vgmstream_cli
vgmstream_cli.c)
vgmstream_cli.c wav_utils.c)
set_target_properties(vgmstream_cli PROPERTIES
PREFIX ""
@ -67,7 +67,7 @@ if(NOT WIN32 AND BUILD_V123)
# vgmstream123
add_executable(vgmstream123
vgmstream123.c)
vgmstream123.c wav_utils.c)
# Link to the vgmstream library as well as libao
target_link_libraries(vgmstream123

View File

@ -41,11 +41,11 @@ export CFLAGS LDFLAGS
### targets
vgmstream_cli: libvgmstream.a $(TARGET_EXT_LIBS)
$(CC) $(CFLAGS) vgmstream_cli.c $(LDFLAGS) -o $(OUTPUT_CLI)
$(CC) $(CFLAGS) vgmstream_cli.c wav_utils.c $(LDFLAGS) -o $(OUTPUT_CLI)
$(STRIP) $(OUTPUT_CLI)
vgmstream123: libvgmstream.a $(TARGET_EXT_LIBS)
$(CC) $(CFLAGS) $(LIBAO_INC) vgmstream123.c $(LDFLAGS) $(LIBAO_LIB) -o $(OUTPUT_123)
$(CC) $(CFLAGS) $(LIBAO_INC) vgmstream123.c wav_utils.c $(LDFLAGS) $(LIBAO_LIB) -o $(OUTPUT_123)
$(STRIP) $(OUTPUT_123)
api_example: libvgmstream.a $(TARGET_EXT_LIBS)

View File

@ -9,8 +9,8 @@ endif
AM_CFLAGS = -DVGMSTREAM_VERSION_AUTO -DVGM_LOG_OUTPUT -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/ $(AO_CFLAGS)
AM_MAKEFLAGS = -f Makefile.autotools
vgmstream_cli_SOURCES = vgmstream_cli.c
vgmstream_cli_SOURCES = vgmstream_cli.c wav_utils.c
vgmstream_cli_LDADD = ../src/libvgmstream.la
vgmstream123_SOURCES = vgmstream123.c
vgmstream123_SOURCES = vgmstream123.c wav_utils.c
vgmstream123_LDADD = ../src/libvgmstream.la $(AO_LIBS)

View File

@ -39,7 +39,6 @@
#include "../src/vgmstream.h"
#include "../src/api.h"
#include "../src/util/samples_ops.h"
#include "../version.h"
#ifndef VGMSTREAM_VERSION
@ -397,7 +396,7 @@ static int play_vgmstream(const char* filename, song_settings_t* cfg) {
render_vgmstream(buffer, to_do, vgmstream);
#if LITTLE_ENDIAN_OUTPUT
swap_samples_le(buffer, output_channels * to_do);
swap_samples_le(buffer, output_channels * to_do, 0);
#endif
if (verbose && !out_filename) {

View File

@ -4,10 +4,10 @@
#define POSIXLY_CORRECT
#include <getopt.h>
#include "wav_utils.h"
#include "../src/vgmstream.h"
#include "../src/api.h"
#include "../src/util.h"
#include "../src/util/samples_ops.h"
//todo use <>?
#ifdef HAVE_JSON
#include "jansson/jansson.h"
@ -48,8 +48,6 @@
//extern int optind, opterr, optopt;
static size_t make_wav_header(uint8_t* buf, size_t buf_size, int32_t sample_count, int32_t sample_rate, int channels, int smpl_chunk, int32_t loop_start, int32_t loop_end);
static void usage(const char* progname, int is_help) {
fprintf(is_help ? stdout : stderr, APP_INFO "\n"
@ -901,7 +899,7 @@ static int write_file(VGMSTREAM* vgmstream, cli_config* cfg) {
render_vgmstream(buf, to_get, vgmstream);
swap_samples_le(buf, channels * to_get); /* change to WAV (LE) endian if PC is Big Endian */
swap_samples_le(buf, channels * to_get, 0);
fwrite(buf, sizeof(sample_t), to_get * channels, outfile);
/* should write infinitely until program kill */
}
@ -912,10 +910,16 @@ static int write_file(VGMSTREAM* vgmstream, cli_config* cfg) {
uint8_t wav_buf[0x100];
size_t bytes_done;
bytes_done = make_wav_header(wav_buf,0x100,
len_samples, vgmstream->sample_rate, channels,
cfg->write_lwav, cfg->lwav_loop_start, cfg->lwav_loop_end);
wav_header_t wav = {
.sample_count = len_samples,
.sample_rate = vgmstream->sample_rate,
.channels = channels,
.write_smpl_chunk = cfg->write_lwav,
.loop_start = cfg->lwav_loop_start,
.loop_end = cfg->lwav_loop_end
};
bytes_done = wav_make_header(wav_buf, 0x100, &wav);
fwrite(wav_buf, sizeof(uint8_t), bytes_done, outfile);
}
@ -929,7 +933,7 @@ static int write_file(VGMSTREAM* vgmstream, cli_config* cfg) {
render_vgmstream(buf, to_get, vgmstream);
if (!cfg->decode_only) {
swap_samples_le(buf, channels * to_get); /* change to WAV (LE) endian if PC is Big Endian */
swap_samples_le(buf, channels * to_get, 0);
fwrite(buf, sizeof(sample_t), to_get * channels, outfile);
}
}
@ -1020,66 +1024,3 @@ static void print_json_info(VGMSTREAM* vgm, cli_config* cfg) {
json_decref(final_object);
}
#endif
static void make_smpl_chunk(uint8_t* buf, int32_t loop_start, int32_t loop_end) {
int i;
memcpy(buf+0, "smpl", 0x04); /* header */
put_s32le(buf+0x04, 0x3c); /* size */
for (i = 0; i < 7; i++)
put_s32le(buf+0x08 + i * 0x04, 0);
put_s32le(buf+0x24, 1);
for (i = 0; i < 3; i++)
put_s32le(buf+0x28 + i * 0x04, 0);
put_s32le(buf+0x34, loop_start);
put_s32le(buf+0x38, loop_end);
put_s32le(buf+0x3C, 0);
put_s32le(buf+0x40, 0);
}
/* make a RIFF header for .wav */
static size_t make_wav_header(uint8_t* buf, size_t buf_size, int32_t sample_count, int32_t sample_rate, int channels, int smpl_chunk, int32_t loop_start, int32_t loop_end) {
size_t data_size, header_size;
data_size = sample_count * channels * sizeof(sample_t);
header_size = 0x2c;
if (smpl_chunk && loop_end)
header_size += 0x3c+ 0x08;
if (header_size > buf_size)
goto fail;
memcpy(buf+0x00, "RIFF", 0x04); /* RIFF header */
put_u32le(buf+0x04, (int32_t)(header_size - 0x08 + data_size)); /* size of RIFF */
memcpy(buf+0x08, "WAVE", 4); /* WAVE header */
memcpy(buf+0x0c, "fmt ", 0x04); /* WAVE fmt chunk */
put_s32le(buf+0x10, 0x10); /* size of WAVE fmt chunk */
put_s16le(buf+0x14, 0x0001); /* codec PCM */
put_s16le(buf+0x16, channels); /* channel count */
put_s32le(buf+0x18, sample_rate); /* sample rate */
put_s32le(buf+0x1c, sample_rate * channels * sizeof(sample_t)); /* bytes per second */
put_s16le(buf+0x20, (int16_t)(channels * sizeof(sample_t))); /* block align */
put_s16le(buf+0x22, sizeof(sample_t) * 8); /* significant bits per sample */
if (smpl_chunk && loop_end) {
make_smpl_chunk(buf+0x24, loop_start, loop_end);
memcpy(buf+0x24+0x3c+0x08, "data", 0x04); /* WAVE data chunk */
put_u32le(buf+0x28+0x3c+0x08, (int32_t)data_size); /* size of WAVE data chunk */
}
else {
memcpy(buf+0x24, "data", 0x04); /* WAVE data chunk */
put_s32le(buf+0x28, (int32_t)data_size); /* size of WAVE data chunk */
}
/* could try to add channel_layout, but would need to write WAVEFORMATEXTENSIBLE (maybe only if arg flag?) */
return header_size;
fail:
return 0;
}

View File

@ -103,8 +103,12 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="wav_utils.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="vgmstream_cli.c" />
<ClCompile Include="wav_utils.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ext_libs\ext_libs.vcxproj">

View File

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
@ -14,9 +18,17 @@
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="wav_utils.h">
<Filter>Header Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="vgmstream_cli.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wav_utils.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

152
cli/wav_utils.c Normal file
View File

@ -0,0 +1,152 @@
#include "wav_utils.h"
#include "../src/util/reader_put.h"
static int make_riff_chunk(uint8_t* buf, wav_header_t* wav, uint32_t header_size, uint32_t data_size) {
put_data (buf+0x00, "RIFF", 0x04);
put_u32le(buf+0x04, header_size - 0x08 + data_size);
put_data (buf+0x08, "WAVE", 0x04);
return 0x08 + 0x04;
}
static int make_fmt_chunk(uint8_t* buf, wav_header_t* wav) {
int codec = wav->is_float ? 0x0003 : 0x0001; /* PCM */
int bytes_per_second = wav->sample_rate * wav->channels * wav->sample_size;
int16_t block_align = wav->channels * wav->sample_size;
int bits_per_sample = wav->sample_size * 8;
put_data (buf + 0x00, "fmt ", 0x04);
put_u32le(buf + 0x04, 0x10);
put_s16le(buf + 0x08, codec);
put_s16le(buf + 0x0a, wav->channels);
put_s32le(buf + 0x0c, wav->sample_rate);
put_s32le(buf + 0x10, bytes_per_second);
put_s16le(buf + 0x14, block_align);
put_s16le(buf + 0x16, bits_per_sample);
return 0x08 + 0x10;
}
/* see riff.c */
static int make_smpl_chunk(uint8_t* buf, wav_header_t* wav) {
put_data (buf + 0x00, "smpl", 0x04);
put_s32le(buf + 0x04, 0x3c);
for (int i = 0; i < 7; i++) {
put_s32le(buf + 0x08 + i * 0x04, 0);
}
put_s32le(buf + 0x24, 1);
for (int i = 0; i < 3; i++) {
put_s32le(buf + 0x28 + i * 0x04, 0);
}
put_s32le(buf + 0x34, wav->loop_start);
put_s32le(buf + 0x38, wav->loop_end);
put_s32le(buf + 0x3C, 0);
put_s32le(buf + 0x40, 0);
return 0x08 + 0x3c;
}
static int make_data_chunk(uint8_t* buf, wav_header_t* wav, uint32_t data_size) {
put_data (buf + 0x00, "data", 0x04);
put_u32le(buf + 0x04, data_size);
return 0x08;
}
/* make a RIFF header for .wav */
size_t wav_make_header(uint8_t* buf, size_t buf_size, wav_header_t* wav) {
size_t header_size;
/* RIFF + fmt + smpl + data */
header_size = 0x08 + 0x04;
header_size += 0x08 + 0x10;
if (wav->write_smpl_chunk && wav->loop_end)
header_size += 0x08 + 0x3c;
header_size += 0x08;
if (header_size > buf_size)
return 0;
if (!wav->sample_size)
wav->sample_size = sizeof(short);
if (wav->sample_size <= 0 || wav->sample_size >= 4)
return 0;
size_t data_size = wav->sample_count * wav->channels * wav->sample_size;
int size;
size = make_riff_chunk(buf, wav, header_size, data_size);
buf += size;
size = make_fmt_chunk(buf, wav);
buf += size;
if (wav->write_smpl_chunk && wav->loop_end) {
size = make_smpl_chunk(buf, wav);
buf += size;
}
size = make_data_chunk(buf, wav, data_size);
buf += size;
/* could try to add channel_layout but would need WAVEFORMATEXTENSIBLE */
return header_size;
}
#if 0
void swap_samples_le(sample_t *buf, int count) {
/* Windows can't be BE... I think */
#if !defined(_WIN32)
#if !defined(__BYTE_ORDER__) || __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
for (int i = 0; i < count; i++) {
/* 16b sample in memory: aabb where aa=MSB, bb=LSB */
uint8_t b0 = buf[i] & 0xff;
uint8_t b1 = buf[i] >> 8;
uint8_t *p = (uint8_t*)&(buf[i]);
/* 16b sample in buffer: bbaa where bb=LSB, aa=MSB */
p[0] = b0;
p[1] = b1;
/* when endianness is LE, buffer has bbaa already so this function can be skipped */
}
#endif
#endif
}
#endif
static inline void swap_value(uint8_t* buf, int sample_size) {
for (int i = 0; i < sample_size / 2; i++) {
char temp = buf[i];
buf[i] = buf[sample_size - i - 1];
buf[sample_size - i - 1] = temp;
}
}
/* when endianness is LE buffer is correct already and this function can be skipped */
void swap_samples_le(void* samples, int samples_len, int sample_size) {
/* Windows can't be BE... I think */
#if !defined(_WIN32)
#if !defined(__BYTE_ORDER__) || __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
if (!sample_size)
sample_size = sizeof(short);
/* 16b sample in memory is AABB where AA=MSB, BB=LSB, swap to BBAA */
uint8_t* buf = samples;
for (int i = 0; i < samples_len; i += sample_size) {
swap_value(buf + i, sample_size);
}
#endif
#endif
}

29
cli/wav_utils.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef _WAV_UTILS_H_
#define _WAV_UTILS_H_
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
typedef struct {
bool is_float;
int sample_size;
int32_t sample_count;
int32_t sample_rate;
int channels;
bool write_smpl_chunk;
int32_t loop_start;
int32_t loop_end;
} wav_header_t;
/* make a RIFF header for .wav; returns final RIFF size or 0 if buffer is too small */
size_t wav_make_header(uint8_t* buf, size_t buf_size, wav_header_t* wav);
/* swap big endian samples to little endian. Does nothing if machine is already LE.
* Used when writting .WAV files, where samples in memory/buf may be BE while RIFF
* is expected to have LE samples. */
void swap_samples_le(void* samples, int samples_len, int sample_size);
#endif

View File

@ -785,10 +785,6 @@ different internally (encrypted, different versions, etc) and not always can be
- Electronic Arts SWVR header [*EA_SWVR*]
- *ea_swvr*: `.stream .str`
- Codecs: PSX NGC_DSP PCM8_U_int
- **ps2_b1s.c**
- B1S header [*PS2_B1S*]
- *ps2_b1s*: `.b1s`
- Codecs: PSX
- **lpcm_shade.c**
- Shade LPCM header [*LPCM_SHADE*]
- *lpcm_shade*: `.w .lpcm`
@ -805,10 +801,6 @@ different internally (encrypted, different versions, etc) and not always can be
- Guitar Hero III Mobile .bar [*GH3_BAR*]
- *bar*: `.bar`
- Codecs: IMA
- **ffw.c**
- Freedom Fighters BGM header [*FFW*]
- *ffw*: `.ffw`
- Codecs: PCM16BE
- **jstm.c**
- JSTM Header [*PS2_JSTM*]
- *jstm*: `.stm .jstm`
@ -1206,9 +1198,9 @@ different internally (encrypted, different versions, etc) and not always can be
- Subfiles: *vag riff*
- *sps_n1_segmented*: `.at9 .nlsd`
- Subfiles: *ogg_vorbis opus_std*
- **atx.c**
- **apa3.c**
- (container)
- *atx*: `.atx + .(external)`
- *apa3*: `.atx`
- Subfiles: *riff*
- **sqex_sead.c**
- Square Enix SAB header [*SQEX_SAB*]

View File

@ -8,8 +8,7 @@
/* vgmstream's public API
*
* By default vgmstream behaves like a simple decoder (extract samples until stream end), but you can configure it
* to loop N times or even downmix (since complex formats need those features). In other words, it also behaves
* a bit like a player.
* to loop N times or even downmix. In other words, it also behaves a bit like a player.
*
* It exposes multiple options and convenience functions beyond simple decoding mainly for various plugins,
* since it was faster moving shared behavior to core rather than reimplementing every time.
@ -19,14 +18,13 @@
* Notes:
* - vgmstream may dynamically allocate stuff as needed (not too much beyond some setup buffers, but varies per format)
* - previously the only way to use vgmstream was accesing its internals. Now there is an API internals may change in the future
* - some details described in the API may not happen at the moment (they are defined to consider internal changes)
* - some details described in the API may not happen at the moment (they are defined for future internal changes)
* - main reason it uses the slighly long-winded libvgmstream_* names is that internals use the vgmstream_* 'namespace'
* - c-strings should be in UTF-8
* - the API is still WIP and may be slightly buggy overall due to lack of time, to be improved later
* - vgmstream's features are mostly stable, but this API may be tweaked from time to time (check API_VERSION)
*
* Basic usage (also see api_example.c):
* - libvgmstream_get_version() // just in case
* - libvgmstream_init(...) // base context
* - libvgmstream_setup(...) // config if needed
* - libvgmstream_open(...) // setup format
@ -42,7 +40,6 @@
//#define LIBVGMSTREAM_CALL __cdecl //needed?
//LIBVGMSTREAM_API (type) LIBVGMSTREAM_CALL libvgmstream_function(...);
/* define external function behavior (during compilation) */
#if defined(LIBVGMSTREAM_EXPORT)
#define LIBVGMSTREAM_API __declspec(dllexport) /* when exporting/creating vgmstream DLL */
@ -52,21 +49,7 @@
#define LIBVGMSTREAM_API /* nothing, internal/default */
#endif
/* Current API version.
* - only refers to the API itself, as changes related to formats/etc don't alter this (since they are usually additive)
* - vgmstream's features are mostly stable, but this API may be tweaked from time to time
*/
#define LIBVGMSTREAM_API_VERSION_MAJOR 1 // breaking API/ABI changes
#define LIBVGMSTREAM_API_VERSION_MINOR 0 // compatible API/ABI changes
#define LIBVGMSTREAM_API_VERSION_PATCH 0 // fixes
/* returns API version in hex format: 0xMMmmpppp = MM-major, mm-minor, pppp-patch
* - use when loading vgmstream as a dynamic library to ensure API/ABI compatibility
*/
LIBVGMSTREAM_API uint32_t libvgmstream_get_version(void);
#include "api_version.h"
#include "api_decode.h"
#include "api_helpers.h"
#include "api_streamfile.h"

25
src/api_version.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef _API_VERSION_H_
#define _API_VERSION_H_
#include "api.h"
#if LIBVGMSTREAM_ENABLE
/* Current API version.
* - only refers to the API itself, as changes related to formats/etc don't alter this (since they are usually additive)
* - vgmstream's features are mostly stable, but this API may be tweaked from time to time
*/
#define LIBVGMSTREAM_API_VERSION_MAJOR 1 // breaking API/ABI changes
#define LIBVGMSTREAM_API_VERSION_MINOR 0 // compatible API/ABI changes
#define LIBVGMSTREAM_API_VERSION_PATCH 0 // fixes
/* returns API version in hex format: 0xMMmmpppp = MM-major, mm-minor, pppp-patch
* - use when loading vgmstream as a dynamic library to ensure API/ABI compatibility
*/
LIBVGMSTREAM_API uint32_t libvgmstream_get_version(void);
/* CHANGELOG:
*
* - 1.0.0: initial version
*/
#endif
#endif

View File

@ -92,7 +92,7 @@ static const char* extension_list[] = {
"awc",
"awd",
"b1s",
"b1s", //txth/reserved [7 Wonders of the Ancient World (PS2)]
"baf",
"baka",
"bank",
@ -190,7 +190,6 @@ static const char* extension_list[] = {
"fag",
"fcb", //FFmpeg/not parsed (BINK AUDIO)
"fda",
"ffw",
"filp",
"fish",
//"flac", //common
@ -1204,7 +1203,6 @@ static const meta_info meta_info_list[] = {
{meta_NGC_DSP_MPDS, "MPDS DSP header"},
{meta_DSP_STR_IG, "Infogrames .DSP header"},
{meta_EA_SWVR, "Electronic Arts SWVR header"},
{meta_PS2_B1S, "B1S header"},
{meta_DSP_XIII, "XIII dsp header"},
{meta_DSP_CABELAS, "Cabelas games .DSP header"},
{meta_PS2_ADM, "Dragon Quest V .ADM raw header"},
@ -1212,7 +1210,6 @@ static const meta_info meta_info_list[] = {
{meta_PS2_VMS, "VMS Header"},
{meta_XAU, "XPEC XAU header"},
{meta_GH3_BAR, "Guitar Hero III Mobile .bar"},
{meta_FFW, "Freedom Fighters BGM header"},
{meta_DSP_DSPW, "Capcom DSPW header"},
{meta_PS2_JSTM, "JSTM Header"},
{meta_XVAG, "Sony XVAG header"},

View File

@ -85,6 +85,7 @@
<ClInclude Include="api_helpers.h" />
<ClInclude Include="api_streamfile.h" />
<ClInclude Include="api_tags.h" />
<ClInclude Include="api_version.h" />
<ClInclude Include="streamfile.h" />
<ClInclude Include="streamtypes.h" />
<ClInclude Include="util.h" />
@ -126,6 +127,7 @@
<ClInclude Include="meta\adx_keys.h" />
<ClInclude Include="meta\ahx_keys.h" />
<ClInclude Include="meta\aix_streamfile.h" />
<ClInclude Include="meta\apa3_streamfile.h" />
<ClInclude Include="meta\awc_decryption_streamfile.h" />
<ClInclude Include="meta\awc_streamfile.h" />
<ClInclude Include="meta\bar_streamfile.h" />
@ -200,7 +202,6 @@
<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\sf_utils.h" />
<ClInclude Include="util\text_reader.h" />
<ClInclude Include="util\vgmstream_limits.h" />
@ -395,6 +396,7 @@
<ClCompile Include="meta\akb.c" />
<ClCompile Include="meta\alp.c" />
<ClCompile Include="meta\ao.c" />
<ClCompile Include="meta\apa3.c" />
<ClCompile Include="meta\apc.c" />
<ClCompile Include="meta\apple_caff.c" />
<ClCompile Include="meta\asd_naxat.c" />
@ -404,7 +406,6 @@
<ClCompile Include="meta\ast_mmv.c" />
<ClCompile Include="meta\ast_mv.c" />
<ClCompile Include="meta\atsl.c" />
<ClCompile Include="meta\atx.c" />
<ClCompile Include="meta\aus.c" />
<ClCompile Include="meta\awb.c" />
<ClCompile Include="meta\awc.c" />
@ -479,7 +480,6 @@
<ClCompile Include="meta\fda.c" />
<ClCompile Include="meta\ffdl.c" />
<ClCompile Include="meta\ffmpeg.c" />
<ClCompile Include="meta\ffw.c" />
<ClCompile Include="meta\filp.c" />
<ClCompile Include="meta\flx.c" />
<ClCompile Include="meta\fsb.c" />
@ -610,7 +610,6 @@
<ClCompile Include="meta\ppst.c" />
<ClCompile Include="meta\ps2_adm.c" />
<ClCompile Include="meta\ps2_ass.c" />
<ClCompile Include="meta\ps2_b1s.c" />
<ClCompile Include="meta\ps2_bmdx.c" />
<ClCompile Include="meta\ps2_gcm.c" />
<ClCompile Include="meta\ps2_hsf.c" />
@ -804,7 +803,6 @@
<ClCompile Include="util\miniz.c" />
<ClCompile Include="util\paths.c" />
<ClCompile Include="util\reader.c" />
<ClCompile Include="util\samples_ops.c" />
<ClCompile Include="util\sf_utils.c" />
<ClCompile Include="util\text_reader.c" />
</ItemGroup>

View File

@ -89,6 +89,9 @@
<ClInclude Include="api_tags.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="api_version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="streamfile.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -212,6 +215,9 @@
<ClInclude Include="meta\aix_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\apa3_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\awc_decryption_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
@ -434,9 +440,6 @@
<ClInclude Include="util\reader_text.h">
<Filter>util\Header Files</Filter>
</ClInclude>
<ClInclude Include="util\samples_ops.h">
<Filter>util\Header Files</Filter>
</ClInclude>
<ClInclude Include="util\sf_utils.h">
<Filter>util\Header Files</Filter>
</ClInclude>
@ -1015,6 +1018,9 @@
<ClCompile Include="meta\ao.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\apa3.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\apc.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1042,9 +1048,6 @@
<ClCompile Include="meta\atsl.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\atx.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\aus.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1267,9 +1270,6 @@
<ClCompile Include="meta\ffmpeg.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ffw.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\filp.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1660,9 +1660,6 @@
<ClCompile Include="meta\ps2_ass.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_b1s.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_bmdx.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -2242,9 +2239,6 @@
<ClCompile Include="util\reader.c">
<Filter>util\Source Files</Filter>
</ClCompile>
<ClCompile Include="util\samples_ops.c">
<Filter>util\Source Files</Filter>
</ClCompile>
<ClCompile Include="util\sf_utils.c">
<Filter>util\Source Files</Filter>
</ClCompile>

View File

@ -1,74 +1,145 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
#include "../util/reader_text.h"
#include "../util/meta_utils.h"
/* .agsc - from Metroid Prime 2 */
static bool parse_agsc(meta_header_t* hdr, STREAMFILE* sf, int version);
VGMSTREAM * init_vgmstream_agsc(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t header_offset;
off_t start_offset;
int channel_count;
int i;
/* .agsc - from Retro Studios games [Metroid Prime (GC), Metroid Prime 2 (GC)] */
VGMSTREAM* init_vgmstream_agsc(STREAMFILE* sf) {
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("agsc",filename_extension(filename))) goto fail;
/* checks */
int version;
if (is_id32be(0x00, sf, "Audi"))
version = 1;
else if (read_u32be(0x00, sf) == 0x00000001)
version = 2;
else
return NULL;
/* check header */
if ((uint32_t)read_32bitBE(0,streamFile)!=0x00000001)
goto fail;
/* .agsc: 'class' type in .pak */
if (!check_extensions(sf, "agsc"))
return NULL;
/* count length of name, including terminating 0 */
for (header_offset=4;header_offset < get_streamfile_size(streamFile) && read_8bit(header_offset,streamFile)!='\0';header_offset++);
header_offset ++;
meta_header_t hdr = {0};
if (!parse_agsc(&hdr, sf, version))
return NULL;
channel_count = 1;
hdr.meta = meta_AGSC;
hdr.coding = coding_NGC_DSP;
hdr.layout = layout_none;
hdr.big_endian = true;
hdr.allow_dual_stereo = true;
/* build the VGMSTREAM */
hdr.sf = sf;
hdr.open_stream = true;
vgmstream = allocate_vgmstream(1,1);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->num_samples = read_32bitBE(header_offset+0xda,streamFile);
vgmstream->sample_rate = (uint16_t)read_16bitBE(header_offset+0xd8,streamFile);
vgmstream->loop_start_sample = read_32bitBE(header_offset+0xde,streamFile);
/* this is cute, we actually have a "loop length" */
vgmstream->loop_end_sample = (vgmstream->loop_start_sample + read_32bitBE(header_offset+0xe2,streamFile))-1;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_AGSC;
vgmstream->allow_dual_stereo = 1;
for (i=0;i<16;i++) {
vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(header_offset+0xf6+i*2,streamFile);
}
start_offset = header_offset+0x116;
/* open the file for reading by each channel */
{
int i;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=
start_offset;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
return alloc_metastream(&hdr);
}
static bool parse_agsc(meta_header_t* hdr, STREAMFILE* sf, int version) {
uint32_t offset;
int name_size;
switch(version) {
case 1:
// usually "Audio/" but rarely "Audio//"
name_size = read_string(NULL, 0x20, 0x00, sf);
if (name_size == 0) // not a string
return false;
offset = name_size + 1;
break;
case 2:
/* after fixed ID */
offset = 0x04;
break;
default:
return false;
}
/* after id starts with name + null */
hdr->name_offset = offset;
name_size = read_string(NULL, 0x20, offset, sf);
if (name_size == 0) // not a string
return false;
offset += name_size + 1;
uint32_t head_offset, data_offset;
uint32_t unk1_size, unk2_size, head_size, data_size;
switch(version) {
case 1:
/* per chunk: chunk size + chunk data */
unk1_size = read_u32be(offset, sf);
offset += 0x04 + unk1_size;
unk2_size = read_u32be(offset, sf);
offset += 0x04 + unk2_size;
data_offset = offset + 0x04; // data chunk goes before headers...
data_size = read_u32be(offset, sf);
offset += 0x04 + data_size;
head_offset = offset + 0x04;
head_size = read_u32be(offset, sf);
offset += 0x04 + head_size;
break;
case 2:
/* chunk sizes per chunk + chunk data per chunk */
offset += 0x02; // song id?
unk1_size = read_u32be(offset + 0x00, sf);
unk2_size = read_u32be(offset + 0x04, sf);
head_size = read_u32be(offset + 0x08, sf);
data_size = read_u32be(offset + 0x0c, sf);
head_offset = offset + 0x10 + unk1_size + unk2_size;
data_offset = head_offset + head_size;
break;
default:
return false;
}
// offsets/values/data aren't 32b aligned but file is (0xFF padding)
// possible in some test banks
if (data_size == 0 || head_size < 0x20 + 0x28) {
vgm_logi("AGSC: bank has no subsongs (ignore)\n");
return false;
}
/* header chunk has 0x20 headers per subsong + 0xFFFFFFFF (end marker) + 0x28 coefs per subsongs,
* no apparent count even in other chunks */
hdr->total_subsongs = (head_size - 0x04) / (0x20 + 0x28);
hdr->target_subsong = sf->stream_index;
if (!check_subsongs(&hdr->target_subsong, hdr->total_subsongs))
return false;
uint32_t entry_offset = head_offset + 0x20 * (hdr->target_subsong - 1);
// 00: id?
hdr->stream_offset = read_u32be(entry_offset + 0x04,sf) + data_offset;
// 08: null?
// 0c: always 0x3c00?
hdr->sample_rate = read_u16be(entry_offset + 0x0e,sf);
hdr->num_samples = read_s32be(entry_offset + 0x10,sf);
hdr->loop_start = read_s32be(entry_offset + 0x14,sf);
hdr->loop_end = read_s32be(entry_offset + 0x18,sf); // loop length
hdr->coefs_offset = read_s32be(entry_offset + 0x1c,sf);
if (hdr->loop_end)
hdr->loop_end = hdr->loop_end + hdr->loop_start - 1;
hdr->loop_flag = hdr->loop_end != 0;
hdr->coefs_offset += head_offset + 0x08; // skip unknown hist/loop ps-like values
hdr->channels = 1; // MP2 uses dual stereo for title track
hdr->stream_size = hdr->num_samples / 14 * 8 * hdr->channels; // meh
return true;
}

34
src/meta/apa3.c Normal file
View File

@ -0,0 +1,34 @@
#include "meta.h"
#include "../coding/coding.h"
#include "apa3_streamfile.h"
/* .ATX - Media.Vision's segmented RIFF AT3 wrapper [Senjo no Valkyria 3 (PSP), Shining Blade (PSP)] */
VGMSTREAM* init_vgmstream_apa3(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
/* checks */
if (!is_id32be(0x00, sf, "APA3"))
return NULL;
if (!check_extensions(sf,"atx"))
return NULL;
/* .ATX is made of subfile segments, handled by a custom SF.
* Each segment has a header/footer, and part of the full AT3 data
* (i.e. ATRAC3 data ends in a subfile and continues in the next) */
temp_sf = setup_apa3_streamfile(sf);
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_riff(temp_sf);
if (!vgmstream) goto fail;
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,81 @@
#ifndef _APA3_STREAMFILE_H_
#define _APA3_STREAMFILE_H_
#include "meta.h"
#define ATX_MAX_SEGMENTS 2
static STREAMFILE* setup_apa3_streamfile(STREAMFILE* sf) {
STREAMFILE* new_sf = NULL;
STREAMFILE* segments_sf[ATX_MAX_SEGMENTS] = {0};
char filename[PATH_LIMIT];
size_t riff_size;
/* this must be first segment */
if (read_u16le(0x1c,sf) != 0)
return NULL;
int total_segments = read_u16le(0x1e,sf);
if (total_segments < 1 || total_segments > ATX_MAX_SEGMENTS)
return NULL;
/* expected segment name: X_XXX_XXX_0n.ATX, starting from n=1 */
get_streamfile_filename(sf, filename, PATH_LIMIT);
size_t filename_len = strlen(filename);
if (filename_len < 7 || filename[filename_len - 5] != '1')
return NULL;
/* setup segments (could avoid reopening first segment but meh) */
for (int i = 0; i < total_segments; i++) {
off_t subfile_offset;
size_t subfile_size;
filename[filename_len - 5] = ('0' + i + 1); /* digit conversion */
segments_sf[i] = open_streamfile_by_filename(sf, filename);
if (!segments_sf[i]) goto fail;
if (!is_id32be(0x00, segments_sf[i], "APA3"))
goto fail;
/* parse block/segment header (other Media.Vision's files use it too) */
subfile_offset = read_32bitLE(0x08, segments_sf[i]); /* header size */
subfile_size = read_32bitLE(0x14, segments_sf[i]); /* can be 0 in other containers */
if (read_u16le(0x1c,segments_sf[i]) != i)
goto fail; /* segment sequence */
// 0x04: block size (should match subfile_size in .ATX)
// 0x0c: flags? also in other files
// 0x10/18: null
// 0x1e: total segments
/* clamp to ignore header/footer during next reads */
segments_sf[i] = open_clamp_streamfile_f(segments_sf[i], subfile_offset, subfile_size);
if (!segments_sf[i]) goto fail;
}
/* setup with all segments and clamp further using riff_size (last segment has padding) */
riff_size = read_32bitLE(read_32bitLE(0x08,sf) + 0x04,sf) + 0x08;
new_sf = open_multifile_streamfile_f(segments_sf, total_segments);
new_sf = open_clamp_streamfile_f(new_sf, 0, riff_size);
new_sf = open_fakename_streamfile_f(new_sf, NULL, "at3");
/* if all this worked we'll have this frankenstein streamfile:
* fakename( clamp( multifile( segment0=clamp(standard(FILE)), segment1=clamp(standard(FILE)) ) ) ) */
return new_sf;
fail:
if (!new_sf) {
for (int i = 0; i < total_segments; i++) {
close_streamfile(segments_sf[i]);
}
} else {
close_streamfile(new_sf); /* closes all segments */
}
return NULL;
}
#endif

View File

@ -1,113 +0,0 @@
#include "meta.h"
#include "../coding/coding.h"
#define ATX_MAX_SEGMENTS 2
static STREAMFILE* setup_atx_streamfile(STREAMFILE *streamFile);
/* .ATX - Media.Vision's segmented RIFF AT3 wrapper [Senjo no Valkyria 3 (PSP), Shining Blade (PSP)] */
VGMSTREAM * init_vgmstream_atx(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
/* check extensions */
if ( !check_extensions(streamFile,"atx"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x41504133) /* "APA3" */
goto fail;
/* .ATX is made of subfile segments, handled by the streamFile.
* Each segment has a header/footer, and part of the whole data
* (i.e. ATRAC3 data ends in a subfile and continues in the next) */
temp_streamFile = setup_atx_streamfile(streamFile);
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_riff(temp_streamFile);
if (!vgmstream) goto fail;
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
static STREAMFILE* setup_atx_streamfile(STREAMFILE *streamFile) {
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
STREAMFILE *segment_streamFiles[ATX_MAX_SEGMENTS] = {0};
char filename[PATH_LIMIT];
size_t filename_len;
int i, num_segments = 0;
size_t riff_size;
if (read_16bitLE(0x1c,streamFile) != 0) goto fail; /* this must be first segment */
if (read_16bitLE(0x1e,streamFile) < 1 || read_16bitLE(0x1e,streamFile) > ATX_MAX_SEGMENTS) goto fail;
num_segments = read_16bitLE(0x1e,streamFile);
/* expected segment name: X_XXX_XXX_0n.ATX, starting from n=1 */
get_streamfile_filename(streamFile, filename,PATH_LIMIT);
filename_len = strlen(filename);
if (filename_len < 7 || filename[filename_len - 5] != '1') goto fail;
/* setup segments (could avoid reopening first segment but meh) */
for (i = 0; i < num_segments; i++) {
off_t subfile_offset;
size_t subfile_size;
filename[filename_len - 5] = ('0'+i+1); /* ghetto digit conversion */
new_streamFile = open_streamfile_by_filename(streamFile, filename);
if (!new_streamFile) goto fail;
segment_streamFiles[i] = new_streamFile;
if (read_32bitBE(0x00,segment_streamFiles[i]) != 0x41504133) /* "APA3" */
goto fail;
/* parse block/segment header (other Media.Vision's files use it too) */
subfile_offset = read_32bitLE(0x08,segment_streamFiles[i]); /* header size */
subfile_size = read_32bitLE(0x14,segment_streamFiles[i]); /* can be 0 in other containers */
if (read_16bitLE(0x1c,segment_streamFiles[i]) != i)
goto fail; /* segment sequence */
/* 0x04: block size (should match subfile_size in .ATX) */
/* 0x0c: flags? also in other files, 0x10/18: null, 0x1e: segments */
/* clamp to ignore header/footer during next reads */
new_streamFile = open_clamp_streamfile(segment_streamFiles[i], subfile_offset,subfile_size);
if (!new_streamFile) goto fail;
segment_streamFiles[i] = new_streamFile;
}
/* setup with all segments and clamp further using riff_size (last segment has padding) */
riff_size = read_32bitLE(read_32bitLE(0x08,streamFile) + 0x04,streamFile) + 0x08;
new_streamFile = open_multifile_streamfile(segment_streamFiles, num_segments);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_clamp_streamfile(temp_streamFile, 0,riff_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL, "at3");
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
/* if all this worked we'll have this frankenstein streamfile:
* fakename( clamp( multifile( segment0=clamp(standard(FILE)), segment1=clamp(standard(FILE)) ) ) ) */
return temp_streamFile;
fail:
if (!temp_streamFile) {
for (i = 0; i < num_segments; i++) {
close_streamfile(segment_streamFiles[i]);
}
} else {
close_streamfile(temp_streamFile); /* closes all segments */
}
return NULL;
}

View File

@ -1,64 +0,0 @@
#include "meta.h"
#include "../util.h"
/* FFW (from Freedom Fighters [NGC]) */
VGMSTREAM * init_vgmstream_ffw(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("ffw",filename_extension(filename))) goto fail;
loop_flag = 0;
channel_count = read_32bitLE(0x11C,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x130;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x10C,streamFile);
vgmstream->coding_type = coding_PCM16BE;
vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count;
if (channel_count == 1)
{
vgmstream->layout_type = layout_none;
}
else
{
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10000;
}
vgmstream->meta_type = meta_FFW;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -453,8 +453,6 @@ VGMSTREAM * init_vgmstream_ngc_dsp_mpds(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_b1s(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_adm(STREAMFILE* streamFile);
VGMSTREAM* init_vgmstream_lpcm_shade(STREAMFILE* sf);
@ -465,8 +463,6 @@ VGMSTREAM * init_vgmstream_xau(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_bar(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ffw(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_jstm(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_xvag(STREAMFILE* streamFile);
@ -690,7 +686,7 @@ VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sps_n1(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sps_n1_segmented(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_atx(STREAMFILE *streamFile);
VGMSTREAM* init_vgmstream_apa3(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile);

View File

@ -1,56 +0,0 @@
#include "meta.h"
#include "../util.h"
/* B1S (found in 7 Wonders of the Ancient World) */
VGMSTREAM * init_vgmstream_ps2_b1s(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int channel_count;
off_t start_offset;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("b1s",filename_extension(filename))) goto fail;
if ((read_32bitLE(0x04,streamFile)+0x18) != get_streamfile_size(streamFile))
goto fail;
channel_count = read_32bitLE(0x14,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,0);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x18;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = read_32bitLE(0x04,streamFile)/16/channel_count*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile);
vgmstream->meta_type = meta_PS2_B1S;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,5 +1,6 @@
#include "../vgmstream.h"
#include "meta_utils.h"
#include "reader_text.h"
/* Allocate memory and setup a VGMSTREAM */
@ -10,7 +11,7 @@ VGMSTREAM* alloc_metastream(meta_header_t* h) {
return NULL;
}
if (h->num_samples <= 0 || h->num_samples > VGMSTREAM_MAX_NUM_SAMPLES) {
VGM_LOG("meta: wrong samples %i\n", h->sample_rate);
VGM_LOG("meta: wrong samples %i\n", h->num_samples);
return NULL;
}
@ -30,7 +31,10 @@ VGMSTREAM* alloc_metastream(meta_header_t* h) {
vgmstream->num_streams = h->total_subsongs;
vgmstream->stream_size = h->stream_size;
vgmstream->interleave_block_size = h->interleave;
vgmstream->allow_dual_stereo = h->allow_dual_stereo;
if (h->name_offset)
read_string(vgmstream->stream_name, sizeof(vgmstream->stream_name), h->name_offset, h->sf ? h->sf : h->sf_head);
if (h->coding == coding_NGC_DSP && (h->sf || h->sf_head)) {
if (h->coefs_offset || h->coefs_spacing)

View File

@ -39,7 +39,9 @@ typedef struct {
uint32_t hists_offset;
uint32_t hists_spacing;
/* optional but can be used for some actions */
uint32_t name_offset;
/* optional but can be used for some actions (such as DSP coefs) */
bool big_endian;
coding_t coding;
layout_t layout;
@ -51,6 +53,8 @@ typedef struct {
STREAMFILE* sf_body;
bool open_stream;
bool allow_dual_stereo;
} meta_header_t;
VGMSTREAM* alloc_metastream(meta_header_t* h);

View File

@ -1,3 +1,4 @@
#include <string.h> // memcpy
#include "reader_put.h"
#include "reader_text.h"
#include "reader_sf.h"
@ -31,6 +32,30 @@ void put_u32be(uint8_t* buf, uint32_t v) {
buf[3] = (uint8_t)((v >> 0) & 0xFF);
}
void put_s8(uint8_t* buf, int8_t v) {
put_u8(buf, v);
}
void put_s16le(uint8_t* buf, int16_t v) {
put_u16le(buf, v);
}
void put_s32le(uint8_t* buf, int32_t v) {
put_u32le(buf, v);
}
void put_s16be(uint8_t* buf, int16_t v) {
put_u16be(buf, v);
}
void put_s32be(uint8_t* buf, int32_t v) {
put_u32be(buf, v);
}
void put_data(uint8_t* buf, void* v, int v_size) {
memcpy (buf, v, v_size);
}
/* **************************************************** */
size_t read_line(char* buf, int buf_size, off_t offset, STREAMFILE* sf, int* p_line_ok) {

View File

@ -9,11 +9,12 @@ void put_u32le(uint8_t* buf, uint32_t v);
void put_u16be(uint8_t* buf, uint16_t v);
void put_u32be(uint8_t* buf, uint32_t v);
/* alias of the above */ //TODO: improve
#define put_s8 put_u8
#define put_s16le put_u16le
#define put_s32le put_u32le
#define put_s16be put_u16be
#define put_s32be put_u32be
void put_s8(uint8_t* buf, int8_t v);
void put_s16le(uint8_t* buf, int16_t v);
void put_s32le(uint8_t* buf, int32_t v);
void put_s16be(uint8_t* buf, int16_t v);
void put_s32be(uint8_t* buf, int32_t v);
void put_data(uint8_t* buf, void* v, int v_size);
#endif

View File

@ -1,63 +0,0 @@
#include "samples_ops.h"
void swap_samples_le(sample_t *buf, int count) {
/* Windows can't be BE... I think */
#if !defined(_WIN32)
#if !defined(__BYTE_ORDER__) || __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
int i;
for (i = 0; i < count; i++) {
/* 16b sample in memory: aabb where aa=MSB, bb=LSB */
uint8_t b0 = buf[i] & 0xff;
uint8_t b1 = buf[i] >> 8;
uint8_t *p = (uint8_t*)&(buf[i]);
/* 16b sample in buffer: bbaa where bb=LSB, aa=MSB */
p[0] = b0;
p[1] = b1;
/* when endianness is LE, buffer has bbaa already so this function can be skipped */
}
#endif
#endif
}
/* unused */
/*
void interleave_channel(sample_t * outbuffer, sample_t * inbuffer, int32_t sample_count, int channel_count, int channel_number) {
int32_t insample,outsample;
if (channel_count==1) {
memcpy(outbuffer,inbuffer,sizeof(sample)*sample_count);
return;
}
for (insample=0,outsample=channel_number;insample<sample_count;insample++,outsample+=channel_count) {
outbuffer[outsample]=inbuffer[insample];
}
}
*/
/* failed attempt at interleave in place */
/*
void interleave_stereo(sample_t * buffer, int32_t sample_count) {
int32_t tomove, belongs;
sample_t moving,temp;
tomove = sample_count;
moving = buffer[tomove];
do {
if (tomove<sample_count)
belongs = tomove*2;
else
belongs = (tomove-sample_count)*2+1;
temp = buffer[belongs];
buffer[belongs] = moving;
moving = temp;
tomove = belongs;
} while (tomove != sample_count);
}
*/

View File

@ -1,9 +0,0 @@
#ifndef _SAMPLES_OPS_H
#define _SAMPLES_OPS_H
#include "../streamtypes.h"
/* swap samples in machine endianness to little endian (useful to write .wav) */
void swap_samples_le(sample_t* buf, int count);
#endif

View File

@ -206,14 +206,12 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_ngc_dsp_mpds,
init_vgmstream_dsp_str_ig,
init_vgmstream_ea_swvr,
init_vgmstream_ps2_b1s,
init_vgmstream_dsp_xiii,
init_vgmstream_dsp_cabelas,
init_vgmstream_lpcm_shade,
init_vgmstream_ps2_vms,
init_vgmstream_xau,
init_vgmstream_bar,
init_vgmstream_ffw,
init_vgmstream_dsp_dspw,
init_vgmstream_jstm,
init_vgmstream_xvag,
@ -335,7 +333,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_xwc,
init_vgmstream_atsl,
init_vgmstream_sps_n1,
init_vgmstream_atx,
init_vgmstream_apa3,
init_vgmstream_sqex_sead,
init_vgmstream_waf,
init_vgmstream_wave,

View File

@ -471,7 +471,6 @@ typedef enum {
meta_NGC_DSP_MPDS, /* Big Air Freestyle, Terminator 3 */
meta_DSP_STR_IG, /* Micro Machines, Superman Superman: Shadow of Apokolis */
meta_EA_SWVR, /* Future Cop L.A.P.D., Freekstyle */
meta_PS2_B1S, /* 7 Wonders of the ancient world */
meta_DSP_XIII, /* XIII, possibly more (Ubisoft header???) */
meta_DSP_CABELAS, /* Cabelas games */
meta_PS2_ADM, /* Dragon Quest V (PS2) */
@ -479,7 +478,6 @@ typedef enum {
meta_PS2_VMS, /* Autobahn Raser - Police Madness */
meta_XAU, /* XPEC Entertainment (Beat Down (PS2 Xbox), Spectral Force Chronicle (PS2)) */
meta_GH3_BAR, /* Guitar Hero III Mobile .bar */
meta_FFW, /* Freedom Fighters [NGC] */
meta_DSP_DSPW, /* Sengoku Basara 3 [WII] */
meta_PS2_JSTM, /* Tantei Jinguji Saburo - Kind of Blue (PS2) */
meta_SQEX_SCD, /* Square-Enix SCD */