diff options
author | theuni <theuni-nospam-@xbmc.org> | 2011-01-24 16:05:21 -0500 |
---|---|---|
committer | theuni <theuni-nospam-@xbmc.org> | 2011-01-24 16:05:21 -0500 |
commit | c51b1189e3d5353e842991f5859ddcea0f73e426 (patch) | |
tree | ef2cb8a6184699aa614f3655dca4ce661cdc108e /lib/vgmstream | |
parent | be61ebdc9e897fe40c6f371111724de79ddee8d5 (diff) |
Merged cptspiff's code-reshuffle branch.
Squashed commit due to build breakage during code-reshuffle history.
Conflicts:
xbmc/Util.cpp
xbmc/cdrip/CDDARipper.cpp
xbmc/filesystem/Directory.cpp
xbmc/filesystem/File.cpp
Diffstat (limited to 'lib/vgmstream')
201 files changed, 30091 insertions, 0 deletions
diff --git a/lib/vgmstream/COPYING b/lib/vgmstream/COPYING new file mode 100644 index 0000000000..8dac8cf7cc --- /dev/null +++ b/lib/vgmstream/COPYING @@ -0,0 +1,19 @@ +Copyright (c) 2008 Adam Gashlin, Fastelbja, Ronny Elfert + +Portions Copyright (c) 2004-2008, Marko Kreen +Portions Copyright (c) 1998, Justin Frankel/Nullsoft Inc. +Portions Copyright (C) 2006 Nullsoft, Inc. +Portions Copyright (c) 2005-2007 Paul Hsieh +Portions Public Domain originating with Sun Microsystems + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/lib/vgmstream/Makefile.in b/lib/vgmstream/Makefile.in new file mode 100644 index 0000000000..9db00ba6cb --- /dev/null +++ b/lib/vgmstream/Makefile.in @@ -0,0 +1,207 @@ +ARCH=@ARCH@ + +ifeq ($(findstring osx,$(ARCH)), osx) + CFLAGS +=-D_LINUX -fPIC -DPIC -O3 -DXBMC + CXXFLAGS +=-D_LINUX -fPIC -DPIC -O3 -DXBMC +else + CFLAGS +=-D_LINUX -fPIC -DXBMC + CXXFLAGS +=-D_LINUX -fPIC -DXBMC +endif + +CODING_OBJS=src/coding/acm_decoder.o \ + src/coding/adx_decoder.o \ + src/coding/aica_decoder.o \ + src/coding/eaxa_decoder.o \ + src/coding/g721_decoder.o \ + src/coding/ima_decoder.o \ + src/coding/l5_555_decoder.o \ + src/coding/mpeg_decoder.o \ + src/coding/msadpcm_decoder.o \ + src/coding/nds_procyon_decoder.o \ + src/coding/ngc_afc_decoder.o \ + src/coding/ngc_dsp_decoder.o \ + src/coding/ngc_dtk_decoder.o \ + src/coding/nwa_decoder.o \ + src/coding/ogg_vorbis_decoder.o \ + src/coding/pcm_decoder.o \ + src/coding/psx_decoder.o \ + src/coding/sdx2_decoder.o \ + src/coding/ws_decoder.o \ + src/coding/xa_decoder.o + +LAYOUT_OBJS=src/layout/aax_layout.o \ + src/layout/aix_layout.o \ + src/layout/ast_blocked.o \ + src/layout/blocked.o \ + src/layout/caf_blocked.o \ + src/layout/de2_blocked.o \ + src/layout/ea_block.o \ + src/layout/emff_blocked.o \ + src/layout/filp_blocked.o \ + src/layout/gsb_blocked.o \ + src/layout/halpst_blocked.o \ + src/layout/ims_block.o \ + src/layout/interleave.o \ + src/layout/interleave_byte.o \ + src/layout/mus_acm_layout.o \ + src/layout/nolayout.o \ + src/layout/str_snds_blocked.o \ + src/layout/thp_blocked.o \ + src/layout/vs_blocked.o \ + src/layout/ws_aud_blocked.o \ + src/layout/wsi_blocked.o \ + src/layout/xa_blocked.o \ + src/layout/xvas_block.o + +META_OBJS=src/meta/aax.o \ + src/meta/acm.o \ + src/meta/adx_header.o \ + src/meta/afc_header.o \ + src/meta/agsc.o \ + src/meta/ahx.o \ + src/meta/aifc.o \ + src/meta/aix.o \ + src/meta/ast.o \ + src/meta/bgw.o \ + src/meta/brstm.o \ + src/meta/capdsp.o \ + src/meta/Cstr.o \ + src/meta/dc_asd.o \ + src/meta/dc_idvi.o \ + src/meta/dc_kcey.o \ + src/meta/dc_str.o \ + src/meta/dc_wav_dcs.o \ + src/meta/de2.o \ + src/meta/ea_header.o \ + src/meta/ea_old.o \ + src/meta/emff.o \ + src/meta/fsb.o \ + src/meta/gca.o \ + src/meta/gcsw.o \ + src/meta/genh.o \ + src/meta/gsp_gsb.o \ + src/meta/halpst.o \ + src/meta/idsp.o \ + src/meta/ish_isd.o \ + src/meta/ivb.o \ + src/meta/kraw.o \ + src/meta/msvp.o \ + src/meta/mus_acm.o \ + src/meta/musc.o \ + src/meta/musx.o \ + src/meta/naomi_spsd.o \ + src/meta/nds_sad.o \ + src/meta/nds_strm.o \ + src/meta/ngc_adpdtk.o \ + src/meta/ngc_bh2pcm.o \ + src/meta/ngc_caf.o \ + src/meta/ngc_dsp_std.o \ + src/meta/ngc_ffcc_str.o \ + src/meta/ngc_iadp.o \ + src/meta/ngc_pdt.o \ + src/meta/ngc_ssm.o \ + src/meta/ngc_tydsp.o \ + src/meta/ngc_waa_wac_wad_wam.o \ + src/meta/ngc_ymf.o \ + src/meta/nwa.o \ + src/meta/ogg_vorbis_file.o \ + src/meta/pcm.o \ + src/meta/pos.o \ + src/meta/ps2_ads.o \ + src/meta/ps2_ass.o \ + src/meta/ps2_aus.o \ + src/meta/ps2_bg00.o \ + src/meta/ps2_bmdx.o \ + src/meta/ps2_ccc.o \ + src/meta/ps2_dxh.o \ + src/meta/ps2_enth.o \ + src/meta/ps2_exst.o \ + src/meta/ps2_filp.o \ + src/meta/ps2_gbts.o \ + src/meta/ps2_hgc1.o \ + src/meta/ps2_ikm.o \ + src/meta/ps2_ild.o \ + src/meta/ps2_int.o \ + src/meta/ps2_joe.o \ + src/meta/ps2_kces.o \ + src/meta/ps2_leg.o \ + src/meta/ps2_mib.o \ + src/meta/ps2_mic.o \ + src/meta/ps2_mihb.o \ + src/meta/ps2_npsf.o \ + src/meta/ps2_p2bt.o \ + src/meta/ps2_pnb.o \ + src/meta/ps2_psh.o \ + src/meta/ps2_psw.o \ + src/meta/ps2_rkv.o \ + src/meta/ps2_rnd.o \ + src/meta/ps2_rstm.o \ + src/meta/ps2_rws.o \ + src/meta/ps2_rxw.o \ + src/meta/ps2_seg.o \ + src/meta/ps2_sfs.o \ + src/meta/ps2_sl3.o \ + src/meta/ps2_str.o \ + src/meta/ps2_svag.o \ + src/meta/ps2_tec.o \ + src/meta/ps2_vag.o \ + src/meta/ps2_vas.o \ + src/meta/ps2_vpk.o \ + src/meta/ps2_xa2.o \ + src/meta/ps2_xa30.o \ + src/meta/psx_cdxa.o \ + src/meta/psx_fag.o \ + src/meta/psx_gms.o \ + src/meta/raw.o \ + src/meta/riff.o \ + src/meta/rs03.o \ + src/meta/rsd.o \ + src/meta/rsf.o \ + src/meta/rwsd.o \ + src/meta/rwx.o \ + src/meta/sat_dvi.o \ + src/meta/sat_sap.o \ + src/meta/sdt.o \ + src/meta/sfl.o \ + src/meta/sli.o \ + src/meta/spt_spd.o \ + src/meta/ss_stream.o \ + src/meta/str_asr.o \ + src/meta/str_snds.o \ + src/meta/svs.o \ + src/meta/thp.o \ + src/meta/vgs.o \ + src/meta/vs.o \ + src/meta/wii_mus.o \ + src/meta/wii_smp.o \ + src/meta/wii_sng.o \ + src/meta/wii_sts.o \ + src/meta/ws_aud.o \ + src/meta/xbox_ims.o \ + src/meta/xbox_stma.o \ + src/meta/xbox_wavm.o \ + src/meta/xbox_wvs.o \ + src/meta/xbox_xmu.o \ + src/meta/xbox_xvas.o \ + src/meta/xbox_xwav.o \ + src/meta/xss.o \ + src/meta/xwb.o \ + src/meta/ydsp.o \ + src/meta/zwdsp.o + +OBJS = $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS) XBMCVGM.o src/vgmstream.o src/util.o src/streamfile.o + +SLIB=@abs_top_srcdir@/system/players/paplayer/vgmstream-@ARCH@.so + +$(SLIB): $(OBJS) +ifeq ($(findstring osx,$(ARCH)), osx) + ld -bundle -flat_namespace -undefined suppress -o $@ $(OBJS) $(BUNDLE1_O) + @abs_top_srcdir@/tools/Mach5/wrapper.rb $@;mv output.so $@ + chmod +x $@ +else + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -o $@ $(OBJS) `cat @abs_top_srcdir@/xbmc/cores/DllLoader/exports/wrapper.def` @abs_top_srcdir@/xbmc/cores/DllLoader/exports/wrapper.o + +endif + +include @abs_top_srcdir@/Makefile.include + diff --git a/lib/vgmstream/XBMCVGM.cpp b/lib/vgmstream/XBMCVGM.cpp new file mode 100644 index 0000000000..9228322f44 --- /dev/null +++ b/lib/vgmstream/XBMCVGM.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2008-2010 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef _LINUX +#include <windows.h> +#else +#define __cdecl +#define __declspec(x) +#endif + +extern "C" +{ + #include "src/vgmstream.h" + + long __declspec(dllexport) DLL_Init() + { + return 1; + } + + long __declspec(dllexport) DLL_LoadVGM(const char* szFileName, int* sampleRate, int* sampleSize, int* channels) + { + VGMSTREAM* result; + + if ((result = init_vgmstream(szFileName)) == NULL) + return 0; + + *sampleRate = result->sample_rate; + *sampleSize = 16; + *channels = result->channels; + return (long)result; + } + + void __declspec(dllexport) DLL_FreeVGM(long vgm) + { + close_vgmstream((VGMSTREAM*)vgm); + } + + int __declspec(dllexport) DLL_FillBuffer(long vgm, char* szBuffer, int iSize) + { + VGMSTREAM* song = (VGMSTREAM*)vgm; + render_vgmstream((sample*)szBuffer,iSize/(2*song->channels),(VGMSTREAM*)vgm); + + return iSize; + } + + unsigned long __declspec(dllexport) DLL_Seek(long vgm, unsigned long timepos) + { + VGMSTREAM* song = (VGMSTREAM*)vgm; + int16_t* buffer = new int16_t[576*song->channels]; + long samples_to_do = (long)timepos * song->sample_rate / 1000L; + if (samples_to_do < song->current_sample ) + reset_vgmstream(song); + else + samples_to_do -= song->current_sample; + + while (samples_to_do > 0) + { + long l = samples_to_do>576?576:samples_to_do; + render_vgmstream(buffer,l,song); + samples_to_do -= l; + } + delete[] buffer; + + return timepos; + } + + unsigned long __declspec(dllexport) DLL_GetLength(long vgm) + { + VGMSTREAM* song = (VGMSTREAM*)vgm; + + return song->num_samples/song->sample_rate*1000; + } +} diff --git a/lib/vgmstream/ext_includes/pstdint.h b/lib/vgmstream/ext_includes/pstdint.h new file mode 100644 index 0000000000..b36f63db3a --- /dev/null +++ b/lib/vgmstream/ext_includes/pstdint.h @@ -0,0 +1,728 @@ +/* A portable stdint.h + **************************************************************************** + * BSD License: + **************************************************************************** + * + * Copyright (c) 2005-2007 Paul Hsieh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************** + * + * Version 0.1.10 + * + * The ANSI C standard committee, for the C99 standard, specified the + * inclusion of a new standard include file called stdint.h. This is + * a very useful and long desired include file which contains several + * very precise definitions for integer scalar types that is + * critically important for making portable several classes of + * applications including cryptography, hashing, variable length + * integer libraries and so on. But for most developers its likely + * useful just for programming sanity. + * + * The problem is that most compiler vendors have decided not to + * implement the C99 standard, and the next C++ language standard + * (which has a lot more mindshare these days) will be a long time in + * coming and its unknown whether or not it will include stdint.h or + * how much adoption it will have. Either way, it will be a long time + * before all compilers come with a stdint.h and it also does nothing + * for the extremely large number of compilers available today which + * do not include this file, or anything comparable to it. + * + * So that's what this file is all about. Its an attempt to build a + * single universal include file that works on as many platforms as + * possible to deliver what stdint.h is supposed to. A few things + * that should be noted about this file: + * + * 1) It is not guaranteed to be portable and/or present an identical + * interface on all platforms. The extreme variability of the + * ANSI C standard makes this an impossibility right from the + * very get go. Its really only meant to be useful for the vast + * majority of platforms that possess the capability of + * implementing usefully and precisely defined, standard sized + * integer scalars. Systems which are not intrinsically 2s + * complement may produce invalid constants. + * + * 2) There is an unavoidable use of non-reserved symbols. + * + * 3) Other standard include files are invoked. + * + * 4) This file may come in conflict with future platforms that do + * include stdint.h. The hope is that one or the other can be + * used with no real difference. + * + * 5) In the current verison, if your platform can't represent + * int32_t, int16_t and int8_t, it just dumps out with a compiler + * error. + * + * 6) 64 bit integers may or may not be defined. Test for their + * presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX. + * Note that this is different from the C99 specification which + * requires the existence of 64 bit support in the compiler. If + * this is not defined for your platform, yet it is capable of + * dealing with 64 bits then it is because this file has not yet + * been extended to cover all of your system's capabilities. + * + * 7) (u)intptr_t may or may not be defined. Test for its presence + * with the test: #ifdef PTRDIFF_MAX. If this is not defined + * for your platform, then it is because this file has not yet + * been extended to cover all of your system's capabilities, not + * because its optional. + * + * 8) The following might not been defined even if your platform is + * capable of defining it: + * + * WCHAR_MIN + * WCHAR_MAX + * (u)int64_t + * PTRDIFF_MIN + * PTRDIFF_MAX + * (u)intptr_t + * + * 9) The following have not been defined: + * + * WINT_MIN + * WINT_MAX + * + * 10) The criteria for defining (u)int_least(*)_t isn't clear, + * except for systems which don't have a type that precisely + * defined 8, 16, or 32 bit types (which this include file does + * not support anyways). Default definitions have been given. + * + * 11) The criteria for defining (u)int_fast(*)_t isn't something I + * would trust to any particular compiler vendor or the ANSI C + * committee. It is well known that "compatible systems" are + * commonly created that have very different performance + * characteristics from the systems they are compatible with, + * especially those whose vendors make both the compiler and the + * system. Default definitions have been given, but its strongly + * recommended that users never use these definitions for any + * reason (they do *NOT* deliver any serious guarantee of + * improved performance -- not in this file, nor any vendor's + * stdint.h). + * + * 12) The following macros: + * + * PRINTF_INTMAX_MODIFIER + * PRINTF_INT64_MODIFIER + * PRINTF_INT32_MODIFIER + * PRINTF_INT16_MODIFIER + * PRINTF_LEAST64_MODIFIER + * PRINTF_LEAST32_MODIFIER + * PRINTF_LEAST16_MODIFIER + * PRINTF_INTPTR_MODIFIER + * + * are strings which have been defined as the modifiers required + * for the "d", "u" and "x" printf formats to correctly output + * (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t, + * (u)least32_t, (u)least16_t and (u)intptr_t types respectively. + * PRINTF_INTPTR_MODIFIER is not defined for some systems which + * provide their own stdint.h. PRINTF_INT64_MODIFIER is not + * defined if INT64_MAX is not defined. These are an extension + * beyond what C99 specifies must be in stdint.h. + * + * In addition, the following macros are defined: + * + * PRINTF_INTMAX_HEX_WIDTH + * PRINTF_INT64_HEX_WIDTH + * PRINTF_INT32_HEX_WIDTH + * PRINTF_INT16_HEX_WIDTH + * PRINTF_INT8_HEX_WIDTH + * PRINTF_INTMAX_DEC_WIDTH + * PRINTF_INT64_DEC_WIDTH + * PRINTF_INT32_DEC_WIDTH + * PRINTF_INT16_DEC_WIDTH + * PRINTF_INT8_DEC_WIDTH + * + * Which specifies the maximum number of characters required to + * print the number of that type in either hexadecimal or decimal. + * These are an extension beyond what C99 specifies must be in + * stdint.h. + * + * Compilers tested (all with 0 warnings at their highest respective + * settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32 + * bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio + * .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3 + * + * This file should be considered a work in progress. Suggestions for + * improvements, especially those which increase coverage are strongly + * encouraged. + * + * Acknowledgements + * + * The following people have made significant contributions to the + * development and testing of this file: + * + * Chris Howie + * John Steele Scott + * Dave Thorup + * + */ + +#include <stddef.h> +#include <limits.h> +#include <signal.h> + +/* + * For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and + * do nothing else. On the Mac OS X version of gcc this is _STDINT_H_. + */ + +#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) )) && !defined (_PSTDINT_H_INCLUDED) +#include <stdint.h> +#define _PSTDINT_H_INCLUDED +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "l" +# endif +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "h" +# endif +# ifndef PRINTF_INTMAX_MODIFIER +# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER +# endif +# ifndef PRINTF_INT64_HEX_WIDTH +# define PRINTF_INT64_HEX_WIDTH "16" +# endif +# ifndef PRINTF_INT32_HEX_WIDTH +# define PRINTF_INT32_HEX_WIDTH "8" +# endif +# ifndef PRINTF_INT16_HEX_WIDTH +# define PRINTF_INT16_HEX_WIDTH "4" +# endif +# ifndef PRINTF_INT8_HEX_WIDTH +# define PRINTF_INT8_HEX_WIDTH "2" +# endif +# ifndef PRINTF_INT64_DEC_WIDTH +# define PRINTF_INT64_DEC_WIDTH "20" +# endif +# ifndef PRINTF_INT32_DEC_WIDTH +# define PRINTF_INT32_DEC_WIDTH "10" +# endif +# ifndef PRINTF_INT16_DEC_WIDTH +# define PRINTF_INT16_DEC_WIDTH "5" +# endif +# ifndef PRINTF_INT8_DEC_WIDTH +# define PRINTF_INT8_DEC_WIDTH "3" +# endif +# ifndef PRINTF_INTMAX_HEX_WIDTH +# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH +# endif +# ifndef PRINTF_INTMAX_DEC_WIDTH +# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH +# endif + +/* + * Something really weird is going on with Open Watcom. Just pull some of + * these duplicated definitions from Open Watcom's stdint.h file for now. + */ + +# if defined (__WATCOMC__) && __WATCOMC__ >= 1250 +# if !defined (INT64_C) +# define INT64_C(x) (x + (INT64_MAX - INT64_MAX)) +# endif +# if !defined (UINT64_C) +# define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX)) +# endif +# if !defined (INT32_C) +# define INT32_C(x) (x + (INT32_MAX - INT32_MAX)) +# endif +# if !defined (UINT32_C) +# define UINT32_C(x) (x + (UINT32_MAX - UINT32_MAX)) +# endif +# if !defined (INT16_C) +# define INT16_C(x) (x) +# endif +# if !defined (UINT16_C) +# define UINT16_C(x) (x) +# endif +# if !defined (INT8_C) +# define INT8_C(x) (x) +# endif +# if !defined (UINT8_C) +# define UINT8_C(x) (x) +# endif +# if !defined (UINT64_MAX) +# define UINT64_MAX 18446744073709551615ULL +# endif +# if !defined (INT64_MAX) +# define INT64_MAX 9223372036854775807LL +# endif +# if !defined (UINT32_MAX) +# define UINT32_MAX 4294967295UL +# endif +# if !defined (INT32_MAX) +# define INT32_MAX 2147483647L +# endif +# if !defined (INTMAX_MAX) +# define INTMAX_MAX INT64_MAX +# endif +# if !defined (INTMAX_MIN) +# define INTMAX_MIN INT64_MIN +# endif +# endif +#endif + +#ifndef _PSTDINT_H_INCLUDED +#define _PSTDINT_H_INCLUDED + +#ifndef SIZE_MAX +# define SIZE_MAX (~(size_t)0) +#endif + +/* + * Deduce the type assignments from limits.h under the assumption that + * integer sizes in bits are powers of 2, and follow the ANSI + * definitions. + */ + +#ifndef UINT8_MAX +# define UINT8_MAX 0xff +#endif +#ifndef uint8_t +# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S) + typedef unsigned char uint8_t; +# define UINT8_C(v) ((uint8_t) v) +# else +# error "Platform not supported" +# endif +#endif + +#ifndef INT8_MAX +# define INT8_MAX 0x7f +#endif +#ifndef INT8_MIN +# define INT8_MIN INT8_C(0x80) +#endif +#ifndef int8_t +# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S) + typedef signed char int8_t; +# define INT8_C(v) ((int8_t) v) +# else +# error "Platform not supported" +# endif +#endif + +#ifndef UINT16_MAX +# define UINT16_MAX 0xffff +#endif +#ifndef uint16_t +#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S) + typedef unsigned int uint16_t; +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "" +# endif +# define UINT16_C(v) ((uint16_t) (v)) +#elif (USHRT_MAX == UINT16_MAX) + typedef unsigned short uint16_t; +# define UINT16_C(v) ((uint16_t) (v)) +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "h" +# endif +#else +#error "Platform not supported" +#endif +#endif + +#ifndef INT16_MAX +# define INT16_MAX 0x7fff +#endif +#ifndef INT16_MIN +# define INT16_MIN INT16_C(0x8000) +#endif +#ifndef int16_t +#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S) + typedef signed int int16_t; +# define INT16_C(v) ((int16_t) (v)) +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "" +# endif +#elif (SHRT_MAX == INT16_MAX) + typedef signed short int16_t; +# define INT16_C(v) ((int16_t) (v)) +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "h" +# endif +#else +#error "Platform not supported" +#endif +#endif + +#ifndef UINT32_MAX +# define UINT32_MAX (0xffffffffUL) +#endif +#ifndef uint32_t +#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S) + typedef unsigned long uint32_t; +# define UINT32_C(v) v ## UL +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "l" +# endif +#elif (UINT_MAX == UINT32_MAX) + typedef unsigned int uint32_t; +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +# define UINT32_C(v) v ## U +#elif (USHRT_MAX == UINT32_MAX) + typedef unsigned short uint32_t; +# define UINT32_C(v) ((unsigned short) (v)) +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +#else +#error "Platform not supported" +#endif +#endif + +#ifndef INT32_MAX +# define INT32_MAX (0x7fffffffL) +#endif +#ifndef INT32_MIN +# define INT32_MIN INT32_C(0x80000000) +#endif +#ifndef int32_t +#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S) + typedef signed long int32_t; +# define INT32_C(v) v ## L +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "l" +# endif +#elif (INT_MAX == INT32_MAX) + typedef signed int int32_t; +# define INT32_C(v) v +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +#elif (SHRT_MAX == INT32_MAX) + typedef signed short int32_t; +# define INT32_C(v) ((short) (v)) +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +#else +#error "Platform not supported" +#endif +#endif + +/* + * The macro stdint_int64_defined is temporarily used to record + * whether or not 64 integer support is available. It must be + * defined for any 64 integer extensions for new platforms that are + * added. + */ + +#undef stdint_int64_defined +#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S) +# if (__STDC__ && __STDC_VERSION >= 199901L) || defined (S_SPLINT_S) +# define stdint_int64_defined + typedef long long int64_t; + typedef unsigned long long uint64_t; +# define UINT64_C(v) v ## ULL +# define INT64_C(v) v ## LL +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# endif +#endif + +#if !defined (stdint_int64_defined) +# if defined(__GNUC__) +# define stdint_int64_defined + __extension__ typedef long long int64_t; + __extension__ typedef unsigned long long uint64_t; +# define UINT64_C(v) v ## ULL +# define INT64_C(v) v ## LL +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S) +# define stdint_int64_defined + typedef long long int64_t; + typedef unsigned long long uint64_t; +# define UINT64_C(v) v ## ULL +# define INT64_C(v) v ## LL +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC) +# define stdint_int64_defined + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +# define UINT64_C(v) v ## UI64 +# define INT64_C(v) v ## I64 +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "I64" +# endif +# endif +#endif + +#if !defined (LONG_LONG_MAX) && defined (INT64_C) +# define LONG_LONG_MAX INT64_C (9223372036854775807) +#endif +#ifndef ULONG_LONG_MAX +# define ULONG_LONG_MAX UINT64_C (18446744073709551615) +#endif + +#if !defined (INT64_MAX) && defined (INT64_C) +# define INT64_MAX INT64_C (9223372036854775807) +#endif +#if !defined (INT64_MIN) && defined (INT64_C) +# define INT64_MIN INT64_C (-9223372036854775808) +#endif +#if !defined (UINT64_MAX) && defined (INT64_C) +# define UINT64_MAX UINT64_C (18446744073709551615) +#endif + +/* + * Width of hexadecimal for number field. + */ + +#ifndef PRINTF_INT64_HEX_WIDTH +# define PRINTF_INT64_HEX_WIDTH "16" +#endif +#ifndef PRINTF_INT32_HEX_WIDTH +# define PRINTF_INT32_HEX_WIDTH "8" +#endif +#ifndef PRINTF_INT16_HEX_WIDTH +# define PRINTF_INT16_HEX_WIDTH "4" +#endif +#ifndef PRINTF_INT8_HEX_WIDTH +# define PRINTF_INT8_HEX_WIDTH "2" +#endif + +#ifndef PRINTF_INT64_DEC_WIDTH +# define PRINTF_INT64_DEC_WIDTH "20" +#endif +#ifndef PRINTF_INT32_DEC_WIDTH +# define PRINTF_INT32_DEC_WIDTH "10" +#endif +#ifndef PRINTF_INT16_DEC_WIDTH +# define PRINTF_INT16_DEC_WIDTH "5" +#endif +#ifndef PRINTF_INT8_DEC_WIDTH +# define PRINTF_INT8_DEC_WIDTH "3" +#endif + +/* + * Ok, lets not worry about 128 bit integers for now. Moore's law says + * we don't need to worry about that until about 2040 at which point + * we'll have bigger things to worry about. + */ + +#ifdef stdint_int64_defined + typedef int64_t intmax_t; + typedef uint64_t uintmax_t; +# define INTMAX_MAX INT64_MAX +# define INTMAX_MIN INT64_MIN +# define UINTMAX_MAX UINT64_MAX +# define UINTMAX_C(v) UINT64_C(v) +# define INTMAX_C(v) INT64_C(v) +# ifndef PRINTF_INTMAX_MODIFIER +# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER +# endif +# ifndef PRINTF_INTMAX_HEX_WIDTH +# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH +# endif +# ifndef PRINTF_INTMAX_DEC_WIDTH +# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH +# endif +#else + typedef int32_t intmax_t; + typedef uint32_t uintmax_t; +# define INTMAX_MAX INT32_MAX +# define UINTMAX_MAX UINT32_MAX +# define UINTMAX_C(v) UINT32_C(v) +# define INTMAX_C(v) INT32_C(v) +# ifndef PRINTF_INTMAX_MODIFIER +# define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER +# endif +# ifndef PRINTF_INTMAX_HEX_WIDTH +# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH +# endif +# ifndef PRINTF_INTMAX_DEC_WIDTH +# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH +# endif +#endif + +/* + * Because this file currently only supports platforms which have + * precise powers of 2 as bit sizes for the default integers, the + * least definitions are all trivial. Its possible that a future + * version of this file could have different definitions. + */ + +#ifndef stdint_least_defined + typedef int8_t int_least8_t; + typedef uint8_t uint_least8_t; + typedef int16_t int_least16_t; + typedef uint16_t uint_least16_t; + typedef int32_t int_least32_t; + typedef uint32_t uint_least32_t; +# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER +# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER +# define UINT_LEAST8_MAX UINT8_MAX +# define INT_LEAST8_MAX INT8_MAX +# define UINT_LEAST16_MAX UINT16_MAX +# define INT_LEAST16_MAX INT16_MAX +# define UINT_LEAST32_MAX UINT32_MAX +# define INT_LEAST32_MAX INT32_MAX +# define INT_LEAST8_MIN INT8_MIN +# define INT_LEAST16_MIN INT16_MIN +# define INT_LEAST32_MIN INT32_MIN +# ifdef stdint_int64_defined + typedef int64_t int_least64_t; + typedef uint64_t uint_least64_t; +# define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER +# define UINT_LEAST64_MAX UINT64_MAX +# define INT_LEAST64_MAX INT64_MAX +# define INT_LEAST64_MIN INT64_MIN +# endif +#endif +#undef stdint_least_defined + +/* + * The ANSI C committee pretending to know or specify anything about + * performance is the epitome of misguided arrogance. The mandate of + * this file is to *ONLY* ever support that absolute minimum + * definition of the fast integer types, for compatibility purposes. + * No extensions, and no attempt to suggest what may or may not be a + * faster integer type will ever be made in this file. Developers are + * warned to stay away from these types when using this or any other + * stdint.h. + */ + +typedef int_least8_t int_fast8_t; +typedef uint_least8_t uint_fast8_t; +typedef int_least16_t int_fast16_t; +typedef uint_least16_t uint_fast16_t; +typedef int_least32_t int_fast32_t; +typedef uint_least32_t uint_fast32_t; +#define UINT_FAST8_MAX UINT_LEAST8_MAX +#define INT_FAST8_MAX INT_LEAST8_MAX +#define UINT_FAST16_MAX UINT_LEAST16_MAX +#define INT_FAST16_MAX INT_LEAST16_MAX +#define UINT_FAST32_MAX UINT_LEAST32_MAX +#define INT_FAST32_MAX INT_LEAST32_MAX +#define INT_FAST8_MIN INT_LEAST8_MIN +#define INT_FAST16_MIN INT_LEAST16_MIN +#define INT_FAST32_MIN INT_LEAST32_MIN +#ifdef stdint_int64_defined + typedef int_least64_t int_fast64_t; + typedef uint_least64_t uint_fast64_t; +# define UINT_FAST64_MAX UINT_LEAST64_MAX +# define INT_FAST64_MAX INT_LEAST64_MAX +# define INT_FAST64_MIN INT_LEAST64_MIN +#endif + +#undef stdint_int64_defined + +/* + * Whatever piecemeal, per compiler thing we can do about the wchar_t + * type limits. + */ + +#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__) +# include <wchar.h> +# ifndef WCHAR_MIN +# define WCHAR_MIN 0 +# endif +# ifndef WCHAR_MAX +# define WCHAR_MAX ((wchar_t)-1) +# endif +#endif + +/* + * Whatever piecemeal, per compiler/platform thing we can do about the + * (u)intptr_t types and limits. + */ + +#if defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED) +# define STDINT_H_UINTPTR_T_DEFINED +#endif + +#ifndef STDINT_H_UINTPTR_T_DEFINED +# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64) +# define stdint_intptr_bits 64 +# elif defined (__WATCOMC__) || defined (__TURBOC__) +# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__) +# define stdint_intptr_bits 16 +# else +# define stdint_intptr_bits 32 +# endif +# elif defined (__i386__) || defined (_WIN32) || defined (WIN32) +# define stdint_intptr_bits 32 +# elif defined (__INTEL_COMPILER) +/* TODO -- what will Intel do about x86-64? */ +# endif + +# ifdef stdint_intptr_bits +# define stdint_intptr_glue3_i(a,b,c) a##b##c +# define stdint_intptr_glue3(a,b,c) stdint_intptr_glue3_i(a,b,c) +# ifndef PRINTF_INTPTR_MODIFIER +# define PRINTF_INTPTR_MODIFIER stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER) +# endif +# ifndef PTRDIFF_MAX +# define PTRDIFF_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX) +# endif +# ifndef PTRDIFF_MIN +# define PTRDIFF_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN) +# endif +# ifndef UINTPTR_MAX +# define UINTPTR_MAX stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX) +# endif +# ifndef INTPTR_MAX +# define INTPTR_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX) +# endif +# ifndef INTPTR_MIN +# define INTPTR_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN) +# endif +# ifndef INTPTR_C +# define INTPTR_C(x) stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x) +# endif +# ifndef UINTPTR_C +# define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x) +# endif + typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t; + typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t; +# else +/* TODO -- This following is likely wrong for some platforms, and does + nothing for the definition of uintptr_t. */ + typedef ptrdiff_t intptr_t; +# endif +# define STDINT_H_UINTPTR_T_DEFINED +#endif + +/* + * Assumes sig_atomic_t is signed and we have a 2s complement machine. + */ + +#ifndef SIG_ATOMIC_MAX +# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1) +#endif + +#endif diff --git a/lib/vgmstream/readme.txt b/lib/vgmstream/readme.txt new file mode 100644 index 0000000000..9e6f24cabd --- /dev/null +++ b/lib/vgmstream/readme.txt @@ -0,0 +1,148 @@ +vgmstream + +This is vgmstream, a library for playing streamed audio from video games. +It is very much under development. There are two end-user bits: a command +line decoder called "test", and a simple Winamp plugin called "in_vgmstream". + +--- needed files (for Windows) --- +Since Ogg Vorbis and MPEG audio are now supported, you will need to have +libvorbis.dll and libmpg123-0.dll. +I suggest getting libvorbis.dll here: +http://www.rarewares.org/files/ogg/libvorbis1.2.0.zip +and the companion Intel math dll: +http://www.rarewares.org/files/libmmd9.1.zip +And libmpg123-0.dll from this archive: +http://www.mpg123.de/download/win32/mpg123-1.4.3-x86.zip + +Put libvorbis.dll, libmmd.dll, and libmpg123-0.dll somewhere Windows can find +them. For in_vgmstream this means in the directory with winamp.exe, or in a +system directory. For test.exe this means in the same directory as test.exe, +or in a system directory. + +--- test.exe --- +Usage: test.exe [-o outfile.wav] [-l loop count] + [-f fade time] [-d fade delay] [-ipPcmxeE] infile +Options: + -o outfile.wav: name of output .wav file, default is dump.wav + -l loop count: loop count, default 2.0 + -f fade time: fade time (seconds), default 10.0 + -d fade delay: fade delay (seconds, default 0.0 + -i: ignore looping information and play the whole stream once + -p: output to stdout (for piping into another program) + -P: output to stdout even if stdout is a terminal + -c: loop forever (continuously) + -m: print metadata only, don't decode + -x: decode and print adxencd command line to encode as ADX + -e: force end-to-end looping + -E: force end-to-end looping even if file has real loop points + -r outfile2.wav: output a second time after resetting + +Typical usage would be: +test -o happy.wav happy.adx +to decode happy.adx to happy.wav. + +--- in_vgmstream --- +Drop the in_vgmstream.dll in your Winamp plugins directory. + +--- +File types supported by this version of vgmstream: +- .adx (CRI ADX ADPCM) +- .brstm (RSTM: GC/Wii DSP ADPCM, 8/16 bit PCM) +- .strm (STRM: NDS IMA ADPCM, 8/16 bit PCM) +- .adp (GC DTK ADPCM) +- .agsc (GC DSP ADPCM) +- .rsf (CCITT G.721 ADPCM) +- .afc (GC AFC ADPCM) +- .ast (GC/Wii AFC ADPCM, 16 bit PCM) +- .hps (GC DSP ADPCM) +- .dsp (GC DSP ADPCM) + - standard, with dual file stereo + - RS03 + - Cstr + - .stm + - _lr.dsp +- .gcsw (16 bit PCM) +- .ads/.ss2 (PSX ADPCM) +- .npsf (PSX ADPCM) +- .rwsd (Wii DSP ADPCM, 8/16 bit PCM) +- .xa (CD-ROM XA audio) +- .rxw (PSX ADPCM) +- .int (16 bit PCM) +- .stm/.dsp (GC DSP ADPCM) +- .sts (PSX ADPCM) +- .svag (PSX ADPCM) +- .mib, .mi4 (w/ or w/o .mih) (PSX ADPCM) +- .mpdsp (GC DSP ADPCM) +- .mic (PSX ADPCM) +- .mss (GC DSP ADPCM) +- .gcm (GC DSP ADPCM) +- .raw (16 bit PCM) +- .vag (PSX ADPCM) +- .gms (PSX ADPCM) +- .str+.sth (PSX ADPCM) +- .ild (PSX APDCM) +- .pnb (PSX ADPCM) +- .wavm (XBOX IMA ADPCM) +- .xwav (XBOX IMA ADPCM) +- .wp2 (PSX ADPCM) +- .str (GC DSP ADPCM) +- .sng, .asf, .str, .eam (EA/XA ADPCM or PSX ADPCM) +- .cfn (GC DSP ADPCM) +- .vpk (PSX ADPCM) +- .genh (PSX ADPCM, XBOX IMA ADPCM, GC DTK ADPCM, 8/16 bit PCM, SDX2, DVI, MPEG) +- .ogg, .logg (Ogg Vorbis) +- .sad (GC DSP ADPCM) +- .bmdx (PSX ADPCM) +- .wsi (Wii DSP ADPCM) +- .aifc (SDX2 DPCM, DVI IMA ADPCM) +- .aiff (8/16 bit PCM) +- .str (SDX2 DPCM) +- .aud (IMA ADPCM, WS DPCM) +- .ahx (MPEG-2 Layer II) +- .ivb (PS2 ADPCM) +- .amts (GC DSP ADPCM) +- .svs (PS2 ADPCM) +- .wav (8/16 bit PCM) +- .lwav (8/16 bit PCM) +- .pos (loop info for .wav) +- .nwa (16 bit PCM, NWA DPCM) +- .xss (16 bit PCM) +- .sl3 (PS2 ADPCM) +- .hgc1 (PS2 ADPCM) +- .aus (PS2 ADPCM) +- .rws (PS2 ADPCM) +- .fsb (PS2 ADPCM, Wii DSP ADPCM, Xbox IMA ADPCM) +- .rsd (PS2 ADPCM, 16 bit PCM) +- .rwx (16 bit PCM) +- .xwb (16 bit PCM) +- .asf, .as4 (8/16 bit PCM, EACS IMA ADPCM) +- .cnk (PS2 ADPCM) +- .xa30 (PS2 ADPCM) +- .musc (PS2 ADPCM) +- .leg (PS2 ADPCM) +- .filp (PS2 ADPCM) +- .ikm (PS2 ADPCM) +- .musx (PS2 ADPCM) +- .sfs (PS2 ADPCM) +- .bg00 (PS2 ADPCM) +- .dvi (DVI IMA ADPCM) +- .kcey (EACS IMA ADPCM) +- .rstm (PS2 ADPCM) +- .acm (InterPlay ACM) +- .sli (loop info for .ogg) +- .psh (PS2 ADPCM) +- .vig (PS2 ADPCM) +- .sfl (loop info for .ogg); +- .um3 (Ogg Vorbis) +- .rkv (PS2 ADPCM) +- .psw (PS2 ADPCM) +- .vas (PS2 ADPCM) +- .tec (PS2 ADPCM) +- .enth (PS2 ADPCM) +- .sdt (GC DSP ADPCM) +- .aix (CRI ADX ADPCM) +- .tydsp (GC DSP ADPCM) +- .matx (xbox audio) + +Enjoy! +-hcs diff --git a/lib/vgmstream/src/coding/acm_decoder.c b/lib/vgmstream/src/coding/acm_decoder.c new file mode 100644 index 0000000000..edc53d742a --- /dev/null +++ b/lib/vgmstream/src/coding/acm_decoder.c @@ -0,0 +1,839 @@ +/* + * ACM decoder. + * + * Copyright (c) 2004-2008, Marko Kreen + * Copyright (c) 2008, Adam Gashlin + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "coding.h" +#include "../vgmstream.h" +#include "../streamtypes.h" +#include "acm_decoder.h" + +#define ACM_EXPECTED_EOF -99 + +typedef int (*filler_t)(ACMStream *acm, unsigned ind, unsigned col); + +/************************************** + * Stream processing + **************************************/ + +/* NB: bits <= 31! Thus less checks in code. */ + +static int get_bits_reload(ACMStream *acm, unsigned bits) +{ + int got; + unsigned data, b_data, b_avail; + + data = acm->bit_data; + got = acm->bit_avail; + bits -= got; + + switch (acm->data_len - acm->buf_start_ofs) { + case 0: + b_data = 0; + b_avail = 8; + break; + case 1: + b_data = (uint8_t)read_8bit(acm->buf_start_ofs,acm->streamfile); + b_avail = 8; + acm->buf_start_ofs += 1; + break; + case 2: + b_data = (uint16_t)read_16bitLE(acm->buf_start_ofs,acm->streamfile); + b_avail = 16; + acm->buf_start_ofs += 2; + break; + case 3: + b_data = (uint8_t)read_8bit(acm->buf_start_ofs,acm->streamfile); + b_data |= (int32_t)(uint16_t)read_16bitLE(acm->buf_start_ofs+1,acm->streamfile)<<8; + b_avail = 24; + acm->buf_start_ofs += 3; + break; + case 4: + default: + if (acm->data_len - acm->buf_start_ofs <= 0) { + b_data = 0; + b_avail = 8; + break; + } + + b_data = read_32bitLE(acm->buf_start_ofs,acm->streamfile); + b_avail = 32; + acm->buf_start_ofs += 4; + break; + } + + data |= (b_data & ((1 << bits) - 1)) << got; + acm->bit_data = b_data >> bits; + acm->bit_avail = b_avail - bits; + return data; +} + +#define GET_BITS_NOERR(tmpval, acm, bits) do { \ + if (acm->bit_avail >= bits) { \ + tmpval = acm->bit_data & ((1 << bits) - 1); \ + acm->bit_data >>= bits; \ + acm->bit_avail -= bits; \ + } else \ + tmpval = get_bits_reload(acm, bits); \ + } while (0) + +#define GET_BITS(res, acm, bits) do { \ + int tmpval; \ + GET_BITS_NOERR(tmpval, acm, bits); \ + if (tmpval < 0) \ + return tmpval; \ + res = tmpval; \ + } while (0) + +#define GET_BITS_EXPECT_EOF(res, acm, bits) do { \ + int tmpval; \ + GET_BITS_NOERR(tmpval, acm, bits); \ + if (tmpval < 0) { \ + if (tmpval == ACM_ERR_UNEXPECTED_EOF) \ + return ACM_EXPECTED_EOF; \ + return tmpval; \ + } \ + res = tmpval; \ + } while (0) + +/************************************************* + * Table filling + *************************************************/ +static const int map_1bit[] = { -1, +1 }; +static const int map_2bit_near[] = { -2, -1, +1, +2 }; +static const int map_2bit_far[] = { -3, -2, +2, +3 }; +static const int map_3bit[] = { -4, -3, -2, -1, +1, +2, +3, +4 }; +static int mul_3x3[3*3*3]; +static int mul_3x5[5*5*5]; +static int mul_2x11[11*11]; +static int tables_generated; + +static void generate_tables(void) +{ + int x1, x2, x3; + if (tables_generated) + return; + for (x3 = 0; x3 < 3; x3++) + for (x2 = 0; x2 < 3; x2++) + for (x1 = 0; x1 < 3; x1++) + mul_3x3[x1 + x2*3 + x3*3*3] = + x1 + (x2 << 4) + (x3 << 8); + for (x3 = 0; x3 < 5; x3++) + for (x2 = 0; x2 < 5; x2++) + for (x1 = 0; x1 < 5; x1++) + mul_3x5[x1 + x2*5 + x3*5*5] = + x1 + (x2 << 4) + (x3 << 8); + for (x2 = 0; x2 < 11; x2++) + for (x1 = 0; x1 < 11; x1++) + mul_2x11[x1 + x2*11] = x1 + (x2 << 4); + + tables_generated = 1; +} + +/* IOW: (r * acm->subblock_len) + c */ +#define set_pos(acm, r, c, idx) do { \ + unsigned _pos = ((r) << acm->info.acm_level) + (c); \ + acm->block[_pos] = acm->midbuf[idx]; \ + } while (0) + +/************ Fillers **********/ + +static int f_zero(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i; + for (i = 0; i < acm->info.acm_rows; i++) + set_pos(acm, i, col, 0); + + return 1; +} + +static int f_bad(ACMStream *acm, unsigned ind, unsigned col) +{ + /* corrupt block? */ + return ACM_ERR_CORRUPT; +} + +static int f_linear(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned int i; + int b, middle = 1 << (ind - 1); + + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, ind); + set_pos(acm, i, col, b - middle); + } + return 1; +} + +static int f_k13(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i++, col, 0); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, 0); + continue; + } + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 0 */ + set_pos(acm, i, col, 0); + continue; + } + /* 1, 1, ? */ + GET_BITS(b, acm, 1); + set_pos(acm, i, col, map_1bit[b]); + } + return 1; +} + +static int f_k12(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i, col, 0); + continue; + } + + /* 1, ? */ + GET_BITS(b, acm, 1); + set_pos(acm, i, col, map_1bit[b]); + } + return 1; +} + +static int f_k24(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i++, col, 0); + if (i >= acm->info.acm_rows) break; + set_pos(acm, i, col, 0); + continue; + } + + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 0 */ + set_pos(acm, i, col, 0); + continue; + } + + /* 1, 1, ?, ? */ + GET_BITS(b, acm, 2); + set_pos(acm, i, col, map_2bit_near[b]); + } + return 1; +} + +static int f_k23(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i, col, 0); + continue; + } + + /* 1, ?, ? */ + GET_BITS(b, acm, 2); + set_pos(acm, i, col, map_2bit_near[b]); + } + return 1; +} + +static int f_k35(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i++, col, 0); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, 0); + continue; + } + + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 0 */ + set_pos(acm, i, col, 0); + continue; + } + + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 1, 0, ? */ + GET_BITS(b, acm, 1); + set_pos(acm, i, col, map_1bit[b]); + continue; + } + + /* 1, 1, 1, ?, ? */ + GET_BITS(b, acm, 2); + set_pos(acm, i, col, map_2bit_far[b]); + } + return 1; +} + +static int f_k34(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i, col, 0); + continue; + } + + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 0, ? */ + GET_BITS(b, acm, 1); + set_pos(acm, i, col, map_1bit[b]); + continue; + } + + /* 1, 1, ?, ? */ + GET_BITS(b, acm, 2); + set_pos(acm, i, col, map_2bit_far[b]); + } + return 1; +} + +static int f_k45(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i, col, 0); i++; + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, 0); + continue; + } + + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 0 */ + set_pos(acm, i, col, 0); + continue; + } + + /* 1, 1, ?, ?, ? */ + GET_BITS(b, acm, 3); + set_pos(acm, i, col, map_3bit[b]); + } + return 1; +} + +static int f_k44(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i, col, 0); + continue; + } + + /* 1, ?, ?, ? */ + GET_BITS(b, acm, 3); + set_pos(acm, i, col, map_3bit[b]); + } + return 1; +} + +static int f_t15(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i, b; + int n1, n2, n3; + for (i = 0; i < acm->info.acm_rows; i++) { + /* b = (x1) + (x2 * 3) + (x3 * 9) */ + GET_BITS(b, acm, 5); + + n1 = (mul_3x3[b] & 0x0F) - 1; + n2 = ((mul_3x3[b] >> 4) & 0x0F) - 1; + n3 = ((mul_3x3[b] >> 8) & 0x0F) - 1; + + set_pos(acm, i++, col, n1); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i++, col, n2); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, n3); + } + return 1; +} + +static int f_t27(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i, b; + int n1, n2, n3; + for (i = 0; i < acm->info.acm_rows; i++) { + /* b = (x1) + (x2 * 5) + (x3 * 25) */ + GET_BITS(b, acm, 7); + + n1 = (mul_3x5[b] & 0x0F) - 2; + n2 = ((mul_3x5[b] >> 4) & 0x0F) - 2; + n3 = ((mul_3x5[b] >> 8) & 0x0F) - 2; + + set_pos(acm, i++, col, n1); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i++, col, n2); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, n3); + } + return 1; +} + +static int f_t37(ACMStream *acm, unsigned ind, unsigned col) +{ + unsigned i, b; + int n1, n2; + for (i = 0; i < acm->info.acm_rows; i++) { + /* b = (x1) + (x2 * 11) */ + GET_BITS(b, acm, 7); + + n1 = (mul_2x11[b] & 0x0F) - 5; + n2 = ((mul_2x11[b] >> 4) & 0x0F) - 5; + + set_pos(acm, i++, col, n1); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, n2); + } + return 1; +} + +/****************/ + +static const filler_t filler_list[] = { + f_zero, f_bad, f_bad, f_linear, /* 0..3 */ + f_linear, f_linear, f_linear, f_linear, /* 4..7 */ + f_linear, f_linear, f_linear, f_linear, /* 8..11 */ + f_linear, f_linear, f_linear, f_linear, /* 12..15 */ + f_linear, f_k13, f_k12, f_t15, /* 16..19 */ + f_k24, f_k23, f_t27, f_k35, /* 20..23 */ + f_k34, f_bad, f_k45, f_k44, /* 24..27 */ + f_bad, f_t37, f_bad, f_bad /* 28..31 */ +}; + +static int fill_block(ACMStream *acm) +{ + unsigned i, ind; + int err; + for (i = 0; i < acm->info.acm_cols; i++) { + GET_BITS_EXPECT_EOF(ind, acm, 5); + err = filler_list[ind](acm, ind, i); + if (err < 0) + return err; + } + return 1; +} + +/********************************************** + * Decompress code + **********************************************/ + +static void juggle(int *wrap_p, int *block_p, unsigned sub_len, unsigned sub_count) +{ + unsigned int i, j; + int *p, r0, r1, r2, r3; + for (i = 0; i < sub_len; i++) { + p = block_p; + r0 = wrap_p[0]; + r1 = wrap_p[1]; + for (j = 0; j < sub_count/2; j++) { + r2 = *p; *p = r1*2 + (r0 + r2); p += sub_len; + r3 = *p; *p = r2*2 - (r1 + r3); p += sub_len; + r0 = r2; r1 = r3; + } + *wrap_p++ = r0; + *wrap_p++ = r1; + block_p++; + } +} + +static void juggle_block(ACMStream *acm) +{ + unsigned sub_count, sub_len, todo_count, step_subcount, i; + int *wrap_p, *block_p, *p; + + /* juggle only if subblock_len > 1 */ + if (acm->info.acm_level == 0) + return; + + /* 2048 / subblock_len */ + if (acm->info.acm_level > 9) + step_subcount = 1; + else + step_subcount = (2048 >> acm->info.acm_level) - 2; + + /* Apply juggle() (rows)x(cols) + * from (step_subcount * 2) x (subblock_len/2) + * to (step_subcount * subblock_len) x (1) + */ + todo_count = acm->info.acm_rows; + block_p = acm->block; + while (1) { + wrap_p = acm->wrapbuf; + sub_count = step_subcount; + if (sub_count > todo_count) + sub_count = todo_count; + + sub_len = acm->info.acm_cols / 2; + sub_count *= 2; + + juggle(wrap_p, block_p, sub_len, sub_count); + wrap_p += sub_len*2; + + for (i = 0, p = block_p; i < sub_count; i++) { + p[0]++; + p += sub_len; + } + + while (sub_len > 1) { + sub_len /= 2; + sub_count *= 2; + juggle(wrap_p, block_p, sub_len, sub_count); + wrap_p += sub_len*2; + } + if (todo_count <= step_subcount) + break; + todo_count -= step_subcount; + block_p += step_subcount << acm->info.acm_level; + } +} + +/***************************************************************/ +static int decode_block(ACMStream *acm) +{ + int pwr, count, val, i, x, err; + + acm->block_ready = 0; + acm->block_pos = 0; + + /* read header */ + GET_BITS_EXPECT_EOF(pwr, acm, 4); + GET_BITS_EXPECT_EOF(val, acm, 16); + + /* generate tables */ + count = 1 << pwr; + for (i = 0, x = 0; i < count; i++) { + acm->midbuf[i] = x; + x += val; + } + for (i = 1, x = -val; i <= count; i++) { + acm->midbuf[-i] = x; + x -= val; + } + + /* to_check? */ + if ((err = fill_block(acm)) <= 0) + return err; + + juggle_block(acm); + + acm->block_ready = 1; + + return 1; +} + +/****************************** + * Output formats + ******************************/ + +static unsigned char *out_s16le(int *src, unsigned char *dst, unsigned n, unsigned shift) +{ + while (n--) { + int val = *src++ >> shift; + *dst++ = val & 0xFF; + *dst++ = (val >> 8) & 0xFF; + } + return dst; +} + +static unsigned char *out_s16be(int *src, unsigned char *dst, unsigned n, unsigned shift) +{ + while (n--) { + int val = *src++ >> shift; + *dst++ = (val >> 8) & 0xFF; + *dst++ = val & 0xFF; + } + return dst; +} + +static unsigned char *out_u16le(int *src, unsigned char *dst, unsigned n, unsigned shift) +{ + while (n--) { + int val = (*src++ >> shift) + 0x8000; + *dst++ = val & 0xFF; + *dst++ = (val >> 8) & 0xFF; + } + return dst; +} + +static unsigned char *out_u16be(int *src, unsigned char *dst, unsigned n, unsigned shift) +{ + while (n--) { + int val = (*src++ >> shift) + 0x8000; + *dst++ = (val >> 8) & 0xFF; + *dst++ = val & 0xFF; + } + return dst; +} + +static int output_values(int *src, unsigned char *dst, int n, + int acm_level, int bigendianp, int wordlen, int sgned) +{ + unsigned char *res = NULL; + if (wordlen == 2) { + if (bigendianp == 0) { + if (sgned) + res = out_s16le(src, dst, n, acm_level); + else + res = out_u16le(src, dst, n, acm_level); + } else { + if (sgned) + res = out_s16be(src, dst, n, acm_level); + else + res = out_u16be(src, dst, n, acm_level); + } + } + if (res != NULL) + return res - dst; + return ACM_ERR_BADFMT; +} + +/* + * Header parsing. + */ + +static int read_header(ACMStream *acm) +{ + int tmp; + /* read header */ + GET_BITS(acm->info.acm_id, acm, 24); + if (acm->info.acm_id != ACM_ID) + return ACM_ERR_NOT_ACM; + GET_BITS(acm->info.acm_version, acm, 8); + if (acm->info.acm_version != 1) + return ACM_ERR_NOT_ACM; + GET_BITS(acm->total_values, acm, 16); + GET_BITS(tmp, acm, 16); + acm->total_values += tmp << 16; + if (acm->total_values == 0) + return ACM_ERR_NOT_ACM; + GET_BITS(acm->info.channels, acm, 16); + if (acm->info.channels < 1) + return ACM_ERR_NOT_ACM; + /* we play music, music is stereo, though not all headers agree */ + acm->info.channels = 2; + GET_BITS(acm->info.rate, acm, 16); + + GET_BITS(acm->info.acm_level, acm, 4); + GET_BITS(acm->info.acm_rows, acm, 12); + return 0; +} + +/*********************************************** + * Public functions + ***********************************************/ + +int acm_open_decoder(ACMStream **res, STREAMFILE *facilitator_file, + const char *const filename) +{ + int err = ACM_ERR_OTHER; + ACMStream *acm; + + acm = malloc(sizeof(*acm)); + if (!acm) + return err; + memset(acm, 0, sizeof(*acm)); + + acm->streamfile = facilitator_file->open(facilitator_file,filename, + STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (!acm->streamfile) + { + err = ACM_ERR_OPEN; + goto err_out; + } + + acm->data_len = get_streamfile_size(acm->streamfile); + + /* read header data */ + err = ACM_ERR_NOT_ACM; + if (read_header(acm) < 0) + goto err_out; + + /* calculate blocks */ + acm->info.acm_cols = 1 << acm->info.acm_level; + acm->wrapbuf_len = 2 * acm->info.acm_cols - 2; + acm->block_len = acm->info.acm_rows * acm->info.acm_cols; + + /* allocate */ + acm->block = malloc(acm->block_len * sizeof(int)); + acm->wrapbuf = malloc(acm->wrapbuf_len * sizeof(int)); + acm->ampbuf = malloc(0x10000 * sizeof(int)); + acm->midbuf = acm->ampbuf + 0x8000; + + memset(acm->wrapbuf, 0, acm->wrapbuf_len * sizeof(int)); + + generate_tables(); + + *res = acm; + return ACM_OK; + +err_out: + + acm_close(acm); + return err; +} + +int acm_read(ACMStream *acm, void *dst, unsigned numbytes, + int bigendianp, int wordlen, int sgned) +{ + int avail, gotbytes = 0, err; + int *src, numwords; + + if (wordlen == 2) + numwords = numbytes / 2; + else + return ACM_ERR_BADFMT; + + if (acm->stream_pos >= acm->total_values) + return 0; + + if (!acm->block_ready) { + err = decode_block(acm); + if (err == ACM_EXPECTED_EOF) + return 0; + if (err < 0) + return err; + } + + /* check how many words can be read */ + avail = acm->block_len - acm->block_pos; + if (avail < numwords) + numwords = avail; + + if (acm->stream_pos + numwords > acm->total_values) + numwords = acm->total_values - acm->stream_pos; + + if (acm->info.channels > 1) + numwords -= numwords % acm->info.channels; + + /* convert, but if dst == NULL, simulate */ + if (dst != NULL) { + src = acm->block + acm->block_pos; + gotbytes = output_values(src, dst, numwords, + acm->info.acm_level, + bigendianp, wordlen, sgned); + } else + gotbytes = numwords * wordlen; + + if (gotbytes >= 0) { + acm->stream_pos += numwords; + acm->block_pos += numwords; + if (acm->block_pos == acm->block_len) + acm->block_ready = 0; + } + + return gotbytes; +} + +void acm_close(ACMStream *acm) +{ + if (acm == NULL) + return; + if (acm->streamfile) { + close_streamfile(acm->streamfile); + acm->streamfile = NULL; + } + if (acm->block) + free(acm->block); + if (acm->wrapbuf) + free(acm->wrapbuf); + if (acm->ampbuf) + free(acm->ampbuf); + free(acm); +} + +void acm_reset(ACMStream *acm) +{ + acm->bit_avail = 0; + acm->bit_data = 0; + + acm->stream_pos = 0; + acm->block_pos = 0; + acm->block_ready = 0; + acm->buf_start_ofs = ACM_HEADER_LEN; + + memset(acm->wrapbuf, 0, acm->wrapbuf_len * sizeof(int)); +} + +/* interface to vgmstream */ +void decode_acm(ACMStream * acm, sample * outbuf, + int32_t samples_to_do, int channelspacing) { + int32_t samples_read = 0; + while (samples_read < samples_to_do) { + int32_t bytes_read_just_now; + bytes_read_just_now = + acm_read(acm,(char*)( + outbuf+samples_read*channelspacing), + (samples_to_do-samples_read)*sizeof(sample)* + channelspacing,0,2,1); + + if (bytes_read_just_now > 0) { + samples_read += + bytes_read_just_now/sizeof(sample)/channelspacing; + } else { + return; + } + } +} diff --git a/lib/vgmstream/src/coding/acm_decoder.h b/lib/vgmstream/src/coding/acm_decoder.h new file mode 100644 index 0000000000..2ddff5f84d --- /dev/null +++ b/lib/vgmstream/src/coding/acm_decoder.h @@ -0,0 +1,87 @@ +/* + * libacm - Interplay ACM audio decoder. + * + * Copyright (c) 2004-2008, Marko Kreen + * Copyright (c) 2008, Adam Gashlin + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __LIBACM_H +#define __LIBACM_H + +#include "../streamfile.h" + +#define LIBACM_VERSION "1.0-svn" + +#define ACM_ID 0x032897 +#define ACM_WORD 2 + +#define ACM_HEADER_LEN 14 +#define ACM_OK 0 +#define ACM_ERR_OTHER -1 +#define ACM_ERR_OPEN -2 +#define ACM_ERR_NOT_ACM -3 +#define ACM_ERR_READ_ERR -4 +#define ACM_ERR_BADFMT -5 +#define ACM_ERR_CORRUPT -6 +#define ACM_ERR_UNEXPECTED_EOF -7 +#define ACM_ERR_NOT_SEEKABLE -8 + +typedef struct ACMInfo { + unsigned channels; + unsigned rate; + unsigned acm_id; + unsigned acm_version; + unsigned acm_level; + unsigned acm_cols; /* 1 << acm_level */ + unsigned acm_rows; +} ACMInfo; + +struct ACMStream { + ACMInfo info; + unsigned total_values; + + /* acm data stream */ + STREAMFILE *streamfile; + unsigned data_len; + + /* acm stream buffer */ + unsigned bit_avail; + unsigned bit_data; + unsigned buf_start_ofs; + + /* block lengths (in samples) */ + unsigned block_len; + unsigned wrapbuf_len; + /* buffers */ + int *block; + int *wrapbuf; + int *ampbuf; + int *midbuf; /* pointer into ampbuf */ + /* result */ + unsigned block_ready:1; + unsigned file_eof:1; + unsigned stream_pos; /* in words. absolute */ + unsigned block_pos; /* in words, relative */ +}; +typedef struct ACMStream ACMStream; + +/* decode.c */ +int acm_open_decoder(ACMStream **res, STREAMFILE *facilitator_file, const char *const filename); +int acm_read(ACMStream *acm, void *buf, unsigned nbytes, + int bigendianp, int wordlen, int sgned); +void acm_close(ACMStream *acm); +void acm_reset(ACMStream *acm); + +#endif diff --git a/lib/vgmstream/src/coding/adx_decoder.c b/lib/vgmstream/src/coding/adx_decoder.c new file mode 100644 index 0000000000..338d82c44b --- /dev/null +++ b/lib/vgmstream/src/coding/adx_decoder.c @@ -0,0 +1,81 @@ +#include "coding.h" +#include "../util.h" + +void decode_adx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + int framesin = first_sample/32; + + int32_t scale = read_16bitBE(stream->offset+framesin*18,stream->streamfile) + 1; + int32_t hist1 = stream->adpcm_history1_32; + int32_t hist2 = stream->adpcm_history2_32; + int coef1 = stream->adpcm_coef[0]; + int coef2 = stream->adpcm_coef[1]; + + first_sample = first_sample%32; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int sample_byte = read_8bit(stream->offset+framesin*18+2+i/2,stream->streamfile); + + outbuf[sample_count] = clamp16( + (i&1? + get_low_nibble_signed(sample_byte): + get_high_nibble_signed(sample_byte) + ) * scale + + ((coef1 * hist1 + coef2 * hist2) >> 12) + ); + + hist2 = hist1; + hist1 = outbuf[sample_count]; + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_history2_32 = hist2; +} + +void adx_next_key(VGMSTREAMCHANNEL * stream) +{ + stream->adx_xor = ( stream->adx_xor * stream->adx_mult + stream->adx_add ) & 0x7fff; +} + +void decode_adx_enc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + int framesin = first_sample/32; + + int32_t scale = (read_16bitBE(stream->offset+framesin*18,stream->streamfile) ^ stream->adx_xor) + 1; + int32_t hist1 = stream->adpcm_history1_32; + int32_t hist2 = stream->adpcm_history2_32; + int coef1 = stream->adpcm_coef[0]; + int coef2 = stream->adpcm_coef[1]; + + first_sample = first_sample%32; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int sample_byte = read_8bit(stream->offset+framesin*18+2+i/2,stream->streamfile); + + outbuf[sample_count] = clamp16( + (i&1? + get_low_nibble_signed(sample_byte): + get_high_nibble_signed(sample_byte) + ) * scale + + ((coef1 * hist1 + coef2 * hist2) >> 12) + ); + + hist2 = hist1; + hist1 = outbuf[sample_count]; + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_history2_32 = hist2; + + if (!(i % 32)) { + for (i=0;i<stream->adx_channels;i++) + { + adx_next_key(stream); + } + } + +} diff --git a/lib/vgmstream/src/coding/aica_decoder.c b/lib/vgmstream/src/coding/aica_decoder.c new file mode 100644 index 0000000000..9bd6b7468b --- /dev/null +++ b/lib/vgmstream/src/coding/aica_decoder.c @@ -0,0 +1,50 @@ +#include "../util.h" +#include "coding.h" + +/* fixed point (.8) amount to scale the current step size by */ +/* part of the same series as used in MS ADPCM "ADPCMTable" */ +static const unsigned int scale_step[16] = +{ + 230, 230, 230, 230, 307, 409, 512, 614, + 230, 230, 230, 230, 307, 409, 512, 614 +}; + +/* expand an unsigned four bit delta to a wider signed range */ +static const int scale_delta[16] = +{ + 1, 3, 5, 7, 9, 11, 13, 15, + -1, -3, -5, -7, -9,-11,-13,-15 +}; + +/* Yamaha AICA ADPCM (as seen in Dreamcast) */ + +void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + int32_t hist1 = stream->adpcm_history1_16; + unsigned long step_size = stream->adpcm_step_index; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int sample_nibble = + ( + (unsigned)read_8bit(stream->offset+i/2,stream->streamfile) >> + (i&1?4:0) + )&0xf; + + int32_t sample_delta = (int32_t)step_size * scale_delta[sample_nibble]; + int32_t new_sample; + + new_sample = hist1 + sample_delta/8; + + outbuf[sample_count] = clamp16(new_sample); + + hist1 = outbuf[sample_count]; + + step_size = (step_size * scale_step[sample_nibble])/0x100; + if (step_size < 0x7f) step_size = 0x7f; + if (step_size > 0x6000) step_size = 0x6000; + } + + stream->adpcm_history1_16 = hist1; + stream->adpcm_step_index = step_size; +} diff --git a/lib/vgmstream/src/coding/coding.h b/lib/vgmstream/src/coding/coding.h new file mode 100644 index 0000000000..de7c26d113 --- /dev/null +++ b/lib/vgmstream/src/coding/coding.h @@ -0,0 +1,83 @@ +#ifndef _CODING_H +#define _CODING_H + +#include "../vgmstream.h" + +void decode_adx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_adx_enc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void adx_next_key(VGMSTREAMCHANNEL * stream); + +void decode_g721(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void g72x_init_state(struct g72x_state *state_ptr); + +void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); +void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_eacs_ima(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); + +void decode_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void decode_ngc_afc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_ngc_dsp_mem(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem); + +int32_t dsp_nibbles_to_samples(int32_t nibbles); + +void decode_ngc_dtk(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); + +void decode_pcm16LE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm16LE_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm16BE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void decode_invert_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void decode_ffxi_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); +void init_get_high_nibble(VGMSTREAM * vgmstream); + +void decode_eaxa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); +void decode_ea_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); + +#ifdef VGM_USE_VORBIS +void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels); +#endif + +void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +#ifdef VGM_USE_MPEG +void decode_fake_mpeg2_l2(VGMSTREAMCHANNEL * stream, + mpeg_codec_data * data, + sample * outbuf, int32_t samples_to_do); +void decode_mpeg(VGMSTREAMCHANNEL * stream, + mpeg_codec_data * data, + sample * outbuf, int32_t samples_to_do, int channels); +#endif + +void decode_acm(ACMStream * acm, sample * outbuf, + int32_t samples_to_do, int channelspacing); + +void decode_nwa(NWAData *nwa, sample *outbuf, int32_t samples_to_do); + +void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do); + +void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void decode_nds_procyon(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void decode_l5_555(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +#endif diff --git a/lib/vgmstream/src/coding/eaxa_decoder.c b/lib/vgmstream/src/coding/eaxa_decoder.c new file mode 100644 index 0000000000..16a4d23e8b --- /dev/null +++ b/lib/vgmstream/src/coding/eaxa_decoder.c @@ -0,0 +1,117 @@ +#include "coding.h" +#include "../util.h" + +long EA_XA_TABLE[28] = {0,0,240,0,460,-208,0x0188,-220, + 0x0000,0x0000,0x00F0,0x0000, + 0x01CC,0x0000,0x0188,0x0000, + 0x0000,0x0000,0x0000,0x0000, + -208,-1,-220,-1, + 0x0000,0x0000,0x0000,0x3F70}; + +long EA_TABLE[20]= { 0x00000000, 0x000000F0, 0x000001CC, 0x00000188, + 0x00000000, 0x00000000, 0xFFFFFF30, 0xFFFFFF24, + 0x00000000, 0x00000001, 0x00000003, 0x00000004, + 0x00000007, 0x00000008, 0x0000000A, 0x0000000B, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFC}; + +void decode_eaxa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { + uint8_t frame_info; + int32_t sample_count; + long coef1,coef2; + int i,shift; + off_t channel_offset=stream->channel_start_offset; + + first_sample = first_sample%28; + frame_info = (uint8_t)read_8bit(stream->offset+channel_offset,stream->streamfile); + + if(frame_info==0xEE) { + + channel_offset++; + stream->adpcm_history1_32 = read_16bitBE(stream->offset+channel_offset,stream->streamfile); + stream->adpcm_history2_32 = read_16bitBE(stream->offset+channel_offset+2,stream->streamfile); + + channel_offset+=4; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + outbuf[sample_count]=read_16bitBE(stream->offset+channel_offset,stream->streamfile); + channel_offset+=2; + } + + // Only increment offset on complete frame + if(channel_offset-stream->channel_start_offset==(2*28)+5) + stream->channel_start_offset+=(2*28)+5; + + } else { + + + coef1 = EA_XA_TABLE[((frame_info >> 4) & 0x0F) << 1]; + coef2 = EA_XA_TABLE[(((frame_info >> 4) & 0x0F) << 1) + 1]; + shift = (frame_info & 0x0F) + 8; + + channel_offset++; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + uint8_t sample_byte = (uint8_t)read_8bit(stream->offset+channel_offset+i/2,stream->streamfile); + int32_t sample = ((((i&1? + sample_byte & 0x0F: + sample_byte >> 4 + ) << 0x1C) >> shift) + + (coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32)) >> 8; + + outbuf[sample_count] = clamp16(sample); + stream->adpcm_history2_32 = stream->adpcm_history1_32; + stream->adpcm_history1_32 = sample; + } + + channel_offset+=i/2; + + // Only increment offset on complete frame + if(channel_offset-stream->channel_start_offset==0x0F) + stream->channel_start_offset+=0x0F; + } +} + + +void decode_ea_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { + uint8_t frame_info; + int32_t sample_count; + long coef1,coef2; + int i,shift; + VGMSTREAMCHANNEL *stream = &(vgmstream->ch[channel]); + off_t channel_offset=stream->channel_start_offset; + + vgmstream->get_high_nibble=!vgmstream->get_high_nibble; + + first_sample = first_sample%28; + frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile); + + coef1 = EA_TABLE[(vgmstream->get_high_nibble? frame_info & 0x0F: frame_info >> 4)]; + coef2 = EA_TABLE[(vgmstream->get_high_nibble? frame_info & 0x0F: frame_info >> 4) + 4]; + + channel_offset++; + + frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile); + shift = (vgmstream->get_high_nibble? frame_info & 0x0F : frame_info >> 4)+8; + + channel_offset++; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + uint8_t sample_byte = (uint8_t)read_8bit(stream->offset+channel_offset+i,stream->streamfile); + int32_t sample = ((((vgmstream->get_high_nibble? + sample_byte & 0x0F: + sample_byte >> 4 + ) << 0x1C) >> shift) + + (coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32) + 0x80) >> 8; + + outbuf[sample_count] = clamp16(sample); + stream->adpcm_history2_32 = stream->adpcm_history1_32; + stream->adpcm_history1_32 = sample; + } + + channel_offset+=i; + + // Only increment offset on complete frame + if(channel_offset-stream->channel_start_offset==0x1E) + stream->channel_start_offset+=0x1E; +} + diff --git a/lib/vgmstream/src/coding/g721_decoder.c b/lib/vgmstream/src/coding/g721_decoder.c new file mode 100644 index 0000000000..41e147ac44 --- /dev/null +++ b/lib/vgmstream/src/coding/g721_decoder.c @@ -0,0 +1,471 @@ +/* G.721 decoder, from Sun's public domain CCITT-ADPCM sources, + * retrieved from ftp://ftp.cwi.nl/pub/audio/ccitt-adpcm.tar.gz + * + * For reference, here's the original license: + * + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + */ + +#include "coding.h" +#include "../util.h" + +static short power2[15] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, + 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000}; + +/* + * quan() + * + * quantizes the input val against the table of size short integers. + * It returns i if table[i - 1] <= val < table[i]. + * + * Using linear search for simple coding. + */ +static int +quan( + int val, + short *table, + int size) +{ + int i; + + for (i = 0; i < size; i++) + if (val < *table++) + break; + return (i); +} + +/* + * fmult() + * + * returns the integer product of the 14-bit integer "an" and + * "floating point" representation (4-bit exponent, 6-bit mantessa) "srn". + */ +static int +fmult( + int an, + int srn) +{ + short anmag, anexp, anmant; + short wanexp, wanmant; + short retval; + + anmag = (an > 0) ? an : ((-an) & 0x1FFF); + anexp = quan(anmag, power2, 15) - 6; + anmant = (anmag == 0) ? 32 : + (anexp >= 0) ? anmag >> anexp : anmag << -anexp; + wanexp = anexp + ((srn >> 6) & 0xF) - 13; + + wanmant = (anmant * (srn & 077) + 0x30) >> 4; + retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) : + (wanmant >> -wanexp); + + return (((an ^ srn) < 0) ? -retval : retval); +} + +/* + * g72x_init_state() + * + * This routine initializes and/or resets the g72x_state structure + * pointed to by 'state_ptr'. + * All the initial state values are specified in the CCITT G.721 document. + */ +void +g72x_init_state( + struct g72x_state *state_ptr) +{ + int cnta; + + state_ptr->yl = 34816; + state_ptr->yu = 544; + state_ptr->dms = 0; + state_ptr->dml = 0; + state_ptr->ap = 0; + for (cnta = 0; cnta < 2; cnta++) { + state_ptr->a[cnta] = 0; + state_ptr->pk[cnta] = 0; + state_ptr->sr[cnta] = 32; + } + for (cnta = 0; cnta < 6; cnta++) { + state_ptr->b[cnta] = 0; + state_ptr->dq[cnta] = 32; + } + state_ptr->td = 0; +} + +/* + * predictor_zero() + * + * computes the estimated signal from 6-zero predictor. + * + */ +int +predictor_zero( + struct g72x_state *state_ptr) +{ + int i; + int sezi; + + sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]); + for (i = 1; i < 6; i++) /* ACCUM */ + sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]); + return (sezi); +} +/* + * predictor_pole() + * + * computes the estimated signal from 2-pole predictor. + * + */ +int +predictor_pole( + struct g72x_state *state_ptr) +{ + return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) + + fmult(state_ptr->a[0] >> 2, state_ptr->sr[0])); +} +/* + * step_size() + * + * computes the quantization step size of the adaptive quantizer. + * + */ +int +step_size( + struct g72x_state *state_ptr) +{ + int y; + int dif; + int al; + + if (state_ptr->ap >= 256) + return (state_ptr->yu); + else { + y = state_ptr->yl >> 6; + dif = state_ptr->yu - y; + al = state_ptr->ap >> 2; + if (dif > 0) + y += (dif * al) >> 6; + else if (dif < 0) + y += (dif * al + 0x3F) >> 6; + return (y); + } +} + +/* + * reconstruct() + * + * Returns reconstructed difference signal 'dq' obtained from + * codeword 'i' and quantization step size scale factor 'y'. + * Multiplication is performed in log base 2 domain as addition. + */ +int +reconstruct( + int sign, /* 0 for non-negative value */ + int dqln, /* G.72x codeword */ + int y) /* Step size multiplier */ +{ + short dql; /* Log of 'dq' magnitude */ + short dex; /* Integer part of log */ + short dqt; + short dq; /* Reconstructed difference signal sample */ + + dql = dqln + (y >> 2); /* ADDA */ + + if (dql < 0) { + return ((sign) ? -0x8000 : 0); + } else { /* ANTILOG */ + dex = (dql >> 7) & 15; + dqt = 128 + (dql & 127); + dq = (dqt << 7) >> (14 - dex); + return ((sign) ? (dq - 0x8000) : dq); + } +} + + +/* + * update() + * + * updates the state variables for each output code + */ +void +update( + /*int code_size,*/ /* distinguish 723_40 with others */ + int y, /* quantizer step size */ + int wi, /* scale factor multiplier */ + int fi, /* for long/short term energies */ + int dq, /* quantized prediction difference */ + int sr, /* reconstructed signal */ + int dqsez, /* difference from 2-pole predictor */ + struct g72x_state *state_ptr) /* coder state pointer */ +{ + int cnt; + short mag, exp; /* Adaptive predictor, FLOAT A */ + short a2p; /* LIMC */ + short a1ul; /* UPA1 */ + short pks1; /* UPA2 */ + short fa1; + char tr; /* tone/transition detector */ + short ylint, thr2, dqthr; + short ylfrac, thr1; + short pk0; + + pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */ + + mag = dq & 0x7FFF; /* prediction difference magnitude */ + /* TRANS */ + ylint = state_ptr->yl >> 15; /* exponent part of yl */ + ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */ + thr1 = (32 + ylfrac) << ylint; /* threshold */ + thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */ + dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */ + if (state_ptr->td == 0) /* signal supposed voice */ + tr = 0; + else if (mag <= dqthr) /* supposed data, but small mag */ + tr = 0; /* treated as voice */ + else /* signal is data (modem) */ + tr = 1; + + /* + * Quantizer scale factor adaptation. + */ + + /* FUNCTW & FILTD & DELAY */ + /* update non-steady state step size multiplier */ + state_ptr->yu = y + ((wi - y) >> 5); + + /* LIMB */ + if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */ + state_ptr->yu = 544; + else if (state_ptr->yu > 5120) + state_ptr->yu = 5120; + + /* FILTE & DELAY */ + /* update steady state step size multiplier */ + state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6); + + /* + * Adaptive predictor coefficients. + */ + if (tr == 1) { /* reset a's and b's for modem signal */ + state_ptr->a[0] = 0; + state_ptr->a[1] = 0; + state_ptr->b[0] = 0; + state_ptr->b[1] = 0; + state_ptr->b[2] = 0; + state_ptr->b[3] = 0; + state_ptr->b[4] = 0; + state_ptr->b[5] = 0; + a2p=0; /* won't be used, clear warning */ + } else { /* update a's and b's */ + pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */ + + /* update predictor pole a[1] */ + a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7); + if (dqsez != 0) { + fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0]; + if (fa1 < -8191) /* a2p = function of fa1 */ + a2p -= 0x100; + else if (fa1 > 8191) + a2p += 0xFF; + else + a2p += fa1 >> 5; + + if (pk0 ^ state_ptr->pk[1]) + /* LIMC */ + if (a2p <= -12160) + a2p = -12288; + else if (a2p >= 12416) + a2p = 12288; + else + a2p -= 0x80; + else if (a2p <= -12416) + a2p = -12288; + else if (a2p >= 12160) + a2p = 12288; + else + a2p += 0x80; + } + + /* TRIGB & DELAY */ + state_ptr->a[1] = a2p; + + /* UPA1 */ + /* update predictor pole a[0] */ + state_ptr->a[0] -= state_ptr->a[0] >> 8; + if (dqsez != 0) { + if (pks1 == 0) + state_ptr->a[0] += 192; + else + state_ptr->a[0] -= 192; + } + + /* LIMD */ + a1ul = 15360 - a2p; + if (state_ptr->a[0] < -a1ul) + state_ptr->a[0] = -a1ul; + else if (state_ptr->a[0] > a1ul) + state_ptr->a[0] = a1ul; + + /* UPB : update predictor zeros b[6] */ + for (cnt = 0; cnt < 6; cnt++) { + /*if (code_size == 5)*/ /* for 40Kbps G.723 */ + /* state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;*/ + /*else*/ /* for G.721 and 24Kbps G.723 */ + state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8; + if (dq & 0x7FFF) { /* XOR */ + if ((dq ^ state_ptr->dq[cnt]) >= 0) + state_ptr->b[cnt] += 128; + else + state_ptr->b[cnt] -= 128; + } + } + } + + for (cnt = 5; cnt > 0; cnt--) + state_ptr->dq[cnt] = state_ptr->dq[cnt-1]; + /* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */ + if (mag == 0) { + state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20; + } else { + exp = quan(mag, power2, 15); + state_ptr->dq[0] = (dq >= 0) ? + (exp << 6) + ((mag << 6) >> exp) : + (exp << 6) + ((mag << 6) >> exp) - 0x400; + } + + state_ptr->sr[1] = state_ptr->sr[0]; + /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */ + if (sr == 0) { + state_ptr->sr[0] = 0x20; + } else if (sr > 0) { + exp = quan(sr, power2, 15); + state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp); + } else if (sr > -32768) { + mag = -sr; + exp = quan(mag, power2, 15); + state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400; + } else + state_ptr->sr[0] = 0xFC20; + + /* DELAY A */ + state_ptr->pk[1] = state_ptr->pk[0]; + state_ptr->pk[0] = pk0; + + /* TONE */ + if (tr == 1) /* this sample has been treated as data */ + state_ptr->td = 0; /* next one will be treated as voice */ + else if (a2p < -11776) /* small sample-to-sample correlation */ + state_ptr->td = 1; /* signal may be data */ + else /* signal is voice */ + state_ptr->td = 0; + + /* + * Adaptation speed control. + */ + state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */ + state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */ + + if (tr == 1) + state_ptr->ap = 256; + else if (y < 1536) /* SUBTC */ + state_ptr->ap += (0x200 - state_ptr->ap) >> 4; + else if (state_ptr->td == 1) + state_ptr->ap += (0x200 - state_ptr->ap) >> 4; + else if (abs((state_ptr->dms << 2) - state_ptr->dml) >= + (state_ptr->dml >> 3)) + state_ptr->ap += (0x200 - state_ptr->ap) >> 4; + else + state_ptr->ap += (-state_ptr->ap) >> 4; +} + +/* + * Maps G.721 code word to reconstructed scale factor normalized log + * magnitude values. + */ +static short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425, + 425, 373, 323, 273, 213, 135, 4, -2048}; + +/* Maps G.721 code word to log of scale factor multiplier. */ +static short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122, + 1122, 355, 198, 112, 64, 41, 18, -12}; +/* + * Maps G.721 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00, + 0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0}; +/* + * g721_decoder() + * + * Description: + * + * Decodes a 4-bit code of G.721 encoded data of i and + * returns the resulting linear PCM, A-law or u-law value. + * return -1 for unknown out_coding value. + */ +int +g721_decoder( + int i, + struct g72x_state *state_ptr) +{ + short sezi, sei, sez, se; /* ACCUM */ + short y; /* MIX */ + short sr; /* ADDB */ + short dq; + short dqsez; + + i &= 0x0f; /* mask to get proper bits */ + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + sei = sezi + predictor_pole(state_ptr); + se = sei >> 1; /* se = estimated signal */ + + y = step_size(state_ptr); /* dynamic quantizer step size */ + + dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */ + + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */ + + dqsez = sr - se + sez; /* pole prediction diff. */ + + update(y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr); + + return (sr << 2); /* sr was 14-bit dynamic range */ +} + +void decode_g721(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + outbuf[sample_count]= + g721_decoder( + read_8bit(stream->offset+i/2,stream->streamfile)>>(i&1?4:0), + &(stream->g72x_state) + ); + } +} diff --git a/lib/vgmstream/src/coding/g72x_state.h b/lib/vgmstream/src/coding/g72x_state.h new file mode 100644 index 0000000000..bf1a6ade59 --- /dev/null +++ b/lib/vgmstream/src/coding/g72x_state.h @@ -0,0 +1,35 @@ +/* + * streamtypes.h - widely used type definitions + */ + + +#ifndef _G72X_STATE_H +#define _G72X_STATE_H + +struct g72x_state { + long yl; /* Locked or steady state step size multiplier. */ + short yu; /* Unlocked or non-steady state step size multiplier. */ + short dms; /* Short term energy estimate. */ + short dml; /* Long term energy estimate. */ + short ap; /* Linear weighting coefficient of 'yl' and 'yu'. */ + + short a[2]; /* Coefficients of pole portion of prediction filter. */ + short b[6]; /* Coefficients of zero portion of prediction filter. */ + short pk[2]; /* + * Signs of previous two samples of a partially + * reconstructed signal. + */ + short dq[6]; /* + * Previous 6 samples of the quantized difference + * signal represented in an internal floating point + * format. + */ + short sr[2]; /* + * Previous 2 samples of the quantized difference + * signal represented in an internal floating point + * format. + */ + char td; /* delayed tone detect, new in 1988 version */ +}; + +#endif diff --git a/lib/vgmstream/src/coding/ima_decoder.c b/lib/vgmstream/src/coding/ima_decoder.c new file mode 100644 index 0000000000..e190647e57 --- /dev/null +++ b/lib/vgmstream/src/coding/ima_decoder.c @@ -0,0 +1,273 @@ +#include "../util.h" +#include "coding.h" + +const int32_t ADPCMTable[89] = + +{ + + 7, 8, 9, 10, 11, 12, 13, 14, + 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, + 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, + 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, + 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, + 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767 + +}; + +const int IMA_IndexTable[16] = + +{ + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 +}; + +void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i=first_sample; + int32_t sample_count; + int32_t hist1 = stream->adpcm_history1_16; + int step_index = stream->adpcm_step_index; + + if (first_sample==0) { + hist1 = read_16bitLE(stream->offset,stream->streamfile); + step_index = read_16bitLE(stream->offset+2,stream->streamfile); + } + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int sample_nibble = + (read_8bit(stream->offset+4+i/2,stream->streamfile) >> (i&1?4:0))&0xf; + int delta; + int step = ADPCMTable[step_index]; + + delta = step >> 3; + if (sample_nibble & 1) delta += step >> 2; + if (sample_nibble & 2) delta += step >> 1; + if (sample_nibble & 4) delta += step; + if (sample_nibble & 8) + outbuf[sample_count] = clamp16(hist1 - delta); + else + outbuf[sample_count] = clamp16(hist1 + delta); + + step_index += IMA_IndexTable[sample_nibble]; + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + + hist1 = outbuf[sample_count]; + } + + stream->adpcm_history1_16 = hist1; + stream->adpcm_step_index = step_index; +} + +void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { + int i=first_sample; + int sample_nibble; + int sample_decoded; + int delta; + + int32_t sample_count=0; + int32_t hist1=stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + off_t offset=stream->offset; + + if(vgmstream->channels==1) + first_sample = first_sample % 32; + else + first_sample = first_sample % (32*(vgmstream->channels&2)); + + if (first_sample == 0) { + + if(vgmstream->layout_type==layout_ea_blocked) { + hist1 = read_16bitLE(offset,stream->streamfile); + step_index = read_16bitLE(offset+2,stream->streamfile); + } else { + hist1 = read_16bitLE(offset+(channel%2)*4,stream->streamfile); + step_index = read_16bitLE(offset+(channel%2)*4+2,stream->streamfile); + } + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + } + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int step = ADPCMTable[step_index]; + + if(vgmstream->layout_type==layout_ea_blocked) + offset = stream->offset + (i/8*4+(i%8)/2+4); + else { + if(channelspacing==1) + offset = stream->offset + 4 + (i/8*4+(i%8)/2+4*(channel%2)); + else + offset = stream->offset + 4*2 + (i/8*4*2+(i%8)/2+4*(channel%2)); + } + + sample_nibble = (read_8bit(offset,stream->streamfile) >> (i&1?4:0))&0xf; + + sample_decoded=hist1; + + delta = step >> 3; + if (sample_nibble & 1) delta += step >> 2; + if (sample_nibble & 2) delta += step >> 1; + if (sample_nibble & 4) delta += step; + if (sample_nibble & 8) + sample_decoded -= delta; + else + sample_decoded += delta; + + hist1=clamp16(sample_decoded); + + step_index += IMA_IndexTable[sample_nibble]; + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + + outbuf[sample_count]=(short)(hist1); + } + + // Only increment offset on complete frame + if(vgmstream->layout_type==layout_ea_blocked) { + if(offset-stream->offset==32+3) // ?? + stream->offset+=36; + } else { + if(channelspacing==1) { + if(offset-stream->offset==32+3) // ?? + stream->offset+=36; + } else { + if(offset-stream->offset==64+(4*(channel%2))+3) // ?? + stream->offset+=36*channelspacing; + } + } + stream->adpcm_history1_32=hist1; + stream->adpcm_step_index=step_index; +} + +void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + + int32_t sample_count=0; + int32_t hist1=stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int step = ADPCMTable[step_index]; + uint8_t sample_byte; + int sample_nibble; + int sample_decoded; + int delta; + + sample_byte = read_8bit(stream->offset+i/2,stream->streamfile); + /* old-style DVI takes high nibble first */ + sample_nibble = (sample_byte >> (i&1?0:4))&0xf; + + sample_decoded = hist1; + delta = step >> 3; + if (sample_nibble & 1) delta += step >> 2; + if (sample_nibble & 2) delta += step >> 1; + if (sample_nibble & 4) delta += step; + if (sample_nibble & 8) + sample_decoded -= delta; + else + sample_decoded += delta; + + hist1=clamp16(sample_decoded); + + step_index += IMA_IndexTable[sample_nibble&0x7]; + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + + outbuf[sample_count]=(short)(hist1); + } + + stream->adpcm_history1_32=hist1; + stream->adpcm_step_index=step_index; +} + + +void decode_eacs_ima(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { + int i; + VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]); + + int32_t sample_count=0; + int32_t hist1=stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + vgmstream->get_high_nibble=!vgmstream->get_high_nibble; + + if((first_sample) && (channelspacing==1)) + vgmstream->get_high_nibble=!vgmstream->get_high_nibble; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int step = ADPCMTable[step_index]; + uint8_t sample_byte; + int sample_nibble; + int sample_decoded; + int delta; + + sample_byte = read_8bit(stream->offset+i,stream->streamfile); + sample_nibble = (sample_byte >> (vgmstream->get_high_nibble?0:4))&0xf; + + sample_decoded = hist1; + delta = step >> 3; + if (sample_nibble & 1) delta += step >> 2; + if (sample_nibble & 2) delta += step >> 1; + if (sample_nibble & 4) delta += step; + if (sample_nibble & 8) + sample_decoded -= delta; + else + sample_decoded += delta; + + hist1=clamp16(sample_decoded); + + step_index += IMA_IndexTable[sample_nibble&0x7]; + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + + outbuf[sample_count]=(short)(hist1); + } + + stream->adpcm_history1_32=hist1; + stream->adpcm_step_index=step_index; +} + +void decode_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + + int32_t sample_count=0; + int32_t hist1=stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int step = ADPCMTable[step_index]; + uint8_t sample_byte; + int sample_nibble; + int sample_decoded; + int delta; + + sample_byte = read_8bit(stream->offset+i/2,stream->streamfile); + sample_nibble = (sample_byte >> (i&1?4:0))&0xf; + + sample_decoded = hist1; + delta = step >> 3; + if (sample_nibble & 1) delta += step >> 2; + if (sample_nibble & 2) delta += step >> 1; + if (sample_nibble & 4) delta += step; + if (sample_nibble & 8) + sample_decoded -= delta; + else + sample_decoded += delta; + + hist1=clamp16(sample_decoded); + + step_index += IMA_IndexTable[sample_nibble&0x7]; + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + + outbuf[sample_count]=(short)(hist1); + } + + stream->adpcm_history1_32=hist1; + stream->adpcm_step_index=step_index; +} diff --git a/lib/vgmstream/src/coding/l5_555_decoder.c b/lib/vgmstream/src/coding/l5_555_decoder.c new file mode 100644 index 0000000000..0a12e83720 --- /dev/null +++ b/lib/vgmstream/src/coding/l5_555_decoder.c @@ -0,0 +1,58 @@ +#include "coding.h" +#include "../util.h" + +static const int32_t l5_scales[32] = { + 0x00001000, 0x0000144E, 0x000019C5, 0x000020B4, 0x00002981, 0x000034AC, 0x000042D9, 0x000054D6, + 0x00006BAB, 0x000088A4, 0x0000AD69, 0x0000DC13, 0x0001174C, 0x00016275, 0x0001C1D8, 0x00023AE5, + 0x0002D486, 0x0003977E, 0x00048EEE, 0x0005C8F3, 0x00075779, 0x0009513E, 0x000BD31C, 0x000F01B5, + 0x00130B82, 0x00182B83, 0x001EAC92, 0x0026EDB2, 0x00316777, 0x003EB2E6, 0x004F9232, 0x0064FBD1 +}; + +void decode_l5_555(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i=first_sample; + int32_t sample_count; + + int framesin = first_sample/32; + + uint16_t header = (uint16_t)read_16bitLE(framesin*0x12+stream->offset,stream->streamfile); + int32_t pos_scale = l5_scales[(header>>5)&0x1f]; + int32_t neg_scale = l5_scales[header&0x1f]; + + int coef_index = (header >> 10) & 0x1f; + int16_t hist1 = stream->adpcm_history1_16; + int16_t hist2 = stream->adpcm_history2_16; + int16_t hist3 = stream->adpcm_history3_16; + int32_t coef1 = stream->adpcm_coef_3by32[coef_index*3]; + int32_t coef2 = stream->adpcm_coef_3by32[coef_index*3+1]; + int32_t coef3 = stream->adpcm_coef_3by32[coef_index*3+2]; + /*printf("offset: %x\nscale: %d\nindex: %d (%lf,%lf)\nhist: %d %d\n", + (unsigned)stream->offset,scale,coef_index,coef1/2048.0,coef2/2048.0,hist1,hist2);*/ + + first_sample = first_sample%32; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int sample_byte = read_8bit(framesin*0x12+stream->offset+2+i/2,stream->streamfile); + int nibble = (i&1? + get_low_nibble_signed(sample_byte): + get_high_nibble_signed(sample_byte)); + int32_t prediction = + -(hist1 * coef1 + hist2 * coef2 + hist3 * coef3); + + if (nibble >= 0) + { + outbuf[sample_count] = clamp16((prediction + nibble * pos_scale) >> 12); + } + else + { + outbuf[sample_count] = clamp16((prediction + nibble * neg_scale) >> 12); + } + + hist3 = hist2; + hist2 = hist1; + hist1 = outbuf[sample_count]; + } + + stream->adpcm_history1_16 = hist1; + stream->adpcm_history2_16 = hist2; + stream->adpcm_history3_16 = hist3; +} diff --git a/lib/vgmstream/src/coding/mpeg_decoder.c b/lib/vgmstream/src/coding/mpeg_decoder.c new file mode 100644 index 0000000000..ae176af9c2 --- /dev/null +++ b/lib/vgmstream/src/coding/mpeg_decoder.c @@ -0,0 +1,129 @@ +#include "../vgmstream.h" + +#ifdef VGM_USE_MPEG +#include <string.h> +#include <mpg123.h> +#include "coding.h" +#include "../util.h" + +/* mono, mpg123 expects frames of 0x414 (160kbps, 22050Hz) but they + * actually vary and are much shorter */ +void decode_fake_mpeg2_l2(VGMSTREAMCHANNEL *stream, + mpeg_codec_data * data, + sample * outbuf, int32_t samples_to_do) { + int samples_done = 0; + + while (samples_done < samples_to_do) { + size_t bytes_done; + int rc; + + if (!data->buffer_full) { + /* fill buffer up to next frame ending (or file ending) */ + int bytes_into_header = 0; + const uint8_t header[4] = {0xff,0xf5,0xe0,0xc0}; + off_t frame_offset = 0; + + /* assume that we are starting at a header, skip it and look for the + * next one */ + read_streamfile(data->buffer, stream->offset+frame_offset, 4, + stream->streamfile); + frame_offset += 4; + + do { + uint8_t byte; + byte = + read_8bit(stream->offset+frame_offset,stream->streamfile); + data->buffer[frame_offset] = byte; + frame_offset++; + + if (byte == header[bytes_into_header]) { + bytes_into_header++; + } else { + /* This might have been the first byte of the header, so + * we need to check again. + * No need to get more complicated than this, though, since + * there are no repeated characters in the search string. */ + if (bytes_into_header>0) { + frame_offset--; + } + bytes_into_header=0; + } + + if (bytes_into_header==4) { + break; + } + } while (frame_offset < AHX_EXPECTED_FRAME_SIZE); + + if (bytes_into_header==4) frame_offset-=4; + memset(data->buffer+frame_offset,0, + AHX_EXPECTED_FRAME_SIZE-frame_offset); + + data->buffer_full = 1; + data->buffer_used = 0; + + stream->offset += frame_offset; + } + + if (!data->buffer_used) { + rc = mpg123_decode(data->m, + data->buffer,AHX_EXPECTED_FRAME_SIZE, + (unsigned char *)(outbuf+samples_done), + (samples_to_do-samples_done)*sizeof(sample), + &bytes_done); + data->buffer_used = 1; + } else { + rc = mpg123_decode(data->m, + NULL,0, + (unsigned char *)(outbuf+samples_done), + (samples_to_do-samples_done)*sizeof(sample), + &bytes_done); + } + + if (rc == MPG123_NEED_MORE) data->buffer_full = 0; + + samples_done += bytes_done/sizeof(sample); + } +} + +/* decode anything mpg123 can */ +void decode_mpeg(VGMSTREAMCHANNEL *stream, + mpeg_codec_data * data, + sample * outbuf, int32_t samples_to_do, int channels) { + int samples_done = 0; + + while (samples_done < samples_to_do) { + size_t bytes_done; + int rc; + + if (!data->buffer_full) { + data->bytes_in_buffer = read_streamfile(data->buffer, + stream->offset,MPEG_BUFFER_SIZE,stream->streamfile); + + data->buffer_full = 1; + data->buffer_used = 0; + + stream->offset += data->bytes_in_buffer; + } + + if (!data->buffer_used) { + rc = mpg123_decode(data->m, + data->buffer,data->bytes_in_buffer, + (unsigned char *)(outbuf+samples_done*channels), + (samples_to_do-samples_done)*sizeof(sample)*channels, + &bytes_done); + data->buffer_used = 1; + } else { + rc = mpg123_decode(data->m, + NULL,0, + (unsigned char *)(outbuf+samples_done*channels), + (samples_to_do-samples_done)*sizeof(sample)*channels, + &bytes_done); + } + + if (rc == MPG123_NEED_MORE) data->buffer_full = 0; + + samples_done += bytes_done/sizeof(sample)/channels; + } +} + +#endif diff --git a/lib/vgmstream/src/coding/msadpcm_decoder.c b/lib/vgmstream/src/coding/msadpcm_decoder.c new file mode 100644 index 0000000000..9c2fbd9f38 --- /dev/null +++ b/lib/vgmstream/src/coding/msadpcm_decoder.c @@ -0,0 +1,96 @@ +#include "../util.h" +#include "coding.h" + +/* used to compute next scale */ +static const int ADPCMTable[16] = +{ + 230, 230, 230, 230, + 307, 409, 512, 614, + 768, 614, 512, 409, + 307, 230, 230, 230 +}; + +static const int ADPCMCoeffs[7][2] = +{ + { 256, 0 }, + { 512, -256 }, + { 0, 0 }, + { 192, 64 }, + { 240, 0 }, + { 460, -208 }, + { 392, -232 } +}; + +void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do) { + VGMSTREAMCHANNEL *ch1,*ch2; + int i; + int framesin; + STREAMFILE *streamfile; + off_t offset; + + framesin = first_sample/get_vgmstream_samples_per_frame(vgmstream); + first_sample = first_sample%get_vgmstream_samples_per_frame(vgmstream); + + ch1 = &vgmstream->ch[0]; + ch2 = &vgmstream->ch[1]; + streamfile = ch1->streamfile; + offset = ch1->offset+framesin*get_vgmstream_frame_size(vgmstream); + + if (first_sample==0) { + ch1->adpcm_coef[0] = ADPCMCoeffs[read_8bit(offset,streamfile)][0]; + ch1->adpcm_coef[1] = ADPCMCoeffs[read_8bit(offset,streamfile)][1]; + ch2->adpcm_coef[0] = ADPCMCoeffs[read_8bit(offset+1,streamfile)][0]; + ch2->adpcm_coef[1] = ADPCMCoeffs[read_8bit(offset+1,streamfile)][1]; + ch1->adpcm_scale = read_16bitLE(offset+2,streamfile); + ch2->adpcm_scale = read_16bitLE(offset+4,streamfile); + ch1->adpcm_history1_16 = read_16bitLE(offset+6,streamfile); + ch2->adpcm_history1_16 = read_16bitLE(offset+8,streamfile); + ch1->adpcm_history2_16 = read_16bitLE(offset+10,streamfile); + ch2->adpcm_history2_16 = read_16bitLE(offset+12,streamfile); + + outbuf[0] = ch1->adpcm_history2_16; + outbuf[1] = ch2->adpcm_history2_16; + + outbuf+=2; + first_sample++; + samples_to_do--; + } + if (first_sample==1 && samples_to_do > 0) { + outbuf[0] = ch1->adpcm_history1_16; + outbuf[1] = ch2->adpcm_history1_16; + + outbuf+=2; + first_sample++; + samples_to_do--; + } + + for (i=first_sample; i<first_sample+samples_to_do; i++) { + int j; + + for (j=0;j<2;j++) + { + VGMSTREAMCHANNEL *ch = &vgmstream->ch[j]; + int sample_nibble = + (j == 0 ? + get_high_nibble_signed(read_8bit(offset+14+i-2,streamfile)) : + get_low_nibble_signed(read_8bit(offset+14+i-2,streamfile)) + ); + int32_t hist1,hist2; + int32_t predicted; + + hist1 = ch->adpcm_history1_16; + hist2 = ch->adpcm_history2_16; + predicted = hist1 * ch->adpcm_coef[0] + hist2 * ch->adpcm_coef[1]; + predicted /= 256; + predicted += sample_nibble*ch->adpcm_scale; + outbuf[0] = clamp16(predicted); + ch->adpcm_history2_16 = ch->adpcm_history1_16; + ch->adpcm_history1_16 = outbuf[0]; + ch->adpcm_scale = (ADPCMTable[sample_nibble&0xf] * + ch->adpcm_scale) / 256; + if (ch->adpcm_scale < 0x10) ch->adpcm_scale = 0x10; + + outbuf++; + } + } +} diff --git a/lib/vgmstream/src/coding/nds_procyon_decoder.c b/lib/vgmstream/src/coding/nds_procyon_decoder.c new file mode 100644 index 0000000000..75f86125b2 --- /dev/null +++ b/lib/vgmstream/src/coding/nds_procyon_decoder.c @@ -0,0 +1,60 @@ +#include "coding.h" +#include "../util.h" + +/* ADPCM found in NDS games using Procyon Studio Digital Sound Elements */ + +static const int8_t proc_coef[5][2] = +{ + {0x00,0x00}, + {0x3C,0x00}, + {0x73,0xCC}, + {0x62,0xC9}, + {0x7A,0xC4}, +}; + +void decode_nds_procyon(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i=first_sample; + int32_t sample_count; + + int framesin = first_sample/30; + + uint8_t header = read_8bit(framesin*16+15+stream->offset,stream->streamfile) ^ 0x80; + int scale = 12 - (header & 0xf); + int coef_index = (header >> 4) & 0xf; + int32_t hist1 = stream->adpcm_history1_32; + int32_t hist2 = stream->adpcm_history2_32; + int32_t coef1; + int32_t coef2; + + if (coef_index > 4) coef_index = 0; + coef1 = proc_coef[coef_index][0]; + coef2 = proc_coef[coef_index][1]; + first_sample = first_sample%30; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int sample_byte = read_8bit(framesin*16+stream->offset+i/2,stream->streamfile) ^ 0x80; + + int32_t sample = + (int32_t) + (i&1? + get_high_nibble_signed(sample_byte): + get_low_nibble_signed(sample_byte) + ) * 64 * 64; + if (scale < 0) + { + sample <<= -scale; + } + else + sample >>= scale; + + sample = (hist1 * coef1 + hist2 * coef2 + 32) / 64 + (sample * 64); + + hist2 = hist1; + hist1 = sample; + + outbuf[sample_count] = clamp16((sample + 32) / 64) / 64 * 64; + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_history2_32 = hist2; +} diff --git a/lib/vgmstream/src/coding/ngc_afc_decoder.c b/lib/vgmstream/src/coding/ngc_afc_decoder.c new file mode 100644 index 0000000000..8c796f9518 --- /dev/null +++ b/lib/vgmstream/src/coding/ngc_afc_decoder.c @@ -0,0 +1,58 @@ +#include "coding.h" +#include "../util.h" + +const short afc_coef[16][2] = +{{0,0}, +{0x0800,0}, +{0,0x0800}, +{0x0400,0x0400}, +{0x1000,0xf800}, +{0x0e00,0xfa00}, +{0x0c00,0xfc00}, +{0x1200,0xf600}, +{0x1068,0xf738}, +{0x12c0,0xf704}, +{0x1400,0xf400}, +{0x0800,0xf800}, +{0x0400,0xfc00}, +{0xfc00,0x0400}, +{0xfc00,0}, +{0xf800,0}}; + +void decode_ngc_afc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i=first_sample; + int32_t sample_count; + + int framesin = first_sample/16; + + int8_t header = read_8bit(framesin*9+stream->offset,stream->streamfile); + int32_t scale = 1 << ((header>>4) & 0xf); + int coef_index = (header & 0xf); + int32_t hist1 = stream->adpcm_history1_16; + int32_t hist2 = stream->adpcm_history2_16; + int coef1 = afc_coef[coef_index][0]; + int coef2 = afc_coef[coef_index][1]; + /*printf("offset: %x\nscale: %d\nindex: %d (%lf,%lf)\nhist: %d %d\n", + (unsigned)stream->offset,scale,coef_index,coef1/2048.0,coef2/2048.0,hist1,hist2);*/ + + first_sample = first_sample%16; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int sample_byte = read_8bit(framesin*9+stream->offset+1+i/2,stream->streamfile); + + outbuf[sample_count] = clamp16(( + (((i&1? + get_low_nibble_signed(sample_byte): + get_high_nibble_signed(sample_byte) + ) * scale)<<11) + + (coef1 * hist1 + coef2 * hist2))>>11 + ); + /*printf("%hd\n",outbuf[sample_count]);*/ + + hist2 = hist1; + hist1 = outbuf[sample_count]; + } + + stream->adpcm_history1_16 = hist1; + stream->adpcm_history2_16 = hist2; +} diff --git a/lib/vgmstream/src/coding/ngc_dsp_decoder.c b/lib/vgmstream/src/coding/ngc_dsp_decoder.c new file mode 100644 index 0000000000..27825ae968 --- /dev/null +++ b/lib/vgmstream/src/coding/ngc_dsp_decoder.c @@ -0,0 +1,106 @@ +#include "coding.h" +#include "../util.h" + +void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i=first_sample; + int32_t sample_count; + + int framesin = first_sample/14; + + int8_t header = read_8bit(framesin*8+stream->offset,stream->streamfile); + int32_t scale = 1 << (header & 0xf); + int coef_index = (header >> 4) & 0xf; + int32_t hist1 = stream->adpcm_history1_16; + int32_t hist2 = stream->adpcm_history2_16; + int coef1 = stream->adpcm_coef[coef_index*2]; + int coef2 = stream->adpcm_coef[coef_index*2+1]; + + first_sample = first_sample%14; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int sample_byte = read_8bit(framesin*8+stream->offset+1+i/2,stream->streamfile); + +#ifdef DEBUG + if (hist1==stream->loop_history1 && hist2==stream->loop_history2) fprintf(stderr,"yo! %#x (start %#x) %d\n",stream->offset+framesin*8+i/2,stream->channel_start_offset,stream->samples_done); + stream->samples_done++; +#endif + + outbuf[sample_count] = clamp16(( + (((i&1? + get_low_nibble_signed(sample_byte): + get_high_nibble_signed(sample_byte) + ) * scale)<<11) + 1024 + + (coef1 * hist1 + coef2 * hist2))>>11 + ); + + hist2 = hist1; + hist1 = outbuf[sample_count]; + } + + stream->adpcm_history1_16 = hist1; + stream->adpcm_history2_16 = hist2; +} + +/* read from memory rather than a file */ +void decode_ngc_dsp_mem(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem) { + int i=first_sample; + int32_t sample_count; + + int framesin = first_sample/14; + + int8_t header = mem[framesin*8]; + int32_t scale = 1 << (header & 0xf); + int coef_index = (header >> 4) & 0xf; + int32_t hist1 = stream->adpcm_history1_16; + int32_t hist2 = stream->adpcm_history2_16; + int coef1 = stream->adpcm_coef[coef_index*2]; + int coef2 = stream->adpcm_coef[coef_index*2+1]; + + first_sample = first_sample%14; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int sample_byte = mem[framesin*8+1+i/2]; + +#ifdef DEBUG + if (hist1==stream->loop_history1 && hist2==stream->loop_history2) fprintf(stderr,"yo! %#x (start %#x) %d\n",stream->offset+framesin*8+i/2,stream->channel_start_offset,stream->samples_done); + stream->samples_done++; +#endif + + outbuf[sample_count] = clamp16(( + (((i&1? + get_low_nibble_signed(sample_byte): + get_high_nibble_signed(sample_byte) + ) * scale)<<11) + 1024 + + (coef1 * hist1 + coef2 * hist2))>>11 + ); + + hist2 = hist1; + hist1 = outbuf[sample_count]; + } + + stream->adpcm_history1_16 = hist1; + stream->adpcm_history2_16 = hist2; +} + +/* + * The original DSP spec uses nibble counts for loop points, and some + * variants don't have a proper sample count, so we (who are interested + * in sample counts) need to do this conversion occasionally. + */ +int32_t dsp_nibbles_to_samples(int32_t nibbles) { + int32_t whole_frames = nibbles/16; + int32_t remainder = nibbles%16; + + /* + fprintf(stderr,"%d (%#x) nibbles => %x bytes and %d samples\n",nibbles,nibbles,whole_frames*8,remainder); + */ + +#if 0 + if (remainder > 0 && remainder < 14) + return whole_frames*14 + remainder; + else if (remainder >= 14) + fprintf(stderr,"***** last frame %d leftover nibbles makes no sense\n",remainder); +#endif + if (remainder>0) return whole_frames*14+remainder-2; + else return whole_frames*14; +} diff --git a/lib/vgmstream/src/coding/ngc_dtk_decoder.c b/lib/vgmstream/src/coding/ngc_dtk_decoder.c new file mode 100644 index 0000000000..21d1890217 --- /dev/null +++ b/lib/vgmstream/src/coding/ngc_dtk_decoder.c @@ -0,0 +1,53 @@ +#include "coding.h" +#include "../util.h" + +void decode_ngc_dtk(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { + int i=first_sample; + int32_t sample_count; + + int framesin = first_sample/28; + + uint8_t q = read_8bit(framesin*32+stream->offset+channel,stream->streamfile); + int32_t hist1 = stream->adpcm_history1_32; + int32_t hist2 = stream->adpcm_history2_32; + + first_sample = first_sample%28; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int sample_byte = read_8bit(framesin*32+stream->offset+4+i,stream->streamfile); + + int32_t hist=0; + + switch (q>>4) + { + case 0: + hist = 0; + break; + case 1: + hist = (hist1 * 0x3c); + break; + case 2: + hist = (hist1 * 0x73) - (hist2 * 0x34); + break; + case 3: + hist = (hist1 * 0x62) - (hist2 * 0x37); + break; + } + + hist = (hist+0x20)>>6; + if (hist > 0x1fffff) hist = 0x1fffff; + if (hist < -0x200000) hist = -0x200000; + + hist2 = hist1; + + hist1 = ((((channel==0? + get_low_nibble_signed(sample_byte): + get_high_nibble_signed(sample_byte) + ) << 12) >> (q & 0xf)) << 6) + hist; + + outbuf[sample_count] = clamp16(hist1 >> 6); + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_history2_32 = hist2; +} diff --git a/lib/vgmstream/src/coding/nwa_decoder.c b/lib/vgmstream/src/coding/nwa_decoder.c new file mode 100644 index 0000000000..a568007859 --- /dev/null +++ b/lib/vgmstream/src/coding/nwa_decoder.c @@ -0,0 +1,352 @@ +/* originally from nwatowav.cc 2007.7.28 version, which read: */ +/* + * Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp> + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * ¤³¤Î¥×¥í¥°¥é¥à¤Îºî¼Ô¤Ï jagarl ¤Ç¤¹¡£ + * + * ¤³¤Î¥×¥í¥°¥é¥à¡¢µÚ¤Ó¥³¥ó¥Ñ¥¤¥ë¤Ë¤è¤Ã¤ÆÀ¸À®¤·¤¿¥Ð¥¤¥Ê¥ê¤Ï + * ¥×¥í¥°¥é¥à¤òÊѹ¹¤¹¤ë¡¢¤·¤Ê¤¤¤Ë¤«¤«¤ï¤é¤ººÆÇÛÉÛ²Äǽ¤Ç¤¹¡£ + * ¤½¤ÎºÝ¡¢¾åµ Copyright ɽ¼¨¤òÊÝ»ý¤¹¤ë¤Ê¤É¤Î¾ò·ï¤Ï²Ý¤·¤Þ + * ¤»¤ó¡£Âбþ¤¬ÌÌÅݤʤΤǥХ°Êó¹ð¤ò½ü¤¡¢¥á¡¼¥ë¤ÇÏ¢Íí¤ò¤¹¤ë + * ¤Ê¤É¤ÎɬÍפ⤢¤ê¤Þ¤»¤ó¡£¥½¡¼¥¹¤Î°ìÉô¤òήÍѤ¹¤ë¤³¤È¤ò´Þ¤á¡¢ + * ¤´¼«Í³¤Ë¤ª»È¤¤¤¯¤À¤µ¤¤¡£ + * + * THIS SOFTWARE IS PROVIDED BY KAZUNORI 'jagarl' UENO ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KAZUNORI UENO BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include <stdlib.h> +#include "nwa_decoder.h" + +/* can serve up 8 bits at a time */ +static int +getbits (STREAMFILE *file, off_t *offset, int *shift, int bits) +{ + int ret; + if (*shift > 8) + { + ++*offset; + *shift -= 8; + } + ret = read_16bitLE(*offset,file) >> *shift; + *shift += bits; + return ret & ((1 << bits) - 1); /* mask */ +} + +NWAData * +open_nwa (STREAMFILE * streamFile, const char *filename) +{ + int i; + NWAData * const nwa = malloc(sizeof(NWAData)); + if (!nwa) goto fail; + + nwa->channels = read_16bitLE(0x00,streamFile); + nwa->bps = read_16bitLE(0x02,streamFile); + nwa->freq = read_32bitLE(0x04,streamFile); + nwa->complevel = read_32bitLE(0x08,streamFile); + nwa->blocks = read_32bitLE(0x10,streamFile); + nwa->datasize = read_32bitLE(0x14,streamFile); + nwa->compdatasize = read_32bitLE(0x18,streamFile); + nwa->samplecount = read_32bitLE(0x1c,streamFile); + nwa->blocksize = read_32bitLE(0x20,streamFile); + nwa->restsize = read_32bitLE(0x24,streamFile); + nwa->offsets = NULL; + nwa->buffer = NULL; + nwa->buffer_readpos = NULL; + nwa->file = NULL; + + /* PCM not handled here */ + if (nwa->complevel < 0 || nwa->complevel > 5) goto fail; + + if (nwa->channels != 1 && nwa->channels != 2) goto fail; + + if (nwa->bps != 8 && nwa->bps != 16) goto fail; + + if (nwa->blocks <= 0) goto fail; + + if (nwa->compdatasize == 0 + || get_streamfile_size(streamFile) != nwa->compdatasize) goto fail; + + if (nwa->datasize != nwa->samplecount * (nwa->bps/8)) goto fail; + + if (nwa->samplecount != + (nwa->blocks-1) * nwa->blocksize + nwa->restsize) goto fail; + + nwa->offsets = malloc(sizeof(off_t)*nwa->blocks); + if (!nwa->offsets) goto fail; + + for (i = 0; i < nwa->blocks; i++) + { + int32_t o = read_32bitLE(0x2c+i*4,streamFile); + if (o < 0) goto fail; + nwa->offsets[i] = o; + } + + if (nwa->offsets[nwa->blocks-1] >= nwa->compdatasize) goto fail; + + if (nwa->restsize > nwa->blocksize) nwa->buffer = + malloc(sizeof(sample)*nwa->restsize); + else nwa->buffer = + malloc(sizeof(sample)*nwa->blocksize); + if (nwa->buffer == NULL) goto fail; + + nwa->buffer_readpos = nwa->buffer; + + nwa->samples_in_buffer = 0; + + nwa->curblock = 0; + + /* if we got this far, it's probably safe */ + nwa->file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!nwa->file) goto fail; + + return nwa; +fail: + if (nwa) + { + close_nwa(nwa); + free(nwa); + } + + return NULL; +} + +void +close_nwa(NWAData * nwa) +{ + if (!nwa) return; + + if (nwa->offsets) + free (nwa->offsets); + nwa->offsets = NULL; + if (nwa->buffer) + free (nwa->buffer); + nwa->buffer = NULL; + if (nwa->file) + close_streamfile (nwa->file); + nwa->file = NULL; + free(nwa); +} + +void +reset_nwa(NWAData *nwa) +{ + nwa->curblock = 0; + nwa->buffer_readpos = nwa->buffer; + nwa->samples_in_buffer = 0; +} + +static int use_runlength(NWAData *nwa) +{ + if (nwa->channels == 2 && nwa->bps == 16 && nwa->complevel == 2) + { + /* sw2 */ + return 0; + } + if (nwa->complevel == 5) + { + if (nwa->channels == 2) return 0; /* BGM*.nwa in Little Busters! */ + return 1; /* Tomoyo After (.nwk koe file) */ + } + return 0; +} + +static void +nwa_decode_block(NWAData *nwa) +{ + /* º£²óÆɤ߹þ¤à¡¿¥Ç¥³¡¼¥É¤¹¤ë¥Ç¡¼¥¿¤ÎÂ礤µ¤òÆÀ¤ë */ + int curblocksize, curcompsize; + if (nwa->curblock != nwa->blocks - 1) + { + curblocksize = nwa->blocksize * (nwa->bps / 8); + curcompsize = nwa->offsets[nwa->curblock + 1] - nwa->offsets[nwa->curblock]; + } + else + { + curblocksize = nwa->restsize * (nwa->bps / 8); + curcompsize = nwa->blocksize * (nwa->bps / 8) * 2; + } + + nwa->samples_in_buffer = 0; + nwa->buffer_readpos = nwa->buffer; + + { + sample d[2]; + int i; + int shift = 0; + off_t offset = nwa->offsets[nwa->curblock]; + int dsize = curblocksize / (nwa->bps / 8); + int flip_flag = 0; /* stereo ÍÑ */ + int runlength = 0; + + /* read initial sample value */ + for (i=0;i<nwa->channels;i++) + { + if (nwa->bps == 8) { d[i] = read_8bit(offset,nwa->file); } + else /* bps == 16 */ + { + d[i] = read_16bitLE(offset,nwa->file); + offset += 2; + } + } + + for (i = 0; i < dsize; i++) + { + if (runlength == 0) + { /* ¥³¥Ô¡¼¥ë¡¼¥×Ãæ¤Ç¤Ê¤¤¤Ê¤é¥Ç¡¼¥¿Æɤ߹þ¤ß */ + int type = getbits(nwa->file, &offset, &shift, 3); + /* type ¤Ë¤è¤êʬ´ô¡§0, 1-6, 7 */ + if (type == 7) + { + /* 7 : Â礤ʺ¹Ê¬ */ + /* RunLength() ͸ú»þ¡ÊCompLevel==5, ²»À¼¥Õ¥¡¥¤¥ë) ¤Ç¤Ï̵¸ú */ + if (getbits(nwa->file, &offset, &shift, 1) == 1) + { + d[flip_flag] = 0; /* ̤»ÈÍÑ */ + } + else + { + int BITS, SHIFT; + if (nwa->complevel >= 3) + { + BITS = 8; + SHIFT = 9; + } + else + { + BITS = 8 - nwa->complevel; + SHIFT = 2 + 7 + nwa->complevel; + } + { + const int MASK1 = (1 << (BITS - 1)); + const int MASK2 = (1 << (BITS - 1)) - 1; + int b = getbits(nwa->file, &offset, &shift, BITS); + if (b & MASK1) + d[flip_flag] -= (b & MASK2) << SHIFT; + else + d[flip_flag] += (b & MASK2) << SHIFT; + } + } + } + else if (type != 0) + { + /* 1-6 : Ä̾ï¤Îº¹Ê¬ */ + int BITS, SHIFT; + if (nwa->complevel >= 3) + { + BITS = nwa->complevel + 3; + SHIFT = 1 + type; + } + else + { + BITS = 5 - nwa->complevel; + SHIFT = 2 + type + nwa->complevel; + } + { + const int MASK1 = (1 << (BITS - 1)); + const int MASK2 = (1 << (BITS - 1)) - 1; + int b = getbits(nwa->file, &offset, &shift, BITS); + if (b & MASK1) + d[flip_flag] -= (b & MASK2) << SHIFT; + else + d[flip_flag] += (b & MASK2) << SHIFT; + } + } + else + { /* type == 0 */ + /* ¥é¥ó¥ì¥ó¥°¥¹°µ½Ì¤Ê¤·¤Î¾ì¹ç¤Ï¤Ê¤Ë¤â¤·¤Ê¤¤ */ + if (use_runlength(nwa)) + { + /* ¥é¥ó¥ì¥ó¥°¥¹°µ½Ì¤¢¤ê¤Î¾ì¹ç */ + runlength = getbits(nwa->file, &offset, &shift, 1); + if (runlength == 1) + { + runlength = getbits(nwa->file, &offset, &shift, 2); + if (runlength == 3) + { + runlength = getbits(nwa->file, &offset, &shift, 8); + } + } + } + } + } + else + { + runlength--; + } + if (nwa->bps == 8) + { + nwa->buffer[i] = d[flip_flag]*0x100; + } + else + { + nwa->buffer[i] = d[flip_flag]; + } + nwa->samples_in_buffer++; + if (nwa->channels == 2) + flip_flag ^= 1; /* channel ÀÚ¤êÂؤ¨ */ + } + } + + nwa->curblock++; + return; +} + +void +seek_nwa(NWAData *nwa, int32_t seekpos) +{ + int dest_block = seekpos/(nwa->blocksize/nwa->channels); + int32_t remainder = seekpos%(nwa->blocksize/nwa->channels); + + nwa->curblock = dest_block; + + nwa_decode_block(nwa); + + nwa->buffer_readpos = nwa->buffer + remainder*nwa->channels; + nwa->samples_in_buffer -= remainder*nwa->channels; +} + +/* interface to vgmstream */ +void +decode_nwa(NWAData *nwa, sample *outbuf, + int32_t samples_to_do) +{ + while (samples_to_do > 0) + { + int32_t samples_to_read; + + if (nwa->samples_in_buffer > 0) + { + samples_to_read = nwa->samples_in_buffer/nwa->channels; + if (samples_to_read > samples_to_do) + samples_to_read = samples_to_do; + + memcpy(outbuf,nwa->buffer_readpos, + sizeof(sample)*samples_to_read*nwa->channels); + + nwa->buffer_readpos += samples_to_read*nwa->channels; + nwa->samples_in_buffer -= samples_to_read*nwa->channels; + outbuf += samples_to_read*nwa->channels; + samples_to_do -= samples_to_read; + } + else + { + nwa_decode_block(nwa); + } + } +} diff --git a/lib/vgmstream/src/coding/nwa_decoder.h b/lib/vgmstream/src/coding/nwa_decoder.h new file mode 100644 index 0000000000..80b45ba7c2 --- /dev/null +++ b/lib/vgmstream/src/coding/nwa_decoder.h @@ -0,0 +1,67 @@ +/* originally from nwatowav.cc 2007.7.28 version, which read: */ +/* + * Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp> + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * ¤³¤Î¥×¥í¥°¥é¥à¤Îºî¼Ô¤Ï jagarl ¤Ç¤¹¡£ + * + * ¤³¤Î¥×¥í¥°¥é¥à¡¢µÚ¤Ó¥³¥ó¥Ñ¥¤¥ë¤Ë¤è¤Ã¤ÆÀ¸À®¤·¤¿¥Ð¥¤¥Ê¥ê¤Ï + * ¥×¥í¥°¥é¥à¤òÊѹ¹¤¹¤ë¡¢¤·¤Ê¤¤¤Ë¤«¤«¤ï¤é¤ººÆÇÛÉÛ²Äǽ¤Ç¤¹¡£ + * ¤½¤ÎºÝ¡¢¾åµ Copyright ɽ¼¨¤òÊÝ»ý¤¹¤ë¤Ê¤É¤Î¾ò·ï¤Ï²Ý¤·¤Þ + * ¤»¤ó¡£Âбþ¤¬ÌÌÅݤʤΤǥХ°Êó¹ð¤ò½ü¤¡¢¥á¡¼¥ë¤ÇÏ¢Íí¤ò¤¹¤ë + * ¤Ê¤É¤ÎɬÍפ⤢¤ê¤Þ¤»¤ó¡£¥½¡¼¥¹¤Î°ìÉô¤òήÍѤ¹¤ë¤³¤È¤ò´Þ¤á¡¢ + * ¤´¼«Í³¤Ë¤ª»È¤¤¤¯¤À¤µ¤¤¡£ + * + * THIS SOFTWARE IS PROVIDED BY KAZUNORI 'jagarl' UENO ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KAZUNORI UENO BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef _NWA_DECODER_H +#define _NWA_DECODER_H + +#include "../streamfile.h" + +typedef struct NWAData_s +{ + int channels; + int bps; /* bits per sample */ + int freq; /* samples per second */ + int complevel; /* compression level */ + int blocks; /* block count */ + int datasize; /* all data size */ + int compdatasize; /* compressed data size */ + int samplecount; /* all samples */ + int blocksize; /* samples per block */ + int restsize; /* samples of the last block */ + + int curblock; + off_t *offsets; + + STREAMFILE *file; + + /* temporarily store samples */ + sample *buffer; + sample *buffer_readpos; + int samples_in_buffer; +} NWAData; + +NWAData *open_nwa(STREAMFILE *streamFile, const char *filename); +void close_nwa(NWAData *nwa); +void reset_nwa(NWAData *nwa); +void seek_nwa(NWAData *nwa, int32_t seekpos); + +#endif diff --git a/lib/vgmstream/src/coding/ogg_vorbis_decoder.c b/lib/vgmstream/src/coding/ogg_vorbis_decoder.c new file mode 100644 index 0000000000..5f571d1e7f --- /dev/null +++ b/lib/vgmstream/src/coding/ogg_vorbis_decoder.c @@ -0,0 +1,22 @@ +#include "../vgmstream.h" + +#ifdef VGM_USE_VORBIS +#include <vorbis/vorbisfile.h> +#include "coding.h" +#include "../util.h" + +void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) { + int samples_done = 0; + OggVorbis_File *ogg_vorbis_file = &data->ogg_vorbis_file; + + do { + long rc = ov_read(ogg_vorbis_file, (char *)(outbuf + samples_done*channels), + (samples_to_do - samples_done)*sizeof(sample)*channels, 0, + sizeof(sample), 1, &data->bitstream); + + if (rc > 0) samples_done += rc/sizeof(sample)/channels; + else return; + } while (samples_done < samples_to_do); +} + +#endif diff --git a/lib/vgmstream/src/coding/pcm_decoder.c b/lib/vgmstream/src/coding/pcm_decoder.c new file mode 100644 index 0000000000..c1e64ee81d --- /dev/null +++ b/lib/vgmstream/src/coding/pcm_decoder.c @@ -0,0 +1,68 @@ +#include "coding.h" +#include "../util.h" + +void decode_pcm16LE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + outbuf[sample_count]=read_16bitLE(stream->offset+i*2,stream->streamfile); + } +} + +void decode_pcm16BE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + outbuf[sample_count]=read_16bitBE(stream->offset+i*2,stream->streamfile); + } +} + +void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + outbuf[sample_count]=read_8bit(stream->offset+i,stream->streamfile)*0x100; + } +} + +void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + outbuf[sample_count]=read_8bit(stream->offset+i*channelspacing,stream->streamfile)*0x100; + } +} + +void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int16_t v = (uint8_t)read_8bit(stream->offset+i*channelspacing,stream->streamfile); + if (v&0x80) v = 0-(v&0x7f); + outbuf[sample_count] = v*0x100; + } +} + +void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int16_t v = (uint8_t)read_8bit(stream->offset+i*channelspacing,stream->streamfile); + outbuf[sample_count] = v*0x100 - 0x8000; + } +} + +void decode_pcm16LE_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + outbuf[sample_count]=read_16bitLE(stream->offset+i*2*channelspacing,stream->streamfile); + } +} diff --git a/lib/vgmstream/src/coding/psx_decoder.c b/lib/vgmstream/src/coding/psx_decoder.c new file mode 100644 index 0000000000..775fdd643a --- /dev/null +++ b/lib/vgmstream/src/coding/psx_decoder.c @@ -0,0 +1,181 @@ +#include <math.h> +#include "coding.h" +#include "../util.h" + +double VAG_f[5][2] = { { 0.0 , 0.0 }, + { 60.0 / 64.0 , 0.0 }, + { 115.0 / 64.0 , -52.0 / 64.0 }, + { 98.0 / 64.0 , -55.0 / 64.0 } , + { 122.0 / 64.0 , -60.0 / 64.0 } } ; +long VAG_coefs[5][2] = { { 0 , 0 }, + { 60 , 0 }, + { 115 , -52 }, + { 98 , -55 } , + { 122 , -60 } } ; + +void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + + int predict_nr, shift_factor, sample; + int32_t hist1=stream->adpcm_history1_32; + int32_t hist2=stream->adpcm_history2_32; + + short scale; + int i; + int32_t sample_count; + uint8_t flag; + + int framesin = first_sample/28; + + predict_nr = read_8bit(stream->offset+framesin*16,stream->streamfile) >> 4; + shift_factor = read_8bit(stream->offset+framesin*16,stream->streamfile) & 0xf; + flag = read_8bit(stream->offset+framesin*16+1,stream->streamfile); + + first_sample = first_sample % 28; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + + sample=0; + + if(flag<0x07) { + + short sample_byte = (short)read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile); + + scale = ((i&1 ? + sample_byte >> 4 : + sample_byte & 0x0f)<<12); + + sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]); + } + + outbuf[sample_count] = clamp16(sample); + hist2=hist1; + hist1=sample; + } + stream->adpcm_history1_32=hist1; + stream->adpcm_history2_32=hist2; +} + +void decode_invert_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + + int predict_nr, shift_factor, sample; + int32_t hist1=stream->adpcm_history1_32; + int32_t hist2=stream->adpcm_history2_32; + + short scale; + int i; + int32_t sample_count; + uint8_t flag; + + int framesin = first_sample/28; + int head = read_8bit(stream->offset+framesin*16,stream->streamfile) ^ stream->bmdx_xor; + + predict_nr = ((head >> 4) & 0xf); + shift_factor = (head & 0xf); + flag = read_8bit(stream->offset+framesin*16+1,stream->streamfile); + + first_sample = first_sample % 28; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + + sample=0; + + if(flag<0x07) { + + short sample_byte = (short)read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile); + if (i/2 == 0) + sample_byte = (short)(int8_t)(sample_byte+stream->bmdx_add); + + scale = ((i&1 ? + sample_byte >> 4 : + sample_byte & 0x0f)<<12); + + sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]); + } + + outbuf[sample_count] = clamp16(sample); + hist2=hist1; + hist1=sample; + } + stream->adpcm_history1_32=hist1; + stream->adpcm_history2_32=hist2; +} + +/* some TAITO games have garbage (?) in their flags, this decoder + * just ignores that byte */ +void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + + int predict_nr, shift_factor, sample; + int32_t hist1=stream->adpcm_history1_32; + int32_t hist2=stream->adpcm_history2_32; + + short scale; + int i; + int32_t sample_count; + + int framesin = first_sample/28; + + predict_nr = read_8bit(stream->offset+framesin*16,stream->streamfile) >> 4; + shift_factor = read_8bit(stream->offset+framesin*16,stream->streamfile) & 0xf; + first_sample = first_sample % 28; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + short sample_byte = (short)read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile); + + scale = ((i&1 ? + sample_byte >> 4 : + sample_byte & 0x0f)<<12); + + sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]); + + outbuf[sample_count] = clamp16(sample); + hist2=hist1; + hist1=sample; + } + stream->adpcm_history1_32=hist1; + stream->adpcm_history2_32=hist2; +} + +/* FF XI's Vag-ish format */ +void decode_ffxi_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + + int predict_nr, shift_factor, sample; + int32_t hist1=stream->adpcm_history1_32; + int32_t hist2=stream->adpcm_history2_32; + + short scale; + int i; + int32_t sample_count; + long predictor; + + int framesin = first_sample/16; + + predict_nr = read_8bit(stream->offset+framesin*9,stream->streamfile) >> 4; + shift_factor = read_8bit(stream->offset+framesin*9,stream->streamfile) & 0xf; + first_sample = first_sample % 16; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + short sample_byte = (short)read_8bit(stream->offset+(framesin*9)+1+i/2,stream->streamfile); + + sample=0; + + scale = ((i&1 ? + sample_byte >> 4 : + sample_byte & 0x0f)<<12); + +#if 1 + predictor = + (int)((hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1])); +#else + predictor = + (hist1*VAG_coefs[predict_nr][0]+hist2*VAG_coefs[predict_nr][1])/64; +#endif + sample=(scale >> shift_factor) + predictor; + + outbuf[sample_count] = clamp16(sample); + hist2=hist1; + hist1=sample; + } + stream->adpcm_history1_32=hist1; + stream->adpcm_history2_32=hist2; +} + diff --git a/lib/vgmstream/src/coding/sdx2_decoder.c b/lib/vgmstream/src/coding/sdx2_decoder.c new file mode 100644 index 0000000000..958590eb87 --- /dev/null +++ b/lib/vgmstream/src/coding/sdx2_decoder.c @@ -0,0 +1,71 @@ +#include <math.h> +#include "coding.h" +#include "../util.h" + +/* SDX2 - 2:1 Squareroot-delta-exact compression */ + +/* for (i=-128;i<128;i++) squares[i+128]=i<0?(-i*i)*2:(i*i)*2); */ +static int16_t squares[256] = { +-32768,-32258,-31752,-31250,-30752,-30258,-29768,-29282,-28800,-28322,-27848, +-27378,-26912,-26450,-25992,-25538,-25088,-24642,-24200,-23762,-23328,-22898, +-22472,-22050,-21632,-21218,-20808,-20402,-20000,-19602,-19208,-18818,-18432, +-18050,-17672,-17298,-16928,-16562,-16200,-15842,-15488,-15138,-14792,-14450, +-14112,-13778,-13448,-13122,-12800,-12482,-12168,-11858,-11552,-11250,-10952, +-10658,-10368,-10082, -9800, -9522, -9248, -8978, -8712, -8450, -8192, -7938, + -7688, -7442, -7200, -6962, -6728, -6498, -6272, -6050, -5832, -5618, -5408, + -5202, -5000, -4802, -4608, -4418, -4232, -4050, -3872, -3698, -3528, -3362, + -3200, -3042, -2888, -2738, -2592, -2450, -2312, -2178, -2048, -1922, -1800, + -1682, -1568, -1458, -1352, -1250, -1152, -1058, -968, -882, -800, -722, + -648, -578, -512, -450, -392, -338, -288, -242, -200, -162, -128, + -98, -72, -50, -32, -18, -8, -2, 0, 2, 8, 18, + 32, 50, 72, 98, 128, 162, 200, 242, 288, 338, 392, + 450, 512, 578, 648, 722, 800, 882, 968, 1058, 1152, 1250, + 1352, 1458, 1568, 1682, 1800, 1922, 2048, 2178, 2312, 2450, 2592, + 2738, 2888, 3042, 3200, 3362, 3528, 3698, 3872, 4050, 4232, 4418, + 4608, 4802, 5000, 5202, 5408, 5618, 5832, 6050, 6272, 6498, 6728, + 6962, 7200, 7442, 7688, 7938, 8192, 8450, 8712, 8978, 9248, 9522, + 9800, 10082, 10368, 10658, 10952, 11250, 11552, 11858, 12168, 12482, 12800, + 13122, 13448, 13778, 14112, 14450, 14792, 15138, 15488, 15842, 16200, 16562, + 16928, 17298, 17672, 18050, 18432, 18818, 19208, 19602, 20000, 20402, 20808, + 21218, 21632, 22050, 22472, 22898, 23328, 23762, 24200, 24642, 25088, 25538, + 25992, 26450, 26912, 27378, 27848, 28322, 28800, 29282, 29768, 30258, 30752, + 31250, 31752, 32258 +}; + +void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + + int32_t hist = stream->adpcm_history1_32; + + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int8_t sample_byte = read_8bit(stream->offset+i,stream->streamfile); + int16_t sample; + + if (!(sample_byte & 1)) hist = 0; + sample = hist + squares[sample_byte+128]; + + hist = outbuf[sample_count] = clamp16(sample); + } + stream->adpcm_history1_32=hist; +} + +void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + + int32_t hist = stream->adpcm_history1_32; + + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + int8_t sample_byte = read_8bit(stream->offset+i*channelspacing,stream->streamfile); + int16_t sample; + + if (!(sample_byte & 1)) hist = 0; + sample = hist + squares[sample_byte+128]; + + hist = outbuf[sample_count] = clamp16(sample); + } + stream->adpcm_history1_32=hist; +} diff --git a/lib/vgmstream/src/coding/ws_decoder.c b/lib/vgmstream/src/coding/ws_decoder.c new file mode 100644 index 0000000000..b72193dc7c --- /dev/null +++ b/lib/vgmstream/src/coding/ws_decoder.c @@ -0,0 +1,146 @@ +#include <math.h> +#include "coding.h" +#include "../util.h" + +/* Westwood Studios ADPCM */ + +/* Based on Valery V. Anisimovsky's WS-AUD.txt */ + +static char WSTable2bit[4]={-2,-1,0,1}; +static char WSTable4bit[16]={-9,-8,-6,-5,-4,-3,-2,-1, + 0, 1, 2, 3, 4, 5 ,6, 8}; + +/* We pass in the VGMSTREAM here, unlike in other codings, because + the decoder has to know about the block structure. */ +void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample, + int32_t samples_to_do) { + + VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]); + int16_t hist = stream->adpcm_history1_16; + off_t offset = stream->offset; + int samples_left_in_frame = stream->samples_left_in_frame; + off_t header_off = stream->frame_header_offset; + + int i; + int32_t sample_count; + + if (vgmstream->ws_output_size == vgmstream->current_block_size) { + /* uncompressed, we just need to convert to 16-bit */ + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing,offset++) { + outbuf[sample_count]=((uint8_t)read_8bit(offset,stream->streamfile)-0x80)*0x100; + } + } else { + if (first_sample == 0) { + hist = 0x80; + samples_left_in_frame = 0; + } + /* actually decompress */ + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; ) { + uint8_t header; + uint8_t count; + + if (samples_left_in_frame == 0) { + header_off = offset; + offset++; + } + + header = read_8bit(header_off,stream->streamfile); + count = header & 0x3f; + switch (header>>6) { /* code */ + case 0: /* 2-bit ADPCM */ + if (samples_left_in_frame == 0) { + samples_left_in_frame = (count + 1)*4; + } + for (;samples_left_in_frame>0 && /* read this frame */ + i<first_sample+samples_to_do; /* up to samples_to_do */ + i++,sample_count+=channelspacing, /* done with writing a sample */ + samples_left_in_frame--) { /* done with reading a sample */ + int twobit = ((count + 1)*4-samples_left_in_frame)%4; + uint8_t sample; + sample = read_8bit(offset,stream->streamfile); + sample = (sample >> (twobit*2)) & 0x3; + hist += WSTable2bit[sample]; + if (hist < 0) hist = 0; + if (hist > 0xff) hist = 0xff; + outbuf[sample_count]=(hist-0x80)*0x100; + + if (twobit == 3) + offset++; /* done with that byte */ + } + break; + case 1: /* 4-bit ADPCM */ + if (samples_left_in_frame == 0) { + samples_left_in_frame = (count + 1)*2; + } + for (;samples_left_in_frame>0 && /* read this frame */ + i<first_sample+samples_to_do; /* up to samples_to_do */ + i++,sample_count+=channelspacing, /* done with writing a sample */ + samples_left_in_frame--) { /* done with reading a sample */ + int nibble = ((count + 1)*4-samples_left_in_frame)%2; + uint8_t sample; + sample = read_8bit(offset,stream->streamfile); + if (nibble == 0) + sample &= 0xf; + else + sample >>= 4; + hist += WSTable4bit[sample]; + if (hist < 0) hist = 0; + if (hist > 0xff) hist = 0xff; + outbuf[sample_count]=(hist-0x80)*0x100; + + if (nibble == 1) + offset++; /* done with that byte */ + } + break; + case 2: /* no compression */ + if (count & 0x20) { /* delta */ + /* Note no checks against samples_to_do here, + at the top of the for loop we can always do at + least one sample */ + /* low 5 bits are a signed delta */ + if (count & 0x10) { + hist -= ((count & 0xf)^0xf) + 1; + } else { + hist += count & 0xf; + } + + /* Valery doesn't specify this, but I will assume */ + if (hist < 0) hist = 0; + if (hist > 0xff) hist = 0xff; + + outbuf[sample_count]=(hist-0x80)*0x100; + sample_count+=channelspacing; + i++; + + /* just one, and we got it */ + samples_left_in_frame = 0; + } else { /* copy bytes verbatim */ + if (samples_left_in_frame == 0) + samples_left_in_frame=count+1; + for (;samples_left_in_frame>0 && /* read this frame */ + i<first_sample+samples_to_do; /* up to samples_to_do */ + offset++, /* done with a byte */ + i++,sample_count+=channelspacing, /* done with writing a sample */ + samples_left_in_frame--) { /* done with reading a sample */ + outbuf[sample_count]=((hist=(uint8_t)read_8bit(offset,stream->streamfile))-0x80)*0x100; + } + } + break; + case 3: /* RLE */ + if (samples_left_in_frame == 0) + samples_left_in_frame=count+1; + for (;samples_left_in_frame>0 && /* read this frame */ + i<first_sample+samples_to_do; /* up to samples_to_do */ + i++,sample_count+=channelspacing, /* done with writing a sample */ + samples_left_in_frame--) { /* done with reading a sample */ + outbuf[sample_count]=(hist-0x80)*0x100; + } + } + } + } + + stream->offset = offset; + stream->adpcm_history1_16 = hist; + stream->samples_left_in_frame = samples_left_in_frame; + stream->frame_header_offset = header_off; +} diff --git a/lib/vgmstream/src/coding/xa_decoder.c b/lib/vgmstream/src/coding/xa_decoder.c new file mode 100644 index 0000000000..c974cea6c5 --- /dev/null +++ b/lib/vgmstream/src/coding/xa_decoder.c @@ -0,0 +1,72 @@ +#include "coding.h" +#include "../util.h" + +const int SH = 4; +const int SHC = 10; + +double K0[4] = { 0.0, 0.9375, 1.796875, 1.53125}; +double K1[4] = { 0.0, 0.0, -0.8125,-0.859375}; + +int IK0(int fid) +{ return ((int)((-K0[fid]) * (1 << SHC))); } + +int IK1(int fid) +{ return ((int)((-K1[fid]) * (1 << SHC))); } + +int CLAMP(int value, int Minim, int Maxim) +{ + if (value < Minim) value = Minim; + if (value > Maxim) value = Maxim; + return value; +} + +void init_get_high_nibble(VGMSTREAM *vgmstream) { + vgmstream->get_high_nibble=1; +} + +void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { + + VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]); + int predict_nr, shift_factor, sample; + int32_t hist1=stream->adpcm_history1_32; + int32_t hist2=stream->adpcm_history2_32; + int HeadTable[8]={0,2,8,10}; + + short scale; + int i; + int32_t sample_count; + + int framesin = first_sample / (56 / channelspacing); + + + first_sample = first_sample % 28; + + vgmstream->get_high_nibble=!vgmstream->get_high_nibble; + + if((first_sample) && (channelspacing==1)) + vgmstream->get_high_nibble=!vgmstream->get_high_nibble; + + predict_nr = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->get_high_nibble,stream->streamfile) >> 4; + shift_factor = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->get_high_nibble,stream->streamfile) & 0xf; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + short sample_byte = (short)read_8bit(stream->offset+16+framesin+(i*4),stream->streamfile); + + scale = ((vgmstream->get_high_nibble ? + sample_byte >> 4 : + sample_byte & 0x0f)<<12); + + sample = (short)(scale & 0xf000) >> shift_factor; + sample <<= SH; + sample -= (IK0(predict_nr) * hist1 + (IK1(predict_nr) * hist2)) >> SHC; + + hist2=hist1; + hist1=sample; + + sample = CLAMP(sample, -32768 << SH, 32767 << SH); + outbuf[sample_count] = (short)(sample >> SH); + } + + stream->adpcm_history1_32=hist1; + stream->adpcm_history2_32=hist2; +} diff --git a/lib/vgmstream/src/layout/aax_layout.c b/lib/vgmstream/src/layout/aax_layout.c new file mode 100644 index 0000000000..2e0834ae99 --- /dev/null +++ b/lib/vgmstream/src/layout/aax_layout.c @@ -0,0 +1,67 @@ +#include "layout.h" +#include "../vgmstream.h" +#include "../coding/coding.h" + +void render_vgmstream_aax(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { + int samples_written=0; + aax_codec_data *data = vgmstream->codec_data; + + while (samples_written<sample_count) { + int samples_to_do; + int samples_this_block = data->sample_counts[data->current_segment]; + + if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { + int i; + data->current_segment = data->loop_segment; + + reset_vgmstream(data->adxs[data->current_segment]); + + /* carry over the history from the loop point */ + if (data->loop_segment > 0) + { + for (i=0;i<data->adxs[0]->channels;i++) + { + data->adxs[data->loop_segment]->ch[i].adpcm_history1_32 = + data->adxs[data->loop_segment-1]->ch[i].adpcm_history1_32; + data->adxs[data->loop_segment]->ch[i].adpcm_history2_32 = + data->adxs[data->loop_segment-1]->ch[i].adpcm_history2_32; + } + } + vgmstream->samples_into_block = 0; + continue; + } + + samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream); + + /*printf("samples_to_do=%d,samples_this_block=%d,samples_written=%d,sample_count=%d\n",samples_to_do,samples_this_block,samples_written,sample_count);*/ + + if (samples_written+samples_to_do > sample_count) + samples_to_do=sample_count-samples_written; + + if (samples_to_do == 0) + { + int i; + data->current_segment++; + /*printf("advance to %d at %d samples\n",data->current_segment,vgmstream->current_sample);*/ + reset_vgmstream(data->adxs[data->current_segment]); + + /* carry over the history from the previous segment */ + for (i=0;i<data->adxs[0]->channels;i++) + { + data->adxs[data->current_segment]->ch[i].adpcm_history1_32 = + data->adxs[data->current_segment-1]->ch[i].adpcm_history1_32; + data->adxs[data->current_segment]->ch[i].adpcm_history2_32 = + data->adxs[data->current_segment-1]->ch[i].adpcm_history2_32; + } + vgmstream->samples_into_block = 0; + continue; + } + + render_vgmstream(&buffer[samples_written*data->adxs[data->current_segment]->channels], + samples_to_do,data->adxs[data->current_segment]); + + samples_written += samples_to_do; + vgmstream->current_sample += samples_to_do; + vgmstream->samples_into_block+=samples_to_do; + } +} diff --git a/lib/vgmstream/src/layout/aix_layout.c b/lib/vgmstream/src/layout/aix_layout.c new file mode 100644 index 0000000000..2e8a7b8319 --- /dev/null +++ b/lib/vgmstream/src/layout/aix_layout.c @@ -0,0 +1,92 @@ +#include "layout.h" +#include "../vgmstream.h" +#include "../coding/coding.h" + +void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { + int samples_written=0; + aix_codec_data *data = vgmstream->codec_data; + + while (samples_written<sample_count) { + int samples_to_do; + int samples_this_block = data->sample_counts[data->current_segment]; + int current_stream; + int channels_sofar = 0; + + if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { + data->current_segment = 1; + for (current_stream = 0; current_stream < data->stream_count; current_stream++) + { + int i; + reset_vgmstream(data->adxs[data->current_segment*data->stream_count+current_stream]); + + /* carry over the history from the loop point */ + for (i=0;i<data->adxs[data->stream_count+current_stream]->channels;i++) + { + data->adxs[1*data->stream_count+current_stream]->ch[i].adpcm_history1_32 = + data->adxs[0+current_stream]->ch[i].adpcm_history1_32; + data->adxs[1*data->stream_count+current_stream]->ch[i].adpcm_history2_32 = + data->adxs[0+current_stream]->ch[i].adpcm_history2_32; + } + } + vgmstream->samples_into_block = 0; + continue; + } + + samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream); + + /*printf("samples_to_do=%d,samples_this_block=%d,samples_written=%d,sample_count=%d\n",samples_to_do,samples_this_block,samples_written,sample_count);*/ + + if (samples_written+samples_to_do > sample_count) + samples_to_do=sample_count-samples_written; + + if (samples_to_do == 0) + { + int i; + data->current_segment++; + /*printf("next %d, %d samples\n",data->current_file,data->files[data->current_file]->total_values/data->files[data->current_file]->info.channels);*/ + for (current_stream = 0; current_stream < data->stream_count; current_stream++) + { + reset_vgmstream(data->adxs[data->current_segment*data->stream_count+current_stream]); + + /* carry over the history from the previous segment */ + for (i=0;i<data->adxs[data->current_segment*data->stream_count+current_stream]->channels;i++) + { + data->adxs[data->current_segment*data->stream_count+current_stream]->ch[i].adpcm_history1_32 = + data->adxs[(data->current_segment-1)*data->stream_count+current_stream]->ch[i].adpcm_history1_32; + data->adxs[data->current_segment*data->stream_count+current_stream]->ch[i].adpcm_history2_32 = + data->adxs[(data->current_segment-1)*data->stream_count+current_stream]->ch[i].adpcm_history2_32; + } + } + vgmstream->samples_into_block = 0; + continue; + } + + /*printf("decode %d samples file %d\n",samples_to_do,data->current_file);*/ + if (samples_to_do > AIX_BUFFER_SIZE/2) + { + samples_to_do = AIX_BUFFER_SIZE/2; + } + + for (current_stream = 0; current_stream < data->stream_count; current_stream++) + { + int i,j; + VGMSTREAM *adx = data->adxs[data->current_segment*data->stream_count+current_stream]; + + render_vgmstream(data->buffer,samples_to_do,adx); + + for (i = 0; i < samples_to_do; i++) + { + for (j = 0; j < adx->channels; j++) + { + buffer[(i+samples_written)*vgmstream->channels+channels_sofar+j] = data->buffer[i*adx->channels+j]; + } + } + + channels_sofar += adx->channels; + } + + samples_written += samples_to_do; + vgmstream->current_sample += samples_to_do; + vgmstream->samples_into_block+=samples_to_do; + } +} diff --git a/lib/vgmstream/src/layout/ast_blocked.c b/lib/vgmstream/src/layout/ast_blocked.c new file mode 100644 index 0000000000..d882a0de1c --- /dev/null +++ b/lib/vgmstream/src/layout/ast_blocked.c @@ -0,0 +1,18 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void ast_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = read_32bitBE( + vgmstream->current_block_offset+4, + vgmstream->ch[0].streamfile); + vgmstream->next_block_offset = vgmstream->current_block_offset + + vgmstream->current_block_size*vgmstream->channels + 0x20; + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + + 0x20 + vgmstream->current_block_size*i; + } +} diff --git a/lib/vgmstream/src/layout/blocked.c b/lib/vgmstream/src/layout/blocked.c new file mode 100644 index 0000000000..036e69a36f --- /dev/null +++ b/lib/vgmstream/src/layout/blocked.c @@ -0,0 +1,126 @@ +#include "layout.h" +#include "../vgmstream.h" + +void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { + int samples_written=0; + + int frame_size = get_vgmstream_frame_size(vgmstream); + int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); + int samples_this_block; + + if (frame_size == 0) { + /* assume 4 bit */ + /* TODO: get_vgmstream_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; + } + + while (samples_written<sample_count) { + int samples_to_do; + + if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { + if (frame_size == 0) { + samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame; + } else { + samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame; + } + continue; + } + + samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); + + if (samples_written+samples_to_do > sample_count) + samples_to_do=sample_count-samples_written; + + if (vgmstream->current_block_offset>=0) + decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer); + else { + int i; + /* we've run off the end! */ + for (i=samples_written*vgmstream->channels; + i<(samples_written+samples_to_do)*vgmstream->channels;i++) + buffer[i]=0; + } + + samples_written += samples_to_do; + vgmstream->current_sample += samples_to_do; + vgmstream->samples_into_block+=samples_to_do; + + if (vgmstream->samples_into_block==samples_this_block) { + switch (vgmstream->layout_type) { + case layout_ast_blocked: + ast_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_halpst_blocked: + if (vgmstream->next_block_offset>=0) + halpst_block_update(vgmstream->next_block_offset,vgmstream); + else + vgmstream->current_block_offset=-1; + break; + case layout_xa_blocked: + xa_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_ea_blocked: + ea_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_eacs_blocked: + eacs_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_caf_blocked: + caf_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_wsi_blocked: + wsi_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_str_snds_blocked: + str_snds_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_ws_aud_blocked: + ws_aud_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_matx_blocked: + matx_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_de2_blocked: + de2_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_emff_ps2_blocked: + emff_ps2_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_emff_ngc_blocked: + emff_ngc_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_gsb_blocked: + gsb_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_vs_blocked: + vs_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_xvas_blocked: + xvas_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_thp_blocked: + thp_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_filp_blocked: + filp_block_update(vgmstream->next_block_offset,vgmstream); + break; + default: + break; + } + + /* for VBR these may change */ + frame_size = get_vgmstream_frame_size(vgmstream); + samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); + + if (frame_size == 0) { + samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame; + } else { + samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame; + } + vgmstream->samples_into_block=0; + } + + } +} diff --git a/lib/vgmstream/src/layout/caf_blocked.c b/lib/vgmstream/src/layout/caf_blocked.c new file mode 100644 index 0000000000..d944baa01c --- /dev/null +++ b/lib/vgmstream/src/layout/caf_blocked.c @@ -0,0 +1,26 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void caf_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = read_32bitBE( + vgmstream->current_block_offset+0x14, + vgmstream->ch[0].streamfile); + vgmstream->next_block_offset = vgmstream->current_block_offset + + (off_t)read_32bitBE(vgmstream->current_block_offset+0x04, + vgmstream->ch[0].streamfile); + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + + read_32bitBE(block_offset+0x10+(8*i),vgmstream->ch[0].streamfile); + } + + /* coeffs */ + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(block_offset+0x34+(2*i),vgmstream->ch[0].streamfile); + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(block_offset+0x60+(2*i),vgmstream->ch[0].streamfile); + } +} diff --git a/lib/vgmstream/src/layout/de2_blocked.c b/lib/vgmstream/src/layout/de2_blocked.c new file mode 100644 index 0000000000..a89ddbafac --- /dev/null +++ b/lib/vgmstream/src/layout/de2_blocked.c @@ -0,0 +1,18 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void de2_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = read_32bitLE( + vgmstream->current_block_offset, + vgmstream->ch[0].streamfile); + vgmstream->next_block_offset = block_offset+8+read_32bitLE( + vgmstream->current_block_offset, + vgmstream->ch[0].streamfile); + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + 8; + } +} diff --git a/lib/vgmstream/src/layout/ea_block.c b/lib/vgmstream/src/layout/ea_block.c new file mode 100644 index 0000000000..a195e7bf73 --- /dev/null +++ b/lib/vgmstream/src/layout/ea_block.c @@ -0,0 +1,142 @@ +#include "layout.h" +#include "../coding/coding.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void ea_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + + init_get_high_nibble(vgmstream); + + // Search for next SCDL or SCEl block ... + do { + block_offset+=4; + if(block_offset>=(off_t)get_streamfile_size(vgmstream->ch[0].streamfile)) { + vgmstream->next_block_offset=block_offset; + return; + } + } while (read_32bitBE(block_offset,vgmstream->ch[0].streamfile)!=0x5343446C); + + // reset channel offset + for(i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].channel_start_offset=0; + } + + vgmstream->current_block_offset = block_offset; + vgmstream->next_block_offset = block_offset+read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile)-4; + + if(vgmstream->ea_big_endian) { + vgmstream->current_block_size = read_32bitBE(block_offset+8,vgmstream->ch[0].streamfile); + + for(i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset=read_32bitBE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels); + vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C; + } + vgmstream->current_block_size /= 28; + + } else { + switch(vgmstream->coding_type) { + case coding_PSX: + vgmstream->ch[0].offset=vgmstream->current_block_offset+0x10; + vgmstream->ch[1].offset=(read_32bitLE(block_offset+0x04,vgmstream->ch[0].streamfile)-0x10)/vgmstream->channels; + vgmstream->ch[1].offset+=vgmstream->ch[0].offset; + vgmstream->current_block_size=read_32bitLE(block_offset+0x04,vgmstream->ch[0].streamfile)-0x10; + vgmstream->current_block_size/=vgmstream->channels; + break; + case coding_EA_ADPCM: + vgmstream->current_block_size = read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile); + for(i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset=vgmstream->current_block_offset+0x0C+(4*vgmstream->channels); + vgmstream->ch[i].adpcm_history1_32=(uint32_t)read_16bitLE(vgmstream->current_block_offset+0x0c+(i*4),vgmstream->ch[0].streamfile); + vgmstream->ch[i].adpcm_history2_32=(uint32_t)read_16bitLE(vgmstream->current_block_offset+0x0e +(i*4),vgmstream->ch[0].streamfile); + } + break; + case coding_PCM16LE_int: + vgmstream->current_block_size = read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile)-0x0C; + for(i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset=block_offset+0x0C+(i*2); + } + vgmstream->current_block_size/=2; + vgmstream->current_block_size-=2; + break; + case coding_XBOX: + vgmstream->current_block_size = read_32bitLE(block_offset+0x10,vgmstream->ch[0].streamfile); + for(i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset=read_32bitLE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels); + vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C; + } + break; + default: + vgmstream->current_block_size = read_32bitLE(block_offset+8,vgmstream->ch[0].streamfile); + for(i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset=read_32bitLE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels); + vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C; + } + vgmstream->current_block_size /= 28; + } + } + + if((vgmstream->ea_compression_version<3) && (vgmstream->coding_type!=coding_PSX) && (vgmstream->coding_type!=coding_EA_ADPCM) && (vgmstream->coding_type!=coding_XBOX)) { + for(i=0;i<vgmstream->channels;i++) { + if(vgmstream->ea_big_endian) { + vgmstream->ch[i].adpcm_history1_32=read_16bitBE(vgmstream->ch[i].offset,vgmstream->ch[0].streamfile); + vgmstream->ch[i].adpcm_history2_32=read_16bitBE(vgmstream->ch[i].offset+2,vgmstream->ch[0].streamfile); + } else { + vgmstream->ch[i].adpcm_history1_32=read_16bitLE(vgmstream->ch[i].offset,vgmstream->ch[0].streamfile); + vgmstream->ch[i].adpcm_history2_32=read_16bitLE(vgmstream->ch[i].offset+2,vgmstream->ch[0].streamfile); + } + vgmstream->ch[i].offset+=4; + } + } +} + +void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + off_t block_size=vgmstream->current_block_size; + + if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) { + block_offset+=0x0C; + } + + vgmstream->current_block_offset = block_offset; + + if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */ + block_offset+=4; + if(vgmstream->ea_platform==0) + block_size=read_32bitLE(vgmstream->current_block_offset+0x04, + vgmstream->ch[0].streamfile); + else + block_size=read_32bitBE(vgmstream->current_block_offset+0x04, + vgmstream->ch[0].streamfile); + block_offset+=4; + } + + vgmstream->current_block_size=block_size-8; + + if(vgmstream->coding_type==coding_EACS_IMA) { + init_get_high_nibble(vgmstream); + vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile); + + for(i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile); + vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile); + vgmstream->ch[i].offset = block_offset+0x14; + } + } else { + if(vgmstream->coding_type==coding_PSX) { + for (i=0;i<vgmstream->channels;i++) + vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2)); + } else { + + for (i=0;i<vgmstream->channels;i++) { + if(vgmstream->coding_type==coding_PCM16LE_int) + vgmstream->ch[i].offset = block_offset+(i*2); + else + vgmstream->ch[i].offset = block_offset+i; + } + } + vgmstream->current_block_size/=vgmstream->channels; + } + vgmstream->next_block_offset = vgmstream->current_block_offset + + (off_t)block_size; +} diff --git a/lib/vgmstream/src/layout/emff_blocked.c b/lib/vgmstream/src/layout/emff_blocked.c new file mode 100644 index 0000000000..b3ed7f5f24 --- /dev/null +++ b/lib/vgmstream/src/layout/emff_blocked.c @@ -0,0 +1,34 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void emff_ps2_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = read_32bitLE( + vgmstream->current_block_offset+0x10, + vgmstream->ch[0].streamfile); + vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size+0x20; + vgmstream->current_block_size/=vgmstream->channels; + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset+0x20+(vgmstream->current_block_size*i); + } +} + +void emff_ngc_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = read_32bitBE( + vgmstream->current_block_offset+0x20, + vgmstream->ch[0].streamfile); + vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size+0x40; + vgmstream->current_block_size/=vgmstream->channels; + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset+0x40+(vgmstream->current_block_size*i); + } +} + diff --git a/lib/vgmstream/src/layout/filp_blocked.c b/lib/vgmstream/src/layout/filp_blocked.c new file mode 100644 index 0000000000..550c6e7381 --- /dev/null +++ b/lib/vgmstream/src/layout/filp_blocked.c @@ -0,0 +1,19 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = read_32bitLE( + vgmstream->current_block_offset+0x18, + vgmstream->ch[0].streamfile)-0x800; + vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+0x800; + vgmstream->current_block_size/=vgmstream->channels; + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset+0x800+(vgmstream->current_block_size*i); + + } +} diff --git a/lib/vgmstream/src/layout/gsb_blocked.c b/lib/vgmstream/src/layout/gsb_blocked.c new file mode 100644 index 0000000000..80ce3eef1d --- /dev/null +++ b/lib/vgmstream/src/layout/gsb_blocked.c @@ -0,0 +1,18 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void gsb_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = 0x10000; /*read_32bitLE( + vgmstream->current_block_offset+0x10, + vgmstream->ch[0].streamfile); */ + vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size+0x20; + vgmstream->current_block_size/=vgmstream->channels; + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset+0x20+(vgmstream->current_block_size*i); + } +} diff --git a/lib/vgmstream/src/layout/halpst_blocked.c b/lib/vgmstream/src/layout/halpst_blocked.c new file mode 100644 index 0000000000..affb135f77 --- /dev/null +++ b/lib/vgmstream/src/layout/halpst_blocked.c @@ -0,0 +1,19 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void halpst_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = read_32bitBE( + vgmstream->current_block_offset, + vgmstream->ch[0].streamfile)/vgmstream->channels; + vgmstream->next_block_offset = read_32bitBE( + vgmstream->current_block_offset+8, + vgmstream->ch[0].streamfile); + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + + 0x20 + vgmstream->current_block_size*i; + } +} diff --git a/lib/vgmstream/src/layout/ims_block.c b/lib/vgmstream/src/layout/ims_block.c new file mode 100644 index 0000000000..c5df59480c --- /dev/null +++ b/lib/vgmstream/src/layout/ims_block.c @@ -0,0 +1,18 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void matx_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = read_32bitLE( + vgmstream->current_block_offset, + vgmstream->ch[0].streamfile); + vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size + 8; + vgmstream->current_block_size/=vgmstream->channels; + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + 8; + } +} diff --git a/lib/vgmstream/src/layout/interleave.c b/lib/vgmstream/src/layout/interleave.c new file mode 100644 index 0000000000..f10ee574e7 --- /dev/null +++ b/lib/vgmstream/src/layout/interleave.c @@ -0,0 +1,65 @@ +#include "layout.h" +#include "../vgmstream.h" + +void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { + int samples_written=0; + + int frame_size = get_vgmstream_frame_size(vgmstream); + int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); + int samples_this_block; + + samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame; + + if (vgmstream->layout_type == layout_interleave_shortblock && + vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block> vgmstream->num_samples) { + frame_size = get_vgmstream_shortframe_size(vgmstream); + samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream); + + samples_this_block = vgmstream->interleave_smallblock_size / frame_size * samples_per_frame; + } + + while (samples_written<sample_count) { + int samples_to_do; + + if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { + /* we assume that the loop is not back into a short block */ + if (vgmstream->layout_type == layout_interleave_shortblock) { + frame_size = get_vgmstream_frame_size(vgmstream); + samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); + samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame; + } + continue; + } + + samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); + /*printf("vgmstream_samples_to_do(samples_this_block=%d,samples_per_frame=%d,vgmstream) returns %d\n",samples_this_block,samples_per_frame,samples_to_do);*/ + + if (samples_written+samples_to_do > sample_count) + samples_to_do=sample_count-samples_written; + + decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer); + + samples_written += samples_to_do; + vgmstream->current_sample += samples_to_do; + vgmstream->samples_into_block+=samples_to_do; + + if (vgmstream->samples_into_block==samples_this_block) { + int chan; + if (vgmstream->layout_type == layout_interleave_shortblock && + vgmstream->current_sample + samples_this_block > vgmstream->num_samples) { + frame_size = get_vgmstream_shortframe_size(vgmstream); + samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream); + + samples_this_block = vgmstream->interleave_smallblock_size / frame_size * samples_per_frame; + for (chan=0;chan<vgmstream->channels;chan++) + vgmstream->ch[chan].offset+=vgmstream->interleave_block_size*(vgmstream->channels-chan)+vgmstream->interleave_smallblock_size*chan; + } else { + + for (chan=0;chan<vgmstream->channels;chan++) + vgmstream->ch[chan].offset+=vgmstream->interleave_block_size*vgmstream->channels; + } + vgmstream->samples_into_block=0; + } + + } +} diff --git a/lib/vgmstream/src/layout/interleave_byte.c b/lib/vgmstream/src/layout/interleave_byte.c new file mode 100644 index 0000000000..c9f8eb0886 --- /dev/null +++ b/lib/vgmstream/src/layout/interleave_byte.c @@ -0,0 +1,62 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* for formats where the interleave is smaller than a frame, so we need to + * deinterleave in memory before passing it along to a specialized decoder which + * reads from memory + */ + +/* just do one frame at a time */ + +void render_vgmstream_interleave_byte(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { + /* frame sizes are much smaller than this */ + uint8_t sample_data[0x400]; + int samples_written=0; + + int frame_size = get_vgmstream_frame_size(vgmstream); + int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); + int samples_this_block; + + samples_this_block = samples_per_frame; + + while (samples_written<sample_count) { + int samples_to_do; + + if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { + continue; + } + + samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); + + if (samples_written+samples_to_do > sample_count) + samples_to_do=sample_count-samples_written; + + { + int i,j; + for (j=0;j<vgmstream->channels;j++) { + for (i=0;i<frame_size;i++) { + sample_data[i] = read_8bit(vgmstream->ch[j].offset+ + i/vgmstream->interleave_block_size* + vgmstream->interleave_block_size* + vgmstream->channels+ + i%vgmstream->interleave_block_size, + vgmstream->ch[j].streamfile); + } + decode_vgmstream_mem(vgmstream, samples_written, + samples_to_do, buffer, sample_data, j); + } + } + + samples_written += samples_to_do; + vgmstream->current_sample += samples_to_do; + vgmstream->samples_into_block+=samples_to_do; + + if (vgmstream->samples_into_block==samples_this_block) { + int chan; + for (chan=0;chan<vgmstream->channels;chan++) + vgmstream->ch[chan].offset+=frame_size*vgmstream->channels; + vgmstream->samples_into_block=0; + } + + } +} diff --git a/lib/vgmstream/src/layout/layout.h b/lib/vgmstream/src/layout/layout.h new file mode 100644 index 0000000000..3d7ab19f2d --- /dev/null +++ b/lib/vgmstream/src/layout/layout.h @@ -0,0 +1,57 @@ +#ifndef _LAYOUT_H +#define _LAYOUT_H + +#include "../streamtypes.h" +#include "../vgmstream.h" + +void ast_block_update(off_t block_ofset, VGMSTREAM * vgmstream); + +void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); + +void halpst_block_update(off_t block_ofset, VGMSTREAM * vgmstream); + +void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void ea_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void caf_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void wsi_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void str_snds_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void ws_aud_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void matx_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void de2_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void vs_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void emff_ps2_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void emff_ngc_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void gsb_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void xvas_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream); + +void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); + +void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); + +void render_vgmstream_interleave_byte(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); + +void render_vgmstream_mus_acm(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); + +void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); + +void render_vgmstream_aax(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); + +#endif diff --git a/lib/vgmstream/src/layout/mus_acm_layout.c b/lib/vgmstream/src/layout/mus_acm_layout.c new file mode 100644 index 0000000000..bda82b501c --- /dev/null +++ b/lib/vgmstream/src/layout/mus_acm_layout.c @@ -0,0 +1,50 @@ +#include "layout.h" +#include "../vgmstream.h" +#include "../coding/acm_decoder.h" +#include "../coding/coding.h" + +void render_vgmstream_mus_acm(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { + int samples_written=0; + mus_acm_codec_data *data = vgmstream->codec_data; + + while (samples_written<sample_count) { + ACMStream *acm = data->files[data->current_file]; + int samples_to_do; + int samples_this_block = acm->total_values / acm->info.channels; + + if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { + data->current_file = data->loop_start_file; + acm_reset(data->files[data->current_file]); + vgmstream->samples_into_block = 0; + continue; + } + + samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream); + + /*printf("samples_to_do=%d,samples_this_block=%d,samples_written=%d,sample_count=%d\n",samples_to_do,samples_this_block,samples_written,sample_count);*/ + + if (samples_written+samples_to_do > sample_count) + samples_to_do=sample_count-samples_written; + + if (samples_to_do == 0) + { + data->current_file++; + /*printf("next %d, %d samples\n",data->current_file,data->files[data->current_file]->total_values/data->files[data->current_file]->info.channels);*/ + /* force loop back to first file in case we're still playing for some + * reason, prevent out of bounds stuff */ + if (data->current_file >= data->file_count) data->current_file = 0; + acm_reset(data->files[data->current_file]); + vgmstream->samples_into_block = 0; + continue; + } + + /*printf("decode %d samples file %d\n",samples_to_do,data->current_file);*/ + decode_acm(acm, + buffer+samples_written*vgmstream->channels, + samples_to_do, vgmstream->channels); + + samples_written += samples_to_do; + vgmstream->current_sample += samples_to_do; + vgmstream->samples_into_block+=samples_to_do; + } +} diff --git a/lib/vgmstream/src/layout/nolayout.c b/lib/vgmstream/src/layout/nolayout.c new file mode 100644 index 0000000000..dd36976fbb --- /dev/null +++ b/lib/vgmstream/src/layout/nolayout.c @@ -0,0 +1,28 @@ +#include "layout.h" +#include "../vgmstream.h" + +void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { + int samples_written=0; + + const int samples_this_block = vgmstream->num_samples; + int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); + + while (samples_written<sample_count) { + int samples_to_do; + + if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { + continue; + } + + samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); + + if (samples_written+samples_to_do > sample_count) + samples_to_do=sample_count-samples_written; + + decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer); + + samples_written += samples_to_do; + vgmstream->current_sample += samples_to_do; + vgmstream->samples_into_block+=samples_to_do; + } +} diff --git a/lib/vgmstream/src/layout/str_snds_blocked.c b/lib/vgmstream/src/layout/str_snds_blocked.c new file mode 100644 index 0000000000..e18f1510ee --- /dev/null +++ b/lib/vgmstream/src/layout/str_snds_blocked.c @@ -0,0 +1,54 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void str_snds_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + off_t current_chunk; + size_t file_size; + int i; + STREAMFILE *streamfile; + int FoundSSMP = 0; + off_t SSMP_offset = -1; + + current_chunk = block_offset; + streamfile = vgmstream->ch[0].streamfile; + file_size = get_streamfile_size(streamfile); + + /* we may have to skip some chunks */ + while (!FoundSSMP && current_chunk < file_size) { + if (current_chunk+read_32bitBE(current_chunk+4,streamfile)>=file_size) + break; + switch (read_32bitBE(current_chunk,streamfile)) { + case 0x534e4453: /* SNDS */ + /* SSMP */ + if (read_32bitBE(current_chunk+0x10,streamfile)==0x53534d50) { + FoundSSMP = 1; + SSMP_offset = current_chunk; + } + break; + case 0x46494c4c: /* FILL, the main culprit */ + default: + break; + } + + current_chunk += read_32bitBE(current_chunk+4,streamfile); + } + + if (!FoundSSMP) { + /* if we couldn't find it all we can do is try playing the current + * block, which is going to suck */ + vgmstream->current_block_offset = block_offset; + } + + vgmstream->current_block_offset = SSMP_offset; + vgmstream->current_block_size = (read_32bitBE( + vgmstream->current_block_offset+4, + vgmstream->ch[0].streamfile) - 0x18) / vgmstream->channels; + vgmstream->next_block_offset = vgmstream->current_block_offset + + read_32bitBE(vgmstream->current_block_offset+4, + vgmstream->ch[0].streamfile); + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + 0x18; + } +} diff --git a/lib/vgmstream/src/layout/thp_blocked.c b/lib/vgmstream/src/layout/thp_blocked.c new file mode 100644 index 0000000000..f4ed39e876 --- /dev/null +++ b/lib/vgmstream/src/layout/thp_blocked.c @@ -0,0 +1,31 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i,j; + STREAMFILE *streamFile=vgmstream->ch[0].streamfile; + off_t start_offset; + int32_t nextFrameSize; + + vgmstream->current_block_offset = block_offset; + nextFrameSize=read_32bitBE(vgmstream->current_block_offset,streamFile); + + vgmstream->next_block_offset = vgmstream->current_block_offset + + vgmstream->thpNextFrameSize; + vgmstream->thpNextFrameSize=nextFrameSize; + + start_offset=vgmstream->current_block_offset + + read_32bitBE(vgmstream->current_block_offset+0x08,streamFile)+0x10; + vgmstream->current_block_size=read_32bitBE(start_offset,streamFile); + start_offset+=8; + + for(i=0;i<vgmstream->channels;i++) { + for(j=0;j<16;j++) { + vgmstream->ch[i].adpcm_coef[j]=read_16bitBE(start_offset+(i*0x20)+(j*2),streamFile); + } + vgmstream->ch[i].adpcm_history1_16=read_16bitBE(start_offset + (0x20*vgmstream->channels) + (i*4),streamFile); + vgmstream->ch[i].adpcm_history2_16=read_16bitBE(start_offset + (0x20*vgmstream->channels) + (i*4) + 2,streamFile); + vgmstream->ch[i].offset = start_offset + (0x24*vgmstream->channels)+(i*vgmstream->current_block_size); + } +} diff --git a/lib/vgmstream/src/layout/vs_blocked.c b/lib/vgmstream/src/layout/vs_blocked.c new file mode 100644 index 0000000000..76e4cb277d --- /dev/null +++ b/lib/vgmstream/src/layout/vs_blocked.c @@ -0,0 +1,17 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void vs_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = read_32bitLE( + vgmstream->current_block_offset, + vgmstream->ch[0].streamfile); + vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size + 0x4; + vgmstream->ch[i].offset = vgmstream->current_block_offset + 0x4; + if(i==0) block_offset=vgmstream->next_block_offset; + } +} diff --git a/lib/vgmstream/src/layout/ws_aud_blocked.c b/lib/vgmstream/src/layout/ws_aud_blocked.c new file mode 100644 index 0000000000..dfc824a575 --- /dev/null +++ b/lib/vgmstream/src/layout/ws_aud_blocked.c @@ -0,0 +1,24 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void ws_aud_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = read_16bitLE( + vgmstream->current_block_offset, + vgmstream->ch[0].streamfile); + vgmstream->next_block_offset = vgmstream->current_block_offset + + vgmstream->current_block_size + 8; + + if (vgmstream->coding_type == coding_WS) { + vgmstream->ws_output_size = read_16bitLE( + vgmstream->current_block_offset+2, + vgmstream->ch[0].streamfile); + } + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + + 8 + vgmstream->current_block_size*i; + } +} diff --git a/lib/vgmstream/src/layout/wsi_blocked.c b/lib/vgmstream/src/layout/wsi_blocked.c new file mode 100644 index 0000000000..6dcd79a52e --- /dev/null +++ b/lib/vgmstream/src/layout/wsi_blocked.c @@ -0,0 +1,23 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void wsi_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + + /* assume that all channels have the same size for this block */ + + vgmstream->current_block_offset = block_offset; + /* current_block_size is the data size in this block, so subtract header */ + vgmstream->current_block_size = read_32bitBE( + vgmstream->current_block_offset, + vgmstream->ch[0].streamfile) - 0x10; + vgmstream->next_block_offset = + vgmstream->current_block_offset + + (vgmstream->current_block_size + 0x10) * vgmstream->channels; + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + + 0x10 + (vgmstream->current_block_size+0x10)*i; + } +} diff --git a/lib/vgmstream/src/layout/xa_blocked.c b/lib/vgmstream/src/layout/xa_blocked.c new file mode 100644 index 0000000000..6de0623a7b --- /dev/null +++ b/lib/vgmstream/src/layout/xa_blocked.c @@ -0,0 +1,49 @@ +#include "layout.h" +#include "../coding/coding.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + + int i; + int8_t currentChannel=0; + int8_t subAudio=0; + + init_get_high_nibble(vgmstream); + + if(vgmstream->samples_into_block!=0) + // don't change this variable in the init process + vgmstream->xa_sector_length+=128; + + // We get to the end of a sector ? + if(vgmstream->xa_sector_length==(18*128)) { + vgmstream->xa_sector_length=0; + + // 0x30 of unused bytes/sector :( + block_offset+=0x30; +begin: + // Search for selected channel & valid audio + currentChannel=read_8bit(block_offset-7,vgmstream->ch[0].streamfile); + subAudio=read_8bit(block_offset-6,vgmstream->ch[0].streamfile); + + // audio is coded as 0x64 + if(!((subAudio==0x64) && (currentChannel==vgmstream->xa_channel))) { + // go to next sector + block_offset+=2352; + if(currentChannel!=-1) goto begin; + } + } + + vgmstream->current_block_offset = block_offset; + + // Quid : how to stop the current channel ??? + // i set up 0 to current_block_size to make vgmstream not playing bad samples + // another way to do it ??? + // (as the number of samples can be false in cd-xa due to multi-channels) + vgmstream->current_block_size = (currentChannel==-1?0:112); + + vgmstream->next_block_offset = vgmstream->current_block_offset+128; + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset; + } +} diff --git a/lib/vgmstream/src/layout/xvas_block.c b/lib/vgmstream/src/layout/xvas_block.c new file mode 100644 index 0000000000..ee78c3ad10 --- /dev/null +++ b/lib/vgmstream/src/layout/xvas_block.c @@ -0,0 +1,24 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void xvas_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + + vgmstream->current_block_offset = block_offset; + + if((vgmstream->current_block_offset-get_streamfile_size(vgmstream->ch[0].streamfile))>(0x20000-0x20)) + vgmstream->current_block_size = 0x20000-0x20; + else + vgmstream->current_block_size = vgmstream->current_block_offset-get_streamfile_size(vgmstream->ch[0].streamfile)-0x20; + + vgmstream->next_block_offset = + vgmstream->current_block_offset + + (vgmstream->current_block_size + 0x20); + + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset; + } + vgmstream->current_block_size /=2; + +} diff --git a/lib/vgmstream/src/libvgmstream.vcproj b/lib/vgmstream/src/libvgmstream.vcproj new file mode 100644 index 0000000000..8d42e13f55 --- /dev/null +++ b/lib/vgmstream/src/libvgmstream.vcproj @@ -0,0 +1,1027 @@ +<?xml version="1.0" encoding="UTF-8"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8,00" + Name="libvgmstream" + ProjectGUID="{54A6AD11-5369-4895-A06F-E255ABB99B11}" + RootNamespace="libvgmstream" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="4" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="../ext_includes" + PreprocessorDefinitions="WIN32;_DEBUG;_LIB;" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="4" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="../ext_includes" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB;" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release DLL|Win32" + OutputDirectory="$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="../ext_includes" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB;" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)\vgmstream.dll" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath=".\streamfile.h" + > + </File> + <File + RelativePath=".\streamtypes.h" + > + </File> + <File + RelativePath=".\util.h" + > + </File> + <File + RelativePath=".\vgmstream.h" + > + </File> + </Filter> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\streamfile.c" + > + </File> + <File + RelativePath=".\util.c" + > + </File> + <File + RelativePath=".\vgmstream.c" + > + </File> + <File + RelativePath="..\XBMCVGM.cpp" + > + </File> + </Filter> + <Filter + Name="meta" + > + <Filter + Name="Header Files" + > + <File + RelativePath=".\meta\meta.h" + > + </File> + </Filter> + <Filter + Name="Source Files" + > + <File + RelativePath=".\meta\aax.c" + > + </File> + <File + RelativePath=".\meta\acm.c" + > + </File> + <File + RelativePath=".\meta\adx_header.c" + > + </File> + <File + RelativePath=".\meta\afc_header.c" + > + </File> + <File + RelativePath=".\meta\agsc.c" + > + </File> + <File + RelativePath=".\meta\ahx.c" + > + </File> + <File + RelativePath=".\meta\aifc.c" + > + </File> + <File + RelativePath=".\meta\aix.c" + > + </File> + <File + RelativePath=".\meta\ast.c" + > + </File> + <File + RelativePath=".\meta\bgw.c" + > + </File> + <File + RelativePath=".\meta\brstm.c" + > + </File> + <File + RelativePath=".\meta\capdsp.c" + > + </File> + <File + RelativePath=".\meta\Cstr.c" + > + </File> + <File + RelativePath=".\meta\dc_asd.c" + > + </File> + <File + RelativePath=".\meta\dc_idvi.c" + > + </File> + <File + RelativePath=".\meta\dc_kcey.c" + > + </File> + <File + RelativePath=".\meta\dc_str.c" + > + </File> + <File + RelativePath=".\meta\dc_wav_dcs.c" + > + </File> + <File + RelativePath=".\meta\de2.c" + > + </File> + <File + RelativePath=".\meta\ea_header.c" + > + </File> + <File + RelativePath=".\meta\ea_old.c" + > + </File> + <File + RelativePath=".\meta\emff.c" + > + </File> + <File + RelativePath=".\meta\fsb.c" + > + </File> + <File + RelativePath=".\meta\gca.c" + > + </File> + <File + RelativePath=".\meta\gcsw.c" + > + </File> + <File + RelativePath=".\meta\genh.c" + > + </File> + <File + RelativePath=".\meta\gsp_gsb.c" + > + </File> + <File + RelativePath=".\meta\halpst.c" + > + </File> + <File + RelativePath=".\meta\idsp.c" + > + </File> + <File + RelativePath=".\meta\ish_isd.c" + > + </File> + <File + RelativePath=".\meta\ivb.c" + > + </File> + <File + RelativePath=".\meta\kraw.c" + > + </File> + <File + RelativePath=".\meta\msvp.c" + > + </File> + <File + RelativePath=".\meta\mus_acm.c" + > + </File> + <File + RelativePath=".\meta\musc.c" + > + </File> + <File + RelativePath=".\meta\musx.c" + > + </File> + <File + RelativePath=".\meta\naomi_spsd.c" + > + </File> + <File + RelativePath=".\meta\nds_sad.c" + > + </File> + <File + RelativePath=".\meta\nds_strm.c" + > + </File> + <File + RelativePath=".\meta\ngc_adpdtk.c" + > + </File> + <File + RelativePath=".\meta\ngc_bh2pcm.c" + > + </File> + <File + RelativePath=".\meta\ngc_caf.c" + > + </File> + <File + RelativePath=".\meta\ngc_dsp_std.c" + > + </File> + <File + RelativePath=".\meta\ngc_ffcc_str.c" + > + </File> + <File + RelativePath=".\meta\ngc_pdt.c" + > + </File> + <File + RelativePath=".\meta\ngc_ssm.c" + > + </File> + <File + RelativePath=".\meta\ngc_tydsp.c" + > + </File> + <File + RelativePath=".\meta\ngc_waa_wac_wad_wam.c" + > + </File> + <File + RelativePath=".\meta\ngc_ymf.c" + > + </File> + <File + RelativePath=".\meta\nwa.c" + > + </File> + <File + RelativePath=".\meta\ogg_vorbis_file.c" + > + </File> + <File + RelativePath=".\meta\pcm.c" + > + </File> + <File + RelativePath=".\meta\pos.c" + > + </File> + <File + RelativePath=".\meta\ps2_ads.c" + > + </File> + <File + RelativePath=".\meta\ps2_ass.c" + > + </File> + <File + RelativePath=".\meta\ps2_aus.c" + > + </File> + <File + RelativePath=".\meta\ps2_bg00.c" + > + </File> + <File + RelativePath=".\meta\ps2_bmdx.c" + > + </File> + <File + RelativePath=".\meta\ps2_ccc.c" + > + </File> + <File + RelativePath=".\meta\ps2_dxh.c" + > + </File> + <File + RelativePath=".\meta\ps2_enth.c" + > + </File> + <File + RelativePath=".\meta\ps2_exst.c" + > + </File> + <File + RelativePath=".\meta\ps2_filp.c" + > + </File> + <File + RelativePath=".\meta\ps2_gbts.c" + > + </File> + <File + RelativePath=".\meta\ps2_hgc1.c" + > + </File> + <File + RelativePath=".\meta\ps2_ikm.c" + > + </File> + <File + RelativePath=".\meta\ps2_ild.c" + > + </File> + <File + RelativePath=".\meta\ps2_int.c" + > + </File> + <File + RelativePath=".\meta\ps2_joe.c" + > + </File> + <File + RelativePath=".\meta\ps2_kces.c" + > + </File> + <File + RelativePath=".\meta\ps2_leg.c" + > + </File> + <File + RelativePath=".\meta\ps2_mib.c" + > + </File> + <File + RelativePath=".\meta\ps2_mic.c" + > + </File> + <File + RelativePath=".\meta\ps2_mihb.c" + > + </File> + <File + RelativePath=".\meta\ps2_npsf.c" + > + </File> + <File + RelativePath=".\meta\ps2_p2bt.c" + > + </File> + <File + RelativePath=".\meta\ps2_pnb.c" + > + </File> + <File + RelativePath=".\meta\ps2_psh.c" + > + </File> + <File + RelativePath=".\meta\ps2_psw.c" + > + </File> + <File + RelativePath=".\meta\ps2_rkv.c" + > + </File> + <File + RelativePath=".\meta\ps2_rnd.c" + > + </File> + <File + RelativePath=".\meta\ps2_rstm.c" + > + </File> + <File + RelativePath=".\meta\ps2_rws.c" + > + </File> + <File + RelativePath=".\meta\ps2_rxw.c" + > + </File> + <File + RelativePath=".\meta\ps2_seg.c" + > + </File> + <File + RelativePath=".\meta\ps2_sfs.c" + > + </File> + <File + RelativePath=".\meta\ps2_sl3.c" + > + </File> + <File + RelativePath=".\meta\ps2_str.c" + > + </File> + <File + RelativePath=".\meta\ps2_svag.c" + > + </File> + <File + RelativePath=".\meta\ps2_tec.c" + > + </File> + <File + RelativePath=".\meta\ps2_vag.c" + > + </File> + <File + RelativePath=".\meta\ps2_vas.c" + > + </File> + <File + RelativePath=".\meta\ps2_vpk.c" + > + </File> + <File + RelativePath=".\meta\ps2_xa2.c" + > + </File> + <File + RelativePath=".\meta\ps2_xa30.c" + > + </File> + <File + RelativePath=".\meta\psx_cdxa.c" + > + </File> + <File + RelativePath=".\meta\psx_fag.c" + > + </File> + <File + RelativePath=".\meta\psx_gms.c" + > + </File> + <File + RelativePath=".\meta\raw.c" + > + </File> + <File + RelativePath=".\meta\riff.c" + > + </File> + <File + RelativePath=".\meta\rs03.c" + > + </File> + <File + RelativePath=".\meta\rsd.c" + > + </File> + <File + RelativePath=".\meta\rsf.c" + > + </File> + <File + RelativePath=".\meta\rwsd.c" + > + </File> + <File + RelativePath=".\meta\rwx.c" + > + </File> + <File + RelativePath=".\meta\sat_dvi.c" + > + </File> + <File + RelativePath=".\meta\sat_sap.c" + > + </File> + <File + RelativePath=".\meta\sdt.c" + > + </File> + <File + RelativePath=".\meta\sfl.c" + > + </File> + <File + RelativePath=".\meta\sli.c" + > + </File> + <File + RelativePath=".\meta\spt_spd.c" + > + </File> + <File + RelativePath=".\meta\ss_stream.c" + > + </File> + <File + RelativePath=".\meta\str_asr.c" + > + </File> + <File + RelativePath=".\meta\str_snds.c" + > + </File> + <File + RelativePath=".\meta\svs.c" + > + </File> + <File + RelativePath=".\meta\thp.c" + > + </File> + <File + RelativePath=".\meta\vgs.c" + > + </File> + <File + RelativePath=".\meta\vs.c" + > + </File> + <File + RelativePath=".\meta\wii_mus.c" + > + </File> + <File + RelativePath=".\meta\wii_smp.c" + > + </File> + <File + RelativePath=".\meta\wii_sng.c" + > + </File> + <File + RelativePath=".\meta\wii_sts.c" + > + </File> + <File + RelativePath=".\meta\ws_aud.c" + > + </File> + <File + RelativePath=".\meta\xbox_ims.c" + > + </File> + <File + RelativePath=".\meta\xbox_stma.c" + > + </File> + <File + RelativePath=".\meta\xbox_wavm.c" + > + </File> + <File + RelativePath=".\meta\xbox_wvs.c" + > + </File> + <File + RelativePath=".\meta\xbox_xmu.c" + > + </File> + <File + RelativePath=".\meta\xbox_xvas.c" + > + </File> + <File + RelativePath=".\meta\xbox_xwav.c" + > + </File> + <File + RelativePath=".\meta\xss.c" + > + </File> + <File + RelativePath=".\meta\xwb.c" + > + </File> + <File + RelativePath=".\meta\ydsp.c" + > + </File> + <File + RelativePath=".\meta\zwdsp.c" + > + </File> + </Filter> + </Filter> + <Filter + Name="coding" + > + <Filter + Name="Header Files" + > + <File + RelativePath=".\coding\acm_decoder.h" + > + </File> + <File + RelativePath=".\coding\coding.h" + > + </File> + <File + RelativePath=".\coding\g72x_state.h" + > + </File> + <File + RelativePath=".\coding\nwa_decoder.h" + > + </File> + </Filter> + <Filter + Name="Source Files" + > + <File + RelativePath=".\coding\acm_decoder.c" + > + </File> + <File + RelativePath=".\coding\adx_decoder.c" + > + </File> + <File + RelativePath=".\coding\aica_decoder.c" + > + </File> + <File + RelativePath=".\coding\eaxa_decoder.c" + > + </File> + <File + RelativePath=".\coding\g721_decoder.c" + > + </File> + <File + RelativePath=".\coding\ima_decoder.c" + > + </File> + <File + RelativePath=".\coding\l5_555_decoder.c" + > + </File> + <File + RelativePath=".\coding\mpeg_decoder.c" + > + </File> + <File + RelativePath=".\coding\msadpcm_decoder.c" + > + </File> + <File + RelativePath=".\coding\nds_procyon_decoder.c" + > + </File> + <File + RelativePath=".\coding\ngc_afc_decoder.c" + > + </File> + <File + RelativePath=".\coding\ngc_dsp_decoder.c" + > + </File> + <File + RelativePath=".\coding\ngc_dtk_decoder.c" + > + </File> + <File + RelativePath=".\coding\nwa_decoder.c" + > + </File> + <File + RelativePath=".\coding\ogg_vorbis_decoder.c" + > + </File> + <File + RelativePath=".\coding\pcm_decoder.c" + > + </File> + <File + RelativePath=".\coding\psx_decoder.c" + > + </File> + <File + RelativePath=".\coding\sdx2_decoder.c" + > + </File> + <File + RelativePath=".\coding\ws_decoder.c" + > + </File> + <File + RelativePath=".\coding\xa_decoder.c" + > + </File> + </Filter> + </Filter> + <Filter + Name="layout" + > + <Filter + Name="Header Files" + > + <File + RelativePath=".\layout\layout.h" + > + </File> + </Filter> + <Filter + Name="Source Files" + > + <File + RelativePath=".\layout\aax_layout.c" + > + </File> + <File + RelativePath=".\layout\aix_layout.c" + > + </File> + <File + RelativePath=".\layout\ast_blocked.c" + > + </File> + <File + RelativePath=".\layout\blocked.c" + > + </File> + <File + RelativePath=".\layout\caf_blocked.c" + > + </File> + <File + RelativePath=".\layout\de2_blocked.c" + > + </File> + <File + RelativePath=".\layout\ea_block.c" + > + </File> + <File + RelativePath=".\layout\emff_blocked.c" + > + </File> + <File + RelativePath=".\layout\filp_blocked.c" + > + </File> + <File + RelativePath=".\layout\gsb_blocked.c" + > + </File> + <File + RelativePath=".\layout\halpst_blocked.c" + > + </File> + <File + RelativePath=".\layout\ims_block.c" + > + </File> + <File + RelativePath=".\layout\interleave.c" + > + </File> + <File + RelativePath=".\layout\interleave_byte.c" + > + </File> + <File + RelativePath=".\layout\mus_acm_layout.c" + > + </File> + <File + RelativePath=".\layout\nolayout.c" + > + </File> + <File + RelativePath=".\layout\str_snds_blocked.c" + > + </File> + <File + RelativePath=".\layout\thp_blocked.c" + > + </File> + <File + RelativePath=".\layout\vs_blocked.c" + > + </File> + <File + RelativePath=".\layout\ws_aud_blocked.c" + > + </File> + <File + RelativePath=".\layout\wsi_blocked.c" + > + </File> + <File + RelativePath=".\layout\xa_blocked.c" + > + </File> + <File + RelativePath=".\layout\xvas_block.c" + > + </File> + </Filter> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/lib/vgmstream/src/meta/Cstr.c b/lib/vgmstream/src/meta/Cstr.c new file mode 100644 index 0000000000..0cd2867a5a --- /dev/null +++ b/lib/vgmstream/src/meta/Cstr.c @@ -0,0 +1,303 @@ +#include "meta.h" +#include "../coding/coding.h" +#include "../util.h" + +/* .dsp w/ Cstr header, seen in Star Fox Assault and Donkey Konga */ + +VGMSTREAM * init_vgmstream_Cstr(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag; + off_t start_offset; + off_t first_data; + off_t loop_offset; + size_t interleave; + int loop_adjust; + int double_loop_end = 0; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("dsp",filename_extension(filename))) goto fail; + + /* check header */ + if ((uint32_t)read_32bitBE(0,streamFile)!=0x43737472) /* "Cstr" */ + goto fail; +#ifdef DEBUG + fprintf(stderr,"header ok\n"); +#endif + + if (read_8bit(0x1b,streamFile)==1) { + /* mono version, much simpler to handle */ + /* Only seen in R Racing Evolution radio sfx */ + + start_offset = 0x80; + loop_flag = read_16bitBE(0x2c,streamFile); + + /* check initial predictor/scale */ + if (read_16bitBE(0x5e,streamFile) != (uint8_t)read_8bit(start_offset,streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (read_16bitBE(0x2e,streamFile) || read_16bitBE(0x5c,streamFile)) + goto fail; + + loop_offset = start_offset+read_32bitBE(0x10,streamFile); + if (loop_flag) { + if (read_16bitBE(0x64,streamFile) != (uint8_t)read_8bit(loop_offset,streamFile)) goto fail; + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(1,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->sample_rate = read_32bitBE(0x28,streamFile); + vgmstream->num_samples = read_32bitBE(0x20,streamFile); + + if (loop_flag) { + vgmstream->loop_start_sample = dsp_nibbles_to_samples( + read_32bitBE(0x30,streamFile)); + vgmstream->loop_end_sample = dsp_nibbles_to_samples( + read_32bitBE(0x34,streamFile))+1; + } + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_DSP_CSTR; + + { + int i; + for (i=0;i<16;i++) + vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(0x3c+i*2,streamFile); + } + + /* open the file for reading by each channel */ + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (!vgmstream->ch[0].streamfile) goto fail; + + vgmstream->ch[0].channel_start_offset= + vgmstream->ch[0].offset= + start_offset; + + return vgmstream; + } /* end mono */ + + interleave = read_16bitBE(0x06,streamFile); + start_offset = 0xe0; + first_data = start_offset+read_32bitBE(0x0c,streamFile); + loop_flag = read_16bitBE(0x2c,streamFile); + + if (!loop_flag) { + /* Nonlooped tracks seem to follow no discernable pattern + * with where they actually start. + * But! with the magic of initial p/s redundancy, we can guess. + */ + while (first_data<start_offset+0x800 && + (read_16bitBE(0x5e,streamFile) != (uint8_t)read_8bit(first_data,streamFile) || + read_16bitBE(0xbe,streamFile) != (uint8_t)read_8bit(first_data+interleave,streamFile))) + first_data+=8; +#ifdef DEBUG + fprintf(stderr,"guessed first_data at %#x\n",first_data); +#endif + } + + /* check initial predictor/scale */ + if (read_16bitBE(0x5e,streamFile) != (uint8_t)read_8bit(first_data,streamFile)) + goto fail; + if (read_16bitBE(0xbe,streamFile) != (uint8_t)read_8bit(first_data+interleave,streamFile)) + goto fail; + +#ifdef DEBUG + fprintf(stderr,"p/s ok\n"); +#endif + + /* check type==0 and gain==0 */ + if (read_16bitBE(0x2e,streamFile) || read_16bitBE(0x5c,streamFile)) + goto fail; + if (read_16bitBE(0x8e,streamFile) || read_16bitBE(0xbc,streamFile)) + goto fail; + +#ifdef DEBUG + fprintf(stderr,"type & gain ok\n"); +#endif + + /* check for loop flag agreement */ + if (read_16bitBE(0x2c,streamFile) != read_16bitBE(0x8c,streamFile)) + goto fail; + +#ifdef DEBUG + fprintf(stderr,"loop flags agree\n"); +#endif + + loop_offset = start_offset+read_32bitBE(0x10,streamFile)*2; + if (loop_flag) { + int loops_ok=0; + /* check loop predictor/scale */ + /* some fuzz allowed */ + for (loop_adjust=0;loop_adjust>=-0x10;loop_adjust-=8) { +#ifdef DEBUG + fprintf(stderr,"looking for loop p/s at %#x,%#x\n",loop_offset-interleave+loop_adjust,loop_offset+loop_adjust); +#endif + if (read_16bitBE(0x64,streamFile) == (uint8_t)read_8bit(loop_offset-interleave+loop_adjust,streamFile) && + read_16bitBE(0xc4,streamFile) == (uint8_t)read_8bit(loop_offset+loop_adjust,streamFile)) { + loops_ok=1; + break; + } + } + if (!loops_ok) + for (loop_adjust=interleave;loop_adjust<=interleave+0x10;loop_adjust+=8) { +#ifdef DEBUG + fprintf(stderr,"looking for loop p/s at %#x,%#x\n",loop_offset-interleave+loop_adjust,loop_offset+loop_adjust); +#endif + if (read_16bitBE(0x64,streamFile) == (uint8_t)read_8bit(loop_offset-interleave+loop_adjust,streamFile) && + read_16bitBE(0xc4,streamFile) == (uint8_t)read_8bit(loop_offset+loop_adjust,streamFile)) { + loops_ok=1; + break; + } + } + + if (!loops_ok) goto fail; +#ifdef DEBUG + fprintf(stderr,"loop p/s ok (with %#4x adjust)\n",loop_adjust); +#endif + + /* check for agreement */ + /* loop end (channel 1 & 2 headers) */ + if (read_32bitBE(0x34,streamFile) != read_32bitBE(0x94,streamFile)) + goto fail; + + /* Mr. Driller oddity */ + if (dsp_nibbles_to_samples(read_32bitBE(0x34,streamFile)*2)+1 <= read_32bitBE(0x20,streamFile)) { +#ifdef DEBUG + fprintf(stderr,"loop end <= half total samples, should be doubled\n"); +#endif + double_loop_end = 1; + } + + /* loop start (Cstr header and channel 1 header) */ + if (read_32bitBE(0x30,streamFile) != read_32bitBE(0x10,streamFile) +#if 0 + /* this particular glitch only true for SFA, though it + * seems like something similar happens in Donkey Konga */ + /* loop start (Cstr, channel 1 & 2 headers) */ + || (read_32bitBE(0x0c,streamFile)+read_32bitLE(0x30,streamFile)) != + read_32bitBE(0x90,streamFile) +#endif + ) + /* alternatively (Donkey Konga) the header loop is 0x0c+0x10 */ + if ( + /* loop start (Cstr header and channel 1 header) */ + read_32bitBE(0x30,streamFile) != read_32bitBE(0x10,streamFile)+ + read_32bitBE(0x0c,streamFile)) + /* further alternatively (Donkey Konga), if we loop back to + * the very first frame 0x30 might be 0x00000002 (which + * is a *valid* std dsp loop start, imagine that) while 0x10 + * is 0x00000000 */ + if (!(read_32bitBE(0x30,streamFile) == 2 && + read_32bitBE(0x10,streamFile) == 0)) + /* lest there be too few alternatives, in Mr. Driller we + * find that [0x30] + [0x0c] + 8 = [0x10]*2 */ + if (!(double_loop_end && + read_32bitBE(0x30,streamFile) + + read_32bitBE(0x0c,streamFile) + 8 == + read_32bitBE(0x10,streamFile)*2)) + goto fail; + +#ifdef DEBUG + fprintf(stderr,"loop points agree\n"); +#endif + } + + /* assure that sample counts, sample rates agree */ + if ( + /* sample count (channel 1 & 2 headers) */ + read_32bitBE(0x20,streamFile) != read_32bitBE(0x80,streamFile) || + /* sample rate (channel 1 & 2 headers) */ + read_32bitBE(0x28,streamFile) != read_32bitBE(0x88,streamFile) || + /* sample count (Cstr header and channel 1 header) */ + read_32bitLE(0x14,streamFile) != read_32bitBE(0x20,streamFile) || + /* sample rate (Cstr header and channel 1 header) */ + (uint16_t)read_16bitLE(0x18,streamFile) != read_32bitBE(0x28,streamFile)) + goto fail; + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(2,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->sample_rate = read_32bitBE(0x28,streamFile); + /* This is a slight hack to counteract their hack. + * All the data is ofset by first_data so that the loop + * point occurs at a block boundary. However, I always begin decoding + * right after the header, as that is the start of the first block and + * my interleave code relies on starting at the beginning of a block. + * So we decode a few silent samples at the beginning, and here we make up + * for it by lengthening the track by that much. + */ + vgmstream->num_samples = read_32bitBE(0x20,streamFile) + + (first_data-start_offset)/8*14; + + if (loop_flag) { + off_t loop_start_bytes = loop_offset-start_offset-interleave; + vgmstream->loop_start_sample = dsp_nibbles_to_samples((loop_start_bytes/(2*interleave)*interleave+loop_start_bytes%(interleave*2))*2); + /*dsp_nibbles_to_samples(loop_start_bytes);*/ + /*dsp_nibbles_to_samples(read_32bitBE(0x30,streamFile)*2-inter);*/ + vgmstream->loop_end_sample = dsp_nibbles_to_samples( + read_32bitBE(0x34,streamFile))+1; + + if (double_loop_end) + vgmstream->loop_end_sample = + dsp_nibbles_to_samples(read_32bitBE(0x34,streamFile)*2)+1; + + if (vgmstream->loop_end_sample > vgmstream->num_samples) { +#ifdef DEBUG + fprintf(stderr,"loop_end_sample > num_samples, adjusting\n"); +#endif + vgmstream->loop_end_sample = vgmstream->num_samples; + } + } + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + vgmstream->meta_type = meta_DSP_CSTR; + + { + int i; + for (i=0;i<16;i++) + vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(0x3c+i*2,streamFile); + for (i=0;i<16;i++) + vgmstream->ch[1].adpcm_coef[i]=read_16bitBE(0x9c+i*2,streamFile); + } +#ifdef DEBUG + vgmstream->ch[0].loop_history1 = read_16bitBE(0x66,streamFile); + vgmstream->ch[0].loop_history2 = read_16bitBE(0x68,streamFile); + vgmstream->ch[1].loop_history1 = read_16bitBE(0xc6,streamFile); + vgmstream->ch[1].loop_history2 = read_16bitBE(0xc8,streamFile); +#endif + + /* open the file for reading by each channel */ + { + int i; + for (i=0;i<2;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,interleave); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + start_offset+interleave*i; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/aax.c b/lib/vgmstream/src/meta/aax.c new file mode 100644 index 0000000000..7853c0ed3e --- /dev/null +++ b/lib/vgmstream/src/meta/aax.c @@ -0,0 +1,733 @@ +#include "../vgmstream.h" +#include "meta.h" +#include "../util.h" + +typedef struct _AAXSTREAMFILE +{ + STREAMFILE sf; + STREAMFILE *real_file; + off_t start_physical_offset; + size_t file_size; +} AAXSTREAMFILE; + +static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size); + +struct utf_query +{ + /* if 0 */ + const char *name; + int index; +}; + +struct offset_size_pair +{ + uint32_t offset; + uint32_t size; +}; + +struct utf_query_result +{ + int valid; /* table is valid */ + int found; + int type; /* one of COLUMN_TYPE_* */ + union + { + uint64_t value_u64; + uint32_t value_u32; + uint16_t value_u16; + uint8_t value_u8; + float value_float; + struct offset_size_pair value_data; + uint32_t value_string; + } value; + + /* info for the queried table */ + uint32_t rows; + uint32_t name_offset; + uint32_t string_table_offset; + uint32_t data_offset; +}; + +static struct utf_query_result analyze_utf(STREAMFILE *infile, long offset, + const struct utf_query *query); + +static struct utf_query_result query_utf(STREAMFILE *infile, long offset, + const struct utf_query *query); + +static struct utf_query_result query_utf_nofail(STREAMFILE *infile, const long offset, + const struct utf_query *query, int *error); + +static struct utf_query_result query_utf_key(STREAMFILE *infile, const long offset, + int index, const char *name, int *error); + +static uint8_t query_utf_1byte(STREAMFILE *infile, const long offset, + int index, const char *name, int *error); + +static struct offset_size_pair query_utf_data(STREAMFILE *infile, const long offset, + int index, const char *name, int *error); + +#define COLUMN_STORAGE_MASK 0xf0 +#define COLUMN_STORAGE_PERROW 0x50 +#define COLUMN_STORAGE_CONSTANT 0x30 +#define COLUMN_STORAGE_ZERO 0x10 + +#define COLUMN_TYPE_MASK 0x0f +#define COLUMN_TYPE_DATA 0x0b +#define COLUMN_TYPE_STRING 0x0a +#define COLUMN_TYPE_FLOAT 0x08 +#define COLUMN_TYPE_8BYTE 0x06 +#define COLUMN_TYPE_4BYTE 0x04 +#define COLUMN_TYPE_2BYTE2 0x03 +#define COLUMN_TYPE_2BYTE 0x02 +#define COLUMN_TYPE_1BYTE2 0x01 +#define COLUMN_TYPE_1BYTE 0x00 + +struct utf_column_info +{ + uint8_t type; + const char *column_name; + long constant_offset; +}; + +struct utf_table_info +{ + long table_offset; + uint32_t table_size; + uint32_t schema_offset; + uint32_t rows_offset; + uint32_t string_table_offset; + uint32_t data_offset; + const char *string_table; + const char *table_name; + uint16_t columns; + uint16_t row_width; + uint32_t rows; + + const struct utf_column_info *schema; +}; + + +/* Actual AAX init fcn */ +VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamFileAAX = NULL; + STREAMFILE * streamFileADX = NULL; + char filename[260]; + off_t *segment_offset = NULL; + off_t *segment_size = NULL; + int32_t sample_count; + int table_error; + + int loop_flag = 0; + int32_t loop_start_sample=0; + int32_t loop_end_sample=0; + int loop_segment = 0; + + aax_codec_data *data = NULL; + + const long AAX_offset = 0; + + int channel_count = 0, segment_count; + int sample_rate = 0; + + int i; + + + long aax_data_offset; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("aax",filename_extension(filename))) goto fail; + + /* get AAX entry count, data offset */ + { + struct utf_query_result result; + long aax_string_table_offset; + long aax_string_table_size; + + result = query_utf_nofail(streamFile, AAX_offset, NULL, &table_error); + if (table_error) goto fail; + segment_count = result.rows; + aax_string_table_offset = AAX_offset + 8 + result.string_table_offset; + aax_data_offset = AAX_offset + 8 + result.data_offset; + aax_string_table_size = aax_data_offset - aax_string_table_offset; + + if (result.name_offset+4 > aax_string_table_size) goto fail; + if (read_32bitBE(aax_string_table_offset + result.name_offset, + streamFile) != 0x41415800) /* "AAX\0" */ + goto fail; + } + + segment_offset = calloc(segment_count,sizeof(off_t)); + if (!segment_offset) + goto fail; + segment_size = calloc(segment_count,sizeof(off_t)); + if (!segment_size) + goto fail; + + /* get offsets of constituent ADXs */ + for (i = 0; i < segment_count; i++) + { + struct offset_size_pair offset_size; + offset_size = query_utf_data(streamFile, AAX_offset, i, "data", &table_error); + if (table_error) goto fail; + segment_offset[i] = aax_data_offset + offset_size.offset; + segment_size[i] = offset_size.size; + } + + streamFileAAX = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!streamFileAAX) goto fail; + + data = malloc(sizeof(aax_codec_data)); + if (!data) goto fail; + data->segment_count = segment_count; + data->adxs = malloc(sizeof(STREAMFILE *)*segment_count); + if (!data->adxs) goto fail; + for (i=0;i<segment_count;i++) { + data->adxs[i] = NULL; + } + data->sample_counts = calloc(segment_count,sizeof(int32_t)); + if (!data->sample_counts) goto fail; + + /* for each segment */ + for (i = 0; i < segment_count; i++) + { + VGMSTREAM *adx; + /*printf("try opening segment %d/%d %x\n",i,segment_count,segment_offset[i]);*/ + streamFileADX = open_aax_with_STREAMFILE(streamFileAAX,segment_offset[i],segment_size[i]); + if (!streamFileADX) goto fail; + adx = data->adxs[i] = init_vgmstream_adx(streamFileADX); + if (!adx) + goto fail; + data->sample_counts[i] = adx->num_samples; + close_streamfile(streamFileADX); streamFileADX = NULL; + + if (i == 0) + { + channel_count = adx->channels; + sample_rate = adx->sample_rate; + } + else + { + if (channel_count != adx->channels) + goto fail; + if (sample_rate != adx->sample_rate) + goto fail; + } + + if (adx->loop_flag != 0) + goto fail; + + /* save start things so we can restart for seeking/looping */ + /* copy the channels */ + memcpy(adx->start_ch,adx->ch,sizeof(VGMSTREAMCHANNEL)*adx->channels); + /* copy the whole VGMSTREAM */ + memcpy(adx->start_vgmstream,adx,sizeof(VGMSTREAM)); + + } + + sample_count = 0; + loop_flag = 0; + for (i = 0; i < segment_count; i++) + { + int segment_loop_flag = query_utf_1byte(streamFile, AAX_offset, i, + "lpflg", &table_error); + if (table_error) segment_loop_flag = 0; + + if (!loop_flag && segment_loop_flag) + { + loop_start_sample = sample_count; + loop_segment = i; + } + + sample_count += data->sample_counts[i]; + + if (!loop_flag && segment_loop_flag) + { + loop_end_sample = sample_count; + loop_flag = 1; + } + } + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + + vgmstream->num_samples = sample_count; + vgmstream->sample_rate = sample_rate; + + vgmstream->loop_start_sample = loop_start_sample; + vgmstream->loop_end_sample = loop_end_sample; + + vgmstream->coding_type = data->adxs[0]->coding_type; + vgmstream->layout_type = layout_aax; + vgmstream->meta_type = meta_AAX; + + vgmstream->ch[0].streamfile = streamFileAAX; + data->current_segment = 0; + data->loop_segment = loop_segment; + + vgmstream->codec_data = data; + free(segment_offset); + free(segment_size); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (streamFileAAX) close_streamfile(streamFileAAX); + if (streamFileADX) close_streamfile(streamFileADX); + if (vgmstream) close_vgmstream(vgmstream); + if (segment_offset) free(segment_offset); + if (segment_size) free(segment_size); + if (data) { + if (data->adxs) + { + int i; + for (i=0;i<data->segment_count;i++) + if (data->adxs) + close_vgmstream(data->adxs[i]); + free(data->adxs); + } + if (data->sample_counts) + { + free(data->sample_counts); + } + free(data); + } + return NULL; +} + +/* virtual file, a piece of the overall file */ + +static size_t read_aax(AAXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length) +{ + /* truncate at end of logical file */ + if (offset+length > streamfile->file_size) + { + long signed_length = length; + signed_length = streamfile->file_size - offset; + if (signed_length < 0) signed_length = 0; + length = signed_length; + } + return read_streamfile(dest, + streamfile->start_physical_offset+offset, + length,streamfile->real_file); +} + +static void close_aax(AAXSTREAMFILE *streamfile) +{ + free(streamfile); + return; +} + +static size_t get_size_aax(AAXSTREAMFILE *streamfile) +{ + return 0; +} + +static size_t get_offset_aax(AAXSTREAMFILE *streamfile) +{ + long offset = streamfile->real_file->get_offset(streamfile->real_file); + offset -= streamfile->start_physical_offset; + if (offset < 0) offset = 0; + if (offset > streamfile->file_size) offset = streamfile->file_size; + + return offset; +} + +static void get_name_aax(AAXSTREAMFILE *streamfile,char *buffer,size_t length) +{ + strncpy(buffer,"ARBITRARY.ADX",length); + buffer[length-1]='\0'; +} + +static STREAMFILE *open_aax_impl(AAXSTREAMFILE *streamfile,const char * const filename,size_t buffersize) +{ + AAXSTREAMFILE *newfile; + if (strcmp(filename,"ARBITRARY.ADX")) + return NULL; + + newfile = malloc(sizeof(AAXSTREAMFILE)); + if (!newfile) + return NULL; + memcpy(newfile,streamfile,sizeof(AAXSTREAMFILE)); + return &newfile->sf; +} + +static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size) +{ + AAXSTREAMFILE *streamfile = malloc(sizeof(AAXSTREAMFILE)); + + if (!streamfile) + return NULL; + + /* success, set our pointers */ + + streamfile->sf.read = (void*)read_aax; + streamfile->sf.get_size = (void*)get_size_aax; + streamfile->sf.get_offset = (void*)get_offset_aax; + streamfile->sf.get_name = (void*)get_name_aax; + streamfile->sf.get_realname = (void*)get_name_aax; + streamfile->sf.open = (void*)open_aax_impl; + streamfile->sf.close = (void*)close_aax; +#ifdef PROFILE_STREAMFILE + streamfile->sf.get_bytes_read = NULL; + streamfile->sf.get_error_count = NULL; +#endif + + streamfile->real_file = file; + streamfile->start_physical_offset = start_offset; + streamfile->file_size = file_size; + + return &streamfile->sf; +} + +/* @UTF table reading, abridged */ +static struct utf_query_result analyze_utf(STREAMFILE *infile, const long offset, const struct utf_query *query) +{ + unsigned char buf[4]; + struct utf_table_info table_info; + char *string_table = NULL; + struct utf_column_info * schema = NULL; + struct utf_query_result result; + uint32_t table_name_string; + int string_table_size; + + result.valid = 0; + + table_info.table_offset = offset; + + /* check header */ + { + static const char UTF_signature[4] = "@UTF"; /* intentionally unterminated */ + if (4 != read_streamfile(buf, offset, 4, infile)) goto cleanup_error; + if (memcmp(buf, UTF_signature, sizeof(UTF_signature))) + { + goto cleanup_error; + } + } + + /* get table size */ + table_info.table_size = read_32bitBE(offset+4, infile); + + table_info.schema_offset = 0x20; + table_info.rows_offset = read_32bitBE(offset+8, infile); + table_info.string_table_offset = read_32bitBE(offset+0xc,infile); + table_info.data_offset = read_32bitBE(offset+0x10,infile); + table_name_string = read_32bitBE(offset+0x14,infile); + table_info.columns = read_16bitBE(offset+0x18,infile); + table_info.row_width = read_16bitBE(offset+0x1a,infile); + table_info.rows = read_32bitBE(offset+0x1c,infile); + + /* allocate for string table */ + string_table_size = table_info.data_offset-table_info.string_table_offset; + string_table = malloc(string_table_size+1); + if (!string_table) goto cleanup_error; + table_info.string_table = string_table; + memset(string_table, 0, string_table_size+1); + + /* load schema */ + schema = malloc(sizeof(struct utf_column_info) * table_info.columns); + if (!schema) goto cleanup_error; + + { + int i; + long schema_current_offset = table_info.schema_offset; + for (i = 0; i < table_info.columns; i++) + { + schema[i].type = read_8bit(schema_current_offset,infile); + schema_current_offset ++; + schema[i].column_name = string_table + read_32bitBE(schema_current_offset,infile); + schema_current_offset += 4; + + if ((schema[i].type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT) + { + schema[i].constant_offset = schema_current_offset; + switch (schema[i].type & COLUMN_TYPE_MASK) + { + case COLUMN_TYPE_8BYTE: + case COLUMN_TYPE_DATA: + schema_current_offset+=8; + break; + case COLUMN_TYPE_STRING: + case COLUMN_TYPE_FLOAT: + case COLUMN_TYPE_4BYTE: + schema_current_offset+=4; + break; + case COLUMN_TYPE_2BYTE2: + case COLUMN_TYPE_2BYTE: + schema_current_offset+=2; + break; + case COLUMN_TYPE_1BYTE2: + case COLUMN_TYPE_1BYTE: + schema_current_offset++; + break; + default: + goto cleanup_error; + } + } + } + } + + table_info.schema = schema; + + /* read string table */ + read_streamfile((unsigned char *)string_table, + table_info.string_table_offset+8+offset, + string_table_size, infile); + table_info.table_name = table_info.string_table+table_name_string; + + /* fill in the default stuff */ + result.found = 0; + result.rows = table_info.rows; + result.name_offset = table_name_string; + result.string_table_offset = table_info.string_table_offset; + result.data_offset = table_info.data_offset; + + /* explore the values */ + if (query) { + int i, j; + + for (i = 0; i < table_info.rows; i++) + { + uint32_t row_offset = + table_info.table_offset + 8 + table_info.rows_offset + + i * table_info.row_width; + const uint32_t row_start_offset = row_offset; + + if (query && i != query->index) continue; + + for (j = 0; j < table_info.columns; j++) + { + uint8_t type = table_info.schema[j].type; + long constant_offset = table_info.schema[j].constant_offset; + int constant = 0; + + int qthis = (query && i == query->index && + !strcmp(table_info.schema[j].column_name, query->name)); + + if (qthis) + { + result.found = 1; + result.type = schema[j].type & COLUMN_TYPE_MASK; + } + + switch (schema[j].type & COLUMN_STORAGE_MASK) + { + case COLUMN_STORAGE_PERROW: + break; + case COLUMN_STORAGE_CONSTANT: + constant = 1; + break; + case COLUMN_STORAGE_ZERO: + if (qthis) + { + memset(&result.value, 0, + sizeof(result.value)); + } + continue; + default: + goto cleanup_error; + } + + if (1) + { + long data_offset; + int bytes_read; + + if (constant) + { + data_offset = constant_offset; + } + else + { + data_offset = row_offset; + } + + switch (type & COLUMN_TYPE_MASK) + { + case COLUMN_TYPE_STRING: + { + uint32_t string_offset; + string_offset = read_32bitBE(data_offset, infile); + bytes_read = 4; + if (qthis) + { + result.value.value_string = string_offset; + } + } + break; + case COLUMN_TYPE_DATA: + { + uint32_t vardata_offset, vardata_size; + + vardata_offset = read_32bitBE(data_offset, infile); + vardata_size = read_32bitBE(data_offset+4, infile); + bytes_read = 8; + if (qthis) + { + result.value.value_data.offset = vardata_offset; + result.value.value_data.size = vardata_size; + } + } + break; + + case COLUMN_TYPE_8BYTE: + { + uint64_t value = + read_32bitBE(data_offset, infile); + value <<= 32; + value |= + read_32bitBE(data_offset+4, infile); + if (qthis) + { + result.value.value_u64 = value; + } + bytes_read = 8; + break; + } + case COLUMN_TYPE_4BYTE: + { + uint32_t value = + read_32bitBE(data_offset, infile); + if (qthis) + { + result.value.value_u32 = value; + } + bytes_read = 4; + } + break; + case COLUMN_TYPE_2BYTE2: + case COLUMN_TYPE_2BYTE: + { + uint16_t value = + read_16bitBE(data_offset, infile); + if (qthis) + { + result.value.value_u16 = value; + } + bytes_read = 2; + } + break; + case COLUMN_TYPE_FLOAT: + if (sizeof(float) == 4) + { + union { + float float_value; + uint32_t int_value; + } int_float; + + int_float.int_value = read_32bitBE(data_offset, infile); + if (qthis) + { + result.value.value_float = int_float.float_value; + } + } + else + { + read_32bitBE(data_offset, infile); + if (qthis) + { + goto cleanup_error; + } + } + bytes_read = 4; + break; + case COLUMN_TYPE_1BYTE2: + case COLUMN_TYPE_1BYTE: + { + uint8_t value = + read_8bit(data_offset, infile); + if (qthis) + { + result.value.value_u8 = value; + } + bytes_read = 1; + } + break; + default: + goto cleanup_error; + } + + if (!constant) + { + row_offset += bytes_read; + } + } /* useless if end */ + } /* column for loop end */ + + if (row_offset - row_start_offset != table_info.row_width) + goto cleanup_error; + + if (query && i >= query->index) break; + } /* row for loop end */ + } /* explore values block end */ + +//cleanup: + + result.valid = 1; +cleanup_error: + + if (string_table) + { + free(string_table); + string_table = NULL; + } + + if (schema) + { + free(schema); + schema = NULL; + } + + return result; +} + +static struct utf_query_result query_utf(STREAMFILE *infile, const long offset, const struct utf_query *query) +{ + return analyze_utf(infile, offset, query); +} + +static struct utf_query_result query_utf_nofail(STREAMFILE *infile, const long offset, const struct utf_query *query, int *error) +{ + const struct utf_query_result result = query_utf(infile, offset, query); + + if (error) + { + *error = 0; + if (!result.valid) *error = 1; + if (query && !result.found) *error = 1; + } + + return result; +} + +static struct utf_query_result query_utf_key(STREAMFILE *infile, const long offset, int index, const char *name, int *error) +{ + struct utf_query query; + query.index = index; + query.name = name; + + return query_utf_nofail(infile, offset, &query, error); +} + +static uint8_t query_utf_1byte(STREAMFILE *infile, const long offset, int index, const char *name, int *error) +{ + struct utf_query_result result = query_utf_key(infile, offset, index, name, error); + if (error) + { + if (result.type != COLUMN_TYPE_1BYTE) *error = 1; + } + return result.value.value_u8; +} + +static struct offset_size_pair query_utf_data(STREAMFILE *infile, const long offset, + int index, const char *name, int *error) +{ + struct utf_query_result result = query_utf_key(infile, offset, index, name, error); + if (error) + { + if (result.type != COLUMN_TYPE_DATA) *error = 1; + } + return result.value.value_data; +} diff --git a/lib/vgmstream/src/meta/acm.c b/lib/vgmstream/src/meta/acm.c new file mode 100644 index 0000000000..c58e596788 --- /dev/null +++ b/lib/vgmstream/src/meta/acm.c @@ -0,0 +1,66 @@ +#include "../vgmstream.h" +#include "meta.h" +#include "../util.h" +#include "../coding/acm_decoder.h" + +/* InterPlay ACM */ +/* The real work is done by libacm */ +VGMSTREAM * init_vgmstream_acm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + ACMStream *acm_stream = NULL; + mus_acm_codec_data *data; + + char filename[260]; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("acm",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x97280301) + goto fail; + + data = calloc(1,sizeof(mus_acm_codec_data)); + if (!data) goto fail; + + data->files = calloc(1,sizeof(ACMStream *)); + if (!data->files) { + free(data); data = NULL; + goto fail; + } + + /* gonna do this a little backwards, open and parse the file + before creating the vgmstream */ + + if (acm_open_decoder(&acm_stream,streamFile,filename) != ACM_OK) { + goto fail; + } + + channel_count = acm_stream->info.channels; + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->channels = channel_count; + vgmstream->sample_rate = acm_stream->info.rate; + vgmstream->coding_type = coding_ACM; + vgmstream->num_samples = acm_stream->total_values / acm_stream->info.channels; + vgmstream->layout_type = layout_acm; + vgmstream->meta_type = meta_ACM; + + data->file_count = 1; + data->current_file = 0; + data->files[0] = acm_stream; + /*data->end_file = -1;*/ + + vgmstream->codec_data = data; + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/adx_header.c b/lib/vgmstream/src/meta/adx_header.c new file mode 100644 index 0000000000..57952118ce --- /dev/null +++ b/lib/vgmstream/src/meta/adx_header.c @@ -0,0 +1,347 @@ +#ifdef _MSC_VER +#define _USE_MATH_DEFINES +#endif +#include <math.h> +#include <string.h> +#include <limits.h> +#include "meta.h" + +#include "../coding/coding.h" +#include "../util.h" + +static int find_key(STREAMFILE *file, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add); + +VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t stream_offset; + size_t filesize; + uint16_t version_signature; + int loop_flag=0; + int channel_count; + int32_t loop_start_offset=0; + int32_t loop_end_offset=0; + int32_t loop_start_sample=0; + int32_t loop_end_sample=0; + meta_t header_type; + int16_t coef1, coef2; + uint16_t cutoff; + char filename[260]; + int coding_type = coding_CRI_ADX; + uint16_t xor_start=0,xor_mult=0,xor_add=0; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("adx",filename_extension(filename))) goto fail; + + filesize = get_streamfile_size(streamFile); + + /* check first 2 bytes */ + if ((uint16_t)read_16bitBE(0,streamFile)!=0x8000) goto fail; + + /* get stream offset, check for CRI signature just before */ + stream_offset = (uint16_t)read_16bitBE(2,streamFile) + 4; + if ((uint16_t)read_16bitBE(stream_offset-6,streamFile)!=0x2863 ||/* "(c" */ + (uint32_t)read_32bitBE(stream_offset-4,streamFile)!=0x29435249 /* ")CRI" */ + ) goto fail; + + /* check for encoding type */ + /* 2 is for some unknown fixed filter, 3 is standard ADX, 4 is + * ADX with exponential scale, 0x11 is AHX */ + if (read_8bit(4,streamFile) != 3) goto fail; + + /* check for frame size (only 18 is supported at the moment) */ + if (read_8bit(5,streamFile) != 18) goto fail; + + /* check for bits per sample? (only 4 makes sense for ADX) */ + if (read_8bit(6,streamFile) != 4) goto fail; + + /* check version signature, read loop info */ + version_signature = read_16bitBE(0x12,streamFile); + /* encryption */ + if (version_signature == 0x0408) { + if (find_key(streamFile, &xor_start, &xor_mult, &xor_add)) + { + coding_type = coding_CRI_ADX_enc; + version_signature = 0x0400; + } + } + if (version_signature == 0x0300) { /* type 03 */ + header_type = meta_ADX_03; + if (stream_offset-6 >= 0x2c) { /* enough space for loop info? */ + loop_flag = (read_32bitBE(0x18,streamFile) != 0); + loop_start_sample = read_32bitBE(0x1c,streamFile); + loop_start_offset = read_32bitBE(0x20,streamFile); + loop_end_sample = read_32bitBE(0x24,streamFile); + loop_end_offset = read_32bitBE(0x28,streamFile); + } + } else if (version_signature == 0x0400) { + + off_t ainf_info_length=0; + + if((uint32_t)read_32bitBE(0x24,streamFile)==0x41494E46) /* AINF Header */ + ainf_info_length = (off_t)read_32bitBE(0x28,streamFile); + + header_type = meta_ADX_04; + if (stream_offset-ainf_info_length-6 >= 0x38) { /* enough space for loop info? */ + loop_flag = (read_32bitBE(0x24,streamFile) != 0); + loop_start_sample = read_32bitBE(0x28,streamFile); + loop_start_offset = read_32bitBE(0x2c,streamFile); + loop_end_sample = read_32bitBE(0x30,streamFile); + loop_end_offset = read_32bitBE(0x34,streamFile); + } + } else if (version_signature == 0x0500) { /* found in some SFD : Buggy Heat, appears to have no loop */ + header_type = meta_ADX_05; + } else goto fail; /* not a known/supported version signature */ + + /* At this point we almost certainly have an ADX file, + * so let's build the VGMSTREAM. */ + + /* high-pass cutoff frequency, always 500 that I've seen */ + cutoff = (uint16_t)read_16bitBE(0x10,streamFile); + + channel_count = read_8bit(7,streamFile); + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = read_32bitBE(0xc,streamFile); + vgmstream->sample_rate = read_32bitBE(8,streamFile); + /* channels and loop flag are set by allocate_vgmstream */ + vgmstream->loop_start_sample = loop_start_sample; + vgmstream->loop_end_sample = loop_end_sample; + + vgmstream->coding_type = coding_type; + if (channel_count==1) + vgmstream->layout_type = layout_none; + else + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = header_type; + + vgmstream->interleave_block_size=18; + + /* calculate filter coefficients */ + { + double x,y,z,a,b,c; + + x = cutoff; + y = vgmstream->sample_rate; + z = cos(2.0*M_PI*x/y); + + a = M_SQRT2-z; + b = M_SQRT2-1.0; + c = (a-sqrt((a+b)*(a-b)))/b; + + coef1 = floor(c*8192); + coef2 = floor(c*c*-4096); + } + + { + int i; + STREAMFILE * chstreamfile; + + /* ADX is so tightly interleaved that having two buffers is silly */ + chstreamfile = streamFile->open(streamFile,filename,18*0x400); + if (!chstreamfile) goto fail; + + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = chstreamfile; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + stream_offset+18*i; + + vgmstream->ch[i].adpcm_coef[0] = coef1; + vgmstream->ch[i].adpcm_coef[1] = coef2; + + if (coding_type == coding_CRI_ADX_enc) + { + int j; + vgmstream->ch[i].adx_channels = channel_count; + vgmstream->ch[i].adx_xor = xor_start; + vgmstream->ch[i].adx_mult = xor_mult; + vgmstream->ch[i].adx_add = xor_add; + + for (j=0;j<i;j++) + adx_next_key(&vgmstream->ch[i]); + } + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +/* guessadx stuff */ + +static struct { + uint16_t start,mult,add; +} keys[] = { + /* Clover Studio (GOD HAND, Okami) */ + /* I'm pretty sure this is right, based on a decrypted version of some GOD HAND tracks. */ + /* Also it is the 2nd result from guessadx */ + {0x49e1,0x4a57,0x553d}, + + /* Grasshopper Manufacture 0 (Blood+) */ + /* this is estimated */ + {0x5f5d,0x58bd,0x55ed}, + + /* Grasshopper Manufacture 1 (Killer7) */ + /* this is estimated */ + {0x50fb,0x5803,0x5701}, + + /* Grasshopper Manufacture 2 (Samurai Champloo) */ + /* confirmed unique with guessadx */ + {0x4f3f,0x472f,0x562f}, + + /* Moss Ltd (Raiden III) */ + /* this is estimated */ + {0x66f5,0x58bd,0x4459}, + + /* Sonic Team 0 (Phantasy Star Universe) */ + /* this is estimated */ + {0x5deb,0x5f27,0x673f}, + + /* G.dev (Senko no Ronde) */ + /* this is estimated */ + {0x46d3,0x5ced,0x474d}, + + /* Sonic Team 1 (NiGHTS: Journey of Dreams) */ + /* this seems to be dead on, but still estimated */ + {0x440b,0x6539,0x5723}, + + /* from guessadx (unique?), unknown source */ + {0x586d,0x5d65,0x63eb}, + + /* Navel (Shuffle! On the Stage) */ + /* 2nd key from guessadx */ + {0x4969,0x5deb,0x467f}, + + /* Success (Aoishiro) */ + /* 1st key from guessadx */ + {0x4d65,0x5eb7,0x5dfd}, +}; + +static const int key_count = sizeof(keys)/sizeof(keys[0]); + +/* return 0 if not found, 1 if found and set parameters */ +static int find_key(STREAMFILE *file, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add) +{ + uint16_t * scales = NULL; + uint16_t * prescales = NULL; + int bruteframe=0,bruteframecount=-1; + int startoff, endoff; + int rc = 0; + + startoff=read_16bitBE(2, file)+4; + endoff=(read_32bitBE(12, file)+31)/32*18*read_8bit(7, file)+startoff; + + /* how many scales? */ + { + int framecount=(endoff-startoff)/18; + if (framecount<bruteframecount || bruteframecount<0) + bruteframecount=framecount; + } + + /* find longest run of nonzero frames */ + { + int longest=-1,longest_length=-1; + int i; + int length=0; + for (i=0;i<bruteframecount;i++) { + static const unsigned char zeroes[18]={0}; + unsigned char buf[18]; + read_streamfile(buf, startoff+i*18, 18, file); + if (memcmp(zeroes,buf,18)) length++; + else length=0; + if (length > longest_length) { + longest_length=length; + longest=i-length+1; + if (longest_length >= 0x8000) break; + } + } + if (longest==-1) { + goto find_key_cleanup; + } + bruteframecount = longest_length; + bruteframe = longest; + } + + { + /* try to guess key */ +#define MAX_FRAMES (INT_MAX/0x8000) + int scales_to_do; + int key_id; + + /* allocate storage for scales */ + scales_to_do = (bruteframecount > MAX_FRAMES ? MAX_FRAMES : bruteframecount); + scales = malloc(scales_to_do*sizeof(uint16_t)); + if (!scales) { + goto find_key_cleanup; + } + /* prescales are those scales before the first frame we test + * against, we use these to compute the actual start */ + if (bruteframe > 0) { + int i; + /* allocate memory for the prescales */ + prescales = malloc(bruteframe*sizeof(uint16_t)); + if (!prescales) { + goto find_key_cleanup; + } + /* read the prescales */ + for (i=0; i<bruteframe; i++) { + prescales[i] = read_16bitBE(startoff+i*18, file); + } + } + + /* read in the scales */ + { + int i; + for (i=0; i < scales_to_do; i++) { + scales[i] = read_16bitBE(startoff+(bruteframe+i)*18, file); + } + } + + /* guess each of the keys */ + for (key_id=0;key_id<=key_count;key_id++) { + /* test pre-scales */ + uint16_t xor = keys[key_id].start; + uint16_t mult = keys[key_id].mult; + uint16_t add = keys[key_id].add; + int i; + + for (i=0;i<bruteframe && + ((prescales[i]&0x6000)==(xor&0x6000) || + prescales[i]==0); + i++) { + xor = xor * mult + add; + } + + if (i == bruteframe) + { + /* test */ + for (i=0;i<scales_to_do && + (scales[i]&0x6000)==(xor&0x6000);i++) { + xor = xor * mult + add; + } + if (i == scales_to_do) + { + *xor_start = keys[key_id].start; + *xor_mult = keys[key_id].mult; + *xor_add = keys[key_id].add; + + rc = 1; + goto find_key_cleanup; + } + } + } + } + +find_key_cleanup: + if (scales) free(scales); + if (prescales) free(prescales); + return rc; +} diff --git a/lib/vgmstream/src/meta/afc_header.c b/lib/vgmstream/src/meta/afc_header.c new file mode 100644 index 0000000000..d7bec9c0b1 --- /dev/null +++ b/lib/vgmstream/src/meta/afc_header.c @@ -0,0 +1,67 @@ +#include "meta.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_afc(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag; + const int channel_count = 2; /* .afc seems to be stereo only */ + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("afc",filename_extension(filename))) goto fail; + + /* don't grab AIFF-C with .afc extension */ + if ((uint32_t)read_32bitBE(0x0,streamFile)==0x464F524D) /* FORM */ + goto fail; + + /* we will get a sample rate, that's as close to checking as I think + * we can get */ + + /* build the VGMSTREAM */ + + loop_flag = read_32bitBE(0x10,streamFile); + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = read_32bitBE(0x04,streamFile); + vgmstream->sample_rate = (uint16_t)read_16bitBE(0x08,streamFile); + /* channels and loop flag are set by allocate_vgmstream */ + vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile); + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_NGC_AFC; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_AFC; + + /* frame-level interleave (9 bytes) */ + vgmstream->interleave_block_size = 9; + + /* open the file for reading by each channel */ + { + STREAMFILE *chstreamfile; + int i; + + /* both channels use same buffer, as interleave is so small */ + chstreamfile = streamFile->open(streamFile,filename,9*channel_count*0x100); + if (!chstreamfile) goto fail; + + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = chstreamfile; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + 0x20 + i*vgmstream->interleave_block_size; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/agsc.c b/lib/vgmstream/src/meta/agsc.c new file mode 100644 index 0000000000..4388df1cb3 --- /dev/null +++ b/lib/vgmstream/src/meta/agsc.c @@ -0,0 +1,73 @@ +#include "meta.h" +#include "../util.h" + +/* .agsc - from Metroid Prime 2 */ + +VGMSTREAM * init_vgmstream_agsc(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + off_t header_offset; + off_t start_offset; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("agsc",filename_extension(filename))) goto fail; + + /* check header */ + if ((uint32_t)read_32bitBE(0,streamFile)!=0x00000001) + goto fail; + + /* 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 ++; + + channel_count = 1; + + /* build the VGMSTREAM */ + + 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_DSP_AGSC; + + 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; +} diff --git a/lib/vgmstream/src/meta/ahx.c b/lib/vgmstream/src/meta/ahx.c new file mode 100644 index 0000000000..cce0040b1d --- /dev/null +++ b/lib/vgmstream/src/meta/ahx.c @@ -0,0 +1,121 @@ +#include "../vgmstream.h" + +#ifdef VGM_USE_MPEG + +#include "meta.h" +#include "../util.h" + +/* AHX is a CRI format which contains an MPEG-2 Layer 2 audio stream. + * Although the MPEG frame headers are incorrect... */ + +VGMSTREAM * init_vgmstream_ahx(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t stream_offset; + size_t filesize; + char filename[260]; + int channel_count = 1; + int loop_flag = 0; + mpeg_codec_data *data = NULL; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ahx",filename_extension(filename))) goto fail; + + filesize = get_streamfile_size(streamFile); + + /* check first 2 bytes */ + if ((uint16_t)read_16bitBE(0,streamFile)!=0x8000) goto fail; + + /* get stream offset, check for CRI signature just before */ + stream_offset = (uint16_t)read_16bitBE(2,streamFile) + 4; + if ((uint16_t)read_16bitBE(stream_offset-6,streamFile)!=0x2863 ||/* "(c" */ + (uint32_t)read_32bitBE(stream_offset-4,streamFile)!=0x29435249 /* ")CRI" */ + ) goto fail; + + /* check for encoding type */ + /* 2 is for some unknown fixed filter, 3 is standard ADX, 4 is + * ADX with exponential scale, 0x11 is AHX */ + /* Sappharad reports that old AHXs (Sonic Adventure 2) don't have this flag. + * When I see one perhaps I can add an exception for those. */ + if (read_8bit(4,streamFile) != 0x11) goto fail; + + /* check for frame size (0 for AHX) */ + if (read_8bit(5,streamFile) != 0) goto fail; + + /* check for bits per sample? (0 for AHX) */ + if (read_8bit(6,streamFile) != 0) goto fail; + + /* check channel count (only mono AHXs are known) */ + if (read_8bit(7,streamFile) != 1) goto fail; + + /* At this point we almost certainly have an ADX file, + * so let's build the VGMSTREAM. */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = read_32bitBE(0xc,streamFile); + /* This is the One True Samplerate, the MPEG headers lie. */ + vgmstream->sample_rate = read_32bitBE(8,streamFile); + + vgmstream->coding_type = coding_fake_MPEG2_L2; + vgmstream->layout_type = layout_fake_mpeg; + vgmstream->meta_type = meta_AHX; + + { + int i; + STREAMFILE * chstreamfile; + + chstreamfile = streamFile->open(streamFile,filename, + STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!chstreamfile) goto fail; + + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = chstreamfile; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + stream_offset; + } + } + + /* ooh, fun part, set up mpg123 */ + { + int rc; + data = calloc(1,sizeof(mpeg_codec_data)); + if (!data) goto fail; + + data->m = mpg123_new(NULL,&rc); + if (rc==MPG123_NOT_INITIALIZED) { + if (mpg123_init()!=MPG123_OK) goto fail; + data->m = mpg123_new(NULL,&rc); + if (rc!=MPG123_OK) goto fail; + } else if (rc!=MPG123_OK) { + goto fail; + } + + if (mpg123_open_feed(data->m)!=MPG123_OK) { + goto fail; + } + + vgmstream->codec_data = data; + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (data) { + if (data->m) { + mpg123_delete(data->m); + data->m = NULL; + } + free(data); + data = NULL; + } + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +#endif diff --git a/lib/vgmstream/src/meta/aifc.c b/lib/vgmstream/src/meta/aifc.c new file mode 100644 index 0000000000..900bacacd7 --- /dev/null +++ b/lib/vgmstream/src/meta/aifc.c @@ -0,0 +1,305 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* Audio Interchange File Format AIFF-C */ +/* also plain AIFF, for good measure */ + +/* Included primarily for 3DO */ + +/* for reading integers inexplicably packed into 80 bit floats */ +uint32_t read80bitSANE(off_t offset, STREAMFILE *streamFile) { + uint8_t buf[10]; + int32_t exponent; + int32_t mantissa; + int i; + + if (read_streamfile(buf,offset,10,streamFile) != 10) return 0; + + exponent = ((buf[0]<<8)|(buf[1]))&0x7fff; + exponent -= 16383; + + mantissa = 0; + for (i=0;i<8;i++) { + int32_t shift = exponent-7-i*8; + if (shift >= 0) + mantissa |= buf[i+2] << shift; + else if (shift > -8) + mantissa |= buf[i+2] >> -shift; + } + + return mantissa*((buf[0]&0x80)?-1:1); +} + +uint32_t find_marker(STREAMFILE *streamFile, off_t MarkerChunkOffset, + int marker_id) { + uint16_t marker_count; + int i; + off_t marker_offset; + + marker_count = read_16bitBE(MarkerChunkOffset+8,streamFile); + marker_offset = MarkerChunkOffset+10; + for (i=0;i<marker_count;i++) { + int name_length; + + if (read_16bitBE(marker_offset,streamFile) == marker_id) + return read_32bitBE(marker_offset+2,streamFile); + + name_length = (uint8_t)read_8bit(marker_offset+6,streamFile) + 1; + if (name_length % 2) name_length++; + marker_offset += 6 + name_length; + } + + return -1; +} + +VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + off_t file_size = -1; + int channel_count = 0; + int sample_count = 0; + int sample_size = 0; + int sample_rate = 0; + int coding_type = -1; + off_t start_offset = -1; + int interleave = -1; + + int loop_flag = 0; + int32_t loop_start = -1; + int32_t loop_end = -1; + + int AIFFext = 0; + int AIFCext = 0; + int AIFF = 0; + int AIFC = 0; + int FormatVersionChunkFound = 0; + int CommonChunkFound = 0; + int SoundDataChunkFound = 0; + int MarkerChunkFound = 0; + off_t MarkerChunkOffset = -1; + int InstrumentChunkFound =0; + off_t InstrumentChunkOffset = -1; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (!strcasecmp("aifc",filename_extension(filename)) || + !strcasecmp("afc",filename_extension(filename)) || + !strcasecmp("aifcl",filename_extension(filename))) + { + AIFCext = 1; + } + else if (!strcasecmp("aiff",filename_extension(filename)) || + !strcasecmp("aif",filename_extension(filename)) || + !strcasecmp("aiffl",filename_extension(filename))) + { + AIFFext = 1; + } + else goto fail; + + /* check header */ + if ((uint32_t)read_32bitBE(0,streamFile)==0x464F524D && /* "FORM" */ + /* check that file = header (8) + data */ + (uint32_t)read_32bitBE(4,streamFile)+8==get_streamfile_size(streamFile)) + { + if ((uint32_t)read_32bitBE(8,streamFile)==0x41494643) /* "AIFC" */ + { + if (!AIFCext) goto fail; + AIFC = 1; + } + else if ((uint32_t)read_32bitBE(8,streamFile)==0x41494646) /* "AIFF" */ + { + if (!AIFFext) goto fail; + AIFF = 1; + } + else goto fail; + } else goto fail; + + file_size = get_streamfile_size(streamFile); + + /* read through chunks to verify format and find metadata */ + { + off_t current_chunk = 0xc; /* start with first chunk within FORM */ + + while (current_chunk < file_size) { + uint32_t chunk_type = read_32bitBE(current_chunk,streamFile); + off_t chunk_size = read_32bitBE(current_chunk+4,streamFile); + + /* chunks must be padded to an even number of bytes but chunk + * size does not include that padding */ + if (chunk_size % 2) chunk_size++; + + if (current_chunk+8+chunk_size > file_size) goto fail; + + switch(chunk_type) { + case 0x46564552: /* FVER */ + /* only one per file */ + if (FormatVersionChunkFound) goto fail; + /* plain AIFF shouldn't have */ + if (AIFF) goto fail; + FormatVersionChunkFound = 1; + + /* specific size */ + if (chunk_size != 4) goto fail; + + /* Version 1 of AIFF-C spec timestamp */ + if ((uint32_t)read_32bitBE(current_chunk+8,streamFile) != + 0xA2805140) goto fail; + break; + case 0x434F4D4D: /* COMM */ + /* only one per file */ + if (CommonChunkFound) goto fail; + CommonChunkFound = 1; + + channel_count = read_16bitBE(current_chunk+8,streamFile); + if (channel_count <= 0) goto fail; + + sample_count = (uint32_t)read_32bitBE(current_chunk+0xa,streamFile); + + sample_size = read_16bitBE(current_chunk+0xe,streamFile); + + sample_rate = read80bitSANE(current_chunk+0x10,streamFile); + + if (AIFC) { + switch (read_32bitBE(current_chunk+0x1a,streamFile)) { + case 0x53445832: /* SDX2 */ + coding_type = coding_SDX2; + interleave = 1; + break; + case 0x41445034: /* ADP4 */ + coding_type = coding_DVI_IMA; + /* don't know how stereo DVI is laid out */ + if (channel_count != 1) break; + break; + default: + /* we should probably support uncompressed here */ + goto fail; + } + } else if (AIFF) { + switch (sample_size) { + case 8: + coding_type = coding_PCM8; + interleave = 1; + break; + case 16: + coding_type = coding_PCM16BE; + interleave = 2; + break; + /* 32 is a possibility, but we don't see it and I + * don't have a reader for it yet */ + default: + goto fail; + } + } + + /* we don't check the human-readable portion of AIFF-C*/ + + break; + case 0x53534E44: /* SSND */ + /* at most one per file */ + if (SoundDataChunkFound) goto fail; + SoundDataChunkFound = 1; + + start_offset = current_chunk + 16 + read_32bitBE(current_chunk+8,streamFile); + break; + case 0x4D41524B: /* MARK */ + if (MarkerChunkFound) goto fail; + MarkerChunkFound = 1; + MarkerChunkOffset = current_chunk; + break; + case 0x494E5354: /* INST */ + if (InstrumentChunkFound) goto fail; + InstrumentChunkFound = 1; + InstrumentChunkOffset = current_chunk; + break; + default: + /* spec says we can skip unrecognized chunks */ + break; + } + + current_chunk += 8+chunk_size; + } + } + + if (AIFC) { + if (!FormatVersionChunkFound || !CommonChunkFound || !SoundDataChunkFound) + goto fail; + } else if (AIFF) { + if (!CommonChunkFound || !SoundDataChunkFound) + goto fail; + } + + /* read loop points */ + if (InstrumentChunkFound && MarkerChunkFound) { + int start_marker; + int end_marker; + /* use the sustain loop */ + /* if playMode=ForwardLooping */ + if (read_16bitBE(InstrumentChunkOffset+16,streamFile) == 1) { + start_marker = read_16bitBE(InstrumentChunkOffset+18,streamFile); + end_marker = read_16bitBE(InstrumentChunkOffset+20,streamFile); + /* check for sustain markers != 0 (invalid marker no) */ + if (start_marker && end_marker) { + /* find start marker */ + loop_start = find_marker(streamFile,MarkerChunkOffset,start_marker); + loop_end = find_marker(streamFile,MarkerChunkOffset,end_marker); + + /* find_marker is type uint32_t as the spec says that's the type + * of the position value, but it returns a -1 on error, and the + * loop_start and loop_end variables are int32_t, so the error + * will become apparent. + * We shouldn't have a loop point that overflows an int32_t + * anyway. */ + loop_flag = 1; + if (loop_start==loop_end) loop_flag = 0; + } + } + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = sample_count; + vgmstream->sample_rate = sample_rate; + + vgmstream->coding_type = coding_type; + if (channel_count > 1) + vgmstream->layout_type = layout_interleave; + else + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = interleave; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + + if (AIFC) + vgmstream->meta_type = meta_AIFC; + else if (AIFF) + vgmstream->meta_type = meta_AIFF; + + /* open the file, set up each channel */ + { + int i; + + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, + STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!vgmstream->ch[0].streamfile) goto fail; + + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile; + vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset = + start_offset+i*interleave; + } + } + + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/aix.c b/lib/vgmstream/src/meta/aix.c new file mode 100644 index 0000000000..cb545287b6 --- /dev/null +++ b/lib/vgmstream/src/meta/aix.c @@ -0,0 +1,410 @@ +#include "../vgmstream.h" +#include "meta.h" +#include "../util.h" + +typedef struct _AIXSTREAMFILE +{ + STREAMFILE sf; + STREAMFILE *real_file; + off_t start_physical_offset; + off_t current_physical_offset; + off_t current_logical_offset; + off_t current_block_size; + int stream_id; +} AIXSTREAMFILE; + +static STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file,off_t start_offset,int stream_id); + +VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamFileAIX = NULL; + STREAMFILE * streamFileADX = NULL; + char filename[260]; + off_t *segment_offset = NULL; + int32_t *samples_in_segment = NULL; + int32_t sample_count; + + int loop_flag = 0; + int32_t loop_start_sample=0; + int32_t loop_end_sample=0; + + aix_codec_data *data = NULL; + + off_t first_AIXP; + off_t stream_list_offset; + off_t stream_list_end; + + int stream_count,channel_count,segment_count; + int sample_rate; + + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("aix",filename_extension(filename))) goto fail; + + if (read_32bitBE(0x0,streamFile) != 0x41495846 || /* "AIXF" */ + read_32bitBE(0x08,streamFile) != 0x01000014 || + read_32bitBE(0x0c,streamFile) != 0x00000800) + goto fail; + + first_AIXP = read_32bitBE(0x4,streamFile)+8; + segment_count = (uint16_t)read_16bitBE(0x18,streamFile); + stream_list_offset = 0x20+0x10*segment_count+0x10; + + if (stream_list_offset >= first_AIXP) + goto fail; + if (segment_count < 1) + goto fail; + + sample_rate = read_32bitBE(stream_list_offset+8,streamFile); + if (!check_sample_rate(sample_rate)) + goto fail; + + samples_in_segment = calloc(segment_count,sizeof(int32_t)); + if (!samples_in_segment) + goto fail; + segment_offset = calloc(segment_count,sizeof(off_t)); + if (!segment_offset) + goto fail; + + for (i = 0; i < segment_count; i++) + { + segment_offset[i] = read_32bitBE(0x20+0x10*i+0,streamFile); + samples_in_segment[i] = read_32bitBE(0x20+0x10*i+0x08,streamFile); + /*printf("samples_in_segment[%d]=%d\n",i,samples_in_segment[i]);*/ + /* all segments must have equal samplerate */ + if (read_32bitBE(0x20+0x10*i+0x0c,streamFile) != sample_rate) + goto fail; + } + + if (segment_offset[0] != first_AIXP) + goto fail; + + stream_count = (uint8_t)read_8bit(stream_list_offset,streamFile); + if (stream_count < 1) + goto fail; + stream_list_end = stream_list_offset + 0x8 + stream_count * 8; + + if (stream_list_end >= first_AIXP) + goto fail; + + channel_count = 0; + for (i = 0; i < stream_count; i++) + { + /* all streams must have same samplerate as segments */ + if (read_32bitBE(stream_list_offset+8+i*8,streamFile)!=sample_rate) + goto fail; + channel_count += read_8bit(stream_list_offset+8+i*8+4,streamFile); + } + + /* check for existence of segments */ + for (i = 0; i < segment_count; i++) + { + int j; + off_t AIXP_offset = segment_offset[i]; + for (j = 0; j < stream_count; j++) + { + if (read_32bitBE(AIXP_offset,streamFile)!=0x41495850) /* "AIXP" */ + goto fail; + if (read_8bit(AIXP_offset+8,streamFile)!=j) + goto fail; + AIXP_offset += read_32bitBE(AIXP_offset+4,streamFile)+8; + } + } + + /*streamFileAIX = streamFile->open(streamFile,filename,sample_rate*0.0375*2/32*18segment_count);*/ + streamFileAIX = streamFile->open(streamFile,filename,sample_rate*0.1*segment_count); + if (!streamFileAIX) goto fail; + + data = malloc(sizeof(aix_codec_data)); + if (!data) goto fail; + data->segment_count = segment_count; + data->stream_count = stream_count; + data->adxs = malloc(sizeof(STREAMFILE *)*segment_count*stream_count); + if (!data->adxs) goto fail; + for (i=0;i<segment_count*stream_count;i++) { + data->adxs[i] = NULL; + } + data->sample_counts = calloc(segment_count,sizeof(int32_t)); + if (!data->sample_counts) goto fail; + memcpy(data->sample_counts,samples_in_segment,segment_count*sizeof(int32_t)); + + /* for each segment */ + for (i = 0; i < segment_count; i++) + { + int j; + /* for each stream */ + for (j = 0; j < stream_count; j++) + { + VGMSTREAM *adx; + /*printf("try opening segment %d/%d stream %d/%d %x\n",i,segment_count,j,stream_count,segment_offset[i]);*/ + streamFileADX = open_aix_with_STREAMFILE(streamFileAIX,segment_offset[i],j); + if (!streamFileADX) goto fail; + adx = data->adxs[i*stream_count+j] = init_vgmstream_adx(streamFileADX); + if (!adx) + goto fail; + close_streamfile(streamFileADX); streamFileADX = NULL; + + if (adx->num_samples != data->sample_counts[i] || + adx->loop_flag != 0) + goto fail; + + /* save start things so we can restart for seeking/looping */ + /* copy the channels */ + memcpy(adx->start_ch,adx->ch,sizeof(VGMSTREAMCHANNEL)*adx->channels); + /* copy the whole VGMSTREAM */ + memcpy(adx->start_vgmstream,adx,sizeof(VGMSTREAM)); + + } + } + + if (segment_count > 1) + { + loop_flag = 1; + } + + sample_count = 0; + for (i = 0; i < segment_count; i++) + { + sample_count += data->sample_counts[i]; + + if (i == 0) + loop_start_sample = sample_count; + if (i == 1) + loop_end_sample = sample_count; + } + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + + vgmstream->num_samples = sample_count; + vgmstream->sample_rate = sample_rate; + + vgmstream->loop_start_sample = loop_start_sample; + vgmstream->loop_end_sample = loop_end_sample; + + vgmstream->coding_type = data->adxs[0]->coding_type; + vgmstream->layout_type = layout_aix; + vgmstream->meta_type = meta_AIX; + + vgmstream->ch[0].streamfile = streamFileAIX; + data->current_segment = 0; + + vgmstream->codec_data = data; + free(segment_offset); + free(samples_in_segment); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (streamFileAIX) close_streamfile(streamFileAIX); + if (streamFileADX) close_streamfile(streamFileADX); + if (vgmstream) close_vgmstream(vgmstream); + if (samples_in_segment) free(samples_in_segment); + if (segment_offset) free(segment_offset); + if (data) { + if (data->adxs) + { + int i; + for (i=0;i<data->segment_count*data->stream_count;i++) + if (data->adxs) + close_vgmstream(data->adxs[i]); + free(data->adxs); + } + if (data->sample_counts) + { + free(data->sample_counts); + } + free(data); + } + return NULL; +} +static size_t read_aix(AIXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length) +{ + size_t sz = 0; + + /*printf("trying to read %x bytes from %x (str%d)\n",length,offset,streamfile->stream_id);*/ + while (length > 0) + { + int read_something = 0; + + /* read the beginning of the requested block, if we can */ + if (offset >= streamfile->current_logical_offset) + { + off_t to_read; + off_t length_available; + + length_available = + (streamfile->current_logical_offset+ + streamfile->current_block_size) - + offset; + + if (length < length_available) + { + to_read = length; + } + else + { + to_read = length_available; + } + + if (to_read > 0) + { + size_t bytes_read; + + bytes_read = read_streamfile(dest, + streamfile->current_physical_offset+0x10+ + (offset-streamfile->current_logical_offset), + to_read,streamfile->real_file); + + sz += bytes_read; + if (bytes_read != to_read) + { + /* an error which we will not attempt to handle here */ + return sz; + } + + read_something = 1; + + dest += bytes_read; + offset += bytes_read; + length -= bytes_read; + } + } + + if (!read_something) + { + /* couldn't read anything, must seek */ + int found_block = 0; + + /* as we have no memory we must start seeking from the beginning */ + if (offset < streamfile->current_logical_offset) + { + streamfile->current_logical_offset = 0; + streamfile->current_block_size = 0; + streamfile->current_physical_offset = + streamfile->start_physical_offset; + } + + /* seek ye forwards */ + while (!found_block) { + /*printf("seek looks at %x\n",streamfile->current_physical_offset);*/ + switch (read_32bitBE(streamfile->current_physical_offset, + streamfile->real_file)) + { + case 0x41495850: /* AIXP */ + if (read_8bit( + streamfile->current_physical_offset+8, + streamfile->real_file) == + streamfile->stream_id) + { + streamfile->current_block_size = + (uint16_t)read_16bitBE( + streamfile->current_physical_offset+0x0a, + streamfile->real_file); + + if (offset >= streamfile->current_logical_offset+ + streamfile->current_block_size) + { + streamfile->current_logical_offset += + streamfile->current_block_size; + } + else + { + found_block = 1; + } + } + + if (!found_block) + { + streamfile->current_physical_offset += + read_32bitBE( + streamfile->current_physical_offset+0x04, + streamfile->real_file + ) + 8; + } + + break; + case 0x41495846: /* AIXF */ + /* shouldn't ever see this */ + case 0x41495845: /* AIXE */ + /* shouldn't have reached the end o' the line... */ + default: + return sz; + break; + } /* end block/chunk type select */ + } /* end while !found_block */ + } /* end if !read_something */ + } /* end while length > 0 */ + + return sz; +} + +static void close_aix(AIXSTREAMFILE *streamfile) +{ + free(streamfile); + return; +} + +static size_t get_size_aix(AIXSTREAMFILE *streamfile) +{ + return 0; +} + +static size_t get_offset_aix(AIXSTREAMFILE *streamfile) +{ + return streamfile->current_logical_offset; +} + +static void get_name_aix(AIXSTREAMFILE *streamfile,char *buffer,size_t length) +{ + strncpy(buffer,"ARBITRARY.ADX",length); + buffer[length-1]='\0'; +} + +static STREAMFILE *open_aix_impl(AIXSTREAMFILE *streamfile,const char * const filename,size_t buffersize) +{ + AIXSTREAMFILE *newfile; + if (strcmp(filename,"ARBITRARY.ADX")) + return NULL; + + newfile = malloc(sizeof(AIXSTREAMFILE)); + if (!newfile) + return NULL; + memcpy(newfile,streamfile,sizeof(AIXSTREAMFILE)); + return &newfile->sf; +} + +static STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file,off_t start_offset,int stream_id) +{ + AIXSTREAMFILE *streamfile = malloc(sizeof(AIXSTREAMFILE)); + + if (!streamfile) + return NULL; + + /* success, set our pointers */ + + streamfile->sf.read = (void*)read_aix; + streamfile->sf.get_size = (void*)get_size_aix; + streamfile->sf.get_offset = (void*)get_offset_aix; + streamfile->sf.get_name = (void*)get_name_aix; + streamfile->sf.get_realname = (void*)get_name_aix; + streamfile->sf.open = (void*)open_aix_impl; + streamfile->sf.close = (void*)close_aix; +#ifdef PROFILE_STREAMFILE + streamfile->sf.get_bytes_read = NULL; + streamfile->sf.get_error_count = NULL; +#endif + + streamfile->real_file = file; + streamfile->current_physical_offset = + streamfile->start_physical_offset = start_offset; + streamfile->current_logical_offset = 0; + streamfile->current_block_size = 0; + streamfile->stream_id = stream_id; + + return &streamfile->sf; +} + diff --git a/lib/vgmstream/src/meta/ast.c b/lib/vgmstream/src/meta/ast.c new file mode 100644 index 0000000000..ffcf80675f --- /dev/null +++ b/lib/vgmstream/src/meta/ast.c @@ -0,0 +1,91 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + coding_t coding_type; + + int codec_number; + int channel_count; + int loop_flag; + + size_t max_block; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ast",filename_extension(filename))) goto fail; + + /* check header */ + if ((uint32_t)read_32bitBE(0,streamFile)!=0x5354524D || /* "STRM" */ + read_16bitBE(0xa,streamFile)!=0x10 || + /* check that file = header (0x40) + data */ + read_32bitBE(4,streamFile)+0x40!=get_streamfile_size(streamFile)) + goto fail; + + /* check for a first block */ + if (read_32bitBE(0x40,streamFile)!=0x424C434B) /* "BLCK" */ + goto fail; + + /* check type details */ + codec_number = read_16bitBE(8,streamFile); + loop_flag = read_16bitBE(0xe,streamFile); + channel_count = read_16bitBE(0xc,streamFile); + max_block = read_32bitBE(0x20,streamFile); + + switch (codec_number) { + case 0: + coding_type = coding_NGC_AFC; + break; + case 1: + coding_type = coding_PCM16BE; + break; + default: + goto fail; + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = read_32bitBE(0x14,streamFile); + vgmstream->sample_rate = read_32bitBE(0x10,streamFile); + /* channels and loop flag are set by allocate_vgmstream */ + vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile); + vgmstream->loop_end_sample = read_32bitBE(0x1c,streamFile); + + vgmstream->coding_type = coding_type; + vgmstream->layout_type = layout_ast_blocked; + vgmstream->meta_type = meta_AST; + + /* 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, + (i==0? + max_block+0x20-4: /* first buffer a bit bigger to + read block header without + inefficiency */ + max_block + ) + ); + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + /* start me up */ + ast_block_update(0x40,vgmstream); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/bgw.c b/lib/vgmstream/src/meta/bgw.c new file mode 100644 index 0000000000..4bc0b19823 --- /dev/null +++ b/lib/vgmstream/src/meta/bgw.c @@ -0,0 +1,140 @@ +#include "meta.h" +#include "../util.h" + +/* BGW (FF XI) */ +VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int32_t loop_start; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("bgw",filename_extension(filename))) goto fail; + + /* "BGMStream" */ + if (read_32bitBE(0,streamFile) != 0x42474d53 || + read_32bitBE(4,streamFile) != 0x74726561 || + read_32bitBE(8,streamFile) != 0x6d000000 || + read_32bitBE(12,streamFile) != 0) goto fail; + + /* check file size with header value */ + if (read_32bitLE(0x10,streamFile) != get_streamfile_size(streamFile)) + goto fail; + + channel_count = read_8bit(0x2e,streamFile); + loop_start = read_32bitLE(0x1c,streamFile); + loop_flag = (loop_start > 0); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x28,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = 44100; + vgmstream->coding_type = coding_FFXI; + vgmstream->num_samples = read_32bitLE(0x18,streamFile)*16; + if (loop_flag) { + vgmstream->loop_start_sample = (loop_start-1)*16; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 9; + vgmstream->meta_type = meta_FFXI_BGW; + + /* 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+i*9; + + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +/* .spw (SEWave, PlayOnline viewer for FFXI), very similar to bgw */ +VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int32_t loop_start; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("spw",filename_extension(filename))) goto fail; + + /* "SeWave" */ + if (read_32bitBE(0,streamFile) != 0x53655761 || + read_32bitBE(4,streamFile) != 0x76650000) goto fail; + + /* check file size with header value */ + if (read_32bitLE(0x8,streamFile) != get_streamfile_size(streamFile)) + goto fail; + + channel_count = read_8bit(0x2a,streamFile); + loop_start = read_32bitLE(0x18,streamFile); + loop_flag = (loop_start > 0); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x24,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = 44100; + vgmstream->coding_type = coding_FFXI; + vgmstream->num_samples = read_32bitLE(0x14,streamFile)*16; + if (loop_flag) { + vgmstream->loop_start_sample = (loop_start-1)*16; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 9; + vgmstream->meta_type = meta_FFXI_SPW; + + /* 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+i*9; + + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/brstm.c b/lib/vgmstream/src/meta/brstm.c new file mode 100644 index 0000000000..168e7b7ac2 --- /dev/null +++ b/lib/vgmstream/src/meta/brstm.c @@ -0,0 +1,163 @@ +#include "meta.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_brstm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + coding_t coding_type; + + off_t head_offset; + int codec_number; + int channel_count; + int loop_flag; + /* Certain Super Paper Mario tracks have a 44.1KHz sample rate in the + * header, but they should be played at 22.05KHz. We will make this + * correction if we see a file with a .brstmspm extension. */ + int spm_flag = 0; + /* Trauma Center Second Opinion has an odd, semi-corrupt header */ + int atlus_shrunken_head = 0; + + off_t start_offset; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("brstm",filename_extension(filename))) { + if (strcasecmp("brstmspm",filename_extension(filename))) goto fail; + else spm_flag = 1; + } + + /* check header */ + if ((uint32_t)read_32bitBE(0,streamFile)!=0x5253544D) /* "RSTM" */ + goto fail; + if ((uint32_t)read_32bitBE(4,streamFile)!=0xFEFF0100) + { + if ((uint32_t)read_32bitBE(4,streamFile)!=0xFEFF0001) + goto fail; + else + atlus_shrunken_head = 1; + } + + /* get head offset, check */ + head_offset = read_32bitBE(0x10,streamFile); + if (atlus_shrunken_head) + { + /* the HEAD chunk is where we would expect to find the offset of that + * chunk... */ + + if ((uint32_t)head_offset!=0x48454144 || read_32bitBE(0x14,streamFile) != 8) + goto fail; + + head_offset = -8; /* most of the normal Nintendo RSTM offsets work + with this assumption */ + } + else + { + if ((uint32_t)read_32bitBE(head_offset,streamFile)!=0x48454144) /* "HEAD" */ + goto fail; + } + + /* check type details */ + codec_number = read_8bit(head_offset+0x20,streamFile); + loop_flag = read_8bit(head_offset+0x21,streamFile); + channel_count = read_8bit(head_offset+0x22,streamFile); + + switch (codec_number) { + case 0: + coding_type = coding_PCM8; + break; + case 1: + coding_type = coding_PCM16BE; + break; + case 2: + coding_type = coding_NGC_DSP; + break; + default: + goto fail; + } + + if (channel_count < 1) goto fail; + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = read_32bitBE(head_offset+0x2c,streamFile); + vgmstream->sample_rate = (uint16_t)read_16bitBE(head_offset+0x24,streamFile); + /* channels and loop flag are set by allocate_vgmstream */ + vgmstream->loop_start_sample = read_32bitBE(head_offset+0x28,streamFile); + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_type; + if (channel_count==1) + vgmstream->layout_type = layout_none; + else + vgmstream->layout_type = layout_interleave_shortblock; + vgmstream->meta_type = meta_RSTM; + if (atlus_shrunken_head) + vgmstream->meta_type = meta_RSTM_shrunken; + + if (spm_flag&& vgmstream->sample_rate == 44100) { + vgmstream->meta_type = meta_RSTM_SPM; + vgmstream->sample_rate = 22050; + } + + vgmstream->interleave_block_size = read_32bitBE(head_offset+0x38,streamFile); + vgmstream->interleave_smallblock_size = read_32bitBE(head_offset+0x48,streamFile); + + if (vgmstream->coding_type == coding_NGC_DSP) { + off_t coef_offset; + off_t coef_offset1; + off_t coef_offset2; + int i,j; + int coef_spacing = 0x38; + + if (atlus_shrunken_head) + { + coef_offset = 0x50; + coef_spacing = 0x30; + } + else + { + coef_offset1=read_32bitBE(head_offset+0x1c,streamFile); + coef_offset2=read_32bitBE(head_offset+0x10+coef_offset1,streamFile); + coef_offset=coef_offset2+0x10; + } + + for (j=0;j<vgmstream->channels;j++) { + for (i=0;i<16;i++) { + vgmstream->ch[j].adpcm_coef[i]=read_16bitBE(head_offset+coef_offset+j*coef_spacing+i*2,streamFile); + } + } + } + + start_offset = read_32bitBE(head_offset+0x30,streamFile); + + /* open the file for reading by each channel */ + { + int i; + for (i=0;i<channel_count;i++) { + if (vgmstream->layout_type==layout_interleave_shortblock) + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename, + vgmstream->interleave_block_size); + else + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename, + 0x1000); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + start_offset + i*vgmstream->interleave_block_size; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/capdsp.c b/lib/vgmstream/src/meta/capdsp.c new file mode 100644 index 0000000000..02d97d1d74 --- /dev/null +++ b/lib/vgmstream/src/meta/capdsp.c @@ -0,0 +1,71 @@ +#include "meta.h" +#include "../util.h" + +/* CAPDSP (found in Capcom games) */ +VGMSTREAM * init_vgmstream_capdsp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("capdsp",filename_extension(filename))) goto fail; + + loop_flag = (read_32bitBE(0x14,streamFile) !=2); + channel_count = read_32bitBE(0x10,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x80; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x0C,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitBE(0x04,streamFile); + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile)/8/channel_count*14; + vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile)/8/channel_count*14; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2000; + vgmstream->meta_type = meta_CAPDSP; + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<8;i++) { + vgmstream->ch[0].adpcm_coef[i*2]=read_16bitBE(0x20+i*2,streamFile); + vgmstream->ch[0].adpcm_coef[i*2+1]=read_16bitBE(0x30+i*2,streamFile); + vgmstream->ch[1].adpcm_coef[i*2]=read_16bitBE(0x40+i*2,streamFile); + vgmstream->ch[1].adpcm_coef[i*2+1]=read_16bitBE(0x50+i*2,streamFile); + } + } + + /* 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; +} diff --git a/lib/vgmstream/src/meta/dc_asd.c b/lib/vgmstream/src/meta/dc_asd.c new file mode 100644 index 0000000000..aae03096e7 --- /dev/null +++ b/lib/vgmstream/src/meta/dc_asd.c @@ -0,0 +1,75 @@ +#include "meta.h" +#include "../util.h" + +/* ASD - found in Miss Moonlight (DC) */ +VGMSTREAM * init_vgmstream_dc_asd(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("asd",filename_extension(filename))) goto fail; + + /* We have no "Magic" words in this header format, so we have to do some, + other checks, it seems the samplecount is stored twice in the header, + we'll compare it... */ + if (read_32bitLE(0x0,streamFile) != read_32bitLE(0x4,streamFile)) + goto fail; + /* compare the frequency with the bitrate, if it doesn't match we'll close + the vgmstream... */ + if (read_32bitLE(0x10,streamFile)/read_32bitLE(0xC,streamFile) != (uint16_t)read_16bitLE(0xA,streamFile)*2) + goto fail; + + loop_flag = 0; + channel_count = read_16bitLE(0x0A,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = get_streamfile_size(streamFile) - read_32bitLE(0x0,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x0C,streamFile); + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = read_32bitLE(0x0,streamFile)/2/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x0,streamFile)/2/channel_count; + } + + vgmstream->meta_type = meta_DC_ASD; + + if (vgmstream->channels == 1) { + vgmstream->layout_type = layout_none; + } else if (vgmstream->channels == 2) { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + } + + /* 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; +} diff --git a/lib/vgmstream/src/meta/dc_idvi.c b/lib/vgmstream/src/meta/dc_idvi.c new file mode 100644 index 0000000000..7473fdb7d9 --- /dev/null +++ b/lib/vgmstream/src/meta/dc_idvi.c @@ -0,0 +1,71 @@ +#include "meta.h" +#include "../util.h" + +/* IDVI (Eldorado Gate Volume 1-7) */ +VGMSTREAM * init_vgmstream_dc_idvi(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("idvi",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x49445649) /* "IDVI." */ + goto fail; + + loop_flag = read_32bitLE(0x0C,streamFile); + channel_count = read_32bitLE(0x04,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + start_offset = 0x800; + vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + vgmstream->coding_type = coding_INT_DVI_IMA; + vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset); + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x0C,streamFile); + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset); + } + vgmstream->meta_type = meta_DC_IDVI; + + /* Calculating the short block... */ + if (channel_count > 1) { + vgmstream->interleave_block_size = 0x400; + vgmstream->interleave_smallblock_size = ((get_streamfile_size(streamFile)-start_offset)%(vgmstream->channels*vgmstream->interleave_block_size))/vgmstream->channels; + vgmstream->layout_type = layout_interleave_shortblock; + } else { + vgmstream->layout_type = layout_none; + } + + /* 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; +} diff --git a/lib/vgmstream/src/meta/dc_kcey.c b/lib/vgmstream/src/meta/dc_kcey.c new file mode 100644 index 0000000000..7fbf5584d8 --- /dev/null +++ b/lib/vgmstream/src/meta/dc_kcey.c @@ -0,0 +1,66 @@ +#include "meta.h" +#include "../coding/coding.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_kcey(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("kcey",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x4B434559) /* "DVI." */ + goto fail; + + loop_flag = (read_32bitBE(0x14,streamFile)!=0xFFFFFFFF); + channel_count = read_32bitBE(0x08,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + start_offset = read_32bitBE(0x10,streamFile); + vgmstream->sample_rate = 37800; + vgmstream->coding_type = coding_EACS_IMA; + + vgmstream->num_samples = read_32bitBE(0x0C,streamFile); + + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile); + vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile); + } + + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_KCEY; + vgmstream->get_high_nibble=1; + + /* 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+(i*vgmstream->interleave_block_size); + vgmstream->ch[i].adpcm_history1_32=0; + vgmstream->ch[i].adpcm_step_index=0; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/dc_str.c b/lib/vgmstream/src/meta/dc_str.c new file mode 100644 index 0000000000..071dcbb380 --- /dev/null +++ b/lib/vgmstream/src/meta/dc_str.c @@ -0,0 +1,165 @@ +#include "meta.h" +#include "../coding/coding.h" +#include "../util.h" + +/* SEGA Stream Asset Builder... + this meta handles only V1 and V3... */ + +VGMSTREAM * init_vgmstream_dc_str(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int interleave; + int channel_count; + int samples; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("str",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0xD5,streamFile) != 0x53656761) /* "Sega" */ + goto fail; + + interleave = read_32bitLE(0xC,streamFile); + if ((get_streamfile_size(streamFile)-0x800) != (read_32bitLE(0x10,streamFile) * + ((read_32bitLE(0x0,streamFile)*(read_32bitLE(0x18,streamFile))))*interleave)) + goto fail; + + + loop_flag = 0; /* (read_32bitLE(0x00,streamFile)!=0x00000000); */ + samples = read_32bitLE(0x08,streamFile); + channel_count = (read_32bitLE(0x0,streamFile))*(read_32bitLE(0x18,streamFile)); + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + + /* fill in the vital statistics */ + switch (samples) { + case 4: + vgmstream->coding_type = coding_AICA; + vgmstream->num_samples = read_32bitLE(0x14,streamFile); + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile); + } + break; + case 16: + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = read_32bitLE(0x14,streamFile)/2/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile)/2/channel_count; + } + break; + default: + goto fail; +} + + + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + + if (vgmstream->channels == 1) { + vgmstream->layout_type = layout_none; + } else if (vgmstream->channels > 1) { + vgmstream->interleave_block_size = interleave; + vgmstream->layout_type = layout_interleave; + } + + vgmstream->meta_type = meta_DC_STR; + + /* 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; +} + +/* This handles V2, not sure if it is really V2, cause the header is always + the same, not like in V1 and V3, only found in "102 Dalmatians - Puppies to the Rescue" + until now... */ + +VGMSTREAM * init_vgmstream_dc_str_v2(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("str",filename_extension(filename))) goto fail; +#if 0 + /* check header */ + if ((read_32bitBE(0x00,streamFile) != 0x00000002) && + (read_32bitBE(0x10,streamFile) != 0x00000100) && + (read_32bitBE(0x1C,streamFile) != 0x1F000000)) + goto fail; +#endif + + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x4,streamFile); + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0xC,streamFile); + vgmstream->meta_type = meta_DC_STR_V2; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/dc_wav_dcs.c b/lib/vgmstream/src/meta/dc_wav_dcs.c new file mode 100644 index 0000000000..654042716f --- /dev/null +++ b/lib/vgmstream/src/meta/dc_wav_dcs.c @@ -0,0 +1,116 @@ +#include "meta.h" +#include "../util.h" + +/* WAV+DCS +2008-12-06 - manakoAT : Evil Twin - Cypriens Chronicles... +2008-12-07 - manakoAT : Added a function to read the Header file and for + retrieving the channels/frequency, Frequency starts + always at a "data" chunk - 0x0C bytes, Channels + always - 0x0E bytes... */ + +VGMSTREAM * init_vgmstream_dc_wav_dcs(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamFileWAV = NULL; + char filename[260]; + char filenameWAV[260]; + int i; + int channel_count; + int loop_flag; + int frequency; + int dataBuffer = 0; + int Founddata = 0; + size_t file_size; + off_t current_chunk; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("dcs",filename_extension(filename))) goto fail; + + /* Getting the Header file name... */ + strcpy(filenameWAV,filename); + strcpy(filenameWAV+strlen(filenameWAV)-3,"wav"); + + /* Look if the Header file is present, else cancel vgmstream */ + streamFileWAV = streamFile->open(streamFile,filenameWAV,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!streamFileWAV) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFileWAV) != 0x52494646 || /* "RIFF" */ + read_32bitBE(0x08,streamFileWAV) != 0x57415645 || /* "WAVE" */ + read_32bitBE(0x0C,streamFileWAV) != 0x34582E76 || /* 0x34582E76 */ + read_32bitBE(0x3C,streamFileWAV) != 0x406E616D) /* "@nam" */ + goto fail; + + /* scan file until we find a "data" string */ + file_size = get_streamfile_size(streamFileWAV); + { + current_chunk = 0; + /* Start at 0 and loop until we reached the + file size, or until we found a "data string */ + while (!Founddata && current_chunk < file_size) { + dataBuffer = (read_32bitBE(current_chunk,streamFileWAV)); + if (dataBuffer == 0x64617461) { /* "data" */ + /* if "data" string found, retrieve the needed infos */ + Founddata = 1; + /* We will cancel the search here if we have a match */ + break; + } + /* else we will increase the search offset by 1 */ + current_chunk = current_chunk + 1; + } + } + + if (Founddata == 0) { + goto fail; + } else if (Founddata == 1) { + channel_count = (uint16_t)read_16bitLE(current_chunk-0x0E,streamFileWAV); + frequency = read_32bitLE(current_chunk-0x0C,streamFileWAV); + } + + loop_flag = 0; + + /* Seems we're dealing with a vaild file+header, + now we can finally build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = frequency; + vgmstream->num_samples=(get_streamfile_size(streamFile))*2/channel_count; + + if(loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile))*2/channel_count; + } + + if (channel_count == 1) { + vgmstream->layout_type = layout_none; + } else if (channel_count > 1) { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x4000; + } + + vgmstream->coding_type = coding_AICA; + vgmstream->meta_type = meta_DC_WAV_DCS; + + /* open the file for reading */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + vgmstream->ch[i].offset = 0; + vgmstream->ch[i].adpcm_step_index = 0x7f; /* AICA */ + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + close_streamfile(streamFileWAV); streamFileWAV=NULL; + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (streamFileWAV) close_streamfile(streamFileWAV); + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/de2.c b/lib/vgmstream/src/meta/de2.c new file mode 100644 index 0000000000..f1b051eb06 --- /dev/null +++ b/lib/vgmstream/src/meta/de2.c @@ -0,0 +1,101 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* Gurumin .de2 */ +/* A ways into the file we have a fake RIFF header wrapping MS ADPCM */ + +VGMSTREAM * init_vgmstream_de2(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + off_t riff_off; + int channel_count; + int sample_count; + int sample_rate; + off_t start_offset; + + int loop_flag = 0; + uint32_t data_size; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("de2",filename_extension(filename))) goto fail; + + /* still not sure what this is for, but consistently 0xb */ + if (read_32bitLE(0x04,streamFile)!=0xb) goto fail; + + /* legitimate! really! */ + riff_off = 0x10 + + (read_32bitLE(0x0c,streamFile) ^ read_32bitLE(0x04,streamFile)); + + /* check header */ + if ((uint32_t)read_32bitBE(riff_off+0,streamFile)!=0x52494646) /* "RIFF" */ + goto fail; + /* check for WAVE form */ + if ((uint32_t)read_32bitBE(riff_off+8,streamFile)!=0x57415645) /* "WAVE" */ + goto fail; + /* check for "fmt " */ + if ((uint32_t)read_32bitBE(riff_off+12,streamFile)!=0x666d7420) /* "fmt " */ + goto fail; + /* check for "data" */ + if ((uint32_t)read_32bitBE(riff_off+0x24,streamFile)!=0x64617461) /* "data" */ + goto fail; + /* check for bad fmt chunk size */ + if (read_32bitLE(riff_off+0x10,streamFile)!=0x12) goto fail; + + sample_rate = read_32bitLE(riff_off+0x18,streamFile); + + channel_count = read_16bitLE(riff_off+0x16,streamFile); + if (channel_count != 2) goto fail; + + /* PCM */ + if (read_16bitLE(riff_off+0x14,streamFile) != 1) goto fail; + + /* 16-bit */ + if (read_16bitLE(riff_off+0x20,streamFile) != 4 || + read_16bitLE(riff_off+0x22,streamFile) != 16) goto fail; + + start_offset = riff_off + 0x2c; + data_size = read_32bitLE(riff_off+0x28,streamFile); + + sample_count = data_size/2/channel_count; + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = sample_count; + vgmstream->sample_rate = sample_rate; + + vgmstream->coding_type = coding_MSADPCM; + vgmstream->layout_type = layout_de2_blocked; + vgmstream->interleave_block_size = 0x800; + + vgmstream->meta_type = meta_DE2; + + /* open the file, set up each channel */ + { + int i; + + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, + STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!vgmstream->ch[0].streamfile) goto fail; + + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile; + } + } + + /* start me up */ + de2_block_update(start_offset,vgmstream); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ea_header.c b/lib/vgmstream/src/meta/ea_header.c new file mode 100644 index 0000000000..c9192134b1 --- /dev/null +++ b/lib/vgmstream/src/meta/ea_header.c @@ -0,0 +1,293 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../coding/coding.h" +#include "../util.h" + +// Platform constants +#define EA_PC 0x00 +#define EA_PSX 0x01 +#define EA_PS2 0x05 +#define EA_GC 0x06 +#define EA_XBOX 0x07 +#define EA_X360 0x09 + +// Compression Version +#define EAXA_R1 0x01 +#define EAXA_R2 0x02 +#define EAXA_R3 0x03 + +// Compression Type +#define EA_VAG 0x01 +#define EA_EAXA 0x0A +#define EA_ADPCM 0x30 +#define EA_PCM_BE 0x07 +#define EA_PCM_LE 0x08 +#define EA_IMA 0x14 + +typedef struct { + int32_t num_samples; + int32_t sample_rate; + uint8_t channels; + uint8_t platform; + int32_t interleave; + uint8_t compression_type; + uint8_t compression_version; +} EA_STRUCT; + +uint32_t readPatch(STREAMFILE* streamFile, off_t* offset) { + + uint32_t result=0; + uint8_t byteCount; + + byteCount = read_8bit(*offset,streamFile); + (*offset)++; + + for(;byteCount>0;byteCount--) { + result <<=8; + result+=(uint8_t)read_8bit(*offset,streamFile); + (*offset)++; + } + return result; +} + +void Parse_Header(STREAMFILE* streamFile,EA_STRUCT* ea, off_t offset, int length) { + + uint8_t byteRead; + off_t begin_offset=offset; + + // default value ... + ea->channels=1; + ea->compression_type=0; + ea->compression_version=0x01; + ea->platform=EA_GC; + + if(read_32bitBE(offset, streamFile)==0x47535452) { // GSTR + ea->compression_version=0x03; + offset+=8; + ea->platform=6; + } else { + if(read_16bitBE(offset,streamFile)!=0x5054) // PT + offset+=4; + + ea->platform=(uint8_t)read_16bitLE(offset+2,streamFile); + offset+=4; + } + + do { + byteRead = read_8bit(offset++,streamFile); + + switch(byteRead) { + case 0xFF: + case 0xFE: + case 0xFC: + case 0xFD: + break; + case 0x80: // compression version + ea->compression_version = (uint8_t)readPatch(streamFile, &offset); + break; + case 0x82: // channels count + ea->channels = (uint8_t)readPatch(streamFile, &offset); + break; + case 0x83: // compression type + ea->compression_type = (uint8_t)readPatch(streamFile, &offset); + if(ea->compression_type==0x07) ea->compression_type=0x30; + break; + case 0x84: // sample frequency + ea->sample_rate = readPatch(streamFile,&offset); + break; + case 0x85: // samples count + ea->num_samples = readPatch(streamFile, &offset); + break; + case 0x8A: + offset+=4; + if(ea->compression_type==0) ea->compression_type=EA_PCM_LE; + break; + case 0x86: + case 0x87: + case 0x8C: + case 0x92: + case 0x9C: + case 0x9D: // unknown patch + readPatch(streamFile, &offset); + break; + case 0x88: // interleave + ea->interleave = readPatch(streamFile, &offset); + break; + case 0xA0: // compression type + ea->compression_type = (uint8_t)readPatch(streamFile, &offset); + break; + } + } while(offset-begin_offset<length); + + if(ea->platform==EA_PSX) + ea->compression_type=EA_VAG; + if(ea->compression_type==0) + ea->compression_type=EA_EAXA; +} + +VGMSTREAM * init_vgmstream_ea(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + EA_STRUCT ea; + char filename[260]; + + int loop_flag=0; + int channel_count; + int header_length; + off_t start_offset; + int i; + + memset(&ea,0,sizeof(EA_STRUCT)); + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sng",filename_extension(filename)) && + strcasecmp("asf",filename_extension(filename)) && + strcasecmp("str",filename_extension(filename)) && + strcasecmp("xsf",filename_extension(filename)) && + strcasecmp("eam",filename_extension(filename))) goto fail; + + /* check Header */ + if (read_32bitBE(0x00,streamFile) != 0x5343486C) // SCHl + goto fail; + + header_length = read_32bitLE(0x04,streamFile); + start_offset=8; + + if(header_length>0x100) goto fail; + + Parse_Header(streamFile,&ea,start_offset,header_length-8); + + /* unknown loop value for the moment */ + loop_flag = 0; + + channel_count=ea.channels; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->ea_platform=ea.platform; + + vgmstream->ea_compression_type=ea.compression_type; + vgmstream->ea_compression_version=ea.compression_version; + + // Set defaut sample rate if not define in the header + if(ea.sample_rate!=0) { + vgmstream->sample_rate = ea.sample_rate; + } else { + if(read_32bitBE(0x08,streamFile)==0x47535452) { // GSTR + vgmstream->sample_rate=44100; + } else { + switch(vgmstream->ea_platform) { + case EA_XBOX: + vgmstream->sample_rate=24000; + break; + case EA_X360: + vgmstream->sample_rate=44100; + break; + default: + vgmstream->sample_rate=22050; + } + } + } + + // Set default compression scheme if not define in the header + switch(vgmstream->ea_platform) { + case EA_X360: + vgmstream->ea_compression_version=0x03; + break; + } + + vgmstream->num_samples=ea.num_samples; + + switch(vgmstream->ea_compression_type) { + case EA_EAXA: + if(vgmstream->ea_compression_version==0x03) + vgmstream->meta_type=meta_EAXA_R3; + else { + // seems there's no EAXA R2 on PC + if(ea.platform==EA_PC) { + vgmstream->ea_compression_version=0x03; + vgmstream->meta_type=meta_EAXA_R3; + } else + vgmstream->meta_type=meta_EAXA_R2; + } + + vgmstream->coding_type=coding_EAXA; + vgmstream->layout_type=layout_ea_blocked; + if((vgmstream->ea_platform==EA_GC) || (vgmstream->ea_platform==EA_X360)) + vgmstream->ea_big_endian=1; + + break; + case EA_VAG: + vgmstream->meta_type=meta_EAXA_PSX; + vgmstream->coding_type=coding_PSX; + vgmstream->layout_type=layout_ea_blocked; + break; + case EA_PCM_LE: + vgmstream->meta_type=meta_EA_PCM; + vgmstream->coding_type=coding_PCM16LE_int; + vgmstream->layout_type=layout_ea_blocked; + break; + case EA_ADPCM: + vgmstream->meta_type=meta_EA_ADPCM; + vgmstream->coding_type=coding_EA_ADPCM; + vgmstream->layout_type=layout_ea_blocked; + break; + case EA_IMA: + vgmstream->meta_type=meta_EA_IMA; + vgmstream->coding_type=coding_XBOX; + vgmstream->layout_type=layout_ea_blocked; + break; + } + + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + + // Special function for .EAM files ... + if(!strcasecmp("eam",filename_extension(filename))) { + + size_t file_length=get_streamfile_size(streamFile); + size_t block_length; + + vgmstream->next_block_offset=start_offset+header_length; + vgmstream->num_samples=0; + + // to initialize the block length + ea_block_update(start_offset+header_length,vgmstream); + block_length=vgmstream->next_block_offset-start_offset+header_length; + + do { + ea_block_update(vgmstream->next_block_offset,vgmstream); + if(vgmstream->coding_type==coding_PSX) + vgmstream->num_samples+=(int32_t)vgmstream->current_block_size/16*28; + else if (vgmstream->coding_type==coding_EA_ADPCM) + vgmstream->num_samples+=(int32_t)vgmstream->current_block_size; + else if (vgmstream->coding_type==coding_PCM16LE_int) + vgmstream->num_samples+=(int32_t)vgmstream->current_block_size/vgmstream->channels; + else + vgmstream->num_samples+=(int32_t)vgmstream->current_block_size*28; + } while(vgmstream->next_block_offset<(off_t)(file_length-block_length)); + } + + ea_block_update(start_offset+header_length,vgmstream); + + init_get_high_nibble(vgmstream); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ea_old.c b/lib/vgmstream/src/meta/ea_old.c new file mode 100644 index 0000000000..701d14b60f --- /dev/null +++ b/lib/vgmstream/src/meta/ea_old.c @@ -0,0 +1,162 @@ +#include "meta.h" +#include "../coding/coding.h" +#include "../layout/layout.h" +#include "../util.h" + +typedef struct +{ + char szID[4]; + int dwSampleRate; + char bBits; + char bChannels; + char bCompression; + char bType; + int dwNumSamples; + int dwLoopStart; + int dwLoopLength; + int dwDataStart; + int dwUnknown; +} EACSHeader; + +VGMSTREAM * init_vgmstream_eacs(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + int channel_count; + int loop_flag; + char little_endian=0; + off_t start_offset; + EACSHeader *ea_header = NULL; + int32_t samples_count=0; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("cnk",filename_extension(filename)) && + strcasecmp("as4",filename_extension(filename)) && + strcasecmp("asf",filename_extension(filename))) goto fail; + + ea_header=(EACSHeader *)malloc(sizeof(EACSHeader)); + + /* check header */ + if ((uint32_t)read_32bitBE(0,streamFile)!=0x31534E68) /* "1SNh" */ + goto fail; + + /* check if we are little or big endian */ + if ((uint32_t)read_32bitBE(4,streamFile)<0x40) + little_endian=1; + + /* check type details */ + start_offset = read_32bitLE(0x04,streamFile); + + if((uint32_t)read_32bitBE(0x08,streamFile)==0x45414353) { /* EACS */ + read_streamfile((uint8_t*)ea_header,0x08,sizeof(EACSHeader),streamFile); + loop_flag = 0; //(ea_header->dwLoopStart!=0); + channel_count = (ea_header->bChannels); + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,0); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + init_get_high_nibble(vgmstream); + + vgmstream->sample_rate = ea_header->dwSampleRate; + + if(ea_header->bCompression==0) { + vgmstream->coding_type = coding_PCM16LE_int; + if(ea_header->bBits==1) + vgmstream->coding_type = coding_PCM8_int; + } + else + vgmstream->coding_type = coding_EACS_IMA; + + vgmstream->layout_type = layout_eacs_blocked; + vgmstream->meta_type = meta_EACS_PC; + + if(little_endian) + vgmstream->meta_type = meta_EACS_SAT; + + } else { + channel_count=read_32bitLE(0x20,streamFile); + + vgmstream = allocate_vgmstream(channel_count,0); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type=layout_eacs_blocked; + vgmstream->meta_type=meta_EACS_PSX; + } + + vgmstream->ea_platform=little_endian; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + // calc the samples length ... + if(little_endian) + vgmstream->next_block_offset=read_32bitBE(0x04,streamFile); + else + vgmstream->next_block_offset=read_32bitLE(0x04,streamFile); + + if(vgmstream->next_block_offset>0x30) { + vgmstream->current_block_size=vgmstream->next_block_offset-sizeof(EACSHeader); + samples_count=(int32_t)vgmstream->current_block_size/get_vgmstream_frame_size(vgmstream)*get_vgmstream_samples_per_frame(vgmstream); + samples_count/=vgmstream->channels; + } + + do { + if(read_32bitBE(vgmstream->next_block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) { + ea_header->dwLoopStart=read_32bitLE(vgmstream->next_block_offset+0x08,vgmstream->ch[0].streamfile); + vgmstream->next_block_offset+=0x0C; + } + + if(read_32bitBE(vgmstream->next_block_offset,vgmstream->ch[0].streamfile)==0x31534E65) + break; + + eacs_block_update(vgmstream->next_block_offset,vgmstream); + samples_count+=vgmstream->current_block_size/get_vgmstream_frame_size(vgmstream)*get_vgmstream_samples_per_frame(vgmstream); + } while(vgmstream->next_block_offset<get_streamfile_size(streamFile)-8); + + // Reset values ... + // setting up the first header by calling the eacs_block_update sub + if(little_endian) + vgmstream->next_block_offset=read_32bitBE(0x04,streamFile); + else + vgmstream->next_block_offset=read_32bitLE(0x04,streamFile); + + vgmstream->current_block_size=vgmstream->next_block_offset-sizeof(EACSHeader); + + if(vgmstream->coding_type!=coding_PSX) + vgmstream->current_block_size-=8; + + if(vgmstream->coding_type==coding_PSX) + eacs_block_update(0x2C,vgmstream); + else + eacs_block_update(0x28,vgmstream); + + // re-allocate the sample count + vgmstream->num_samples=samples_count; + + if(loop_flag) { + vgmstream->loop_start_sample = ea_header->dwLoopStart; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + if(ea_header) + free(ea_header); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if(ea_header) + free(ea_header); + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/emff.c b/lib/vgmstream/src/meta/emff.c new file mode 100644 index 0000000000..0798ddfee1 --- /dev/null +++ b/lib/vgmstream/src/meta/emff.c @@ -0,0 +1,179 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* EMFF - Eidos Music File Format (PS2), +Legacy of Kain - Defiance, possibly more... */ +VGMSTREAM * init_vgmstream_emff_ps2(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + int frequency; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("emff",filename_extension(filename))) goto fail; + + /* do some checks on the file, cause we have no magic words to check the header... + it seems if 0x800 and 0x804 = 0 then the file has only audio, if 0x800 = 1 + it has a text section, if both are 1 it's video with a text section included... */ + if (read_32bitBE(0x800,streamFile) == 0x01000000 || /* "0x01000000" */ + read_32bitBE(0x804,streamFile) == 0x01000000) /* "0x01000000" */ + goto fail; + + frequency = read_32bitLE(0x0,streamFile); + channel_count = read_32bitLE(0xC,streamFile); + + if (frequency > 48000 || + channel_count > 8) { + goto fail; + } + + loop_flag = (read_32bitLE(0x4,streamFile) != 0xFFFFFFFF); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->sample_rate = frequency; + vgmstream->channels = channel_count; + vgmstream->coding_type = coding_PSX; + + vgmstream->layout_type = layout_emff_ps2_blocked; + vgmstream->interleave_block_size = 0x10; + vgmstream->meta_type = meta_EMFF_PS2; + + /* open the file for reading */ + { + 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; + } + } + + /* Calc num_samples */ + emff_ps2_block_update(start_offset,vgmstream); + vgmstream->num_samples = read_32bitLE(0x8,streamFile);; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitLE(0x28,streamFile)-start_offset)*28/16/channel_count; + vgmstream->loop_end_sample = read_32bitLE(0x8,streamFile); + } + + return vgmstream; + +/* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + +/* EMFF - Eidos Music File Format (NGC/WII), +found in Tomb Raider Legend/Anniversary/Underworld, possibly more... */ +VGMSTREAM * init_vgmstream_emff_ngc(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + int frequency; + int i; + int j; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("emff",filename_extension(filename))) goto fail; + + /* do some checks on the file, cause we have no magic words to check the header... + it seems if 0x800 and 0x804 = 0 then the file has only audio, if 0x800 = 1 + it has a text section, if both are 1 it's video with a text section included... */ + if (read_32bitBE(0x800,streamFile) == 0x00000001 || /* "0x00000001" */ + read_32bitBE(0x804,streamFile) == 0x00000001) /* "0x00000001" */ + goto fail; + + frequency = read_32bitBE(0x0,streamFile); + channel_count = read_32bitBE(0xC,streamFile); + + if (frequency > 48000 || + channel_count > 8) { + goto fail; + } + + loop_flag = (read_32bitBE(0x4,streamFile) != 0xFFFFFFFF); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->sample_rate = frequency; + vgmstream->channels = channel_count; + vgmstream->coding_type = coding_NGC_DSP; + + /* Retrieving coefs and loops, depending on the file layout... */ + /* Found in Tomb Raider - Legend for GameCube */ + if (read_32bitBE(0xC8,streamFile) > 0x0) { + off_t coef_table[8] = {0xC8,0xF6,0x124,0x152,0x180,0x1AE,0x1DC,0x20A}; + for (j=0;j<vgmstream->channels;j++) { + for (i=0;i<16;i++) { + vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+i*2,streamFile); + } + } + /* Found in Tomb Raider - Anniversary for WII */ + } else if (read_32bitBE(0xCC,streamFile) > 0x0) { + off_t coef_table[8] = {0xCC,0xFA,0x128,0x156,0x184,0x1B2,0x1E0,0x20E}; + for (j=0;j<vgmstream->channels;j++) { + for (i=0;i<16;i++) { + vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+i*2,streamFile); + } +} + /* Found in Tomb Raider - Underworld for WII */ + } else if (read_32bitBE(0x2D0,streamFile) > 0x0) { + off_t coef_table[8] = {0x2D0,0x2FE,0x32C,0x35A,0x388,0x3B6,0x3E4,0x412}; + for (j=0;j<vgmstream->channels;j++) { + for (i=0;i<16;i++) { + vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+i*2,streamFile); + } +} + + } else { + goto fail; + } + + vgmstream->layout_type = layout_emff_ngc_blocked; + vgmstream->interleave_block_size = 0x10; + vgmstream->meta_type = meta_EMFF_NGC; + + /* open the file for reading */ + { + 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; + } + } + + /* Calc num_samples */ + emff_ngc_block_update(start_offset,vgmstream); + vgmstream->num_samples = read_32bitBE(0x8,streamFile);; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitBE(0x28,streamFile))*14/8/channel_count; + vgmstream->loop_end_sample = read_32bitBE(0x8,streamFile); + } + + return vgmstream; + +/* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/fsb.c b/lib/vgmstream/src/meta/fsb.c new file mode 100644 index 0000000000..fe3a0ca5bf --- /dev/null +++ b/lib/vgmstream/src/meta/fsb.c @@ -0,0 +1,322 @@ +#include "meta.h" +#include "../util.h" + +/* comment from hcs: +((uint8_t)read_8bit(offset, file))&0xf for the low nibble, +((uint8_t)read_8bit(offset, file)) >> 4 for the high one +((uint8_t)read_8bit(0x4B,streamFile) >> (1?0:4))&0xf; +*/ +/* FSB1 */ +VGMSTREAM * init_vgmstream_fsb1(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + /* int fsb1_included_files; */ + int fsb1_format; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("fsb",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x46534231) /* "FSB1" */ + goto fail; + + /* "Check if the FSB is used as + conatiner or as single file" */ + if (read_32bitBE(0x04,streamFile) != 0x01000000) + goto fail; + + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* This will be tricky ;o) */ + fsb1_format = read_32bitBE(0x44,streamFile); + switch (fsb1_format) { + case 0x40008800: /* PS2 (Operation Genesis) */ + case 0x41008800: /* PS2 (Operation Genesis) */ + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + vgmstream->num_samples = (read_32bitLE(0x34,streamFile))*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x30,streamFile); + } + break; + default: + goto fail; + + } + /* fill in the vital statistics */ + start_offset = 0x50; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x38,streamFile); + vgmstream->meta_type = meta_FSB1; + + + /* 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; +} + + + +/* FSB3 */ +VGMSTREAM * init_vgmstream_fsb3(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + /* int fsb3_included_files; */ + int fsb3_headerlen = 0x18; + int fsb3_format; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("fsb",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x46534233) /* "FSB3" */ + goto fail; + + /* "Check if the FSB is used as + conatiner or as single file" */ + if (read_32bitBE(0x04,streamFile) != 0x01000000) + goto fail; + + + + if (read_32bitBE(0x48,streamFile) == 0x02000806) { + loop_flag = 1; + } else { + loop_flag = 0; /* (read_32bitLE(0x08,streamFile)!=0); */ + } + + /* Channel check + if (read_16bitLE(0x56,streamFile) == 2) { + channel_count = 2; + } else { + goto fail; + } + */ + + channel_count = read_16bitLE(0x56,streamFile); + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* This will be tricky ;o) */ + fsb3_format = read_32bitBE(0x48,streamFile); + switch (fsb3_format) { + case 0x40008800: /* PS2 (Agent Hugo, Flat Out 2) */ + case 0x41008800: /* PS2 (Flat Out) */ + case 0x42008800: /* PS2 (Jackass - The Game) */ + case 0x01008804: /* PS2 (Cold Fear) */ + case 0x02008804: /* PS2 (Shrek - Smash 'n Crash */ + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x40,streamFile); + vgmstream->loop_end_sample = (read_32bitLE(0x0C,streamFile))*28/16/channel_count; + } + break; + case 0x02000806: /* WII (Metroid Prime 3) */ + case 0x01000806: /* WII (Metroid Prime 3) */ + case 0x40000802: /* WII (WWE Smackdown Vs. Raw 2008) */ + case 0x40000882: /* WII (Bully) */ + case 0x41000802: /* GC (Dysney's Incredibles, The) */ + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave_byte; + vgmstream->interleave_block_size = 2; + vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*14/8/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x40,streamFile); + vgmstream->loop_end_sample = (read_32bitLE(0x0C,streamFile))*14/8/channel_count; + } + break; + case 0x40004020: /* WII (Guitar Hero III), uses Xbox-ish IMA */ + case 0x400040A0: /* WII (Guitar Hero III), uses Xbox-ish IMA */ + case 0x41004800: /* XBOX (FlatOut, Rainbow Six - Lockdown) */ + case 0x01004804: /* XBOX (Cold Fear) <- maybe IMA??? */ + vgmstream->coding_type = coding_XBOX; + vgmstream->layout_type = layout_none; + vgmstream->num_samples = read_32bitLE(0x0C,streamFile)*64/36/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x40,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile)*64/36/channel_count; + } + break; + default: + goto fail; + } + /* fill in the vital statistics */ + start_offset = (read_32bitLE(0x08,streamFile))+fsb3_headerlen; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x4C,streamFile); + vgmstream->meta_type = meta_FSB3; + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x68+i*2,streamFile); + } + if (vgmstream->channels) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x96+i*2,streamFile); + } + } + } + + /* 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; + + + if (vgmstream->coding_type == coding_XBOX) { + /* xbox interleaving is a little odd */ + vgmstream->ch[i].channel_start_offset=start_offset; + } else { + vgmstream->ch[i].channel_start_offset= + start_offset+vgmstream->interleave_block_size*i; + } + vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset; + + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + + +/* FSB4 */ +VGMSTREAM * init_vgmstream_fsb4(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + /* int fsb1_included_files; */ + int fsb4_format; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("fsb",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x46534234) /* "FSB4" */ + goto fail; + + /* "Check if the FSB is used as + conatiner or as single file" */ + if (read_32bitBE(0x04,streamFile) != 0x01000000) + goto fail; + + + if (read_32bitBE(0x60,streamFile) == 0x40008800) { + loop_flag = 1; + } else { + loop_flag = 0; + } + + + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + + /* fill in the vital statistics */ + start_offset = 0x80; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x64,streamFile); + fsb4_format = read_32bitBE(0x60,streamFile); + switch (fsb4_format) { + /* PS2 (Spider Man - Web of Shadows), Speed Racer */ + case 0x40008800: + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + vgmstream->num_samples = (read_32bitLE(0x54,streamFile))*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x50,streamFile); + } + break; + default: + goto fail; + + } + + vgmstream->meta_type = meta_FSB4; + + + /* 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; +} + diff --git a/lib/vgmstream/src/meta/gca.c b/lib/vgmstream/src/meta/gca.c new file mode 100644 index 0000000000..f6ff5bbdf0 --- /dev/null +++ b/lib/vgmstream/src/meta/gca.c @@ -0,0 +1,69 @@ +#include "meta.h" +#include "../util.h" + +/* GCA (from Metal Slug Anthology [Wii]) */ +VGMSTREAM * init_vgmstream_gca(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count = 1; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("gca",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x47434131) /* "GCA1" */ + goto fail; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x40; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x2A,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitBE(0x26,streamFile)*7/8; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitBE(0x26,streamFile)*7/8; + } + + /* We have no interleave, so we have no layout */ + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_GCA; + + /* 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; + + } + } + + /*Retrieving the coef table */ + { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x04+i*2,streamFile); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/gcsw.c b/lib/vgmstream/src/meta/gcsw.c new file mode 100644 index 0000000000..dfcbd4ad37 --- /dev/null +++ b/lib/vgmstream/src/meta/gcsw.c @@ -0,0 +1,62 @@ +#include "meta.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_gcsw(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int channel_count; + int loop_flag; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("gcw",filename_extension(filename))) goto fail; + + /* check header */ + if ((uint32_t)read_32bitBE(0,streamFile)!=0x47435357) /* "GCSW" */ + goto fail; + + /* check type details */ + /* guess */ + loop_flag = read_32bitBE(0x1c,streamFile); + channel_count = read_32bitBE(0xc,streamFile); + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = read_32bitBE(0x10,streamFile); + vgmstream->sample_rate = read_32bitBE(0x8,streamFile); + /* channels and loop flag are set by allocate_vgmstream */ + vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile); + vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile); + + vgmstream->coding_type = coding_PCM16BE; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_GCSW; + + vgmstream->interleave_block_size = 0x8000; + + /* 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,0x8000); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + 0x20+0x8000*i; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/genh.c b/lib/vgmstream/src/meta/genh.c new file mode 100644 index 0000000000..5b81e6971c --- /dev/null +++ b/lib/vgmstream/src/meta/genh.c @@ -0,0 +1,398 @@ +#include "../vgmstream.h" +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" +#ifdef VGM_USE_MPEG +#include <mpg123.h> +#endif + +/* GENH is an artificial "generic" header for headerless streams */ + +VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + + int32_t channel_count; + int32_t interleave; + int32_t sample_rate; + int32_t loop_start; + int32_t loop_end; + int32_t start_offset; + int32_t header_size; + int32_t coef[2]; + int32_t coef_splitted[2]; + int32_t dsp_interleave_type; + int32_t coef_type; + + char filename[260]; + int coding; +#ifdef VGM_USE_MPEG + mpeg_codec_data *data = NULL; +#endif + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("genh",filename_extension(filename))) goto fail; + + /* check header magic */ + if (read_32bitBE(0x0,streamFile) != 0x47454e48) goto fail; + + /* check channel count (needed for ADP/DTK check) */ + channel_count = read_32bitLE(0x4,streamFile); + if (channel_count < 1) goto fail; + + /* check format */ + /* 0 = PSX ADPCM */ + /* 1 = XBOX IMA ADPCM */ + /* 2 = NGC ADP/DTK ADPCM */ + /* 3 = 16bit big endian PCM */ + /* 4 = 16bit little endian PCM */ + /* 5 = 8bit PCM */ + /* 6 = SDX2 */ + /* 7 = DVI IMA */ + /* 8 = MPEG-1 Layer III, possibly also the MPEG-2 and 2.5 extensions */ + /* 9 = IMA */ + /* 10 = AICA ADPCM */ + /* 11 = MS ADPCM */ + /* 12 = NGC DSP */ + /* 13 = 8bit unsingned PCM */ + /* 14 = PSX ADPCM (bad flagged) */ + /* ... others to come */ + switch (read_32bitLE(0x18,streamFile)) { + case 0: + coding = coding_PSX; + break; + case 1: + coding = coding_XBOX; + break; + case 2: + coding = coding_NGC_DTK; + if (channel_count != 2) goto fail; + break; + case 3: + coding = coding_PCM16BE; + break; + case 4: + coding = coding_PCM16LE; + break; + case 5: + coding = coding_PCM8; + break; + case 6: + coding = coding_SDX2; + break; + case 7: + coding = coding_DVI_IMA; + break; +#ifdef VGM_USE_MPEG + case 8: + /* we say MPEG-1 L3 here, but later find out exactly which */ + coding = coding_MPEG1_L3; + break; +#endif + case 9: + coding = coding_IMA; + break; + case 10: + coding = coding_AICA; + break; + case 11: + coding = coding_MSADPCM; + break; + case 12: + coding = coding_NGC_DSP; + break; + case 13: + coding = coding_PCM8_U_int; + break; + case 14: + coding = coding_PSX_badflags; + break; + default: + goto fail; + } + + start_offset = read_32bitLE(0x1C,streamFile); + header_size = read_32bitLE(0x20,streamFile); + + /* HACK to support old genh */ + if (header_size == 0) { + start_offset = 0x800; + header_size = 0x800; + } + + /* check for audio data start past header end */ + if (header_size > start_offset) goto fail; + + interleave = read_32bitLE(0x8,streamFile); + sample_rate = read_32bitLE(0xc,streamFile); + loop_start = read_32bitLE(0x10,streamFile); + loop_end = read_32bitLE(0x14,streamFile); + + coef[0] = read_32bitLE(0x24,streamFile); + coef[1] = read_32bitLE(0x28,streamFile); + dsp_interleave_type = read_32bitLE(0x2C,streamFile); + coef_type = read_32bitLE(0x30,streamFile); /* 0 - normal coefs + 1 - splitted coefs (16byte rows) */ + coef_splitted[0] = read_32bitLE(0x34,streamFile); + coef_splitted[1] = read_32bitLE(0x38,streamFile); + //if (coding == coding_XBOX && channel_count != 2) goto fail; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,(loop_start!=-1)); + if (!vgmstream) goto fail; + + /* fill in the vital information */ + + vgmstream->channels = channel_count; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = loop_end; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + vgmstream->loop_flag = (loop_start != -1); + + switch (coding) { + case coding_PCM8_U_int: + vgmstream->layout_type=layout_none; + break; + case coding_PCM16LE: + case coding_PCM16BE: + case coding_PCM8: + case coding_SDX2: + case coding_PSX: + case coding_PSX_badflags: + case coding_DVI_IMA: + case coding_IMA: + case coding_AICA: + vgmstream->interleave_block_size = interleave; + if (channel_count > 1) + { + if (coding == coding_SDX2) { + coding = coding_SDX2_int; + vgmstream->coding_type = coding_SDX2_int; + } + if(vgmstream->interleave_block_size==0xffffffff) + vgmstream->layout_type=layout_none; + else { + vgmstream->layout_type = layout_interleave; + if(coding==coding_DVI_IMA) + coding=coding_INT_DVI_IMA; + if(coding==coding_IMA) + coding=coding_INT_IMA; + } + } else { + vgmstream->layout_type = layout_none; + } + break; + case coding_MSADPCM: + if (channel_count != 2) goto fail; + vgmstream->interleave_block_size = interleave; + vgmstream->layout_type = layout_none; + break; + case coding_XBOX: + vgmstream->layout_type = layout_none; + break; + case coding_NGC_DTK: + vgmstream->layout_type = layout_dtk_interleave; + break; + case coding_NGC_DSP: + if (dsp_interleave_type == 0) { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + } else if (dsp_interleave_type == 1) { + vgmstream->layout_type = layout_interleave_byte; + vgmstream->interleave_block_size = interleave; + } else if (dsp_interleave_type == 2) { + vgmstream->layout_type = layout_none; + } + break; + +#ifdef VGM_USE_MPEG + case coding_MPEG1_L3: + vgmstream->layout_type = layout_mpeg; + break; +#endif + } + + vgmstream->coding_type = coding; + vgmstream->meta_type = meta_GENH; + + /* open the file for reading by each channel */ + { + int i; + int j; + + STREAMFILE * chstreamfile = NULL; + + for (i=0;i<channel_count;i++) { + off_t chstart_offset = start_offset; + + switch (coding) { + case coding_PSX: + case coding_PSX_badflags: + case coding_PCM16BE: + case coding_PCM16LE: + case coding_SDX2: + case coding_SDX2_int: + case coding_DVI_IMA: + case coding_IMA: + case coding_PCM8: + case coding_PCM8_U_int: + case coding_AICA: + case coding_INT_DVI_IMA: + case coding_INT_IMA: + if (vgmstream->layout_type == layout_interleave) { + if (interleave >= 512) { + chstreamfile = + streamFile->open(streamFile,filename,interleave); + } else { + if (!chstreamfile) + chstreamfile = + streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + } + chstart_offset = + start_offset+vgmstream->interleave_block_size*i; + } else { + chstreamfile = + streamFile->open(streamFile,filename, + STREAMFILE_DEFAULT_BUFFER_SIZE); + } + break; + case coding_XBOX: + case coding_MSADPCM: + /* xbox's "interleave" is a lie, all channels start at same + * offset */ + chstreamfile = + streamFile->open(streamFile,filename, + STREAMFILE_DEFAULT_BUFFER_SIZE); + break; + case coding_NGC_DTK: + if (!chstreamfile) + chstreamfile = + streamFile->open(streamFile,filename,32*0x400); + break; + case coding_NGC_DSP: + if (!chstreamfile) + chstreamfile = + streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (coef_type == 0) { + for (j=0;j<16;j++) { + vgmstream->ch[i].adpcm_coef[j] = read_16bitBE(coef[i]+j*2,streamFile); + } + } else if (coef_type == 1) { + for (j=0;j<8;j++) { + vgmstream->ch[i].adpcm_coef[j*2]=read_16bitBE(coef[i]+j*2,streamFile); + vgmstream->ch[i].adpcm_coef[j*2+1]=read_16bitBE(coef_splitted[i]+j*2,streamFile); + } + } + chstart_offset =start_offset+vgmstream->interleave_block_size*i; + break; + +#ifdef VGM_USE_MPEG + case coding_MPEG1_L3: + if (!chstreamfile) + chstreamfile = + streamFile->open(streamFile,filename,MPEG_BUFFER_SIZE); + break; +#endif + } + + if (!chstreamfile) goto fail; + + vgmstream->ch[i].streamfile = chstreamfile; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=chstart_offset; + } + } + +#ifdef VGM_USE_MPEG + if (coding == coding_MPEG1_L3) { + int rc; + off_t read_offset; + data = calloc(1,sizeof(mpeg_codec_data)); + if (!data) goto mpeg_fail; + + data->m = mpg123_new(NULL,&rc); + if (rc==MPG123_NOT_INITIALIZED) { + if (mpg123_init()!=MPG123_OK) goto mpeg_fail; + data->m = mpg123_new(NULL,&rc); + if (rc!=MPG123_OK) goto mpeg_fail; + } else if (rc!=MPG123_OK) { + goto mpeg_fail; + } + + mpg123_param(data->m,MPG123_REMOVE_FLAGS,MPG123_GAPLESS,0.0); + + if (mpg123_open_feed(data->m)!=MPG123_OK) { + goto mpeg_fail; + } + + /* check format */ + read_offset=0; + do { + size_t bytes_done; + if (read_streamfile(data->buffer, start_offset+read_offset, + MPEG_BUFFER_SIZE,vgmstream->ch[0].streamfile) != + MPEG_BUFFER_SIZE) goto mpeg_fail; + read_offset+=1; + rc = mpg123_decode(data->m,data->buffer,MPEG_BUFFER_SIZE, + NULL,0,&bytes_done); + if (rc != MPG123_OK && rc != MPG123_NEW_FORMAT && + rc != MPG123_NEED_MORE) goto mpeg_fail; + } while (rc != MPG123_NEW_FORMAT); + + { + long rate; + int channels,encoding; + struct mpg123_frameinfo mi; + rc = mpg123_getformat(data->m,&rate,&channels,&encoding); + if (rc != MPG123_OK) goto mpeg_fail; + if (rate != vgmstream->sample_rate || + channels != vgmstream->channels || + encoding != MPG123_ENC_SIGNED_16) goto mpeg_fail; + mpg123_info(data->m,&mi); + if (mi.rate != vgmstream->sample_rate) goto mpeg_fail; + if (mi.version == MPG123_1_0 && mi.layer == 1) + vgmstream->coding_type = coding_MPEG1_L1; + else if (mi.version == MPG123_1_0 && mi.layer == 2) + vgmstream->coding_type = coding_MPEG1_L2; + else if (mi.version == MPG123_1_0 && mi.layer == 3) + vgmstream->coding_type = coding_MPEG1_L3; + else if (mi.version == MPG123_2_0 && mi.layer == 1) + vgmstream->coding_type = coding_MPEG2_L1; + else if (mi.version == MPG123_2_0 && mi.layer == 2) + vgmstream->coding_type = coding_MPEG2_L2; + else if (mi.version == MPG123_2_0 && mi.layer == 3) + vgmstream->coding_type = coding_MPEG2_L3; + else if (mi.version == MPG123_2_5 && mi.layer == 1) + vgmstream->coding_type = coding_MPEG25_L1; + else if (mi.version == MPG123_2_5 && mi.layer == 2) + vgmstream->coding_type = coding_MPEG25_L2; + else if (mi.version == MPG123_2_5 && mi.layer == 3) + vgmstream->coding_type = coding_MPEG25_L3; + else goto mpeg_fail; + } + + /* reinit, to ignore the reading we've done so far */ + mpg123_open_feed(data->m); + + vgmstream->codec_data = data; + } +#endif + + return vgmstream; + + /* clean up anything we may have opened */ +#ifdef VGM_USE_MPEG +mpeg_fail: + if (data) { + mpg123_delete(data->m); + free(data); + } +#endif +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/gsp_gsb.c b/lib/vgmstream/src/meta/gsp_gsb.c new file mode 100644 index 0000000000..0caa034615 --- /dev/null +++ b/lib/vgmstream/src/meta/gsp_gsb.c @@ -0,0 +1,111 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* GSP+GSB - 2008-11-28 - manakoAT +Super Swing Golf 1 & 2 (WII) */ +VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamFileGSP = NULL; + char filename[260]; + char filenameGSP[260]; + off_t start_offset; + int channel_count; + int loop_flag; + int header_len; + off_t coef1_start; + off_t coef2_start; + int dsp_blocks; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("gsb",filename_extension(filename))) goto fail; + + + strcpy(filenameGSP,filename); + strcpy(filenameGSP+strlen(filenameGSP)-3,"gsp"); + + streamFileGSP = streamFile->open(streamFile,filenameGSP,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!streamFileGSP) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFileGSP) != 0x47534E44) /* "GSND" */ + goto fail; + + channel_count = (uint16_t)read_16bitBE(0x3A,streamFileGSP); + loop_flag = (read_32bitBE(0x64,streamFileGSP) !=0xFFFFFFFF); + header_len = read_32bitBE(0x1C,streamFileGSP); + + coef1_start = header_len-0x4C; + coef2_start = header_len-0x1C; + dsp_blocks = read_32bitBE(header_len-0x5C,streamFileGSP); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x34,streamFileGSP); + vgmstream->coding_type = coding_NGC_DSP; + if(loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x64,streamFileGSP); + vgmstream->loop_end_sample = read_32bitBE(0x68,streamFileGSP); + } + + if (channel_count == 1) { + vgmstream->layout_type = layout_gsb_blocked; + } else if (channel_count > 1) { + vgmstream->layout_type = layout_gsb_blocked; + vgmstream->interleave_block_size = read_32bitBE(header_len-0x64,streamFileGSP); + } + + vgmstream->meta_type = meta_GSP_GSB; + + /* open the file for reading */ + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!vgmstream->ch[0].streamfile) goto fail; + vgmstream->ch[0].channel_start_offset=0; + if (channel_count == 2) { + vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!vgmstream->ch[1].streamfile) goto fail; + vgmstream->ch[1].channel_start_offset=vgmstream->interleave_block_size; + } + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(coef1_start+i*2,streamFileGSP); + } + if (vgmstream->channels == 2) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(coef2_start+i*2,streamFileGSP); + } + } + } + + /* Calc num_samples */ + start_offset = 0x0; + gsb_block_update(start_offset,vgmstream); + vgmstream->num_samples=0; + + do { + + vgmstream->num_samples += vgmstream->current_block_size*14/8; + gsb_block_update(vgmstream->next_block_offset,vgmstream); + } while (vgmstream->next_block_offset<get_streamfile_size(streamFile)); + + gsb_block_update(start_offset,vgmstream); + + close_streamfile(streamFileGSP); streamFileGSP=NULL; + + return vgmstream; + + + /* clean up anything we may have opened */ +fail: + if (streamFileGSP) close_streamfile(streamFileGSP); + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/halpst.c b/lib/vgmstream/src/meta/halpst.c new file mode 100644 index 0000000000..31f3a1f04d --- /dev/null +++ b/lib/vgmstream/src/meta/halpst.c @@ -0,0 +1,124 @@ +#include "meta.h" +#include "../coding/coding.h" +#include "../layout/layout.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_halpst(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int channel_count; + int loop_flag = 0; + + int32_t samples_l,samples_r; + int32_t start_sample = 0; + + size_t max_block; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("hps",filename_extension(filename))) goto fail; + + /* check header */ + if ((uint32_t)read_32bitBE(0,streamFile)!=0x2048414C || /* " HAL" */ + read_32bitBE(4,streamFile)!=0x50535400) /* "PST\0" */ + goto fail; + + /* details */ + channel_count = read_32bitBE(0xc,streamFile); + max_block = read_32bitBE(0x10,streamFile)/channel_count; + + /* have I ever seen a mono .hps? */ + if (channel_count!=2) goto fail; + + /* yay for redundancy, gives us something to test */ + samples_l = dsp_nibbles_to_samples(read_32bitBE(0x18,streamFile))+1; + samples_r = dsp_nibbles_to_samples(read_32bitBE(0x50,streamFile))+1; + + if (samples_l != samples_r) goto fail; + + /* + * looping info is implicit in the "next block" field of the final + * block, so we have to find that + */ + { + off_t offset = 0x80, last_offset = 0; + off_t loop_offset; + + /* determine if there is a loop */ + while (offset > last_offset) { + last_offset = offset; + offset = read_32bitBE(offset+8,streamFile); + } + if (offset < 0) loop_flag = 0; + else { + /* one more pass to determine start sample */ + int32_t start_nibble = 0; + loop_flag = 1; + + loop_offset = offset; + offset = 0x80; + while (offset != loop_offset) { + start_nibble += read_32bitBE(offset,streamFile); + offset = read_32bitBE(offset+8,streamFile); + } + + start_sample = dsp_nibbles_to_samples(start_nibble); + } + + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = samples_l; + vgmstream->sample_rate = read_32bitBE(8,streamFile); + /* channels and loop flag are set by allocate_vgmstream */ + if (loop_flag) { + vgmstream->loop_start_sample = start_sample; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_halpst_blocked; + vgmstream->meta_type = meta_HALPST; + + /* load decode coefs */ + { + int i; + for (i=0;i<16;i++) + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x20+i*2,streamFile); + for (i=0;i<16;i++) + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x58+i*2,streamFile); + } + + /* 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, + (i==0? + max_block+0x20: /* first buffer a bit bigger to + read block header without + inefficiency */ + max_block + ) + ); + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + /* start me up */ + halpst_block_update(0x80,vgmstream); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/idsp.c b/lib/vgmstream/src/meta/idsp.c new file mode 100644 index 0000000000..3447fa9c60 --- /dev/null +++ b/lib/vgmstream/src/meta/idsp.c @@ -0,0 +1,162 @@ +#include "meta.h" +#include "../util.h" + +/* IDSP (Chronicles of Narnia Wii) */ +VGMSTREAM * init_vgmstream_idsp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("idsp",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x49445350) /* "IDSP" */ + goto fail; + + + loop_flag = 0; + channel_count = read_32bitBE(0x04,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0xD0; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x28,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitBE(0x20,streamFile); + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitBE(0x20,streamFile); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitBE(0x0C,streamFile); + vgmstream->meta_type = meta_IDSP; + + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x3C+i*2,streamFile); + } + if (vgmstream->channels) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x9C+i*2,streamFile); + } + } + } + + /* 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; +} + + + +/* IDSP (Soul Calibur Legends Wii) */ +VGMSTREAM * init_vgmstream_idsp2(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("idsp",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x69647370 || /* "idsp" */ + read_32bitBE(0xBC,streamFile) != 0x49445350) /* IDSP */ + goto fail; + + + loop_flag = read_32bitBE(0x20,streamFile); + channel_count = read_32bitBE(0xC4,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x1C0; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0xC8,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = (read_32bitBE(0x14,streamFile))*14/8/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitBE(0xD0,streamFile)); + vgmstream->loop_end_sample = (read_32bitBE(0xD4,streamFile)); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + vgmstream->meta_type = meta_IDSP2; + + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x118+i*2,streamFile); + } + if (vgmstream->channels) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x178+i*2,streamFile); + } + } + } + + /* 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; +} + + + diff --git a/lib/vgmstream/src/meta/ish_isd.c b/lib/vgmstream/src/meta/ish_isd.c new file mode 100644 index 0000000000..b612987049 --- /dev/null +++ b/lib/vgmstream/src/meta/ish_isd.c @@ -0,0 +1,89 @@ +#include "meta.h" +#include "../util.h" + +/* +ISH+ISD +*/ + +VGMSTREAM * init_vgmstream_ish_isd(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamFileISH = NULL; + char filename[260]; + char filenameISH[260]; + int i; + int channel_count; + int loop_flag; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("isd",filename_extension(filename))) goto fail; + + strcpy(filenameISH,filename); + strcpy(filenameISH+strlen(filenameISH)-3,"ish"); + + streamFileISH = streamFile->open(streamFile,filenameISH,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!streamFileISH) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFileISH) != 0x495F5346) /* "I_SF" */ + goto fail; + + channel_count = read_32bitBE(0x14,streamFileISH); + loop_flag = read_32bitBE(0x20,streamFileISH); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x08,streamFileISH); + vgmstream->num_samples=read_32bitBE(0x0C,streamFileISH); + vgmstream->coding_type = coding_NGC_DSP; + if(loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x20,streamFileISH)*14/8/channel_count; + vgmstream->loop_end_sample = read_32bitBE(0x24,streamFileISH)*14/8/channel_count; + } + + if (channel_count == 1) { + vgmstream->layout_type = layout_none; + } else if (channel_count == 2) { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitBE(0x18,streamFileISH); + } + + vgmstream->meta_type = meta_ISH_ISD; + + /* open the file for reading */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + vgmstream->ch[i].offset = 0; + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x40+i*2,streamFileISH); + } + if (vgmstream->channels == 2) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x80+i*2,streamFileISH); + } + } + } + + close_streamfile(streamFileISH); streamFileISH=NULL; + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (streamFileISH) close_streamfile(streamFileISH); + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ivb.c b/lib/vgmstream/src/meta/ivb.c new file mode 100644 index 0000000000..2fa303bc81 --- /dev/null +++ b/lib/vgmstream/src/meta/ivb.c @@ -0,0 +1,60 @@ +#include "meta.h" +#include "../util.h" + +/* a simple PS2 ADPCM format seen in Langrisser 3 */ +VGMSTREAM * init_vgmstream_ivb(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + off_t stream_length; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ivb",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x42564949) /* "BVII", probably */ + goto fail; /* supposed to be "IIVB"*/ + + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x8,streamFile); /* big endian? */ + vgmstream->coding_type = coding_PSX; + stream_length = read_32bitLE(0x04,streamFile); + start_offset = 0x10; + vgmstream->num_samples = stream_length*28/16; + + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_PS2_IVB; + + /* open the file for reading */ + { + 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+stream_length*i; + + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/kraw.c b/lib/vgmstream/src/meta/kraw.c new file mode 100644 index 0000000000..9a07709731 --- /dev/null +++ b/lib/vgmstream/src/meta/kraw.c @@ -0,0 +1,63 @@ +#include "meta.h" +#include "../util.h" + +/* KRAW (from Geometry Wars - Galaxies) */ +VGMSTREAM * init_vgmstream_kraw(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("kraw",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x6B524157) /* "kRAW" */ + goto fail; + + loop_flag = 0; + channel_count = 1; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x8; + vgmstream->channels = channel_count; + vgmstream->sample_rate = 32000; + vgmstream->coding_type = coding_PCM16BE; + vgmstream->num_samples = read_32bitBE(0x04,streamFile)/2/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitBE(0x04,streamFile)/2/channel_count; + } + + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_KRAW; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/meta.h b/lib/vgmstream/src/meta/meta.h new file mode 100644 index 0000000000..432ebdc9d4 --- /dev/null +++ b/lib/vgmstream/src/meta/meta.h @@ -0,0 +1,335 @@ +#ifndef _META_H +#define _META_H + +#include "../vgmstream.h" + +VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_afc(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_agsc(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_brstm(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_Cstr(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_gcsw(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_halpst(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ngc_dsp_stm(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ngc_mpdsp(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_npsf(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_rs03(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_rsf(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_rxw(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_int(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_exst(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_svag(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_mic(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_raw(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_psx_gms(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_str(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_ild(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_pnb(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_xbox_wavm(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_xbox_xwav(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ea(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_vpk(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_amts(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_xbox_stma(STREAMFILE *streamFile); + +#ifdef VGM_USE_VORBIS +VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_sfl(STREAMFILE * streamFile); +#endif + +VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_bmdx(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_wsi(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_aifc(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_str_snds(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ws_aud(STREAMFILE * streamFile); + +#ifdef VGM_USE_MPEG +VGMSTREAM * init_vgmstream_ahx(STREAMFILE * streamFile); +#endif + +VGMSTREAM * init_vgmstream_ivb(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_svs(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_riff(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_pos(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_nwa(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_eacs(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_xss(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_sl3(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_hgc1(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_aus(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rws(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_fsb1(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_fsb3(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_fsb4(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rwx(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_xwb(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_xa30(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_musc(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_musx_v004(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_musx_v006(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_musx_v201(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_leg(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_filp(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ikm(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_sfs(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_dvi(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_bg00(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_kcey(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_rstm(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_acm(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_kces(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_dxh(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_psh(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_pcm(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_psw(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_tec(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_enth(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_sdt(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_aix(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ngc_tydsp(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_capdsp(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_xbox_wvs(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_dc_str(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_dc_str_v2(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_xbox_matx(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_de2(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_xbox_xmu(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_xbox_xvas(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ngc_bh2pcm(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_sat_sap(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_dc_idvi(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_rnd(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_kraw(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_omu(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_xa2(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ss_stream(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_idsp(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_idsp2(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ngc_ymf(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_sadl(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_ccc(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_psx_fag(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_mihb(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_ngc_pdt(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_wii_mus(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rsd2vag(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rsd2pcmb(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rsd2xadp(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rsd3pcm(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rsd4pcmb(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rsd4pcm(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rsd4vag(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rsd6vag(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rsd6wadp(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_rsd6xadp(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_dc_asd(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_naomi_spsd(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_bgw(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_spw(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_ass(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_waa_wac_wad_wam(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_seg(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_nds_strm_ffta2(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_str_asr(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_zwdsp(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_gca(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_spt_spd(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ish_isd(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ydsp(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_msvp(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ngc_ssm(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_vgs(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_dc_wav_dcs(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_wii_smp(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_emff_ps2(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_emff_ngc(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_thp(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_wii_sts(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_p2bt(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ps2_gbts(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_wii_sng(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_ngc_ffcc_str(STREAMFILE *streamFile); + +#endif diff --git a/lib/vgmstream/src/meta/msvp.c b/lib/vgmstream/src/meta/msvp.c new file mode 100644 index 0000000000..0627dfab69 --- /dev/null +++ b/lib/vgmstream/src/meta/msvp.c @@ -0,0 +1,70 @@ +#include "meta.h" +#include "../util.h" + +/* MSVP (from PoPcap Hits Vol. 1) */ +VGMSTREAM * init_vgmstream_msvp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("msvp",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x4D535670) /* "MSVp" */ + goto fail; + + loop_flag = 0; + channel_count = 1; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x30; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x10,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = (read_32bitBE(0x0C,streamFile))*28/16/channel_count; + } + +/* Just to be sure that there comes a 2 channel file */ + if (channel_count == 1) { + vgmstream->layout_type = layout_none; + } else if (channel_count == 2) { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; /* Unknown for now */ + } + + vgmstream->meta_type = meta_MSVP; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/mus_acm.c b/lib/vgmstream/src/meta/mus_acm.c new file mode 100644 index 0000000000..fddf354df6 --- /dev/null +++ b/lib/vgmstream/src/meta/mus_acm.c @@ -0,0 +1,360 @@ +#include "../vgmstream.h" +#include "meta.h" +#include "../util.h" +#include "../streamfile.h" +#include "../coding/acm_decoder.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#ifdef WIN32 +#define DIRSEP '\\' +#else +#define DIRSEP '/' +#endif + +#define NAME_LENGTH 260 + +int exists(char *filename, STREAMFILE *streamfile) { + STREAMFILE * temp = + streamfile->open(streamfile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!temp) return 0; + + close_streamfile(temp); + return 1; +} + +/* needs the name of a file in the directory to test, as all we can do reliably is attempt to open a file */ +int find_directory_name(char *name_base, char *dir_name, int subdir_name_size, char *subdir_name, char *name, char *file_name, STREAMFILE *streamfile) { + /* find directory name */ + { + char temp_dir_name[NAME_LENGTH]; + + subdir_name[0]='\0'; + concatn(subdir_name_size,subdir_name,name_base); + + if (strlen(subdir_name) >= subdir_name_size-2) goto fail; + subdir_name[strlen(subdir_name)+1]='\0'; + subdir_name[strlen(subdir_name)]=DIRSEP; + + temp_dir_name[0]='\0'; + concatn(sizeof(temp_dir_name),temp_dir_name,dir_name); + concatn(sizeof(temp_dir_name),temp_dir_name,subdir_name); + concatn(sizeof(temp_dir_name),temp_dir_name,name_base); + concatn(sizeof(temp_dir_name),temp_dir_name,name); + concatn(sizeof(temp_dir_name),temp_dir_name,".ACM"); + + if (!exists(temp_dir_name,streamfile)) { + int i; + /* try all lowercase */ + for (i=strlen(subdir_name)-1;i>=0;i--) { + subdir_name[i]=tolower(subdir_name[i]); + } + temp_dir_name[0]='\0'; + concatn(sizeof(temp_dir_name),temp_dir_name,dir_name); + concatn(sizeof(temp_dir_name),temp_dir_name,subdir_name); + concatn(sizeof(temp_dir_name),temp_dir_name,name_base); + concatn(sizeof(temp_dir_name),temp_dir_name,name); + concatn(sizeof(temp_dir_name),temp_dir_name,".ACM"); + + if (!exists(temp_dir_name,streamfile)) { + /* try first uppercase */ + subdir_name[0]=toupper(subdir_name[0]); + temp_dir_name[0]='\0'; + concatn(sizeof(temp_dir_name),temp_dir_name,dir_name); + concatn(sizeof(temp_dir_name),temp_dir_name,subdir_name); + concatn(sizeof(temp_dir_name),temp_dir_name,name_base); + concatn(sizeof(temp_dir_name),temp_dir_name,name); + concatn(sizeof(temp_dir_name),temp_dir_name,".ACM"); + if (!exists(temp_dir_name,streamfile)) { + /* try also 3rd uppercase */ + subdir_name[2]=toupper(subdir_name[2]); + temp_dir_name[0]='\0'; + concatn(sizeof(temp_dir_name),temp_dir_name,dir_name); + concatn(sizeof(temp_dir_name),temp_dir_name,subdir_name); + concatn(sizeof(temp_dir_name),temp_dir_name,name_base); + concatn(sizeof(temp_dir_name),temp_dir_name,name); + concatn(sizeof(temp_dir_name),temp_dir_name,".ACM"); + + if (!exists(temp_dir_name,streamfile)) { + /* ah well, disaster has befallen your party */ + goto fail; + } + } + } + } + } + + return 0; + +fail: + return 1; +} + +/* MUS playlist for InterPlay ACM */ +VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + ACMStream *acm_stream = NULL; + mus_acm_codec_data *data = NULL; + + char filename[NAME_LENGTH]; + char line_buffer[NAME_LENGTH]; + char * end_ptr; + char name_base[NAME_LENGTH]; + char (*names)[NAME_LENGTH] = NULL; + char dir_name[NAME_LENGTH]; + char subdir_name[NAME_LENGTH]; + + int i; + int loop_flag = 0; + int channel_count; + int file_count; + size_t line_bytes; + int whole_line_read = 0; + off_t mus_offset = 0; + + int loop_end_index = -1; + int loop_start_index = -1; + int32_t loop_start_samples = -1; + int32_t loop_end_samples = -1; + + int32_t total_samples = 0; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("mus",filename_extension(filename))) goto fail; + + /* read file name base */ + line_bytes = get_streamfile_dos_line(sizeof(line_buffer),line_buffer, + mus_offset, streamFile, &whole_line_read); + if (!whole_line_read) goto fail; + mus_offset += line_bytes; + memcpy(name_base,line_buffer,sizeof(name_base)); + + /* uppercase name_base */ + { + int i; + for (i=0;name_base[i];i++) name_base[i]=toupper(name_base[i]); + } + + /*printf("name base: %s\n",name_base);*/ + + /* read track entry count */ + line_bytes = get_streamfile_dos_line(sizeof(line_buffer),line_buffer, + mus_offset, streamFile, &whole_line_read); + if (!whole_line_read) goto fail; + if (line_buffer[0] == '\0') goto fail; + mus_offset += line_bytes; + file_count = strtol(line_buffer,&end_ptr,10); + /* didn't parse whole line as an integer (optional opening whitespace) */ + if (*end_ptr != '\0') goto fail; + + /*printf("entries: %d\n",file_count);*/ + + names = calloc(file_count,sizeof(names[0])); + if (!names) goto fail; + + dir_name[0]='\0'; + concatn(sizeof(dir_name),dir_name,filename); + + { + /* find directory name for the directory contianing the MUS */ + char * last_slash; + last_slash = strrchr(dir_name,DIRSEP); + if (last_slash != NULL) { + /* trim off the file name */ + last_slash[1]='\0'; + } else { + /* no dir name? annihilate! */ + dir_name[0] = '\0'; + } + } + + /* can't do this until we have a file name */ + subdir_name[0]='\0'; + + /* parse each entry */ + { + char name[NAME_LENGTH]; + char loop_name_base_temp[NAME_LENGTH]; + char loop_name_temp[NAME_LENGTH]; + char loop_name_base[NAME_LENGTH]; + char loop_name[NAME_LENGTH]; + for (i=0;i<file_count;i++) + { + int fields_matched; + line_bytes = + get_streamfile_dos_line(sizeof(line_buffer),line_buffer, + mus_offset, streamFile, &whole_line_read); + if (!whole_line_read) goto fail; + mus_offset += line_bytes; + + fields_matched = sscanf(line_buffer,"%259s %259s %259s",name, + loop_name_base_temp,loop_name_temp); + + + if (fields_matched < 1) goto fail; + if (fields_matched == 3 && loop_name_base_temp[0] != '@' && loop_name_temp[0] != '@') + { + int j; + memcpy(loop_name,loop_name_temp,sizeof(loop_name)); + memcpy(loop_name_base,loop_name_base_temp,sizeof(loop_name_base)); + for (j=0;loop_name[j];j++) loop_name[j]=toupper(loop_name[j]); + for (j=0;loop_name_base[j];j++) loop_name_base[j]=toupper(loop_name_base[j]); + /* loop back entry */ + loop_end_index = i; + } + else if (fields_matched >= 2 && loop_name_base_temp[0] != '@') + { + int j; + memcpy(loop_name,loop_name_base_temp,sizeof(loop_name)); + memcpy(loop_name_base,name_base,sizeof(loop_name_base)); + for (j=0;loop_name[j];j++) loop_name[j]=toupper(loop_name[j]); + for (j=0;loop_name_base[j];j++) loop_name_base[j]=toupper(loop_name_base[j]); + /* loop back entry */ + loop_end_index = i; + } + else + { + /* normal entry, ignoring the @TAG for now */ + } + + { + /* uppercase */ + int j; + for (j=0;j<strlen(name);j++) name[j]=toupper(name[j]); + } + + /* try looking in the common directory */ + names[i][0] = '\0'; + concatn(sizeof(names[0]),names[i],dir_name); + concatn(sizeof(names[0]),names[i],name); + concatn(sizeof(names[0]),names[i],".ACM"); + + if (!exists(names[i],streamFile)) { + + /* We can't test for the directory until we have a file name + * to look for, so we do it here with the first file that seems to + * be in a subdirectory */ + if (subdir_name[0]=='\0') { + if (find_directory_name(name_base, dir_name, sizeof(subdir_name), subdir_name, name, filename, streamFile)) + goto fail; + } + + names[i][0] = '\0'; + concatn(sizeof(names[0]),names[i],dir_name); + concatn(sizeof(names[0]),names[i],subdir_name); + concatn(sizeof(names[0]),names[i],name_base); + concatn(sizeof(names[0]),names[i],name); + concatn(sizeof(names[0]),names[i],".ACM"); + + if (!exists(names[i],streamFile)) goto fail; + } + + /*printf("%2d %s\n",i,names[i]);*/ + } + + if (loop_end_index != -1) { + /* find the file to loop back to */ + char target_name[NAME_LENGTH]; + target_name[0]='\0'; + concatn(sizeof(target_name),target_name,dir_name); + concatn(sizeof(target_name),target_name,subdir_name); + concatn(sizeof(target_name),target_name,loop_name_base); + concatn(sizeof(target_name),target_name,loop_name); + concatn(sizeof(target_name),target_name,".ACM"); + /*printf("looking for loop %s\n",target_name);*/ + + for (i=0;i<file_count;i++) { + if (!strcmp(target_name,names[i])) + { + loop_start_index = i; + break; + } + } + + if (loop_start_index != -1) { + /*printf("loop from %d to %d\n",loop_end_index,loop_start_index);*/ + /*if (loop_start_index < file_count-1) loop_start_index++;*/ + loop_end_index++; + loop_flag = 1; + } + + } + } + + /* set up the struct to track the files */ + data = calloc(1,sizeof(mus_acm_codec_data)); + if (!data) goto fail; + + data->files = calloc(file_count,sizeof(ACMStream *)); + if (!data->files) { + free(data); data = NULL; + goto fail; + } + + /* open each file... */ + for (i=0;i<file_count;i++) { + + /* gonna do this a little backwards, open and parse the file + before creating the vgmstream */ + + if (acm_open_decoder(&acm_stream,streamFile,names[i]) != ACM_OK) { + goto fail; + } + + data->files[i]=acm_stream; + + if (i==loop_start_index) loop_start_samples = total_samples; + if (i==loop_end_index) loop_end_samples = total_samples; + + total_samples += acm_stream->total_values / acm_stream->info.channels; + + if (i>0) { + if (acm_stream->info.channels != data->files[0]->info.channels || + acm_stream->info.rate != data->files[0]->info.rate) goto fail; + } + } + + if (i==loop_end_index) loop_end_samples = total_samples; + + channel_count = data->files[0]->info.channels; + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->channels = channel_count; + vgmstream->sample_rate = data->files[0]->info.rate; + vgmstream->coding_type = coding_ACM; + vgmstream->num_samples = total_samples; + vgmstream->loop_start_sample = loop_start_samples; + vgmstream->loop_end_sample = loop_end_samples; + vgmstream->layout_type = layout_mus_acm; + vgmstream->meta_type = meta_MUS_ACM; + + data->file_count = file_count; + data->current_file = 0; + data->loop_start_file = loop_start_index; + data->loop_end_file = loop_end_index; + /*data->end_file = -1;*/ + + vgmstream->codec_data = data; + + free(names); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (data) { + int i; + for (i=0;i<data->file_count;i++) { + if (data->files[i]) { + acm_close(data->files[i]); + data->files[i] = NULL; + } + } + } + if (names) free(names); + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/musc.c b/lib/vgmstream/src/meta/musc.c new file mode 100644 index 0000000000..1abca4fff2 --- /dev/null +++ b/lib/vgmstream/src/meta/musc.c @@ -0,0 +1,72 @@ +#include "meta.h" +#include "../util.h" + +/* MUSC (near all Spyro games and many other using this) */ +VGMSTREAM * init_vgmstream_musc(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int musc_version; + int loop_flag = 0; + int channel_count = 2; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("musc",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x4D555343) /* MUSC */ + goto fail; + + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + musc_version=read_32bitLE(0x10,streamFile); + switch (musc_version) { + /* This handles the 'new' MUSC Version, which has only a 32 byte header + and doesn't provide any loop info! + Spyro - The Eternal Night, Spyro - A new Beginning, Ty - The Tsamanian Tiger */ + case 0x20: + start_offset = 0x20; + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x14,streamFile))*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (read_32bitLE(0x14,streamFile))*28/16/channel_count; + } + break; + default: + goto fail; +} + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x06,streamFile); + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = (read_32bitLE(0x18,streamFile))/2; + vgmstream->meta_type = meta_MUSC; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/musx.c b/lib/vgmstream/src/meta/musx.c new file mode 100644 index 0000000000..01ed5cb244 --- /dev/null +++ b/lib/vgmstream/src/meta/musx.c @@ -0,0 +1,342 @@ +#include "meta.h" +#include "../util.h" + +/* MUSX */ +/* Old MUSX formats, found in Spyro, Ty and other games */ +VGMSTREAM * init_vgmstream_musx_v004(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int musx_type; /* determining the decoder by strings like "PS2_", "GC__" and so on */ + //int musx_version; /* 0x08 provides a "version" byte */ + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("musx",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */ + goto fail; + if (read_32bitBE(0x08,streamFile) != 0x04000000) /* "0x04000000" */ + goto fail; + + /* This is tricky, the header changes it's layout if the file is unlooped */ + loop_flag = (read_32bitLE(0x840,streamFile)!=0xFFFFFFFF); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + + /* fill in the vital statistics */ + musx_type=(read_32bitBE(0x10,streamFile)); + + switch (musx_type) { + case 0x5053325F: /* PS2_ */ + start_offset = read_32bitLE(0x28,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = 32000; + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*28/16/channel_count; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x80; + vgmstream->meta_type = meta_MUSX_V004; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))*28/16/channel_count; + vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))*28/16/channel_count; + } + break; + /* seems to not work for Spyro, maybe i find other games for testing + case 0x58425F5F: XB__ + start_offset = read_32bitLE(0x28,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = 32000; + vgmstream->coding_type = coding_XBOX; + vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*64/36/channel_count; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_MUSX_V004; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))*64/36/channel_count; + vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))*64/36/channel_count; + } + break; + */ + default: + goto fail; + + } + + /* 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; + + + if (vgmstream->coding_type == coding_XBOX) { + /* xbox interleaving is a little odd */ + vgmstream->ch[i].channel_start_offset=start_offset; + } else { + vgmstream->ch[i].channel_start_offset= + start_offset+vgmstream->interleave_block_size*i; + } + vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset; + + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + + +/* MUSX */ +/* Old MUSX formats, found in Spyro, Ty and other games */ +VGMSTREAM * init_vgmstream_musx_v006(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int musx_type; /* determining the decoder by strings like "PS2_", "GC__" and so on */ + //int musx_version; /* 0x08 provides a "version" byte */ + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("musx",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */ + goto fail; + if (read_32bitBE(0x08,streamFile) != 0x06000000) /* "0x06000000" */ + goto fail; + + loop_flag = (read_32bitLE(0x840,streamFile)!=0xFFFFFFFF); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + musx_type=(read_32bitBE(0x10,streamFile)); + + switch (musx_type) { + case 0x5053325F: /* PS2_ */ + start_offset = read_32bitLE(0x28,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = 32000; + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*28/16/channel_count; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x80; + vgmstream->meta_type = meta_MUSX_V006; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))*28/16/channel_count; + vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))*28/16/channel_count; + } + break; + default: + goto fail; + + } + + /* 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; +} + + +/* MUSX */ +/* New MUSX formats, found in Quantum of Solace, The Mummy 3, possibly more */ +VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int musx_type; /* determining the decoder by strings like "PS2_", "GC__" and so on */ + //int musx_version; /* 0x08 provides a "version" byte */ + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("musx",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */ + goto fail; + if (read_32bitBE(0x08,streamFile) != 0x0A000000) /* "0x0A000000" */ + goto fail; + + loop_flag = (read_32bitLE(0x34,streamFile)!=0x00000000); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + musx_type=(read_32bitBE(0x10,streamFile)); + + switch (musx_type) { + case 0x5053325F: /* PS2_ */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = 32000; + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x40,streamFile); + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x80; + vgmstream->meta_type = meta_MUSX_V010; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x44,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x40,streamFile); + } + break; + default: + goto fail; + + } + + /* 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; +} + +/* MUSX */ +/* Old MUSX format, this one handles "Sphinx and the cursed Mummy", it's different from the other formats */ +VGMSTREAM * init_vgmstream_musx_v201(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + //int musx_version; /* 0x08 provides a "version" byte */ + int loop_flag; + int channel_count; + int loop_detect; + int loop_offsets; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("musx",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */ + goto fail; + if (read_32bitBE(0x08,streamFile) != 0xC9000000) /* "0xC9000000" */ + goto fail; + + channel_count = 2; + + loop_detect = read_32bitBE(0x800,streamFile); + switch (loop_detect) { + case 0x02000000: + loop_offsets = 0x8E0; + break; + case 0x03000000: + loop_offsets = 0x880; + break; + case 0x04000000: + loop_offsets = 0x8B4; + break; + case 0x05000000: + loop_offsets = 0x8E8; + break; + case 0x06000000: + loop_offsets = 0x91C; + break; + default: + goto fail; + } + + loop_flag = (read_32bitLE(loop_offsets+0x04,streamFile) !=0x00000000); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x18,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = 32000; + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(loop_offsets+0x10,streamFile)*28/16/channel_count; + vgmstream->loop_end_sample = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count; + } + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x80; + vgmstream->meta_type = meta_MUSX_V201; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/naomi_spsd.c b/lib/vgmstream/src/meta/naomi_spsd.c new file mode 100644 index 0000000000..f38e669c57 --- /dev/null +++ b/lib/vgmstream/src/meta/naomi_spsd.c @@ -0,0 +1,72 @@ +#include "meta.h" +#include "../util.h" + +/* SPSD (Guilty Gear X [NAOMI GD-ROM]) */ +VGMSTREAM * init_vgmstream_naomi_spsd(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("spsd",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x53505344) /* "SPSD" */ + goto fail; + + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + start_offset = 0x40; + vgmstream->sample_rate = (uint16_t)read_16bitLE(0x2A,streamFile); + vgmstream->coding_type = coding_AICA; + + vgmstream->num_samples = read_32bitLE(0x0C,streamFile); + + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile); + } + + vgmstream->interleave_block_size = 0x2000; + if (channel_count > 1) { + vgmstream->interleave_smallblock_size = ((get_streamfile_size(streamFile)-start_offset)%(vgmstream->channels*vgmstream->interleave_block_size))/vgmstream->channels; + vgmstream->layout_type = layout_interleave_shortblock; + } else { + vgmstream->layout_type = layout_none; + } + + vgmstream->meta_type = meta_NAOMI_SPSD; + + /* 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; + vgmstream->ch[i].adpcm_step_index = 0x7f; /* AICA */ + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/nds_sad.c b/lib/vgmstream/src/meta/nds_sad.c new file mode 100644 index 0000000000..e60c0ac80e --- /dev/null +++ b/lib/vgmstream/src/meta/nds_sad.c @@ -0,0 +1,110 @@ +#include "meta.h" +#include "../util.h" + +/* sadl (only the Professor Layton interleaved IMA version) */ +VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + int coding_type; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sad",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x7361646c) /* "sadl" */ + goto fail; + + /* check file size */ + if (read_32bitLE(0x40,streamFile) != get_streamfile_size(streamFile) ) + goto fail; + + /* check coding type */ + switch (read_8bit(0x33,streamFile)&0xf0) + { + case 0x70: + coding_type = coding_INT_IMA; + break; + case 0xb0: + coding_type = coding_NDS_PROCYON; + break; + default: + goto fail; + } + + loop_flag = read_8bit(0x31,streamFile); + channel_count = read_8bit(0x32,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x100; + vgmstream->channels = channel_count; + + switch (read_8bit(0x33,streamFile) & 6) + { + case 4: + vgmstream->sample_rate = 32728; + break; + case 2: + vgmstream->sample_rate = 16364; + break; + default: + goto fail; + } + + vgmstream->coding_type = coding_type; + + if (coding_type == coding_INT_IMA) + vgmstream->num_samples = + (read_32bitLE(0x40,streamFile)-start_offset)/channel_count*2; + else if (coding_type == coding_NDS_PROCYON) + vgmstream->num_samples = + (read_32bitLE(0x40,streamFile)-start_offset)/channel_count/16*30; + + vgmstream->interleave_block_size=0x10; + + if (loop_flag) + { + if (coding_type == coding_INT_IMA) + vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count*2; + else + vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count/16*30; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + if (channel_count > 1) + vgmstream->layout_type = layout_interleave; + else + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_SADL; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/nds_strm.c b/lib/vgmstream/src/meta/nds_strm.c new file mode 100644 index 0000000000..39fa88fa43 --- /dev/null +++ b/lib/vgmstream/src/meta/nds_strm.c @@ -0,0 +1,171 @@ +#include "meta.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + coding_t coding_type; + + int codec_number; + int channel_count; + int loop_flag; + + off_t start_offset; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("strm",filename_extension(filename))) goto fail; + + /* check header */ + if ((uint32_t)read_32bitBE(0x00,streamFile)!=0x5354524D) /* STRM */ + goto fail; + if ((uint32_t)read_32bitBE(0x04,streamFile)!=0xFFFE0001 && /* Old Header Check */ + ((uint32_t)read_32bitBE(0x04,streamFile)!=0xFEFF0001)) /* Some newer games have a new flag */ + goto fail; + + + + /* check for HEAD section */ + if ((uint32_t)read_32bitBE(0x10,streamFile)!=0x48454144 && /* "HEAD" */ + (uint32_t)read_32bitLE(0x14,streamFile)!=0x50) /* 0x50-sized head is all I've seen */ + goto fail; + + /* check type details */ + codec_number = read_8bit(0x18,streamFile); + loop_flag = read_8bit(0x19,streamFile); + channel_count = read_8bit(0x1a,streamFile); + + switch (codec_number) { + case 0: + coding_type = coding_PCM8; + break; + case 1: + coding_type = coding_PCM16LE; + break; + case 2: + coding_type = coding_NDS_IMA; + break; + default: + goto fail; + } + + /* TODO: only mono and stereo supported */ + if (channel_count < 1 || channel_count > 2) goto fail; + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = read_32bitLE(0x24,streamFile); + vgmstream->sample_rate = (uint16_t)read_16bitLE(0x1c,streamFile); + /* channels and loop flag are set by allocate_vgmstream */ + vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile); + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_type; + vgmstream->meta_type = meta_STRM; + + vgmstream->interleave_block_size = read_32bitLE(0x30,streamFile); + vgmstream->interleave_smallblock_size = read_32bitLE(0x38,streamFile); + + if (coding_type==coding_PCM8 || coding_type==coding_PCM16LE) + vgmstream->layout_type = layout_none; + else + vgmstream->layout_type = layout_interleave_shortblock; + + start_offset = read_32bitLE(0x28,streamFile); + + /* open the file for reading by each channel */ + { + int i; + for (i=0;i<channel_count;i++) { + if (vgmstream->layout_type==layout_interleave_shortblock) + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename, + vgmstream->interleave_block_size); + else + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename, + 0x1000); + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + start_offset + i*vgmstream->interleave_block_size; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + +/* STRM (from Final Fantasy Tactics A2 - Fuuketsu no Grimoire) */ +VGMSTREAM * init_vgmstream_nds_strm_ffta2(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("strm",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* RIFF */ + read_32bitBE(0x08,streamFile) != 0x494D4120) /* "IMA " */ + goto fail; + + loop_flag = (read_32bitLE(0x20,streamFile) !=0); + channel_count = read_32bitLE(0x24,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x2C; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x0C,streamFile); + vgmstream->coding_type = coding_INT_IMA; + vgmstream->num_samples = (read_32bitLE(0x04,streamFile)-start_offset); + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x28,streamFile); + } + + vgmstream->interleave_block_size = 0x80; + vgmstream->interleave_smallblock_size = (vgmstream->loop_end_sample)%((vgmstream->loop_end_sample)/vgmstream->interleave_block_size); + vgmstream->layout_type = layout_interleave_shortblock; + vgmstream->meta_type = meta_NDS_STRM_FFTA2; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ngc_adpdtk.c b/lib/vgmstream/src/meta/ngc_adpdtk.c new file mode 100644 index 0000000000..a8f6fc871f --- /dev/null +++ b/lib/vgmstream/src/meta/ngc_adpdtk.c @@ -0,0 +1,52 @@ +#include <math.h> +#include "meta.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + STREAMFILE * chstreamfile; + char filename[260]; + + size_t file_size; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("adp",filename_extension(filename))) goto fail; + + /* file size is the only way to determine sample count */ + file_size = get_streamfile_size(streamFile); + + /* .adp files have no header, so all we can do is look for a valid first frame */ + if (read_8bit(0,streamFile)!=read_8bit(2,streamFile) || read_8bit(1,streamFile)!=read_8bit(3,streamFile)) goto fail; + + /* Hopefully we haven't falsely detected something else... */ + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(2,0); /* always stereo, no loop */ + if (!vgmstream) goto fail; + + vgmstream->num_samples = file_size/32*28; + vgmstream->sample_rate = 48000; + vgmstream->coding_type = coding_NGC_DTK; + vgmstream->layout_type = layout_dtk_interleave; + vgmstream->meta_type = meta_NGC_ADPDTK; + + /* locality is such that two streamfiles is silly */ + chstreamfile = streamFile->open(streamFile,filename,32*0x400); + if (!chstreamfile) goto fail; + + for (i=0;i<2;i++) { + vgmstream->ch[i].channel_start_offset = + vgmstream->ch[i].offset = 0; + + vgmstream->ch[i].streamfile = chstreamfile; + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + diff --git a/lib/vgmstream/src/meta/ngc_bh2pcm.c b/lib/vgmstream/src/meta/ngc_bh2pcm.c new file mode 100644 index 0000000000..0894827be7 --- /dev/null +++ b/lib/vgmstream/src/meta/ngc_bh2pcm.c @@ -0,0 +1,87 @@ +#include "meta.h" +#include "../util.h" + +/* BH2PCM (from Bio Hazard 2) */ +VGMSTREAM * init_vgmstream_ngc_bh2pcm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int channel_count; + int format_detect; + int loop_flag; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("bh2pcm",filename_extension(filename))) goto fail; + +#if 0 + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x00000000) + goto fail; +#endif + + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + format_detect=read_32bitLE(0x00,streamFile); + switch (format_detect) { + case 1: + start_offset = 0x20; + channel_count = 2; + vgmstream->channels = channel_count; + vgmstream->sample_rate = 32000; + vgmstream->num_samples = read_32bitLE(0x04,streamFile)/2; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x04,streamFile); + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile); + } + break; + case 0: + start_offset = 0x20; + channel_count = 1; + vgmstream->channels = channel_count; + vgmstream->sample_rate = 32000; + vgmstream->num_samples = read_32bitLE(0x0C,streamFile); + vgmstream->layout_type = layout_none; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile); + } + break; + default: + goto fail; + } + + vgmstream->coding_type = coding_PCM16BE; + vgmstream->meta_type = meta_NGC_BH2PCM; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ngc_caf.c b/lib/vgmstream/src/meta/ngc_caf.c new file mode 100644 index 0000000000..f56b6db56b --- /dev/null +++ b/lib/vgmstream/src/meta/ngc_caf.c @@ -0,0 +1,75 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + // Calculate sample length ... + int32_t num_of_samples=0; + int32_t block_count=0; + + uint32_t loop_start=-1; + + off_t offset=0; + off_t next_block; + off_t file_length; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("cfn",filename_extension(filename))) goto fail; + + /* Check "CAF " ID */ + if (read_32bitBE(0,streamFile)!=0x43414620) goto fail; + + // Calculate sample length ... + file_length=(off_t)get_streamfile_size(streamFile); + + do { + next_block=read_32bitBE(offset+0x04,streamFile); + num_of_samples+=read_32bitBE(offset+0x14,streamFile)/8*14; + + if(read_32bitBE(offset+0x20,streamFile)==read_32bitBE(offset+0x08,streamFile)) { + loop_start=num_of_samples-read_32bitBE(offset+0x14,streamFile)/8*14; + } + offset+=next_block; + block_count++; + } while(offset<file_length); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(2,(loop_start!=-1)); /* always stereo */ + if (!vgmstream) goto fail; + + vgmstream->channels=2; + vgmstream->sample_rate=32000; + vgmstream->num_samples=num_of_samples; + + if(loop_start!=-1) { + vgmstream->loop_start_sample=loop_start; + vgmstream->loop_end_sample=num_of_samples; + } + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_caf_blocked; + vgmstream->meta_type = meta_CFN; + + /* open the file for reading by each channel */ + { + for (i=0;i<2;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + caf_block_update(0,vgmstream); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ngc_dsp_std.c b/lib/vgmstream/src/meta/ngc_dsp_std.c new file mode 100644 index 0000000000..83cca09737 --- /dev/null +++ b/lib/vgmstream/src/meta/ngc_dsp_std.c @@ -0,0 +1,1232 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../coding/coding.h" +#include "../util.h" + +/* If these variables are packed properly in the struct (one after another) + * then this is actually how they are laid out in the file, albeit big-endian */ + +struct dsp_header { + uint32_t sample_count; + uint32_t nibble_count; + uint32_t sample_rate; + uint16_t loop_flag; + uint16_t format; + uint32_t loop_start_offset; + uint32_t loop_end_offset; + uint32_t ca; + int16_t coef[16]; /* really 8x2 */ + uint16_t gain; + uint16_t initial_ps; + int16_t initial_hist1; + int16_t initial_hist2; + uint16_t loop_ps; + int16_t loop_hist1; + int16_t loop_hist2; +}; + +/* nonzero on failure */ +static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *file) { + int i; + uint8_t buf[0x4a]; /* usually padded out to 0x60 */ + if (read_streamfile(buf, offset, 0x4a, file) != 0x4a) return 1; + + header->sample_count = + get_32bitBE(buf+0x00); + header->nibble_count = + get_32bitBE(buf+0x04); + header->sample_rate = + get_32bitBE(buf+0x08); + header->loop_flag = + get_16bitBE(buf+0x0c); + header->format = + get_16bitBE(buf+0x0e); + header->loop_start_offset = + get_32bitBE(buf+0x10); + header->loop_end_offset = + get_32bitBE(buf+0x14); + header->ca = + get_32bitBE(buf+0x18); + for (i=0; i < 16; i++) + header->coef[i] = + get_16bitBE(buf+0x1c+i*2); + header->gain = + get_16bitBE(buf+0x3c); + header->initial_ps = + get_16bitBE(buf+0x3e); + header->initial_hist1 = + get_16bitBE(buf+0x40); + header->initial_hist2 = + get_16bitBE(buf+0x42); + header->loop_ps = + get_16bitBE(buf+0x44); + header->loop_hist1 = + get_16bitBE(buf+0x46); + header->loop_hist2 = + get_16bitBE(buf+0x48); + + return 0; +} + +/* the standard .dsp, as generated by DSPADPCM.exe */ + +VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + struct dsp_header header; + const off_t start_offset = 0x60; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("dsp",filename_extension(filename))) goto fail; + + if (read_dsp_header(&header, 0, streamFile)) goto fail; + + /* check initial predictor/scale */ + if (header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (header.format || header.gain) + goto fail; + + /* Check for a matching second header. If we find one and it checks + * out thoroughly, we're probably not dealing with a genuine mono DSP. + * In many cases these will pass all the other checks, including the + * predictor/scale check if the first byte is 0 */ + { + struct dsp_header header2; + + read_dsp_header(&header2, 0x60, streamFile); + + if (header.sample_count == header2.sample_count && + header.nibble_count == header2.nibble_count && + header.sample_rate == header2.sample_rate && + header.loop_flag == header2.loop_flag) goto fail; + } + + if (header.loop_flag) { + off_t loop_off; + /* check loop predictor/scale */ + loop_off = header.loop_start_offset/16*8; + if (header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) + goto fail; + } + + /* compare num_samples with nibble count */ + /* + fprintf(stderr,"num samples (literal): %d\n",read_32bitBE(0,streamFile)); + fprintf(stderr,"num samples (nibbles): %d\n",dsp_nibbles_to_samples(read_32bitBE(4,streamFile))); + */ + + /* build the VGMSTREAM */ + + + vgmstream = allocate_vgmstream(1,header.loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = header.sample_count; + vgmstream->sample_rate = header.sample_rate; + + vgmstream->loop_start_sample = dsp_nibbles_to_samples( + header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples( + header.loop_end_offset)+1; + + /* don't know why, but it does happen*/ + if (vgmstream->loop_end_sample > vgmstream->num_samples) + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_DSP_STD; + + /* coeffs */ + for (i=0;i<16;i++) + vgmstream->ch[0].adpcm_coef[i] = header.coef[i]; + + /* initial history */ + /* always 0 that I've ever seen, but for completeness... */ + vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1; + vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2; + + /* open the file for reading */ + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (!vgmstream->ch[0].streamfile) goto fail; + + vgmstream->ch[0].channel_start_offset= + vgmstream->ch[0].offset=start_offset; + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +/* Some very simple stereo variants of standard dsp just use the standard header + * twice and add interleave, or just concatenate the channels. We'll support + * them all here. + * Note that Cstr isn't here, despite using the form of the standard header, + * because its loop values are wacky. */ + +/* .stm + * Used in Paper Mario 2, Fire Emblem: Path of Radiance, Cubivore + * I suspected that this was an Intelligent Systems format, but its use in + * Cubivore calls that into question. */ +VGMSTREAM * init_vgmstream_ngc_dsp_stm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + struct dsp_header ch0_header, ch1_header; + int i; + int stm_header_sample_rate; + int channel_count; + const off_t start_offset = 0x100; + off_t first_channel_size; + off_t second_channel_start; + + /* check extension, case insensitive */ + /* to avoid collision with Scream Tracker 2 Modules, also ending in .stm + * and supported by default in Winamp, it was policy in the old days to + * rename these files to .dsp */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("stm",filename_extension(filename)) && + strcasecmp("dsp",filename_extension(filename))) goto fail; + + /* check intro magic */ + if (read_16bitBE(0, streamFile) != 0x0200) goto fail; + + channel_count = read_32bitBE(4, streamFile); + /* only stereo and mono are known */ + if (channel_count != 1 && channel_count != 2) goto fail; + + first_channel_size = read_32bitBE(8, streamFile); + /* this is bad rounding, wastes space, but it looks like that's what's + * used */ + second_channel_start = ((start_offset+first_channel_size)+0x20)/0x20*0x20; + + /* an additional check */ + stm_header_sample_rate = (uint16_t)read_16bitBE(2, streamFile); + + /* read the DSP headers */ + if (read_dsp_header(&ch0_header, 0x40, streamFile)) goto fail; + if (channel_count == 2) { + if (read_dsp_header(&ch1_header, 0xa0, streamFile)) goto fail; + } + + /* checks for fist channel */ + { + if (ch0_header.sample_rate != stm_header_sample_rate) goto fail; + + /* check initial predictor/scale */ + if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset, streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (ch0_header.format || ch0_header.gain) + goto fail; + + if (ch0_header.loop_flag) { + off_t loop_off; + /* check loop predictor/scale */ + loop_off = ch0_header.loop_start_offset/16*8; + if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) + goto fail; + } + } + + + /* checks for second channel */ + if (channel_count == 2) { + if (ch1_header.sample_rate != stm_header_sample_rate) goto fail; + + /* check for agreement with first channel header */ + if ( + ch0_header.sample_count != ch1_header.sample_count || + ch0_header.nibble_count != ch1_header.nibble_count || + ch0_header.loop_flag != ch1_header.loop_flag || + ch0_header.loop_start_offset != ch1_header.loop_start_offset || + ch0_header.loop_end_offset != ch1_header.loop_end_offset + ) goto fail; + + /* check initial predictor/scale */ + if (ch1_header.initial_ps != (uint8_t)read_8bit(second_channel_start, streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (ch1_header.format || ch1_header.gain) + goto fail; + + if (ch1_header.loop_flag) { + off_t loop_off; + /* check loop predictor/scale */ + loop_off = ch1_header.loop_start_offset/16*8; + /*printf("loop_start_offset=%x\nloop_ps=%x\nloop_off=%x\n",ch1_header.loop_start_offset,ch1_header.loop_ps,second_channel_start+loop_off);*/ + if (ch1_header.loop_ps != (uint8_t)read_8bit(second_channel_start+loop_off,streamFile)) + goto fail; + } + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count, ch0_header.loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = ch0_header.sample_count; + vgmstream->sample_rate = ch0_header.sample_rate; + + vgmstream->loop_start_sample = dsp_nibbles_to_samples( + ch0_header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples( + ch0_header.loop_end_offset)+1; + + /* don't know why, but it does happen*/ + if (vgmstream->loop_end_sample > vgmstream->num_samples) + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_DSP_STM; + + /* coeffs */ + for (i=0;i<16;i++) + vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; + + /* initial history */ + /* always 0 that I've ever seen, but for completeness... */ + vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; + vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; + + if (channel_count == 2) { + /* coeffs */ + for (i=0;i<16;i++) + vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; + + /* initial history */ + /* always 0 that I've ever seen, but for completeness... */ + vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; + vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; + } + + /* open the file for reading */ + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (!vgmstream->ch[0].streamfile) goto fail; + + vgmstream->ch[0].channel_start_offset= + vgmstream->ch[0].offset=start_offset; + + if (channel_count == 2) { + vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (!vgmstream->ch[1].streamfile) goto fail; + + vgmstream->ch[1].channel_start_offset= + vgmstream->ch[1].offset=second_channel_start; + } + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +/* mpdsp: looks like a standard .dsp header, but the data is actually + * interleaved stereo + * The files originally had a .dsp extension, we rename them to .mpdsp so we + * can catch this. + */ + +VGMSTREAM * init_vgmstream_ngc_mpdsp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + struct dsp_header header; + const off_t start_offset = 0x60; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("mpdsp",filename_extension(filename))) goto fail; + + if (read_dsp_header(&header, 0, streamFile)) goto fail; + + /* none have loop flag set, save us from loop code that involves them */ + if (header.loop_flag) goto fail; + + /* check initial predictor/scale */ + if (header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (header.format || header.gain) + goto fail; + + /* build the VGMSTREAM */ + + + /* no loop flag, but they do loop */ + vgmstream = allocate_vgmstream(2,0); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = header.sample_count/2; + vgmstream->sample_rate = header.sample_rate; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0xf000; + vgmstream->meta_type = meta_DSP_MPDSP; + + /* coeffs */ + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = header.coef[i]; + vgmstream->ch[1].adpcm_coef[i] = header.coef[i]; + } + + /* initial history */ + /* always 0 that I've ever seen, but for completeness... */ + vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1; + vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2; + vgmstream->ch[1].adpcm_history1_16 = header.initial_hist1; + vgmstream->ch[1].adpcm_history2_16 = header.initial_hist2; + + /* open the file for reading */ + for (i=0;i<2;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename, + vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=start_offset+ + vgmstream->interleave_block_size*i; + } + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +/* str: a very simple header format with implicit loop values + * it's allways in interleaved stereo format + */ +VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + const off_t start_offset = 0x60; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("str",filename_extension(filename))) goto fail; + + /* always 0xFAAF0001 @ offset 0 */ + if (read_32bitBE(0x00,streamFile)!=0xFAAF0001) goto fail; + + /* build the VGMSTREAM */ + /* always loop & stereo */ + vgmstream = allocate_vgmstream(2,1); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = read_32bitBE(0x08,streamFile); + vgmstream->sample_rate = read_32bitBE(0x04,streamFile); + + /* always loop to the beginning */ + vgmstream->loop_start_sample=0; + vgmstream->loop_end_sample=vgmstream->num_samples; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitBE(0x0C,streamFile); + vgmstream->meta_type = meta_DSP_STR; + + /* coeffs */ + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x10+(i*2),streamFile); + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x30+(i*2),streamFile); + } + + /* open the file for reading */ + for (i=0;i<2;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename, + vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=start_offset+ + vgmstream->interleave_block_size*i; + } + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +/* a bunch of formats that are identical except for file extension, + * but have different interleaves */ + +VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + const off_t start_offset = 0xc0; + off_t interleave; + int meta_type; + + struct dsp_header ch0_header,ch1_header; + + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strlen(filename) > 7 && !strcasecmp("_lr.dsp",filename+strlen(filename)-7)) { + /* Bomberman Jetters */ + interleave = 0x14180; + meta_type = meta_DSP_JETTERS; + } else if (!strcasecmp("mss",filename_extension(filename))) { + interleave = 0x1000; + meta_type = meta_DSP_MSS; + } else if (!strcasecmp("gcm",filename_extension(filename))) { + interleave = 0x8000; + meta_type = meta_DSP_GCM; + } else goto fail; + + if (read_dsp_header(&ch0_header, 0, streamFile)) goto fail; + if (read_dsp_header(&ch1_header, 0x60, streamFile)) goto fail; + + /* check initial predictor/scale */ + if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) + goto fail; + if (ch1_header.initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (ch0_header.format || ch0_header.gain || + ch1_header.format || ch1_header.gain) + goto fail; + + /* check for agreement */ + if ( + ch0_header.sample_count != ch1_header.sample_count || + ch0_header.nibble_count != ch1_header.nibble_count || + ch0_header.sample_rate != ch1_header.sample_rate || + ch0_header.loop_flag != ch1_header.loop_flag || + ch0_header.loop_start_offset != ch1_header.loop_start_offset || + ch0_header.loop_end_offset != ch1_header.loop_end_offset + ) goto fail; + + if (ch0_header.loop_flag) { + off_t loop_off; + /* check loop predictor/scale */ + loop_off = ch0_header.loop_start_offset/16*8; + loop_off = (loop_off/interleave*interleave*2) + (loop_off%interleave); + if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) + goto fail; + if (ch1_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off+interleave,streamFile)) + goto fail; + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(2,ch0_header.loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = ch0_header.sample_count; + vgmstream->sample_rate = ch0_header.sample_rate; + + /* TODO: adjust for interleave? */ + vgmstream->loop_start_sample = dsp_nibbles_to_samples( + ch0_header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples( + ch0_header.loop_end_offset)+1; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + vgmstream->meta_type = meta_type; + + /* coeffs */ + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; + vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; + } + + /* initial history */ + /* always 0 that I've ever seen, but for completeness... */ + vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; + vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; + vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; + vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; + + /* open the file for reading */ + for (i=0;i<2;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+i*interleave; + } + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +/* sadb - .SAD files, two standard DSP headers */ +VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + off_t start_offset; + off_t interleave; + + struct dsp_header ch0_header,ch1_header; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sad",filename_extension(filename))) goto fail; + + if (read_dsp_header(&ch0_header, 0x80, streamFile)) goto fail; + if (read_dsp_header(&ch1_header, 0xe0, streamFile)) goto fail; + + /* check header magic */ + if (read_32bitBE(0x0,streamFile) != 0x73616462) goto fail; /* "sadb" */ + + start_offset = read_32bitBE(0x48,streamFile); + interleave = 16; + + /* check initial predictor/scale */ + if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) + goto fail; + if (ch1_header.initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (ch0_header.format || ch0_header.gain || + ch1_header.format || ch1_header.gain) + goto fail; + + /* check for agreement */ + if ( + ch0_header.sample_count != ch1_header.sample_count || + ch0_header.nibble_count != ch1_header.nibble_count || + ch0_header.sample_rate != ch1_header.sample_rate || + ch0_header.loop_flag != ch1_header.loop_flag || + ch0_header.loop_start_offset != ch1_header.loop_start_offset || + ch0_header.loop_end_offset != ch1_header.loop_end_offset + ) goto fail; + + if (ch0_header.loop_flag) { + off_t loop_off; + /* check loop predictor/scale */ + loop_off = ch0_header.loop_start_offset/16*8; + loop_off = (loop_off/interleave*interleave*2) + (loop_off%interleave); + if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) + goto fail; + if (ch1_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off+interleave,streamFile)) + goto fail; + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(2,ch0_header.loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = ch0_header.sample_count; + vgmstream->sample_rate = ch0_header.sample_rate; + + /* TODO: adjust for interleave? */ + vgmstream->loop_start_sample = dsp_nibbles_to_samples( + ch0_header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples( + ch0_header.loop_end_offset)+1; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + vgmstream->meta_type = meta_DSP_SADB; + + /* coeffs */ + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; + vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; + } + + /* initial history */ + /* always 0 that I've ever seen, but for completeness... */ + vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; + vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; + vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; + vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; + + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + vgmstream->ch[1].streamfile = vgmstream->ch[0].streamfile; + + if (!vgmstream->ch[0].streamfile) goto fail; + /* open the file for reading */ + for (i=0;i<2;i++) { + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=start_offset+i*interleave; + } + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +/* AMTS - .amts files */ +VGMSTREAM * init_vgmstream_amts(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + off_t start_offset; + off_t interleave; + int channel_count; + + struct dsp_header ch0_header,ch1_header; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("amts",filename_extension(filename))) goto fail; + + /* check header magic */ + if (read_32bitBE(0x0,streamFile) != 0x414D5453) goto fail; /* "sadb" */ + + channel_count=read_32bitBE(0x14,streamFile); + start_offset = 0x800; + interleave = read_32bitBE(0x08,streamFile); + + if (read_dsp_header(&ch0_header, 0x20, streamFile)) goto fail; + + /* check initial predictor/scale */ + if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) + goto fail; + + if(channel_count==2) { + if (read_dsp_header(&ch1_header, 0x80, streamFile)) goto fail; + + if (ch1_header.initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (ch0_header.format || ch0_header.gain || + ch1_header.format || ch1_header.gain) + goto fail; + + /* check for agreement */ + if ( + ch0_header.sample_count != ch1_header.sample_count || + ch0_header.nibble_count != ch1_header.nibble_count || + ch0_header.sample_rate != ch1_header.sample_rate || + ch0_header.loop_flag != ch1_header.loop_flag || + ch0_header.loop_start_offset != ch1_header.loop_start_offset || + ch0_header.loop_end_offset != ch1_header.loop_end_offset + ) goto fail; + + if (ch0_header.loop_flag) { + off_t loop_off; + /* check loop predictor/scale */ + loop_off = ch0_header.loop_start_offset/16*8; + loop_off = (loop_off/interleave*interleave*2) + (loop_off%interleave); + if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) + goto fail; + if (ch1_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off+interleave,streamFile)) + goto fail; + } + + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,ch0_header.loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = ch0_header.sample_count; + vgmstream->sample_rate = ch0_header.sample_rate; + + /* TODO: adjust for interleave? */ + vgmstream->loop_start_sample = dsp_nibbles_to_samples( + ch0_header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples( + ch0_header.loop_end_offset)+1; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + vgmstream->meta_type = meta_DSP_AMTS; + + /* coeffs */ + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; + vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; + } + + /* initial history */ + /* always 0 that I've ever seen, but for completeness... */ + vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; + vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if(channel_count==2) { + vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; + vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; + vgmstream->ch[1].streamfile = vgmstream->ch[0].streamfile; + } + + if (!vgmstream->ch[0].streamfile) goto fail; + /* open the file for reading */ + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=start_offset+i*interleave; + } + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +/* .wsi as found in Alone in the Dark for Wii */ +/* These appear to be standard .dsp, but interleaved in a blocked format */ + +VGMSTREAM * init_vgmstream_wsi(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + struct dsp_header header[2]; + off_t start_offset[2]; + + int channel_count; + size_t est_block_size = 0; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("wsi",filename_extension(filename))) goto fail; + + /* I don't know if this is actually the channel count, or a block type + for the first block. Won't know until I see a mono .wsi */ + channel_count = read_32bitBE(0x04,streamFile); + + /* I've only allocated two headers, and I want to be alerted if a mono + .wsi shows up */ + if (channel_count != 2) goto fail; + + /* check for consistent block headers */ + { + off_t check_offset; + off_t block_size_has_been; + int i; + + check_offset = read_32bitBE(0x0,streamFile); + if (check_offset < 8) goto fail; + + block_size_has_been = check_offset; + + /* check 4 blocks, to get an idea */ + for (i=0;i<4*channel_count;i++) { + off_t block_size; + block_size = read_32bitBE(check_offset,streamFile); + + /* expect at least the block header */ + if (block_size < 0x10) goto fail; + + /* expect the channel numbers to alternate */ + if (i%channel_count+1 != read_32bitBE(check_offset+8,streamFile)) goto fail; + + /* expect every block in a set of channels to have the same size */ + if (i%channel_count==0) block_size_has_been = block_size; + else if (block_size != block_size_has_been) goto fail; + + /* get an estimate of block size for buffer sizing */ + if (block_size > est_block_size) est_block_size = block_size; + + check_offset += block_size; + } + } + + /* look at DSP headers */ + + { + off_t check_offset; + int i; + + check_offset = read_32bitBE(0x0,streamFile); + + for (i=0;i<channel_count;i++) { + off_t block_size; + + block_size = read_32bitBE(check_offset,streamFile); + + /* make sure block is actually big enough to hold the dsp header + and beginning of first frame */ + if (block_size < 0x61+0x10) goto fail; + if (read_dsp_header(&header[i], check_offset+0x10, streamFile)) goto fail; + + start_offset[i] = check_offset + 0x60+0x10; + + /* check initial predictor/scale */ + if (header[i].initial_ps != (uint8_t)read_8bit(check_offset+0x60+0x10,streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (header[i].format || header[i].gain) + goto fail; + +#if 0 + /* difficult to use this with blocks, but might be worth doing */ + if (header[i].loop_flag) { + off_t loop_off; + /* check loop predictor/scale */ + loop_off = header[i].loop_start_offset/16*8; + if (header[i].loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) + goto fail; + } +#endif + + check_offset += block_size; + } + } /* done looking at headers */ + + /* check for agreement (two channels only) */ + if ( + header[0].sample_count != header[1].sample_count || + header[0].nibble_count != header[1].nibble_count || + header[0].sample_rate != header[1].sample_rate || + header[0].loop_flag != header[1].loop_flag || + header[0].loop_start_offset != header[1].loop_start_offset || + header[0].loop_end_offset != header[1].loop_end_offset + ) goto fail; + + + vgmstream = allocate_vgmstream(channel_count,header[0].loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = header[0].sample_count; + vgmstream->sample_rate = header[0].sample_rate; + + vgmstream->loop_start_sample = dsp_nibbles_to_samples( + header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples( + header[0].loop_end_offset)+1; + + /* don't know why, but it does happen*/ + if (vgmstream->loop_end_sample > vgmstream->num_samples) + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_wsi_blocked; + vgmstream->meta_type = meta_DSP_WSI; + + /* coeffs */ + { + int i,j; + for (j=0;j<channel_count;j++) { + for (i=0;i<16;i++) { + vgmstream->ch[j].adpcm_coef[i] = header[j].coef[i]; + } + + /* initial history */ + /* always 0 that I've ever seen, but for completeness... */ + vgmstream->ch[j].adpcm_history1_16 = header[j].initial_hist1; + vgmstream->ch[j].adpcm_history2_16 = header[j].initial_hist2; + } + } + + + /* open the file for reading */ + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,est_block_size*4); + + if (!vgmstream->ch[0].streamfile) goto fail; + + wsi_block_update(read_32bitBE(0,streamFile),vgmstream); + + { + int i; + + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile; + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=start_offset[i]; + } + + } + + /* first block isn't full of musics */ + vgmstream->current_block_size -= 0x60; + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +#include "meta.h" +#include "../util.h" + + +/* SWD (found in Conflict - Desert Storm 1 & 2 */ +VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + off_t start_offset; + off_t interleave; + + struct dsp_header ch0_header, ch1_header; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("swd",filename_extension(filename))) goto fail; + + if (read_dsp_header(&ch0_header, 0x08, streamFile)) goto fail; + if (read_dsp_header(&ch1_header, 0x68, streamFile)) goto fail; + + /* check header magic */ + if (read_32bitBE(0x00,streamFile) != 0x505346D1) /* PSF\0xD1 */ + goto fail; + + start_offset = 0xC8; + interleave = 0x8; + + /* check initial predictor/scale */ + if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) + goto fail; + if (ch1_header.initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (ch0_header.format || ch0_header.gain || + ch1_header.format || ch1_header.gain) + goto fail; + + /* check for agreement */ + if ( + ch0_header.sample_count != ch1_header.sample_count || + ch0_header.nibble_count != ch1_header.nibble_count || + ch0_header.sample_rate != ch1_header.sample_rate || + ch0_header.loop_flag != ch1_header.loop_flag || + ch0_header.loop_start_offset != ch1_header.loop_start_offset || + ch0_header.loop_end_offset != ch1_header.loop_end_offset + ) goto fail; + + if (ch0_header.loop_flag) { + off_t loop_off; + /* check loop predictor/scale */ + loop_off = ch0_header.loop_start_offset/16*8; + loop_off = (loop_off/interleave*interleave*2) + (loop_off%interleave); + if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) + goto fail; + if (ch1_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off+interleave,streamFile)) + goto fail; + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(2,ch0_header.loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = ch0_header.sample_count; + vgmstream->sample_rate = ch0_header.sample_rate; + + /* TODO: adjust for interleave? */ + vgmstream->loop_start_sample = dsp_nibbles_to_samples( + ch0_header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples( + ch0_header.loop_end_offset)+1; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + vgmstream->meta_type = meta_NGC_SWD; + + /* coeffs */ + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; + vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; + } + + /* initial history */ + /* always 0 that I've ever seen, but for completeness... */ + vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; + vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; + vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; + vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; + + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + vgmstream->ch[1].streamfile = vgmstream->ch[0].streamfile; + + if (!vgmstream->ch[0].streamfile) goto fail; + /* open the file for reading */ + for (i=0;i<2;i++) { + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=start_offset+i*interleave; + } + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +/* IDSP .gcm files, two standard DSP headers */ +/* found in LEGO Star Wars Complete Collection for Wii */ +VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + off_t start_offset; + off_t interleave; + + struct dsp_header ch0_header,ch1_header; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("gcm",filename_extension(filename))) goto fail; + + /* check header magic */ + if (read_32bitBE(0x0,streamFile) != 0x49445350) goto fail; /* "IDSP" */ + + /* different versions? */ + if (read_32bitBE(0x4, streamFile) == 1 && + read_32bitBE(0x8, streamFile) == 0xc8) + { + if (read_dsp_header(&ch0_header, 0x10, streamFile)) goto fail; + if (read_dsp_header(&ch1_header, 0x70, streamFile)) goto fail; + + start_offset = 0xd0; + } + else if (read_32bitBE(0x4, streamFile) == 2 && + read_32bitBE(0x8, streamFile) == 0xd2) + { + if (read_dsp_header(&ch0_header, 0x20, streamFile)) goto fail; + if (read_dsp_header(&ch1_header, 0x80, streamFile)) goto fail; + + start_offset = 0xe0; + } + else goto fail; + + interleave = read_32bitBE(0xc, streamFile); + + /* check initial predictor/scale */ + if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) + goto fail; + if (ch1_header.initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (ch0_header.format || ch0_header.gain || + ch1_header.format || ch1_header.gain) + goto fail; + + /* check for agreement */ + if ( + ch0_header.sample_count != ch1_header.sample_count || + ch0_header.nibble_count != ch1_header.nibble_count || + ch0_header.sample_rate != ch1_header.sample_rate || + ch0_header.loop_flag != ch1_header.loop_flag || + ch0_header.loop_start_offset != ch1_header.loop_start_offset || + ch0_header.loop_end_offset != ch1_header.loop_end_offset + ) goto fail; + + if (ch0_header.loop_flag) { + off_t loop_off; + /* check loop predictor/scale */ + loop_off = ch0_header.loop_start_offset/16*8; + loop_off = (loop_off/interleave*interleave*2) + (loop_off%interleave); + if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) + goto fail; + if (ch1_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off+interleave,streamFile)) + goto fail; + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(2,ch0_header.loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = ch0_header.sample_count; + vgmstream->sample_rate = ch0_header.sample_rate; + + /* TODO: adjust for interleave? */ + vgmstream->loop_start_sample = dsp_nibbles_to_samples( + ch0_header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples( + ch0_header.loop_end_offset)+1; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + vgmstream->meta_type = meta_DSP_WII_IDSP; + + /* coeffs */ + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; + vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; + } + + /* initial history */ + /* always 0 that I've ever seen, but for completeness... */ + vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; + vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; + vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; + vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; + + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + vgmstream->ch[1].streamfile = vgmstream->ch[0].streamfile; + + if (!vgmstream->ch[0].streamfile) goto fail; + /* open the file for reading */ + for (i=0;i<2;i++) { + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=start_offset+i*interleave; + } + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + diff --git a/lib/vgmstream/src/meta/ngc_ffcc_str.c b/lib/vgmstream/src/meta/ngc_ffcc_str.c new file mode 100644 index 0000000000..bcc18af4ed --- /dev/null +++ b/lib/vgmstream/src/meta/ngc_ffcc_str.c @@ -0,0 +1,85 @@ +#include "meta.h" +#include "../util.h" + +/* STR (Final Fantasy: Crystal Chronicles) */ +VGMSTREAM * init_vgmstream_ngc_ffcc_str(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("str",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x53545200 || /* "STR\0" */ + read_32bitBE(0x08,streamFile) != get_streamfile_size(streamFile) || + read_32bitBE(0x10,streamFile) != -1) /* this might be loop point */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitBE(0x18,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x1000; + vgmstream->channels = channel_count; + if (read_32bitBE(0x14,streamFile)==0) + vgmstream->sample_rate = 32000; + else + vgmstream->sample_rate = 44100; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitBE(0x0C,streamFile)*14; + + if (channel_count > 1) + { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x1000; + } + else + { + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = 0x1000; + } + vgmstream->meta_type = meta_FFCC_STR; + + + if (vgmstream->coding_type == coding_NGC_DSP) { + int c; + for (c=0;c<channel_count;c++) + { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[c].adpcm_coef[i] = read_16bitBE(0x20 + c * 0x2e + i * 2,streamFile); + } + } + } + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ngc_iadp.c b/lib/vgmstream/src/meta/ngc_iadp.c new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/vgmstream/src/meta/ngc_iadp.c diff --git a/lib/vgmstream/src/meta/ngc_pdt.c b/lib/vgmstream/src/meta/ngc_pdt.c new file mode 100644 index 0000000000..56e7029228 --- /dev/null +++ b/lib/vgmstream/src/meta/ngc_pdt.c @@ -0,0 +1,79 @@ +#include "meta.h" +#include "../util.h" + +/* PDT - Custom Generated File (Mario Party) */ +VGMSTREAM * init_vgmstream_ngc_pdt(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("pdt",filename_extension(filename))) goto fail; + +#if 0 + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x00000000) /* 0x0 */ + goto fail; +#endif + + loop_flag = (read_32bitBE(0x0C,streamFile)!=2); /* not sure, but it seems unlooped = 2 */ + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x60; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x04,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitBE(0x08,streamFile)*14/8/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x0C,streamFile)*14/8/channel_count; + vgmstream->loop_end_sample = read_32bitBE(0x08,streamFile)*14/8/channel_count; + } + + /* dealing with no interleave, 'cause the interleave + for 2 channels is larger than the sample count/2 */ + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_NGC_PDT; + + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x20+i*2,streamFile); + } + if (vgmstream->channels == 2) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x40+i*2,streamFile); + } + } + } + + /* 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=(get_streamfile_size(streamFile)+start_offset)/2*i; + + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ngc_ssm.c b/lib/vgmstream/src/meta/ngc_ssm.c new file mode 100644 index 0000000000..7ea40369cd --- /dev/null +++ b/lib/vgmstream/src/meta/ngc_ssm.c @@ -0,0 +1,96 @@ +#include "meta.h" +#include "../util.h" + +/* SSM (Golden Gashbell Full Power GC) */ +VGMSTREAM * init_vgmstream_ngc_ssm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + int coef1_start; + int coef2_start; + int second_channel_start; + + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ssm",filename_extension(filename))) + goto fail; + + /* check header */ +#if 0 + if (read_32bitBE(0x00,streamFile) != 0x0) + goto fail; +#endif + + loop_flag = (uint32_t)read_16bitBE(0x18,streamFile); + channel_count = read_32bitBE(0x10,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitBE(0x0,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x14,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitBE(0x04,streamFile)*14/8/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x24,streamFile)*14/8/channel_count; + vgmstream->loop_end_sample = read_32bitBE(0x20,streamFile)*14/8/channel_count; + } + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_NGC_SSM; + + /* Retrieveing the coef tables and the start of the second channel*/ + coef1_start = 0x28; + coef2_start = 0x68; + second_channel_start = (read_32bitBE(0x04,streamFile)/2)+start_offset; + + { + int i; + for (i=0;i<16;i++) + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(coef1_start+i*2,streamFile); + if (channel_count == 2) { + for (i=0;i<16;i++) + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(coef2_start+i*2,streamFile); + } + } + + + /* 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; + + /* The first channel */ + vgmstream->ch[0].channel_start_offset= + vgmstream->ch[0].offset=start_offset; + + /* The second channel */ + if (channel_count == 2) { + vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (!vgmstream->ch[1].streamfile) goto fail; + + vgmstream->ch[1].channel_start_offset= + vgmstream->ch[1].offset=second_channel_start; + } + } + +} + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + + diff --git a/lib/vgmstream/src/meta/ngc_tydsp.c b/lib/vgmstream/src/meta/ngc_tydsp.c new file mode 100644 index 0000000000..bfce69493a --- /dev/null +++ b/lib/vgmstream/src/meta/ngc_tydsp.c @@ -0,0 +1,72 @@ +#include "meta.h" +#include "../util.h" + +/* TYDSP (Ty - The Tasmanian Tiger) */ +VGMSTREAM * init_vgmstream_ngc_tydsp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("tydsp",filename_extension(filename))) goto fail; + + loop_flag = 1; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitBE(0x08,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = (uint16_t)(read_16bitBE(0x6C,streamFile)); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitBE(0x00,streamFile); + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitBE(0x00,streamFile); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitBE(0x04,streamFile); + vgmstream->meta_type = meta_NGC_TYDSP; + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x10+i*2,streamFile); + } + if (vgmstream->channels) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x3E +i*2,streamFile); + } + } + } + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ngc_waa_wac_wad_wam.c b/lib/vgmstream/src/meta/ngc_waa_wac_wad_wam.c new file mode 100644 index 0000000000..8738f5fb89 --- /dev/null +++ b/lib/vgmstream/src/meta/ngc_waa_wac_wad_wam.c @@ -0,0 +1,100 @@ +#include "meta.h" +#include "../util.h" + +/* WAC - WAD - WAM (Beyond Good & Evil GC) */ +VGMSTREAM * init_vgmstream_waa_wac_wad_wam(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + int coef1_start; + int coef2_start; + int second_channel_start; + + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("waa",filename_extension(filename)) && + strcasecmp("wac",filename_extension(filename)) && + strcasecmp("wad",filename_extension(filename)) && + strcasecmp("wam",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* "RIFF" */ + read_32bitBE(0x08,streamFile) != 0x57415645 || /* "WAVE" */ + read_32bitBE(0x0C,streamFile) != 0x666D7420 || /* "fmt\0x20" */ + read_32bitBE(0x10,streamFile) != 0x12000000 || /* "0x12000000" */ + read_16bitBE(0x14,streamFile) != (int16_t)0xFEFF) /* "FEFF" */ + goto fail; + + loop_flag = 1; + channel_count = (uint16_t)read_16bitLE(0x16,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x5C; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x18,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = (read_32bitLE(0x2A,streamFile))*14/8/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (read_32bitLE(0x2A,streamFile))*14/8/channel_count; + } + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_WAA_WAC_WAD_WAM; + + /* Retrieveing the coef tables and the start of the second channel*/ + coef1_start = 0x2E; + coef2_start = (read_32bitLE(0x2A,streamFile)/2)+0x5C; + second_channel_start = coef2_start+0x2E; + + { + int i; + for (i=0;i<16;i++) + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(coef1_start+i*2,streamFile); + if (channel_count == 2) { + for (i=0;i<16;i++) + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(coef2_start+i*2,streamFile); + } + } + + + /* 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; + + /* The first channel */ + vgmstream->ch[0].channel_start_offset= + vgmstream->ch[0].offset=start_offset; + + /* The second channel */ + if (channel_count == 2) { + vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (!vgmstream->ch[1].streamfile) goto fail; + + vgmstream->ch[1].channel_start_offset= + vgmstream->ch[1].offset=second_channel_start; + } + } + +} + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + + diff --git a/lib/vgmstream/src/meta/ngc_ymf.c b/lib/vgmstream/src/meta/ngc_ymf.c new file mode 100644 index 0000000000..9ca6a29443 --- /dev/null +++ b/lib/vgmstream/src/meta/ngc_ymf.c @@ -0,0 +1,77 @@ +#include "meta.h" +#include "../util.h" + +/* YMF (WWE WrestleMania X8) */ +VGMSTREAM * init_vgmstream_ngc_ymf(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ymf",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x00000180) + goto fail; + + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x180; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0xA8,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitBE(0xDC,streamFile); + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitBE(0xDC,streamFile); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x20000; + vgmstream->meta_type = meta_NGC_YMF; + + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0xAE +i*2,streamFile); + } + if (vgmstream->channels) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x10E +i*2,streamFile); + } + } + } + + /* 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; +} diff --git a/lib/vgmstream/src/meta/nwa.c b/lib/vgmstream/src/meta/nwa.c new file mode 100644 index 0000000000..868bef43d7 --- /dev/null +++ b/lib/vgmstream/src/meta/nwa.c @@ -0,0 +1,358 @@ +#include "meta.h" +#include "../util.h" +#include "../coding/nwa_decoder.h" +#include <string.h> +#include <ctype.h> + +#ifdef WIN32 +#define DIRSEP '\\' +#else +#define DIRSEP '/' +#endif + +/* NWA - Visual Art's streams */ + +VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + int i; + int channel_count; + int loop_flag = 0; + int32_t loop_start_sample = 0; + int32_t loop_end_sample = 0; + int nwainfo_ini_found = 0; + int gameexe_ini_found = 0; + int just_pcm = 0; + int comp_level = -2; + nwa_codec_data *data = NULL; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("nwa",filename_extension(filename))) goto fail; + + channel_count = read_16bitLE(0x00,streamFile); + if (channel_count != 1 && channel_count != 2) goto fail; + + /* check if we're using raw pcm */ + if ( + read_32bitLE(0x08,streamFile)==-1 || /* compression level */ + read_32bitLE(0x10,streamFile)==0 || /* block count */ + read_32bitLE(0x18,streamFile)==0 || /* compressed data size */ + read_32bitLE(0x20,streamFile)==0 || /* block size */ + read_32bitLE(0x24,streamFile)==0 /* restsize */ + ) + { + just_pcm = 1; + } + else + { + comp_level = read_32bitLE(0x08,streamFile); + + data = malloc(sizeof(nwa_codec_data)); + if (!data) goto fail; + + data->nwa = open_nwa(streamFile,filename); + if (!data->nwa) goto fail; + } + + /* try to locate NWAINFO.INI in the same directory */ + { + char ininame[260]; + char * ini_lastslash; + char namebase_array[260]; + char *namebase; + STREAMFILE *inistreamfile; + + /* here we assume that the "special encoding" does not affect + * the directory separator */ + strncpy(ininame,filename,sizeof(ininame)); + ininame[sizeof(ininame)-1]='\0'; /* a pox on the stdlib! */ + + streamFile->get_realname(streamFile,namebase_array,sizeof(namebase_array)); + + ini_lastslash = strrchr(ininame,DIRSEP); + if (!ini_lastslash) { + strncpy(ininame,"NWAINFO.INI",sizeof(ininame)); + namebase = namebase_array; + } else { + strncpy(ini_lastslash+1,"NWAINFO.INI", + sizeof(ininame)-(ini_lastslash+1-ininame)); + namebase = strrchr(namebase_array,DIRSEP)+1; + } + ininame[sizeof(ininame)-1]='\0'; /* curse you, strncpy! */ + + inistreamfile = streamFile->open(streamFile,ininame,4096); + + if (inistreamfile) { + /* ini found, try to find our name */ + const char * ext; + int length; + int found; + off_t offset; + off_t file_size; + off_t found_off = -1; + + nwainfo_ini_found = 1; + + ext = filename_extension(namebase); + length = ext-1-namebase; + file_size = get_streamfile_size(inistreamfile); + + for (found = 0, offset = 0; !found && offset<file_size; offset++) { + off_t suboffset; + /* Go for an n*m search 'cause it's easier than building an + * FSA for the search string. Just wanted to make the point that + * I'm not ignorant, just lazy. */ + for (suboffset = offset; + suboffset<file_size && + suboffset-offset<length && + read_8bit(suboffset,inistreamfile)== + namebase[suboffset-offset]; + suboffset++) {} + + if (suboffset-offset==length && + read_8bit(suboffset,inistreamfile)==0x09) { /* tab */ + found=1; + found_off = suboffset+1; + } + } + + if (found) { + char loopstring[9]={0}; + + if (read_streamfile((uint8_t*)loopstring,found_off,8, + inistreamfile)==8) + { + loop_start_sample = atol(loopstring); + if (loop_start_sample > 0) loop_flag = 1; + } + } /* if found file name in INI */ + + close_streamfile(inistreamfile); + } /* if opened INI ok */ + } /* INI block */ + + /* try to locate Gameexe.ini in the same directory */ + { + char ininame[260]; + char * ini_lastslash; + char namebase_array[260]; + char * namebase; + STREAMFILE *inistreamfile; + + strncpy(ininame,filename,sizeof(ininame)); + ininame[sizeof(ininame)-1]='\0'; /* a pox on the stdlib! */ + + streamFile->get_realname(streamFile,namebase_array,sizeof(namebase_array)); + + ini_lastslash = strrchr(ininame,DIRSEP); + if (!ini_lastslash) { + strncpy(ininame,"Gameexe.ini",sizeof(ininame)); + namebase = namebase_array; + } else { + strncpy(ini_lastslash+1,"Gameexe.ini", + sizeof(ininame)-(ini_lastslash+1-ininame)); + namebase = strrchr(namebase_array,DIRSEP)+1; + } + ininame[sizeof(ininame)-1]='\0'; /* curse you, strncpy! */ + + inistreamfile = streamFile->open(streamFile,ininame,4096); + + if (inistreamfile) { + /* ini found, try to find our name */ + const char * ext; + int length; + int found; + off_t offset; + off_t file_size; + off_t found_off = -1; + + gameexe_ini_found = 1; + + ext = filename_extension(namebase); + length = ext-1-namebase; + file_size = get_streamfile_size(inistreamfile); + + /* format of line is: + * #DSTRACK = 00000000 - eeeeeeee - ssssssss = "name" = "name2?" + * ^22 ^33 ^45 ^57 + */ + + for (found = 0, offset = 0; !found && offset<file_size; offset++) { + off_t suboffset; + uint8_t buf[10]; + + if (read_8bit(offset,inistreamfile)!='#') continue; + if (read_streamfile(buf,offset+1,10,inistreamfile)!=10) break; + if (memcmp("DSTRACK = ",buf,10)) continue; + if (read_8bit(offset+44,inistreamfile)!='\"') continue; + + for (suboffset = offset+45; + suboffset<file_size && + suboffset-offset-45<length && + tolower(read_8bit(suboffset,inistreamfile))== + tolower(namebase[suboffset-offset-45]); + suboffset++) {} + + if (suboffset-offset-45==length && + read_8bit(suboffset,inistreamfile)=='\"') { /* tab */ + found=1; + found_off = offset+22; /* loop end */ + } + } + + if (found) { + char loopstring[9]={0}; + int start_ok = 0, end_ok = 0; + int32_t total_samples = + read_32bitLE(0x1c,streamFile)/channel_count; + + if (read_streamfile((uint8_t*)loopstring,found_off,8, + inistreamfile)==8) + { + if (!memcmp("99999999",loopstring,8)) + { + loop_end_sample = total_samples; + } + else + { + loop_end_sample = atol(loopstring); + } + end_ok = 1; + } + if (read_streamfile((uint8_t*)loopstring,found_off+11,8, + inistreamfile)==8) + { + if (!memcmp("99999999",loopstring,8)) + { + /* not ok to start at last sample, + * don't set start_ok flag */ + } + else if (!memcmp("00000000",loopstring,8)) + { + /* loops from the start aren't really loops */ + } + else + { + loop_start_sample = atol(loopstring); + start_ok = 1; + } + } + + if (start_ok && end_ok) loop_flag = 1; + } /* if found file name in INI */ + + close_streamfile(inistreamfile); + } /* if opened INI ok */ + } /* INI block */ + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + + vgmstream->num_samples = read_32bitLE(0x1c,streamFile)/channel_count; + + if (just_pcm) { + switch (read_16bitLE(0x02,streamFile)) { + case 8: + vgmstream->coding_type = coding_PCM8; + vgmstream->interleave_block_size = 1; + break; + case 16: + vgmstream->coding_type = coding_PCM16LE; + vgmstream->interleave_block_size = 2; + break; + default: + goto fail; + } + if (channel_count > 1) { + vgmstream->layout_type = layout_interleave; + } else { + vgmstream->layout_type = layout_none; + } + } + else + { + switch (comp_level) + { + case 0: + vgmstream->coding_type = coding_NWA0; + break; + case 1: + vgmstream->coding_type = coding_NWA1; + break; + case 2: + vgmstream->coding_type = coding_NWA2; + break; + case 3: + vgmstream->coding_type = coding_NWA3; + break; + case 4: + vgmstream->coding_type = coding_NWA4; + break; + case 5: + vgmstream->coding_type = coding_NWA5; + break; + default: + goto fail; + break; + } + vgmstream->layout_type = layout_none; + } + + if (nwainfo_ini_found) { + vgmstream->meta_type = meta_NWA_NWAINFOINI; + if (loop_flag) { + vgmstream->loop_start_sample = loop_start_sample; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + } else if (gameexe_ini_found) { + vgmstream->meta_type = meta_NWA_GAMEEXEINI; + if (loop_flag) { + vgmstream->loop_start_sample = loop_start_sample; + vgmstream->loop_end_sample = loop_end_sample; + } + } else { + vgmstream->meta_type = meta_NWA; + } + + + if (just_pcm) { + /* open the file for reading by each channel */ + STREAMFILE *chstreamfile; + + /* have both channels use the same buffer, as interleave is so small */ + chstreamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (!chstreamfile) goto fail; + + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = chstreamfile; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=0x2c+(off_t)(i*vgmstream->interleave_block_size); + } + } + else + { + vgmstream->codec_data = data; + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + if (data) { + if (data->nwa) + { + close_nwa(data->nwa); + } + free(data); + } + return NULL; +} diff --git a/lib/vgmstream/src/meta/ogg_vorbis_file.c b/lib/vgmstream/src/meta/ogg_vorbis_file.c new file mode 100644 index 0000000000..2aa08217a6 --- /dev/null +++ b/lib/vgmstream/src/meta/ogg_vorbis_file.c @@ -0,0 +1,292 @@ +#include "../vgmstream.h" + +#ifdef VGM_USE_VORBIS + +#include <stdio.h> +#include <string.h> +#include "meta.h" +#include "../util.h" +#include <vorbis/vorbisfile.h> + + +#define DEFAULT_BITSTREAM 0 + +static size_t read_func(void *ptr, size_t size, size_t nmemb, void * datasource) +{ + ogg_vorbis_streamfile * const ov_streamfile = datasource; + size_t items_read; + + size_t bytes_read; + + bytes_read = read_streamfile(ptr, ov_streamfile->offset, size * nmemb, + ov_streamfile->streamfile); + + items_read = bytes_read / size; + + ov_streamfile->offset += items_read * size; + + return items_read; +} + +static size_t read_func_um3(void *ptr, size_t size, size_t nmemb, void * datasource) +{ + ogg_vorbis_streamfile * const ov_streamfile = datasource; + size_t items_read; + + size_t bytes_read; + + bytes_read = read_streamfile(ptr, ov_streamfile->offset, size * nmemb, + ov_streamfile->streamfile); + + items_read = bytes_read / size; + + /* first 0x800 bytes of um3 are xor'd with 0xff */ + if (ov_streamfile->offset < 0x800) { + int num_crypt = 0x800-ov_streamfile->offset; + int i; + + if (num_crypt > bytes_read) num_crypt=bytes_read; + for (i=0;i<num_crypt;i++) + ((uint8_t*)ptr)[i] ^= 0xff; + } + + ov_streamfile->offset += items_read * size; + + return items_read; +} + +static int seek_func(void *datasource, ogg_int64_t offset, int whence) { + ogg_vorbis_streamfile * const ov_streamfile = datasource; + ogg_int64_t base_offset; + ogg_int64_t new_offset; + + switch (whence) { + case SEEK_SET: + base_offset = 0; + break; + case SEEK_CUR: + base_offset = ov_streamfile->offset; + break; + case SEEK_END: + base_offset = ov_streamfile->size; + break; + default: + return -1; + break; + } + + new_offset = base_offset + offset; + if (new_offset < 0 || new_offset > ov_streamfile->size) { + return -1; + } else { + ov_streamfile->offset = new_offset; + return 0; + } +} + +static long tell_func(void * datasource) { + ogg_vorbis_streamfile * const ov_streamfile = datasource; + return ov_streamfile->offset; +} + +/* setting close_func in ov_callbacks to NULL doesn't seem to work */ +static int close_func(void * datasource) { + return 0; +} + +/* Ogg Vorbis, by way of libvorbisfile */ + +VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + ov_callbacks callbacks; + OggVorbis_File temp_ovf; + ogg_vorbis_streamfile temp_streamfile; + + ogg_vorbis_codec_data * data = NULL; + OggVorbis_File *ovf; + int inited_ovf = 0; + vorbis_info *info; + + int loop_flag = 0; + int32_t loop_start = 0; + int loop_length_found = 0; + int32_t loop_length = 0; + int loop_end_found = 0; + int32_t loop_end = 0; + + int um3_ogg = 0; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + + /* It is only interesting to use oggs with vgmstream if they are looped. + To prevent such files from being played by other plugins and such they + may be renamed to .logg. This meta reader should still support .ogg, + though. */ + if (strcasecmp("logg",filename_extension(filename)) && + strcasecmp("ogg",filename_extension(filename)) + ) { + if(!strcasecmp("um3",filename_extension(filename))) { + um3_ogg = 1; + } + else goto fail; + } + + /* not all um3-ogg are crypted */ + if (um3_ogg && read_32bitBE(0x0,streamFile)==0x4f676753) um3_ogg = 0; + + if (um3_ogg) + callbacks.read_func = read_func_um3; + else + callbacks.read_func = read_func; + callbacks.seek_func = seek_func; + callbacks.close_func = close_func; + callbacks.tell_func = tell_func; + + temp_streamfile.streamfile = streamFile; + temp_streamfile.offset = 0; + temp_streamfile.size = get_streamfile_size(temp_streamfile.streamfile); + + /* can we open this as a proper ogg vorbis file? */ + memset(&temp_ovf, 0, sizeof(temp_ovf)); + if (ov_test_callbacks(&temp_streamfile, &temp_ovf, NULL, + 0, callbacks)) goto fail; + /* we have to close this as it has the init_vgmstream meta-reading + STREAMFILE */ + ov_clear(&temp_ovf); + + /* proceed to open a STREAMFILE just for this stream */ + data = calloc(1,sizeof(ogg_vorbis_codec_data)); + if (!data) goto fail; + + data->ov_streamfile.streamfile = streamFile->open(streamFile,filename, + STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!data->ov_streamfile.streamfile) goto fail; + data->ov_streamfile.offset = 0; + data->ov_streamfile.size = get_streamfile_size(data->ov_streamfile.streamfile); + + /* open the ogg vorbis file for real */ + if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL, + 0, callbacks)) goto fail; + ovf = &data->ogg_vorbis_file; + inited_ovf = 1; + + data->bitstream = DEFAULT_BITSTREAM; + + info = ov_info(ovf,DEFAULT_BITSTREAM); + + /* grab the comments */ + { + int i; + vorbis_comment *comment; + + comment = ov_comment(ovf,DEFAULT_BITSTREAM); + + /* search for a "loop_start" comment */ + for (i=0;i<comment->comments;i++) { + if (strstr(comment->user_comments[i],"loop_start=")== + comment->user_comments[i] || + strstr(comment->user_comments[i],"LOOP_START=")== + comment->user_comments[i] || + strstr(comment->user_comments[i],"COMMENT=LOOPPOINT=")== + comment->user_comments[i] || + strstr(comment->user_comments[i],"LOOPSTART=")== + comment->user_comments[i] || + strstr(comment->user_comments[i],"um3.stream.looppoint.start=")== + comment->user_comments[i] || + strstr(comment->user_comments[i],"LoopStart=")== + comment->user_comments[i] + ) { + loop_start=atol(strrchr(comment->user_comments[i],'=')+1); + if (loop_start >= 0) + loop_flag=1; + } + else if (strstr(comment->user_comments[i],"LOOPLENGTH=")== + comment->user_comments[i]) { + loop_length=atol(strrchr(comment->user_comments[i],'=')+1); + loop_length_found=1; + } + else if (strstr(comment->user_comments[i],"title=-lps")== + comment->user_comments[i]) { + loop_start=atol(comment->user_comments[i]+10); + if (loop_start >= 0) + loop_flag=1; + } + else if (strstr(comment->user_comments[i],"album=-lpe")== + comment->user_comments[i]) { + loop_end=atol(comment->user_comments[i]+10); + loop_flag=1; + loop_end_found=1; + } + else if (strstr(comment->user_comments[i],"LoopEnd=")== + comment->user_comments[i]) { + if(loop_flag) { + loop_length=atol(strrchr(comment->user_comments[i],'=')+1)-loop_start; + loop_length_found=1; + } + } + else if (strstr(comment->user_comments[i],"lp=")== + comment->user_comments[i]) { + sscanf(strrchr(comment->user_comments[i],'=')+1,"%d,%d", + &loop_start,&loop_end); + loop_flag=1; + loop_end_found=1; + } + } + } + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(info->channels,loop_flag); + if (!vgmstream) goto fail; + + /* store our fun extra datas */ + vgmstream->codec_data = data; + + /* fill in the vital statistics */ + vgmstream->channels = info->channels; + vgmstream->sample_rate = info->rate; + + /* let's play the whole file */ + vgmstream->num_samples = ov_pcm_total(ovf,-1); + + if (loop_flag) { + vgmstream->loop_start_sample = loop_start; + if (loop_length_found) + vgmstream->loop_end_sample = loop_start+loop_length; + else if (loop_end_found) + vgmstream->loop_end_sample = loop_end; + else + vgmstream->loop_end_sample = vgmstream->num_samples; + vgmstream->loop_flag = loop_flag; + + if (vgmstream->loop_end_sample > vgmstream->num_samples) + vgmstream->loop_end_sample = vgmstream->num_samples; + } + vgmstream->coding_type = coding_ogg_vorbis; + vgmstream->layout_type = layout_ogg_vorbis; + if (um3_ogg) + vgmstream->meta_type = meta_um3_ogg; + else + vgmstream->meta_type = meta_ogg_vorbis; + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (data) { + if (inited_ovf) + ov_clear(&data->ogg_vorbis_file); + if (data->ov_streamfile.streamfile) + close_streamfile(data->ov_streamfile.streamfile); + free(data); + } + if (vgmstream) { + vgmstream->codec_data = NULL; + close_vgmstream(vgmstream); + } + return NULL; +} + +#endif diff --git a/lib/vgmstream/src/meta/pcm.c b/lib/vgmstream/src/meta/pcm.c new file mode 100644 index 0000000000..1092aa2a33 --- /dev/null +++ b/lib/vgmstream/src/meta/pcm.c @@ -0,0 +1,115 @@ +#include "meta.h" +#include "../util.h" + +/* PCM (from Ephemeral Fantasia) */ +VGMSTREAM * init_vgmstream_pcm(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("pcm",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0C,streamFile) ==0x0AA00AA0) { + + loop_flag = (read_32bitLE(0x02,streamFile)!=0); + channel_count = 1; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x200; + vgmstream->channels = channel_count; + vgmstream->sample_rate = 44100; + vgmstream->coding_type = coding_PCM8_SB_int; + vgmstream->num_samples = read_32bitBE(0x06,streamFile)*2; + + if(loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x02,streamFile)*2; + vgmstream->loop_end_sample = read_32bitBE(0x06,streamFile)*2; + } + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + vgmstream->meta_type = meta_PCM; + + } else if (read_32bitBE(0x410,streamFile) ==0x9CDB0740) { + + loop_flag = (read_32bitLE(0x0C,streamFile)!=0); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = 22050; + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = read_32bitLE(0x4,streamFile); + + if(loop_flag == 1) { + vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + vgmstream->meta_type = meta_PCM; + } else if ((read_32bitBE(0x0,streamFile) ==0x786D6402) || + (read_32bitBE(0x0,streamFile) ==0x786D6401)) { + loop_flag = 0; + channel_count = read_8bit(0x03,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x10; + vgmstream->channels = channel_count; + vgmstream->sample_rate = (int32_t)(read_16bitLE(0x4,streamFile) & 0x0000ffff); + vgmstream->coding_type = coding_PCM8_int; + vgmstream->num_samples = read_32bitLE(0x6,streamFile); + + if(loop_flag == 1) { + vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x8; + vgmstream->meta_type = meta_PCM; + } else + goto fail; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/pos.c b/lib/vgmstream/src/meta/pos.c new file mode 100644 index 0000000000..aac9291bff --- /dev/null +++ b/lib/vgmstream/src/meta/pos.c @@ -0,0 +1,66 @@ +#include <ctype.h> +#include "meta.h" +#include "../util.h" + +#ifdef WIN32 +#define DIRSEP '\\' +#else +#define DIRSEP '/' +#endif + +/* .pos is a tiny file with loop points, and the same base name as a .wav */ + +VGMSTREAM * init_vgmstream_pos(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamFileWAV = NULL; + char filename[260]; + char filenameWAV[260]; + + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("pos",filename_extension(filename))) goto fail; + + /* check for .WAV file */ + strcpy(filenameWAV,filename); + strcpy(filenameWAV+strlen(filenameWAV)-3,"wav"); + + streamFileWAV = streamFile->open(streamFile,filenameWAV,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!streamFileWAV) { + /* try again, ucase */ + for (i=strlen(filenameWAV);i>=0&&filenameWAV[i]!=DIRSEP;i--) + filenameWAV[i]=toupper(filenameWAV[i]); + + streamFileWAV = streamFile->open(streamFile,filenameWAV,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!streamFileWAV) goto fail; + } + + /* let the real initer do the parsing */ + vgmstream = init_vgmstream_riff(streamFileWAV); + if (!vgmstream) goto fail; + + close_streamfile(streamFileWAV); + streamFileWAV = NULL; + + /* install loops */ + if (!vgmstream->loop_flag) { + vgmstream->loop_flag = 1; + vgmstream->loop_ch = calloc(vgmstream->channels, + sizeof(VGMSTREAMCHANNEL)); + if (!vgmstream->loop_ch) goto fail; + } + + vgmstream->loop_start_sample = read_32bitLE(0,streamFile); + vgmstream->loop_end_sample = read_32bitLE(4,streamFile); + vgmstream->meta_type = meta_RIFF_WAVE_POS; + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (streamFileWAV) close_streamfile(streamFileWAV); + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_ads.c b/lib/vgmstream/src/meta/ps2_ads.c new file mode 100644 index 0000000000..b840017d5c --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_ads.c @@ -0,0 +1,141 @@ +#include "meta.h" +#include "../util.h" + +/* Sony .ADS with SShd & SSbd Headers */ + +VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + off_t start_offset; + + uint8_t testBuffer[0x10]; + off_t readOffset = 0; + off_t loopEnd = 0; + + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ads",filename_extension(filename)) && + strcasecmp("ss2",filename_extension(filename))) goto fail; + + /* check SShd Header */ + if (read_32bitBE(0x00,streamFile) != 0x53536864) + goto fail; + + /* check SSbd Header */ + if (read_32bitBE(0x20,streamFile) != 0x53536264) + goto fail; + + /* check if file is not corrupt */ + if (get_streamfile_size(streamFile)<(size_t)(read_32bitLE(0x24,streamFile) + 0x28)) + goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x1C,streamFile)!=0xFFFFFFFF); + + channel_count=read_32bitLE(0x10,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = read_32bitLE(0x10,streamFile); + vgmstream->sample_rate = read_32bitLE(0x0C,streamFile); + + /* Check for Compression Scheme */ + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = ((read_32bitLE(0x24,streamFile)-0x40)/16*28)/vgmstream->channels; + + /* SS2 container with RAW Interleaved PCM */ + if (read_32bitLE(0x08,streamFile)!=0x10) { + vgmstream->coding_type=coding_PCM16LE; + vgmstream->num_samples = read_32bitLE(0x24,streamFile)/2/vgmstream->channels; + } + + vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile); + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_SShd; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + if((read_32bitLE(0x1C,streamFile)*0x10*vgmstream->channels+0x800)==get_streamfile_size(streamFile)) + { + // Search for Loop Value + readOffset=(off_t)get_streamfile_size(streamFile)-(4*vgmstream->interleave_block_size); + + do { + readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); + + // Loop End ... + if(testBuffer[0x01]==0x01) { + if(loopEnd==0) loopEnd = readOffset-0x10; + break; + } + + } while (streamFile->get_offset(streamFile)<(int32_t)get_streamfile_size(streamFile)); + + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (loopEnd/(vgmstream->interleave_block_size)*vgmstream->interleave_block_size)/16*28; + vgmstream->loop_end_sample += (loopEnd%vgmstream->interleave_block_size)/16*28; + vgmstream->loop_end_sample /=vgmstream->channels; + + } else { + if(read_32bitLE(0x1C,streamFile)<=vgmstream->num_samples) { + vgmstream->loop_start_sample = read_32bitLE(0x18,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x1C,streamFile); + } else { + vgmstream->loop_start_sample = (read_32bitLE(0x18,streamFile)*0x10)/16*28/vgmstream->channels;; + vgmstream->loop_end_sample = (read_32bitLE(0x1C,streamFile)*0x10)/16*28/vgmstream->channels; + } + } + } + + /* don't know why, but it does happen, in ps2 too :( */ + if (vgmstream->loop_end_sample > vgmstream->num_samples) + vgmstream->loop_end_sample = vgmstream->num_samples; + + start_offset=0x28; + + // Hack for files with start_offset = 0x800 + if(get_streamfile_size(streamFile)-read_32bitLE(0x24,streamFile)>=0x800) + start_offset=0x800; + + if((vgmstream->coding_type == coding_PSX) && (start_offset==0x28)) { + start_offset=0x800; + for(i=0;i<0x1f6;i+=4) { + if(read_32bitLE(0x28+(i*4),streamFile)!=0) { + start_offset=0x28; + break; + } + } + } + + /* expect pcm format allways start @ 0x800, don't know if it's true :P */ + /*if(vgmstream->coding_type == coding_PCM16LE) + start_offset=0x800;*/ + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(start_offset+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_ass.c b/lib/vgmstream/src/meta/ps2_ass.c new file mode 100644 index 0000000000..eba5375620 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_ass.c @@ -0,0 +1,92 @@ +#include "meta.h" +#include "../util.h" + +/* SVS (from Dai Senryaku VII - Exceed) */ + +VGMSTREAM * init_vgmstream_ps2_ass(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + uint8_t testBuffer[0x10]; + off_t loopStart = 0; + off_t loopEnd = 0; + off_t readOffset = 0; + size_t fileLength; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ass",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x02000000) /* "0x02000000" */ + goto fail; + + loop_flag = 1; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x08,streamFile)*2)*28/16/channel_count; + + fileLength = get_streamfile_size(streamFile); + + do { + + readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); + /* Loop Start */ + if(testBuffer[0x01]==0x06) { + if(loopStart == 0) loopStart = readOffset-0x10; + /* break; */ + } + /* Loop End */ + if(testBuffer[0x01]==0x03) { + if(loopEnd == 0) loopEnd = readOffset-0x10; + /* break; */ + } + } while (streamFile->get_offset(streamFile)<(int32_t)fileLength); + + if(loopStart == 0) { + loop_flag = 0; + vgmstream->num_samples = read_32bitLE(0x4,streamFile)*28/16/channel_count; + } else { + loop_flag = 1; + vgmstream->loop_start_sample = (loopStart-start_offset)*28/16/channel_count; + vgmstream->loop_end_sample = (loopEnd-start_offset)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile); + vgmstream->meta_type = meta_PS2_ASS; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_aus.c b/lib/vgmstream/src/meta/ps2_aus.c new file mode 100644 index 0000000000..994b31af14 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_aus.c @@ -0,0 +1,71 @@ +#include "meta.h" +#include "../util.h" + +/* AUS (found in various Capcom games) */ +VGMSTREAM * init_vgmstream_aus(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("aus",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x41555320) /* "AUS " */ + goto fail; + + loop_flag = (read_32bitLE(0x0c,streamFile)!=0); + channel_count = read_32bitLE(0xC,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->num_samples = read_32bitLE(0x08,streamFile); + + if(read_16bitLE(0x06,streamFile)==0x02) { + vgmstream->coding_type = coding_XBOX; + vgmstream->layout_type=layout_none; + } else { + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x800; + } + + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x08,streamFile); + } + + vgmstream->meta_type = meta_AUS; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_bg00.c b/lib/vgmstream/src/meta/ps2_bg00.c new file mode 100644 index 0000000000..273c08fe39 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_bg00.c @@ -0,0 +1,65 @@ +#include "meta.h" +#include "../util.h" + +/* BG0 (from Ibara, Mushihimesama) +Note: Seems the Loop Infos are stored external... */ +VGMSTREAM * init_vgmstream_bg00(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("bg00",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x42473030) /* "BG00" */ + goto fail; + + loop_flag = (read_32bitLE(0x08,streamFile)!=0); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x80,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitBE(0x4C,streamFile)*2)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (read_32bitBE(0x4C,streamFile)*2)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile); + vgmstream->meta_type = meta_BG00; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_bmdx.c b/lib/vgmstream/src/meta/ps2_bmdx.c new file mode 100644 index 0000000000..34d08102e6 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_bmdx.c @@ -0,0 +1,92 @@ +#include "meta.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_ps2_bmdx(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + int loop_flag=0; + int channel_count; + off_t start_offset; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("bmdx",filename_extension(filename))) goto fail; + + /* check NPSF Header */ + if (read_32bitBE(0x00,streamFile) != 0x01006408 || + read_32bitBE(0x04,streamFile) != 0) + goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x10,streamFile)!=0); + channel_count=read_32bitLE(0x1C,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x18,streamFile); + + /* Check for Compression Scheme */ + if (read_32bitLE(0x20,streamFile) == 1) + vgmstream->coding_type = coding_invert_PSX; + else + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x0c,streamFile)*28/16/channel_count; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x10,streamFile)*28/16/channel_count; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + if (channel_count == 1) { + vgmstream->layout_type = layout_none; + } else if (channel_count > 1) { + vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile); + vgmstream->layout_type = layout_interleave; + } + + vgmstream->meta_type = meta_PS2_BMDX; + + start_offset = read_32bitLE(0x08,streamFile); + + if (vgmstream->coding_type == coding_invert_PSX) + { + uint8_t xor = read_8bit(start_offset,streamFile); + uint8_t add = (~(uint8_t)read_8bit(start_offset+2,streamFile))+1; + int c; + for (c=0;c<channel_count;c++) { + vgmstream->ch[c].bmdx_xor = xor; + vgmstream->ch[c].bmdx_add = add; + } + } + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + if (!vgmstream->ch[0].streamfile) { + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,0x8000); + } + vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile; + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(start_offset+vgmstream->interleave_block_size*i); + } + } + + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_ccc.c b/lib/vgmstream/src/meta/ps2_ccc.c new file mode 100644 index 0000000000..c665b48a54 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_ccc.c @@ -0,0 +1,68 @@ +#include "meta.h" +#include "../util.h" + +/* CCC */ +VGMSTREAM * init_vgmstream_ps2_ccc(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ccc",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x01000000) + goto fail; + + /* check file size */ + if (read_32bitLE(0x0C,streamFile)+0x50 != get_streamfile_size(streamFile)) + goto fail; + + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x50; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x08,streamFile))/channel_count/32*28; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (read_32bitLE(0x08,streamFile))/channel_count/32*28; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2000; + vgmstream->meta_type = meta_PS2_CCC; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_dxh.c b/lib/vgmstream/src/meta/ps2_dxh.c new file mode 100644 index 0000000000..2b1d1411aa --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_dxh.c @@ -0,0 +1,76 @@ +#include "meta.h" +#include "../util.h" + +/* DXH (from Tokobot Plus - Mysteries of the Karakuri) */ +VGMSTREAM * init_vgmstream_ps2_dxh(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("dxh",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x00445848) /* 0\DXH" */ + goto fail; + + loop_flag = (read_32bitLE(0x50,streamFile)!=0); + channel_count = read_32bitLE(0x08,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x20,streamFile); + + if (read_32bitBE(0x54,streamFile) == 0) { + /* if (loop_flag) { */ + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = get_streamfile_size(streamFile)*28/16/channel_count; + vgmstream->num_samples = get_streamfile_size(streamFile)*28/16/channel_count; + /* } */ + + } else { + + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitLE(0x50,streamFile)*0x20)*28/16/channel_count; + vgmstream->loop_end_sample = (read_32bitLE(0x54,streamFile)*0x20)*28/16/channel_count; + vgmstream->num_samples = (read_32bitLE(0x54,streamFile)*0x20)*28/16/channel_count; + + } +} + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile); + vgmstream->meta_type = meta_PS2_DXH; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_enth.c b/lib/vgmstream/src/meta/ps2_enth.c new file mode 100644 index 0000000000..fa495b79e5 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_enth.c @@ -0,0 +1,94 @@ +#include "meta.h" +#include "../util.h" + +/* ENTH (from Enthusia - Professional Racing) */ +VGMSTREAM * init_vgmstream_ps2_enth(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int header_check; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("enth",filename_extension(filename))) goto fail; + + /* check header and loop_flag */ + header_check = read_32bitBE(0x00,streamFile); + switch (header_check) { + case 0x41502020: /* AP */ + loop_flag = (read_32bitLE(0x14,streamFile)!=0); + break; + case 0x4C455020: /* LEP */ + loop_flag = (read_32bitLE(0x58,streamFile)!=0); + break; + default: + goto fail; + } + + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + header_check = read_32bitBE(0x00,streamFile); + + switch (header_check) { + case 0x41502020: /* AP */ + start_offset = read_32bitLE(0x1C,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x18,streamFile))*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitLE(0x14,streamFile))*28/16/channel_count; + vgmstream->loop_end_sample = (read_32bitLE(0x18,streamFile))*28/16/channel_count; + } + vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile); + break; + case 0x4C455020: /* LEP */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = (uint16_t)read_16bitLE(0x12,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x08,streamFile))*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitLE(0x58,streamFile))*28/16/channel_count; + vgmstream->loop_end_sample = (read_32bitLE(0x08,streamFile))*28/16/channel_count; + } + vgmstream->interleave_block_size = 0x10; + break; + default: + goto fail; +} + + + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_ENTH; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_exst.c b/lib/vgmstream/src/meta/ps2_exst.c new file mode 100644 index 0000000000..5451262255 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_exst.c @@ -0,0 +1,79 @@ +#include "meta.h" +#include "../util.h" + +/* EXST + + PS2 INT format is an interleaved format found in Shadow of the Colossus + The header start with a EXST id. + The headers and bgm datas was separated in the game, and joined in order + to add support for vgmstream + + The interleave value is allways 0x400 + known extensions : .STS + + 2008-05-13 - Fastelbja : First version ... +*/ + +VGMSTREAM * init_vgmstream_ps2_exst(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sts",filename_extension(filename))) goto fail; + + /* check EXST Header */ + if (read_32bitBE(0x00,streamFile) != 0x45585354) + goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x0C,streamFile)==1); + + channel_count=read_16bitLE(0x06,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = read_16bitLE(0x06,streamFile); + vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + + /* Compression Scheme */ + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x14,streamFile)*0x400)/16*28; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = (read_32bitLE(0x10,streamFile)*0x400)/16*28; + vgmstream->loop_end_sample = (read_32bitLE(0x14,streamFile)*0x400)/16*28; + } + + vgmstream->interleave_block_size = 0x400; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_EXST; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(0x78+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_filp.c b/lib/vgmstream/src/meta/ps2_filp.c new file mode 100644 index 0000000000..372d0b90b8 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_filp.c @@ -0,0 +1,67 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* FILp (Resident Evil - Dead Aim) */ +VGMSTREAM * init_vgmstream_filp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("filp",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x46494C70) /* "FILp" */ + goto fail; + if (read_32bitBE(0x100,streamFile) != 0x56414770) /* "VAGp" */ + goto fail; + if (read_32bitBE(0x130,streamFile) != 0x56414770) /* "VAGp" */ + goto fail; + if (get_streamfile_size(streamFile) != read_32bitLE(0xC,streamFile)) + goto fail; + + loop_flag = (read_32bitLE(0x34,streamFile) == 0); + channel_count = read_32bitLE(0x4,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x0; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x110,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_filp_blocked; + vgmstream->meta_type = meta_FILP; + + /* open the file for reading */ + { + 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; + } + } + + filp_block_update(start_offset,vgmstream); + vgmstream->num_samples = read_32bitLE(0x10C,streamFile)/16*28; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_gbts.c b/lib/vgmstream/src/meta/ps2_gbts.c new file mode 100644 index 0000000000..858be05fb5 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_gbts.c @@ -0,0 +1,92 @@ +#include "meta.h" +#include "../util.h" + +/* GBTS : Pop'n'Music 9 Bgm File */ + +VGMSTREAM * init_vgmstream_ps2_gbts(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + off_t start_offset; + off_t loopStart = 0; + off_t loopEnd = 0; + size_t filelength; + + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("gbts",filename_extension(filename))) goto fail; + + /* check loop */ + start_offset=0x801; + + filelength = get_streamfile_size(streamFile); + do { + // Loop Start ... + if(read_8bit(start_offset,streamFile)==0x06) { + if(loopStart==0) loopStart = start_offset-0x801; + } + + // Loop End ... + if(read_8bit(start_offset,streamFile)==0x03) { + if(loopEnd==0) loopEnd = start_offset-0x801-0x10; + } + + start_offset+=0x10; + + } while (start_offset<(int32_t)filelength); + + loop_flag = (loopEnd!=0); + channel_count=read_32bitLE(0x1C,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x18,streamFile);; + + /* Check for Compression Scheme */ + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x0C,streamFile)/16*28/vgmstream->channels; + vgmstream->interleave_block_size = 0x10; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = (loopStart/(vgmstream->interleave_block_size)*vgmstream->interleave_block_size)/16*28; + vgmstream->loop_start_sample += (loopStart%vgmstream->interleave_block_size)/16*28; + vgmstream->loop_start_sample /=vgmstream->channels; + vgmstream->loop_end_sample = (loopEnd/(vgmstream->interleave_block_size)*vgmstream->interleave_block_size)/16*28; + vgmstream->loop_end_sample += (loopEnd%vgmstream->interleave_block_size)/16*28; + vgmstream->loop_end_sample /=vgmstream->channels; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_GBTS; + + start_offset = (off_t)0x800; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(start_offset+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_hgc1.c b/lib/vgmstream/src/meta/ps2_hgc1.c new file mode 100644 index 0000000000..081a2f15e9 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_hgc1.c @@ -0,0 +1,64 @@ +#include "meta.h" +#include "../util.h" + +/* hgC1 (from Knights of the Temple 2) */ +VGMSTREAM * init_vgmstream_hgc1(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("hgc1",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x68674331) /* "hgC1" */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x08,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x40; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x0C,streamFile)*32)/channel_count/16*28; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (read_32bitLE(0x0C,streamFile)*32)/channel_count/16*28; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + vgmstream->meta_type = meta_HGC1; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_ikm.c b/lib/vgmstream/src/meta/ps2_ikm.c new file mode 100644 index 0000000000..d644174830 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_ikm.c @@ -0,0 +1,65 @@ +#include "meta.h" +#include "../util.h" + +/* IKM (found in Zwei!) */ +VGMSTREAM * init_vgmstream_ikm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ikm",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x494B4D00) /* "IKM\0" */ + goto fail; + if (read_32bitBE(0x40,streamFile) != 0x41535400) /* AST\0 */ + goto fail; + + loop_flag = (read_32bitLE(0x14,streamFile)!=0); /* Not sure */ + channel_count = read_32bitLE(0x50,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x44,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x4C,streamFile)-start_offset)/16/channel_count*28; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + vgmstream->meta_type = meta_IKM; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_ild.c b/lib/vgmstream/src/meta/ps2_ild.c new file mode 100644 index 0000000000..5649444b59 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_ild.c @@ -0,0 +1,69 @@ +#include "meta.h" +#include "../util.h" + +/* ILD */ + +VGMSTREAM * init_vgmstream_ps2_ild(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + int loop_flag=0; + int channel_count; + off_t start_offset; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ild",filename_extension(filename))) goto fail; + + /* check ILD Header */ + if (read_32bitBE(0x00,streamFile) != 0x494C4400) + goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x2C,streamFile)!=0); + channel_count=read_32bitLE(0x04,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = read_32bitLE(0x04,streamFile); + vgmstream->sample_rate = read_32bitLE(0x28,streamFile); + + /* Check for Compression Scheme */ + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x0C,streamFile)/16*28/vgmstream->channels; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x2C,streamFile)/16*28; + vgmstream->loop_end_sample = read_32bitLE(0x30,streamFile)/16*28; + } + + vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile)/2; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_ILD; + + start_offset = (off_t)read_32bitLE(0x08,streamFile); + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(start_offset+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_int.c b/lib/vgmstream/src/meta/ps2_int.c new file mode 100644 index 0000000000..5debb2a20c --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_int.c @@ -0,0 +1,115 @@ +#include "meta.h" +#include "../util.h" + +/* INT + + PS2 INT format is a RAW 48khz PCM file without header + The only fact about those file, is that the raw is interleaved + + The interleave value is allways 0x200 + known extensions : INT + + 2008-05-11 - Fastelbja : First version ... +*/ + +VGMSTREAM * init_vgmstream_ps2_int(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + int i,channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("int",filename_extension(filename)) && + strcasecmp("wp2",filename_extension(filename))) goto fail; + + if(!strcasecmp("int",filename_extension(filename))) + channel_count = 2; + else + channel_count = 4; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,0); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels=channel_count; + vgmstream->sample_rate = 48000; + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = (int32_t)(get_streamfile_size(streamFile)/(vgmstream->channels*2)); + vgmstream->interleave_block_size = 0x200; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_RAW; + + /* open the file for reading by each channel */ + { + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=i*vgmstream->interleave_block_size; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + +// OMU is a PS2 .INT file with header ... +// found in Alter Echo +VGMSTREAM * init_vgmstream_ps2_omu(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + int i,channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("omu",filename_extension(filename))) goto fail; + + /* check header */ + if((read_32bitBE(0,streamFile)!=0x4F4D5520) && (read_32bitBE(0x08,streamFile)!=0x46524D54)) + goto fail; + + channel_count = (int)read_8bit(0x14,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,1); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels=channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = (int32_t)(read_32bitLE(0x3C,streamFile)/(vgmstream->channels*2)); + vgmstream->interleave_block_size = 0x200; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_OMU; + + vgmstream->loop_start_sample=0; + vgmstream->loop_end_sample=vgmstream->num_samples; + + /* open the file for reading by each channel */ + { + for (i=0;i<vgmstream->channels;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=0x40+(i*vgmstream->interleave_block_size); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_joe.c b/lib/vgmstream/src/meta/ps2_joe.c new file mode 100644 index 0000000000..1faf055be3 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_joe.c @@ -0,0 +1,94 @@ +#include "meta.h" +#include "../util.h" + +/* JOE (found in Wall-E and some more Pixar games) */ +VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + uint8_t testBuffer[0x10]; + off_t loopStart = 0; + off_t loopEnd = 0; + off_t readOffset = 0; + size_t fileLength; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("joe",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0C,streamFile) != 0xCCCCCCCC) + goto fail; + + loop_flag = 1; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x4020; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x0,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)*28/16/channel_count; + + + fileLength = get_streamfile_size(streamFile); + + do { + + readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); + + /* Loop Start */ + if(testBuffer[0x01]==0x06) { + if(loopStart == 0) loopStart = readOffset-0x10; + /* break; */ + } + /* Loop End */ + if(testBuffer[0x01]==0x03) { + if(loopEnd == 0) loopEnd = readOffset-0x10; + /* break; */ + } + + } while (streamFile->get_offset(streamFile)<(int32_t)fileLength); + + if(loopStart == 0) { + loop_flag = 0; + vgmstream->num_samples = read_32bitLE(0x4,streamFile)*28/16/channel_count; + } else { + loop_flag = 1; + vgmstream->loop_start_sample = (loopStart-start_offset-0x20)*28/16/channel_count; + vgmstream->loop_end_sample = (loopEnd-start_offset+0x20)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + vgmstream->meta_type = meta_PS2_JOE; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_kces.c b/lib/vgmstream/src/meta/ps2_kces.c new file mode 100644 index 0000000000..0d803939c8 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_kces.c @@ -0,0 +1,71 @@ +#include "meta.h" +#include "../util.h" + +/* KCES (from Dance Dance Revolution) */ +VGMSTREAM * init_vgmstream_ps2_kces(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("kces",filename_extension(filename)) && + strcasecmp("vig",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x01006408) + goto fail; + + loop_flag = 0; /* (read_32bitLE(0x08,streamFile)!=0); */ + channel_count = read_32bitLE(0x1C,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x08,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x18,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x0C,streamFile)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile)*28/16/channel_count; + } + + + if(vgmstream->channels==1) { + vgmstream->layout_type=layout_none; + } else { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile); + } + vgmstream->meta_type = meta_PS2_KCES; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_leg.c b/lib/vgmstream/src/meta/ps2_leg.c new file mode 100644 index 0000000000..8fa85b9c94 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_leg.c @@ -0,0 +1,66 @@ +#include "meta.h" +#include "../util.h" + +/* LEG - found in Legaia 2 - Duel Saga (PS2) +the headers are stored seperately in the main executable... */ +VGMSTREAM * init_vgmstream_leg(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("leg",filename_extension(filename))) goto fail; + + /* comparing the filesize with (num_samples*0x800) + headersize, + if it doesn't match, we will abort the vgmstream... */ + if ((read_32bitLE(0x48,streamFile)*0x800)+0x4C != get_streamfile_size(streamFile)) + goto fail; + + loop_flag = (read_32bitLE(0x44,streamFile)!=0); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x4C; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x40,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x48,streamFile)*0x800)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitLE(0x44,streamFile)*0x800)*28/16/channel_count; + vgmstream->loop_end_sample = (read_32bitLE(0x48,streamFile)*0x800)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x400; + vgmstream->meta_type = meta_LEG; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_mib.c b/lib/vgmstream/src/meta/ps2_mib.c new file mode 100644 index 0000000000..375488a9e9 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_mib.c @@ -0,0 +1,170 @@ +#include "meta.h" +#include "../util.h" + +/* MIB + + PS2 MIB format is a headerless format. + The interleave value can be found by checking the body of the data. + + The interleave start allways at offset 0 with a int value (which can have + many values : 0x0000, 0x0002, 0x0006 etc...) follow by 12 empty (zero) values. + + The interleave value is the offset where you found the same 16 bytes. + + The n° of channels can be found by checking each time you found this 16 bytes. + + The interleave value can be very "large" (up to 0x20000 found so far) and is allways + a 0x10 multiply value. + + The loop values can be found by checking the 'tags' offset (found @ 0x02 each 0x10 bytes). + 06 = start of the loop point (can be found for each channel) + 03 - end of the loop point (can be found for each channel) + + The .MIH header contains all informations about frequency, numbers of channels, interleave + but has, afaik, no loop values. + + known extensions : MIB (MIH for the header) MIC (concatenation of MIB+MIH) + Nota : the MIC stuff is not supported here as there is + another MIC format which can be found in Koei Games. + + 2008-05-14 - Fastelbja : First version ... + 2008-05-20 - Fastelbja : Fix loop value when loopEnd==0 +*/ + +VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamFileMIH = NULL; + char filename[260]; + + uint8_t mibBuffer[0x10]; + uint8_t testBuffer[0x10]; + + size_t fileLength; + + off_t loopStart = 0; + off_t loopEnd = 0; + off_t interleave = 0; + off_t readOffset = 0; + + char filenameMIH[260]; + + uint8_t gotMIH=0; + + int i, channel_count=1; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("mib",filename_extension(filename)) && + strcasecmp("mi4",filename_extension(filename))) goto fail; + + /* check for .MIH file */ + strcpy(filenameMIH,filename); + strcpy(filenameMIH+strlen(filenameMIH)-3,"MIH"); + + streamFileMIH = streamFile->open(streamFile,filenameMIH,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (streamFileMIH) gotMIH = 1; + + /* Search for interleave value & loop points */ + /* Get the first 16 values */ + fileLength = get_streamfile_size(streamFile); + + readOffset+=(off_t)read_streamfile(mibBuffer,0,0x10,streamFile); + + do { + readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); + + if(!memcmp(testBuffer,mibBuffer,0x10)) { + if(interleave==0) interleave=readOffset-0x10; + + // be sure to point to an interleave value + if(((readOffset-0x10)==channel_count*interleave)) { + channel_count++; + } + } + + // Loop Start ... + if(testBuffer[0x01]==0x06) { + if(loopStart==0) loopStart = readOffset-0x10; + } + + // Loop End ... + if(testBuffer[0x01]==0x03) { + if(loopEnd==0) loopEnd = readOffset-0x10; + } + + } while (streamFile->get_offset(streamFile)<(int32_t)fileLength); + + if(gotMIH) + channel_count=read_32bitLE(0x08,streamFileMIH); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,((loopStart!=0) && (loopEnd!=0))); + if (!vgmstream) goto fail; + + if(interleave==0) interleave=0x10; + + /* fill in the vital statistics */ + if(gotMIH) { + // Read stuff from the MIH file + vgmstream->channels = read_32bitLE(0x08,streamFileMIH); + vgmstream->sample_rate = read_32bitLE(0x0C,streamFileMIH); + vgmstream->interleave_block_size = read_32bitLE(0x10,streamFileMIH); + vgmstream->num_samples=((read_32bitLE(0x10,streamFileMIH)* + (read_32bitLE(0x14,streamFileMIH)-1)*2)+ + ((read_32bitLE(0x04,streamFileMIH)>>8)*2))/16*28/2; + } else { + vgmstream->channels = channel_count; + vgmstream->interleave_block_size = interleave; + + if(!strcasecmp("mib",filename_extension(filename))) + vgmstream->sample_rate = 44100; + + if(!strcasecmp("mi4",filename_extension(filename))) + vgmstream->sample_rate = 48000; + + vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28); + } + + if(loopStart!=0) { + if(vgmstream->channels==1) { + vgmstream->loop_start_sample = loopStart/16*18; + vgmstream->loop_end_sample = loopEnd/16*28; + } else { + vgmstream->loop_start_sample = ((loopStart/(interleave*channel_count))*interleave)/16*14*(2/channel_count); + vgmstream->loop_start_sample += (loopStart%(interleave*channel_count))/16*14*(2/channel_count); + vgmstream->loop_end_sample = ((loopEnd/(interleave*channel_count))*interleave)/16*28*(2/channel_count); + vgmstream->loop_end_sample += (loopEnd%(interleave*channel_count))/16*14*(2/channel_count); + } + } + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + + vgmstream->meta_type = meta_PS2_MIB; + + if (gotMIH) { + vgmstream->meta_type = meta_PS2_MIB_MIH; + close_streamfile(streamFileMIH); streamFileMIH=NULL; + } + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=i*vgmstream->interleave_block_size; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (streamFileMIH) close_streamfile(streamFileMIH); + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_mic.c b/lib/vgmstream/src/meta/ps2_mic.c new file mode 100644 index 0000000000..89a615d200 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_mic.c @@ -0,0 +1,75 @@ +#include "meta.h" +#include "../util.h" + +/* MIC + + PS2 MIC format is an interleaved format found in most of KOEI Games + The header always start the long value 0x800 which is the start + of the BGM datas. + + 2008-05-15 - Fastelbja : First version ... +*/ + +VGMSTREAM * init_vgmstream_ps2_mic(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("mic",filename_extension(filename))) goto fail; + + /* check Header */ + if (read_32bitLE(0x00,streamFile) != 0x800) + goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x14,streamFile)!=1); + + channel_count=read_32bitLE(0x08,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + + /* Compression Scheme */ + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x10,streamFile)*14*channel_count; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile)*14*channel_count; + vgmstream->loop_end_sample = read_32bitLE(0x10,streamFile)*14*channel_count; + } + + vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile); + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_MIC; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(0x800+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_mihb.c b/lib/vgmstream/src/meta/ps2_mihb.c new file mode 100644 index 0000000000..687157f2f2 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_mihb.c @@ -0,0 +1,66 @@ +#include "meta.h" +#include "../util.h" + +/* MIHB (Merged MIH+MIB) */ +VGMSTREAM * init_vgmstream_ps2_mihb(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int mib_blocks; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("mihb",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x40000000) + goto fail; + + mib_blocks = read_32bitLE(0x14,streamFile); + loop_flag = 0; + channel_count = read_32bitLE(0x08,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x40; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x0C,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x10,streamFile))*mib_blocks*channel_count/32*28; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (read_32bitLE(0x10,streamFile))*mib_blocks*channel_count/32*28; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile); + vgmstream->meta_type = meta_PS2_MIHB; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_npsf.c b/lib/vgmstream/src/meta/ps2_npsf.c new file mode 100644 index 0000000000..69cc4e389e --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_npsf.c @@ -0,0 +1,70 @@ +#include "meta.h" +#include "../util.h" + +/* Sony .ADS with SShd & SSbd Headers */ + +VGMSTREAM * init_vgmstream_ps2_npsf(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + off_t start_offset; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("npsf",filename_extension(filename))) goto fail; + + /* check NPSF Header */ + if (read_32bitBE(0x00,streamFile) != 0x4E505346) + goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x14,streamFile)!=0xFFFFFFFF); + channel_count=read_32bitLE(0x0C,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = read_32bitLE(0x0C,streamFile); + vgmstream->sample_rate = read_32bitLE(0x18,streamFile); + + /* Check for Compression Scheme */ + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x08,streamFile)*28/16; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x08,streamFile)*28/16; + } + + vgmstream->interleave_block_size = read_32bitLE(0x04,streamFile)/2; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_NPSF; + + start_offset = (off_t)read_32bitLE(0x10,streamFile); + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(start_offset+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_p2bt.c b/lib/vgmstream/src/meta/ps2_p2bt.c new file mode 100644 index 0000000000..ff34cd84e6 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_p2bt.c @@ -0,0 +1,70 @@ +#include "meta.h" +#include "../util.h" + +/* P2BT : Pop'n'Music 7 & 8 Bgm File */ + +VGMSTREAM * init_vgmstream_ps2_p2bt(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + off_t start_offset; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("p2bt",filename_extension(filename))) goto fail; + + if((read_32bitBE(0x00,streamFile)!=0x4d4F5645) && // MOVE + (read_32bitBE(0x00,streamFile)!=0x50324254)) // P2BT + goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x0C,streamFile)!=0); + channel_count=read_32bitLE(0x20,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x08,streamFile);; + + /* Check for Compression Scheme */ + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x10,streamFile)/16*28/vgmstream->channels; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x0C,streamFile)/16*28/vgmstream->channels; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile);; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_P2BT; + + start_offset = (off_t)0x800; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(start_offset+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_pnb.c b/lib/vgmstream/src/meta/ps2_pnb.c new file mode 100644 index 0000000000..d0d1e7dcf7 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_pnb.c @@ -0,0 +1,66 @@ +#include "meta.h" +#include "../util.h" + +/* PNB : PsychoNauts Bgm File */ + +VGMSTREAM * init_vgmstream_ps2_pnb(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + off_t start_offset; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("pnb",filename_extension(filename))) goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x0C,streamFile)!=0xFFFFFFFF); + channel_count=1; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = 1; + vgmstream->sample_rate = 44100; + + /* Check for Compression Scheme */ + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitBE(0x08,streamFile)/16*28; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x0C,streamFile)/16*28; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + vgmstream->interleave_block_size = 0x10; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_PNB; + + start_offset = (off_t)read_32bitBE(0x00,streamFile); + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(start_offset+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_psh.c b/lib/vgmstream/src/meta/ps2_psh.c new file mode 100644 index 0000000000..bdc353dc24 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_psh.c @@ -0,0 +1,89 @@ +#include "meta.h" +#include "../util.h" + +/* PSH (from Dawn of Mana - Seiken Densetsu 4) */ +/* probably Square Vag Stream */ +VGMSTREAM * init_vgmstream_ps2_psh(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + uint8_t testBuffer[0x10]; + off_t loopEnd = 0; + off_t readOffset = 0; + size_t fileLength; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("psh",filename_extension(filename))) goto fail; + + /* check header */ + if (read_16bitBE(0x02,streamFile) != 0x6400) + goto fail; + + loop_flag = (read_16bitLE(0x06,streamFile)!=0); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0; + vgmstream->channels = channel_count; + vgmstream->sample_rate = (uint16_t)read_16bitLE(0x08,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (uint16_t)read_16bitLE(0x0C,streamFile)*0x800*28/16/channel_count; + + // loop end is set by the loop marker which we need to find ... + // there's some extra data on unloop files, so we calculate + // the sample count with loop marker on this files + fileLength = get_streamfile_size(streamFile); + do { + readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); + + // Loop End ... + if(testBuffer[0x01]==0x03) { + if(loopEnd==0) loopEnd = readOffset-0x10; + break; + } + } while (streamFile->get_offset(streamFile)<(int32_t)fileLength); + + if(loopEnd!=0) + vgmstream->num_samples = loopEnd*28/16/channel_count; + + if(loop_flag) { + vgmstream->loop_start_sample = + ((uint16_t)read_16bitLE(0x06,streamFile)-0x8000)*0x400*28/16; + vgmstream->loop_end_sample=vgmstream->num_samples; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x800; + vgmstream->meta_type = meta_PS2_PSH; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_psw.c b/lib/vgmstream/src/meta/ps2_psw.c new file mode 100644 index 0000000000..5321b26772 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_psw.c @@ -0,0 +1,88 @@ +#include "meta.h" +#include "../util.h" + +/* PSW (from Rayman Raving Rabbids) +...coefs are missing for the dsp type... */ +VGMSTREAM * init_vgmstream_ps2_psw(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("psw",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x52494646 && /* "RIFF" */ + read_32bitBE(0x08,streamFile) != 0x57415645 && /* "WAVE" */ + read_32bitBE(0x26,streamFile) != 0x64617461) /* "data" */ + goto fail; + + loop_flag = 0; + channel_count = read_16bitLE(0x16,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + switch ((uint16_t)read_16bitBE(0x14,streamFile)) { + case 0xFFFF: + start_offset = 0x2E; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_16bitLE(0x1C,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x2A,streamFile)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = read_32bitLE(0x2A,streamFile)*28/16/channel_count; + } + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x6400; + vgmstream->meta_type = meta_PS2_PSW; + + break; + case 0xFEFF: + start_offset = 0x2E; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_16bitLE(0x1C,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitLE(0x2A,streamFile)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = read_32bitLE(0x2A,streamFile)*28/16/channel_count; + } + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x12C00; + vgmstream->meta_type = meta_PS2_PSW; + + break; +default: + goto fail; +} + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_rkv.c b/lib/vgmstream/src/meta/ps2_rkv.c new file mode 100644 index 0000000000..71ee6420ee --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_rkv.c @@ -0,0 +1,64 @@ +#include "meta.h" +#include "../util.h" + +/* RKV (from Legacy of Kain - Blood Omen 2) */ +VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rkv",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x00000000) /* "\0000" */ + goto fail; + + loop_flag = (read_32bitLE(0x10,streamFile)!=0); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x0C,streamFile); + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x10,streamFile)*28/16/channel_count; + vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x400; + vgmstream->meta_type = meta_PS2_RKV; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_rnd.c b/lib/vgmstream/src/meta/ps2_rnd.c new file mode 100644 index 0000000000..fe397344ca --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_rnd.c @@ -0,0 +1,56 @@ +#include "meta.h" +#include "../util.h" + +/* rnd (from Karaoke Revolution) */ +VGMSTREAM * init_vgmstream_ps2_rnd(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rnd",filename_extension(filename))) goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x00,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x10; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (get_streamfile_size(streamFile)-0x10)/16*28/vgmstream->channels; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2000; + vgmstream->meta_type = meta_HGC1; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_rstm.c b/lib/vgmstream/src/meta/ps2_rstm.c new file mode 100644 index 0000000000..d903b38eaa --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_rstm.c @@ -0,0 +1,64 @@ +#include "meta.h" +#include "../util.h" + +/* RSTM (from Midnight Club 3, Bully - Canis Canim Edit) */ +VGMSTREAM * init_vgmstream_ps2_rstm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rstm",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x5253544D) /* "RSTM" */ + goto fail; + + loop_flag = (read_32bitLE(0x24,streamFile)!=0xFFFFFFFF); + channel_count = read_32bitLE(0x0C,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x20,streamFile)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x24,streamFile)*28/16/channel_count; + vgmstream->loop_end_sample = read_32bitLE(0x20,streamFile)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + vgmstream->meta_type = meta_PS2_RSTM; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_rws.c b/lib/vgmstream/src/meta/ps2_rws.c new file mode 100644 index 0000000000..4ca588f015 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_rws.c @@ -0,0 +1,89 @@ +#include "meta.h" +#include "../util.h" + +/* RWS (Silent Hill Origins, Ghost Rider, Max Payne 2) */ +VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rws",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x0D080000) + goto fail; +#if 0 + /* check if is used as container file */ + if (read_32bitBE(0x38,streamFile) != 0x01000000) + goto fail; +#endif + + loop_flag = 1; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x50,streamFile); + vgmstream->channels = channel_count; + + +switch (read_32bitLE(0x38,streamFile)) { + case 0x01: + vgmstream->sample_rate = read_32bitLE(0xE4,streamFile); + vgmstream->num_samples = read_32bitLE(0x98,streamFile)/16*28/vgmstream->channels; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x98,streamFile)/16*28/vgmstream->channels; + } + break; + case 0x02: + vgmstream->sample_rate = read_32bitLE(0x178,streamFile); + vgmstream->num_samples = read_32bitLE(0x150,streamFile)/16*28/vgmstream->channels; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x150,streamFile)/16*28/vgmstream->channels; + } + break; + default: + goto fail; +} + + +vgmstream->coding_type = coding_PSX; + + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x4C,streamFile)/2; + vgmstream->meta_type = meta_RWS; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_rxw.c b/lib/vgmstream/src/meta/ps2_rxw.c new file mode 100644 index 0000000000..ac48b5aaf4 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_rxw.c @@ -0,0 +1,70 @@ +#include "meta.h" +#include "../util.h" + +/* RXW file (Arc the Lad) */ +VGMSTREAM * init_vgmstream_ps2_rxw(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + int loop_flag=0; + int channel_count; + off_t start_offset; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rxw",filename_extension(filename))) goto fail; + + /* check RXWS/FORM Header */ + if (!((read_32bitBE(0x00,streamFile) == 0x52585753) && + (read_32bitBE(0x10,streamFile) == 0x464F524D))) + goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x3C,streamFile)!=0xFFFFFFFF); + + /* Always stereo files */ + channel_count=2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x2E,streamFile); + + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x38,streamFile)*28/16)/2; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x3C,streamFile)/16*14; + vgmstream->loop_end_sample = read_32bitLE(0x38,streamFile)/16*14; + } + + vgmstream->interleave_block_size = read_32bitLE(0x1c,streamFile)+0x10; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_RXW; + + start_offset = 0x40; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(start_offset+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_seg.c b/lib/vgmstream/src/meta/ps2_seg.c new file mode 100644 index 0000000000..749892e3f1 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_seg.c @@ -0,0 +1,71 @@ +#include "meta.h" +#include "../util.h" + +/* SEG (found in Eragon) */ +VGMSTREAM * init_vgmstream_ps2_seg(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("seg",filename_extension(filename))) goto fail; + + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x73656700 && /* "seg\0" */ + read_32bitBE(0x04,streamFile) != 0x70733200) /* "ps2\0" */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x24,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x4000; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x18,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x0C,streamFile)-start_offset)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x1C,streamFile); + } + + if (channel_count == 1) { + vgmstream->layout_type = layout_none; + } else if (channel_count == 2) { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2000; + } + + vgmstream->meta_type = meta_PS2_SEG; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_sfs.c b/lib/vgmstream/src/meta/ps2_sfs.c new file mode 100644 index 0000000000..ce966af404 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_sfs.c @@ -0,0 +1,64 @@ +#include "meta.h" +#include "../util.h" + +/* SFS (from Baroque) */ +VGMSTREAM * init_vgmstream_sfs(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sfs",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x53544552) /* "STER" */ + goto fail; + + loop_flag = (read_32bitLE(0x08,streamFile)!=0xFFFFFFFF); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x30; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x10,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x04,streamFile)*2)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitLE(0x08,streamFile)*2)*28/16/channel_count; + vgmstream->loop_end_sample = (read_32bitLE(0x04,streamFile)*2)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + vgmstream->meta_type = meta_SFS; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_sl3.c b/lib/vgmstream/src/meta/ps2_sl3.c new file mode 100644 index 0000000000..0f774b9dc5 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_sl3.c @@ -0,0 +1,65 @@ +#include "meta.h" +#include "../util.h" + +/* SL3 (from Test Drive Unlimited, Transformers) */ +VGMSTREAM * init_vgmstream_sl3(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sl3",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x534C3300) /* "SL3\0" */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x14,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x8000; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x18,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (get_streamfile_size(streamFile)-0x8000)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x1C,streamFile); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x20,streamFile); + vgmstream->meta_type = meta_SL3; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_str.c b/lib/vgmstream/src/meta/ps2_str.c new file mode 100644 index 0000000000..a00228e2e8 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_str.c @@ -0,0 +1,92 @@ +#include "meta.h" +#include "../util.h" + +/* STR + + 2008-05-19 - Fastelbja : Test version ... +*/ + +VGMSTREAM * init_vgmstream_ps2_str(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + STREAMFILE * infileSTH = NULL; + char filename[260]; + + char * filenameSTH = NULL; + + int i, channel_count, loop_flag; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("str",filename_extension(filename))) goto fail; + + /* check for .MIH file */ + filenameSTH=(char *)malloc(strlen(filename)+1); + + if (!filenameSTH) goto fail; + + strcpy(filenameSTH,filename); + strcpy(filenameSTH+strlen(filenameSTH)-3,"STH"); + + infileSTH = streamFile->open(streamFile,filenameSTH,STREAMFILE_DEFAULT_BUFFER_SIZE); + + /* STH File is necessary, so we can't confuse those file */ + /* with others .STR file as it is a very common extension */ + if (!infileSTH) goto fail; + + if((read_32bitLE(0x2C,infileSTH)==0x07) || + (read_32bitLE(0x2C,infileSTH)==0x06)) + channel_count=2; + if(read_32bitLE(0x2C,infileSTH)==0x05) + channel_count=1; + + loop_flag = read_32bitLE(0x2C,infileSTH) & 0x01; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x24,infileSTH); + + vgmstream->interleave_block_size=0x4000; + + if(read_32bitLE(0x40,infileSTH)==0x01) + vgmstream->interleave_block_size = 0x8000; + + vgmstream->num_samples=read_32bitLE(0x20,infileSTH); + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + + vgmstream->meta_type = meta_PS2_STR; + + if(loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x20,infileSTH); + } + + close_streamfile(infileSTH); infileSTH=NULL; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset+=(off_t)(vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (infileSTH) close_streamfile(infileSTH); + if (filenameSTH) {free(filenameSTH); filenameSTH=NULL;} + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_svag.c b/lib/vgmstream/src/meta/ps2_svag.c new file mode 100644 index 0000000000..c9ddd30f43 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_svag.c @@ -0,0 +1,85 @@ +#include "meta.h" +#include "../util.h" + +/* SVAG + + PS2 SVAG format is an interleaved format found in many konami Games + The header start with a Svag id and have the sentence : + "ALL RIGHTS RESERVED.KONAMITYO Sound Design Dept. " + or "ALL RIGHTS RESERVED.KCE-Tokyo Sound Design Dept. " + + 2008-05-13 - Fastelbja : First version ... + Thx to HCS for his awesome work on shortblock interleave +*/ + +VGMSTREAM * init_vgmstream_ps2_svag(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("svag",filename_extension(filename))) goto fail; + + /* check SVAG Header */ + if (read_32bitBE(0x00,streamFile) != 0x53766167) + goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x14,streamFile)==1); + + channel_count=read_16bitLE(0x0C,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = read_16bitLE(0x0C,streamFile); + vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + + /* Compression Scheme */ + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x04,streamFile)/16*28/vgmstream->channels; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x18,streamFile)/16*28; + vgmstream->loop_end_sample = read_32bitLE(0x04,streamFile)/16*28/vgmstream->channels; + } + + vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile); + if (channel_count > 1) { + vgmstream->interleave_smallblock_size = (read_32bitLE(0x04,streamFile)%(vgmstream->channels*vgmstream->interleave_block_size))/vgmstream->channels; + vgmstream->layout_type = layout_interleave_shortblock; + } else { + vgmstream->layout_type = layout_none; + } + vgmstream->meta_type = meta_PS2_SVAG; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + if (channel_count > 1) + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + else + 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= + (off_t)(0x800+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_tec.c b/lib/vgmstream/src/meta/ps2_tec.c new file mode 100644 index 0000000000..1287d1b0e3 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_tec.c @@ -0,0 +1,61 @@ +#include "meta.h" +#include "../util.h" + +/* TEC (from TECMO games) */ +/* probably TECMO Vag Stream */ +VGMSTREAM * init_vgmstream_ps2_tec(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("tec",filename_extension(filename))) goto fail; + + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x0; + vgmstream->channels = channel_count; + vgmstream->sample_rate = 44100; + vgmstream->coding_type = coding_PSX_badflags; + vgmstream->num_samples = get_streamfile_size(streamFile)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = get_streamfile_size(streamFile)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x4000; + vgmstream->meta_type = meta_PS2_TEC; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_vag.c b/lib/vgmstream/src/meta/ps2_vag.c new file mode 100644 index 0000000000..a6399db1d1 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_vag.c @@ -0,0 +1,200 @@ +#include "meta.h" +#include "../util.h" + +/* VAG + + PS2 SVAG format is an interleaved format found in many SONY Games + The header start with a "VAG" id and is follow by : + + i : interleaved format + + 2008-05-17 - Fastelbja : First version ... +*/ + +VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + // used for loop points ... + uint8_t eofVAG[16]={0x00,0x07,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77}; + uint8_t eofVAG2[16]={0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t readbuf[16]; + + off_t readOffset = 0x20; + + off_t loopStart = 0; + off_t loopEnd = 0; + + uint8_t vagID; + off_t start_offset; + size_t fileLength; + + size_t interleave; + + int loop_flag=0; + int channel_count=1; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("vag",filename_extension(filename))) goto fail; + + /* check VAG Header */ + if (((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x56414700) && + ((read_32bitLE(0x00,streamFile) & 0xFFFFFF00) != 0x56414700)) + goto fail; + + /* Check for correct channel count */ + vagID=read_8bit(0x03,streamFile); + + switch(vagID) { + case 'i': + channel_count=2; + break; + case 'V': + if(read_32bitBE(0x20,streamFile)==0x53746572) // vag Stereo + channel_count=2; + case 'p': + if((read_32bitBE(0x04,streamFile)<=0x00000004) && (read_32bitBE(0x0c,streamFile)<(get_streamfile_size(streamFile)/2))) { + loop_flag=(read_32bitBE(0x14,streamFile)!=0); + channel_count=2; + } else { + /* Search for loop in VAG */ + fileLength = get_streamfile_size(streamFile); + + do { + readOffset+=0x10; + + // Loop Start ... + if(read_8bit(readOffset+0x01,streamFile)==0x06) { + if(loopStart==0) loopStart = readOffset; + } + + // Loop End ... + if(read_8bit(readOffset+0x01,streamFile)==0x03) { + if(loopEnd==0) loopEnd = readOffset; + } + + // Loop from end to beginning ... + if((read_8bit(readOffset+0x01,streamFile)==0x01)) { + // Check if we have the eof tag after the loop point ... + // if so we don't loop, if not present, we loop from end to start ... + read_streamfile(readbuf,readOffset+0x10,0x10,streamFile); + if((readbuf[0]!=0) && (readbuf[0]!=0x0c)) { + if(memcmp(readbuf,eofVAG,0x10) && (memcmp(readbuf,eofVAG2,0x10))) { + loopStart = 0x40; + loopEnd = readOffset; + } + } + } + + } while (streamFile->get_offset(streamFile)<(off_t)fileLength); + loop_flag = (loopEnd!=0); + } + break; + default: + goto fail; + } + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + + switch(vagID) { + case 'i': // VAGi + vgmstream->layout_type=layout_interleave; + vgmstream->sample_rate = read_32bitBE(0x10,streamFile); + vgmstream->num_samples = read_32bitBE(0x0C,streamFile)/16*28; + interleave = read_32bitLE(0x08,streamFile); + vgmstream->meta_type=meta_PS2_VAGi; + start_offset=0x800; + break; + case 'p': // VAGp + vgmstream->sample_rate = read_32bitBE(0x10,streamFile); + interleave=0x10; // used for loop calc + + if((read_32bitBE(0x04,streamFile)==0x00000004) && (read_32bitBE(0x0c,streamFile)<(get_streamfile_size(streamFile)/2))) { + vgmstream->channels=2; + vgmstream->num_samples = read_32bitBE(0x0C,streamFile); + + if(loop_flag) { + vgmstream->loop_start_sample=read_32bitBE(0x14,streamFile); + vgmstream->loop_end_sample =read_32bitBE(0x18,streamFile); + } + + start_offset=0x80; + vgmstream->layout_type=layout_interleave; + vgmstream->meta_type=meta_PS2_VAGs; + + // Double VAG Header @ 0x0000 & 0x1000 + if(read_32bitBE(0,streamFile)==read_32bitBE(0x1000,streamFile)) { + vgmstream->num_samples = read_32bitBE(0x0C,streamFile)/16*28; + interleave=0x1000; + start_offset=0; + } + + } else { + vgmstream->layout_type=layout_none; + vgmstream->num_samples = read_32bitBE(0x0C,streamFile)/16*28; + vgmstream->meta_type=meta_PS2_VAGp; + start_offset=0x30; + } + break; + case 'V': // pGAV + vgmstream->layout_type=layout_interleave; + interleave=0x2000; + + // Jak X hack ... + if(read_32bitLE(0x1000,streamFile)==0x56414770) + interleave=0x1000; + + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->num_samples = read_32bitLE(0x0C,streamFile)/16*14; + vgmstream->meta_type=meta_PS2_pGAV; + start_offset=0; + break; + default: + goto fail; + } + + vgmstream->interleave_block_size=interleave; + + /* Don't add the header size to loop calc points */ + if(vgmstream->meta_type!=meta_PS2_VAGs) { + loopStart-=start_offset; + loopEnd-=start_offset; + + if(loop_flag!=0) { + vgmstream->loop_start_sample = (int32_t)((loopStart/(interleave*channel_count))*interleave)/16*28; + vgmstream->loop_start_sample += (int32_t)(loopStart%(interleave*channel_count))/16*28; + vgmstream->loop_end_sample = (int32_t)((loopEnd/(interleave*channel_count))*interleave)/16*28; + vgmstream->loop_end_sample += (int32_t)(loopEnd%(interleave*channel_count))/16*28; + } + } + + /* Compression Scheme */ + vgmstream->coding_type = coding_PSX; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(start_offset+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_vas.c b/lib/vgmstream/src/meta/ps2_vas.c new file mode 100644 index 0000000000..aa25d2d12b --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_vas.c @@ -0,0 +1,66 @@ +#include "meta.h" +#include "../util.h" + +/* VAS (from Pro Baseball Spirits 5) */ +VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("vas",filename_extension(filename))) goto fail; + + /* check header */ +#if 0 + if (read_32bitBE(0x00,streamFile) != 0x00000000) /* 0x0 */ + goto fail; +#endif + + loop_flag = (read_32bitLE(0x10,streamFile)!=0); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x00,streamFile)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile)*28/16/channel_count; + vgmstream->loop_end_sample = read_32bitLE(0x00,streamFile)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x200; + vgmstream->meta_type = meta_PS2_VAS; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/ps2_vpk.c b/lib/vgmstream/src/meta/ps2_vpk.c new file mode 100644 index 0000000000..7def9785c1 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_vpk.c @@ -0,0 +1,70 @@ +#include "meta.h" +#include "../util.h" + +/* VPK */ + +VGMSTREAM * init_vgmstream_ps2_vpk(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + off_t start_offset; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("vpk",filename_extension(filename))) goto fail; + + /* check VPK Header */ + if (read_32bitBE(0x00,streamFile) != 0x204B5056) + goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x7FC,streamFile)!=0); + channel_count=read_32bitLE(0x14,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = read_32bitLE(0x14,streamFile); + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + + /* Check for Compression Scheme */ + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x04,streamFile)/16*28; + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x7FC,streamFile); + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile)/2; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_PS2_VPK; + + start_offset = (off_t)read_32bitLE(0x08,streamFile); + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(start_offset+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_xa2.c b/lib/vgmstream/src/meta/ps2_xa2.c new file mode 100644 index 0000000000..9b902dc3e7 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_xa2.c @@ -0,0 +1,60 @@ +#include "meta.h" +#include "../util.h" + +/* XA2 (XG3 Extreme-G Racing) */ +VGMSTREAM * init_vgmstream_ps2_xa2(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("xa2",filename_extension(filename))) goto fail; + + loop_flag = (read_32bitLE(0x10,streamFile)!=0); + channel_count = read_32bitLE(0x0,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = 44100; + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x0C,streamFile); + if (loop_flag) { + vgmstream->loop_start_sample = vgmstream->num_samples-read_32bitLE(0x08,streamFile); + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x04,streamFile); + vgmstream->meta_type = meta_PS2_XA2; + + /* 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; + + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ps2_xa30.c b/lib/vgmstream/src/meta/ps2_xa30.c new file mode 100644 index 0000000000..21339e6191 --- /dev/null +++ b/lib/vgmstream/src/meta/ps2_xa30.c @@ -0,0 +1,63 @@ +#include "meta.h" +#include "../util.h" + +/* XA30 (found in Driver - Parallel Lines) */ +VGMSTREAM * init_vgmstream_xa30(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("xa30",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x58413330) /* "XA30 */ + goto fail; + + loop_flag = 0; + channel_count = 1; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x0C,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x14,streamFile)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile)*28/16/channel_count; + } + + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_XA30; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/psx_cdxa.c b/lib/vgmstream/src/meta/psx_cdxa.c new file mode 100644 index 0000000000..24b274f6ae --- /dev/null +++ b/lib/vgmstream/src/meta/psx_cdxa.c @@ -0,0 +1,117 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* Sony PSX CD-XA */ +/* No looped file ! */ + +off_t init_xa_channel(int channel,STREAMFILE *streamFile); + +uint8_t AUDIO_CODING_GET_STEREO(uint8_t value) { + return (uint8_t)(value & 3); +} + +uint8_t AUDIO_CODING_GET_FREQ(uint8_t value) { + return (uint8_t)((value >> 2) & 3); +} + +VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int channel_count; + uint8_t bCoding; + off_t start_offset; + + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("xa",filename_extension(filename))) goto fail; + + /* check RIFF Header */ + if (!((read_32bitBE(0x00,streamFile) == 0x52494646) && + (read_32bitBE(0x08,streamFile) == 0x43445841) && + (read_32bitBE(0x0C,streamFile) == 0x666D7420))) + goto fail; + + /* First init to have the correct info of the channel */ + start_offset=init_xa_channel(0,streamFile); + + /* No sound ? */ + if(start_offset==0) + goto fail; + + bCoding = read_8bit(start_offset-5,streamFile); + + switch (AUDIO_CODING_GET_STEREO(bCoding)) { + case 0: channel_count = 1; break; + case 1: channel_count = 2; break; + default: channel_count = 0; break; + } + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,0); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->xa_channel = 0; + + switch (AUDIO_CODING_GET_FREQ(bCoding)) { + case 0: vgmstream->sample_rate = 37800; break; + case 1: vgmstream->sample_rate = 18900; break; + default: vgmstream->sample_rate = 0; break; + } + + /* Check for Compression Scheme */ + vgmstream->coding_type = coding_XA; + vgmstream->num_samples = (int32_t)((((get_streamfile_size(streamFile) - 0x3C)/2352)*0x1F80)/(2*channel_count)); + + vgmstream->layout_type = layout_xa_blocked; + vgmstream->meta_type = meta_PSX_XA; + + /* open the file for reading by each channel */ + { + STREAMFILE *chstreamfile; + chstreamfile = streamFile->open(streamFile,filename,2352); + + if (!chstreamfile) goto fail; + + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = chstreamfile; + } + } + + xa_block_update(start_offset,vgmstream); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +off_t init_xa_channel(int channel,STREAMFILE* streamFile) { + + off_t block_offset=0x44; + size_t filelength=get_streamfile_size(streamFile); + + int8_t currentChannel; + int8_t subAudio; + +begin: + + // 0 can't be a correct value + if(block_offset>=(off_t)filelength) + return 0; + + currentChannel=read_8bit(block_offset-7,streamFile); + subAudio=read_8bit(block_offset-6,streamFile); + if (!((currentChannel==channel) && (subAudio==0x64))) { + block_offset+=2352; + goto begin; + } + return block_offset; +} diff --git a/lib/vgmstream/src/meta/psx_fag.c b/lib/vgmstream/src/meta/psx_fag.c new file mode 100644 index 0000000000..21be33cbe6 --- /dev/null +++ b/lib/vgmstream/src/meta/psx_fag.c @@ -0,0 +1,66 @@ +#include "meta.h" +#include "../util.h" + +/* FAG (Jackie Chan - Stuntmaster) */ +VGMSTREAM * init_vgmstream_psx_fag(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("fag",filename_extension(filename))) goto fail; + + /* check header */ + + /* Look if there's more than 1 one file... */ + if (read_32bitBE(0x00,streamFile) != 0x01000000) + goto fail; + + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x04,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = 24000; + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (read_32bitLE(0x08,streamFile))/channel_count/32*28; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (read_32bitLE(0x08,streamFile))/channel_count/32*28; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x8000; + vgmstream->meta_type = meta_PSX_FAG; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/psx_gms.c b/lib/vgmstream/src/meta/psx_gms.c new file mode 100644 index 0000000000..fdbf07cdb4 --- /dev/null +++ b/lib/vgmstream/src/meta/psx_gms.c @@ -0,0 +1,76 @@ +#include "meta.h" +#include "../util.h" + +/* GMS + + PSX GMS format has no recognition ID. + This format was used essentially in Grandia Games but + can be easily used by other header format as the format of the header is very simple + + known extensions : GMS + + 2008-05-19 - Fastelbja : First version ... +*/ + +VGMSTREAM * init_vgmstream_psx_gms(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + off_t start_offset; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("gms",filename_extension(filename))) goto fail; + + /* check loop */ + loop_flag = (read_32bitLE(0x20,streamFile)==0); + + /* Always stereo files */ + channel_count=read_32bitLE(0x00,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = read_32bitLE(0x1C,streamFile); + + /* Get loop point values */ + if(vgmstream->loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x1C,streamFile); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x800; + vgmstream->meta_type = meta_PSX_GMS; + + start_offset = 0x800; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + (off_t)(start_offset+vgmstream->interleave_block_size*i); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/raw.c b/lib/vgmstream/src/meta/raw.c new file mode 100644 index 0000000000..4a002d7920 --- /dev/null +++ b/lib/vgmstream/src/meta/raw.c @@ -0,0 +1,59 @@ +#include "meta.h" +#include "../util.h" + +/* RAW + + RAW format is native 44khz PCM file + Nothing more :P ... + + 2008-05-17 - Fastelbja : First version ... +*/ + +VGMSTREAM * init_vgmstream_raw(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("raw",filename_extension(filename))) goto fail; + + /* No check to do as they are raw pcm */ + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(2,0); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = 2; + vgmstream->sample_rate = 44100; + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = (int32_t)(get_streamfile_size(streamFile)/4); + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 2; + vgmstream->meta_type = meta_RAW; + + /* open the file for reading by each channel */ + { + STREAMFILE *chstreamfile; + + /* have both channels use the same buffer, as interleave is so small */ + chstreamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (!chstreamfile) goto fail; + + for (i=0;i<2;i++) { + vgmstream->ch[i].streamfile = chstreamfile; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=(off_t)(i*vgmstream->interleave_block_size); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/riff.c b/lib/vgmstream/src/meta/riff.c new file mode 100644 index 0000000000..32697c5fc9 --- /dev/null +++ b/lib/vgmstream/src/meta/riff.c @@ -0,0 +1,342 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* Resource Interchange File Format */ +/* only the bare minimum needed to read PCM wavs */ + +/* return milliseconds */ +long parse_marker(unsigned char * marker) { + long hh,mm,ss,ms; + if (memcmp("Marker ",marker,7)) return -1; + + if (4 != sscanf((char*)marker+7,"%ld:%ld:%ld.%ld",&hh,&mm,&ss,&ms)) + return -1; + + return ((hh*60+mm)*60+ss)*1000+ms; +} + +/* loop points have been found hiding here */ +void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *streamFile, + long *loop_start, long *loop_end, int *loop_flag) { + int loop_start_found = 0; + int loop_end_found = 0; + + off_t current_chunk = adtl_offset+4; + + while (current_chunk < adtl_offset+adtl_length) { + uint32_t chunk_type = read_32bitBE(current_chunk,streamFile); + off_t chunk_size = read_32bitLE(current_chunk+4,streamFile); + + if (current_chunk+8+chunk_size > adtl_offset+adtl_length) return; + + switch(chunk_type) { + case 0x6c61626c: /* labl */ + { + unsigned char *labelcontent; + labelcontent = malloc(chunk_size-4); + if (!labelcontent) return; + if (read_streamfile(labelcontent,current_chunk+0xc, + chunk_size-4,streamFile)!=chunk_size-4) { + free(labelcontent); + return; + } + + switch (read_32bitLE(current_chunk+8,streamFile)) { + case 1: + if (!loop_start_found && + (*loop_start = parse_marker(labelcontent))>=0) + { + loop_start_found = 1; + } + break; + case 2: + if (!loop_end_found && + (*loop_end = parse_marker(labelcontent))>=0) + { + loop_end_found = 1; + } + break; + default: + break; + } + + free(labelcontent); + } + break; + default: + break; + } + + current_chunk += 8 + chunk_size; + } + + if (loop_start_found && loop_end_found) *loop_flag = 1; + + /* labels don't seem to be consistently ordered */ + if (*loop_start > *loop_end) { + long temp = *loop_start; + *loop_start = *loop_end; + *loop_end = temp; + } +} + +VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + off_t file_size = -1; + int channel_count = 0; + int sample_count = 0; + int sample_rate = 0; + int coding_type = -1; + off_t start_offset = -1; + int interleave = -1; + + int loop_flag = 0; + long loop_start_ms = -1; + long loop_end_ms = -1; + off_t loop_start_offset = -1; + off_t loop_end_offset = -1; + uint32_t riff_size; + uint32_t data_size = 0; + + int FormatChunkFound = 0; + int DataChunkFound = 0; + + /* Level-5 mwv */ + int mwv = 0; + off_t mwv_pflt_offset = -1; + off_t mwv_ctrl_offset = -1; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("wav",filename_extension(filename)) && + strcasecmp("lwav",filename_extension(filename))) + { + if (strcasecmp("mwv",filename_extension(filename))) + goto fail; + else + mwv = 1; + } + + /* check header */ + if ((uint32_t)read_32bitBE(0,streamFile)!=0x52494646) /* "RIFF" */ + goto fail; + /* check for WAVE form */ + if ((uint32_t)read_32bitBE(8,streamFile)!=0x57415645) /* "WAVE" */ + goto fail; + + riff_size = read_32bitLE(4,streamFile); + file_size = get_streamfile_size(streamFile); + + /* check for tructated RIFF */ + if (file_size < riff_size+8) goto fail; + + /* read through chunks to verify format and find metadata */ + { + off_t current_chunk = 0xc; /* start with first chunk */ + + while (current_chunk < file_size && current_chunk < riff_size+8) { + uint32_t chunk_type = read_32bitBE(current_chunk,streamFile); + off_t chunk_size = read_32bitLE(current_chunk+4,streamFile); + + if (current_chunk+8+chunk_size > file_size) goto fail; + + switch(chunk_type) { + case 0x666d7420: /* "fmt " */ + /* only one per file */ + if (FormatChunkFound) goto fail; + FormatChunkFound = 1; + + sample_rate = read_32bitLE(current_chunk+0x0c,streamFile); + channel_count = read_16bitLE(current_chunk+0x0a,streamFile); + + switch (read_16bitLE(current_chunk+0x8,streamFile)) { + case 1: /* PCM */ + switch (read_16bitLE(current_chunk+0x16,streamFile)) { + case 16: + coding_type = coding_PCM16LE; + interleave = 2; + break; + case 8: + coding_type = coding_PCM8_U_int; + interleave = 1; + break; + default: + goto fail; + } + break; + case 0x555: /* Level-5 0x555 ADPCM */ + if (!mwv) goto fail; + coding_type = coding_L5_555; + interleave = 0x12; + break; + default: + goto fail; + } + break; + case 0x64617461: /* data */ + /* at most one per file */ + if (DataChunkFound) goto fail; + DataChunkFound = 1; + + start_offset = current_chunk + 8; + data_size = chunk_size; + break; + case 0x4C495354: /* LIST */ + /* what lurks within?? */ + switch (read_32bitBE(current_chunk + 8, streamFile)) { + case 0x6164746C: /* adtl */ + /* yay, atdl is its own little world */ + parse_adtl(current_chunk + 8, chunk_size, + streamFile, + &loop_start_ms,&loop_end_ms,&loop_flag); + break; + default: + break; + } + break; + case 0x736D706C: /* smpl */ + /* check loop count */ + if (read_32bitLE(current_chunk+0x24, streamFile)==1) + { + /* check loop info */ + if (read_32bitLE(current_chunk+0x2c+4, streamFile)==0) + { + loop_flag = 1; + loop_start_offset = + read_32bitLE(current_chunk+0x2c+8, streamFile); + loop_end_offset = + read_32bitLE(current_chunk+0x2c+0xc,streamFile); + } + } + break; + case 0x70666c74: /* pflt */ + if (!mwv) break; /* ignore if not in an mwv */ + /* predictor filters */ + mwv_pflt_offset = current_chunk; + break; + case 0x6374726c: /* ctrl */ + if (!mwv) break; /* ignore if not in an mwv */ + /* loops! */ + if (read_32bitLE(current_chunk+8, streamFile)) + { + loop_flag = 1; + } + mwv_ctrl_offset = current_chunk; + break; + default: + /* ignorance is bliss */ + break; + } + + current_chunk += 8+chunk_size; + } + } + + if (!FormatChunkFound || !DataChunkFound) goto fail; + + switch (coding_type) { + case coding_PCM16LE: + sample_count = data_size/2/channel_count; + break; + case coding_PCM8_U_int: + sample_count = data_size/channel_count; + break; + case coding_L5_555: + sample_count = data_size/0x12/channel_count*32; + break; + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = sample_count; + vgmstream->sample_rate = sample_rate; + + vgmstream->coding_type = coding_type; + if (channel_count > 1 && coding_type != coding_PCM8_U_int) + vgmstream->layout_type = layout_interleave; + else + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = interleave; + + if (loop_flag) { + if (loop_start_ms >= 0) + { + vgmstream->loop_start_sample = + (long long)loop_start_ms*sample_rate/1000; + vgmstream->loop_end_sample = + (long long)loop_end_ms*sample_rate/1000; + vgmstream->meta_type = meta_RIFF_WAVE_labl_Marker; + } + else if (loop_start_offset >= 0) + { + vgmstream->loop_start_sample = loop_start_offset; + vgmstream->loop_end_sample = loop_end_offset; + vgmstream->meta_type = meta_RIFF_WAVE_smpl; + } + else if (mwv && mwv_ctrl_offset != -1) + { + vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, + streamFile); + vgmstream->loop_end_sample = sample_count; + } + } + else + { + vgmstream->meta_type = meta_RIFF_WAVE; + } + + if (mwv) + { + int i, c; + if (coding_type == coding_L5_555) + { + const int filter_order = 3; + int filter_count = read_32bitLE(mwv_pflt_offset+12, streamFile); + + if (mwv_pflt_offset == -1 || + read_32bitLE(mwv_pflt_offset+8, streamFile) != filter_order || + read_32bitLE(mwv_pflt_offset+4, streamFile) < 8 + filter_count * 4 * filter_order) + goto fail; + if (filter_count > 0x20) goto fail; + for (c = 0; c < channel_count; c++) + { + for (i = 0; i < filter_count * filter_order; i++) + { + vgmstream->ch[c].adpcm_coef_3by32[i] = read_32bitLE( + mwv_pflt_offset+16+i*4, streamFile + ); + } + } + } + vgmstream->meta_type = meta_RIFF_WAVE_MWV; + } + + /* open the file, set up each channel */ + { + int i; + + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, + STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!vgmstream->ch[0].streamfile) goto fail; + + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile; + vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset = + start_offset+i*interleave; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/rs03.c b/lib/vgmstream/src/meta/rs03.c new file mode 100644 index 0000000000..82f57c8131 --- /dev/null +++ b/lib/vgmstream/src/meta/rs03.c @@ -0,0 +1,81 @@ +#include "meta.h" +#include "../coding/coding.h" +#include "../util.h" + +/* .dsp w/ RS03 header - from Metroid Prime 2 */ + +VGMSTREAM * init_vgmstream_rs03(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int channel_count; + int loop_flag; + off_t start_offset; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("dsp",filename_extension(filename))) goto fail; + + /* check header */ + if ((uint32_t)read_32bitBE(0,streamFile)!=0x52530003) /* "RS03" */ + goto fail; + + channel_count = read_32bitBE(4,streamFile); + if (channel_count != 1 && channel_count != 2) goto fail; + + /* build the VGMSTREAM */ + + loop_flag = read_16bitBE(0x14,streamFile); + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = read_32bitBE(8,streamFile); + vgmstream->sample_rate = read_32bitBE(0xc,streamFile); + + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile)/8*14; + vgmstream->loop_end_sample = read_32bitBE(0x1c,streamFile)/8*14; + } + + start_offset = 0x60; + + vgmstream->coding_type = coding_NGC_DSP; + if (channel_count == 2) { + vgmstream->layout_type = layout_interleave_shortblock; + vgmstream->interleave_block_size = 0x8f00; + vgmstream->interleave_smallblock_size = (((get_streamfile_size(streamFile)-start_offset)%(0x8f00*2))/2+7)/8*8; + } else + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_DSP_RS03; + + for (i=0;i<16;i++) + vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(0x20+i*2,streamFile); + if (channel_count==2) { + for (i=0;i<16;i++) + vgmstream->ch[1].adpcm_coef[i]=read_16bitBE(0x40+i*2,streamFile); + } + + /* 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,0x8f00); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + start_offset+0x8f00*i; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/rsd.c b/lib/vgmstream/src/meta/rsd.c new file mode 100644 index 0000000000..f81a6b557e --- /dev/null +++ b/lib/vgmstream/src/meta/rsd.c @@ -0,0 +1,705 @@ +#include "meta.h" +#include "../util.h" + +/* RSD */ +/* RSD2VAG */ +VGMSTREAM * init_vgmstream_rsd2vag(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rsd",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x52534432) /* RSD2 */ + goto fail; + if (read_32bitBE(0x4,streamFile) != 0x56414720) /* VAG\0x20 */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x8,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile); + vgmstream->meta_type = meta_RSD2VAG; + + /* 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; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + +/* RSD2PCMB - Big Endian */ +VGMSTREAM * init_vgmstream_rsd2pcmb(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rsd",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x52534432) /* RSD2 */ + goto fail; + if (read_32bitBE(0x4,streamFile) != 0x50434D42) /* PCMB */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x8,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x18,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_PCM16BE; + vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; + } + + + if (channel_count == 1) { + vgmstream->layout_type = layout_none; + } else if (channel_count == 2) { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + } + + + vgmstream->meta_type = meta_RSD2PCMB; + + /* 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; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + + +/* RSD2XADP */ +VGMSTREAM * init_vgmstream_rsd2xadp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rsd",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x52534432) /* RSD2 */ + goto fail; + if (read_32bitBE(0x4,streamFile) != 0x58414450) /* XADP */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x8,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x18,streamFile); /* not sure about this */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_XBOX; + vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)*64/36/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x24; + vgmstream->meta_type = meta_RSD2XADP; + + /* 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; + + + if (vgmstream->coding_type == coding_XBOX) { + vgmstream->layout_type=layout_none; + vgmstream->ch[i].channel_start_offset=start_offset; + } else { + vgmstream->ch[i].channel_start_offset= + start_offset+vgmstream->interleave_block_size*i; + } + vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset; + + } + } + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + +/* RSD3PCM - Little Endian */ +VGMSTREAM * init_vgmstream_rsd3pcm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rsd",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x52534433) /* RSD3 */ + goto fail; + if (read_32bitBE(0x4,streamFile) != 0x50434D20) /* PCM\0x20 */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x8,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x18,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; + } + + + if (channel_count == 1) { + vgmstream->layout_type = layout_none; + } else if (channel_count == 2) { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + } + + vgmstream->meta_type = meta_RSD3PCM; + + + /* 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; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + + +/* RSD4VAG */ +VGMSTREAM * init_vgmstream_rsd4vag(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rsd",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x52534434) /* RSD4 */ + goto fail; + if (read_32bitBE(0x4,streamFile) != 0x56414720) /* VAG\0x20 */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x8,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0xC,streamFile); + vgmstream->meta_type = meta_RSD4VAG; + + /* 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; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + +/* RSD4PCM - Little Endian */ +VGMSTREAM * init_vgmstream_rsd4pcm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rsd",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x52534434) /* RSD4 */ + goto fail; + if (read_32bitBE(0x4,streamFile) != 0x50434D20) /* PCM\0x20 */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x8,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)/2/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)/2/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + vgmstream->meta_type = meta_RSD4PCM; + + /* 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; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + + +/* RSD4PCMB - Big Endian */ +VGMSTREAM * init_vgmstream_rsd4pcmb(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rsd",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x52534434) /* RSD4 */ + goto fail; + if (read_32bitBE(0x4,streamFile) != 0x50434D42) /* PCMB */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x8,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x80; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_PCM16BE; + vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)/2/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)/2/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + vgmstream->meta_type = meta_RSD4PCMB; + + /* 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; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + + +/* RSD6VAG */ +VGMSTREAM * init_vgmstream_rsd6vag(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rsd",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x52534436) /* RSD6 */ + goto fail; + if (read_32bitBE(0x4,streamFile) != 0x56414720) /* VAG\0x20 */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x8,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0xC,streamFile); + vgmstream->meta_type = meta_RSD6VAG; + + /* 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; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + +/* RSD6WADP */ +VGMSTREAM * init_vgmstream_rsd6wadp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rsd",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x52534436) /* RSD6 */ + goto fail; + if (read_32bitBE(0x4,streamFile) != 0x57414450) /* WADP */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x8,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave_byte; //layout_interleave; + vgmstream->interleave_block_size = 2; //read_32bitLE(0xC,streamFile); + vgmstream->meta_type = meta_RSD6WADP; + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x1A4+i*2,streamFile); + } + if (vgmstream->channels) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x1CC+i*2,streamFile); + } + } + } + /* 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; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + + + +/* RSD6XADP */ +VGMSTREAM * init_vgmstream_rsd6xadp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rsd",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x0,streamFile) != 0x52534436) /* RSD6 */ + goto fail; + if (read_32bitBE(0x4,streamFile) != 0x58414450) /* XADP */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x8,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + vgmstream->coding_type = coding_XBOX; + vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)*64/36/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = loop_flag; + vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x24; + vgmstream->meta_type = meta_RSD6XADP; + + /* 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; + + + if (vgmstream->coding_type == coding_XBOX) { + vgmstream->layout_type=layout_none; + vgmstream->ch[i].channel_start_offset=start_offset; + } else { + vgmstream->ch[i].channel_start_offset= + start_offset+vgmstream->interleave_block_size*i; + } + vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset; + + } + } + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/rsf.c b/lib/vgmstream/src/meta/rsf.c new file mode 100644 index 0000000000..9ae8325e11 --- /dev/null +++ b/lib/vgmstream/src/meta/rsf.c @@ -0,0 +1,73 @@ +#include "meta.h" +#include "../util.h" +#include "../coding/coding.h" + +/* .rsf - from Metroid Prime */ + +VGMSTREAM * init_vgmstream_rsf(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + size_t file_size; + + /* check extension, case insensitive */ + /* this is all we have to go on, rsf is completely headerless */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rsf",filename_extension(filename))) goto fail; + + file_size = get_streamfile_size(streamFile); + + { + /* extra check: G.721 has no zero nibbles, so we look at + * the first few bytes*/ + int8_t test_byte; + off_t i; + /* 0x20 is arbitrary, all files are much larger */ + for (i=0;i<0x20;i++) { + test_byte = read_8bit(i,streamFile); + if (!(test_byte&0xf) || !(test_byte&0xf0)) goto fail; + } + /* and also check start of second channel */ + for (i=(file_size+1)/2;i<(file_size+1)/2+0x20;i++) { + test_byte = read_8bit(i,streamFile); + if (!(test_byte&0xf) || !(test_byte&0xf0)) goto fail; + } + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(2,0); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = file_size; + vgmstream->sample_rate = 32000; + + vgmstream->coding_type = coding_G721; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_RSF; + + /* open the file for reading by each channel */ + { + int i; + for (i=0;i<2;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= + (file_size+1)/2*i; + + + g72x_init_state(&(vgmstream->ch[i].g72x_state)); + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/rwsd.c b/lib/vgmstream/src/meta/rwsd.c new file mode 100644 index 0000000000..52994c5551 --- /dev/null +++ b/lib/vgmstream/src/meta/rwsd.c @@ -0,0 +1,245 @@ +#include "meta.h" +#include "../coding/coding.h" +#include "../util.h" + +static off_t read_rwav(off_t offset, int *version, off_t *start_offset, off_t *info_chunkp, STREAMFILE *streamFile) +{ + off_t info_chunk; + off_t data_chunk; + off_t wave_offset; + + if ((uint32_t)read_32bitBE(offset,streamFile)!=0x52574156) /* "RWAV" */ + goto fail; + if ((uint32_t)read_32bitBE(offset+4,streamFile)!=0xFEFF0102) /* version 2 */ + goto fail; + + info_chunk = offset+read_32bitBE(offset+0x10,streamFile); + if ((uint32_t)read_32bitBE(info_chunk,streamFile)!=0x494e464f) /* "INFO" */ + goto fail; + data_chunk = offset+read_32bitBE(offset+0x18,streamFile); + if ((uint32_t)read_32bitBE(data_chunk,streamFile)!=0x44415441) /* "DATA" */ + goto fail; + + *start_offset = data_chunk + 8; + *info_chunkp = info_chunk + 8; + *version = 2; + wave_offset = info_chunk - 8; + + return wave_offset; +fail: + return -1; +} + +static off_t read_rwar(off_t offset, int *version, off_t *start_offset, off_t *info_chunk, STREAMFILE *streamFile) +{ + off_t wave_offset; + if ((uint32_t)read_32bitBE(offset,streamFile)!=0x52574152) /* "RWAR" */ + goto fail; + if ((uint32_t)read_32bitBE(offset+4,streamFile)!=0xFEFF0100) /* version 0 */ + goto fail; + + wave_offset = read_rwav(offset+0x60,version,start_offset,info_chunk,streamFile); + *version = 0; + return wave_offset; + +fail: + return -1; +} + +/* RWSD is quite similar to BRSTM, but can contain several streams. + * Still, some games use it for single streams. We only support the + * single stream form here */ +VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + coding_t coding_type; + + off_t info_chunk; + off_t wave_offset; + size_t wave_length; + int codec_number; + int channel_count; + int loop_flag; + int rwar = 0; + int rwav = 0; + int version = -1; + + off_t start_offset = 0; + size_t stream_size; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rwsd",filename_extension(filename))) + { + if (strcasecmp("rwar",filename_extension(filename))) + { + if (strcasecmp("rwav",filename_extension(filename))) + { + goto fail; + } + else + { + rwav = 1; + } + } + else + { + rwar = 1; + } + } + + /* check header */ + if (rwar) + { + wave_offset = read_rwar(0,&version,&start_offset,&info_chunk,streamFile); + if (wave_offset < 0) goto fail; + } + else if (rwav) + { + wave_offset = read_rwav(0,&version,&start_offset,&info_chunk,streamFile); + if (wave_offset < 0) goto fail; + } + else + { + if ((uint32_t)read_32bitBE(0,streamFile)!=0x52575344) /* "RWSD" */ + goto fail; + + switch (read_32bitBE(4,streamFile)) + { + case 0xFEFF0102: + /* ideally we would look through the chunk list for a WAVE chunk, + * but it's always in the same order */ + /* get WAVE offset, check */ + wave_offset = read_32bitBE(0x18,streamFile); + if ((uint32_t)read_32bitBE(wave_offset,streamFile)!=0x57415645) /* "WAVE" */ + goto fail; + /* get WAVE size, check */ + wave_length = read_32bitBE(0x1c,streamFile); + if (read_32bitBE(wave_offset+4,streamFile)!=wave_length) + goto fail; + + /* check wave count */ + if (read_32bitBE(wave_offset+8,streamFile) != 1) + goto fail; /* only support 1 */ + + version = 2; + + break; + case 0xFEFF0103: + wave_offset = read_rwar(0xe0,&version,&start_offset,&info_chunk,streamFile); + if (wave_offset < 0) goto fail; + + rwar = 1; + break; + default: + goto fail; + } + + } + + /* get type details */ + codec_number = read_8bit(wave_offset+0x10,streamFile); + loop_flag = read_8bit(wave_offset+0x11,streamFile); + channel_count = read_8bit(wave_offset+0x12,streamFile); + + switch (codec_number) { + case 0: + coding_type = coding_PCM8; + break; + case 1: + coding_type = coding_PCM16BE; + break; + case 2: + coding_type = coding_NGC_DSP; + break; + default: + goto fail; + } + + if (channel_count < 1) goto fail; + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = dsp_nibbles_to_samples(read_32bitBE(wave_offset+0x1c,streamFile)); + vgmstream->sample_rate = (uint16_t)read_16bitBE(wave_offset+0x14,streamFile); + /* channels and loop flag are set by allocate_vgmstream */ + vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(wave_offset+0x18,streamFile)); + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_type; + vgmstream->layout_type = layout_none; + + if (rwar) + vgmstream->meta_type = meta_RWAR; + else if (rwav) + vgmstream->meta_type = meta_RWAV; + else + vgmstream->meta_type = meta_RWSD; + + if (vgmstream->coding_type == coding_NGC_DSP) { + off_t coef_offset; + int i,j; + + for (j=0;j<vgmstream->channels;j++) { + if (rwar || rwav) + { + /* This is pretty nasty, so an explaination is in order. + * At 0x10 in the info_chunk is the offset of a table with + * one entry per channel. Each entry in this table is itself + * an offset to a set of information for the channel. The + * first element in the set is the offset into DATA of the + * channel. The stream_size read far below just happens to + * hit on this properly for stereo. The second element is the + * offset of the coefficient table for the channel. */ + coef_offset = info_chunk + + read_32bitBE(info_chunk + + read_32bitBE(info_chunk+ + read_32bitBE(info_chunk+0x10,streamFile)+j*4, + streamFile) + 4, streamFile); + } else { + coef_offset=wave_offset+0x6c+j*0x30; + } + for (i=0;i<16;i++) { + vgmstream->ch[j].adpcm_coef[i]=read_16bitBE(coef_offset+i*2,streamFile); + } + } + } + + if (rwar || rwav) + { + /* */ + } + else + { + if (version == 2) + start_offset = read_32bitBE(8,streamFile); + } + stream_size = read_32bitBE(wave_offset+0x50,streamFile); + + /* 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, + 0x1000); + + if (!vgmstream->ch[i].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset= + start_offset + i*stream_size; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/rwx.c b/lib/vgmstream/src/meta/rwx.c new file mode 100644 index 0000000000..ac00279504 --- /dev/null +++ b/lib/vgmstream/src/meta/rwx.c @@ -0,0 +1,66 @@ +#include "meta.h" +#include "../util.h" +/* RWX (found in Air Force Delta Storm (XBOX)) */ +VGMSTREAM * init_vgmstream_rwx(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("rwx",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x52415758) + goto fail; + + + loop_flag = read_32bitLE(0x0C,streamFile); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x04,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = read_32bitLE(0x10,streamFile); + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x0C,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x10,streamFile); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + vgmstream->meta_type = meta_RWX; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/sat_dvi.c b/lib/vgmstream/src/meta/sat_dvi.c new file mode 100644 index 0000000000..8b763bed72 --- /dev/null +++ b/lib/vgmstream/src/meta/sat_dvi.c @@ -0,0 +1,68 @@ +#include "meta.h" +#include "../util.h" + +/* DVI (Castlevania Symphony of the Night) */ +VGMSTREAM * init_vgmstream_dvi(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("dvi",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x4456492E) /* "DVI." */ + goto fail; + + loop_flag = (read_32bitBE(0x0C,streamFile)!=0xFFFFFFFF); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + start_offset = read_32bitBE(0x04,streamFile); + vgmstream->sample_rate = 44100; + vgmstream->coding_type = coding_INT_DVI_IMA; + + vgmstream->num_samples = read_32bitBE(0x08,streamFile); + + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x0C,streamFile); + vgmstream->loop_end_sample = read_32bitBE(0x08,streamFile); + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 4; + vgmstream->meta_type = meta_DVI; + vgmstream->get_high_nibble=1; + + + /* 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+(i*vgmstream->interleave_block_size); + vgmstream->ch[i].adpcm_history1_32=0; + vgmstream->ch[i].adpcm_step_index=0; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/sat_sap.c b/lib/vgmstream/src/meta/sat_sap.c new file mode 100644 index 0000000000..3d1f2ba29a --- /dev/null +++ b/lib/vgmstream/src/meta/sat_sap.c @@ -0,0 +1,67 @@ +#include "meta.h" +#include "../util.h" + +/* SAP (from Bubble_Symphony) */ +VGMSTREAM * init_vgmstream_sat_sap(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sap",filename_extension(filename))) goto fail; + + + /* check header */ + if (read_32bitBE(0x0A,streamFile) != 0x0010400E) /* "0010400E" */ + goto fail; + + + loop_flag = 0; /* (read_32bitLE(0x08,streamFile)!=0); */ + channel_count = read_32bitBE(0x04,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = (uint16_t)read_16bitBE(0x0E,streamFile); + vgmstream->coding_type = coding_PCM16BE; + vgmstream->num_samples = read_32bitBE(0x00,streamFile); + if (loop_flag) { + vgmstream->loop_start_sample = 0; /* (read_32bitLE(0x08,streamFile)-1)*28; */ + vgmstream->loop_end_sample = read_32bitBE(0x00,streamFile); + } + + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = 0x10; + vgmstream->meta_type = meta_SAT_SAP; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/sdt.c b/lib/vgmstream/src/meta/sdt.c new file mode 100644 index 0000000000..1959ef8a86 --- /dev/null +++ b/lib/vgmstream/src/meta/sdt.c @@ -0,0 +1,80 @@ +#include "meta.h" +#include "../util.h" + +/* SDT (Baldur's Gate - Dark Alliance) */ +VGMSTREAM * init_vgmstream_sdt(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sdt",filename_extension(filename))) goto fail; + +#if 0 + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x53565300) /* "SVS\0" */ + goto fail; +#endif + + loop_flag = (read_32bitBE(0x04,streamFile)!=0); + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0xA0; + vgmstream->channels = read_32bitBE(0x00,streamFile); + vgmstream->sample_rate = read_32bitBE(0x08,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitBE(0x14,streamFile)/8*14/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; /* (read_32bitLE(0x08,streamFile)-1)*28; */ + vgmstream->loop_end_sample = read_32bitBE(0x14,streamFile)/8*14/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x8000; + vgmstream->meta_type = meta_SDT; + + +if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x3C+i*2,streamFile); + } + if (vgmstream->channels) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x6A+i*2,streamFile); + } + } +} + + /* 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; +} diff --git a/lib/vgmstream/src/meta/sfl.c b/lib/vgmstream/src/meta/sfl.c new file mode 100644 index 0000000000..8e72b34157 --- /dev/null +++ b/lib/vgmstream/src/meta/sfl.c @@ -0,0 +1,182 @@ +#include "../vgmstream.h" + +#ifdef VGM_USE_VORBIS + +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* .sfl, odd RIFF-formatted files that go along with oggs */ + +/* return milliseconds */ +static int parse_region(unsigned char * region, long *start, long *end) { + long start_hh,start_mm,start_ss,start_ms; + long end_hh,end_mm,end_ss,end_ms; + + if (memcmp("Region ",region,7)) return -1; + + if (8 != sscanf((char*)region+7,"%ld:%ld:%ld.%ld to %ld:%ld:%ld.%ld", + &start_hh,&start_mm,&start_ss,&start_ms, + &end_hh,&end_mm,&end_ss,&end_ms)) + return -1; + + *start = ((start_hh*60+start_mm)*60+start_ss)*1000+start_ms; + *end = ((end_hh*60+end_mm)*60+end_ss)*1000+end_ms; + + return 0; +} + +/* loop points have been found hiding here */ +static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *streamFile, + long *loop_start, long *loop_end, int *loop_flag) { + int loop_found = 0; + + off_t current_chunk = adtl_offset+4; + + while (current_chunk < adtl_offset+adtl_length) { + uint32_t chunk_type = read_32bitBE(current_chunk,streamFile); + off_t chunk_size = read_32bitLE(current_chunk+4,streamFile); + + if (current_chunk+8+chunk_size > adtl_offset+adtl_length) return; + + switch(chunk_type) { + case 0x6c61626c: /* labl */ + { + unsigned char *labelcontent; + labelcontent = malloc(chunk_size-4); + if (!labelcontent) return; + if (read_streamfile(labelcontent,current_chunk+0xc, + chunk_size-4,streamFile)!=chunk_size-4) { + free(labelcontent); + return; + } + + if (!loop_found && + parse_region(labelcontent,loop_start,loop_end)>=0) + { + loop_found = 1; + } + + free(labelcontent); + } + break; + default: + break; + } + + current_chunk += 8 + chunk_size; + } + + if (loop_found) *loop_flag = 1; +} + +VGMSTREAM * init_vgmstream_sfl(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamFileOGG = NULL; + char filenameOGG[260]; + char filename[260]; + + off_t file_size = -1; + + int loop_flag = 0; + long loop_start_ms = -1; + long loop_end_ms = -1; + uint32_t riff_size; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sfl",filename_extension(filename))) goto fail; + + /* check header */ + if ((uint32_t)read_32bitBE(0,streamFile)!=0x52494646) /* "RIFF" */ + goto fail; + /* check for SFPL form */ + if ((uint32_t)read_32bitBE(8,streamFile)!=0x5346504C) /* "SFPL" */ + goto fail; + + /* check for .OGG file */ + strcpy(filenameOGG,filename); + strcpy(filenameOGG+strlen(filenameOGG)-3,"ogg"); + + streamFileOGG = streamFile->open(streamFile,filenameOGG,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!streamFileOGG) { + goto fail; + } + + /* let the real initer do the parsing */ + vgmstream = init_vgmstream_ogg_vorbis(streamFileOGG); + if (!vgmstream) goto fail; + + close_streamfile(streamFileOGG); + streamFileOGG = NULL; + + /* now that we have an ogg, proceed with parsing the .sfl */ + riff_size = read_32bitLE(4,streamFile); + file_size = get_streamfile_size(streamFile); + + /* check for tructated RIFF */ + if (file_size < riff_size+8) goto fail; + + /* read through chunks to verify format and find metadata */ + { + off_t current_chunk = 0xc; /* start with first chunk */ + + while (current_chunk < file_size) { + uint32_t chunk_type = read_32bitBE(current_chunk,streamFile); + off_t chunk_size = read_32bitLE(current_chunk+4,streamFile); + + /* There seem to be a few bytes left over, included in the + * RIFF but not enough to make a new chunk. + */ + if (current_chunk+8 > file_size) break; + + if (current_chunk+8+chunk_size > file_size) goto fail; + + switch(chunk_type) { + case 0x4C495354: /* LIST */ + /* what lurks within?? */ + switch (read_32bitBE(current_chunk + 8, streamFile)) { + case 0x6164746C: /* adtl */ + /* yay, atdl is its own little world */ + parse_adtl(current_chunk + 8, chunk_size, + streamFile, + &loop_start_ms,&loop_end_ms,&loop_flag); + break; + default: + break; + } + break; + default: + /* ignorance is bliss */ + break; + } + + current_chunk += 8+chunk_size; + } + } + + if (loop_flag) { + /* install loops */ + if (!vgmstream->loop_flag) { + vgmstream->loop_flag = 1; + vgmstream->loop_ch = calloc(vgmstream->channels, + sizeof(VGMSTREAMCHANNEL)); + if (!vgmstream->loop_ch) goto fail; + } + + vgmstream->loop_start_sample = (long long)loop_start_ms*vgmstream->sample_rate/1000; + vgmstream->loop_end_sample = (long long)loop_end_ms*vgmstream->sample_rate/1000; + } + + vgmstream->meta_type = meta_OGG_SFL; + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (streamFileOGG) close_streamfile(streamFileOGG); + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} + +#endif diff --git a/lib/vgmstream/src/meta/sli.c b/lib/vgmstream/src/meta/sli.c new file mode 100644 index 0000000000..d94499246f --- /dev/null +++ b/lib/vgmstream/src/meta/sli.c @@ -0,0 +1,121 @@ +#include "../vgmstream.h" + +#ifdef VGM_USE_VORBIS + +#include <ctype.h> +#include "meta.h" +#include "../util.h" + +#ifdef WIN32 +#define DIRSEP '\\' +#else +#define DIRSEP '/' +#endif + +/* .sli is a file with loop points, associated with a similarly named .ogg */ + +VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamFileOGG = NULL; + char filename[260]; + char filenameOGG[260]; + char linebuffer[260]; + off_t bytes_read; + off_t sli_offset; + int done; + int32_t loop_start = -1; + int32_t loop_length = -1; + int32_t loop_from = -1; + int32_t loop_to = -1; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sli",filename_extension(filename))) goto fail; + + /* check for .OGG file */ + strcpy(filenameOGG,filename); + /* strip off .sli */ + filenameOGG[strlen(filenameOGG)-4]='\0'; + + streamFileOGG = streamFile->open(streamFile,filenameOGG,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!streamFileOGG) { + goto fail; + } + + /* let the real initer do the parsing */ + vgmstream = init_vgmstream_ogg_vorbis(streamFileOGG); + if (!vgmstream) goto fail; + + close_streamfile(streamFileOGG); + streamFileOGG = NULL; + + sli_offset = 0; + while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(streamFile)) { + char *endptr; + char *foundptr; + bytes_read=get_streamfile_dos_line(sizeof(linebuffer),linebuffer,sli_offset,streamFile,&done); + if (!done) goto fail; + + if (!memcmp("LoopStart=",linebuffer,10) && linebuffer[10]!='\0') { + loop_start = strtol(linebuffer+10,&endptr,10); + if (*endptr != '\0') { + /* if it didn't parse cleanly */ + loop_start = -1; + } + } + else if (!memcmp("LoopLength=",linebuffer,11) && linebuffer[11]!='\0') { + loop_length = strtol(linebuffer+11,&endptr,10); + if (*endptr != '\0') { + /* if it didn't parse cleanly */ + loop_length = -1; + } + } + + /* a completely different format, also with .sli extension and can be handled similarly */ + if ((foundptr=strstr(linebuffer,"To="))!=NULL && isdigit(foundptr[3])) { + loop_to = strtol(foundptr+3,&endptr,10); + if (*endptr != ';') { + loop_to = -1; + } + } + if ((foundptr=strstr(linebuffer,"From="))!=NULL && isdigit(foundptr[5])) { + loop_from = strtol(foundptr+5,&endptr,10); + if (*endptr != ';') { + loop_from = -1; + } + } + + sli_offset += bytes_read; + } + + if ((loop_start != -1 && loop_length != -1) || + (loop_to != -1 && loop_from != -1)) { + /* install loops */ + if (!vgmstream->loop_flag) { + vgmstream->loop_flag = 1; + vgmstream->loop_ch = calloc(vgmstream->channels, + sizeof(VGMSTREAMCHANNEL)); + if (!vgmstream->loop_ch) goto fail; + } + + if (loop_to != -1 && loop_from != -1) { + vgmstream->loop_start_sample = loop_to; + vgmstream->loop_end_sample = loop_from; + vgmstream->meta_type = meta_OGG_SLI2; + } else { + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_start+loop_length; + vgmstream->meta_type = meta_OGG_SLI; + } + } else goto fail; /* if there's no loop points the .sli wasn't valid */ + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (streamFileOGG) close_streamfile(streamFileOGG); + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} +#endif diff --git a/lib/vgmstream/src/meta/spt_spd.c b/lib/vgmstream/src/meta/spt_spd.c new file mode 100644 index 0000000000..7d5caa3cba --- /dev/null +++ b/lib/vgmstream/src/meta/spt_spd.c @@ -0,0 +1,96 @@ +#include "meta.h" +#include "../util.h" + +/* SPT+SPT + + 2008-11-27 - manakoAT : First try for splitted files... +*/ + +VGMSTREAM * init_vgmstream_spt_spd(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamFileSPT = NULL; + char filename[260]; + char filenameSPT[260]; + + int i; + int channel_count; + int loop_flag; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("spd",filename_extension(filename))) goto fail; + + + strcpy(filenameSPT,filename); + strcpy(filenameSPT+strlen(filenameSPT)-3,"spt"); + + streamFileSPT = streamFile->open(streamFile,filenameSPT,STREAMFILE_DEFAULT_BUFFER_SIZE); + + + if (!streamFileSPT) goto fail; + + channel_count = read_32bitBE(0x00,streamFileSPT); + loop_flag = read_32bitBE(0x04,streamFileSPT); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x08,streamFileSPT); + vgmstream->num_samples=read_32bitBE(0x14,streamFileSPT)*14/16/channel_count; + vgmstream->coding_type = coding_NGC_DSP; + + if(loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitBE(0x14,streamFileSPT)*14/16/channel_count; + } + + if (channel_count == 1) { + vgmstream->layout_type = layout_none; + } else if (channel_count == 2) { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size=0x4000; /* Unknown now, never seen 2ch files in psd+spt */ + } + + + + vgmstream->meta_type = meta_SPT_SPD; + + /* open the file for reading */ + { + for (i=0;i<channel_count;i++) { + /* Not sure, i'll put a fake value here for now */ + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); + vgmstream->ch[i].offset = 0; + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x20+i*2,streamFileSPT); + } + if (vgmstream->channels == 2) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x40+i*2,streamFileSPT); + } + } + } + + + close_streamfile(streamFileSPT); streamFileSPT=NULL; + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (streamFileSPT) close_streamfile(streamFileSPT); + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ss_stream.c b/lib/vgmstream/src/meta/ss_stream.c new file mode 100644 index 0000000000..d6e0d6dede --- /dev/null +++ b/lib/vgmstream/src/meta/ss_stream.c @@ -0,0 +1,61 @@ +#include "meta.h" +#include "../util.h" + +/* SS_STREAM + + SS_STREAM is format used by various UBI Soft Games + + 2008-11-15 - Fastelbja : First version ... +*/ + +VGMSTREAM * init_vgmstream_ss_stream(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + int loop_flag=0; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ss7",filename_extension(filename))) goto fail; + + loop_flag = 0; + channel_count=read_8bit(0x0C,streamFile)+1; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = 44100; + + if(channel_count==1) + vgmstream->coding_type = coding_IMA; + else + vgmstream->coding_type = coding_EACS_IMA; + + vgmstream->num_samples = (int32_t)((get_streamfile_size(streamFile) -0x44)* 2 / vgmstream->channels); + vgmstream->layout_type = layout_none; + + vgmstream->meta_type = meta_XBOX_WAVM; + vgmstream->get_high_nibble=0; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,36); + vgmstream->ch[i].offset = 0x44; + vgmstream->ch[i].adpcm_history1_32=(int32_t)read_16bitLE(0x10+i*4,streamFile); + vgmstream->ch[i].adpcm_step_index =(int)read_8bit(0x12+i*4,streamFile); + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/str_asr.c b/lib/vgmstream/src/meta/str_asr.c new file mode 100644 index 0000000000..bfaa20f181 --- /dev/null +++ b/lib/vgmstream/src/meta/str_asr.c @@ -0,0 +1,97 @@ +#include "meta.h" +#include "../util.h" + +/* STR -ASR (from Donkey Kong Jet Race) */ +VGMSTREAM * init_vgmstream_str_asr(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("str",filename_extension(filename)) && /* PCM Files */ + strcasecmp("asr",filename_extension(filename))) /* DSP Files */ + goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x4B4E4F4E && /* "KNON" */ + read_32bitBE(0x04,streamFile) != 0x00000000 && /* "0x0" */ + read_32bitBE(0x08,streamFile) != 0x57494920) goto fail; /* "WII\0x20" */ + + + loop_flag = (read_32bitBE(0x44,streamFile)!=0); + channel_count = 2; + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x40,streamFile); + + switch (read_32bitBE(0x20,streamFile)) { + case 0x4B415354: /* KAST - DSP encoding */ + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = (read_32bitBE(0x3C,streamFile))*14/8/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitBE(0x44,streamFile))*14/8/channel_count; + vgmstream->loop_end_sample = (read_32bitBE(0x48,streamFile))*14/8/channel_count; + } + vgmstream->interleave_block_size = 0x10; + break; + case 0x4B505354: /* KPST - PCM encoding */ + vgmstream->coding_type = coding_PCM16BE; + vgmstream->num_samples = (read_32bitBE(0x3C,streamFile))/2/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitBE(0x44,streamFile))/2/channel_count; + vgmstream->loop_end_sample = (read_32bitBE(0x48,streamFile))/2/channel_count; + } + vgmstream->interleave_block_size = 0x10; + break; + default: + goto fail; + } + + /* Interleave and Layout settings */ + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_STR_ASR; + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x8C+i*2,streamFile); + } + if (vgmstream->channels) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0xEC+i*2,streamFile); + } + } + } + + /* 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; +} diff --git a/lib/vgmstream/src/meta/str_snds.c b/lib/vgmstream/src/meta/str_snds.c new file mode 100644 index 0000000000..f2dc585471 --- /dev/null +++ b/lib/vgmstream/src/meta/str_snds.c @@ -0,0 +1,134 @@ +#include "meta.h" +#include "../coding/coding.h" +#include "../layout/layout.h" +#include "../util.h" + +/* 3DO format, .str extension and possibly a CTRL header, blocks and + * AIFF-C style format specifier. Blocks are not IFF-compliant. Interesting + * blocks are all SNDS */ + +VGMSTREAM * init_vgmstream_str_snds(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int channel_count; + int loop_flag = 0; + off_t SHDR_offset = -1; + int FoundSHDR = 0; + int CTRL_size = -1; + + size_t file_size; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("str",filename_extension(filename))) goto fail; + + /* check for opening CTRL or SNDS chunk */ + if (read_32bitBE(0x0,streamFile) != 0x4354524c && /* CTRL */ + read_32bitBE(0x0,streamFile) != 0x534e4453) /* SNDS */ + goto fail; + + file_size = get_streamfile_size(streamFile); + + /* scan chunks until we find a SNDS containing a SHDR */ + { + off_t current_chunk; + + current_chunk = 0; + + while (!FoundSHDR && current_chunk < file_size) { + if (current_chunk < 0) goto fail; + + if (current_chunk+read_32bitBE(current_chunk+4,streamFile) >= + file_size) goto fail; + + switch (read_32bitBE(current_chunk,streamFile)) { + case 0x4354524C: /* CTRL */ + /* to distinguish between styles */ + CTRL_size = read_32bitBE(current_chunk+4,streamFile); + break; + case 0x534e4453: /* SNDS */ + switch (read_32bitBE(current_chunk+16,streamFile)) { + case 0x53484452: /* SHDR */ + FoundSHDR = 1; + SHDR_offset = current_chunk+16; + break; + default: + break; + } + break; + default: + /* ignore others for now */ + break; + } + + current_chunk += read_32bitBE(current_chunk+4,streamFile); + } + } + + if (!FoundSHDR) goto fail; + + /* details */ + channel_count = read_32bitBE(SHDR_offset+0x20,streamFile); + loop_flag = 0; + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + if (CTRL_size == 0x1C) { + vgmstream->num_samples = + read_32bitBE(SHDR_offset+0x2c,streamFile)-1; /* sample count? */ + } else { + vgmstream->num_samples = + read_32bitBE(SHDR_offset+0x2c,streamFile) /* frame count? */ + * 0x10; + } + + vgmstream->num_samples/=vgmstream->channels; + + vgmstream->sample_rate = read_32bitBE(SHDR_offset+0x1c,streamFile); + switch (read_32bitBE(SHDR_offset+0x24,streamFile)) { + case 0x53445832: /* SDX2 */ + if (channel_count > 1) { + vgmstream->coding_type = coding_SDX2_int; + vgmstream->interleave_block_size = 1; + } else + vgmstream->coding_type = coding_SDX2; + break; + default: + goto fail; + } + vgmstream->layout_type = layout_str_snds_blocked; + vgmstream->meta_type = meta_STR_SNDS; + + /* channels and loop flag are set by allocate_vgmstream */ + if (loop_flag) { + /* just guessin', no way to set loop flag anyway */ + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + /* open the file for reading by each channel */ + { + int i; + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, + STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!vgmstream->ch[0].streamfile) goto fail; + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile; + } + } + + /* start me up */ + str_snds_block_update(0,vgmstream); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/svs.c b/lib/vgmstream/src/meta/svs.c new file mode 100644 index 0000000000..4e8eddd708 --- /dev/null +++ b/lib/vgmstream/src/meta/svs.c @@ -0,0 +1,69 @@ +#include "meta.h" +#include "../util.h" + +/* SVS (from Unlimited Saga) */ +/* probably Square Vag Stream */ +VGMSTREAM * init_vgmstream_svs(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("svs",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x53565300) /* "SVS\0" */ + goto fail; + + loop_flag = (read_32bitLE(0x08,streamFile)!=0); + /* 63.SVS has start and end on the same sample, which crashes stuff */ + if (read_32bitLE(0x08,streamFile)==read_32bitLE(0x0c,streamFile)) + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x40; + vgmstream->channels = channel_count; + vgmstream->sample_rate = 44100; + vgmstream->coding_type = coding_PSX; + vgmstream->num_samples = (get_streamfile_size(streamFile)-0x40)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = (read_32bitLE(0x08,streamFile)-1)*28; + vgmstream->loop_end_sample = (read_32bitLE(0x0c,streamFile)-1)*28; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + vgmstream->meta_type = meta_PS2_SVS; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/thp.c b/lib/vgmstream/src/meta/thp.c new file mode 100644 index 0000000000..298bae7168 --- /dev/null +++ b/lib/vgmstream/src/meta/thp.c @@ -0,0 +1,97 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* THP (Just play audio from .thp movie file) + by fastelbja */ + +VGMSTREAM * init_vgmstream_thp(STREAMFILE *streamFile) { + + VGMSTREAM * vgmstream = NULL; + + char filename[260]; + off_t start_offset; + + uint32_t maxAudioSize=0; + + uint32_t numComponents; + off_t componentTypeOffset; + off_t componentDataOffset; + + char thpVersion; + + int loop_flag; + int channel_count=-1; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("thp",filename_extension(filename)) && + strcasecmp("dsp",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x54485000) + goto fail; + + maxAudioSize = read_32bitBE(0x0C,streamFile); + thpVersion = read_8bit(0x06,streamFile); + + if(maxAudioSize==0) // no sound + goto fail; + + loop_flag = 0; // allways unloop + + /* fill in the vital statistics */ + start_offset = read_32bitBE(0x28,streamFile); + + // Get info from the first block + componentTypeOffset = read_32bitBE(0x20,streamFile); + numComponents = read_32bitBE(componentTypeOffset ,streamFile); + componentDataOffset=componentTypeOffset+0x14; + componentTypeOffset+=4; + + for(i=0;i<numComponents;i++) { + if(read_8bit(componentTypeOffset+i,streamFile)==1) { + channel_count=read_32bitBE(componentDataOffset,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->channels=channel_count; + vgmstream->sample_rate=read_32bitBE(componentDataOffset+4,streamFile); + vgmstream->num_samples=read_32bitBE(componentDataOffset+8,streamFile); + break; + } else { + if(thpVersion==0x10) + componentDataOffset+=0x0c; + else + componentDataOffset+=0x08; + } + } + + /* 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->thpNextFrameSize=read_32bitBE(0x18,streamFile); + thp_block_update(start_offset,vgmstream); + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_thp_blocked; + vgmstream->meta_type = meta_THP; + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/vgs.c b/lib/vgmstream/src/meta/vgs.c new file mode 100644 index 0000000000..3890780f46 --- /dev/null +++ b/lib/vgmstream/src/meta/vgs.c @@ -0,0 +1,100 @@ +#include "meta.h" +#include "../util.h" + +/* VGS (from Guitar Hero Encore - Rocks the 80s) */ +VGMSTREAM * init_vgmstream_vgs(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_flag; + int channel_flag_offset; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("vgs",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x56675321) /* "VgS!" */ + goto fail; + + loop_flag = 0; + channel_flag_offset = get_streamfile_size(streamFile)-0x10; + channel_flag = read_32bitBE(channel_flag_offset,streamFile); + + /* Only seen files up to 5 channels, but just + to be sure we will look up to 8 chanels */ + switch (channel_flag) { + case 0x00800000: + channel_count = 1; + break; + case 0x00810000: + channel_count = 2; + break; + case 0x00820000: + channel_count = 3; + break; + case 0x00830000: + channel_count = 4; + break; + case 0x00840000: + channel_count = 5; + break; + case 0x00850000: + channel_count = 6; + break; + case 0x00860000: + channel_count = 7; + break; + case 0x00870000: + channel_count = 8; + break; + default: + goto fail; + } + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x80; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + vgmstream->coding_type = coding_PSX_badflags; + vgmstream->num_samples = (read_32bitLE(0x0C,streamFile)*channel_count*0x10)*28/16/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (read_32bitLE(0x0C,streamFile)*channel_count*0x10)*28/16/channel_count; + } + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + vgmstream->meta_type = meta_VGS; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/vs.c b/lib/vgmstream/src/meta/vs.c new file mode 100644 index 0000000000..b7abe1f86e --- /dev/null +++ b/lib/vgmstream/src/meta/vs.c @@ -0,0 +1,75 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* VS (from Men in Black) */ +VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + int i; + + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("vs",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0xC8000000) /* "0xC8000000" */ + goto fail; + + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x08; + vgmstream->channels = channel_count; + vgmstream->interleave_block_size=0x10; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + vgmstream->coding_type = coding_PSX; + +#if 0 + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = (read_32bitLE(0x0c,streamFile)-start_offset); + } +#endif + + vgmstream->layout_type = layout_vs_blocked; + vgmstream->meta_type = meta_VS; + + + /* open the file for reading */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x2000); + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + /* Calc num_samples */ + vs_block_update(start_offset,vgmstream); + vgmstream->num_samples=0; + + do { + vgmstream->num_samples += vgmstream->current_block_size*28/16; + vs_block_update(vgmstream->next_block_offset,vgmstream); + } while (vgmstream->next_block_offset<get_streamfile_size(streamFile)); + + vs_block_update(start_offset,vgmstream); + + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/wii_mus.c b/lib/vgmstream/src/meta/wii_mus.c new file mode 100644 index 0000000000..a6cdd979e5 --- /dev/null +++ b/lib/vgmstream/src/meta/wii_mus.c @@ -0,0 +1,124 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../coding/coding.h" +#include "../util.h" + +/* .mus, as seen in Star Wars The Force Unleashed for Wii */ +/* Doesn't seem to be working quite right yet, coef table looks odd */ +VGMSTREAM * init_vgmstream_wii_mus(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + off_t start_offset; + off_t interleave; + + int i; + struct { + uint16_t gain; + uint16_t initial_ps; + uint16_t initial_hist1; + uint16_t initial_hist2; + uint16_t loop_ps; + /* + uint16_t loop_hist1; + uint16_t loop_hist2; + */ + } channel[2]; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("mus",filename_extension(filename))) goto fail; + + start_offset = read_32bitBE(0x08,streamFile); + interleave = read_32bitBE(0x04,streamFile); + + for (i=0;i<2;i++) + { + channel[i].gain = read_16bitBE(0x30+i*0x2e,streamFile); + channel[i].initial_ps = read_16bitBE(0x32+i*0x2e,streamFile); + channel[i].initial_hist1 = read_16bitBE(0x34+i*0x2e,streamFile); + channel[i].initial_hist2 = read_16bitBE(0x36+i*0x2e,streamFile); + channel[i].loop_ps = read_16bitBE(0x38+i*0x2e,streamFile); + } + + /* check initial predictor/scale */ + if (channel[0].initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) + goto fail; + if (channel[1].initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile)) + goto fail; + + /* check type==0 and gain==0 */ + if (channel[0].gain || + channel[1].gain) + goto fail; + +#if 0 + if (ch0_header.loop_flag) { + off_t loop_off; + /* check loop predictor/scale */ + loop_off = ch0_header.loop_start_offset/16*8; + loop_off = (loop_off/interleave*interleave*2) + (loop_off%interleave); + if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) + goto fail; + if (ch1_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off+interleave,streamFile)) + goto fail; + } +#endif + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(2,0); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = read_32bitBE(0x0,streamFile); + vgmstream->sample_rate = (uint16_t)read_16bitBE(0x6c,streamFile); + + /* TODO: adjust for interleave? */ +#if 0 + vgmstream->loop_start_sample = dsp_nibbles_to_samples( + ch0_header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples( + ch0_header.loop_end_offset)+1; +#endif + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + vgmstream->meta_type = meta_DSP_WII_MUS; + + /* coeffs */ + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x10 + i*2,streamFile); + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x3e + i*2,streamFile); + } + + /* initial history */ + /* always 0 that I've ever seen, but for completeness... */ + vgmstream->ch[0].adpcm_history1_16 = channel[0].initial_hist1; + vgmstream->ch[0].adpcm_history2_16 = channel[0].initial_hist2; + vgmstream->ch[1].adpcm_history1_16 = channel[1].initial_hist1; + vgmstream->ch[1].adpcm_history2_16 = channel[1].initial_hist2; + + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,interleave); + if (!vgmstream->ch[0].streamfile) goto fail; + vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,interleave); + if (!vgmstream->ch[1].streamfile) goto fail; + + /* open the file for reading */ + for (i=0;i<2;i++) { + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=start_offset+i*interleave; + } + + return vgmstream; + +fail: + /* clean up anything we may have opened */ + if (vgmstream) { + if (vgmstream->ch[0].streamfile) close_streamfile(vgmstream->ch[0].streamfile); + close_vgmstream(vgmstream); + } + return NULL; +} + diff --git a/lib/vgmstream/src/meta/wii_smp.c b/lib/vgmstream/src/meta/wii_smp.c new file mode 100644 index 0000000000..adb7040be3 --- /dev/null +++ b/lib/vgmstream/src/meta/wii_smp.c @@ -0,0 +1,75 @@ +#include "meta.h" +#include "../util.h" + +/* SMP (Mushroom Men: The Spore Wars ) */ +VGMSTREAM * init_vgmstream_wii_smp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("smp",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x05000000) /* 0x05000000 */ + goto fail; + + loop_flag = 0; + channel_count = read_32bitLE(0x28,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x1C,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x30,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitLE(0x34,streamFile)/2; + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = read_32bitLE(0x34,streamFile)/2; + } + + /* We have no interleave, so we have no layout */ + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_WII_SMP; + + /* 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; + + } + } + + /*Retrieving the coef table... + This game has an exception, the coefs are stored in Little Endian... */ + { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitLE(0x50+i*2,streamFile); + } + } + + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/wii_sng.c b/lib/vgmstream/src/meta/wii_sng.c new file mode 100644 index 0000000000..1ba6e13a85 --- /dev/null +++ b/lib/vgmstream/src/meta/wii_sng.c @@ -0,0 +1,125 @@ +#include "meta.h" +#include "../util.h" + +/* SNG (from Excite Truck [WII]) */ +VGMSTREAM * init_vgmstream_wii_sng(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int i; + int loop_flag; + int channel_count; + int coef1; + int coef2; + int first_block_len; + int second_channel_start; + int dataBuffer = 0; + int Founddata = 0; + size_t file_size; + off_t current_chunk; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sng",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x30545352) /* "0STR" */ + goto fail; + if (read_32bitBE(0x04,streamFile) != 0x34000000) /* 0x34000000 */ + goto fail; + if (read_32bitBE(0x08,streamFile) != 0x08000000) /* 0x08000000" */ + goto fail; + if (read_32bitBE(0x0C,streamFile) != 0x01000000) /* 0x01000000 */ + goto fail; + if (read_32bitLE(0x10,streamFile) != (get_streamfile_size(streamFile))) + goto fail; + + loop_flag = (read_32bitLE(0x130,streamFile) !=0); /* not sure */ + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x180; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x110,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitLE(0x100,streamFile)/16*14*2; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x130,streamFile)/16*14; + vgmstream->loop_end_sample = read_32bitBE(0x134,streamFile)/16*14; + } + + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_WII_SNG; + + + /* scan file until we find a "data" string */ + first_block_len = read_32bitLE(0x100,streamFile); + file_size = get_streamfile_size(streamFile); + { + current_chunk = first_block_len; + /* Start at 0 and loop until we reached the + file size, or until we found a "data string */ + while (!Founddata && current_chunk < file_size) { + dataBuffer = (read_32bitLE(current_chunk,streamFile)); + if (dataBuffer == first_block_len) { /* The value from the first block length */ + /* if "data" string found, retrieve the needed infos */ + Founddata = 1; + second_channel_start = current_chunk+0x80; + /* We will cancel the search here if we have a match */ + break; + } + /* else we will increase the search offset by 1 */ + current_chunk = current_chunk + 1; + } + } + + coef1 = 0x13C; + if (Founddata == 0) { + goto fail; + } else if (Founddata == 1) { + coef2 = current_chunk+0x3C; + } + + + for (i=0;i<16;i++) + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(coef1+i*2,streamFile); + if (channel_count == 2) { + for (i=0;i<16;i++) + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(coef2+i*2,streamFile); + } + + /* open the file for reading */ + { + 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; + + /* The first channel */ + vgmstream->ch[0].channel_start_offset= + vgmstream->ch[0].offset=start_offset; + + /* The second channel */ + if (channel_count == 2) { + vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (!vgmstream->ch[1].streamfile) goto fail; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[1].offset=second_channel_start; + } + } +} + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/wii_sts.c b/lib/vgmstream/src/meta/wii_sts.c new file mode 100644 index 0000000000..c63aa96b8b --- /dev/null +++ b/lib/vgmstream/src/meta/wii_sts.c @@ -0,0 +1,87 @@ +#include "meta.h" +#include "../util.h" + +/* STS + + STS (found in Shikigami No Shiro 3) + Don't confuse with ps2 .STS (EXST) format, this one is for WII +*/ + +VGMSTREAM * init_vgmstream_wii_sts(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + int i,j; + off_t start_offset; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("sts",filename_extension(filename))) goto fail; + + /* First bytes contain the size of the file (-4) */ + if(read_32bitBE(0x0,streamFile)!=get_streamfile_size(streamFile)-4) + goto fail; + + loop_flag = (read_32bitLE(0x4C,streamFile)!=0xFFFFFFFF); + channel_count=read_8bit(0x8,streamFile)+1; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x0A,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + + if(vgmstream->channels==1) + vgmstream->num_samples = (read_32bitBE(0x0,streamFile)+4-0x70)/8*14; + else + vgmstream->num_samples = (read_32bitBE(0x0,streamFile)+4-0x50-0x26)/8*14/2; + + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_STS_WII; + + if(loop_flag) { + vgmstream->loop_start_sample=read_32bitLE(0x24,streamFile); + vgmstream->loop_end_sample=vgmstream->num_samples; + } + + /* setting coef tables */ + if(vgmstream->channels==1) + start_offset = 0x70; + else + start_offset = 0x50; + + // First channel + for(j=0;j<16;j++) { + vgmstream->ch[0].adpcm_coef[j]=read_16bitBE(0x1E + (j*2),streamFile); + } + + // Second channel ? + if(vgmstream->channels==2) { + start_offset+=read_32bitBE(0x1a,streamFile); + for(j=0;j<16;j++) { + vgmstream->ch[1].adpcm_coef[j]=read_16bitBE(start_offset+(j*2),streamFile); + } + } + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,36); + vgmstream->ch[i].offset = 0x50+(i*(start_offset+0x26-0x50)); + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ws_aud.c b/lib/vgmstream/src/meta/ws_aud.c new file mode 100644 index 0000000000..4020d09957 --- /dev/null +++ b/lib/vgmstream/src/meta/ws_aud.c @@ -0,0 +1,132 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* Westwood Studios .aud (WS-AUD) */ + +VGMSTREAM * init_vgmstream_ws_aud(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + coding_t coding_type = -1; + off_t format_offset; + + int channel_count; + int new_type = 0; /* if 0 is old type */ + + int bytes_per_sample = 0; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("aud",filename_extension(filename))) goto fail; + + /* check for 0x0000DEAF chunk marker for first chunk */ + if (read_32bitLE(0x10,streamFile)==0x0000DEAF) { /* new */ + new_type = 1; + } else if (read_32bitLE(0x0C,streamFile)==0x0000DEAF) { /* old */ + new_type = 0; + } else goto fail; + + if (new_type) + format_offset = 0xa; + else + format_offset = 0x6; + + /* get channel count */ + if (read_8bit(format_offset,streamFile) & 1) + channel_count = 2; + else + channel_count = 1; + + if (channel_count == 2) goto fail; /* TODO: not yet supported (largely + because not yet seen) */ + + /* get output format */ + if (read_8bit(format_offset+1,streamFile) & 2) + bytes_per_sample = 2; + else + bytes_per_sample = 1; + + /* check codec type */ + switch (read_8bit(format_offset+1,streamFile)) { + case 1: /* Westwood custom */ + coding_type = coding_WS; + /* shouldn't happen? */ + if (bytes_per_sample != 1) goto fail; + break; + case 99: /* IMA ADPCM */ + coding_type = coding_IMA; + break; + default: + goto fail; + break; + } + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,0); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + if (new_type) { + vgmstream->num_samples = read_32bitLE(0x06,streamFile)/bytes_per_sample/channel_count; + } else { + /* Doh, no output size in old type files. We have to read through the + * file looking at chunk headers! Crap! */ + int32_t out_size = 0; + off_t current_offset = 0x8; + off_t file_size = get_streamfile_size(streamFile); + + while (current_offset < file_size) { + int16_t chunk_size; + chunk_size = read_16bitLE(current_offset,streamFile); + out_size += read_16bitLE(current_offset+2,streamFile); + /* while we're here might as well check for valid chunks */ + if (read_32bitLE(current_offset+4,streamFile) != 0x0000DEAF) goto fail; + current_offset+=8+chunk_size; + } + + vgmstream->num_samples = out_size/bytes_per_sample/channel_count; + } + + /* they tend to not actually have data for the last odd sample */ + if (vgmstream->num_samples & 1) vgmstream->num_samples--; + vgmstream->sample_rate = (uint16_t)read_16bitLE(0x00,streamFile); + + vgmstream->coding_type = coding_type; + if (new_type) { + vgmstream->meta_type = meta_WS_AUD; + } else { + vgmstream->meta_type = meta_WS_AUD_old; + } + + vgmstream->layout_type = layout_ws_aud_blocked; + + /* open the file for reading by each channel */ + { + 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; + } + } + + /* start me up */ + if (new_type) { + ws_aud_block_update(0xc,vgmstream); + } else { + ws_aud_block_update(0x8,vgmstream); + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/xbox_ims.c b/lib/vgmstream/src/meta/xbox_ims.c new file mode 100644 index 0000000000..782d32d5a6 --- /dev/null +++ b/lib/vgmstream/src/meta/xbox_ims.c @@ -0,0 +1,61 @@ +#include "meta.h" +#include "../util.h" +#include "../layout/layout.h" + +/* matx + + MATX (found in Matrix) +*/ + +VGMSTREAM * init_vgmstream_xbox_matx(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("matx",filename_extension(filename))) goto fail; + + loop_flag = 0; + channel_count=read_16bitLE(0x4,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_16bitLE(0x06,streamFile) & 0xffff; + vgmstream->coding_type = coding_XBOX; + + vgmstream->layout_type = layout_matx_blocked; + vgmstream->meta_type = meta_XBOX_MATX; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,36); + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + /* Calc num_samples */ + matx_block_update(0,vgmstream); + vgmstream->num_samples=0; + + do { + vgmstream->num_samples += vgmstream->current_block_size/36*64; + matx_block_update(vgmstream->next_block_offset,vgmstream); + } while (vgmstream->next_block_offset<get_streamfile_size(streamFile)); + + matx_block_update(0,vgmstream); + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/xbox_stma.c b/lib/vgmstream/src/meta/xbox_stma.c new file mode 100644 index 0000000000..ed995ec4b9 --- /dev/null +++ b/lib/vgmstream/src/meta/xbox_stma.c @@ -0,0 +1,64 @@ +#include "meta.h" +#include "../util.h" + +/* STMA + + STMA (found in Midnight Club 2) +*/ + +VGMSTREAM * init_vgmstream_xbox_stma(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("stma",filename_extension(filename))) goto fail; + + if(read_32bitBE(0x0,streamFile)!=0x53544D41) + goto fail; + + loop_flag = ((read_32bitLE(0x20,streamFile)==1) || (read_32bitLE(0x18,streamFile)>read_32bitLE(0x1C,streamFile))); + + /* Seems that the loop flag is not allways well defined */ + /* Some of the tracks should loop, but without flag set */ + channel_count=read_32bitLE(0x14,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x0C,streamFile); + vgmstream->coding_type = coding_INT_DVI_IMA; + vgmstream->num_samples = read_32bitLE(0x18,streamFile)*2/vgmstream->channels; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size=0x40; + vgmstream->meta_type = meta_XBOX_STMA; + + if(loop_flag) { + vgmstream->loop_start_sample=read_32bitLE(0x24,streamFile); + vgmstream->loop_end_sample=vgmstream->num_samples; + } + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,36); + vgmstream->ch[i].offset = 0x800+(i*vgmstream->interleave_block_size); + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/xbox_wavm.c b/lib/vgmstream/src/meta/xbox_wavm.c new file mode 100644 index 0000000000..2d2413b919 --- /dev/null +++ b/lib/vgmstream/src/meta/xbox_wavm.c @@ -0,0 +1,61 @@ +#include "meta.h" +#include "../util.h" + +/* WAVM + + WAVM is an headerless format which can be found on XBOX + known extensions : WAVM + + 2008-05-23 - Fastelbja : First version ... +*/ + +VGMSTREAM * init_vgmstream_xbox_wavm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("wavm",filename_extension(filename))) goto fail; + + /* No loop on wavm */ + loop_flag = 0; + + /* Always stereo files */ + channel_count=2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + /* allways 2 channels @ 44100 Hz */ + vgmstream->channels = 2; + vgmstream->sample_rate = 44100; + + vgmstream->coding_type = coding_XBOX; + vgmstream->num_samples = (int32_t)(get_streamfile_size(streamFile) / 36 * 64 / vgmstream->channels); + vgmstream->layout_type = layout_none; + + vgmstream->meta_type = meta_XBOX_WAVM; + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,36); + vgmstream->ch[i].offset = 0; + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/xbox_wvs.c b/lib/vgmstream/src/meta/xbox_wvs.c new file mode 100644 index 0000000000..036fd466e9 --- /dev/null +++ b/lib/vgmstream/src/meta/xbox_wvs.c @@ -0,0 +1,67 @@ +#include "meta.h" +#include "../util.h" + +/* WVS + + WVS (found in Metal Arms - Glitch in the System) +*/ + +VGMSTREAM * init_vgmstream_xbox_wvs(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("wvs",filename_extension(filename))) goto fail; + + if((read_16bitLE(0x0C,streamFile)!=0x69) && + (read_16bitLE(0x08,streamFile)!=0x4400) && + (read_32bitLE(0x0,streamFile)!=get_streamfile_size(streamFile)+0x20)) + goto fail; + + /* Loop seems to be set if offset(0x0A) == 0x472C */ + loop_flag = (read_16bitLE(0x0A,streamFile)==0x472C); + + /* Always stereo files */ + channel_count=read_16bitLE(0x0E,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + /* allways 2 channels @ 44100 Hz */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + + vgmstream->coding_type = coding_XBOX; + vgmstream->num_samples = read_32bitLE(0,streamFile) / 36 * 64 / vgmstream->channels; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_XBOX_WVS; + + if(loop_flag) { + vgmstream->loop_start_sample=0; + vgmstream->loop_end_sample=vgmstream->num_samples; + } + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,36); + vgmstream->ch[i].offset = 0x20; + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/xbox_xmu.c b/lib/vgmstream/src/meta/xbox_xmu.c new file mode 100644 index 0000000000..983cf71a3a --- /dev/null +++ b/lib/vgmstream/src/meta/xbox_xmu.c @@ -0,0 +1,65 @@ +#include "meta.h" +#include "../util.h" + +/* XMU + + XMU (found in Alter Echo) +*/ + +VGMSTREAM * init_vgmstream_xbox_xmu(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("xmu",filename_extension(filename))) goto fail; + + if((read_32bitBE(0x00,streamFile)!=0x584D5520) && + (read_32bitBE(0x08,streamFile)!=0x46524D54)) + goto fail; + + /* No Loop found atm */ + loop_flag = read_8bit(0x16,streamFile);; + + /* Always stereo files */ + channel_count=read_8bit(0x14,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x10,streamFile); + + vgmstream->coding_type = coding_XBOX; + vgmstream->num_samples = read_32bitLE(0x7FC,streamFile) / 36 * 64 / vgmstream->channels; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_XBOX_XMU; + + if(loop_flag) { + vgmstream->loop_start_sample=0; + vgmstream->loop_end_sample=vgmstream->num_samples; + } + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,36); + vgmstream->ch[i].offset = 0x800; + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/xbox_xvas.c b/lib/vgmstream/src/meta/xbox_xvas.c new file mode 100644 index 0000000000..c0d76920a7 --- /dev/null +++ b/lib/vgmstream/src/meta/xbox_xvas.c @@ -0,0 +1,72 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +/* XVAS + + XVAS (found in TMNT 2 & TMNT 3)) +*/ + +VGMSTREAM * init_vgmstream_xbox_xvas(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + int i; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("xvas",filename_extension(filename))) goto fail; + + if((read_32bitLE(0x00,streamFile)!=0x69) && + (read_32bitLE(0x08,streamFile)!=0x48)) + goto fail; + + /* No Loop found atm */ + loop_flag = (read_32bitLE(0x14,streamFile)==read_32bitLE(0x24,streamFile)); + + /* Always stereo files */ + channel_count=read_32bitLE(0x04,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x0c,streamFile); + + vgmstream->coding_type = coding_XBOX; + vgmstream->num_samples = read_32bitLE(0x24,streamFile); + vgmstream->num_samples -= ((vgmstream->num_samples/0x20000)*0x20); + vgmstream->num_samples = vgmstream->num_samples / 36 * 64 / vgmstream->channels; + + vgmstream->layout_type = layout_xvas_blocked; + vgmstream->meta_type = meta_XBOX_XVAS; + + if(loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x10,streamFile); + vgmstream->loop_start_sample -= ((vgmstream->loop_start_sample/0x20000)*0x20); + vgmstream->loop_start_sample = vgmstream->loop_start_sample / 36 * 64 / vgmstream->channels; + vgmstream->loop_end_sample=vgmstream->num_samples; + } + + /* open the file for reading by each channel */ + { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,36); + vgmstream->ch[i].offset = 0x800; + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + + xvas_block_update(0x800,vgmstream); + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/xbox_xwav.c b/lib/vgmstream/src/meta/xbox_xwav.c new file mode 100644 index 0000000000..3b446e1b93 --- /dev/null +++ b/lib/vgmstream/src/meta/xbox_xwav.c @@ -0,0 +1,107 @@ +#include "meta.h" +#include "../util.h" + +/* XWAV + + XWAV use the common RIFF/WAVE format with Codec ID = 0x0069 + It has been renamed to xwav to avoid vgmstream to handle all RIFF/WAV format + known extensions : XWAV + + 2008-05-24 - Fastelbja : First version ... +*/ + +VGMSTREAM * init_vgmstream_xbox_xwav(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int loop_flag=0; + int channel_count; + off_t start_offset; + int i,j=0; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("xwav",filename_extension(filename))) goto fail; + + /* Check for headers */ + if(!((read_32bitBE(0x00,streamFile)==0x52494646) && + (read_32bitBE(0x08,streamFile)==0x57415645) && + (read_32bitBE(0x0C,streamFile)==0x666D7420) && + (read_16bitLE(0x14,streamFile)==0x0069))) + goto fail; + + /* No loop on wavm */ + if(read_32bitBE(0x28,streamFile)==0x77736D70) + loop_flag = 1; + else + loop_flag = 0; + + /* Always stereo files */ + channel_count=read_16bitLE(0x16,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* hack for loop wave found on Dynasty warriors */ + if(loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x4C,streamFile); + vgmstream->loop_end_sample = vgmstream->loop_start_sample + read_32bitLE(0x50,streamFile); + } + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x18,streamFile); + + /* search for "data" */ + start_offset=0x1C; + + do { + if(read_32bitBE(start_offset,streamFile)==0x64617461) + break; + start_offset+=4; + } while (start_offset<(off_t)get_streamfile_size(streamFile)); + + if(start_offset>=(off_t)get_streamfile_size(streamFile)) + goto fail; + + start_offset+=4; + + vgmstream->coding_type = coding_XBOX; + vgmstream->num_samples = read_32bitLE(start_offset,streamFile) / 36 * 64 / vgmstream->channels; + vgmstream->layout_type = layout_none; + + vgmstream->meta_type = meta_XBOX_RIFF; + + /* open the file for reading by each channel */ + + { + if(channel_count>2) { + for (i=0;i<channel_count;i++,j++) { + if((j&2) && (i!=0)) { + j=0; + start_offset+=36*2; + } + + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,36); + vgmstream->ch[i].offset = start_offset+4; + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } else { + for (i=0;i<channel_count;i++) { + vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,36); + vgmstream->ch[i].offset = start_offset+4; + + if (!vgmstream->ch[i].streamfile) goto fail; + } + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/xss.c b/lib/vgmstream/src/meta/xss.c new file mode 100644 index 0000000000..8cfa351730 --- /dev/null +++ b/lib/vgmstream/src/meta/xss.c @@ -0,0 +1,72 @@ +#include "meta.h" +#include "../util.h" + +/* XSS (found in Dino Crisis 3) */ +VGMSTREAM * init_vgmstream_xss(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("xss",filename_extension(filename))) goto fail; + + /* check header */ + if ((uint16_t)read_16bitLE(0x15A,streamFile) != 0x10) + goto fail; + if (read_32bitLE(0x154,streamFile) / read_32bitLE(0x150,streamFile) != + (uint16_t)read_16bitLE(0x158,streamFile)) + goto fail; + + loop_flag = (read_32bitLE(0x144,streamFile)!=0); + channel_count = (uint16_t)read_16bitLE(0x14E,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x800; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitLE(0x150,streamFile); + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x144,streamFile)/2/channel_count; + vgmstream->loop_end_sample = read_32bitLE(0x148,streamFile)/2/channel_count; + } + + if (vgmstream->channels == 1) { + vgmstream->layout_type = layout_none; + } else if (vgmstream->channels > 1) { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + } + + vgmstream->meta_type = meta_XSS; + + /* 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; +} diff --git a/lib/vgmstream/src/meta/xwb.c b/lib/vgmstream/src/meta/xwb.c new file mode 100644 index 0000000000..eaf1218ca1 --- /dev/null +++ b/lib/vgmstream/src/meta/xwb.c @@ -0,0 +1,103 @@ +#include "meta.h" +#include "../util.h" +/* XWB (found in King of Fighters 2003 (XBOX)) */ +VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + int loop_flag = 0; + int channel_count; + int coding; + int coding_flag; + int num_samples; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("xwb",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x57424E44) /* WBND */ + goto fail; +#if 0 + /* check if the file is been used as container */ + if (read_32bitBE(0x2C,streamFile) != 0x01000000) + goto fail; +#endif + /* if it's looped it should be 2, didn't see anything else... */ + loop_flag = (uint8_t)(read_8bit(0x50,streamFile)); + + if (loop_flag == 2) { + loop_flag = 1; + } else if (loop_flag < 2) { + loop_flag = 0; + } + + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = read_32bitLE(0x20,streamFile); + vgmstream->channels = channel_count; + vgmstream->sample_rate = 44100; /* read_32bitLE(0x08,streamFile); */ + + coding_flag = (uint8_t)(read_8bit(0x52,streamFile)); + switch (coding_flag) { + case 0: + coding = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + num_samples = read_32bitLE(0x5C,streamFile)/2/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x60,streamFile)/2/channel_count; + vgmstream->loop_end_sample = read_32bitLE(0x5C,streamFile)/2/channel_count; + } + break; + case 1: + coding = coding_XBOX; + vgmstream->layout_type = layout_none; + num_samples = read_32bitLE(0x5C,streamFile)/36/channel_count*64; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(0x60,streamFile)/36/channel_count*64; + vgmstream->loop_end_sample = read_32bitLE(0x5C,streamFile)/36/channel_count*64; + } + break; + default: + goto fail; + } + + vgmstream->coding_type = coding; + vgmstream->num_samples = num_samples; + vgmstream->meta_type = meta_XWB; + + /* 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; + + + if (vgmstream->coding_type == coding_XBOX) { + /* xbox interleaving is a little odd */ + vgmstream->ch[i].channel_start_offset=start_offset; + } else { + vgmstream->ch[i].channel_start_offset= + start_offset+vgmstream->interleave_block_size*i; + } + vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset; + + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/meta/ydsp.c b/lib/vgmstream/src/meta/ydsp.c new file mode 100644 index 0000000000..007faa3048 --- /dev/null +++ b/lib/vgmstream/src/meta/ydsp.c @@ -0,0 +1,83 @@ +#include "meta.h" +#include "../util.h" + +/* YDSP (from WWE Day of Reckoning) */ +VGMSTREAM * init_vgmstream_ydsp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("ydsp",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x59445350) /* "YDSP" */ + goto fail; + + loop_flag = (read_32bitBE(0xB0,streamFile)!=0); + channel_count = 2; /* (uint32_t)read_16bitBE(0x10,streamFile); */ + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x120; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x0C,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = (read_32bitBE(0x08,streamFile))*14/8/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0xB0,streamFile); + vgmstream->loop_end_sample = read_32bitBE(0xB4,streamFile); + } + + if (channel_count == 1) { + vgmstream->layout_type = layout_none; + } else if (channel_count == 2) { + vgmstream->interleave_block_size = read_32bitBE(0x14,streamFile); + vgmstream->layout_type = layout_interleave; + } + + vgmstream->meta_type = meta_YDSP; + + /* open the file for reading */ + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x20+i*2,streamFile); + } + if (vgmstream->channels == 2) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x44+i*2,streamFile); + } + } + } + + { + 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; +} diff --git a/lib/vgmstream/src/meta/zwdsp.c b/lib/vgmstream/src/meta/zwdsp.c new file mode 100644 index 0000000000..8fd52636f7 --- /dev/null +++ b/lib/vgmstream/src/meta/zwdsp.c @@ -0,0 +1,88 @@ +#include "meta.h" +#include "../util.h" + +/* ZWDSP (hcs' custom DSP files from Zack & Wiki) */ +VGMSTREAM * init_vgmstream_zwdsp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset; + + int loop_flag; + int channel_count; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("zwdsp",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x00000000) /* 0x0 */ + goto fail; + + /* Retrieve the loop flag, some files have 0x0 and some 0x02 as "no loop" */ + + switch (read_32bitBE(0x10, streamFile)) { + case 0: + case 2: + loop_flag = 0; + break; + default: + loop_flag = 1; + } + + channel_count = read_32bitBE(0x1C,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + start_offset = 0x90; + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bitBE(0x08,streamFile); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count; + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x10,streamFile)*14/8/channel_count; + vgmstream->loop_end_sample = read_32bitBE(0x14,streamFile)*14/8/channel_count; + } + + + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_ZWDSP; + + + if (vgmstream->coding_type == coding_NGC_DSP) { + int i; + for (i=0;i<16;i++) { + vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x20+i*2,streamFile); + } + if (vgmstream->channels == 2) { + for (i=0;i<16;i++) { + vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x60+i*2,streamFile); + } + } + } + + /* 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+ + ((get_streamfile_size(streamFile)-start_offset)/2)*i; + + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/lib/vgmstream/src/streamfile.c b/lib/vgmstream/src/streamfile.c new file mode 100644 index 0000000000..6fc6fc54b2 --- /dev/null +++ b/lib/vgmstream/src/streamfile.c @@ -0,0 +1,276 @@ +#ifndef _MSC_VER +#include <unistd.h> +#endif +#include "streamfile.h" +#include "util.h" + +#ifdef _WIN32 +#define IS_VALID_STREAM(stream) (stream != NULL && (stream->_ptr != NULL)) +#else +#define IS_VALID_STREAM(stream) (stream) +#endif + +typedef struct { + STREAMFILE sf; + FILE * infile; + off_t offset; + size_t validsize; + uint8_t * buffer; + size_t buffersize; + char name[260]; +#ifdef PROFILE_STREAMFILE + size_t bytes_read; + int error_count; +#endif +} STDIOSTREAMFILE; + +static STREAMFILE * open_stdio_streamfile_buffer_by_FILE(FILE *infile,const char * const filename, size_t buffersize); + +static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOSTREAMFILE * streamfile) { + size_t length_read_total=0; + + /* is the beginning at least there? */ + if (offset >= streamfile->offset && offset < streamfile->offset+streamfile->validsize) { + size_t length_read; + off_t offset_into_buffer = offset-streamfile->offset; + length_read = streamfile->validsize-offset_into_buffer; + memcpy(dest,streamfile->buffer+offset_into_buffer,length_read); + length_read_total += length_read; + length -= length_read; + offset += length_read; + dest += length_read; + } + + /* TODO: What would make more sense here is to read the whole request + * at once into the dest buffer, as it must be large enough, and then + * copy some part of that into our own buffer. + * The destination buffer is supposed to be much smaller than the + * STREAMFILE buffer, though. Maybe we should only ever return up + * to the buffer size to avoid having to deal with things like this + * which are outside of my intended use. + */ + /* read as much of the beginning of the request as possible, proceed */ + while (length>0) { + size_t length_to_read; + size_t length_read=0; + streamfile->validsize=0; + if (fseeko(streamfile->infile,offset,SEEK_SET)) return length_read; + streamfile->offset=offset; + + /* decide how much must be read this time */ + if (length>streamfile->buffersize) length_to_read=streamfile->buffersize; + else length_to_read=length; + + /* always try to fill the buffer */ + length_read = fread(streamfile->buffer,1,streamfile->buffersize,streamfile->infile); + streamfile->validsize=length_read; + +#ifdef PROFILE_STREAMFILE + if (ferror(streamfile->infile)) { + clearerr(streamfile->infile); + streamfile->error_count++; + } + + streamfile->bytes_read += length_read; +#endif + + /* if we can't get enough to satisfy the request we give up */ + if (length_read < length_to_read) { + memcpy(dest,streamfile->buffer,length_read); + length_read_total+=length_read; + return length_read_total; + } + + /* use the new buffer */ + memcpy(dest,streamfile->buffer,length_to_read); + length_read_total+=length_to_read; + length-=length_to_read; + dest+=length_to_read; + offset+=length_to_read; + } + + return length_read_total; +} + +static size_t read_stdio(STDIOSTREAMFILE *streamfile,uint8_t * dest, off_t offset, size_t length) +{ + // read + if (!streamfile || !dest || length<=0) return 0; + + /* if entire request is within the buffer */ + if (offset >= streamfile->offset && offset+length <= streamfile->offset+streamfile->validsize) { + memcpy(dest,streamfile->buffer+(offset-streamfile->offset),length); + return length; + } + + { + size_t length_read = read_the_rest(dest,offset,length,streamfile); +#if PROFILE_STREAMFILE + if (length_read < length) + streamfile->error_count++; +#endif + return length_read; + } +} + +static void close_stdio(STDIOSTREAMFILE * streamfile) { + fclose(streamfile->infile); + free(streamfile->buffer); + free(streamfile); +} + +static size_t get_size_stdio(STDIOSTREAMFILE * streamfile) { + fseeko(streamfile->infile,0,SEEK_END); + return ftello(streamfile->infile); +} + +static off_t get_offset_stdio(STDIOSTREAMFILE *streamFile) { + return streamFile->offset; +} + +static void get_name_stdio(STDIOSTREAMFILE *streamfile,char *buffer,size_t length) { + strcpy(buffer,streamfile->name); +} + +#ifdef PROFILE_STREAMFILE +static size_t get_bytes_read_stdio(STDIOSTREAMFILE *streamFile) { + return streamFile->bytes_read; +} +static size_t get_error_count_stdio(STDIOSTREAMFILE *streamFile) { + return streamFile->error_count; +} +#endif + +static STREAMFILE *open_stdio(STDIOSTREAMFILE *streamFile,const char * const filename,size_t buffersize) { + int newfd; + FILE *newfile; + STREAMFILE *newstreamFile; + + if (!filename) + return NULL; + // if same name, duplicate the file pointer we already have open + if (!strcmp(streamFile->name,filename)) { + if (IS_VALID_STREAM(streamFile->infile) && ((newfd = dup(fileno(streamFile->infile))) >= 0) && + (newfile = fdopen( newfd, "rb" ))) + { + newstreamFile = open_stdio_streamfile_buffer_by_FILE(newfile,filename,buffersize); + if (newstreamFile) { + return newstreamFile; + } + // failure, close it and try the default path (which will probably fail a second time) + fclose(newfile); + } + } + // a normal open, open a new file + return open_stdio_streamfile_buffer(filename,buffersize); +} + +static STREAMFILE * open_stdio_streamfile_buffer_by_FILE(FILE *infile,const char * const filename, size_t buffersize) { + uint8_t * buffer; + STDIOSTREAMFILE * streamfile; + + buffer = calloc(buffersize,1); + if (!buffer) { + return NULL; + } + + streamfile = calloc(1,sizeof(STDIOSTREAMFILE)); + if (!streamfile) { + free(buffer); + return NULL; + } + + streamfile->sf.read = (void*)read_stdio; + streamfile->sf.get_size = (void*)get_size_stdio; + streamfile->sf.get_offset = (void*)get_offset_stdio; + streamfile->sf.get_name = (void*)get_name_stdio; + streamfile->sf.get_realname = (void*)get_name_stdio; + streamfile->sf.open = (void*)open_stdio; + streamfile->sf.close = (void*)close_stdio; +#ifdef PROFILE_STREAMFILE + streamfile->sf.get_bytes_read = (void*)get_bytes_read_stdio; + streamfile->sf.get_error_count = (void*)get_error_count_stdio; +#endif + + streamfile->infile = infile; + streamfile->buffersize = buffersize; + streamfile->buffer = buffer; + + strcpy(streamfile->name,filename); + + return &streamfile->sf; +} + +STREAMFILE * open_stdio_streamfile_buffer(const char * const filename, size_t buffersize) { + FILE * infile; + STREAMFILE *streamFile; + + infile = fopen(filename,"rb"); + if (!infile) return NULL; + + streamFile = open_stdio_streamfile_buffer_by_FILE(infile,filename,buffersize); + if (!streamFile) { + fclose(infile); + } + + return streamFile; +} + +/* Read a line into dst. The source files are MS-DOS style, + * separated (not terminated) by CRLF. Return 1 if the full line was + * retrieved (if it could fit in dst), 0 otherwise. In any case the result + * will be properly terminated. The CRLF will be removed if there is one. + * Return the number of bytes read (including CRLF line ending). Note that + * this is not the length of the string, and could be larger than the buffer. + * *line_done_ptr is set to 1 if the complete line was read into dst, + * otherwise it is set to 0. line_done_ptr can be NULL if you aren't + * interested in this info. + */ +size_t get_streamfile_dos_line(int dst_length, char * dst, off_t offset, + STREAMFILE * infile, int *line_done_ptr) +{ + int i; + off_t file_length = get_streamfile_size(infile); + /* how many bytes over those put in the buffer were read */ + int extra_bytes = 0; + + if (line_done_ptr) *line_done_ptr = 0; + + for (i=0;i<dst_length-1 && offset+i < file_length;i++) + { + char in_char = read_8bit(offset+i,infile); + /* check for end of line */ + if (in_char == 0x0d && + read_8bit(offset+i+1,infile) == 0x0a) + { + extra_bytes = 2; + if (line_done_ptr) *line_done_ptr = 1; + break; + } + + dst[i]=in_char; + } + + dst[i]='\0'; + + /* did we fill the buffer? */ + if (i==dst_length) { + /* did the bytes we missed just happen to be the end of the line? */ + if (read_8bit(offset+i,infile) == 0x0d && + read_8bit(offset+i+1,infile) == 0x0a) + { + extra_bytes = 2; + /* if so be proud! */ + if (line_done_ptr) *line_done_ptr = 1; + } + } + + /* did we hit the file end? */ + if (offset+i == file_length) + { + /* then we did in fact finish reading the last line */ + if (line_done_ptr) *line_done_ptr = 1; + } + + return i+extra_bytes; +} diff --git a/lib/vgmstream/src/streamfile.h b/lib/vgmstream/src/streamfile.h new file mode 100644 index 0000000000..d9df519e99 --- /dev/null +++ b/lib/vgmstream/src/streamfile.h @@ -0,0 +1,142 @@ +/* +* streamfile.h - definitions for buffered file reading with STREAMFILE +*/ + +#ifndef _STREAMFILE_H +#define _STREAMFILE_H + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include "streamtypes.h" +#include "util.h" + +#if defined(__MSVCRT__) || defined(_MSC_VER) || defined(XBMC) +#define fseeko fseek +#define ftello ftell +#endif +#if defined(__MSVCRT__) || defined(_MSC_VER) +#include <io.h> +#define dup _dup +#ifdef fileno +#undef fileno +#endif +#define fileno _fileno +#define fdopen _fdopen +#endif + +#define STREAMFILE_DEFAULT_BUFFER_SIZE 0x400 + +typedef struct _STREAMFILE { + size_t (*read)(struct _STREAMFILE *,uint8_t * dest, off_t offset, size_t length); + size_t (*get_size)(struct _STREAMFILE *); + off_t (*get_offset)(struct _STREAMFILE *); + // for dual-file support + void (*get_name)(struct _STREAMFILE *,char *name,size_t length); + // for when the "name" is encoded specially, this is the actual user + // visible name + void (*get_realname)(struct _STREAMFILE *,char *name,size_t length); + struct _STREAMFILE * (*open)(struct _STREAMFILE *,const char * const filename,size_t buffersize); + + void (*close)(struct _STREAMFILE *); +#ifdef PROFILE_STREAMFILE + size_t (*get_bytes_read)(struct _STREAMFILE *); + int (*get_error_count)(struct _STREAMFILE *); + +#endif +} STREAMFILE; + +/* close a file, destroy the STREAMFILE object */ +static inline void close_streamfile(STREAMFILE * streamfile) { + streamfile->close(streamfile); +} + +/* read from a file +* +* returns number of bytes read +*/ +static inline size_t read_streamfile(uint8_t * dest, off_t offset, size_t length, STREAMFILE * streamfile) { + return streamfile->read(streamfile,dest,offset,length); +} + +/* return file size */ +static inline size_t get_streamfile_size(STREAMFILE * streamfile) { + return streamfile->get_size(streamfile); +} + +#ifdef PROFILE_STREAMFILE +/* return how many bytes we read into buffers */ +static inline size_t get_streamfile_bytes_read(STREAMFILE * streamfile) { + if (streamfile->get_bytes_read) + return streamfile->get_bytes_read(streamfile); + else + return 0; +} + +/* return how many times we encountered a read error */ +static inline int get_streamfile_error_count(STREAMFILE * streamfile) { + if (streamfile->get_error_count) + return streamfile->get_error_count(streamfile); + else + return 0; +} +#endif + +/* 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 * streamfile) { + uint8_t buf[2]; + + if (read_streamfile(buf,offset,2,streamfile)!=2) return -1; + return get_16bitLE(buf); +} +static inline int16_t read_16bitBE(off_t offset, STREAMFILE * streamfile) { + uint8_t buf[2]; + + if (read_streamfile(buf,offset,2,streamfile)!=2) return -1; + return get_16bitBE(buf); +} +static inline int32_t read_32bitLE(off_t offset, STREAMFILE * streamfile) { + uint8_t buf[4]; + + if (read_streamfile(buf,offset,4,streamfile)!=4) return -1; + return get_32bitLE(buf); +} +static inline int32_t read_32bitBE(off_t offset, STREAMFILE * streamfile) { + uint8_t buf[4]; + + if (read_streamfile(buf,offset,4,streamfile)!=4) return -1; + return get_32bitBE(buf); +} + +static inline int8_t read_8bit(off_t offset, STREAMFILE * streamfile) { + uint8_t buf[1]; + + if (read_streamfile(buf,offset,1,streamfile)!=1) return -1; + return buf[0]; +} + +/* open file with a set buffer size, create a STREAMFILE object +* +* Returns pointer to new STREAMFILE or NULL if open failed +*/ +STREAMFILE * open_stdio_streamfile_buffer(const char * const filename, size_t buffersize); + +/* open file with a default buffer size, create a STREAMFILE object +* +* Returns pointer to new STREAMFILE or NULL if open failed +*/ +static inline STREAMFILE * open_stdio_streamfile(const char * const filename) { + return open_stdio_streamfile_buffer(filename,STREAMFILE_DEFAULT_BUFFER_SIZE); +} + +size_t get_streamfile_dos_line(int dst_length, char * dst, off_t offset, + STREAMFILE * infile, int *line_done_ptr); + +#endif diff --git a/lib/vgmstream/src/streamtypes.h b/lib/vgmstream/src/streamtypes.h new file mode 100644 index 0000000000..e87e4d393f --- /dev/null +++ b/lib/vgmstream/src/streamtypes.h @@ -0,0 +1,20 @@ +/* + * streamtypes.h - widely used type definitions + */ + + +#ifndef _STREAMTYPES_H +#define _STREAMTYPES_H + +#ifdef _MSC_VER +#include <pstdint.h> +#define inline _inline +#define strcasecmp _stricmp +#define snprintf _snprintf +#else +#include <stdint.h> +#endif + +typedef int16_t sample; + +#endif diff --git a/lib/vgmstream/src/util.c b/lib/vgmstream/src/util.c new file mode 100644 index 0000000000..42d7a1c169 --- /dev/null +++ b/lib/vgmstream/src/util.c @@ -0,0 +1,144 @@ +#include <string.h> +#include "util.h" +#include "streamtypes.h" + +int check_sample_rate(int32_t sr) { + return !(sr<1000 || sr>96000); +} + +const char * filename_extension(const char * filename) { + const char * ext; + + /* You know what would be nice? strrchrnul(). + * Instead I have to do it myself. */ + ext = strrchr(filename,'.'); + if (ext==NULL) ext=filename+strlen(filename); /* point to null, i.e. an empty string for the extension */ + else ext=ext+1; /* skip the dot */ + + return ext; +} + +void interleave_channel(sample * outbuffer, sample * 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 * buffer, int32_t sample_count) { + int32_t tomove, belongs; + sample moving,temp; + + tomove = sample_count; + moving = buffer[tomove]; + + do { + if (tomove<sample_count) + belongs = tomove*2; + else + belongs = (tomove-sample_count)*2+1; + + printf("move %d to %d\n",tomove,belongs); + + temp = buffer[belongs]; + buffer[belongs] = moving; + moving = temp; + + tomove = belongs; + } while (tomove != sample_count); +} +*/ + +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); +} + +/* make a header for PCM .wav */ +/* buffer must be 0x2c bytes */ +void make_wav_header(uint8_t * buf, int32_t sample_count, int32_t sample_rate, int channels) { + size_t bytecount; + + bytecount = sample_count*channels*sizeof(sample); + + /* RIFF header */ + memcpy(buf+0, "RIFF", 4); + /* size of RIFF */ + put_32bitLE(buf+4, (int32_t)(bytecount+0x2c-8)); + + /* WAVE header */ + memcpy(buf+8, "WAVE", 4); + + /* WAVE fmt chunk */ + memcpy(buf+0xc, "fmt ", 4); + /* size of WAVE fmt chunk */ + put_32bitLE(buf+0x10, 0x10); + + /* compression code 1=PCM */ + put_16bitLE(buf+0x14, 1); + + /* channel count */ + put_16bitLE(buf+0x16, channels); + + /* sample rate */ + put_32bitLE(buf+0x18, sample_rate); + + /* bytes per second */ + put_32bitLE(buf+0x1c, sample_rate*channels*sizeof(sample)); + + /* block align */ + put_16bitLE(buf+0x20, (int16_t)(channels*sizeof(sample))); + + /* significant bits per sample */ + put_16bitLE(buf+0x22, sizeof(sample)*8); + + /* PCM has no extra format bytes, so we don't even need to specify a count */ + + /* WAVE data chunk */ + memcpy(buf+0x24, "data", 4); + /* size of WAVE data chunk */ + put_32bitLE(buf+0x28, (int32_t)bytecount); +} + +/* length is maximum length of dst. dst will always be null-terminated if + * length > 0 */ +void concatn(int length, char * dst, const char * src) { + int i,j; + if (length <= 0) return; + for (i=0;i<length-1 && dst[i];i++); /* find end of dst */ + for (j=0;i<length-1 && src[j];i++,j++) + dst[i]=src[j]; + dst[i]='\0'; +} + +/* length is maximum length of dst. dst will always be double-null-terminated if + * length > 1 */ +void concatn_doublenull(int length, char * dst, const char * src) { + int i,j; + if (length <= 1) return; + for (i=0;i<length-2 && (dst[i] || dst[i+1]);i++); /* find end of dst */ + if (i==length-2) { + dst[i]='\0'; + dst[i+1]='\0'; + return; + } + if (i>0) i++; + for (j=0;i<length-2 && (src[j] || src[j+1]);i++,j++) dst[i]=src[j]; + dst[i]='\0'; + dst[i+1]='\0'; +} diff --git a/lib/vgmstream/src/util.h b/lib/vgmstream/src/util.h new file mode 100644 index 0000000000..57fcca0313 --- /dev/null +++ b/lib/vgmstream/src/util.h @@ -0,0 +1,66 @@ +/* + * util.h - utility functions + */ + +#include "streamtypes.h" + +#ifndef _UTIL_H +#define _UTIL_H + +/* host endian independent multi-byte integer reading */ + +static inline int16_t get_16bitBE(uint8_t * p) { + return (p[0]<<8) | (p[1]); +} + +static inline int16_t get_16bitLE(uint8_t * p) { + return (p[0]) | (p[1]<<8); +} + +static inline int32_t get_32bitBE(uint8_t * p) { + return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | (p[3]); +} + +static inline int32_t get_32bitLE(uint8_t * p) { + return (p[0]) | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); +} + +void put_16bitLE(uint8_t * buf, int16_t i); + +void put_32bitLE(uint8_t * buf, int32_t i); + +/* signed nibbles come up a lot */ +static int nibble_to_int[16] = {0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1}; + +static inline int get_high_nibble_signed(uint8_t n) { + /*return ((n&0x70)-(n&0x80))>>4;*/ + return nibble_to_int[n>>4]; +} + +static inline int get_low_nibble_signed(uint8_t n) { + /*return (n&7)-(n&8);*/ + return nibble_to_int[n&0xf]; +} + +/* return true for a good sample rate */ +int check_sample_rate(int32_t sr); + +/* return a file's extension (a pointer to the first character of the + * extension in the original filename or the ending null byte if no extension + */ +const char * filename_extension(const char * filename); + +static inline int clamp16(int32_t val) { + if (val>32767) return 32767; + if (val<-32768) return -32768; + return val; +} + +/* make a header for PCM .wav */ +/* buffer must be 0x2c bytes */ +void make_wav_header(uint8_t * buf, int32_t sample_count, int32_t sample_rate, int channels); + +void concatn(int length, char * dst, const char * src); +void concatn_doublenull(int length, char * dst, const char * src); + +#endif diff --git a/lib/vgmstream/src/vgmstream.c b/lib/vgmstream/src/vgmstream.c new file mode 100644 index 0000000000..8c00eda69b --- /dev/null +++ b/lib/vgmstream/src/vgmstream.c @@ -0,0 +1,2209 @@ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#include <stdio.h> +#include <string.h> +#include <math.h> +#include "vgmstream.h" +#include "meta/meta.h" +#include "layout/layout.h" +#include "coding/coding.h" + +/* + * List of functions that will recognize files. These should correspond pretty + * directly to the metadata types + */ +VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { + init_vgmstream_adx, + init_vgmstream_brstm, + init_vgmstream_nds_strm, + init_vgmstream_agsc, + init_vgmstream_ngc_adpdtk, + init_vgmstream_rsf, + init_vgmstream_afc, + init_vgmstream_ast, + init_vgmstream_halpst, + init_vgmstream_rs03, + init_vgmstream_ngc_dsp_std, + init_vgmstream_Cstr, + init_vgmstream_gcsw, + init_vgmstream_ps2_ads, + init_vgmstream_ps2_npsf, + init_vgmstream_rwsd, + init_vgmstream_cdxa, + init_vgmstream_ps2_rxw, + init_vgmstream_ps2_int, + init_vgmstream_ngc_dsp_stm, + init_vgmstream_ps2_exst, + init_vgmstream_ps2_svag, + init_vgmstream_ps2_mib, + init_vgmstream_ngc_mpdsp, + init_vgmstream_ps2_mic, + init_vgmstream_ngc_dsp_std_int, + init_vgmstream_raw, + init_vgmstream_ps2_vag, + init_vgmstream_psx_gms, + init_vgmstream_ps2_str, + init_vgmstream_ps2_ild, + init_vgmstream_ps2_pnb, + init_vgmstream_xbox_wavm, + init_vgmstream_xbox_xwav, + init_vgmstream_ngc_str, + init_vgmstream_ea, + init_vgmstream_caf, + init_vgmstream_ps2_vpk, + init_vgmstream_genh, +#ifdef VGM_USE_VORBIS + init_vgmstream_ogg_vorbis, + init_vgmstream_sli_ogg, + init_vgmstream_sfl, +#endif + init_vgmstream_sadb, + init_vgmstream_ps2_bmdx, + init_vgmstream_wsi, + init_vgmstream_aifc, + init_vgmstream_str_snds, + init_vgmstream_ws_aud, +#ifdef VGM_USE_MPEG + init_vgmstream_ahx, +#endif + init_vgmstream_ivb, + init_vgmstream_amts, + init_vgmstream_svs, + init_vgmstream_riff, + init_vgmstream_pos, + init_vgmstream_nwa, + init_vgmstream_eacs, + init_vgmstream_xss, + init_vgmstream_sl3, + init_vgmstream_hgc1, + init_vgmstream_aus, + init_vgmstream_rws, + init_vgmstream_fsb1, + init_vgmstream_fsb3, + init_vgmstream_fsb4, + init_vgmstream_rwx, + init_vgmstream_xwb, + init_vgmstream_xa30, + init_vgmstream_musc, + init_vgmstream_musx_v004, + init_vgmstream_musx_v006, + init_vgmstream_musx_v010, + init_vgmstream_musx_v201, + init_vgmstream_leg, + init_vgmstream_filp, + init_vgmstream_ikm, + init_vgmstream_sfs, + init_vgmstream_bg00, + init_vgmstream_dvi, + init_vgmstream_kcey, + init_vgmstream_ps2_rstm, + init_vgmstream_acm, + init_vgmstream_mus_acm, + init_vgmstream_ps2_kces, + init_vgmstream_ps2_dxh, + init_vgmstream_ps2_psh, + init_vgmstream_pcm, + init_vgmstream_ps2_rkv, + init_vgmstream_ps2_psw, + init_vgmstream_ps2_vas, + init_vgmstream_ps2_tec, + init_vgmstream_ps2_enth, + init_vgmstream_sdt, + init_vgmstream_aix, + init_vgmstream_ngc_tydsp, + init_vgmstream_ngc_swd, + init_vgmstream_capdsp, + init_vgmstream_xbox_wvs, + init_vgmstream_dc_str, + init_vgmstream_dc_str_v2, + init_vgmstream_xbox_stma, + init_vgmstream_xbox_matx, + init_vgmstream_de2, + init_vgmstream_vs, + init_vgmstream_dc_str, + init_vgmstream_dc_str_v2, + init_vgmstream_xbox_xmu, + init_vgmstream_xbox_xvas, + init_vgmstream_ngc_bh2pcm, + init_vgmstream_sat_sap, + init_vgmstream_dc_idvi, + init_vgmstream_ps2_rnd, + init_vgmstream_wii_idsp, + init_vgmstream_kraw, + init_vgmstream_ps2_omu, + init_vgmstream_ps2_xa2, + init_vgmstream_idsp, + init_vgmstream_idsp2, + init_vgmstream_ngc_ymf, + init_vgmstream_sadl, + init_vgmstream_ps2_ccc, + init_vgmstream_psx_fag, + init_vgmstream_ps2_mihb, + init_vgmstream_ngc_pdt, + init_vgmstream_wii_mus, + init_vgmstream_dc_asd, + init_vgmstream_naomi_spsd, + + init_vgmstream_rsd2vag, + init_vgmstream_rsd2pcmb, + init_vgmstream_rsd2xadp, + init_vgmstream_rsd3pcm, + init_vgmstream_rsd4pcmb, + init_vgmstream_rsd4pcm, + init_vgmstream_rsd4vag, + init_vgmstream_rsd6vag, + init_vgmstream_rsd6wadp, + init_vgmstream_rsd6xadp, + init_vgmstream_bgw, + init_vgmstream_spw, + init_vgmstream_ps2_ass, + init_vgmstream_waa_wac_wad_wam, + init_vgmstream_ps2_seg, + init_vgmstream_nds_strm_ffta2, + init_vgmstream_str_asr, + init_vgmstream_zwdsp, + init_vgmstream_gca, + init_vgmstream_spt_spd, + init_vgmstream_ish_isd, + init_vgmstream_gsp_gsb, + init_vgmstream_ydsp, + init_vgmstream_msvp, + init_vgmstream_ngc_ssm, + init_vgmstream_ps2_joe, + init_vgmstream_vgs, + init_vgmstream_dc_wav_dcs, + init_vgmstream_wii_smp, + init_vgmstream_emff_ps2, + init_vgmstream_emff_ngc, + init_vgmstream_ss_stream, + init_vgmstream_thp, + init_vgmstream_wii_sts, + init_vgmstream_ps2_p2bt, + init_vgmstream_ps2_gbts, + init_vgmstream_wii_sng, +// init_vgmstream_iadp, + init_vgmstream_aax, + init_vgmstream_ngc_ffcc_str, +}; + +#define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0])) + +/* internal version with all parameters */ +VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) { + int i; + + if (!streamFile) + return NULL; + + /* try a series of formats, see which works */ + for (i=0;i<INIT_VGMSTREAM_FCNS;i++) { + VGMSTREAM * vgmstream = (init_vgmstream_fcns[i])(streamFile); + if (vgmstream) { + /* these are little hacky checks */ + + /* everything should have a reasonable sample rate + * (a verification of the metadata) */ + if (!check_sample_rate(vgmstream->sample_rate)) { + close_vgmstream(vgmstream); + continue; + } + + /* dual file stereo */ + if (do_dfs && ( + (vgmstream->meta_type == meta_DSP_STD) || + (vgmstream->meta_type == meta_PS2_VAGp) || + (vgmstream->meta_type == meta_GENH) || + (vgmstream->meta_type == meta_KRAW) + ) && vgmstream->channels == 1) { + try_dual_file_stereo(vgmstream, streamFile); + } + + /* save start things so we can restart for seeking */ + /* copy the channels */ + memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); + /* copy the whole VGMSTREAM */ + memcpy(vgmstream->start_vgmstream,vgmstream,sizeof(VGMSTREAM)); + + return vgmstream; + } + } + + return NULL; +} + +/* format detection and VGMSTREAM setup, uses default parameters */ +VGMSTREAM * init_vgmstream(const char * const filename) { + VGMSTREAM *vgmstream = NULL; + STREAMFILE *streamFile = open_stdio_streamfile(filename); + if (streamFile) { + vgmstream = init_vgmstream_from_STREAMFILE(streamFile); + close_streamfile(streamFile); + } + return vgmstream; +} + +VGMSTREAM * init_vgmstream_from_STREAMFILE(STREAMFILE *streamFile) { + return init_vgmstream_internal(streamFile,1); +} + +/* Reset a VGMSTREAM to its state at the start of playback. + * Note that this does not reset the constituent STREAMFILES. */ +void reset_vgmstream(VGMSTREAM * vgmstream) { + /* copy the vgmstream back into itself */ + memcpy(vgmstream,vgmstream->start_vgmstream,sizeof(VGMSTREAM)); + + /* copy the initial channels */ + memcpy(vgmstream->ch,vgmstream->start_ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); + + /* loop_ch is not zeroed here because there is a possibility of the + * init_vgmstream_* function doing something tricky and precomputing it. + * Otherwise hit_loop will be 0 and it will be copied over anyway when we + * really hit the loop start. */ + +#ifdef VGM_USE_VORBIS + if (vgmstream->coding_type==coding_ogg_vorbis) { + ogg_vorbis_codec_data *data = vgmstream->codec_data; + + OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file); + + ov_pcm_seek(ogg_vorbis_file, 0); + } +#endif +#ifdef VGM_USE_MPEG + if (vgmstream->layout_type==layout_mpeg || + vgmstream->layout_type==layout_fake_mpeg) { + off_t input_offset; + mpeg_codec_data *data = vgmstream->codec_data; + + /* input_offset is ignored as we can assume it will be 0 for a seek + * to sample 0 */ + mpg123_feedseek(data->m,0,SEEK_SET,&input_offset); + data->buffer_full = data->buffer_used = 0; + } +#endif + + if (vgmstream->coding_type==coding_ACM) { + mus_acm_codec_data *data = vgmstream->codec_data; + int i; + + data->current_file = 0; + for (i=0;i<data->file_count;i++) { + acm_reset(data->files[i]); + } + } + + if (vgmstream->layout_type==layout_aix) { + aix_codec_data *data = vgmstream->codec_data; + int i; + + data->current_segment = 0; + for (i=0;i<data->segment_count*data->stream_count;i++) + { + reset_vgmstream(data->adxs[i]); + } + } + + if (vgmstream->layout_type==layout_aax) { + aax_codec_data *data = vgmstream->codec_data; + int i; + + data->current_segment = 0; + for (i=0;i<data->segment_count;i++) + { + reset_vgmstream(data->adxs[i]); + } + } + + if ( + vgmstream->coding_type == coding_NWA0 || + vgmstream->coding_type == coding_NWA1 || + vgmstream->coding_type == coding_NWA2 || + vgmstream->coding_type == coding_NWA3 || + vgmstream->coding_type == coding_NWA4 || + vgmstream->coding_type == coding_NWA5 + ) { + nwa_codec_data *data = vgmstream->codec_data; + reset_nwa(data->nwa); + } +} + +/* simply allocate memory for the VGMSTREAM and its channels */ +VGMSTREAM * allocate_vgmstream(int channel_count, int looped) { + VGMSTREAM * vgmstream; + VGMSTREAM * start_vgmstream; + VGMSTREAMCHANNEL * channels; + VGMSTREAMCHANNEL * start_channels; + VGMSTREAMCHANNEL * loop_channels; + + if (channel_count <= 0) return NULL; + + vgmstream = calloc(1,sizeof(VGMSTREAM)); + if (!vgmstream) return NULL; + + vgmstream->ch = NULL; + vgmstream->start_ch = NULL; + vgmstream->loop_ch = NULL; + vgmstream->start_vgmstream = NULL; + vgmstream->codec_data = NULL; + + start_vgmstream = calloc(1,sizeof(VGMSTREAM)); + if (!start_vgmstream) { + free(vgmstream); + return NULL; + } + vgmstream->start_vgmstream = start_vgmstream; + start_vgmstream->start_vgmstream = start_vgmstream; + + channels = calloc(channel_count,sizeof(VGMSTREAMCHANNEL)); + if (!channels) { + free(vgmstream); + free(start_vgmstream); + return NULL; + } + vgmstream->ch = channels; + vgmstream->channels = channel_count; + + start_channels = calloc(channel_count,sizeof(VGMSTREAMCHANNEL)); + if (!start_channels) { + free(vgmstream); + free(start_vgmstream); + free(channels); + return NULL; + } + vgmstream->start_ch = start_channels; + + if (looped) { + loop_channels = calloc(channel_count,sizeof(VGMSTREAMCHANNEL)); + if (!loop_channels) { + free(vgmstream); + free(start_vgmstream); + free(channels); + free(start_channels); + return NULL; + } + vgmstream->loop_ch = loop_channels; + } + + vgmstream->loop_flag = looped; + + return vgmstream; +} + +void close_vgmstream(VGMSTREAM * vgmstream) { + int i,j; + if (!vgmstream) return; + +#ifdef VGM_USE_VORBIS + if (vgmstream->coding_type==coding_ogg_vorbis) { + ogg_vorbis_codec_data *data = vgmstream->codec_data; + if (vgmstream->codec_data) { + OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file); + + ov_clear(ogg_vorbis_file); + + close_streamfile(data->ov_streamfile.streamfile); + free(vgmstream->codec_data); + vgmstream->codec_data = NULL; + } + } +#endif + +#ifdef VGM_USE_MPEG + if (vgmstream->layout_type==layout_fake_mpeg|| + vgmstream->layout_type==layout_mpeg) { + mpeg_codec_data *data = vgmstream->codec_data; + + if (data) { + mpg123_delete(data->m); + free(vgmstream->codec_data); + vgmstream->codec_data = NULL; + /* The astute reader will note that a call to mpg123_exit is never + * made. While is is evilly breaking our contract with mpg123, it + * doesn't actually do anything except set the "initialized" flag + * to 0. And if we exit we run the risk of turning it off when + * someone else in another thread is using it. */ + } + } +#endif + + if (vgmstream->coding_type==coding_ACM) { + mus_acm_codec_data *data = vgmstream->codec_data; + + if (data) { + if (data->files) { + int i; + for (i=0; i<data->file_count; i++) { + /* shouldn't be duplicates */ + if (data->files[i]) { + acm_close(data->files[i]); + data->files[i] = NULL; + } + } + free(data->files); + data->files = NULL; + } + + free(vgmstream->codec_data); + vgmstream->codec_data = NULL; + } + } + + if (vgmstream->layout_type==layout_aix) { + aix_codec_data *data = vgmstream->codec_data; + + if (data) { + if (data->adxs) { + int i; + for (i=0;i<data->segment_count*data->stream_count;i++) { + + /* note that the AIX close_streamfile won't do anything but + * deallocate itself, there is only one open file and that + * is in vgmstream->ch[0].streamfile */ + close_vgmstream(data->adxs[i]); + } + free(data->adxs); + } + if (data->sample_counts) { + free(data->sample_counts); + } + + free(data); + } + vgmstream->codec_data = NULL; + } + if (vgmstream->layout_type==layout_aax) { + aax_codec_data *data = vgmstream->codec_data; + + if (data) { + if (data->adxs) { + int i; + for (i=0;i<data->segment_count;i++) { + + /* note that the AAX close_streamfile won't do anything but + * deallocate itself, there is only one open file and that + * is in vgmstream->ch[0].streamfile */ + close_vgmstream(data->adxs[i]); + } + free(data->adxs); + } + if (data->sample_counts) { + free(data->sample_counts); + } + + free(data); + } + vgmstream->codec_data = NULL; + } + + if ( + vgmstream->coding_type == coding_NWA0 || + vgmstream->coding_type == coding_NWA1 || + vgmstream->coding_type == coding_NWA2 || + vgmstream->coding_type == coding_NWA3 || + vgmstream->coding_type == coding_NWA4 || + vgmstream->coding_type == coding_NWA5 + ) { + nwa_codec_data *data = vgmstream->codec_data; + + close_nwa(data->nwa); + + free(data); + + vgmstream->codec_data = NULL; + } + + /* now that the special cases have had their chance, clean up the standard items */ + for (i=0;i<vgmstream->channels;i++) { + if (vgmstream->ch[i].streamfile) { + close_streamfile(vgmstream->ch[i].streamfile); + /* Multiple channels might have the same streamfile. Find the others + * that are the same as this and clear them so they won't be closed + * again. */ + for (j=0;j<vgmstream->channels;j++) { + if (i!=j && vgmstream->ch[j].streamfile == + vgmstream->ch[i].streamfile) { + vgmstream->ch[j].streamfile = NULL; + } + } + vgmstream->ch[i].streamfile = NULL; + } + } + + if (vgmstream->loop_ch) free(vgmstream->loop_ch); + if (vgmstream->start_ch) free(vgmstream->start_ch); + if (vgmstream->ch) free(vgmstream->ch); + /* the start_vgmstream is considered just data */ + if (vgmstream->start_vgmstream) free(vgmstream->start_vgmstream); + + free(vgmstream); +} + +int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM * vgmstream) { + if (vgmstream->loop_flag) { + return vgmstream->loop_start_sample+(vgmstream->loop_end_sample-vgmstream->loop_start_sample)*looptimes+(fadedelayseconds+fadeseconds)*vgmstream->sample_rate; + } else return vgmstream->num_samples; +} + +void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { + switch (vgmstream->layout_type) { + case layout_interleave: + case layout_interleave_shortblock: + render_vgmstream_interleave(buffer,sample_count,vgmstream); + break; +#ifdef VGM_USE_VORBIS + case layout_ogg_vorbis: +#endif +#ifdef VGM_USE_MPEG + case layout_fake_mpeg: + case layout_mpeg: +#endif + case layout_dtk_interleave: + case layout_none: + render_vgmstream_nolayout(buffer,sample_count,vgmstream); + break; + case layout_ast_blocked: + case layout_halpst_blocked: + case layout_xa_blocked: + case layout_ea_blocked: + case layout_eacs_blocked: + case layout_caf_blocked: + case layout_wsi_blocked: + case layout_str_snds_blocked: + case layout_ws_aud_blocked: + case layout_matx_blocked: + case layout_de2_blocked: + case layout_vs_blocked: + case layout_emff_ps2_blocked: + case layout_emff_ngc_blocked: + case layout_gsb_blocked: + case layout_xvas_blocked: + case layout_thp_blocked: + case layout_filp_blocked: + render_vgmstream_blocked(buffer,sample_count,vgmstream); + break; + case layout_interleave_byte: + render_vgmstream_interleave_byte(buffer,sample_count,vgmstream); + break; + case layout_acm: + case layout_mus_acm: + render_vgmstream_mus_acm(buffer,sample_count,vgmstream); + break; + case layout_aix: + render_vgmstream_aix(buffer,sample_count,vgmstream); + break; + case layout_aax: + render_vgmstream_aax(buffer,sample_count,vgmstream); + break; + } +} + +int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { + switch (vgmstream->coding_type) { + case coding_CRI_ADX: + case coding_CRI_ADX_enc: + case coding_L5_555: + return 32; + case coding_NGC_DSP: + return 14; + case coding_PCM16LE: + case coding_PCM16LE_int: + case coding_PCM16BE: + case coding_PCM8: + case coding_PCM8_int: + case coding_PCM8_SB_int: + case coding_PCM8_U_int: +#ifdef VGM_USE_VORBIS + case coding_ogg_vorbis: +#endif +#ifdef VGM_USE_MPEG + case coding_fake_MPEG2_L2: + case coding_MPEG1_L1: + case coding_MPEG1_L2: + case coding_MPEG1_L3: + case coding_MPEG2_L1: + case coding_MPEG2_L2: + case coding_MPEG2_L3: + case coding_MPEG25_L1: + case coding_MPEG25_L2: + case coding_MPEG25_L3: +#endif + case coding_SDX2: + case coding_SDX2_int: + case coding_ACM: + case coding_NWA0: + case coding_NWA1: + case coding_NWA2: + case coding_NWA3: + case coding_NWA4: + case coding_NWA5: + return 1; + case coding_NDS_IMA: + return (vgmstream->interleave_block_size-4)*2; + case coding_NGC_DTK: + return 28; + case coding_G721: + case coding_DVI_IMA: + case coding_EACS_IMA: + case coding_IMA: + return 1; + case coding_INT_IMA: + case coding_INT_DVI_IMA: + case coding_AICA: + return 2; + case coding_NGC_AFC: + case coding_FFXI: + return 16; + case coding_PSX: + case coding_PSX_badflags: + case coding_invert_PSX: + case coding_XA: + return 28; + case coding_XBOX: + return 64; + case coding_EAXA: + return 28; + case coding_EA_ADPCM: + return 14*vgmstream->channels; + case coding_WS: + /* only works if output sample size is 8 bit, which is always + is for WS ADPCM */ + return vgmstream->ws_output_size; + case coding_MSADPCM: + return (vgmstream->interleave_block_size-(7-1)*vgmstream->channels)*2/vgmstream->channels; + case coding_NDS_PROCYON: + return 30; + default: + return 0; + } +} + +int get_vgmstream_samples_per_shortframe(VGMSTREAM * vgmstream) { + switch (vgmstream->coding_type) { + case coding_NDS_IMA: + return (vgmstream->interleave_smallblock_size-4)*2; + default: + return get_vgmstream_samples_per_frame(vgmstream); + } +} + +int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { + switch (vgmstream->coding_type) { + case coding_CRI_ADX: + case coding_CRI_ADX_enc: + case coding_L5_555: + return 18; + case coding_NGC_DSP: + return 8; + case coding_PCM16LE: + case coding_PCM16LE_int: + case coding_PCM16BE: + return 2; + case coding_PCM8: + case coding_PCM8_int: + case coding_PCM8_SB_int: + case coding_PCM8_U_int: + case coding_SDX2: + case coding_SDX2_int: + case coding_NWA0: + case coding_NWA1: + case coding_NWA2: + case coding_NWA3: + case coding_NWA4: + case coding_NWA5: + return 1; + case coding_NDS_IMA: + return vgmstream->interleave_block_size; + case coding_NGC_DTK: + return 32; + case coding_EACS_IMA: + return 1; + case coding_DVI_IMA: + case coding_IMA: + case coding_G721: + return 0; + case coding_NGC_AFC: + case coding_FFXI: + return 9; + case coding_PSX: + case coding_PSX_badflags: + case coding_invert_PSX: + case coding_NDS_PROCYON: + return 16; + case coding_XA: + return 14*vgmstream->channels; + case coding_XBOX: + return 36; + case coding_EA_ADPCM: + return 30; + case coding_EAXA: + return 1; // the frame is variant in size + case coding_WS: + return vgmstream->current_block_size; + case coding_INT_IMA: + case coding_INT_DVI_IMA: + case coding_AICA: + return 1; + case coding_MSADPCM: + return vgmstream->interleave_block_size; + default: + return 0; + } +} + +int get_vgmstream_shortframe_size(VGMSTREAM * vgmstream) { + switch (vgmstream->coding_type) { + case coding_NDS_IMA: + return vgmstream->interleave_smallblock_size; + default: + return get_vgmstream_frame_size(vgmstream); + } +} + +void decode_vgmstream_mem(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer, uint8_t * data, int channel) { + + switch (vgmstream->coding_type) { + case coding_NGC_DSP: + decode_ngc_dsp_mem(&vgmstream->ch[channel], + buffer+samples_written*vgmstream->channels+channel, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do, data); + break; + default: + break; + } +} + +void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer) { + int chan; + + switch (vgmstream->coding_type) { + case coding_CRI_ADX: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_adx(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + + break; + case coding_CRI_ADX_enc: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_adx_enc(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + + break; + case coding_NGC_DSP: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_ngc_dsp(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_PCM16LE: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_pcm16LE(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_PCM16LE_int: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_pcm16LE_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_PCM16BE: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_pcm16BE(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_PCM8: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_pcm8(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_PCM8_int: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_pcm8_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_PCM8_SB_int: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_pcm8_sb_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_PCM8_U_int: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_pcm8_unsigned_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_NDS_IMA: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_nds_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_XBOX: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_xbox_ima(vgmstream,&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do,chan); + } + break; + case coding_NGC_DTK: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_ngc_dtk(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do,chan); + } + break; + case coding_G721: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_g721(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_NGC_AFC: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_ngc_afc(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_PSX: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_psx(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_PSX_badflags: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_psx_badflags(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_invert_PSX: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_invert_psx(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_FFXI: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_ffxi_adpcm(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_XA: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_xa(vgmstream,buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do,chan); + } + break; + case coding_EAXA: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_eaxa(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do,chan); + } + break; + case coding_EA_ADPCM: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_ea_adpcm(vgmstream,buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do,chan); + } + break; +#ifdef VGM_USE_VORBIS + case coding_ogg_vorbis: + decode_ogg_vorbis(vgmstream->codec_data, + buffer+samples_written*vgmstream->channels,samples_to_do, + vgmstream->channels); + break; +#endif + case coding_SDX2: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_sdx2(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_SDX2_int: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_sdx2_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_DVI_IMA: + case coding_INT_DVI_IMA: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_dvi_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_EACS_IMA: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_eacs_ima(vgmstream,buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do,chan); + } + break; + case coding_IMA: + case coding_INT_IMA: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_WS: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_ws(vgmstream,chan,buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; +#ifdef VGM_USE_MPEG + case coding_fake_MPEG2_L2: + decode_fake_mpeg2_l2( + &vgmstream->ch[0], + vgmstream->codec_data, + buffer+samples_written*vgmstream->channels,samples_to_do); + break; + case coding_MPEG1_L1: + case coding_MPEG1_L2: + case coding_MPEG1_L3: + case coding_MPEG2_L1: + case coding_MPEG2_L2: + case coding_MPEG2_L3: + case coding_MPEG25_L1: + case coding_MPEG25_L2: + case coding_MPEG25_L3: + decode_mpeg( + &vgmstream->ch[0], + vgmstream->codec_data, + buffer+samples_written*vgmstream->channels,samples_to_do, + vgmstream->channels); + break; +#endif + case coding_ACM: + /* handled in its own layout, here to quiet compiler */ + break; + case coding_NWA0: + case coding_NWA1: + case coding_NWA2: + case coding_NWA3: + case coding_NWA4: + case coding_NWA5: + decode_nwa(((nwa_codec_data*)vgmstream->codec_data)->nwa, + buffer+samples_written*vgmstream->channels, + samples_to_do + ); + break; + case coding_MSADPCM: + if (vgmstream->channels == 2) { + decode_msadpcm_stereo(vgmstream, + buffer+samples_written*vgmstream->channels, + vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_AICA: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_aica(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_NDS_PROCYON: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_nds_procyon(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_L5_555: + for (chan=0;chan<vgmstream->channels;chan++) { + decode_l5_555(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + + break; + } +} + +int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM * vgmstream) { + int samples_to_do; + int samples_left_this_block; + + samples_left_this_block = samples_this_block - vgmstream->samples_into_block; + samples_to_do = samples_left_this_block; + + /* fun loopy crap */ + /* Why did I think this would be any simpler? */ + if (vgmstream->loop_flag) { + /* are we going to hit the loop end during this block? */ + if (vgmstream->current_sample+samples_left_this_block > vgmstream->loop_end_sample) { + /* only do to just before it */ + samples_to_do = vgmstream->loop_end_sample-vgmstream->current_sample; + } + + /* are we going to hit the loop start during this block? */ + if (!vgmstream->hit_loop && vgmstream->current_sample+samples_left_this_block > vgmstream->loop_start_sample) { + /* only do to just before it */ + samples_to_do = vgmstream->loop_start_sample-vgmstream->current_sample; + } + + } + + /* if it's a framed encoding don't do more than one frame */ + if (samples_per_frame>1 && (vgmstream->samples_into_block%samples_per_frame)+samples_to_do>samples_per_frame) samples_to_do=samples_per_frame-(vgmstream->samples_into_block%samples_per_frame); + + return samples_to_do; +} + +/* return 1 if we just looped */ +int vgmstream_do_loop(VGMSTREAM * vgmstream) { +/* if (vgmstream->loop_flag) {*/ + /* is this the loop end? */ + if (vgmstream->current_sample==vgmstream->loop_end_sample) { + /* against everything I hold sacred, preserve adpcm + * history through loop for certain types */ + if (vgmstream->meta_type == meta_DSP_STD || + vgmstream->meta_type == meta_DSP_RS03 || + vgmstream->meta_type == meta_DSP_CSTR || + vgmstream->coding_type == coding_PSX || + vgmstream->coding_type == coding_invert_PSX || + vgmstream->coding_type == coding_PSX_badflags) { + int i; + for (i=0;i<vgmstream->channels;i++) { + vgmstream->loop_ch[i].adpcm_history1_16 = vgmstream->ch[i].adpcm_history1_16; + vgmstream->loop_ch[i].adpcm_history2_16 = vgmstream->ch[i].adpcm_history2_16; + vgmstream->loop_ch[i].adpcm_history1_32 = vgmstream->ch[i].adpcm_history1_32; + vgmstream->loop_ch[i].adpcm_history2_32 = vgmstream->ch[i].adpcm_history2_32; + } + } +#ifdef DEBUG + { + int i; + for (i=0;i<vgmstream->channels;i++) { + fprintf(stderr,"ch%d hist: %04x %04x loop hist: %04x %04x\n",i, + vgmstream->ch[i].adpcm_history1_16,vgmstream->ch[i].adpcm_history2_16, + vgmstream->loop_ch[i].adpcm_history1_16,vgmstream->loop_ch[i].adpcm_history2_16); + fprintf(stderr,"ch%d offset: %x loop offset: %x\n",i, + vgmstream->ch[i].offset, + vgmstream->loop_ch[i].offset); + } + } +#endif + +#ifdef VGM_USE_VORBIS + if (vgmstream->coding_type==coding_ogg_vorbis) { + ogg_vorbis_codec_data *data = + (ogg_vorbis_codec_data *)(vgmstream->codec_data); + OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file); + + ov_pcm_seek_lap(ogg_vorbis_file, vgmstream->loop_sample); + } +#endif +#ifdef VGM_USE_MPEG + /* won't work for fake MPEG */ + if (vgmstream->layout_type==layout_mpeg) { + off_t input_offset; + mpeg_codec_data *data = vgmstream->codec_data; + + mpg123_feedseek(data->m,vgmstream->loop_sample, + SEEK_SET,&input_offset); + vgmstream->loop_ch[0].offset = + vgmstream->loop_ch[0].channel_start_offset + input_offset; + data->buffer_full = data->buffer_used = 0; + } +#endif + + if (vgmstream->coding_type == coding_NWA0 || + vgmstream->coding_type == coding_NWA1 || + vgmstream->coding_type == coding_NWA2 || + vgmstream->coding_type == coding_NWA3 || + vgmstream->coding_type == coding_NWA4 || + vgmstream->coding_type == coding_NWA5) + { + nwa_codec_data *data = vgmstream->codec_data; + + seek_nwa(data->nwa, vgmstream->loop_sample); + } + + /* restore! */ + memcpy(vgmstream->ch,vgmstream->loop_ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); + vgmstream->current_sample=vgmstream->loop_sample; + vgmstream->samples_into_block=vgmstream->loop_samples_into_block; + vgmstream->current_block_size=vgmstream->loop_block_size; + vgmstream->current_block_offset=vgmstream->loop_block_offset; + vgmstream->next_block_offset=vgmstream->loop_next_block_offset; + + return 1; + } + + + /* is this the loop start? */ + if (!vgmstream->hit_loop && vgmstream->current_sample==vgmstream->loop_start_sample) { + /* save! */ + memcpy(vgmstream->loop_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); + + vgmstream->loop_sample=vgmstream->current_sample; + vgmstream->loop_samples_into_block=vgmstream->samples_into_block; + vgmstream->loop_block_size=vgmstream->current_block_size; + vgmstream->loop_block_offset=vgmstream->current_block_offset; + vgmstream->loop_next_block_offset=vgmstream->next_block_offset; + vgmstream->hit_loop=1; + } + /*}*/ + return 0; +} + +/* build a descriptive string */ +void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { +#define TEMPSIZE 256 + char temp[TEMPSIZE]; + + if (!vgmstream) { + snprintf(temp,TEMPSIZE,"NULL VGMSTREAM"); + concatn(length,desc,temp); + return; + } + + snprintf(temp,TEMPSIZE,"sample rate %d Hz\n" + "channels: %d\n", + vgmstream->sample_rate,vgmstream->channels); + concatn(length,desc,temp); + + if (vgmstream->loop_flag) { + snprintf(temp,TEMPSIZE,"loop start: %d samples (%.2lf seconds)\n" + "loop end: %d samples (%.2lf seconds)\n", + vgmstream->loop_start_sample, + (double)vgmstream->loop_start_sample/vgmstream->sample_rate, + vgmstream->loop_end_sample, + (double)vgmstream->loop_end_sample/vgmstream->sample_rate); + concatn(length,desc,temp); + } + + snprintf(temp,TEMPSIZE,"stream total samples: %d (%.2lf seconds)\n", + vgmstream->num_samples, + (double)vgmstream->num_samples/vgmstream->sample_rate); + concatn(length,desc,temp); + + snprintf(temp,TEMPSIZE,"encoding: "); + concatn(length,desc,temp); + + switch (vgmstream->coding_type) { + case coding_PCM16BE: + snprintf(temp,TEMPSIZE,"Big Endian 16-bit PCM"); + break; + case coding_PCM16LE: + snprintf(temp,TEMPSIZE,"Little Endian 16-bit PCM"); + break; + case coding_PCM16LE_int: + snprintf(temp,TEMPSIZE,"Little Endian 16-bit PCM with 2 byte interleave"); + break; + case coding_PCM8: + snprintf(temp,TEMPSIZE,"8-bit PCM"); + break; + case coding_PCM8_U_int: + snprintf(temp,TEMPSIZE,"8-bit unsigned PCM with 1 byte interleave"); + break; + case coding_PCM8_int: + snprintf(temp,TEMPSIZE,"8-bit PCM with 1 byte interleave"); + break; + case coding_PCM8_SB_int: + snprintf(temp,TEMPSIZE,"8-bit PCM with sign bit, 1 byte interleave"); + break; + case coding_NGC_DSP: + snprintf(temp,TEMPSIZE,"Gamecube \"DSP\" 4-bit ADPCM"); + break; + case coding_CRI_ADX: + snprintf(temp,TEMPSIZE,"CRI ADX 4-bit ADPCM"); + break; + case coding_CRI_ADX_enc: + snprintf(temp,TEMPSIZE,"encrypted CRI ADX 4-bit ADPCM"); + break; + case coding_NDS_IMA: + snprintf(temp,TEMPSIZE,"NDS-style 4-bit IMA ADPCM"); + break; + case coding_NGC_DTK: + snprintf(temp,TEMPSIZE,"Gamecube \"ADP\"/\"DTK\" 4-bit ADPCM"); + break; + case coding_G721: + snprintf(temp,TEMPSIZE,"CCITT G.721 4-bit ADPCM"); + break; + case coding_NGC_AFC: + snprintf(temp,TEMPSIZE,"Gamecube \"AFC\" 4-bit ADPCM"); + break; + case coding_PSX: + snprintf(temp,TEMPSIZE,"Playstation 4-bit ADPCM"); + break; + case coding_PSX_badflags: + snprintf(temp,TEMPSIZE,"Playstation 4-bit ADPCM with bad flags"); + break; + case coding_invert_PSX: + snprintf(temp,TEMPSIZE,"BMDX \"encrypted\" Playstation 4-bit ADPCM"); + break; + case coding_FFXI: + snprintf(temp,TEMPSIZE,"FFXI Playstation-ish 4-bit ADPCM"); + break; + case coding_XA: + snprintf(temp,TEMPSIZE,"CD-ROM XA 4-bit ADPCM"); + break; + case coding_XBOX: + snprintf(temp,TEMPSIZE,"XBOX 4-bit IMA ADPCM"); + break; + case coding_EAXA: + snprintf(temp,TEMPSIZE,"Electronic Arts XA Based 4-bit ADPCM"); + break; + case coding_EA_ADPCM: + snprintf(temp,TEMPSIZE,"Electronic Arts XA Based (R1) 4-bit ADPCM"); + break; +#ifdef VGM_USE_VORBIS + case coding_ogg_vorbis: + snprintf(temp,TEMPSIZE,"Vorbis"); + break; +#endif + case coding_SDX2: + snprintf(temp,TEMPSIZE,"Squareroot-delta-exact (SDX2) 8-bit DPCM"); + break; + case coding_SDX2_int: + snprintf(temp,TEMPSIZE,"Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"); + break; + case coding_DVI_IMA: + snprintf(temp,TEMPSIZE,"Intel DVI 4-bit IMA ADPCM"); + break; + case coding_INT_DVI_IMA: + snprintf(temp,TEMPSIZE,"Interleaved Intel DVI 4-bit IMA ADPCM"); + break; + case coding_EACS_IMA: + snprintf(temp,TEMPSIZE,"EACS 4-bit IMA ADPCM"); + break; + case coding_INT_IMA: + snprintf(temp,TEMPSIZE,"Interleaved 4-bit IMA ADPCM"); + break; + case coding_IMA: + snprintf(temp,TEMPSIZE,"4-bit IMA ADPCM"); + break; + case coding_WS: + snprintf(temp,TEMPSIZE,"Westwood Studios DPCM"); + break; +#ifdef VGM_USE_MPEG + case coding_fake_MPEG2_L2: + snprintf(temp,TEMPSIZE,"MPEG-2 Layer II Audio"); + break; + case coding_MPEG1_L1: + snprintf(temp,TEMPSIZE,"MPEG-1 Layer I Audio"); + break; + case coding_MPEG1_L2: + snprintf(temp,TEMPSIZE,"MPEG-1 Layer II Audio"); + break; + case coding_MPEG1_L3: + snprintf(temp,TEMPSIZE,"MPEG-1 Layer III Audio (MP3)"); + break; + case coding_MPEG2_L1: + snprintf(temp,TEMPSIZE,"MPEG-2 Layer I Audio"); + break; + case coding_MPEG2_L2: + snprintf(temp,TEMPSIZE,"MPEG-2 Layer II Audio"); + break; + case coding_MPEG2_L3: + snprintf(temp,TEMPSIZE,"MPEG-2 Layer III Audio (MP3)"); + break; + case coding_MPEG25_L1: + snprintf(temp,TEMPSIZE,"MPEG-2.5 Layer I Audio"); + break; + case coding_MPEG25_L2: + snprintf(temp,TEMPSIZE,"MPEG-2.5 Layer II Audio"); + break; + case coding_MPEG25_L3: + snprintf(temp,TEMPSIZE,"MPEG-2.5 Layer III Audio (MP3)"); + break; +#endif + case coding_ACM: + snprintf(temp,TEMPSIZE,"InterPlay ACM"); + break; + case coding_NWA0: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 0"); + break; + case coding_NWA1: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 1"); + break; + case coding_NWA2: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 2"); + break; + case coding_NWA3: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 3"); + break; + case coding_NWA4: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 4"); + break; + case coding_NWA5: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 5"); + break; + case coding_MSADPCM: + snprintf(temp,TEMPSIZE,"Microsoft 4-bit ADPCM"); + break; + case coding_AICA: + snprintf(temp,TEMPSIZE,"Yamaha AICA 4-bit ADPCM"); + break; + case coding_NDS_PROCYON: + snprintf(temp,TEMPSIZE,"Procyon Studio Digital Sound Elements NDS 4-bit APDCM"); + break; + case coding_L5_555: + snprintf(temp,TEMPSIZE,"Level-5 0x555 ADPCM"); + break; + default: + snprintf(temp,TEMPSIZE,"CANNOT DECODE"); + } + concatn(length,desc,temp); + + snprintf(temp,TEMPSIZE,"\nlayout: "); + concatn(length,desc,temp); + + switch (vgmstream->layout_type) { + case layout_none: + snprintf(temp,TEMPSIZE,"flat (no layout)"); + break; + case layout_interleave: + snprintf(temp,TEMPSIZE,"interleave"); + break; + case layout_interleave_shortblock: + snprintf(temp,TEMPSIZE,"interleave with short last block"); + break; + case layout_interleave_byte: + snprintf(temp,TEMPSIZE,"sub-frame interleave"); + break; + case layout_dtk_interleave: + snprintf(temp,TEMPSIZE,"ADP/DTK nibble interleave"); + break; + case layout_ast_blocked: + snprintf(temp,TEMPSIZE,"AST blocked"); + break; + case layout_halpst_blocked: + snprintf(temp,TEMPSIZE,"HALPST blocked"); + break; + case layout_xa_blocked: + snprintf(temp,TEMPSIZE,"CD-ROM XA"); + break; + case layout_ea_blocked: + snprintf(temp,TEMPSIZE,"Electronic Arts Audio Blocks"); + break; + case layout_eacs_blocked: + snprintf(temp,TEMPSIZE,"Electronic Arts (Old Version) Audio Blocks"); + break; + case layout_caf_blocked: + snprintf(temp,TEMPSIZE,"CAF blocked"); + break; + case layout_wsi_blocked: + snprintf(temp,TEMPSIZE,".wsi blocked"); + break; + case layout_xvas_blocked: + snprintf(temp,TEMPSIZE,".xvas blocked"); + break; +#ifdef VGM_USE_VORBIS + case layout_ogg_vorbis: + snprintf(temp,TEMPSIZE,"Ogg"); + break; +#endif + case layout_str_snds_blocked: + snprintf(temp,TEMPSIZE,".str SNDS blocked"); + break; + case layout_ws_aud_blocked: + snprintf(temp,TEMPSIZE,"Westwood Studios .aud blocked"); + break; + case layout_matx_blocked: + snprintf(temp,TEMPSIZE,"Matrix .matx blocked"); + break; + case layout_de2_blocked: + snprintf(temp,TEMPSIZE,"de2 blocked"); + break; + case layout_vs_blocked: + snprintf(temp,TEMPSIZE,"vs blocked"); + break; + case layout_emff_ps2_blocked: + snprintf(temp,TEMPSIZE,"EMFF (PS2) blocked"); + break; + case layout_emff_ngc_blocked: + snprintf(temp,TEMPSIZE,"EMFF (NGC/WII) blocked"); + break; + case layout_gsb_blocked: + snprintf(temp,TEMPSIZE,"GSB blocked"); + break; + case layout_thp_blocked: + snprintf(temp,TEMPSIZE,"THP Movie Audio blocked"); + break; + case layout_filp_blocked: + snprintf(temp,TEMPSIZE,"FILp blocked"); + break; +#ifdef VGM_USE_MPEG + case layout_fake_mpeg: + snprintf(temp,TEMPSIZE,"MPEG Audio stream with incorrect frame headers"); + break; + case layout_mpeg: + snprintf(temp,TEMPSIZE,"MPEG Audio stream"); + break; +#endif + case layout_acm: + snprintf(temp,TEMPSIZE,"ACM blocked"); + break; + case layout_mus_acm: + snprintf(temp,TEMPSIZE,"multiple ACM files, ACM blocked"); + break; + case layout_aix: + snprintf(temp,TEMPSIZE,"AIX interleave, internally 18-byte interleaved"); + break; + case layout_aax: + snprintf(temp,TEMPSIZE,"AAX blocked, 18-byte interleaved"); + break; + default: + snprintf(temp,TEMPSIZE,"INCONCEIVABLE"); + } + concatn(length,desc,temp); + + snprintf(temp,TEMPSIZE,"\n"); + concatn(length,desc,temp); + + if (vgmstream->layout_type == layout_interleave || vgmstream->layout_type == layout_interleave_shortblock || vgmstream->layout_type == layout_interleave_byte) { + snprintf(temp,TEMPSIZE,"interleave: %#x bytes\n", + (int32_t)vgmstream->interleave_block_size); + concatn(length,desc,temp); + + if (vgmstream->layout_type == layout_interleave_shortblock) { + snprintf(temp,TEMPSIZE,"last block interleave: %#x bytes\n", + (int32_t)vgmstream->interleave_smallblock_size); + concatn(length,desc,temp); + } + } + + snprintf(temp,TEMPSIZE,"metadata from: "); + concatn(length,desc,temp); + + switch (vgmstream->meta_type) { + case meta_RSTM: + snprintf(temp,TEMPSIZE,"Nintendo RSTM header"); + break; + case meta_STRM: + snprintf(temp,TEMPSIZE,"Nintendo STRM header"); + break; + case meta_ADX_03: + snprintf(temp,TEMPSIZE,"CRI ADX header type 03"); + break; + case meta_ADX_04: + snprintf(temp,TEMPSIZE,"CRI ADX header type 04"); + break; + case meta_ADX_05: + snprintf(temp,TEMPSIZE,"CRI ADX header type 05"); + break; + case meta_AIX: + snprintf(temp,TEMPSIZE,"CRI AIX header"); + break; + case meta_AAX: + snprintf(temp,TEMPSIZE,"CRI AAX header"); + break; + case meta_DSP_AGSC: + snprintf(temp,TEMPSIZE,"Retro Studios AGSC header"); + break; + case meta_NGC_ADPDTK: + snprintf(temp,TEMPSIZE,"assumed Nintendo ADP by .adp extension and valid first frame"); + break; + case meta_RSF: + snprintf(temp,TEMPSIZE,"assumed Retro Studios RSF by .rsf extension and valid first bytes"); + break; + case meta_AFC: + snprintf(temp,TEMPSIZE,"Nintendo AFC header"); + break; + case meta_AST: + snprintf(temp,TEMPSIZE,"Nintendo AST header"); + break; + case meta_HALPST: + snprintf(temp,TEMPSIZE,"HAL Laboratory HALPST header"); + break; + case meta_DSP_RS03: + snprintf(temp,TEMPSIZE,"Retro Studios RS03 header"); + break; + case meta_DSP_STD: + snprintf(temp,TEMPSIZE,"Standard Nintendo DSP header"); + break; + case meta_DSP_CSTR: + snprintf(temp,TEMPSIZE,"Namco Cstr header"); + break; + case meta_GCSW: + snprintf(temp,TEMPSIZE,"GCSW header"); + break; + case meta_PS2_SShd: + snprintf(temp,TEMPSIZE,"SShd header"); + break; + case meta_PS2_NPSF: + snprintf(temp,TEMPSIZE,"Namco Production Sound File (NPSF) header"); + break; + case meta_RWSD: + snprintf(temp,TEMPSIZE,"Nintendo RWSD header (single stream)"); + break; + case meta_RWAR: + snprintf(temp,TEMPSIZE,"Nintendo RWAR header (single RWAV stream)"); + break; + case meta_RWAV: + snprintf(temp,TEMPSIZE,"Nintendo RWAV header"); + break; + case meta_PSX_XA: + snprintf(temp,TEMPSIZE,"RIFF/CDXA header"); + break; + case meta_PS2_RXW: + snprintf(temp,TEMPSIZE,"RXWS header)"); + break; + case meta_PS2_RAW: + snprintf(temp,TEMPSIZE,"assumed RAW Interleaved PCM by .int extension"); + break; + case meta_PS2_OMU: + snprintf(temp,TEMPSIZE,"Alter Echo OMU Header"); + break; + case meta_DSP_STM: + snprintf(temp,TEMPSIZE,"Nintendo STM header"); + break; + case meta_PS2_EXST: + snprintf(temp,TEMPSIZE,"EXST header"); + break; + case meta_PS2_SVAG: + snprintf(temp,TEMPSIZE,"Konami SVAG header"); + break; + case meta_PS2_MIB: + snprintf(temp,TEMPSIZE,"assumed MIB Interleaved file by .mib extension"); + break; + case meta_PS2_MIB_MIH: + snprintf(temp,TEMPSIZE,"assumed MIB with MIH Info Header file by .mib+.mih extension"); + break; + case meta_DSP_MPDSP: + snprintf(temp,TEMPSIZE,"Single DSP header stereo by .mpdsp extension"); + break; + case meta_PS2_MIC: + snprintf(temp,TEMPSIZE,"assume KOEI MIC file by .mic extension"); + break; + case meta_DSP_JETTERS: + snprintf(temp,TEMPSIZE,"Double DSP header stereo by _lr.dsp extension"); + break; + case meta_DSP_MSS: + snprintf(temp,TEMPSIZE,"Double DSP header stereo by .mss extension"); + break; + case meta_DSP_GCM: + snprintf(temp,TEMPSIZE,"Double DSP header stereo by .gcm extension"); + break; + case meta_DSP_WII_IDSP: + snprintf(temp,TEMPSIZE,"Wii IDSP Double DSP header"); + break; + case meta_RSTM_SPM: + snprintf(temp,TEMPSIZE,"Nintendo RSTM header and .brstmspm extension"); + break; + case meta_RAW: + snprintf(temp,TEMPSIZE,"assumed RAW PCM file by .raw extension"); + break; + case meta_PS2_VAGi: + snprintf(temp,TEMPSIZE,"Sony VAG Interleaved header (VAGi)"); + break; + case meta_PS2_VAGp: + snprintf(temp,TEMPSIZE,"Sony VAG Mono header (VAGp)"); + break; + case meta_PS2_VAGs: + snprintf(temp,TEMPSIZE,"Sony VAG Stereo header (VAGp)"); + break; + case meta_PS2_VAGm: + snprintf(temp,TEMPSIZE,"Sony VAG Mono header (VAGm)"); + break; + case meta_PS2_pGAV: + snprintf(temp,TEMPSIZE,"Sony VAG Stereo Little Endian header (pGAV)"); + break; + case meta_PSX_GMS: + snprintf(temp,TEMPSIZE,"assumed Grandia GMS file by .gms extension"); + break; + case meta_PS2_STR: + snprintf(temp,TEMPSIZE,"assumed STR + STH File by .str & .sth extension"); + break; + case meta_PS2_ILD: + snprintf(temp,TEMPSIZE,"ILD header"); + break; + case meta_PS2_PNB: + snprintf(temp,TEMPSIZE,"assumed PNB (PsychoNauts Bgm File) by .pnb extension"); + break; + case meta_XBOX_WAVM: + snprintf(temp,TEMPSIZE,"assumed Xbox WAVM file by .wavm extension"); + break; + case meta_XBOX_RIFF: + snprintf(temp,TEMPSIZE,"Xbox RIFF/WAVE file with 0x0069 Codec ID"); + break; + case meta_DSP_STR: + snprintf(temp,TEMPSIZE,"assumed Conan Gamecube STR File by .str extension"); + break; + case meta_EAXA_R2: + snprintf(temp,TEMPSIZE,"Electronic Arts XA R2"); + break; + case meta_EAXA_R3: + snprintf(temp,TEMPSIZE,"Electronic Arts XA R3"); + break; + case meta_EA_ADPCM: + snprintf(temp,TEMPSIZE,"Electronic Arts XA R1"); + break; + case meta_EA_IMA: + snprintf(temp,TEMPSIZE,"Electronic Arts container with IMA blocks"); + break; + case meta_EAXA_PSX: + snprintf(temp,TEMPSIZE,"Electronic Arts With PSX ADPCM"); + break; + case meta_EA_PCM: + snprintf(temp,TEMPSIZE,"Electronic Arts With PCM"); + break; + case meta_CFN: + snprintf(temp,TEMPSIZE,"Namco CAF Header"); + break; + case meta_PS2_VPK: + snprintf(temp,TEMPSIZE,"VPK Header"); + break; + case meta_GENH: + snprintf(temp,TEMPSIZE,"GENH Generic Header"); + break; +#ifdef VGM_USE_VORBIS + case meta_ogg_vorbis: + snprintf(temp,TEMPSIZE,"Ogg Vorbis"); + break; + case meta_OGG_SLI: + snprintf(temp,TEMPSIZE,"Ogg Vorbis with .sli (start,length) for looping"); + break; + case meta_OGG_SLI2: + snprintf(temp,TEMPSIZE,"Ogg Vorbis with .sli (from,to) for looping"); + break; + case meta_OGG_SFL: + snprintf(temp,TEMPSIZE,"Ogg Vorbis with SFPL for looping"); + break; + case meta_um3_ogg: + snprintf(temp,TEMPSIZE,"Ogg Vorbis, Ultramarine3 \"encryption\""); + break; +#endif + case meta_DSP_SADB: + snprintf(temp,TEMPSIZE,"sadb header"); + break; + case meta_SADL: + snprintf(temp,TEMPSIZE,"sadl header"); + break; + case meta_PS2_BMDX: + snprintf(temp,TEMPSIZE,"Beatmania .bmdx header"); + break; + case meta_DSP_WSI: + snprintf(temp,TEMPSIZE,".wsi header"); + break; + case meta_AIFC: + snprintf(temp,TEMPSIZE,"Audio Interchange File Format AIFF-C"); + break; + case meta_AIFF: + snprintf(temp,TEMPSIZE,"Audio Interchange File Format"); + break; + case meta_STR_SNDS: + snprintf(temp,TEMPSIZE,".str SNDS SHDR chunk"); + break; + case meta_WS_AUD: + snprintf(temp,TEMPSIZE,"Westwood Studios .aud header"); + break; + case meta_WS_AUD_old: + snprintf(temp,TEMPSIZE,"Westwood Studios .aud (old) header"); + break; +#ifdef VGM_USE_MPEG + case meta_AHX: + snprintf(temp,TEMPSIZE,"CRI AHX header"); + break; +#endif + case meta_PS2_IVB: + snprintf(temp,TEMPSIZE,"IVB/BVII header"); + break; + case meta_PS2_SVS: + snprintf(temp,TEMPSIZE,"Square SVS header"); + break; + case meta_RIFF_WAVE: + snprintf(temp,TEMPSIZE,"RIFF WAVE header"); + break; + case meta_RIFF_WAVE_POS: + snprintf(temp,TEMPSIZE,"RIFF WAVE header and .pos for looping"); + break; + case meta_NWA: + snprintf(temp,TEMPSIZE,"Visual Art's NWA header"); + break; + case meta_NWA_NWAINFOINI: + snprintf(temp,TEMPSIZE,"Visual Art's NWA header and NWAINFO.INI for looping"); + break; + case meta_NWA_GAMEEXEINI: + snprintf(temp,TEMPSIZE,"Visual Art's NWA header and Gameexe.ini for looping"); + break; + case meta_XSS: + snprintf(temp,TEMPSIZE,"Dino Crisis 3 XSS File"); + break; + case meta_HGC1: + snprintf(temp,TEMPSIZE,"Knights of the Temple 2 hgC1 Header"); + break; + case meta_AUS: + snprintf(temp,TEMPSIZE,"Capcom AUS Header"); + break; + case meta_RWS: + snprintf(temp,TEMPSIZE,"RWS Header"); + break; + case meta_EACS_PC: + snprintf(temp,TEMPSIZE,"EACS Header (PC)"); + break; + case meta_EACS_PSX: + snprintf(temp,TEMPSIZE,"EACS Header (PSX)"); + break; + case meta_EACS_SAT: + snprintf(temp,TEMPSIZE,"EACS Header (SATURN)"); + break; + case meta_SL3: + snprintf(temp,TEMPSIZE,"SL3 Header"); + break; + case meta_FSB1: + snprintf(temp,TEMPSIZE,"FMOD Sample Bank (FSB1) Header"); + break; + case meta_FSB3: + snprintf(temp,TEMPSIZE,"FMOD Sample Bank (FSB3) Header"); + break; + case meta_FSB4: + snprintf(temp,TEMPSIZE,"FMOD Sample Bank (FSB4) Header"); + break; + case meta_RWX: + snprintf(temp,TEMPSIZE,"RWX Header"); + break; + case meta_XWB: + snprintf(temp,TEMPSIZE,"XWB WBND Header"); + break; + case meta_XA30: + snprintf(temp,TEMPSIZE,"XA30 Header"); + break; + case meta_MUSC: + snprintf(temp,TEMPSIZE,"MUSC Header"); + break; + case meta_MUSX_V004: + snprintf(temp,TEMPSIZE,"MUSX / Version 004 Header"); + break; + case meta_MUSX_V006: + snprintf(temp,TEMPSIZE,"MUSX / Version 006 Header"); + break; + case meta_MUSX_V010: + snprintf(temp,TEMPSIZE,"MUSX / Version 010 Header"); + break; + case meta_MUSX_V201: + snprintf(temp,TEMPSIZE,"MUSX / Version 201 Header"); + break; + case meta_LEG: + snprintf(temp,TEMPSIZE,"Legaia 2 - Duel Saga LEG Header"); + break; + case meta_FILP: + snprintf(temp,TEMPSIZE,"Bio Hazard - Gun Survivor FILp Header"); + break; + case meta_IKM: + snprintf(temp,TEMPSIZE,"Zwei!! IKM Header"); + break; + case meta_SFS: + snprintf(temp,TEMPSIZE,"Baroque SFS Header"); + break; + case meta_DVI: + snprintf(temp,TEMPSIZE,"DVI Header"); + break; + case meta_KCEY: + snprintf(temp,TEMPSIZE,"KCEYCOMP Header"); + break; + case meta_BG00: + snprintf(temp,TEMPSIZE,"Falcom BG00 Header"); + break; + case meta_PS2_RSTM: + snprintf(temp,TEMPSIZE,"Rockstar Games RSTM Header"); + break; + case meta_ACM: + snprintf(temp,TEMPSIZE,"InterPlay ACM Header"); + break; + case meta_MUS_ACM: + snprintf(temp,TEMPSIZE,"MUS playlist and multiple InterPlay ACM Headered files"); + break; + case meta_PS2_KCES: + snprintf(temp,TEMPSIZE,"Konami KCES Header"); + break; + case meta_PS2_DXH: + snprintf(temp,TEMPSIZE,"Tokobot Plus DXH Header"); + break; + case meta_PS2_PSH: + snprintf(temp,TEMPSIZE,"Dawn of Mana - Seiken Densetsu 4 PSH Header"); + break; + case meta_RIFF_WAVE_labl_Marker: + snprintf(temp,TEMPSIZE,"RIFF WAVE header with loop markers"); + break; + case meta_RIFF_WAVE_smpl: + snprintf(temp,TEMPSIZE,"RIFF WAVE header with sample looping info"); + break; + case meta_PCM: + snprintf(temp,TEMPSIZE,"PCM file with custom header"); + break; + case meta_PS2_RKV: + snprintf(temp,TEMPSIZE,"Legacy of Kain - Blood Omen 2 RKV Header"); + break; + case meta_PS2_PSW: + snprintf(temp,TEMPSIZE,"Rayman Raving Rabbids Riff Container File"); + break; + case meta_PS2_VAS: + snprintf(temp,TEMPSIZE,"Pro Baseball Spirits 5 VAS Header"); + break; + case meta_PS2_TEC: + snprintf(temp,TEMPSIZE,"assumed TECMO badflagged stream by .tec extension"); + break; + case meta_XBOX_WVS: + snprintf(temp,TEMPSIZE,"Metal Arms WVS Header"); + break; + case meta_XBOX_STMA: + snprintf(temp,TEMPSIZE,"Midnight Club 2 STMA Header"); + break; + case meta_XBOX_MATX: + snprintf(temp,TEMPSIZE,"assumed Matrix file by .matx extension"); + break; + case meta_DE2: + snprintf(temp,TEMPSIZE,"gurumin .de2 with embedded funky RIFF"); + break; + case meta_VS: + snprintf(temp,TEMPSIZE,"Men in Black VS Header"); + break; + case meta_DC_STR: + snprintf(temp,TEMPSIZE,"Sega Stream Asset Builder header"); + break; + case meta_DC_STR_V2: + snprintf(temp,TEMPSIZE,"variant of Sega Stream Asset Builder header"); + break; + case meta_XBOX_XMU: + snprintf(temp,TEMPSIZE,"XMU header"); + break; + case meta_XBOX_XVAS: + snprintf(temp,TEMPSIZE,"assumed TMNT file by .xvas extension"); + break; + case meta_PS2_XA2: + snprintf(temp,TEMPSIZE,"assumed XA2 file by .xa2 extension"); + break; + case meta_DC_IDVI: + snprintf(temp,TEMPSIZE,"IDVI Header"); + break; + case meta_NGC_YMF: + snprintf(temp,TEMPSIZE,"YMF DSP Header"); + break; + case meta_PS2_CCC: + snprintf(temp,TEMPSIZE,"CCC Header"); + break; + case meta_PSX_FAG: + snprintf(temp,TEMPSIZE,"FAG Header"); + break; + case meta_PS2_MIHB: + snprintf(temp,TEMPSIZE,"Merged MIH+MIB"); + break; + case meta_DSP_WII_MUS: + snprintf(temp,TEMPSIZE,"mus header"); + break; + case meta_WII_SNG: + snprintf(temp,TEMPSIZE,"SNG DSP Header"); + break; + case meta_RSD2VAG: + snprintf(temp,TEMPSIZE,"RSD2/VAG Header"); + break; + case meta_RSD2PCMB: + snprintf(temp,TEMPSIZE,"RSD2/PCMB Header"); + break; + case meta_RSD2XADP: + snprintf(temp,TEMPSIZE,"RSD2/XADP Header"); + break; + case meta_RSD3PCM: + snprintf(temp,TEMPSIZE,"RSD3/PCM Header"); + break; + case meta_RSD4PCMB: + snprintf(temp,TEMPSIZE,"RSD4/PCMB Header"); + break; + case meta_RSD4PCM: + snprintf(temp,TEMPSIZE,"RSD4/PCM Header"); + break; + case meta_RSD4VAG: + snprintf(temp,TEMPSIZE,"RSD4/VAG Header"); + break; + case meta_RSD6XADP: + snprintf(temp,TEMPSIZE,"RSD6/XADP Header"); + break; + case meta_RSD6VAG: + snprintf(temp,TEMPSIZE,"RSD6/VAG Header"); + break; + case meta_RSD6WADP: + snprintf(temp,TEMPSIZE,"RSD6/WADP Header"); + break; + case meta_DC_ASD: + snprintf(temp,TEMPSIZE,"ASD Header"); + break; + case meta_NAOMI_SPSD: + snprintf(temp,TEMPSIZE,"SPSD Header"); + break; + case meta_FFXI_BGW: + snprintf(temp,TEMPSIZE,"BGW BGMStream header"); + break; + case meta_FFXI_SPW: + snprintf(temp,TEMPSIZE,"SPW SeWave header"); + break; + case meta_PS2_ASS: + snprintf(temp,TEMPSIZE,"ASS Header"); + break; + case meta_IDSP: + snprintf(temp,TEMPSIZE,"IDSP Header"); + break; + case meta_IDSP2: + snprintf(temp,TEMPSIZE,"IDSP Header"); + break; + case meta_WAA_WAC_WAD_WAM: + snprintf(temp,TEMPSIZE,"WAA/WAC/WAD/WAM RIFF Header"); + break; + case meta_PS2_SEG: + snprintf(temp,TEMPSIZE,"SEG (PS2) Header"); + break; + case meta_NDS_STRM_FFTA2: + snprintf(temp,TEMPSIZE,"Final Fantasy Tactics A2 RIFF Header"); + break; + case meta_STR_ASR: + snprintf(temp,TEMPSIZE,"Donkey Kong Jet Race KNON/WII Header"); + break; + case meta_ZWDSP: + snprintf(temp,TEMPSIZE,"Zack and Wiki custom DSP Header"); + break; + case meta_GCA: + snprintf(temp,TEMPSIZE,"GCA DSP Header"); + break; + case meta_SPT_SPD: + snprintf(temp,TEMPSIZE,"SPT+SPD DSP Header"); + break; + case meta_ISH_ISD: + snprintf(temp,TEMPSIZE,"ISH+ISD DSP Header"); + break; + case meta_YDSP: + snprintf(temp,TEMPSIZE,"YDSP Header"); + break; + case meta_MSVP: + snprintf(temp,TEMPSIZE,"MSVP Header"); + break; + case meta_NGC_SSM: + snprintf(temp,TEMPSIZE,"SSM DSP Header"); + break; + case meta_PS2_JOE: + snprintf(temp,TEMPSIZE,"Disney/Pixar JOE Header"); + break; + case meta_VGS: + snprintf(temp,TEMPSIZE,"Guitar Hero Encore Rocks the 80's Header"); + break; + case meta_DC_WAV_DCS: + snprintf(temp,TEMPSIZE,"Evil Twin WAV+DCS Header"); + break; + case meta_WII_SMP: + snprintf(temp,TEMPSIZE,"SMP DSP Header"); + break; + case meta_EMFF_PS2: + case meta_EMFF_NGC: + snprintf(temp,TEMPSIZE,"Eidos Music File Format Header"); + break; + case meta_THP: + snprintf(temp,TEMPSIZE,"THP Movie File Format Header"); + break; + case meta_STS_WII: + snprintf(temp,TEMPSIZE,"Shikigami no Shiro (WII) Header"); + break; + case meta_PS2_P2BT: + snprintf(temp,TEMPSIZE,"Pop'n'Music 7 Header"); + break; + case meta_PS2_GBTS: + snprintf(temp,TEMPSIZE,"Pop'n'Music 9 Header"); + break; + case meta_NGC_IADP: + snprintf(temp,TEMPSIZE,"Dr MUTO Header"); + break; + case meta_RSTM_shrunken: + snprintf(temp,TEMPSIZE,"Nintendo RSTM header, corrupted by Atlus"); + break; + case meta_RIFF_WAVE_MWV: + snprintf(temp,TEMPSIZE,"RIFF WAVE header with .mwv flavoring"); + break; + case meta_FFCC_STR: + snprintf(temp,TEMPSIZE,"Final Fantasy: Crystal Chronicles STR header"); + break; + default: + snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET"); + } + concatn(length,desc,temp); +} + +/* */ +const char * const dfs_pairs[][2] = { + {"L","R"}, + {"l","r"}, + {"_0","_1"}, + {"left","right"}, + {"Left","Right"}, +}; +#define DFS_PAIR_COUNT (sizeof(dfs_pairs)/sizeof(dfs_pairs[0])) + +void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile) { + char filename[260]; + char filename2[260]; + char * ext; + int dfs_name= -1; /*-1=no stereo, 0=opened_stream is left, 1=opened_stream is right */ + VGMSTREAM * new_stream = NULL; + STREAMFILE *dual_stream = NULL; + int i,j; + + if (opened_stream->channels != 1) return; + + streamFile->get_name(streamFile,filename,sizeof(filename)); + + /* vgmstream's layout stuff currently assumes a single file */ + // fastelbja : no need ... this one works ok with dual file + //if (opened_stream->layout != layout_none) return; + + /* we need at least a base and a name ending to replace */ + if (strlen(filename)<2) return; + + strcpy(filename2,filename); + + /* look relative to the extension; */ + ext = (char *)filename_extension(filename2); + + /* we treat the . as part of the extension */ + if (ext-filename2 >= 1 && ext[-1]=='.') ext--; + + for (i=0; dfs_name==-1 && i<DFS_PAIR_COUNT; i++) { + for (j=0; dfs_name==-1 && j<2; j++) { + /* find a postfix on the name */ + if (!memcmp(ext-strlen(dfs_pairs[i][j]), + dfs_pairs[i][j], + strlen(dfs_pairs[i][j]))) { + int other_name=j^1; + int moveby; + dfs_name=j; + + /* move the extension */ + moveby = strlen(dfs_pairs[i][other_name]) - + strlen(dfs_pairs[i][dfs_name]); + memmove(ext+moveby,ext,strlen(ext)+1); /* terminator, too */ + + /* make the new name */ + memcpy(ext+moveby-strlen(dfs_pairs[i][other_name]),dfs_pairs[i][other_name],strlen(dfs_pairs[i][other_name])); + } + } + } + + /* did we find a name for the other file? */ + if (dfs_name==-1) goto fail; + +#if 0 + printf("input is: %s\n" + "other file would be: %s\n", + filename,filename2); +#endif + + dual_stream = streamFile->open(streamFile,filename2,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!dual_stream) goto fail; + + new_stream = init_vgmstream_internal(dual_stream, + 0 /* don't do dual file on this, to prevent recursion */ + ); + close_streamfile(dual_stream); + + /* see if we were able to open the file, and if everything matched nicely */ + if (new_stream && + new_stream->channels == 1 && + /* we have seen legitimate pairs where these are off by one... */ + /* but leaving it commented out until I can find those and recheck */ + /* abs(new_stream->num_samples-opened_stream->num_samples <= 1) && */ + new_stream->num_samples == opened_stream->num_samples && + new_stream->sample_rate == opened_stream->sample_rate && + new_stream->meta_type == opened_stream->meta_type && + new_stream->coding_type == opened_stream->coding_type && + new_stream->layout_type == opened_stream->layout_type && + new_stream->loop_flag == opened_stream->loop_flag && + /* check these even if there is no loop, because they should then + * be zero in both */ + new_stream->loop_start_sample == opened_stream->loop_start_sample && + new_stream->loop_end_sample == opened_stream->loop_end_sample && + /* check even if the layout doesn't use them, because it is + * difficult to determine when it does, and they should be zero + * otherwise, anyway */ + new_stream->interleave_block_size == opened_stream->interleave_block_size && + new_stream->interleave_smallblock_size == opened_stream->interleave_smallblock_size) { + /* We seem to have a usable, matching file. Merge in the second channel. */ + VGMSTREAMCHANNEL * new_chans; + VGMSTREAMCHANNEL * new_loop_chans = NULL; + VGMSTREAMCHANNEL * new_start_chans = NULL; + + /* build the channels */ + new_chans = calloc(2,sizeof(VGMSTREAMCHANNEL)); + if (!new_chans) goto fail; + + memcpy(&new_chans[dfs_name],&opened_stream->ch[0],sizeof(VGMSTREAMCHANNEL)); + memcpy(&new_chans[dfs_name^1],&new_stream->ch[0],sizeof(VGMSTREAMCHANNEL)); + + /* loop and start will be initialized later, we just need to + * allocate them here */ + new_start_chans = calloc(2,sizeof(VGMSTREAMCHANNEL)); + if (!new_start_chans) { + free(new_chans); + goto fail; + } + + if (opened_stream->loop_ch) { + new_loop_chans = calloc(2,sizeof(VGMSTREAMCHANNEL)); + if (!new_loop_chans) { + free(new_chans); + free(new_start_chans); + goto fail; + } + } + + /* remove the existing structures */ + /* not using close_vgmstream as that would close the file */ + free(opened_stream->ch); + free(new_stream->ch); + + free(opened_stream->start_ch); + free(new_stream->start_ch); + + if (opened_stream->loop_ch) { + free(opened_stream->loop_ch); + free(new_stream->loop_ch); + } + + /* fill in the new structures */ + opened_stream->ch = new_chans; + opened_stream->start_ch = new_start_chans; + opened_stream->loop_ch = new_loop_chans; + + /* stereo! */ + opened_stream->channels = 2; + + /* discard the second VGMSTREAM */ + free(new_stream); + } +fail: + return; +} diff --git a/lib/vgmstream/src/vgmstream.h b/lib/vgmstream/src/vgmstream.h new file mode 100644 index 0000000000..82f377a147 --- /dev/null +++ b/lib/vgmstream/src/vgmstream.h @@ -0,0 +1,608 @@ +/* + * vgmstream.h - definitions for VGMSTREAM, encapsulating a multi-channel, looped audio stream + */ + +#ifndef _VGMSTREAM_H +#define _VGMSTREAM_H + +/* Vorbis and MPEG decoding are done by external libraries. + * If someone wants to do a standalone build, they can do it by simply + * removing these defines (and the references to the libraries in the + * Makefile) */ +//#define VGM_USE_VORBIS +//#define VGM_USE_MPEG + +#include "streamfile.h" +#include "coding/g72x_state.h" +#ifdef VGM_USE_VORBIS +#include <vorbis/vorbisfile.h> +#endif +#ifdef VGM_USE_MPEG +#include <mpg123.h> +#endif +#include "coding/acm_decoder.h" +#include "coding/nwa_decoder.h" + +/* The encoding type specifies the format the sound data itself takes */ +typedef enum { + /* 16-bit PCM */ + coding_PCM16BE, /* big endian 16-bit PCM */ + coding_PCM16LE, /* little endian 16-bit PCM */ + coding_PCM16LE_int, /* little endian 16-bit PCM with sample-level + interleave handled by the decoder */ + + /* 8-bit PCM */ + coding_PCM8, /* 8-bit PCM */ + coding_PCM8_int, /* 8-Bit PCM with sample-level interleave handled + by the decoder */ + coding_PCM8_SB_int, /* 8-bit PCM, sign bit (others are 2's complement), + sample-level interleave */ + coding_PCM8_U_int, /* 8-bit PCM, unsigned (0x80 = 0), sample-level + interleave */ + + /* 4-bit ADPCM */ + coding_NDS_IMA, /* IMA ADPCM w/ NDS layout */ + coding_CRI_ADX, /* CRI ADX */ + coding_CRI_ADX_enc, /* encrypted CRI ADX */ + coding_NGC_DSP, /* NGC ADPCM, called DSP */ + coding_NGC_DTK, /* NGC hardware disc ADPCM, called DTK, TRK or ADP */ + coding_G721, /* CCITT G.721 ADPCM */ + coding_NGC_AFC, /* NGC ADPCM, called AFC */ + coding_PSX, /* PSX & PS2 ADPCM */ + coding_invert_PSX, /* PSX ADPCM with some weirdness */ + coding_PSX_badflags, /* with garbage in the flags byte */ + coding_FFXI, /* FF XI PSX-ish ADPCM */ + coding_XA, /* PSX CD-XA */ + coding_XBOX, /* XBOX IMA */ + coding_EAXA, /* EA/XA ADPCM */ + coding_EA_ADPCM, /* EA ADPCM */ + coding_NDS_PROCYON, /* NDS Procyon Studio ADPCM */ + +#ifdef VGM_USE_VORBIS + coding_ogg_vorbis, /* vorbis */ +#endif + coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression */ + coding_SDX2_int, /* SDX2 2:1 Squareroot-Delta-Exact compression, + with smaple-level interleave handled by the + decoder */ + coding_DVI_IMA, /* DVI (bare IMA, high nibble first), aka ADP4 */ + coding_INT_DVI_IMA, /* Interleaved DVI */ + coding_EACS_IMA, + coding_IMA, /* bare IMA, low nibble first */ + coding_INT_IMA, /* */ + coding_WS, /* Westwood Studios' custom VBR ADPCM */ +#ifdef VGM_USE_MPEG + coding_fake_MPEG2_L2, /* MPEG-2 Layer 2 (AHX), with lying headers */ + /* I don't even know offhand if all these combinations exist... */ + coding_MPEG1_L1, + coding_MPEG1_L2, + coding_MPEG1_L3, /* good ol' MPEG-1 Layer 3 (MP3) */ + coding_MPEG2_L1, + coding_MPEG2_L2, + coding_MPEG2_L3, + coding_MPEG25_L1, + coding_MPEG25_L2, + coding_MPEG25_L3, +#endif + + coding_ACM, /* InterPlay ACM */ + /* compressed NWA at various levels */ + coding_NWA0, + coding_NWA1, + coding_NWA2, + coding_NWA3, + coding_NWA4, + coding_NWA5, + + coding_MSADPCM, /* Microsoft ADPCM */ + coding_AICA, /* Yamaha AICA ADPCM */ + coding_L5_555, /* Level-5 0x555 */ +} coding_t; + +/* The layout type specifies how the sound data is laid out in the file */ +typedef enum { + /* generic */ + layout_none, /* straight data */ + /* interleave */ + layout_interleave, /* equal interleave throughout the stream */ + layout_interleave_shortblock, /* interleave with a short last block */ + + layout_interleave_byte, /* full byte interleave */ + + /* headered blocks */ + layout_ast_blocked, /* .ast STRM with BLCK blocks*/ + layout_halpst_blocked, /* blocks with HALPST-format header */ + layout_xa_blocked, + layout_ea_blocked, + layout_eacs_blocked, + layout_caf_blocked, + layout_wsi_blocked, + layout_str_snds_blocked, + layout_ws_aud_blocked, + layout_matx_blocked, + layout_de2_blocked, + layout_xvas_blocked, + layout_vs_blocked, + layout_emff_ps2_blocked, + layout_emff_ngc_blocked, + layout_gsb_blocked, + layout_thp_blocked, + layout_filp_blocked, + +#if 0 + layout_strm_blocked, /* */ +#endif + /* otherwise odd */ + layout_dtk_interleave, /* dtk interleaves channels by nibble */ +#ifdef VGM_USE_VORBIS + layout_ogg_vorbis, /* ogg vorbis file */ +#endif +#ifdef VGM_USE_MPEG + layout_fake_mpeg, /* MPEG audio stream with bad frame headers (AHX) */ + layout_mpeg, /* proper MPEG audio stream */ +#endif + layout_acm, /* dummy, let libacm handle layout */ + layout_mus_acm, /* mus has multi-files to deal with */ + layout_aix, /* CRI AIX's wheels within wheels */ + layout_aax, /* CRI AAX's wheels within databases */ +} layout_t; + +/* The meta type specifies how we know what we know about the file. We may know because of a header we read, some of it may have been guessed from filenames, etc. */ +typedef enum { + /* DSP-specific */ + meta_DSP_STD, /* standard GC ADPCM (DSP) header */ + meta_DSP_CSTR, /* Star Fox Assault "Cstr" */ + meta_DSP_RS03, /* Metroid Prime 2 "RS03" */ + meta_DSP_STM, /* Paper Mario 2 STM */ + meta_DSP_HALP, /* SSB:M "HALPST" */ + meta_DSP_AGSC, /* Metroid Prime 2 title */ + meta_DSP_MPDSP, /* Monopoly Party single header stereo */ + meta_DSP_JETTERS, /* Bomberman Jetters .dsp */ + meta_DSP_MSS, + meta_DSP_GCM, + meta_DSP_STR, /* Conan .str files */ + meta_DSP_SADB, /* .sad */ + meta_DSP_WSI, /* .wsi */ + meta_DSP_AMTS, /* .amts */ + meta_DSP_WII_IDSP, /* .gcm with IDSP header */ + meta_DSP_WII_MUS, /* .mus */ + + /* Nintendo */ + meta_STRM, /* STRM */ + meta_RSTM, /* RSTM (similar to STRM) */ + meta_AFC, /* AFC */ + meta_AST, /* AST */ + meta_RWSD, /* single-stream RWSD */ + meta_RWAR, /* single-stream RWAR */ + meta_RWAV, /* contents of RWAR */ + meta_RSTM_SPM, /* RSTM with 44->22khz hack */ + meta_THP, + meta_RSTM_shrunken, /* Atlus' mutant shortened RSTM */ + + /* CRI ADX */ + meta_ADX_03, /* ADX "type 03" */ + meta_ADX_04, /* ADX "type 04" */ + meta_ADX_05, /* ADX "type 05" */ + meta_AIX, /* CRI AIX */ + meta_AAX, /* CRI AAX */ + + /* etc */ + meta_NGC_ADPDTK, /* NGC DTK/ADP, no header (.adp) */ + meta_kRAW, /* almost headerless PCM */ + meta_RSF, /* Retro Studios RSF, no header (.rsf) */ + meta_HALPST, /* HAL Labs HALPST */ + meta_GCSW, /* GCSW (PCM) */ + meta_CFN, /* Namco CAF Audio File */ + + meta_PS2_SShd, /* .ADS with SShd header */ + meta_PS2_NPSF, /* Namco Production Sound File */ + meta_PS2_RXW, /* Sony Arc The Lad Sound File */ + meta_PS2_RAW, /* RAW Interleaved Format */ + meta_PS2_EXST, /* Shadow of Colossus EXST */ + meta_PS2_SVAG, /* Konami SVAG */ + meta_PS2_MIB, /* MIB File */ + meta_PS2_MIB_MIH, /* MIB File + MIH Header*/ + meta_PS2_MIC, /* KOEI MIC File */ + meta_PS2_VAGi, /* VAGi Interleaved File */ + meta_PS2_VAGp, /* VAGp Mono File */ + meta_PS2_VAGm, /* VAGp Mono File */ + meta_PS2_pGAV, /* VAGp with Little Endian Header */ + meta_PSX_GMS, /* GMS File (used in PS1 & PS2) */ + meta_PS2_STR, /* Pacman STR+STH files */ + meta_PS2_ILD, /* ILD File */ + meta_PS2_PNB, /* PsychoNauts Bgm File */ + meta_PSX_XA, /* CD-XA with RIFF header */ + meta_PS2_VAGs, /* VAG Stereo from Kingdom Hearts */ + meta_PS2_VPK, /* VPK Audio File */ + meta_PS2_BMDX, /* Beatmania thing */ + meta_PS2_IVB, /* Langrisser 3 IVB */ + meta_PS2_SVS, /* Square SVS */ + meta_XSS, /* Dino Crisis 3 */ + meta_SL3, /* Test Drive Unlimited */ + meta_HGC1, /* Knights of the Temple 2 */ + meta_AUS, /* Variuos Capcom Games */ + meta_RWS, /* Variuos Konami Games */ + meta_FSB1, /* FMOD Sample Bank, version 1 */ + meta_FSB3, /* FMOD Sample Bank, version 3 */ + meta_FSB4, /* FMOD Sample Bank, version 4 */ + meta_RWX, /* Air Force Delta Storm (XBOX) */ + meta_XWB, /* King of Fighters (XBOX) */ + meta_XA30, /* Driver - Parallel Lines (PS2) */ + meta_MUSC, /* Spyro Games, possibly more */ + meta_MUSX_V004, /* Spyro Games, possibly more */ + meta_MUSX_V006, /* Spyro Games, possibly more */ + meta_MUSX_V010, /* Spyro Games, possibly more */ + meta_MUSX_V201, /* Sphinx and the cursed Mummy */ + meta_LEG, /* Legaia 2 */ + meta_FILP, /* Resident Evil - Dead Aim */ + meta_IKM, /* Zwei! */ + meta_SFS, /* Baroque */ + meta_BG00, /* Ibara, Mushihimesama */ + meta_PS2_RSTM, /* Midnight Club 3 */ + meta_PS2_KCES, /* Dance Dance Revolution */ + meta_PS2_DXH, /* Tokobot Plus - Myteries of the Karakuri */ + meta_PS2_PSH, /* Dawn of Mana - Seiken Densetsu 4 */ + meta_PCM, /* Ephemeral Fantasia, Lunar - Eternal Blue */ + meta_PS2_RKV, /* Legacy of Kain - Blood Omen 2 */ + meta_PS2_PSW, /* Rayman Raving Rabbids */ + meta_PS2_VAS, /* Pro Baseball Spirits 5 */ + meta_PS2_TEC, /* TECMO badflagged stream */ + meta_PS2_ENTH, /* Enthusia */ + meta_SDT, /* Baldur's Gate - Dark Alliance */ + meta_NGC_TYDSP, /* Ty - The Tasmanian Tiger */ + meta_NGC_SWD, /* Conflict - Desert Storm 1 & 2 */ + meta_CAPDSP, /* Capcom DSP Header */ + meta_DC_STR, /* SEGA Stream Asset Builder */ + meta_DC_STR_V2, /* variant of SEGA Stream Asset Builder */ + meta_NGC_BH2PCM, /* Bio Hazard 2 */ + meta_SAT_SAP, /* Bubble Symphony */ + meta_DC_IDVI, /* Eldorado Gate */ + meta_KRAW, /* Geometry Wars - Galaxies */ + meta_PS2_OMU, /* PS2 Int file with Header */ + meta_PS2_XA2, /* XA2 XG3 file */ + meta_IDSP, /* Chronicles of Narnia */ + meta_SPT_SPD, /* Variouis */ + meta_ISH_ISD, /* Various */ + meta_GSP_GSB, /* Various */ + meta_YDSP, /* WWE Day of Reckoning */ + meta_FFCC_STR, /* Final Fantasy: Crystal Chronicles */ + + meta_IDSP2, /* Chronicles of Narnia */ + meta_WAA_WAC_WAD_WAM, /* Beyond Good & Evil */ + meta_GCA, /* Metal Slug Anthology */ + meta_MSVP, /* Popcap Hits */ + meta_NGC_SSM, /* Golden Gashbell Full Power */ + meta_PS2_JOE, /* Wall-E / Pixar games */ + + meta_NGC_YMF, /* WWE WrestleMania X8 */ + meta_SADL, /* .sad */ + meta_PS2_CCC, /* Tokyo Xtreme Racer DRIFT 2 */ + meta_PSX_FAG, /* Jackie Chan - Stuntmaster */ + meta_PS2_MIHB, /* Merged MIH+MIB */ + meta_NGC_PDT, /* Mario Party 6 */ + meta_DC_ASD, /* Miss Moonligh */ + meta_NAOMI_SPSD, /* Guilty Gear X */ + + meta_RSD2VAG, /* RSD2VAG */ + meta_RSD2PCMB, /* RSD2PCMB */ + meta_RSD2XADP, /* RSD2XADP */ + meta_RSD3PCM, /* RSD3PCM */ + meta_RSD4PCMB, /* RSD4PCMB */ + meta_RSD4PCM, /* RSD4PCM */ + meta_RSD4VAG, /* RSD4VAG */ + meta_RSD6VAG, /* RSD6VAG */ + meta_RSD6WADP, /* RSD6WADP */ + meta_RSD6XADP, /* RSD6XADP */ + + meta_PS2_ASS, /* ASS */ + meta_PS2_SEG, /* Eragon */ + meta_NDS_STRM_FFTA2, /* Final Fantasy Tactics A2 */ + meta_STR_ASR, /* Donkey Kong Jet Race */ + meta_ZWDSP, /* Zack and Wiki */ + meta_VGS, /* Guitar Hero Encore - Rocks the 80s */ + meta_DC_WAV_DCS, /* Evil Twin - Cypriens Chronicles (DC) */ + meta_WII_SMP, /* Mushroom Men - The Spore Wars */ + meta_WII_SNG, /* Excite Trucks */ + meta_EMFF_PS2, /* Eidos Music File Format for PS2*/ + meta_EMFF_NGC, /* Eidos Music File Format for NGC/WII */ + + meta_XBOX_WAVM, /* XBOX WAVM File */ + meta_XBOX_RIFF, /* XBOX RIFF/WAVE File */ + meta_XBOX_WVS, /* XBOX WVS */ + meta_XBOX_STMA, /* XBOX STMA */ + meta_XBOX_MATX, /* XBOX MATX */ + meta_XBOX_XMU, /* XBOX XMU */ + meta_XBOX_XVAS, /* XBOX VAS */ + + meta_EAXA_R2, /* EA XA Release 2 */ + meta_EAXA_R3, /* EA XA Release 3 */ + meta_EAXA_PSX, /* EA with PSX ADPCM */ + meta_EACS_PC, /* EACS PC */ + meta_EACS_PSX, /* EACS PSX */ + meta_EACS_SAT, /* EACS SATURN */ + meta_EA_ADPCM, /* EA XA ADPCM */ + meta_EA_IMA, /* EA IMA */ + meta_EA_PCM, /* EA PCM */ + + meta_RAW, /* RAW PCM file */ + + meta_GENH, /* generic header */ + +#ifdef VGM_USE_VORBIS + meta_ogg_vorbis, /* ogg vorbis */ + meta_OGG_SLI, /* Ogg Vorbis file w/ companion .sli for looping */ + meta_OGG_SLI2, /* Ogg Vorbis file w/ different styled .sli for looping */ + meta_OGG_SFL, /* Ogg Vorbis file w/ .sfl (RIFF SFPL) for looping */ + meta_um3_ogg, /* Ogg Vorbis with first 0x800 bytes XOR 0xFF */ +#endif + + meta_AIFC, /* Audio Interchange File Format AIFF-C */ + meta_AIFF, /* Audio Interchange File Format */ + meta_STR_SNDS, /* .str with SNDS blocks and SHDR header */ + meta_WS_AUD, /* Westwood Studios .aud */ + meta_WS_AUD_old, /* Westwood Studios .aud, old style */ +#ifdef VGM_USE_MPEG + meta_AHX, /* CRI AHX header (same structure as ADX) */ +#endif + meta_RIFF_WAVE, /* RIFF, for WAVs */ + meta_RIFF_WAVE_POS, /* .wav + .pos for looping */ + meta_RIFF_WAVE_labl_Marker, /* RIFF w/ loop Markers in LIST-adtl-labl */ + meta_RIFF_WAVE_smpl, /* RIFF w/ loop data in smpl chunk */ + meta_RIFF_WAVE_MWV, /* .mwv RIFF w/ loop data in ctrl chunk pflt */ + meta_NWA, /* Visual Art's NWA */ + meta_NWA_NWAINFOINI, /* NWA w/ NWAINFO.INI for looping */ + meta_NWA_GAMEEXEINI, /* NWA w/ Gameexe.ini for looping */ + meta_DVI, /* DVI Interleaved */ + meta_KCEY, /* KCEYCOMP */ + meta_ACM, /* InterPlay ACM header */ + meta_MUS_ACM, /* MUS playlist of InterPlay ACM files */ + meta_DE2, /* Falcom (Gurumin) .de2 */ + meta_VS, /* Men in Black .vs */ + meta_FFXI_BGW, /* FFXI BGW */ + meta_FFXI_SPW, /* FFXI SPW */ + meta_STS_WII, /* Shikigami No Shiro 3 STS Audio File */ + meta_PS2_P2BT, /* Pop'n'Music 7 Audio File */ + meta_PS2_GBTS, /* Pop'n'Music 9 Audio File */ + meta_NGC_IADP, /* Gamecube Interleave DSP */ + +} meta_t; + +typedef struct { + STREAMFILE * streamfile; /* file used by this channel */ + off_t channel_start_offset; /* where data for this channel begins */ + off_t offset; /* current location in the file */ + + off_t frame_header_offset; /* offset of the current frame header (for WS) */ + int samples_left_in_frame; /* for WS */ + + /* format specific */ + + /* adpcm */ + int16_t adpcm_coef[16]; /* for formats with decode coefficients built in */ + int32_t adpcm_coef_3by32[0x60]; /* for Level-5 0x555 */ + union { + int16_t adpcm_history1_16; /* previous sample */ + int32_t adpcm_history1_32; + }; + union { + int16_t adpcm_history2_16; /* previous previous sample */ + int32_t adpcm_history2_32; + }; + union { + int16_t adpcm_history3_16; + int32_t adpcm_history3_32; + }; + + int adpcm_step_index; /* for IMA */ + int adpcm_scale; /* for MS ADPCM */ + + struct g72x_state g72x_state; /* state for G.721 decoder, sort of big but we + might as well keep it around */ + +#ifdef DEBUG + int samples_done; + int16_t loop_history1,loop_history2; +#endif + + /* ADX encryption */ + int adx_channels; + uint16_t adx_xor; + uint16_t adx_mult; + uint16_t adx_add; + + /* BMDX encryption */ + uint8_t bmdx_xor; + uint8_t bmdx_add; +} VGMSTREAMCHANNEL; + +typedef struct { + /* basics */ + int32_t num_samples; /* the actual number of samples in this stream */ + int32_t sample_rate; /* sample rate in Hz */ + int channels; /* number of channels */ + coding_t coding_type; /* type of encoding */ + layout_t layout_type; /* type of layout for data */ + meta_t meta_type; /* how we know the metadata */ + + /* looping */ + int loop_flag; /* is this stream looped? */ + int32_t loop_start_sample; /* first sample of the loop (included in the loop) */ + int32_t loop_end_sample; /* last sample of the loop (not included in the loop) */ + + /* channels */ + VGMSTREAMCHANNEL * ch; /* pointer to array of channels */ + + /* channel copies */ + VGMSTREAMCHANNEL * start_ch; /* copies of channel status as they were at the beginning of the stream */ + VGMSTREAMCHANNEL * loop_ch; /* copies of channel status as they were at the loop point */ + + /* layout-specific */ + int32_t current_sample; /* number of samples we've passed */ + int32_t samples_into_block; /* number of samples into the current block */ + /* interleave */ + size_t interleave_block_size; /* interleave for this file */ + size_t interleave_smallblock_size; /* smaller interleave for last block */ + /* headered blocks */ + off_t current_block_offset; /* start of this block (offset of block header) */ + size_t current_block_size; /* size of the block we're in now */ + off_t next_block_offset; /* offset of header of the next block */ + + int hit_loop; /* have we seen the loop yet? */ + + /* loop layout (saved values) */ + int32_t loop_sample; /* saved from current_sample, should be loop_start_sample... */ + int32_t loop_samples_into_block; /* saved from samples_into_block */ + off_t loop_block_offset; /* saved from current_block_offset */ + size_t loop_block_size; /* saved from current_block_size */ + off_t loop_next_block_offset; /* saved from next_block_offset */ + + uint8_t xa_channel; /* Selected XA Channel */ + int32_t xa_sector_length; /* XA block */ + int8_t get_high_nibble; + + uint8_t ea_big_endian; /* Big Endian ? */ + uint8_t ea_compression_type; + uint8_t ea_compression_version; + uint8_t ea_platform; + + int32_t ws_output_size; /* output bytes for this block */ + + void * start_vgmstream; /* a copy of the VGMSTREAM as it was at the beginning of the stream */ + + int32_t thpNextFrameSize; + + /* Data the codec needs for the whole stream. This is for codecs too + * different from vgmstream's structure to be reasonably shoehorned into + * using the ch structures. + * Note also that support must be added for resetting, looping and + * closing for every codec that uses this, as it will not be handled. */ + void * codec_data; +} VGMSTREAM; + +#ifdef VGM_USE_VORBIS +typedef struct { + STREAMFILE *streamfile; + ogg_int64_t offset; + ogg_int64_t size; +} ogg_vorbis_streamfile; + +typedef struct { + OggVorbis_File ogg_vorbis_file; + int bitstream; + + ogg_vorbis_streamfile ov_streamfile; +} ogg_vorbis_codec_data; +#endif + +#ifdef VGM_USE_MPEG +#define AHX_EXPECTED_FRAME_SIZE 0x414 +/* MPEG_BUFFER_SIZE should be >= AHX_EXPECTED_FRAME_SIZE */ +#define MPEG_BUFFER_SIZE 0x1000 +typedef struct { + uint8_t buffer[MPEG_BUFFER_SIZE]; + int buffer_used; + int buffer_full; + size_t bytes_in_buffer; + mpg123_handle *m; +} mpeg_codec_data; +#endif + +/* with one file this is also used for just + ACM */ +typedef struct { + int file_count; + int current_file; + /* the index we return to upon loop completion */ + int loop_start_file; + /* one after the index of the last file, typically + * will be equal to file_count */ + int loop_end_file; + /* Upon exit from a loop, which file to play. */ + /* -1 if there is no such file */ + /*int end_file;*/ + ACMStream **files; +} mus_acm_codec_data; + +#define AIX_BUFFER_SIZE 0x1000 +/* AIXery */ +typedef struct { + sample buffer[AIX_BUFFER_SIZE]; + int segment_count; + int stream_count; + int current_segment; + /* one per segment */ + int32_t *sample_counts; + /* organized like: + * segment1_stream1, segment1_stream2, segment2_stream1, segment2_stream2*/ + VGMSTREAM **adxs; +} aix_codec_data; + +typedef struct { + int segment_count; + int current_segment; + int loop_segment; + /* one per segment */ + int32_t *sample_counts; + VGMSTREAM **adxs; +} aax_codec_data; + +/* for compressed NWA */ +typedef struct { + NWAData *nwa; +} nwa_codec_data; + +/* do format detection, return pointer to a usable VGMSTREAM, or NULL on failure */ +VGMSTREAM * init_vgmstream(const char * const filename); + +VGMSTREAM * init_vgmstream_from_STREAMFILE(STREAMFILE *streamFile); + +/* reset a VGMSTREAM to start of stream */ +void reset_vgmstream(VGMSTREAM * vgmstream); + +/* allocate a VGMSTREAM and channel stuff */ +VGMSTREAM * allocate_vgmstream(int channel_count, int looped); + +/* deallocate, close, etc. */ +void close_vgmstream(VGMSTREAM * vgmstream); + +/* calculate the number of samples to be played based on looping parameters */ +int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM * vgmstream); + +/* render! */ +void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); + +/* smallest self-contained group of samples is a frame */ +int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream); +/* number of bytes per frame */ +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 get_vgmstream_shortframe_size(VGMSTREAM * vgmstream); + +/* Assume that we have written samples_written into the buffer already, and we have samples_to_do consecutive + * samples ahead of us. Decode those samples into the buffer. */ +void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer); + +/* Assume additionally that we have samples_to_do consecutive samples in "data", + * and this this is for channel number "channel" */ +void decode_vgmstream_mem(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer, uint8_t * data, int channel); + +/* calculate number of consecutive samples to do (taking into account stopping for loop start and end) */ +int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM * vgmstream); + +/* Detect start and save values, also detect end and restore values. Only works on exact sample values. + * Returns 1 if loop was done. */ +int vgmstream_do_loop(VGMSTREAM * vgmstream); + +/* Write a description of the stream into array pointed by desc, + * which must be length bytes long. Will always be null-terminated if length > 0 + */ +void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length); + +/* See if there is a second file which may be the second channel, given + * already opened mono opened_stream which was opened from filename. + * If a suitable file is found, open it and change opened_stream to a + * stereo stream. */ +void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile); + +#endif diff --git a/lib/vgmstream/win32/win32.sln b/lib/vgmstream/win32/win32.sln new file mode 100644 index 0000000000..fee7843cf9 --- /dev/null +++ b/lib/vgmstream/win32/win32.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vgmstream", "win32.vcproj", "{3600E1C5-FECA-468C-83F3-FE467DBE2A66}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3600E1C5-FECA-468C-83F3-FE467DBE2A66}.Debug|Win32.ActiveCfg = Debug|Win32 + {3600E1C5-FECA-468C-83F3-FE467DBE2A66}.Debug|Win32.Build.0 = Debug|Win32 + {3600E1C5-FECA-468C-83F3-FE467DBE2A66}.Release|Win32.ActiveCfg = Release|Win32 + {3600E1C5-FECA-468C-83F3-FE467DBE2A66}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/lib/vgmstream/win32/win32.vcproj b/lib/vgmstream/win32/win32.vcproj new file mode 100644 index 0000000000..53123a9efa --- /dev/null +++ b/lib/vgmstream/win32/win32.vcproj @@ -0,0 +1,1000 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9,00" + Name="libvgmstream_dll" + ProjectGUID="{3600E1C5-FECA-468C-83F3-FE467DBE2A66}" + RootNamespace="libvgmstream_dll" + Keyword="Win32Proj" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\" + IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\" + ConfigurationType="2" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\ext_includes" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;WIN32_EXPORTS;_CRT_SECURE_NO_WARNINGS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="false" + DebugInformationFormat="3" + DisableSpecificWarnings="4267;4018;4244;4312" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile="..\..\..\..\..\system\players\paplayer\vgmstream.dll" + LinkIncremental="1" + IgnoreDefaultLibraryNames="LIBCMTD" + GenerateDebugInformation="true" + ProgramDatabaseFile="win32.pdb" + SubSystem="2" + ProfileGuidedDatabase="" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + ImportLibrary="win32.lib" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\" + IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\" + ConfigurationType="2" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\ext_includes" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN32_EXPORTS;_CRT_SECURE_NO_WARNINGS;_LIB" + RuntimeLibrary="0" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="false" + DebugInformationFormat="3" + DisableSpecificWarnings="4267;4018;4244;4312" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile="..\..\..\..\..\system\players\paplayer\vgmstream.dll" + LinkIncremental="1" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(TargetName).pdb" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + ProfileGuidedDatabase="" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + ImportLibrary="win32.lib" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="coding" + > + <Filter + Name="Header Files" + > + <File + RelativePath="..\src\coding\acm_decoder.h" + > + </File> + <File + RelativePath="..\src\coding\coding.h" + > + </File> + <File + RelativePath="..\src\coding\g72x_state.h" + > + </File> + <File + RelativePath="..\src\coding\nwa_decoder.h" + > + </File> + </Filter> + <Filter + Name="Source Files" + > + <File + RelativePath="..\src\coding\acm_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\adx_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\aica_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\eaxa_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\g721_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\ima_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\l5_555_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\mpeg_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\msadpcm_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\nds_procyon_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\ngc_afc_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\ngc_dsp_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\ngc_dtk_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\nwa_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\ogg_vorbis_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\pcm_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\psx_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\sdx2_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\ws_decoder.c" + > + </File> + <File + RelativePath="..\src\coding\xa_decoder.c" + > + </File> + </Filter> + </Filter> + <Filter + Name="Header Files" + > + <File + RelativePath="..\src\streamfile.h" + > + </File> + <File + RelativePath="..\src\streamtypes.h" + > + </File> + <File + RelativePath="..\src\util.h" + > + </File> + <File + RelativePath="..\src\vgmstream.h" + > + </File> + </Filter> + <Filter + Name="Source Files" + > + <File + RelativePath="..\src\streamfile.c" + > + </File> + <File + RelativePath="..\src\util.c" + > + </File> + <File + RelativePath="..\src\vgmstream.c" + > + </File> + <File + RelativePath="..\XBMCVGM.cpp" + > + </File> + </Filter> + <Filter + Name="meta" + > + <Filter + Name="Header Files" + > + <File + RelativePath="..\src\meta\meta.h" + > + </File> + </Filter> + <Filter + Name="Source Files" + > + <File + RelativePath="..\src\meta\aax.c" + > + </File> + <File + RelativePath="..\src\meta\acm.c" + > + </File> + <File + RelativePath="..\src\meta\adx_header.c" + > + </File> + <File + RelativePath="..\src\meta\afc_header.c" + > + </File> + <File + RelativePath="..\src\meta\agsc.c" + > + </File> + <File + RelativePath="..\src\meta\ahx.c" + > + </File> + <File + RelativePath="..\src\meta\aifc.c" + > + </File> + <File + RelativePath="..\src\meta\aix.c" + > + </File> + <File + RelativePath="..\src\meta\ast.c" + > + </File> + <File + RelativePath="..\src\meta\bgw.c" + > + </File> + <File + RelativePath="..\src\meta\brstm.c" + > + </File> + <File + RelativePath="..\src\meta\capdsp.c" + > + </File> + <File + RelativePath="..\src\meta\Cstr.c" + > + </File> + <File + RelativePath="..\src\meta\dc_asd.c" + > + </File> + <File + RelativePath="..\src\meta\dc_idvi.c" + > + </File> + <File + RelativePath="..\src\meta\dc_kcey.c" + > + </File> + <File + RelativePath="..\src\meta\dc_str.c" + > + </File> + <File + RelativePath="..\src\meta\dc_wav_dcs.c" + > + </File> + <File + RelativePath="..\src\meta\de2.c" + > + </File> + <File + RelativePath="..\src\meta\ea_header.c" + > + </File> + <File + RelativePath="..\src\meta\ea_old.c" + > + </File> + <File + RelativePath="..\src\meta\emff.c" + > + </File> + <File + RelativePath="..\src\meta\fsb.c" + > + </File> + <File + RelativePath="..\src\meta\gca.c" + > + </File> + <File + RelativePath="..\src\meta\gcsw.c" + > + </File> + <File + RelativePath="..\src\meta\genh.c" + > + </File> + <File + RelativePath="..\src\meta\gsp_gsb.c" + > + </File> + <File + RelativePath="..\src\meta\halpst.c" + > + </File> + <File + RelativePath="..\src\meta\idsp.c" + > + </File> + <File + RelativePath="..\src\meta\ish_isd.c" + > + </File> + <File + RelativePath="..\src\meta\ivb.c" + > + </File> + <File + RelativePath="..\src\meta\kraw.c" + > + </File> + <File + RelativePath="..\src\meta\msvp.c" + > + </File> + <File + RelativePath="..\src\meta\mus_acm.c" + > + </File> + <File + RelativePath="..\src\meta\musc.c" + > + </File> + <File + RelativePath="..\src\meta\musx.c" + > + </File> + <File + RelativePath="..\src\meta\naomi_spsd.c" + > + </File> + <File + RelativePath="..\src\meta\nds_sad.c" + > + </File> + <File + RelativePath="..\src\meta\nds_strm.c" + > + </File> + <File + RelativePath="..\src\meta\ngc_adpdtk.c" + > + </File> + <File + RelativePath="..\src\meta\ngc_bh2pcm.c" + > + </File> + <File + RelativePath="..\src\meta\ngc_caf.c" + > + </File> + <File + RelativePath="..\src\meta\ngc_dsp_std.c" + > + </File> + <File + RelativePath="..\src\meta\ngc_ffcc_str.c" + > + </File> + <File + RelativePath="..\src\meta\ngc_iadp.c" + > + </File> + <File + RelativePath="..\src\meta\ngc_pdt.c" + > + </File> + <File + RelativePath="..\src\meta\ngc_ssm.c" + > + </File> + <File + RelativePath="..\src\meta\ngc_tydsp.c" + > + </File> + <File + RelativePath="..\src\meta\ngc_waa_wac_wad_wam.c" + > + </File> + <File + RelativePath="..\src\meta\ngc_ymf.c" + > + </File> + <File + RelativePath="..\src\meta\nwa.c" + > + </File> + <File + RelativePath="..\src\meta\ogg_vorbis_file.c" + > + </File> + <File + RelativePath="..\src\meta\pcm.c" + > + </File> + <File + RelativePath="..\src\meta\pos.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_ads.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_ass.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_aus.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_bg00.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_bmdx.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_ccc.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_dxh.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_enth.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_exst.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_filp.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_gbts.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_hgc1.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_ikm.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_ild.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_int.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_joe.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_kces.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_leg.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_mib.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_mic.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_mihb.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_npsf.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_p2bt.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_pnb.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_psh.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_psw.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_rkv.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_rnd.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_rstm.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_rws.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_rxw.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_seg.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_sfs.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_sl3.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_str.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_svag.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_tec.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_vag.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_vas.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_vpk.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_xa2.c" + > + </File> + <File + RelativePath="..\src\meta\ps2_xa30.c" + > + </File> + <File + RelativePath="..\src\meta\psx_cdxa.c" + > + </File> + <File + RelativePath="..\src\meta\psx_fag.c" + > + </File> + <File + RelativePath="..\src\meta\psx_gms.c" + > + </File> + <File + RelativePath="..\src\meta\raw.c" + > + </File> + <File + RelativePath="..\src\meta\riff.c" + > + </File> + <File + RelativePath="..\src\meta\rs03.c" + > + </File> + <File + RelativePath="..\src\meta\rsd.c" + > + </File> + <File + RelativePath="..\src\meta\rsf.c" + > + </File> + <File + RelativePath="..\src\meta\rwsd.c" + > + </File> + <File + RelativePath="..\src\meta\rwx.c" + > + </File> + <File + RelativePath="..\src\meta\sat_dvi.c" + > + </File> + <File + RelativePath="..\src\meta\sat_sap.c" + > + </File> + <File + RelativePath="..\src\meta\sdt.c" + > + </File> + <File + RelativePath="..\src\meta\sfl.c" + > + </File> + <File + RelativePath="..\src\meta\sli.c" + > + </File> + <File + RelativePath="..\src\meta\spt_spd.c" + > + </File> + <File + RelativePath="..\src\meta\ss_stream.c" + > + </File> + <File + RelativePath="..\src\meta\str_asr.c" + > + </File> + <File + RelativePath="..\src\meta\str_snds.c" + > + </File> + <File + RelativePath="..\src\meta\svs.c" + > + </File> + <File + RelativePath="..\src\meta\thp.c" + > + </File> + <File + RelativePath="..\src\meta\vgs.c" + > + </File> + <File + RelativePath="..\src\meta\vs.c" + > + </File> + <File + RelativePath="..\src\meta\wii_mus.c" + > + </File> + <File + RelativePath="..\src\meta\wii_smp.c" + > + </File> + <File + RelativePath="..\src\meta\wii_sng.c" + > + </File> + <File + RelativePath="..\src\meta\wii_sts.c" + > + </File> + <File + RelativePath="..\src\meta\ws_aud.c" + > + </File> + <File + RelativePath="..\src\meta\xbox_ims.c" + > + </File> + <File + RelativePath="..\src\meta\xbox_stma.c" + > + </File> + <File + RelativePath="..\src\meta\xbox_wavm.c" + > + </File> + <File + RelativePath="..\src\meta\xbox_wvs.c" + > + </File> + <File + RelativePath="..\src\meta\xbox_xmu.c" + > + </File> + <File + RelativePath="..\src\meta\xbox_xvas.c" + > + </File> + <File + RelativePath="..\src\meta\xbox_xwav.c" + > + </File> + <File + RelativePath="..\src\meta\xss.c" + > + </File> + <File + RelativePath="..\src\meta\xwb.c" + > + </File> + <File + RelativePath="..\src\meta\ydsp.c" + > + </File> + <File + RelativePath="..\src\meta\zwdsp.c" + > + </File> + </Filter> + </Filter> + <Filter + Name="layout" + > + <Filter + Name="Header Files" + > + <File + RelativePath="..\src\layout\layout.h" + > + </File> + </Filter> + <Filter + Name="Source Files" + > + <File + RelativePath="..\src\layout\aax_layout.c" + > + </File> + <File + RelativePath="..\src\layout\aix_layout.c" + > + </File> + <File + RelativePath="..\src\layout\ast_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\blocked.c" + > + </File> + <File + RelativePath="..\src\layout\caf_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\de2_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\ea_block.c" + > + </File> + <File + RelativePath="..\src\layout\emff_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\filp_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\gsb_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\halpst_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\ims_block.c" + > + </File> + <File + RelativePath="..\src\layout\interleave.c" + > + </File> + <File + RelativePath="..\src\layout\interleave_byte.c" + > + </File> + <File + RelativePath="..\src\layout\mus_acm_layout.c" + > + </File> + <File + RelativePath="..\src\layout\nolayout.c" + > + </File> + <File + RelativePath="..\src\layout\str_snds_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\thp_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\vs_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\ws_aud_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\wsi_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\xa_blocked.c" + > + </File> + <File + RelativePath="..\src\layout\xvas_block.c" + > + </File> + </Filter> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/lib/vgmstream/win32/win32.vcxproj b/lib/vgmstream/win32/win32.vcxproj new file mode 100644 index 0000000000..4975f6af57 --- /dev/null +++ b/lib/vgmstream/win32/win32.vcxproj @@ -0,0 +1,345 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>libvgmstream_dll</ProjectName> + <ProjectGuid>{3600E1C5-FECA-468C-83F3-FE467DBE2A66}</ProjectGuid> + <RootNamespace>libvgmstream_dll</RootNamespace> + <Keyword>Win32Proj</Keyword> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> + <Import Project="..\..\..\project\VS2010Express\XBMC for Windows.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> + <Import Project="..\..\..\project\VS2010Express\XBMC for Windows.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental> + <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet> + <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" /> + <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" /> + <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet> + <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" /> + <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" /> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">vgmstream</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">vgmstream</TargetName> + <CustomBuildAfterTargets Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Build</CustomBuildAfterTargets> + <CustomBuildAfterTargets Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Build</CustomBuildAfterTargets> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\ext_includes;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;WIN32_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4267;4018;4244;4312;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <Link> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(OutDir)\$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <ProfileGuidedDatabase> + </ProfileGuidedDatabase> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention> + </DataExecutionPrevention> + <ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <IgnoreSpecificDefaultLibraries> + </IgnoreSpecificDefaultLibraries> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + <CustomBuildStep> + <Command>copy /B /Y "$(TargetPath)" "$(SolutionDir)..\..\system\players\paplayer\$(TargetFileName)"</Command> + </CustomBuildStep> + <CustomBuildStep> + <Message>Copy output</Message> + </CustomBuildStep> + <CustomBuildStep> + <Outputs>$(SolutionDir)..\..\system\players\paplayer\$(TargetFileName)</Outputs> + <Inputs>$(TargetPath)</Inputs> + </CustomBuildStep> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <AdditionalIncludeDirectories>..\ext_includes;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN32_EXPORTS;_CRT_SECURE_NO_WARNINGS;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4267;4018;4244;4312;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <Link> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(OutDir)\$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <ProfileGuidedDatabase> + </ProfileGuidedDatabase> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention> + </DataExecutionPrevention> + <ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + <CustomBuildStep> + <Command>copy /B /Y "$(TargetPath)" "$(SolutionDir)..\..\system\players\paplayer\$(TargetFileName)"</Command> + </CustomBuildStep> + <CustomBuildStep> + <Message>Copy output</Message> + </CustomBuildStep> + <CustomBuildStep> + <Outputs>$(SolutionDir)..\..\system\players\paplayer\$(TargetFileName)</Outputs> + <Inputs>$(TargetPath)</Inputs> + </CustomBuildStep> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="..\src\coding\acm_decoder.h" /> + <ClInclude Include="..\src\coding\coding.h" /> + <ClInclude Include="..\src\coding\g72x_state.h" /> + <ClInclude Include="..\src\coding\nwa_decoder.h" /> + <ClInclude Include="..\src\streamfile.h" /> + <ClInclude Include="..\src\streamtypes.h" /> + <ClInclude Include="..\src\util.h" /> + <ClInclude Include="..\src\vgmstream.h" /> + <ClInclude Include="..\src\meta\meta.h" /> + <ClInclude Include="..\src\layout\layout.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\src\coding\acm_decoder.c" /> + <ClCompile Include="..\src\coding\adx_decoder.c" /> + <ClCompile Include="..\src\coding\aica_decoder.c" /> + <ClCompile Include="..\src\coding\eaxa_decoder.c" /> + <ClCompile Include="..\src\coding\g721_decoder.c" /> + <ClCompile Include="..\src\coding\ima_decoder.c" /> + <ClCompile Include="..\src\coding\l5_555_decoder.c" /> + <ClCompile Include="..\src\coding\mpeg_decoder.c" /> + <ClCompile Include="..\src\coding\msadpcm_decoder.c" /> + <ClCompile Include="..\src\coding\nds_procyon_decoder.c" /> + <ClCompile Include="..\src\coding\ngc_afc_decoder.c" /> + <ClCompile Include="..\src\coding\ngc_dsp_decoder.c" /> + <ClCompile Include="..\src\coding\ngc_dtk_decoder.c" /> + <ClCompile Include="..\src\coding\nwa_decoder.c" /> + <ClCompile Include="..\src\coding\ogg_vorbis_decoder.c" /> + <ClCompile Include="..\src\coding\pcm_decoder.c" /> + <ClCompile Include="..\src\coding\psx_decoder.c" /> + <ClCompile Include="..\src\coding\sdx2_decoder.c" /> + <ClCompile Include="..\src\coding\ws_decoder.c" /> + <ClCompile Include="..\src\coding\xa_decoder.c" /> + <ClCompile Include="..\src\streamfile.c" /> + <ClCompile Include="..\src\util.c" /> + <ClCompile Include="..\src\vgmstream.c" /> + <ClCompile Include="..\XBMCVGM.cpp" /> + <ClCompile Include="..\src\meta\aax.c" /> + <ClCompile Include="..\src\meta\acm.c" /> + <ClCompile Include="..\src\meta\adx_header.c" /> + <ClCompile Include="..\src\meta\afc_header.c" /> + <ClCompile Include="..\src\meta\agsc.c" /> + <ClCompile Include="..\src\meta\ahx.c" /> + <ClCompile Include="..\src\meta\aifc.c" /> + <ClCompile Include="..\src\meta\aix.c" /> + <ClCompile Include="..\src\meta\ast.c" /> + <ClCompile Include="..\src\meta\bgw.c" /> + <ClCompile Include="..\src\meta\brstm.c" /> + <ClCompile Include="..\src\meta\capdsp.c" /> + <ClCompile Include="..\src\meta\Cstr.c" /> + <ClCompile Include="..\src\meta\dc_asd.c" /> + <ClCompile Include="..\src\meta\dc_idvi.c" /> + <ClCompile Include="..\src\meta\dc_kcey.c" /> + <ClCompile Include="..\src\meta\dc_str.c" /> + <ClCompile Include="..\src\meta\dc_wav_dcs.c" /> + <ClCompile Include="..\src\meta\de2.c" /> + <ClCompile Include="..\src\meta\ea_header.c" /> + <ClCompile Include="..\src\meta\ea_old.c" /> + <ClCompile Include="..\src\meta\emff.c" /> + <ClCompile Include="..\src\meta\fsb.c" /> + <ClCompile Include="..\src\meta\gca.c" /> + <ClCompile Include="..\src\meta\gcsw.c" /> + <ClCompile Include="..\src\meta\genh.c" /> + <ClCompile Include="..\src\meta\gsp_gsb.c" /> + <ClCompile Include="..\src\meta\halpst.c" /> + <ClCompile Include="..\src\meta\idsp.c" /> + <ClCompile Include="..\src\meta\ish_isd.c" /> + <ClCompile Include="..\src\meta\ivb.c" /> + <ClCompile Include="..\src\meta\kraw.c" /> + <ClCompile Include="..\src\meta\msvp.c" /> + <ClCompile Include="..\src\meta\mus_acm.c" /> + <ClCompile Include="..\src\meta\musc.c" /> + <ClCompile Include="..\src\meta\musx.c" /> + <ClCompile Include="..\src\meta\naomi_spsd.c" /> + <ClCompile Include="..\src\meta\nds_sad.c" /> + <ClCompile Include="..\src\meta\nds_strm.c" /> + <ClCompile Include="..\src\meta\ngc_adpdtk.c" /> + <ClCompile Include="..\src\meta\ngc_bh2pcm.c" /> + <ClCompile Include="..\src\meta\ngc_caf.c" /> + <ClCompile Include="..\src\meta\ngc_dsp_std.c" /> + <ClCompile Include="..\src\meta\ngc_ffcc_str.c" /> + <ClCompile Include="..\src\meta\ngc_iadp.c" /> + <ClCompile Include="..\src\meta\ngc_pdt.c" /> + <ClCompile Include="..\src\meta\ngc_ssm.c" /> + <ClCompile Include="..\src\meta\ngc_tydsp.c" /> + <ClCompile Include="..\src\meta\ngc_waa_wac_wad_wam.c" /> + <ClCompile Include="..\src\meta\ngc_ymf.c" /> + <ClCompile Include="..\src\meta\nwa.c" /> + <ClCompile Include="..\src\meta\ogg_vorbis_file.c" /> + <ClCompile Include="..\src\meta\pcm.c" /> + <ClCompile Include="..\src\meta\pos.c" /> + <ClCompile Include="..\src\meta\ps2_ads.c" /> + <ClCompile Include="..\src\meta\ps2_ass.c" /> + <ClCompile Include="..\src\meta\ps2_aus.c" /> + <ClCompile Include="..\src\meta\ps2_bg00.c" /> + <ClCompile Include="..\src\meta\ps2_bmdx.c" /> + <ClCompile Include="..\src\meta\ps2_ccc.c" /> + <ClCompile Include="..\src\meta\ps2_dxh.c" /> + <ClCompile Include="..\src\meta\ps2_enth.c" /> + <ClCompile Include="..\src\meta\ps2_exst.c" /> + <ClCompile Include="..\src\meta\ps2_filp.c" /> + <ClCompile Include="..\src\meta\ps2_gbts.c" /> + <ClCompile Include="..\src\meta\ps2_hgc1.c" /> + <ClCompile Include="..\src\meta\ps2_ikm.c" /> + <ClCompile Include="..\src\meta\ps2_ild.c" /> + <ClCompile Include="..\src\meta\ps2_int.c" /> + <ClCompile Include="..\src\meta\ps2_joe.c" /> + <ClCompile Include="..\src\meta\ps2_kces.c" /> + <ClCompile Include="..\src\meta\ps2_leg.c" /> + <ClCompile Include="..\src\meta\ps2_mib.c" /> + <ClCompile Include="..\src\meta\ps2_mic.c" /> + <ClCompile Include="..\src\meta\ps2_mihb.c" /> + <ClCompile Include="..\src\meta\ps2_npsf.c" /> + <ClCompile Include="..\src\meta\ps2_p2bt.c" /> + <ClCompile Include="..\src\meta\ps2_pnb.c" /> + <ClCompile Include="..\src\meta\ps2_psh.c" /> + <ClCompile Include="..\src\meta\ps2_psw.c" /> + <ClCompile Include="..\src\meta\ps2_rkv.c" /> + <ClCompile Include="..\src\meta\ps2_rnd.c" /> + <ClCompile Include="..\src\meta\ps2_rstm.c" /> + <ClCompile Include="..\src\meta\ps2_rws.c" /> + <ClCompile Include="..\src\meta\ps2_rxw.c" /> + <ClCompile Include="..\src\meta\ps2_seg.c" /> + <ClCompile Include="..\src\meta\ps2_sfs.c" /> + <ClCompile Include="..\src\meta\ps2_sl3.c" /> + <ClCompile Include="..\src\meta\ps2_str.c" /> + <ClCompile Include="..\src\meta\ps2_svag.c" /> + <ClCompile Include="..\src\meta\ps2_tec.c" /> + <ClCompile Include="..\src\meta\ps2_vag.c" /> + <ClCompile Include="..\src\meta\ps2_vas.c" /> + <ClCompile Include="..\src\meta\ps2_vpk.c" /> + <ClCompile Include="..\src\meta\ps2_xa2.c" /> + <ClCompile Include="..\src\meta\ps2_xa30.c" /> + <ClCompile Include="..\src\meta\psx_cdxa.c" /> + <ClCompile Include="..\src\meta\psx_fag.c" /> + <ClCompile Include="..\src\meta\psx_gms.c" /> + <ClCompile Include="..\src\meta\raw.c" /> + <ClCompile Include="..\src\meta\riff.c" /> + <ClCompile Include="..\src\meta\rs03.c" /> + <ClCompile Include="..\src\meta\rsd.c" /> + <ClCompile Include="..\src\meta\rsf.c" /> + <ClCompile Include="..\src\meta\rwsd.c" /> + <ClCompile Include="..\src\meta\rwx.c" /> + <ClCompile Include="..\src\meta\sat_dvi.c" /> + <ClCompile Include="..\src\meta\sat_sap.c" /> + <ClCompile Include="..\src\meta\sdt.c" /> + <ClCompile Include="..\src\meta\sfl.c" /> + <ClCompile Include="..\src\meta\sli.c" /> + <ClCompile Include="..\src\meta\spt_spd.c" /> + <ClCompile Include="..\src\meta\ss_stream.c" /> + <ClCompile Include="..\src\meta\str_asr.c" /> + <ClCompile Include="..\src\meta\str_snds.c" /> + <ClCompile Include="..\src\meta\svs.c" /> + <ClCompile Include="..\src\meta\thp.c" /> + <ClCompile Include="..\src\meta\vgs.c" /> + <ClCompile Include="..\src\meta\vs.c" /> + <ClCompile Include="..\src\meta\wii_mus.c" /> + <ClCompile Include="..\src\meta\wii_smp.c" /> + <ClCompile Include="..\src\meta\wii_sng.c" /> + <ClCompile Include="..\src\meta\wii_sts.c" /> + <ClCompile Include="..\src\meta\ws_aud.c" /> + <ClCompile Include="..\src\meta\xbox_ims.c" /> + <ClCompile Include="..\src\meta\xbox_stma.c" /> + <ClCompile Include="..\src\meta\xbox_wavm.c" /> + <ClCompile Include="..\src\meta\xbox_wvs.c" /> + <ClCompile Include="..\src\meta\xbox_xmu.c" /> + <ClCompile Include="..\src\meta\xbox_xvas.c" /> + <ClCompile Include="..\src\meta\xbox_xwav.c" /> + <ClCompile Include="..\src\meta\xss.c" /> + <ClCompile Include="..\src\meta\xwb.c" /> + <ClCompile Include="..\src\meta\ydsp.c" /> + <ClCompile Include="..\src\meta\zwdsp.c" /> + <ClCompile Include="..\src\layout\aax_layout.c" /> + <ClCompile Include="..\src\layout\aix_layout.c" /> + <ClCompile Include="..\src\layout\ast_blocked.c" /> + <ClCompile Include="..\src\layout\blocked.c" /> + <ClCompile Include="..\src\layout\caf_blocked.c" /> + <ClCompile Include="..\src\layout\de2_blocked.c" /> + <ClCompile Include="..\src\layout\ea_block.c" /> + <ClCompile Include="..\src\layout\emff_blocked.c" /> + <ClCompile Include="..\src\layout\filp_blocked.c" /> + <ClCompile Include="..\src\layout\gsb_blocked.c" /> + <ClCompile Include="..\src\layout\halpst_blocked.c" /> + <ClCompile Include="..\src\layout\ims_block.c" /> + <ClCompile Include="..\src\layout\interleave.c" /> + <ClCompile Include="..\src\layout\interleave_byte.c" /> + <ClCompile Include="..\src\layout\mus_acm_layout.c" /> + <ClCompile Include="..\src\layout\nolayout.c" /> + <ClCompile Include="..\src\layout\str_snds_blocked.c" /> + <ClCompile Include="..\src\layout\thp_blocked.c" /> + <ClCompile Include="..\src\layout\vs_blocked.c" /> + <ClCompile Include="..\src\layout\ws_aud_blocked.c" /> + <ClCompile Include="..\src\layout\wsi_blocked.c" /> + <ClCompile Include="..\src\layout\xa_blocked.c" /> + <ClCompile Include="..\src\layout\xvas_block.c" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/lib/vgmstream/win32/win32.vcxproj.filters b/lib/vgmstream/win32/win32.vcxproj.filters new file mode 100644 index 0000000000..2fe00ebfcd --- /dev/null +++ b/lib/vgmstream/win32/win32.vcxproj.filters @@ -0,0 +1,612 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="coding"> + <UniqueIdentifier>{732b002c-1974-4554-9ef6-8333f62f4e77}</UniqueIdentifier> + </Filter> + <Filter Include="coding\Header Files"> + <UniqueIdentifier>{f50aab92-7740-403b-847e-5d05d8f8890e}</UniqueIdentifier> + </Filter> + <Filter Include="coding\Source Files"> + <UniqueIdentifier>{bc913f6c-2310-43f9-9aed-1c48c0506489}</UniqueIdentifier> + </Filter> + <Filter Include="meta"> + <UniqueIdentifier>{eb1ead8a-54be-4d36-be29-dae1f2a8341e}</UniqueIdentifier> + </Filter> + <Filter Include="meta\Header Files"> + <UniqueIdentifier>{df36a847-cf51-485b-81a7-1e0754cd5f69}</UniqueIdentifier> + </Filter> + <Filter Include="meta\Source Files"> + <UniqueIdentifier>{0b740a87-d188-4d5e-b2b5-701ec24abc39}</UniqueIdentifier> + </Filter> + <Filter Include="layout"> + <UniqueIdentifier>{994cb7da-a1a3-4bb1-90e8-819e45bb1289}</UniqueIdentifier> + </Filter> + <Filter Include="layout\Header Files"> + <UniqueIdentifier>{48ce4671-a794-4aab-9733-96ee67961247}</UniqueIdentifier> + </Filter> + <Filter Include="layout\Source Files"> + <UniqueIdentifier>{959bbe75-3072-4008-b0d4-7d819b32add0}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\src\coding\acm_decoder.h"> + <Filter>coding\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\src\coding\coding.h"> + <Filter>coding\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\src\coding\g72x_state.h"> + <Filter>coding\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\src\coding\nwa_decoder.h"> + <Filter>coding\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\src\streamfile.h"> + <Filter>coding\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\src\streamtypes.h"> + <Filter>coding\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\src\util.h"> + <Filter>coding\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\src\vgmstream.h"> + <Filter>coding\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\src\meta\meta.h"> + <Filter>meta\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\src\layout\layout.h"> + <Filter>layout\Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\src\coding\acm_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\adx_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\aica_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\eaxa_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\g721_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\ima_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\l5_555_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\mpeg_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\msadpcm_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\nds_procyon_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\ngc_afc_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\ngc_dsp_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\ngc_dtk_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\nwa_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\ogg_vorbis_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\pcm_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\psx_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\sdx2_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\ws_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coding\xa_decoder.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\streamfile.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\util.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vgmstream.c"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\XBMCVGM.cpp"> + <Filter>coding\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\aax.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\acm.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\adx_header.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\afc_header.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\agsc.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ahx.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\aifc.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\aix.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ast.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\bgw.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\brstm.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\capdsp.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\Cstr.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\dc_asd.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\dc_idvi.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\dc_kcey.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\dc_str.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\dc_wav_dcs.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\de2.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ea_header.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ea_old.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\emff.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\fsb.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\gca.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\gcsw.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\genh.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\gsp_gsb.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\halpst.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\idsp.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ish_isd.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ivb.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\kraw.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\msvp.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\mus_acm.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\musc.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\musx.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\naomi_spsd.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\nds_sad.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\nds_strm.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ngc_adpdtk.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ngc_bh2pcm.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ngc_caf.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ngc_dsp_std.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ngc_ffcc_str.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ngc_iadp.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ngc_pdt.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ngc_ssm.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ngc_tydsp.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ngc_waa_wac_wad_wam.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ngc_ymf.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\nwa.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ogg_vorbis_file.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\pcm.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\pos.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_ads.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_ass.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_aus.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_bg00.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_bmdx.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_ccc.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_dxh.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_enth.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_exst.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_filp.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_gbts.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_hgc1.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_ikm.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_ild.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_int.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_joe.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_kces.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_leg.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_mib.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_mic.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_mihb.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_npsf.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_p2bt.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_pnb.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_psh.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_psw.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_rkv.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_rnd.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_rstm.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_rws.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_rxw.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_seg.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_sfs.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_sl3.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_str.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_svag.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_tec.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_vag.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_vas.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_vpk.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_xa2.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ps2_xa30.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\psx_cdxa.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\psx_fag.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\psx_gms.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\raw.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\riff.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\rs03.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\rsd.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\rsf.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\rwsd.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\rwx.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\sat_dvi.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\sat_sap.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\sdt.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\sfl.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\sli.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\spt_spd.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ss_stream.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\str_asr.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\str_snds.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\svs.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\thp.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\vgs.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\vs.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\wii_mus.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\wii_smp.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\wii_sng.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\wii_sts.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ws_aud.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\xbox_ims.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\xbox_stma.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\xbox_wavm.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\xbox_wvs.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\xbox_xmu.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\xbox_xvas.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\xbox_xwav.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\xss.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\xwb.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\ydsp.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\meta\zwdsp.c"> + <Filter>meta\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\aax_layout.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\aix_layout.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\ast_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\caf_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\de2_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\ea_block.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\emff_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\filp_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\gsb_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\halpst_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\ims_block.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\interleave.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\interleave_byte.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\mus_acm_layout.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\nolayout.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\str_snds_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\thp_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\vs_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\ws_aud_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\wsi_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\xa_blocked.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\layout\xvas_block.c"> + <Filter>layout\Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file |