Compare commits

..

7 commits

Author SHA1 Message Date
Christopher Snowhill
4b0f4a43fd minimp3: Fix seeking behavior
Some checks are pending
Check if Cog buildable / Build Universal Cog.app (push) Waiting to run
Seeking should clear the sample buffer if it contains anything, and non-
seekable files should return an error on an attempt to seek.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 16:18:44 -07:00
Christopher Snowhill
b67b2acd6a VGMStream: Update associated filename extensions
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 16:18:39 -07:00
Christopher Snowhill
90c5833fe9 VGMStream: Considerably rewrite plugin interface
It was about time to rewrite this anyway. Now adapted to the new public
interface API.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 16:18:35 -07:00
Christopher Snowhill
8b3a165d9a Bug Fix: Fixed several code signing issues
There were several issues which broke debug and possibly release
signing, and broke VGMStream in debug situations. Not sure if it was
also broken in release.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 16:18:29 -07:00
Christopher Snowhill
cbaacd35b1 VGMStream: Updated libvgmstream code base
Updated VGMStream to r1980-181-g10093db5

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 16:18:25 -07:00
Christopher Snowhill
9b683a9c56 Bug Fix: Reorder LPC scratch memory for alignment
The double members should be ordered first so they are aligned to an 8
byte boundary. The rest are fine as-is.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 00:05:19 -07:00
Christopher Snowhill
7ff653b48f MP3: Replace MAD with minimp3
libMAD had memory safety issues, possibly with corrupt files. Hopefully,
this will fix the problem.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 00:05:11 -07:00
131 changed files with 15922 additions and 6967 deletions

View file

@ -155,12 +155,13 @@ void lpc_extrapolate2(float *const data, const size_t data_len, const int nch, c
*extrapolate_buffer_size = new_size;
}
float *tdata = (float *)(*extrapolate_buffer); // for 1 channel only
double *aut = (double *)(*extrapolate_buffer);
double *lpc = (double *)(*extrapolate_buffer + aut_size);
double *aut = (double *)(*extrapolate_buffer + tdata_size);
double *lpc = (double *)(*extrapolate_buffer + tdata_size + aut_size);
float *lpci = (float *)(*extrapolate_buffer + tdata_size + aut_size + lpc_size);
float *work = (float *)(*extrapolate_buffer + tdata_size + aut_size + lpc_size + lpci_size);
float *tdata = (float *)(*extrapolate_buffer + aut_size + lpc_size); // for 1 channel only
float *lpci = (float *)(*extrapolate_buffer + aut_size + lpc_size + tdata_size);
float *work = (float *)(*extrapolate_buffer + aut_size + lpc_size + tdata_size + lpci_size);
for(int c = 0; c < nch; c++) {
if(extra_bkwd) {

View file

@ -136,7 +136,6 @@
836FB5A718206F2500B3AD2D /* Hively.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 836FB5471820538800B3AD2D /* Hively.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
8370D73D277419F700245CE0 /* SQLiteStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 8370D73C277419F700245CE0 /* SQLiteStore.m */; };
8370D73F2775AE1300245CE0 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8370D73E2775AE1300245CE0 /* libsqlite3.tbd */; };
8372C93D27C7895300E250C9 /* MAD.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8372C93027C785BE00E250C9 /* MAD.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
8377C66327B8CF6300E8BC0F /* SpectrumViewSK.m in Sources */ = {isa = PBXBuildFile; fileRef = 8377C66127B8CF6300E8BC0F /* SpectrumViewSK.m */; };
8377C6B927B900F000E8BC0F /* SpectrumItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 8377C6B827B900F000E8BC0F /* SpectrumItem.m */; };
837DC92B285B05710005C58A /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 837DC92A285B05710005C58A /* CoreData.framework */; };
@ -170,6 +169,7 @@
83B61E2429A8296500CD0580 /* LyricsWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83B61E2229A8296500CD0580 /* LyricsWindow.xib */; };
83B61E2829A82A0200CD0580 /* LyricsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83B61E2729A82A0200CD0580 /* LyricsWindowController.m */; };
83B72E3B279045B7006007A3 /* libfdk-aac.2.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83B72E2A279044F6006007A3 /* libfdk-aac.2.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
83B73B652D8FD75A00A57F08 /* minimp3.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83B73B602D8FC05A00A57F08 /* minimp3.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
83BC5AB220E4C87100631CD4 /* DualWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BC5AB020E4C87100631CD4 /* DualWindow.m */; };
83BC5ABF20E4CE7A00631CD4 /* InfoInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17D1B0D00F6320EA00694C57 /* InfoInspector.xib */; };
83BC5AC020E4CE7D00631CD4 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17342A980D5FD20B00E8D854 /* MainMenu.xib */; };
@ -511,20 +511,6 @@
remoteGlobalIDString = 836FB52C1820538700B3AD2D;
remoteInfo = Hively;
};
8372C92F27C785BE00E250C9 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 8372C92A27C785BD00E250C9 /* MAD.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 8372C92327C785BD00E250C9;
remoteInfo = MAD;
};
8372C93B27C7893100E250C9 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 8372C92A27C785BD00E250C9 /* MAD.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 8372C92227C785BD00E250C9;
remoteInfo = MAD;
};
8375B36117FFEF010092A79F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 8359FF2C17FEF35C0060F3ED /* ArchiveSource.xcodeproj */;
@ -546,6 +532,20 @@
remoteGlobalIDString = 83B06686180D5668008E3612;
remoteInfo = MIDI;
};
83B73B5F2D8FC05A00A57F08 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 8372C92A27C785BD00E250C9 /* minimp3.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 8372C92327C785BD00E250C9;
remoteInfo = minimp3;
};
83B73B632D8FD74000A57F08 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 8372C92A27C785BD00E250C9 /* minimp3.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 8372C92227C785BD00E250C9;
remoteInfo = minimp3;
};
83BB13C120E4E38E00723731 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 836F6B2518BDB80D0095E648 /* vgmstream.xcodeproj */;
@ -678,8 +678,8 @@
dstPath = "";
dstSubfolderSpec = 13;
files = (
83B73B652D8FD75A00A57F08 /* minimp3.bundle in CopyFiles */,
8327DBA9293CAD2400CD0580 /* Organya.bundle in CopyFiles */,
8372C93D27C7895300E250C9 /* MAD.bundle in CopyFiles */,
83489C6B2782F78700BDCEA2 /* libvgmPlayer.bundle in CopyFiles */,
834D794020E4EFEF00C4A5CC /* VorbisPlugin.bundle in CopyFiles */,
834D793F20E4EFEA00C4A5CC /* OpusPlugin.bundle in CopyFiles */,
@ -955,7 +955,7 @@
8370D739277419D200245CE0 /* SQLiteStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQLiteStore.h; sourceTree = "<group>"; };
8370D73C277419F700245CE0 /* SQLiteStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SQLiteStore.m; sourceTree = "<group>"; };
8370D73E2775AE1300245CE0 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
8372C92A27C785BD00E250C9 /* MAD.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MAD.xcodeproj; path = Plugins/MAD/MAD.xcodeproj; sourceTree = "<group>"; };
8372C92A27C785BD00E250C9 /* minimp3.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = minimp3.xcodeproj; path = Plugins/minimp3/minimp3.xcodeproj; sourceTree = "<group>"; };
8375B05117FFEA400092A79F /* OpusPlugin.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OpusPlugin.xcodeproj; path = Plugins/Opus/OpusPlugin.xcodeproj; sourceTree = "<group>"; };
8377C66127B8CF6300E8BC0F /* SpectrumViewSK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SpectrumViewSK.m; path = Visualization/SpectrumViewSK.m; sourceTree = "<group>"; };
8377C66227B8CF6300E8BC0F /* SpectrumViewSK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SpectrumViewSK.h; path = Visualization/SpectrumViewSK.h; sourceTree = "<group>"; };
@ -1270,7 +1270,7 @@
17C808830C3BD181005707C4 /* HTTPSource.xcodeproj */,
83489C4E2782F2DF00BDCEA2 /* libvgmPlayer.xcodeproj */,
8E8D40820CBB036600135C1B /* M3u.xcodeproj */,
8372C92A27C785BD00E250C9 /* MAD.xcodeproj */,
8372C92A27C785BD00E250C9 /* minimp3.xcodeproj */,
83B0669C180D5668008E3612 /* MIDI.xcodeproj */,
17C8089E0C3BD1AB005707C4 /* Musepack.xcodeproj */,
83E5EFAC1FFEF78100659F0F /* OpenMPT.xcodeproj */,
@ -1773,14 +1773,6 @@
name = Products;
sourceTree = "<group>";
};
8372C92B27C785BD00E250C9 /* Products */ = {
isa = PBXGroup;
children = (
8372C93027C785BE00E250C9 /* MAD.bundle */,
);
name = Products;
sourceTree = "<group>";
};
8377C66027B8CF2300E8BC0F /* Visualization */ = {
isa = PBXGroup;
children = (
@ -1824,6 +1816,14 @@
path = LyricsWindow;
sourceTree = "<group>";
};
83B73B5C2D8FC05A00A57F08 /* Products */ = {
isa = PBXGroup;
children = (
83B73B602D8FC05A00A57F08 /* minimp3.bundle */,
);
name = Products;
sourceTree = "<group>";
};
83BB13AE20E4E38E00723731 /* Products */ = {
isa = PBXGroup;
children = (
@ -1984,8 +1984,8 @@
buildRules = (
);
dependencies = (
83B73B642D8FD74000A57F08 /* PBXTargetDependency */,
8327DBA8293CAD0A00CD0580 /* PBXTargetDependency */,
8372C93C27C7893100E250C9 /* PBXTargetDependency */,
83489C6A2782F76900BDCEA2 /* PBXTargetDependency */,
ED69CBC625BE32B40090B90D /* PBXTargetDependency */,
834D793E20E4EFD200C4A5CC /* PBXTargetDependency */,
@ -2130,10 +2130,6 @@
ProductGroup = 8E8D40830CBB036600135C1B /* Products */;
ProjectRef = 8E8D40820CBB036600135C1B /* M3u.xcodeproj */;
},
{
ProductGroup = 8372C92B27C785BD00E250C9 /* Products */;
ProjectRef = 8372C92A27C785BD00E250C9 /* MAD.xcodeproj */;
},
{
ProductGroup = ED69CBB925BE328C0090B90D /* Products */;
ProjectRef = ED69CBB825BE328C0090B90D /* MASShortcut.xcodeproj */;
@ -2142,6 +2138,10 @@
ProductGroup = 83B0669D180D5668008E3612 /* Products */;
ProjectRef = 83B0669C180D5668008E3612 /* MIDI.xcodeproj */;
},
{
ProductGroup = 83B73B5C2D8FC05A00A57F08 /* Products */;
ProjectRef = 8372C92A27C785BD00E250C9 /* minimp3.xcodeproj */;
},
{
ProductGroup = 17C8089F0C3BD1AB005707C4 /* Products */;
ProjectRef = 17C8089E0C3BD1AB005707C4 /* Musepack.xcodeproj */;
@ -2357,13 +2357,6 @@
remoteRef = 836FB5461820538800B3AD2D /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
8372C93027C785BE00E250C9 /* MAD.bundle */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = MAD.bundle;
remoteRef = 8372C92F27C785BE00E250C9 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
83B066A1180D5669008E3612 /* MIDI.bundle */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
@ -2371,6 +2364,13 @@
remoteRef = 83B066A0180D5669008E3612 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
83B73B602D8FC05A00A57F08 /* minimp3.bundle */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = minimp3.bundle;
remoteRef = 83B73B5F2D8FC05A00A57F08 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
83BB13C220E4E38E00723731 /* vgmstream.bundle */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
@ -2748,11 +2748,6 @@
name = Hively;
targetProxy = 836FB5A518206F1500B3AD2D /* PBXContainerItemProxy */;
};
8372C93C27C7893100E250C9 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = MAD;
targetProxy = 8372C93B27C7893100E250C9 /* PBXContainerItemProxy */;
};
8375B36217FFEF010092A79F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = ArchiveSource;
@ -2763,6 +2758,11 @@
name = MIDI;
targetProxy = 83B06702180D5776008E3612 /* PBXContainerItemProxy */;
};
83B73B642D8FD74000A57F08 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = minimp3;
targetProxy = 83B73B632D8FD74000A57F08 /* PBXContainerItemProxy */;
};
83BCB8D917FC96F800760340 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = HighlyComplete;

View file

@ -232,12 +232,6 @@
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1620;
ORGANIZATIONNAME = "Christopher Snowhill";
TargetAttributes = {
83D7311B1A74968900CA1366 = {
DevelopmentTeam = "";
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 83D731161A74968900CA1366 /* Build configuration list for PBXProject "g719" */;
compatibilityVersion = "Xcode 3.2";
@ -422,9 +416,11 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@loader_path/Frameworks";
@ -449,6 +445,7 @@
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11";
PRODUCT_BUNDLE_IDENTIFIER = "org.cogx.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
};
name = Debug;
@ -457,9 +454,11 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@loader_path/Frameworks";
@ -481,6 +480,7 @@
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11";
PRODUCT_BUNDLE_IDENTIFIER = "org.cogx.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
};
name = Release;

View file

@ -376,7 +376,7 @@
835FC6B923F61BF0006960FA /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = YES;
@ -402,7 +402,7 @@
835FC6BA23F61BF0006960FA /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = YES;

View file

@ -550,9 +550,10 @@
83D6762926539A7100252130 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@loader_path/Frameworks";
@ -561,6 +562,7 @@
LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "net.kode54.libcelt-0061";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
};
name = Debug;
@ -568,9 +570,10 @@
83D6762A26539A7100252130 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@loader_path/Frameworks";
@ -579,6 +582,7 @@
LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "net.kode54.libcelt-0061";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
};
name = Release;

View file

@ -538,9 +538,10 @@
83D676B726539F4E00252130 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@loader_path/Frameworks";
@ -549,6 +550,7 @@
LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "net.kode54.libcelt-0110";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
};
name = Debug;
@ -556,9 +558,10 @@
83D676B826539F4E00252130 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@loader_path/Frameworks";
@ -567,6 +570,7 @@
LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "net.kode54.libcelt-0110";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
};
name = Release;

View file

@ -139,7 +139,7 @@
832BF81C21E0514B006F50F1 /* xpcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80A21E05148006F50F1 /* xpcm.c */; };
832BF81D21E0514B006F50F1 /* msf_tamasoft.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80B21E05148006F50F1 /* msf_tamasoft.c */; };
832BF81E21E0514B006F50F1 /* xps.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80C21E05148006F50F1 /* xps.c */; };
832BF81F21E0514B006F50F1 /* ps2_va3.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80D21E05148006F50F1 /* ps2_va3.c */; };
832BF81F21E0514B006F50F1 /* va3.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80D21E05148006F50F1 /* va3.c */; };
832BF82021E0514B006F50F1 /* zsnd_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BF80E21E05149006F50F1 /* zsnd_streamfile.h */; };
832BF82121E0514B006F50F1 /* zsnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80F21E05149006F50F1 /* zsnd.c */; };
832BF82221E0514B006F50F1 /* vs_str.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF81021E05149006F50F1 /* vs_str.c */; };
@ -251,7 +251,6 @@
834F7DB02C7093EA003AC386 /* circus_vq_lib.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D422C7093EA003AC386 /* circus_vq_lib.h */; };
834F7DB12C7093EA003AC386 /* circus_vq_lzxpcm.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D432C7093EA003AC386 /* circus_vq_lzxpcm.h */; };
834F7DB22C7093EA003AC386 /* circus_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D442C7093EA003AC386 /* circus_decoder.c */; };
834F7DB32C7093EA003AC386 /* coding_utils_samples.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D452C7093EA003AC386 /* coding_utils_samples.h */; };
834F7DB42C7093EA003AC386 /* coding_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D462C7093EA003AC386 /* coding_utils.c */; };
834F7DB52C7093EA003AC386 /* coding.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D472C7093EA003AC386 /* coding.h */; };
834F7DB62C7093EA003AC386 /* compresswave_lib.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D482C7093EA003AC386 /* compresswave_lib.c */; };
@ -326,8 +325,6 @@
834F7DFD2C7093EA003AC386 /* tgcadpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D8F2C7093EA003AC386 /* tgcadpcm_decoder.c */; };
834F7DFE2C7093EA003AC386 /* ubi_adpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D902C7093EA003AC386 /* ubi_adpcm_decoder.c */; };
834F7DFF2C7093EA003AC386 /* vadpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D912C7093EA003AC386 /* vadpcm_decoder.c */; };
834F7E002C7093EA003AC386 /* vorbis_custom_data_fsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D922C7093EA003AC386 /* vorbis_custom_data_fsb.h */; };
834F7E012C7093EA003AC386 /* vorbis_custom_data_wwise.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D932C7093EA003AC386 /* vorbis_custom_data_wwise.h */; };
834F7E022C7093EA003AC386 /* vorbis_custom_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D942C7093EA003AC386 /* vorbis_custom_decoder.c */; };
834F7E032C7093EA003AC386 /* vorbis_custom_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D952C7093EA003AC386 /* vorbis_custom_decoder.h */; };
834F7E042C7093EA003AC386 /* vorbis_custom_utils_awc.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D962C7093EA003AC386 /* vorbis_custom_utils_awc.c */; };
@ -443,8 +440,8 @@
834FE10F215C79ED000A5D3D /* sdf.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E6215C79EC000A5D3D /* sdf.c */; };
834FE110215C79ED000A5D3D /* msv.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E7215C79EC000A5D3D /* msv.c */; };
834FE111215C79ED000A5D3D /* ck.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E8215C79EC000A5D3D /* ck.c */; };
835096F22C9979DD00163D93 /* libvgmstream.h in Headers */ = {isa = PBXBuildFile; fileRef = 835096F02C9979DD00163D93 /* libvgmstream.h */; };
835096F32C9979DD00163D93 /* libvgmstream_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 835096F12C9979DD00163D93 /* libvgmstream_streamfile.h */; };
835096F22C9979DD00163D93 /* libvgmstream.h in Headers */ = {isa = PBXBuildFile; fileRef = 835096F02C9979DD00163D93 /* libvgmstream.h */; settings = {ATTRIBUTES = (Public, ); }; };
835096F32C9979DD00163D93 /* libvgmstream_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 835096F12C9979DD00163D93 /* libvgmstream_streamfile.h */; settings = {ATTRIBUTES = (Public, ); }; };
8350C0551E071881009E0A93 /* xma.c in Sources */ = {isa = PBXBuildFile; fileRef = 8350C0541E071881009E0A93 /* xma.c */; };
8351F32D2212B57000A606E4 /* 208.c in Sources */ = {isa = PBXBuildFile; fileRef = 8351F32A2212B57000A606E4 /* 208.c */; };
8351F32E2212B57000A606E4 /* ubi_bao_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8351F32B2212B57000A606E4 /* ubi_bao_streamfile.h */; };
@ -557,14 +554,13 @@
836F6FD518BDC2190095E648 /* lp_ap_lep.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9918BDC2180095E648 /* lp_ap_lep.c */; };
836F6FD718BDC2190095E648 /* filp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9B18BDC2180095E648 /* filp.c */; };
836F6FD818BDC2190095E648 /* gbts.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9C18BDC2180095E648 /* gbts.c */; };
836F6FD918BDC2190095E648 /* ps2_gcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9D18BDC2180095E648 /* ps2_gcm.c */; };
836F6FD918BDC2190095E648 /* mcg.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9D18BDC2180095E648 /* mcg.c */; };
836F6FDA18BDC2190095E648 /* hgc1.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9E18BDC2180095E648 /* hgc1.c */; };
836F6FDB18BDC2190095E648 /* ps2_hsf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9F18BDC2180095E648 /* ps2_hsf.c */; };
836F6FDC18BDC2190095E648 /* ps2_iab.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA018BDC2180095E648 /* ps2_iab.c */; };
836F6FDE18BDC2190095E648 /* ild.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA218BDC2180095E648 /* ild.c */; };
836F6FE018BDC2190095E648 /* ps2_joe.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA418BDC2180095E648 /* ps2_joe.c */; };
836F6FE218BDC2190095E648 /* vig_kces.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA618BDC2180095E648 /* vig_kces.c */; };
836F6FE618BDC2190095E648 /* ps2_mcg.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EAA18BDC2180095E648 /* ps2_mcg.c */; };
836F6FE818BDC2190095E648 /* mic_koei.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EAC18BDC2180095E648 /* mic_koei.c */; };
836F6FEE18BDC2190095E648 /* p2bt_move_visa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB218BDC2180095E648 /* p2bt_move_visa.c */; };
836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB618BDC2180095E648 /* ps2_rnd.c */; };
@ -584,7 +580,6 @@
836F700918BDC2190095E648 /* voi.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECD18BDC2190095E648 /* voi.c */; };
836F700B18BDC2190095E648 /* ps2_wad.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECF18BDC2190095E648 /* ps2_wad.c */; };
836F700C18BDC2190095E648 /* wb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED018BDC2190095E648 /* wb.c */; };
836F700D18BDC2190095E648 /* ps2_wmus.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED118BDC2190095E648 /* ps2_wmus.c */; };
836F701518BDC2190095E648 /* sndp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED918BDC2190095E648 /* sndp.c */; };
836F701E18BDC2190095E648 /* redspark.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EE218BDC2190095E648 /* redspark.c */; };
836F701F18BDC2190095E648 /* riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EE318BDC2190095E648 /* riff.c */; };
@ -744,6 +739,37 @@
83B46FD52707FB9A00847FC9 /* endianness.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B46FD42707FB9A00847FC9 /* endianness.h */; };
83B69B222845A26600D2435A /* bw_mp3_riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B69B212845A26600D2435A /* bw_mp3_riff.c */; };
83B72E3A27904589006007A3 /* libfdk-aac.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 83B72E342790452C006007A3 /* libfdk-aac.2.dylib */; };
83B73C232D8FEC3A00A57F08 /* vorbis_codebooks_oor.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C222D8FEC3A00A57F08 /* vorbis_codebooks_oor.h */; };
83B73C242D8FEC3A00A57F08 /* oor_helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C202D8FEC3A00A57F08 /* oor_helpers.h */; };
83B73C252D8FEC3A00A57F08 /* oor_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C212D8FEC3A00A57F08 /* oor_helpers.c */; };
83B73C272D8FEC5500A57F08 /* vorbis_custom_utils_oor.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C262D8FEC5500A57F08 /* vorbis_custom_utils_oor.c */; };
83B73C292D8FEC7B00A57F08 /* oor.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C282D8FEC7B00A57F08 /* oor.c */; };
83B73C2C2D8FED0500A57F08 /* vorbis_codebooks_wwise.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C2B2D8FED0500A57F08 /* vorbis_codebooks_wwise.h */; };
83B73C2D2D8FED0500A57F08 /* vorbis_codebooks_fsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C2A2D8FED0500A57F08 /* vorbis_codebooks_fsb.h */; };
83B73C312D8FEF7A00A57F08 /* ubi_mpeg_helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C2F2D8FEF7A00A57F08 /* ubi_mpeg_helpers.h */; };
83B73C322D8FEF7A00A57F08 /* minimp3.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C2E2D8FEF7A00A57F08 /* minimp3.h */; };
83B73C332D8FEF7A00A57F08 /* ubi_mpeg_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C302D8FEF7A00A57F08 /* ubi_mpeg_helpers.c */; };
83B73C352D8FEFFD00A57F08 /* ubi_mpeg_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C342D8FEFFD00A57F08 /* ubi_mpeg_decoder.c */; };
83B73C3F2D8FF15700A57F08 /* mio_xerisa.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C3E2D8FF15700A57F08 /* mio_xerisa.h */; };
83B73C402D8FF15700A57F08 /* mio_erisasound.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C3C2D8FF15700A57F08 /* mio_erisasound.h */; };
83B73C412D8FF15700A57F08 /* mio_erisacontext.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C362D8FF15700A57F08 /* mio_erisacontext.h */; };
83B73C422D8FF15700A57F08 /* mio_erisafile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C382D8FF15700A57F08 /* mio_erisafile.h */; };
83B73C432D8FF15700A57F08 /* mio_erisamatrix.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C3A2D8FF15700A57F08 /* mio_erisamatrix.h */; };
83B73C442D8FF15700A57F08 /* mio_erisacontext.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C372D8FF15700A57F08 /* mio_erisacontext.c */; };
83B73C452D8FF15700A57F08 /* mio_erisafile.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C392D8FF15700A57F08 /* mio_erisafile.c */; };
83B73C462D8FF15700A57F08 /* mio_erisamatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C3B2D8FF15700A57F08 /* mio_erisamatrix.c */; };
83B73C472D8FF15700A57F08 /* mio_erisasound.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C3D2D8FF15700A57F08 /* mio_erisasound.c */; };
83B73C492D8FF17900A57F08 /* mio_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C482D8FF17900A57F08 /* mio_decoder.c */; };
83B73C4B2D8FF19800A57F08 /* mio.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C4A2D8FF19800A57F08 /* mio.c */; };
83B73C4F2D8FF1CB00A57F08 /* io_callback_sf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C4D2D8FF1CB00A57F08 /* io_callback_sf.h */; };
83B73C502D8FF1CB00A57F08 /* io_callback.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C4C2D8FF1CB00A57F08 /* io_callback.h */; };
83B73C512D8FF1CB00A57F08 /* io_callback_sf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C4E2D8FF1CB00A57F08 /* io_callback_sf.c */; };
83B73C542D8FF1E300A57F08 /* vorbis_codebooks.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C522D8FF1E300A57F08 /* vorbis_codebooks.h */; };
83B73C552D8FF1E300A57F08 /* vorbis_codebooks.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C532D8FF1E300A57F08 /* vorbis_codebooks.c */; };
83B73C572D8FF27000A57F08 /* 2dx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C562D8FF27000A57F08 /* 2dx.c */; };
83B73C5B2D8FF37700A57F08 /* codec_info.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C592D8FF37700A57F08 /* codec_info.h */; };
83B73C5C2D8FF37700A57F08 /* codec_info.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C5A2D8FF37700A57F08 /* codec_info.c */; };
83B73C5D2D8FF37700A57F08 /* api_libsf_cache.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C582D8FF37700A57F08 /* api_libsf_cache.c */; };
83B8FE2B2D5AB1F5005854C1 /* axhd.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B8FE2A2D5AB1F5005854C1 /* axhd.c */; };
83B8FE2D2D5AB2A5005854C1 /* shaa.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B8FE2C2D5AB2A5005854C1 /* shaa.c */; };
83B8FE2F2D5AB2F4005854C1 /* xwb_konami.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B8FE2E2D5AB2F4005854C1 /* xwb_konami.c */; };
@ -1066,7 +1092,7 @@
832BF80A21E05148006F50F1 /* xpcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpcm.c; sourceTree = "<group>"; };
832BF80B21E05148006F50F1 /* msf_tamasoft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = msf_tamasoft.c; sourceTree = "<group>"; };
832BF80C21E05148006F50F1 /* xps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xps.c; sourceTree = "<group>"; };
832BF80D21E05148006F50F1 /* ps2_va3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_va3.c; sourceTree = "<group>"; };
832BF80D21E05148006F50F1 /* va3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = va3.c; sourceTree = "<group>"; };
832BF80E21E05149006F50F1 /* zsnd_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zsnd_streamfile.h; sourceTree = "<group>"; };
832BF80F21E05149006F50F1 /* zsnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zsnd.c; sourceTree = "<group>"; };
832BF81021E05149006F50F1 /* vs_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vs_str.c; sourceTree = "<group>"; };
@ -1178,7 +1204,6 @@
834F7D422C7093EA003AC386 /* circus_vq_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = circus_vq_lib.h; sourceTree = "<group>"; };
834F7D432C7093EA003AC386 /* circus_vq_lzxpcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = circus_vq_lzxpcm.h; sourceTree = "<group>"; };
834F7D442C7093EA003AC386 /* circus_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = circus_decoder.c; sourceTree = "<group>"; };
834F7D452C7093EA003AC386 /* coding_utils_samples.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coding_utils_samples.h; sourceTree = "<group>"; };
834F7D462C7093EA003AC386 /* coding_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = coding_utils.c; sourceTree = "<group>"; };
834F7D472C7093EA003AC386 /* coding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coding.h; sourceTree = "<group>"; };
834F7D482C7093EA003AC386 /* compresswave_lib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compresswave_lib.c; sourceTree = "<group>"; };
@ -1253,8 +1278,6 @@
834F7D8F2C7093EA003AC386 /* tgcadpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tgcadpcm_decoder.c; sourceTree = "<group>"; };
834F7D902C7093EA003AC386 /* ubi_adpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_adpcm_decoder.c; sourceTree = "<group>"; };
834F7D912C7093EA003AC386 /* vadpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vadpcm_decoder.c; sourceTree = "<group>"; };
834F7D922C7093EA003AC386 /* vorbis_custom_data_fsb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vorbis_custom_data_fsb.h; sourceTree = "<group>"; };
834F7D932C7093EA003AC386 /* vorbis_custom_data_wwise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vorbis_custom_data_wwise.h; sourceTree = "<group>"; };
834F7D942C7093EA003AC386 /* vorbis_custom_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_decoder.c; sourceTree = "<group>"; };
834F7D952C7093EA003AC386 /* vorbis_custom_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vorbis_custom_decoder.h; sourceTree = "<group>"; };
834F7D962C7093EA003AC386 /* vorbis_custom_utils_awc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_utils_awc.c; sourceTree = "<group>"; };
@ -1484,14 +1507,13 @@
836F6E9918BDC2180095E648 /* lp_ap_lep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lp_ap_lep.c; sourceTree = "<group>"; };
836F6E9B18BDC2180095E648 /* filp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filp.c; sourceTree = "<group>"; };
836F6E9C18BDC2180095E648 /* gbts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gbts.c; sourceTree = "<group>"; };
836F6E9D18BDC2180095E648 /* ps2_gcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_gcm.c; sourceTree = "<group>"; };
836F6E9D18BDC2180095E648 /* mcg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mcg.c; sourceTree = "<group>"; };
836F6E9E18BDC2180095E648 /* hgc1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hgc1.c; sourceTree = "<group>"; };
836F6E9F18BDC2180095E648 /* ps2_hsf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_hsf.c; sourceTree = "<group>"; };
836F6EA018BDC2180095E648 /* ps2_iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_iab.c; sourceTree = "<group>"; };
836F6EA218BDC2180095E648 /* ild.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ild.c; sourceTree = "<group>"; };
836F6EA418BDC2180095E648 /* ps2_joe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_joe.c; sourceTree = "<group>"; };
836F6EA618BDC2180095E648 /* vig_kces.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vig_kces.c; sourceTree = "<group>"; };
836F6EAA18BDC2180095E648 /* ps2_mcg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_mcg.c; sourceTree = "<group>"; };
836F6EAC18BDC2180095E648 /* mic_koei.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mic_koei.c; sourceTree = "<group>"; };
836F6EB218BDC2180095E648 /* p2bt_move_visa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = p2bt_move_visa.c; sourceTree = "<group>"; };
836F6EB618BDC2180095E648 /* ps2_rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rnd.c; sourceTree = "<group>"; };
@ -1511,7 +1533,6 @@
836F6ECD18BDC2190095E648 /* voi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = voi.c; sourceTree = "<group>"; };
836F6ECF18BDC2190095E648 /* ps2_wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_wad.c; sourceTree = "<group>"; };
836F6ED018BDC2190095E648 /* wb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wb.c; sourceTree = "<group>"; };
836F6ED118BDC2190095E648 /* ps2_wmus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_wmus.c; sourceTree = "<group>"; };
836F6ED918BDC2190095E648 /* sndp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sndp.c; sourceTree = "<group>"; };
836F6EE218BDC2190095E648 /* redspark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = redspark.c; sourceTree = "<group>"; };
836F6EE318BDC2190095E648 /* riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = riff.c; sourceTree = "<group>"; };
@ -1673,6 +1694,37 @@
83B46FD42707FB9A00847FC9 /* endianness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endianness.h; sourceTree = "<group>"; };
83B69B212845A26600D2435A /* bw_mp3_riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bw_mp3_riff.c; sourceTree = "<group>"; };
83B72E342790452C006007A3 /* libfdk-aac.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libfdk-aac.2.dylib"; path = "../../ThirdParty/fdk-aac/lib/libfdk-aac.2.dylib"; sourceTree = "<group>"; };
83B73C202D8FEC3A00A57F08 /* oor_helpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = oor_helpers.h; sourceTree = "<group>"; };
83B73C212D8FEC3A00A57F08 /* oor_helpers.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = oor_helpers.c; sourceTree = "<group>"; };
83B73C222D8FEC3A00A57F08 /* vorbis_codebooks_oor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vorbis_codebooks_oor.h; sourceTree = "<group>"; };
83B73C262D8FEC5500A57F08 /* vorbis_custom_utils_oor.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_utils_oor.c; sourceTree = "<group>"; };
83B73C282D8FEC7B00A57F08 /* oor.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = oor.c; sourceTree = "<group>"; };
83B73C2A2D8FED0500A57F08 /* vorbis_codebooks_fsb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vorbis_codebooks_fsb.h; sourceTree = "<group>"; };
83B73C2B2D8FED0500A57F08 /* vorbis_codebooks_wwise.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vorbis_codebooks_wwise.h; sourceTree = "<group>"; };
83B73C2E2D8FEF7A00A57F08 /* minimp3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = minimp3.h; sourceTree = "<group>"; };
83B73C2F2D8FEF7A00A57F08 /* ubi_mpeg_helpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ubi_mpeg_helpers.h; sourceTree = "<group>"; };
83B73C302D8FEF7A00A57F08 /* ubi_mpeg_helpers.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ubi_mpeg_helpers.c; sourceTree = "<group>"; };
83B73C342D8FEFFD00A57F08 /* ubi_mpeg_decoder.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ubi_mpeg_decoder.c; sourceTree = "<group>"; };
83B73C362D8FF15700A57F08 /* mio_erisacontext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mio_erisacontext.h; sourceTree = "<group>"; };
83B73C372D8FF15700A57F08 /* mio_erisacontext.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio_erisacontext.c; sourceTree = "<group>"; };
83B73C382D8FF15700A57F08 /* mio_erisafile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mio_erisafile.h; sourceTree = "<group>"; };
83B73C392D8FF15700A57F08 /* mio_erisafile.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio_erisafile.c; sourceTree = "<group>"; };
83B73C3A2D8FF15700A57F08 /* mio_erisamatrix.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mio_erisamatrix.h; sourceTree = "<group>"; };
83B73C3B2D8FF15700A57F08 /* mio_erisamatrix.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio_erisamatrix.c; sourceTree = "<group>"; };
83B73C3C2D8FF15700A57F08 /* mio_erisasound.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mio_erisasound.h; sourceTree = "<group>"; };
83B73C3D2D8FF15700A57F08 /* mio_erisasound.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio_erisasound.c; sourceTree = "<group>"; };
83B73C3E2D8FF15700A57F08 /* mio_xerisa.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mio_xerisa.h; sourceTree = "<group>"; };
83B73C482D8FF17900A57F08 /* mio_decoder.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio_decoder.c; sourceTree = "<group>"; };
83B73C4A2D8FF19800A57F08 /* mio.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio.c; sourceTree = "<group>"; };
83B73C4C2D8FF1CB00A57F08 /* io_callback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = io_callback.h; sourceTree = "<group>"; };
83B73C4D2D8FF1CB00A57F08 /* io_callback_sf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = io_callback_sf.h; sourceTree = "<group>"; };
83B73C4E2D8FF1CB00A57F08 /* io_callback_sf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = io_callback_sf.c; sourceTree = "<group>"; };
83B73C522D8FF1E300A57F08 /* vorbis_codebooks.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vorbis_codebooks.h; sourceTree = "<group>"; };
83B73C532D8FF1E300A57F08 /* vorbis_codebooks.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vorbis_codebooks.c; sourceTree = "<group>"; };
83B73C562D8FF27000A57F08 /* 2dx.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = 2dx.c; sourceTree = "<group>"; };
83B73C582D8FF37700A57F08 /* api_libsf_cache.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = api_libsf_cache.c; sourceTree = "<group>"; };
83B73C592D8FF37700A57F08 /* codec_info.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = codec_info.h; sourceTree = "<group>"; };
83B73C5A2D8FF37700A57F08 /* codec_info.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = codec_info.c; sourceTree = "<group>"; };
83B8FE2A2D5AB1F5005854C1 /* axhd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = axhd.c; sourceTree = "<group>"; };
83B8FE2C2D5AB2A5005854C1 /* shaa.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = shaa.c; sourceTree = "<group>"; };
83B8FE2E2D5AB2F4005854C1 /* xwb_konami.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xwb_konami.c; sourceTree = "<group>"; };
@ -1896,10 +1948,22 @@
834F7D392C7093EA003AC386 /* libacm.h */,
834F7D382C7093EA003AC386 /* libacm_decode.c */,
834F7D3A2C7093EA003AC386 /* libacm_util.c */,
83B73C2E2D8FEF7A00A57F08 /* minimp3.h */,
83B73C362D8FF15700A57F08 /* mio_erisacontext.h */,
83B73C372D8FF15700A57F08 /* mio_erisacontext.c */,
83B73C382D8FF15700A57F08 /* mio_erisafile.h */,
83B73C392D8FF15700A57F08 /* mio_erisafile.c */,
83B73C3A2D8FF15700A57F08 /* mio_erisamatrix.h */,
83B73C3B2D8FF15700A57F08 /* mio_erisamatrix.c */,
83B73C3C2D8FF15700A57F08 /* mio_erisasound.h */,
83B73C3D2D8FF15700A57F08 /* mio_erisasound.c */,
83B73C3E2D8FF15700A57F08 /* mio_xerisa.h */,
834F7D792C7093EA003AC386 /* nwa_lib.h */,
834F7D342C7093EA003AC386 /* nwa_lib.c */,
834F7E7A2C709E66003AC386 /* ongakukan_adp_lib.h */,
834F7E792C709E66003AC386 /* ongakukan_adp_lib.c */,
83B73C202D8FEC3A00A57F08 /* oor_helpers.h */,
83B73C212D8FEC3A00A57F08 /* oor_helpers.c */,
834F7D832C7093EA003AC386 /* relic_lib.h */,
834F7D822C7093EA003AC386 /* relic_lib.c */,
834F7D842C7093EA003AC386 /* relic_mixfft.c */,
@ -1907,8 +1971,13 @@
834F7D8C2C7093EA003AC386 /* tac_lib.h */,
834F7D8B2C7093EA003AC386 /* tac_lib.c */,
834F7D8A2C7093EA003AC386 /* tac_ops.h */,
83B73C2F2D8FEF7A00A57F08 /* ubi_mpeg_helpers.h */,
83B73C302D8FEF7A00A57F08 /* ubi_mpeg_helpers.c */,
834F7D362C7093EA003AC386 /* utkdec.h */,
834F7D352C7093EA003AC386 /* utkdec.c */,
83B73C2A2D8FED0500A57F08 /* vorbis_codebooks_fsb.h */,
83B73C222D8FEC3A00A57F08 /* vorbis_codebooks_oor.h */,
83B73C2B2D8FED0500A57F08 /* vorbis_codebooks_wwise.h */,
);
path = libs;
sourceTree = "<group>";
@ -1924,7 +1993,6 @@
834F7D442C7093EA003AC386 /* circus_decoder.c */,
834F7D472C7093EA003AC386 /* coding.h */,
834F7D462C7093EA003AC386 /* coding_utils.c */,
834F7D452C7093EA003AC386 /* coding_utils_samples.h */,
834F7D4A2C7093EA003AC386 /* compresswave_decoder.c */,
834F7D4B2C7093EA003AC386 /* derf_decoder.c */,
834F7D4C2C7093EA003AC386 /* dpcm_kcej_decoder.c */,
@ -1949,6 +2017,7 @@
834F7D672C7093EA003AC386 /* l5_555_decoder.c */,
834F7D372C7093EA003AC386 /* libs */,
834F7D682C7093EA003AC386 /* lsf_decoder.c */,
83B73C482D8FF17900A57F08 /* mio_decoder.c */,
834F7D6A2C7093EA003AC386 /* mp4_aac_decoder.c */,
834F7D692C7093EA003AC386 /* mpc3_decoder.c */,
834F7D6E2C7093EA003AC386 /* mpeg_custom_utils.c */,
@ -1980,15 +2049,15 @@
834F7D8E2C7093EA003AC386 /* tantalus_decoder.c */,
834F7D8F2C7093EA003AC386 /* tgcadpcm_decoder.c */,
834F7D902C7093EA003AC386 /* ubi_adpcm_decoder.c */,
83B73C342D8FEFFD00A57F08 /* ubi_mpeg_decoder.c */,
834F7D912C7093EA003AC386 /* vadpcm_decoder.c */,
834F7D922C7093EA003AC386 /* vorbis_custom_data_fsb.h */,
834F7D932C7093EA003AC386 /* vorbis_custom_data_wwise.h */,
834F7D952C7093EA003AC386 /* vorbis_custom_decoder.h */,
834F7D942C7093EA003AC386 /* vorbis_custom_decoder.c */,
834F7D9C2C7093EA003AC386 /* vorbis_custom_utils.c */,
834F7D962C7093EA003AC386 /* vorbis_custom_utils_awc.c */,
834F7D972C7093EA003AC386 /* vorbis_custom_utils_fsb.c */,
834F7D982C7093EA003AC386 /* vorbis_custom_utils_ogl.c */,
83B73C262D8FEC5500A57F08 /* vorbis_custom_utils_oor.c */,
834F7D992C7093EA003AC386 /* vorbis_custom_utils_sk.c */,
834F7D9A2C7093EA003AC386 /* vorbis_custom_utils_vid1.c */,
834F7D9B2C7093EA003AC386 /* vorbis_custom_utils_wwise.c */,
@ -2010,7 +2079,10 @@
834F7EA02C70A786003AC386 /* api_helpers.c */,
834F7EA12C70A786003AC386 /* api_internal.h */,
834F7EA22C70A786003AC386 /* api_libsf.c */,
83B73C582D8FF37700A57F08 /* api_libsf_cache.c */,
834F7EA32C70A786003AC386 /* api_tags.c */,
83B73C592D8FF37700A57F08 /* codec_info.h */,
83B73C5A2D8FF37700A57F08 /* codec_info.c */,
834F7EA62C70A786003AC386 /* decode.h */,
834F7EA52C70A786003AC386 /* decode.c */,
834845772D27F2E9000E4928 /* decode_state.h */,
@ -2217,6 +2289,7 @@
836F6E2718BDC2180095E648 /* meta */ = {
isa = PBXGroup;
children = (
83B73C562D8FF27000A57F08 /* 2dx.c */,
836F6E2918BDC2180095E648 /* 2dx9.c */,
836F6E8D18BDC2180095E648 /* 2pfs.c */,
83C727FE22BC893900678B4A /* 9tav.c */,
@ -2420,9 +2493,11 @@
836F6E5C18BDC2180095E648 /* mattel_hyperscan.c */,
836F6E5D18BDC2180095E648 /* maxis_xa.c */,
83EDE5D61A70951A005F5D84 /* mca.c */,
836F6E9D18BDC2180095E648 /* mcg.c */,
836F6E5E18BDC2180095E648 /* meta.h */,
834FE0DE215C79EB000A5D3D /* mib_mih.c */,
836F6EAC18BDC2180095E648 /* mic_koei.c */,
83B73C4A2D8FF19800A57F08 /* mio.c */,
8346D97725BF838C00D1A8B0 /* mjb_mjh.c */,
836F6E5F18BDC2180095E648 /* mn_str.c */,
8349A9031FE6258100E26435 /* mogg.c */,
@ -2483,6 +2558,7 @@
831BA60F1EAC61A500CF89B0 /* ogl.c */,
83AF2CC726226BA400538240 /* ogv_3rdeye.c */,
8349A8FB1FE6257F00E26435 /* omu.c */,
83B73C282D8FEC7B00A57F08 /* oor.c */,
8306B0CE2098458E000302D4 /* opus.c */,
8306B0CD2098458E000302D4 /* opus_interleave_streamfile.h */,
836F6EB218BDC2180095E648 /* p2bt_move_visa.c */,
@ -2505,21 +2581,17 @@
836F6E9118BDC2180095E648 /* ps2_ass.c */,
836F6E9418BDC2180095E648 /* ps2_b1s.c */,
836F6E9618BDC2180095E648 /* ps2_bmdx.c */,
836F6E9D18BDC2180095E648 /* ps2_gcm.c */,
836F6E9F18BDC2180095E648 /* ps2_hsf.c */,
836F6EA018BDC2180095E648 /* ps2_iab.c */,
836F6EA418BDC2180095E648 /* ps2_joe.c */,
836F6EAA18BDC2180095E648 /* ps2_mcg.c */,
836F6EB618BDC2180095E648 /* ps2_rnd.c */,
836F6EBD18BDC2180095E648 /* ps2_snd.c */,
836F6EBF18BDC2190095E648 /* ps2_sps.c */,
836F6EC518BDC2190095E648 /* ps2_tec.c */,
832BF80D21E05148006F50F1 /* ps2_va3.c */,
836F6EC918BDC2190095E648 /* ps2_vbk.c */,
836F6ECB18BDC2190095E648 /* ps2_vgv.c */,
836F6ECC18BDC2190095E648 /* ps2_vms.c */,
836F6ECF18BDC2190095E648 /* ps2_wad.c */,
836F6ED118BDC2190095E648 /* ps2_wmus.c */,
8315868326F586E200803A3A /* psb.c */,
837CEAE823487F2B00E62A4A /* psf.c */,
836F6E5518BDC2180095E648 /* psnd.c */,
@ -2639,6 +2711,7 @@
834FE0C5215C79E6000A5D3D /* ue4opus.c */,
83B8FE302D5AB421005854C1 /* undefind.c */,
834FE0DD215C79EB000A5D3D /* utk.c */,
832BF80D21E05148006F50F1 /* va3.c */,
83D1189228B2F33400AF3370 /* vab.c */,
834FE0E4215C79EC000A5D3D /* vag.c */,
834FE0D3215C79E9000A5D3D /* vai.c */,
@ -2735,42 +2808,47 @@
833E82F92A28595A00CD0580 /* bitstream_lsb.h */,
836DF620298F83F400CD0580 /* bitstream_msb.h */,
833E82C72A28566700CD0580 /* channel_mappings.h */,
83D26A8026E66DC2001A9475 /* chunks.c */,
83D26A7E26E66DC2001A9475 /* chunks.h */,
834F7D132C70861D003AC386 /* cipher_blowfish.c */,
83D26A8026E66DC2001A9475 /* chunks.c */,
834F7D122C70861D003AC386 /* cipher_blowfish.h */,
834F7D1A2C708719003AC386 /* cipher_xxtea.c */,
834F7D132C70861D003AC386 /* cipher_blowfish.c */,
834F7D1B2C708719003AC386 /* cipher_xxtea.h */,
833E82EB2A28587D00CD0580 /* companion_files.c */,
834F7D1A2C708719003AC386 /* cipher_xxtea.c */,
833E82EF2A28587D00CD0580 /* companion_files.h */,
836DF621298F83F400CD0580 /* cri_keys.c */,
833E82EB2A28587D00CD0580 /* companion_files.c */,
836DF61F298F83F400CD0580 /* cri_keys.h */,
836F46B5282087A6005B9B87 /* cri_utf.c */,
836DF621298F83F400CD0580 /* cri_keys.c */,
836F46B6282087A6005B9B87 /* cri_utf.h */,
836F46B5282087A6005B9B87 /* cri_utf.c */,
83B46FD42707FB9A00847FC9 /* endianness.h */,
83C0C75E2AA436370056AFD8 /* layout_utils.c */,
83B73C4C2D8FF1CB00A57F08 /* io_callback.h */,
83B73C4D2D8FF1CB00A57F08 /* io_callback_sf.h */,
83B73C4E2D8FF1CB00A57F08 /* io_callback_sf.c */,
83C0C75F2AA436370056AFD8 /* layout_utils.h */,
83D26A7D26E66DC2001A9475 /* log.c */,
83C0C75E2AA436370056AFD8 /* layout_utils.c */,
83D26A7F26E66DC2001A9475 /* log.h */,
8315868826F586F900803A3A /* m2_psb.c */,
83D26A7D26E66DC2001A9475 /* log.c */,
8315868926F586F900803A3A /* m2_psb.h */,
834F7E9A2C70A6E1003AC386 /* meta_utils.c */,
8315868826F586F900803A3A /* m2_psb.c */,
834F7E992C70A6E1003AC386 /* meta_utils.h */,
8319017A28F67EE100B70711 /* miniz.c */,
834F7E9A2C70A6E1003AC386 /* meta_utils.c */,
8319017928F67EE000B70711 /* miniz.h */,
833E82EC2A28587D00CD0580 /* paths.c */,
8319017A28F67EE100B70711 /* miniz.c */,
833E82ED2A28587D00CD0580 /* paths.h */,
833E82C92A2856B200CD0580 /* reader_get_nibbles.h */,
833E82EC2A28587D00CD0580 /* paths.c */,
833E82F52A2858EF00CD0580 /* reader.c */,
833E82CA2A2856B200CD0580 /* reader_get.h */,
833E82C92A2856B200CD0580 /* reader_get_nibbles.h */,
833E82CB2A2856B200CD0580 /* reader_put.h */,
833E82EE2A28587D00CD0580 /* reader_sf.h */,
833E82F62A2858EF00CD0580 /* reader_text.h */,
833E82F52A2858EF00CD0580 /* reader.c */,
83FBB17B2A4FF87200CD0580 /* sf_utils.c */,
83FBB17A2A4FF87200CD0580 /* sf_utils.h */,
8339B324280FDF4B0076F74B /* text_reader.c */,
83FBB17B2A4FF87200CD0580 /* sf_utils.c */,
8339B325280FDF4B0076F74B /* text_reader.h */,
8339B324280FDF4B0076F74B /* text_reader.c */,
834F7E772C709D0E003AC386 /* vgmstream_limits.h */,
83B73C522D8FF1E300A57F08 /* vorbis_codebooks.h */,
83B73C532D8FF1E300A57F08 /* vorbis_codebooks.c */,
834F7E102C709933003AC386 /* zlib_vgmstream.h */,
);
path = util;
@ -2811,9 +2889,12 @@
834F7DC42C7093EA003AC386 /* g72x_state.h in Headers */,
834F7ED62C70A786003AC386 /* plugins.h in Headers */,
834F7E782C709D0E003AC386 /* vgmstream_limits.h in Headers */,
83B73C5B2D8FF37700A57F08 /* codec_info.h in Headers */,
83D26A8226E66DC2001A9475 /* chunks.h in Headers */,
835096F32C9979DD00163D93 /* libvgmstream_streamfile.h in Headers */,
836F705518BDC2190095E648 /* streamtypes.h in Headers */,
83CBF5362D46309100AA2D75 /* ka1a_dec.h in Headers */,
835096F22C9979DD00163D93 /* libvgmstream.h in Headers */,
83CBF5372D46309100AA2D75 /* ka1a_dec_data.h in Headers */,
833E82CF2A2856B200CD0580 /* reader_get_nibbles.h in Headers */,
833E82D12A2856B200CD0580 /* reader_put.h in Headers */,
@ -2848,6 +2929,8 @@
83B46FD52707FB9A00847FC9 /* endianness.h in Headers */,
834F7D092C7085EB003AC386 /* str_wav_streamfile.h in Headers */,
836F705718BDC2190095E648 /* util.h in Headers */,
83B73C4F2D8FF1CB00A57F08 /* io_callback_sf.h in Headers */,
83B73C502D8FF1CB00A57F08 /* io_callback.h in Headers */,
834F7DF82C7093EA003AC386 /* tac_ops.h in Headers */,
83256CC128666C620036D9C0 /* index.h in Headers */,
834FE0ED215C79ED000A5D3D /* fsb_interleave_streamfile.h in Headers */,
@ -2871,8 +2954,6 @@
83256CD628666C620036D9C0 /* newhuffman.h in Headers */,
835C883722CC17BE001B4B3F /* ogg_vorbis_streamfile.h in Headers */,
837CEAFE23487F2C00E62A4A /* jstm_streamfile.h in Headers */,
835096F22C9979DD00163D93 /* libvgmstream.h in Headers */,
835096F32C9979DD00163D93 /* libvgmstream_streamfile.h in Headers */,
834F7DB02C7093EA003AC386 /* circus_vq_lib.h in Headers */,
832BF82021E0514B006F50F1 /* zsnd_streamfile.h in Headers */,
834F7E862C709FED003AC386 /* api_version.h in Headers */,
@ -2901,6 +2982,8 @@
83256CD128666C620036D9C0 /* mpg123lib_intern.h in Headers */,
83C7281622BC893D00678B4A /* xwma_konami_streamfile.h in Headers */,
834F7D1D2C708719003AC386 /* cipher_xxtea.h in Headers */,
83B73C312D8FEF7A00A57F08 /* ubi_mpeg_helpers.h in Headers */,
83B73C322D8FEF7A00A57F08 /* minimp3.h in Headers */,
833E82C82A28566700CD0580 /* channel_mappings.h in Headers */,
83256CC028666C620036D9C0 /* synth_8bit.h in Headers */,
834F7DCB2C7093EA003AC386 /* g7221_lib.h in Headers */,
@ -2925,15 +3008,20 @@
834F7E202C709AE0003AC386 /* api_tags.h in Headers */,
8396BE7B2935FC2F00CD0580 /* sscf_encrypted.h in Headers */,
83FBD506235D31F800D35BCD /* riff_ogg_streamfile.h in Headers */,
83B73C3F2D8FF15700A57F08 /* mio_xerisa.h in Headers */,
83B73C402D8FF15700A57F08 /* mio_erisasound.h in Headers */,
83B73C412D8FF15700A57F08 /* mio_erisacontext.h in Headers */,
83B73C422D8FF15700A57F08 /* mio_erisafile.h in Headers */,
83B73C432D8FF15700A57F08 /* mio_erisamatrix.h in Headers */,
8339B327280FDF4B0076F74B /* text_reader.h in Headers */,
834F7E002C7093EA003AC386 /* vorbis_custom_data_fsb.h in Headers */,
834F7DD12C7093EA003AC386 /* icelib.h in Headers */,
836F6F9A18BDC2190095E648 /* meta.h in Headers */,
8319017B28F67EE100B70711 /* miniz.h in Headers */,
834F7DA52C7093EA003AC386 /* utkdec.h in Headers */,
834F7ECE2C70A786003AC386 /* mixer_priv.h in Headers */,
83B73C232D8FEC3A00A57F08 /* vorbis_codebooks_oor.h in Headers */,
83B73C242D8FEC3A00A57F08 /* oor_helpers.h in Headers */,
833E82FA2A28595A00CD0580 /* bitstream_lsb.h in Headers */,
834F7DB32C7093EA003AC386 /* coding_utils_samples.h in Headers */,
834F7DF72C7093EA003AC386 /* tac_data.h in Headers */,
834F7DFA2C7093EA003AC386 /* tac_lib.h in Headers */,
83A8BAE625667AA8000F5F3F /* lp_ap_lep_streamfile.h in Headers */,
@ -2972,16 +3060,18 @@
83256CD728666C620036D9C0 /* synth_mono.h in Headers */,
834F7DCE2C7093EA003AC386 /* clhca.h in Headers */,
8349A91B1FE6258200E26435 /* adx_keys.h in Headers */,
834F7E012C7093EA003AC386 /* vorbis_custom_data_wwise.h in Headers */,
836F6F4D18BDC2190095E648 /* layout.h in Headers */,
83269DD22399F5DE00F49FE3 /* nus3bank_streamfile.h in Headers */,
83AA5D251F6E2F9C0020821C /* hca_keys.h in Headers */,
834F7E832C709F5B003AC386 /* apa3_streamfile.h in Headers */,
83256CDA28666C620036D9C0 /* l2tables.h in Headers */,
83256CC828666C620036D9C0 /* getbits.h in Headers */,
83B73C2C2D8FED0500A57F08 /* vorbis_codebooks_wwise.h in Headers */,
83B73C2D2D8FED0500A57F08 /* vorbis_codebooks_fsb.h in Headers */,
83256CC728666C620036D9C0 /* optimize.h in Headers */,
83031ED3243C50DF00C3F3E0 /* fsb5_streamfile.h in Headers */,
83256CE328666C620036D9C0 /* decode.h in Headers */,
83B73C542D8FF1E300A57F08 /* vorbis_codebooks.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -3022,12 +3112,6 @@
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1620;
ORGANIZATIONNAME = "Christopher Snowhill";
TargetAttributes = {
836F6B3818BDB8880095E648 = {
DevelopmentTeam = "";
ProvisioningStyle = Manual;
};
};
};
buildConfigurationList = 836F6B3318BDB8880095E648 /* Build configuration list for PBXProject "libvgmstream" */;
compatibilityVersion = "Xcode 3.2";
@ -3179,6 +3263,8 @@
832BF82821E0514B006F50F1 /* xwma.c in Sources */,
83FC176E23AC58D100E1025F /* csb.c in Sources */,
836F46B32820874D005B9B87 /* esf.c in Sources */,
83B73C512D8FF1CB00A57F08 /* io_callback_sf.c in Sources */,
83B73C352D8FEFFD00A57F08 /* ubi_mpeg_decoder.c in Sources */,
8306B0EB20984590000302D4 /* wave_segmented.c in Sources */,
836F6F9F18BDC2190095E648 /* musc.c in Sources */,
8349A9121FE6258200E26435 /* smss.c in Sources */,
@ -3229,6 +3315,7 @@
836F6F9418BDC2190095E648 /* iivb.c in Sources */,
836F6F8D18BDC2190095E648 /* gsnd.c in Sources */,
836F704518BDC2190095E648 /* wvs.c in Sources */,
83B73C292D8FEC7B00A57F08 /* oor.c in Sources */,
839FBFFB26C354E70016A78A /* wxd_wxh.c in Sources */,
83EDE5D91A70951A005F5D84 /* btsnd.c in Sources */,
834F7DD72C7093EA003AC386 /* mpc3_decoder.c in Sources */,
@ -3336,6 +3423,7 @@
835DF7032C79ABB50008814A /* sbuf.c in Sources */,
830EBE142004656E0023AA10 /* ktss.c in Sources */,
836F6F6618BDC2190095E648 /* aax.c in Sources */,
83B73C272D8FEC5500A57F08 /* vorbis_custom_utils_oor.c in Sources */,
8306B0BC20984552000302D4 /* blocked_vs.c in Sources */,
83AA7F812519C042004C5298 /* silence.c in Sources */,
837CEAF823487F2C00E62A4A /* xwv_valve.c in Sources */,
@ -3430,6 +3518,7 @@
837CEAD823487E8300E62A4A /* bmp_konami.c in Sources */,
834F7DDC2C7093EA003AC386 /* mpeg_custom_utils.c in Sources */,
834F7E922C70A1AB003AC386 /* vgmstream_init.c in Sources */,
83B73C332D8FEF7A00A57F08 /* ubi_mpeg_helpers.c in Sources */,
836F700118BDC2190095E648 /* ps2_tec.c in Sources */,
832BF82121E0514B006F50F1 /* zsnd.c in Sources */,
836F703018BDC2190095E648 /* sqex_scd.c in Sources */,
@ -3486,8 +3575,9 @@
834F7CFD2C70834D003AC386 /* nxof.c in Sources */,
836F6FC718BDC2190095E648 /* pona.c in Sources */,
8306B0B820984552000302D4 /* blocked_ws_aud.c in Sources */,
83B73C5C2D8FF37700A57F08 /* codec_info.c in Sources */,
83B73C5D2D8FF37700A57F08 /* api_libsf_cache.c in Sources */,
834F7D252C7088B9003AC386 /* cbx.c in Sources */,
836F6FE618BDC2190095E648 /* ps2_mcg.c in Sources */,
83AA5D241F6E2F9C0020821C /* awc.c in Sources */,
8349A8E91FE6253900E26435 /* blocked_ea_1snh.c in Sources */,
8306B0E620984590000302D4 /* msb_msh.c in Sources */,
@ -3520,6 +3610,7 @@
83CBF5432D46339200AA2D75 /* skex.c in Sources */,
834F7E182C709A1D003AC386 /* ea_schl_standard.c in Sources */,
836F6FCD18BDC2190095E648 /* ps2_ass.c in Sources */,
83B73C252D8FEC3A00A57F08 /* oor_helpers.c in Sources */,
83CBF5412D4631F300AA2D75 /* i3ds.c in Sources */,
8349A90B1FE6258200E26435 /* pcm_kceje.c in Sources */,
836F6F4A18BDC2190095E648 /* interleave.c in Sources */,
@ -3541,12 +3632,15 @@
834D3A6E19F47C98001C54F6 /* g1l.c in Sources */,
832BF82A21E0514B006F50F1 /* vs_square.c in Sources */,
8349A9091FE6258200E26435 /* pc_ast.c in Sources */,
83B73C442D8FF15700A57F08 /* mio_erisacontext.c in Sources */,
83B73C452D8FF15700A57F08 /* mio_erisafile.c in Sources */,
83B73C462D8FF15700A57F08 /* mio_erisamatrix.c in Sources */,
83B73C472D8FF15700A57F08 /* mio_erisasound.c in Sources */,
834F7DEF2C7093EA003AC386 /* ptadpcm_decoder.c in Sources */,
832BF81F21E0514B006F50F1 /* ps2_va3.c in Sources */,
832BF81F21E0514B006F50F1 /* va3.c in Sources */,
8349A91C1FE6258200E26435 /* mogg.c in Sources */,
834FE0F5215C79ED000A5D3D /* wav2.c in Sources */,
836F703D18BDC2190095E648 /* mus_krome.c in Sources */,
836F700D18BDC2190095E648 /* ps2_wmus.c in Sources */,
831BA61C1EAC61A500CF89B0 /* sndx.c in Sources */,
836F6F9618BDC2190095E648 /* lsf.c in Sources */,
834F7E7E2C709E76003AC386 /* ongakukan_adp_decoder.c in Sources */,
@ -3585,6 +3679,7 @@
836F702A18BDC2190095E648 /* sd9.c in Sources */,
836F6FB418BDC2190095E648 /* ngc_nst_dsp.c in Sources */,
834F7DB92C7093EA003AC386 /* derf_decoder.c in Sources */,
83B73C4B2D8FF19800A57F08 /* mio.c in Sources */,
836F6FDB18BDC2190095E648 /* ps2_hsf.c in Sources */,
836F6FF618BDC2190095E648 /* ster.c in Sources */,
834F7E0D2C7093EA003AC386 /* xa_decoder.c in Sources */,
@ -3610,6 +3705,7 @@
834F7D0B2C7085EB003AC386 /* ea_eaac_standard.c in Sources */,
834FE0FA215C79ED000A5D3D /* nus3bank.c in Sources */,
8306B0B220984552000302D4 /* blocked_mxch.c in Sources */,
83B73C492D8FF17900A57F08 /* mio_decoder.c in Sources */,
834F7DBC2C7093EA003AC386 /* ea_mt_decoder.c in Sources */,
837CEAFA23487F2C00E62A4A /* xa_04sw.c in Sources */,
836F6F8618BDC2190095E648 /* excitebots.c in Sources */,
@ -3633,6 +3729,7 @@
831BA6211EAC61A500CF89B0 /* pasx.c in Sources */,
832BF82621E0514B006F50F1 /* nwav.c in Sources */,
8349A8E81FE6253900E26435 /* blocked_dec.c in Sources */,
83B73C552D8FF1E300A57F08 /* vorbis_codebooks.c in Sources */,
834F7EDA2C70A786003AC386 /* seek.c in Sources */,
834F7DBF2C7093EA003AC386 /* fadpcm_decoder.c in Sources */,
834F7DCC2C7093EA003AC386 /* g7221_decoder.c in Sources */,
@ -3644,6 +3741,7 @@
8306B0B620984552000302D4 /* blocked_hwas.c in Sources */,
836F6FC218BDC2190095E648 /* pc_mxst.c in Sources */,
8375737621F950ED00F01AF5 /* gin.c in Sources */,
83B73C572D8FF27000A57F08 /* 2dx.c in Sources */,
836F6FC918BDC2190095E648 /* 2pfs.c in Sources */,
83AFABBC23795202002F3947 /* xssb.c in Sources */,
836F704818BDC2190095E648 /* xbox_ims.c in Sources */,
@ -3651,7 +3749,7 @@
836F6F7518BDC2190095E648 /* bnsf.c in Sources */,
836F704318BDC2190095E648 /* wpd.c in Sources */,
8349A9081FE6258200E26435 /* ezw.c in Sources */,
836F6FD918BDC2190095E648 /* ps2_gcm.c in Sources */,
836F6FD918BDC2190095E648 /* mcg.c in Sources */,
83A21F88201D8981000F04B9 /* ogg_vorbis.c in Sources */,
837CEAF923487F2C00E62A4A /* xavs.c in Sources */,
836F6F8E18BDC2190095E648 /* halpst.c in Sources */,
@ -3955,14 +4053,16 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "vgmstream/libvgmstream-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "NoWork-Inc.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.libvgmstream;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
WRAPPER_EXTENSION = framework;
};
@ -3972,14 +4072,16 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "vgmstream/libvgmstream-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "NoWork-Inc.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.libvgmstream;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
WRAPPER_EXTENSION = framework;
};

View file

@ -1,13 +1,23 @@
#include "api_internal.h"
#include "mixing.h"
#define INTERNAL_BUF_SAMPLES 1024
LIBVGMSTREAM_API uint32_t libvgmstream_get_version(void) {
return (LIBVGMSTREAM_API_VERSION_MAJOR << 24) | (LIBVGMSTREAM_API_VERSION_MINOR << 16) | (LIBVGMSTREAM_API_VERSION_PATCH << 0);
}
LIBVGMSTREAM_API libvgmstream_t* libvgmstream_create(libstreamfile_t* libsf, int subsong, libvgmstream_config_t* vcfg) {
libvgmstream_t* vgmstream = libvgmstream_init();
libvgmstream_setup(vgmstream, vcfg);
int err = libvgmstream_open_stream(vgmstream, libsf, subsong);
if (err < 0) {
libvgmstream_free(vgmstream);
return NULL;
}
return vgmstream;
}
LIBVGMSTREAM_API libvgmstream_t* libvgmstream_init(void) {
libvgmstream_t* lib = NULL;
@ -48,57 +58,79 @@ LIBVGMSTREAM_API void libvgmstream_free(libvgmstream_t* lib) {
free(lib);
}
// TODO: allow calling after load
LIBVGMSTREAM_API void libvgmstream_setup(libvgmstream_t* lib, libvgmstream_config_t* cfg) {
if (!lib || !lib->priv)
return;
libvgmstream_priv_t* priv = lib->priv;
// Can only apply once b/c some options modify the internal mixing chain and there is no clean way to
// reset the stream when txtp also manipulates it (maybe could add some flag per mixing item)
if (priv->setup_done)
return;
// allow overwritting current config, though will only apply to next load
//if (priv->config_loaded)
// return;
if (!cfg) {
memset(&priv->cfg , 0, sizeof(libvgmstream_config_t));
priv->cfg.loop_count = 1; //TODO: loop 0 means no loop (improve detection)
priv->config_loaded = false;
}
else {
priv->cfg = *cfg;
priv->config_loaded = true;
}
//TODO validate, etc
//TODO validate, etc (for now most incorrect values are ignored)
// apply now if possible to update format info
if (priv->vgmstream) {
api_apply_config(priv);
}
}
void libvgmstream_priv_reset(libvgmstream_priv_t* priv, bool reset_buf) {
void libvgmstream_priv_reset(libvgmstream_priv_t* priv, bool full) {
//memset(&priv->cfg, 0, sizeof(libvgmstream_config_t)); //config is always valid
memset(&priv->fmt, 0, sizeof(libvgmstream_format_t));
memset(&priv->dec, 0, sizeof(libvgmstream_decoder_t));
//memset(&priv->pos, 0, sizeof(libvgmstream_priv_position_t)); //position info is updated on open
memset(&priv->dec, 0, sizeof(libvgmstream_decoder_t));
if (reset_buf) {
free(priv->buf.data);
if (full) {
free(priv->buf.data); //TODO
memset(&priv->buf, 0, sizeof(libvgmstream_priv_buf_t));
memset(&priv->fmt, 0, sizeof(libvgmstream_format_t));
}
else {
priv->buf.consumed = priv->buf.samples;
}
priv->pos.current = 0;
priv->decode_done = false;
}
libvgmstream_sample_t api_get_output_sample_type(libvgmstream_priv_t* priv) {
libvgmstream_sfmt_t api_get_output_sample_type(libvgmstream_priv_t* priv) {
VGMSTREAM* v = priv->vgmstream;
sfmt_t format = mixing_get_output_sample_type(v);
switch(format) {
case SFMT_S16: return LIBVGMSTREAM_SAMPLE_PCM16;
case SFMT_FLT: return LIBVGMSTREAM_SAMPLE_FLOAT;
case SFMT_S16: return LIBVGMSTREAM_SFMT_PCM16;
case SFMT_FLT: return LIBVGMSTREAM_SFMT_FLOAT;
case SFMT_F32: return LIBVGMSTREAM_SFMT_FLOAT; //shouldn't happen?
default:
return 0x00; //???
}
}
int api_get_sample_size(libvgmstream_sample_t sample_type) {
switch(sample_type) {
case LIBVGMSTREAM_SAMPLE_PCM24:
case LIBVGMSTREAM_SAMPLE_PCM32:
case LIBVGMSTREAM_SAMPLE_FLOAT:
int api_get_sample_size(libvgmstream_sfmt_t sample_format) {
switch(sample_format) {
//case LIBVGMSTREAM_SFMT_PCM24:
//case LIBVGMSTREAM_SFMT_PCM32:
case LIBVGMSTREAM_SFMT_FLOAT:
return 0x04;
case LIBVGMSTREAM_SAMPLE_PCM16:
case LIBVGMSTREAM_SFMT_PCM16:
default:
return 0x02;
}

View file

@ -3,18 +3,6 @@
#include "mixing.h"
static void load_vgmstream(libvgmstream_priv_t* priv, libvgmstream_options_t* opt) {
STREAMFILE* sf_api = open_api_streamfile(opt->libsf);
if (!sf_api)
return;
//TODO: handle internal format_id
sf_api->stream_index = opt->subsong_index;
priv->vgmstream = init_vgmstream_from_STREAMFILE(sf_api);
close_streamfile(sf_api);
}
static void apply_config(libvgmstream_priv_t* priv) {
libvgmstream_config_t* cfg = &priv->cfg;
@ -36,23 +24,50 @@ static void apply_config(libvgmstream_priv_t* priv) {
if (!vcfg.allow_play_forever)
vcfg.play_forever = 0;
// Traditionally in CLI loop_count = 0 removes loops but this is pretty odd for a lib
// (calling _setup with nothing set would remove most audio).
// For now loop_count 0 is set to 1, and loop_count <0 is assumed to be same 0
if (vcfg.loop_count == 0) {
vcfg.loop_count = 1;
} else if (vcfg.loop_count < 0)
vcfg.loop_count = 0;
vgmstream_apply_config(priv->vgmstream, &vcfg);
}
static void prepare_mixing(libvgmstream_priv_t* priv, libvgmstream_options_t* opt) {
static void prepare_mixing(libvgmstream_priv_t* priv) {
libvgmstream_config_t* cfg = &priv->cfg;
/* enable after config but before outbuf */
if (priv->cfg.auto_downmix_channels) {
vgmstream_mixing_autodownmix(priv->vgmstream, priv->cfg.auto_downmix_channels);
if (cfg->auto_downmix_channels) {
vgmstream_mixing_autodownmix(priv->vgmstream, cfg->auto_downmix_channels);
}
else if (opt && opt->stereo_track >= 1) {
vgmstream_mixing_stereo_only(priv->vgmstream, opt->stereo_track - 1);
else if (cfg->stereo_track >= 1) {
vgmstream_mixing_stereo_only(priv->vgmstream, cfg->stereo_track - 1);
}
if (priv->cfg.force_pcm16) {
mixing_macro_output_sample_format(priv->vgmstream, SFMT_S16);
if (cfg->force_sfmt) {
// external force
sfmt_t force_sfmt = SFMT_NONE;
switch(cfg->force_sfmt) {
case LIBVGMSTREAM_SFMT_PCM16: force_sfmt = SFMT_S16; break;
case LIBVGMSTREAM_SFMT_FLOAT: force_sfmt = SFMT_FLT; break;
default: break;
}
else if (priv->cfg.force_float) {
mixing_macro_output_sample_format(priv->vgmstream, SFMT_FLT);
mixing_macro_output_sample_format(priv->vgmstream, force_sfmt);
}
else {
// internal force, swap certain internal bufs into standard output
sfmt_t force_sfmt = SFMT_NONE;
sfmt_t input_sfmt = mixing_get_input_sample_type(priv->vgmstream);
switch(input_sfmt) {
case SFMT_F32: force_sfmt = SFMT_FLT; break;
default: break;
}
mixing_macro_output_sample_format(priv->vgmstream, force_sfmt);
}
vgmstream_mixing_enable(priv->vgmstream, INTERNAL_BUF_SAMPLES, NULL /*&input_channels*/, NULL /*&output_channels*/);
@ -76,11 +91,11 @@ static void update_format_info(libvgmstream_priv_t* priv) {
fmt->channels = v->channels;
fmt->input_channels = 0;
vgmstream_mixing_enable(v, 0, &fmt->input_channels, &fmt->channels);
vgmstream_mixing_enable(v, 0, &fmt->input_channels, &fmt->channels); //query
fmt->channel_layout = v->channel_layout;
fmt->sample_type = api_get_output_sample_type(priv);
fmt->sample_size = api_get_sample_size(fmt->sample_type);
fmt->sample_format = api_get_output_sample_type(priv);
fmt->sample_size = api_get_sample_size(fmt->sample_format);
fmt->sample_rate = v->sample_rate;
@ -105,26 +120,58 @@ static void update_format_info(libvgmstream_priv_t* priv) {
}
}
LIBVGMSTREAM_API int libvgmstream_open_stream(libvgmstream_t* lib, libvgmstream_options_t* opt) {
if (!lib ||!lib->priv)
return LIBVGMSTREAM_ERROR_GENERIC;
if (!opt || !opt->libsf || opt->subsong_index < 0)
// apply config if data + config is loaded and not already loaded
void api_apply_config(libvgmstream_priv_t* priv) {
if (priv->setup_done)
return;
if (!priv->vgmstream)
return;
apply_config(priv);
prepare_mixing(priv);
update_position(priv);
update_format_info(priv);
priv->setup_done = true;
}
static void load_vgmstream(libvgmstream_priv_t* priv, libstreamfile_t* libsf, int subsong_index) {
STREAMFILE* sf_api = open_api_streamfile(libsf);
if (!sf_api)
return;
//TODO: handle format_id
sf_api->stream_index = subsong_index;
priv->vgmstream = init_vgmstream_from_STREAMFILE(sf_api);
close_streamfile(sf_api);
}
LIBVGMSTREAM_API int libvgmstream_open_stream(libvgmstream_t* lib, libstreamfile_t* libsf, int subsong_index) {
if (!lib ||!lib->priv || !libsf)
return LIBVGMSTREAM_ERROR_GENERIC;
// close loaded song if any + reset
libvgmstream_close_stream(lib);
libvgmstream_priv_t* priv = lib->priv;
if (subsong_index < 0)
return LIBVGMSTREAM_ERROR_GENERIC;
load_vgmstream(priv, opt);
load_vgmstream(priv, libsf, subsong_index);
if (!priv->vgmstream)
return LIBVGMSTREAM_ERROR_GENERIC;
apply_config(priv);
prepare_mixing(priv, opt);
// apply now if possible to update format info
if (priv->config_loaded) {
api_apply_config(priv);
}
else {
// no config: just update info (apply_config will be called later)
update_position(priv);
update_format_info(priv);
}
return LIBVGMSTREAM_OK;
}
@ -138,6 +185,8 @@ LIBVGMSTREAM_API void libvgmstream_close_stream(libvgmstream_t* lib) {
close_vgmstream(priv->vgmstream);
priv->vgmstream = NULL;
priv->setup_done = false;
//priv->config_loaded = false; // loaded config still applies (_close is also called on _open)
libvgmstream_priv_reset(priv, true);
}

View file

@ -1,6 +1,7 @@
#include "api_internal.h"
#include "mixing.h"
#include "render.h"
#include "../util/log.h"
static bool reset_buf(libvgmstream_priv_t* priv) {
@ -46,15 +47,16 @@ static void update_buf(libvgmstream_priv_t* priv, int samples_done) {
priv->buf.bytes = samples_done * priv->buf.sample_size * priv->buf.channels;
//priv->buf.consumed = 0; //external
// mark done if this buf reached EOF
if (!priv->pos.play_forever) {
priv->decode_done = (priv->pos.current >= priv->pos.play_samples);
priv->pos.current += samples_done;
priv->decode_done = (priv->pos.current >= priv->pos.play_samples);
}
}
// update decoder info based on last render, though at the moment it's all fixed
static void update_decoder_info(libvgmstream_priv_t* priv, int samples_done) {
static void update_decoder_info(libvgmstream_priv_t* priv) {
// output copy
priv->dec.buf = priv->buf.data;
@ -68,6 +70,13 @@ LIBVGMSTREAM_API int libvgmstream_render(libvgmstream_t* lib) {
return LIBVGMSTREAM_ERROR_GENERIC;
libvgmstream_priv_t* priv = lib->priv;
// setup if not called (mainly to make sure mixing is enabled) //TODO: handle internally
// (for cases where _open_stream is called but not _setup)
if (!priv->setup_done) {
api_apply_config(priv);
}
if (priv->decode_done)
return LIBVGMSTREAM_ERROR_GENERIC;
@ -84,7 +93,7 @@ LIBVGMSTREAM_API int libvgmstream_render(libvgmstream_t* lib) {
int decoded = render_main(&ssrc, priv->vgmstream);
update_buf(priv, decoded);
update_decoder_info(priv, decoded);
update_decoder_info(priv);
return LIBVGMSTREAM_OK;
}
@ -161,6 +170,10 @@ LIBVGMSTREAM_API void libvgmstream_seek(libvgmstream_t* lib, int64_t sample) {
seek_vgmstream(priv->vgmstream, sample);
priv->pos.current = priv->vgmstream->pstate.play_position;
// update flags just in case
update_buf(priv, 0);
update_decoder_info(priv);
}

View file

@ -12,28 +12,33 @@ static int get_internal_log_level(libvgmstream_loglevel_t level) {
}
}
LIBVGMSTREAM_API void libvgmstream_set_log(libvgmstream_log_t* cfg) {
if (!cfg)
return;
int ilevel = get_internal_log_level(cfg->level);
if (cfg->stdout_callback) {
//vgmstream_set_log_stdout(ilevel);
vgm_log_set_callback(NULL, ilevel, 1, NULL);
LIBVGMSTREAM_API void libvgmstream_set_log(libvgmstream_loglevel_t level, void (*callback)(int level, const char* str)) {
int ilevel = get_internal_log_level(level);
if (callback) {
vgm_log_set_callback(NULL, ilevel, 0, callback);
}
else {
//vgmstream_set_log_callback(ilevel, cfg->callback);
vgm_log_set_callback(NULL, ilevel, 0, cfg->callback);
vgm_log_set_callback(NULL, ilevel, 1, NULL);
}
}
LIBVGMSTREAM_API const char** libvgmstream_get_extensions(size_t* size) {
return vgmstream_get_formats(size);
LIBVGMSTREAM_API const char** libvgmstream_get_extensions(int* size) {
if (!size)
return NULL;
size_t tmp = 0;
const char** list = vgmstream_get_formats(&tmp);
*size = tmp;
return list;
}
LIBVGMSTREAM_API const char** libvgmstream_get_common_extensions(size_t* size) {
return vgmstream_get_common_formats(size);
LIBVGMSTREAM_API const char** libvgmstream_get_common_extensions(int* size) {
if (!size)
return NULL;
size_t tmp = 0;
const char** list = vgmstream_get_common_formats(&tmp);
*size = tmp;
return list;
}

View file

@ -33,31 +33,36 @@ typedef struct {
} libvgmstream_priv_buf_t;
// used to calculate and stop stream (to be removed once VGMSTREAM can stop on its own)
typedef struct {
int64_t play_forever;
int64_t play_samples;
int64_t current;
} libvgmstream_priv_position_t;
/* vgmstream context/handle */
// vgmstream context/handle
typedef struct {
libvgmstream_format_t fmt; // externally exposed
libvgmstream_decoder_t dec; // externally exposed
// externally exposed to API
libvgmstream_format_t fmt;
libvgmstream_decoder_t dec;
libvgmstream_config_t cfg; // internal copy
// internals
libvgmstream_config_t cfg;
VGMSTREAM* vgmstream;
libvgmstream_priv_buf_t buf;
libvgmstream_priv_position_t pos;
bool config_loaded;
bool setup_done;
bool decode_done;
} libvgmstream_priv_t;
void libvgmstream_priv_reset(libvgmstream_priv_t* priv, bool reset_buf);
libvgmstream_sample_t api_get_output_sample_type(libvgmstream_priv_t* priv);
int api_get_sample_size(libvgmstream_sample_t sample_type);
void libvgmstream_priv_reset(libvgmstream_priv_t* priv, bool full);
libvgmstream_sfmt_t api_get_output_sample_type(libvgmstream_priv_t* priv);
int api_get_sample_size(libvgmstream_sfmt_t sample_format);
void api_apply_config(libvgmstream_priv_t* priv);
STREAMFILE* open_api_streamfile(libstreamfile_t* libsf);

View file

@ -5,63 +5,23 @@ static libstreamfile_t* libstreamfile_from_streamfile(STREAMFILE* sf);
/* libstreamfile_t for external use, as a default implementation calling some internal SF */
typedef struct {
int64_t offset;
int64_t size;
STREAMFILE* sf;
char name[PATH_LIMIT];
} libsf_priv_t;
static int libsf_read(void* user_data, uint8_t* dst, int dst_size) {
static int libsf_read(void* user_data, uint8_t* dst, int64_t offset, int length) {
libsf_priv_t* priv = user_data;
if (!priv || !dst)
return 0;
int bytes = priv->sf->read(priv->sf, dst, priv->offset, dst_size);
priv->offset += bytes;
return bytes;
}
static int64_t libsf_seek(void* user_data, int64_t offset, int whence) {
libsf_priv_t* priv = user_data;
if (!priv)
return -1;
switch (whence) {
case LIBSTREAMFILE_SEEK_SET: /* absolute */
break;
case LIBSTREAMFILE_SEEK_CUR: /* relative to current */
offset += priv->offset;
break;
case LIBSTREAMFILE_SEEK_END: /* relative to file end (should be negative) */
offset += priv->size;
break;
default:
break;
}
/* clamp offset like fseek */
if (offset > priv->size)
offset = priv->size;
else if (offset < 0)
offset = 0;
/* main seek */
priv->offset = offset;
return 0;
return priv->sf->read(priv->sf, dst, offset, length);
}
static int64_t libsf_get_size(void* user_data) {
libsf_priv_t* priv = user_data;
if (!priv)
return 0;
return priv->size;
return priv->sf->get_size(priv->sf);
}
static const char* libsf_get_name(void* user_data) {
libsf_priv_t* priv = user_data;
if (!priv)
return NULL;
if (priv->name[0] == '\0') {
priv->sf->get_name(priv->sf, priv->name, sizeof(priv->name));
@ -72,7 +32,8 @@ static const char* libsf_get_name(void* user_data) {
static libstreamfile_t* libsf_open(void* user_data, const char* filename) {
libsf_priv_t* priv = user_data;
if (!priv || !priv->sf || !filename)
if (!filename)
return NULL;
STREAMFILE* sf = priv->sf->open(priv->sf, filename, 0);
@ -104,14 +65,11 @@ static libstreamfile_t* libstreamfile_from_streamfile(STREAMFILE* sf) {
if (!sf)
return NULL;
libstreamfile_t* libsf = NULL;
libsf_priv_t* priv = NULL;
libsf = calloc(1, sizeof(libstreamfile_t));
libstreamfile_t* libsf = calloc(1, sizeof(libstreamfile_t));
if (!libsf) goto fail;
libsf->read = libsf_read;
libsf->seek = libsf_seek;
libsf->get_size = libsf_get_size;
libsf->get_name = libsf_get_name;
libsf->open = libsf_open;

View file

@ -18,10 +18,10 @@ typedef struct {
char name[PATH_LIMIT];
} cache_priv_t;
static int cache_read(void* user_data, uint8_t* dst, int dst_size) {
static int cache_read(void* user_data, uint8_t* dst, int64_t offset, int length) {
cache_priv_t* priv = user_data;
size_t read_total = 0;
if (!dst || dst_size <= 0)
if (!dst || length <= 0 || offset < 0)
return 0;
/* is the part of the requested length in the buffer? */
@ -30,19 +30,22 @@ static int cache_read(void* user_data, uint8_t* dst, int dst_size) {
int buf_into = (int)(priv->offset - priv->buf_offset);
buf_limit = priv->valid_size - buf_into;
if (buf_limit > dst_size)
buf_limit = dst_size;
if (buf_limit > length)
buf_limit = length;
memcpy(dst, priv->buf + buf_into, buf_limit);
read_total += buf_limit;
dst_size -= buf_limit;
length -= buf_limit;
priv->offset += buf_limit;
dst += buf_limit;
}
/* possible if all data was copied to buf and FD closed */
if (!priv->libsf)
return read_total;
/* read the rest of the requested length */
while (dst_size > 0) {
while (length > 0) {
size_t buf_limit;
/* ignore requests at EOF */
@ -52,18 +55,15 @@ static int cache_read(void* user_data, uint8_t* dst, int dst_size) {
break;
}
/* position to new offset */
priv->libsf->seek(priv, priv->offset, 0);
/* fill the buffer (offset now is beyond buf_offset) */
priv->buf_offset = priv->offset;
priv->valid_size = priv->libsf->read(priv, priv->buf, priv->buf_size);
priv->valid_size = priv->libsf->read(priv, priv->buf, priv->buf_offset, priv->buf_size);
/* decide how much must be read this time */
if (dst_size > priv->buf_size)
if (length > priv->buf_size)
buf_limit = priv->buf_size;
else
buf_limit = dst_size;
buf_limit = length;
/* give up on partial reads (EOF) */
if (priv->valid_size < buf_limit) {
@ -77,40 +77,14 @@ static int cache_read(void* user_data, uint8_t* dst, int dst_size) {
memcpy(dst, priv->buf, buf_limit);
priv->offset += buf_limit;
read_total += buf_limit;
dst_size -= buf_limit;
length -= buf_limit;
dst += buf_limit;
}
priv->offset = offset; /* last fread offset */
return read_total;
}
static int64_t cache_seek(void* user_data, int64_t offset, int whence) {
cache_priv_t* priv = user_data;
switch (whence) {
case LIBSTREAMFILE_SEEK_SET: /* absolute */
break;
case LIBSTREAMFILE_SEEK_CUR: /* relative to current */
offset += priv->offset;
break;
case LIBSTREAMFILE_SEEK_END: /* relative to file end (should be negative) */
offset += priv->file_size;
break;
default:
break;
}
/* clamp offset like fseek */
if (offset > priv->file_size)
offset = priv->file_size;
else if (offset < 0)
offset = 0;
/* main seek */
priv->offset = offset;
return 0;
}
static int64_t cache_get_size(void* user_data) {
cache_priv_t* priv = user_data;
return priv->file_size;
@ -168,7 +142,6 @@ LIBVGMSTREAM_API libstreamfile_t* libstreamfile_open_buffered(libstreamfile_t* e
if (!libsf) goto fail;
libsf->read = cache_read;
libsf->seek = cache_seek;
libsf->get_size = cache_get_size;
libsf->get_name = cache_get_name;
libsf->open = cache_open;

View file

@ -0,0 +1,43 @@
#include "codec_info.h"
//TODO: move to root folder?
extern const codec_info_t ka1a_decoder;
extern const codec_info_t ubimpeg_decoder;
extern const codec_info_t hca_decoder;
#ifdef VGM_USE_VORBIS
extern const codec_info_t vorbis_custom_decoder;
#endif
extern const codec_info_t tac_decoder;
extern const codec_info_t compresswave_decoder;
extern const codec_info_t speex_decoder;
extern const codec_info_t imuse_decoder;
extern const codec_info_t mio_decoder;
const codec_info_t* codec_get_info(VGMSTREAM* v) {
switch(v->coding_type) {
case coding_CRI_HCA:
return &hca_decoder;
case coding_KA1A:
return &ka1a_decoder;
case coding_UBI_MPEG:
return &ubimpeg_decoder;
#ifdef VGM_USE_VORBIS
case coding_VORBIS_custom:
return &vorbis_custom_decoder;
#endif
case coding_TAC:
return &tac_decoder;
case coding_COMPRESSWAVE:
return &compresswave_decoder;
#ifdef VGM_USE_SPEEX
case coding_SPEEX:
return &speex_decoder;
#endif
case coding_IMUSE:
return &imuse_decoder;
case coding_MIO:
return &mio_decoder;
default:
return NULL;
}
}

View file

@ -0,0 +1,33 @@
#ifndef _CODEC_INFO_H
#define _CODEC_INFO_H
#include <stdint.h>
#include <stdbool.h>
#include "../vgmstream.h"
#include "../base/sbuf.h"
/* Class-like definition for codecs.
*/
typedef struct {
//int (*init)();
sfmt_t sample_type; // fixed for most cases; if not set will be assumed to be PCM16
sfmt_t (*get_sample_type)(VGMSTREAM* v); //variable for codecs with variations depending on data
bool (*decode_frame)(VGMSTREAM* v);
void (*free)(void* codec_data);
void (*reset)(void* codec_data);
void (*seek)(VGMSTREAM* v, int32_t num_sample);
// info for vgmstream
//uint32_t flags;
// alloc size of effect's private data (don't set to manage manually in init/free)
//int priv_size;
//int sample_type;
//int get_sample_type();
} codec_info_t;
const codec_info_t* codec_get_info(VGMSTREAM* v);
#endif

View file

@ -5,6 +5,7 @@
#include "mixing.h"
#include "plugins.h"
#include "sbuf.h"
#include "codec_info.h"
#include "../util/log.h"
#include "decode_state.h"
@ -39,14 +40,16 @@ void decode_free(VGMSTREAM* vgmstream) {
if (!vgmstream->codec_data)
return;
const codec_info_t* codec_info = codec_get_info(vgmstream);
if (codec_info) {
codec_info->free(vgmstream->codec_data);
return;
}
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type == coding_OGG_VORBIS) {
free_ogg_vorbis(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_VORBIS_custom) {
free_vorbis_custom(vgmstream->codec_data);
}
#endif
if (vgmstream->coding_type == coding_CIRCUS_VQ) {
@ -57,14 +60,6 @@ void decode_free(VGMSTREAM* vgmstream) {
free_relic(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_CRI_HCA) {
free_hca(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_TAC) {
free_tac(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_ICE_RANGE ||
vgmstream->coding_type == coding_ICE_DCT) {
free_ice(vgmstream->codec_data);
@ -74,26 +69,14 @@ void decode_free(VGMSTREAM* vgmstream) {
free_ubi_adpcm(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_IMUSE) {
free_imuse(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_ONGAKUKAN_ADPCM) {
free_ongakukan_adp(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_COMPRESSWAVE) {
free_compresswave(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_EA_MT) {
free_ea_mt(vgmstream->codec_data, vgmstream->channels);
}
if (vgmstream->coding_type == coding_KA1A) {
free_ka1a(vgmstream->codec_data);
}
#ifdef VGM_USE_FFMPEG
if (vgmstream->coding_type == coding_FFmpeg) {
free_ffmpeg(vgmstream->codec_data);
@ -140,12 +123,6 @@ void decode_free(VGMSTREAM* vgmstream) {
}
#endif
#ifdef VGM_USE_SPEEX
if (vgmstream->coding_type == coding_SPEEX) {
free_speex(vgmstream->codec_data);
}
#endif
if (vgmstream->coding_type == coding_ACM) {
free_acm(vgmstream->codec_data);
}
@ -162,6 +139,12 @@ void decode_seek(VGMSTREAM* vgmstream) {
if (!vgmstream->codec_data)
return;
const codec_info_t* codec_info = codec_get_info(vgmstream);
if (codec_info) {
codec_info->seek(vgmstream, vgmstream->loop_current_sample);
return;
}
if (vgmstream->coding_type == coding_CIRCUS_VQ) {
seek_circus_vq(vgmstream->codec_data, vgmstream->loop_current_sample);
}
@ -170,14 +153,6 @@ void decode_seek(VGMSTREAM* vgmstream) {
seek_relic(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_CRI_HCA) {
loop_hca(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_TAC) {
seek_tac(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_ICE_RANGE ||
vgmstream->coding_type == coding_ICE_DCT) {
seek_ice(vgmstream->codec_data, vgmstream->loop_current_sample);
@ -187,34 +162,18 @@ void decode_seek(VGMSTREAM* vgmstream) {
seek_ubi_adpcm(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_IMUSE) {
seek_imuse(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_ONGAKUKAN_ADPCM) {
seek_ongakukan_adp(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_COMPRESSWAVE) {
seek_compresswave(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_EA_MT) {
seek_ea_mt(vgmstream, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_KA1A) {
seek_ka1a(vgmstream, vgmstream->loop_current_sample);
}
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type == coding_OGG_VORBIS) {
seek_ogg_vorbis(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_VORBIS_custom) {
seek_vorbis_custom(vgmstream, vgmstream->loop_current_sample);
}
#endif
#ifdef VGM_USE_FFMPEG
@ -241,12 +200,6 @@ void decode_seek(VGMSTREAM* vgmstream) {
}
#endif
#ifdef VGM_USE_SPEEX
if (vgmstream->coding_type == coding_SPEEX) {
seek_speex(vgmstream, vgmstream->loop_current_sample);
}
#endif
#ifdef VGM_USE_MPEG
if (vgmstream->coding_type == coding_MPEG_custom ||
vgmstream->coding_type == coding_MPEG_ealayer3 ||
@ -269,14 +222,16 @@ void decode_reset(VGMSTREAM* vgmstream) {
if (!vgmstream->codec_data)
return;
const codec_info_t* codec_info = codec_get_info(vgmstream);
if (codec_info) {
codec_info->reset(vgmstream->codec_data);
return;
}
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type == coding_OGG_VORBIS) {
reset_ogg_vorbis(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_VORBIS_custom) {
reset_vorbis_custom(vgmstream);
}
#endif
if (vgmstream->coding_type == coding_CIRCUS_VQ) {
@ -287,14 +242,6 @@ void decode_reset(VGMSTREAM* vgmstream) {
reset_relic(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_CRI_HCA) {
reset_hca(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_TAC) {
reset_tac(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_ICE_RANGE ||
vgmstream->coding_type == coding_ICE_DCT) {
reset_ice(vgmstream->codec_data);
@ -304,26 +251,14 @@ void decode_reset(VGMSTREAM* vgmstream) {
reset_ubi_adpcm(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_IMUSE) {
reset_imuse(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_ONGAKUKAN_ADPCM) {
reset_ongakukan_adp(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_COMPRESSWAVE) {
reset_compresswave(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_EA_MT) {
reset_ea_mt(vgmstream);
}
if (vgmstream->coding_type == coding_KA1A) {
reset_ka1a(vgmstream->codec_data);
}
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
if (vgmstream->coding_type == coding_MP4_AAC) {
reset_mp4_aac(vgmstream);
@ -364,12 +299,6 @@ void decode_reset(VGMSTREAM* vgmstream) {
}
#endif
#ifdef VGM_USE_SPEEX
if (vgmstream->coding_type == coding_SPEEX) {
reset_speex(vgmstream->codec_data);
}
#endif
#ifdef VGM_USE_FFMPEG
if (vgmstream->coding_type == coding_FFmpeg) {
reset_ffmpeg(vgmstream->codec_data);
@ -433,7 +362,6 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) {
return 1;
#ifdef VGM_USE_VORBIS
case coding_OGG_VORBIS:
case coding_VORBIS_custom:
#endif
#ifdef VGM_USE_MPEG
case coding_MPEG_custom:
@ -586,18 +514,12 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) {
return 0; /* varies per frame */
case coding_ONGAKUKAN_ADPCM:
return 0; /* actually 1. */
case coding_COMPRESSWAVE:
return 0; /* multiple of 2 */
case coding_EA_MT:
return 0; /* 432, but variable in looped files */
case coding_CIRCUS_VQ:
return 0;
case coding_RELIC:
return 0; /* 512 */
case coding_CRI_HCA:
return 0; /* 1024 - delay/padding (which can be bigger than 1024) */
case coding_TAC:
return 0; /* 1024 - delay/padding */
case coding_ICE_RANGE:
case coding_ICE_DCT:
return 0; /* ~100 (range), ~16 (DCT) */
@ -612,10 +534,6 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) {
#ifdef VGM_USE_CELT
case coding_CELT_FSB:
return 0; /* 512? */
#endif
#ifdef VGM_USE_SPEEX
case coding_SPEEX:
return 0;
#endif
default:
return 0;
@ -807,12 +725,9 @@ int decode_get_frame_size(VGMSTREAM* vgmstream) {
/* UBI_ADPCM: varies per mode? */
/* IMUSE: VBR */
/* EA_MT: VBR, frames of bit counts or PCM frames */
/* COMPRESSWAVE: VBR/huffman bits */
/* ATRAC9: CBR around 0x100-200 */
/* CELT FSB: varies, usually 0x80-100 */
/* SPEEX: varies, usually 0x40-60 */
/* TAC: VBR around ~0x200-300 */
/* Vorbis, MPEG, ACM, etc: varies */
default: /* (VBR or managed by decoder) */
return 0;
}
@ -875,6 +790,7 @@ static void decode_frames(sbuf_t* sdst, VGMSTREAM* vgmstream) {
decode_state_t* ds = vgmstream->decode_state;
sbuf_t* ssrc = &ds->sbuf;
const codec_info_t* codec_info = codec_get_info(vgmstream);
// fill the external buf by decoding N times; may read partially that buf
while (sdst->filled < sdst->samples) {
@ -882,11 +798,11 @@ static void decode_frames(sbuf_t* sdst, VGMSTREAM* vgmstream) {
// decode new frame if prev one was consumed
if (ssrc->filled == 0) {
bool ok = false;
switch (vgmstream->coding_type) {
case coding_KA1A:
ok = decode_ka1a_frame(vgmstream);
break;
default:
if (codec_info) {
ok = codec_info->decode_frame(vgmstream);
}
else {
goto decode_fail;
}
@ -902,6 +818,9 @@ static void decode_frames(sbuf_t* sdst, VGMSTREAM* vgmstream) {
goto decode_fail;
}
}
else {
num_empty = 0; //reset for discard loops
}
if (ds->discard) {
// decoder may signal that samples need to be discarded (ex. encoder delay or during loops)
@ -1233,10 +1152,6 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
case coding_OGG_VORBIS:
decode_ogg_vorbis(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels);
break;
case coding_VORBIS_custom:
decode_vorbis_custom(vgmstream, buffer, samples_to_do, vgmstream->channels);
break;
#endif
case coding_CIRCUS_VQ:
decode_circus_vq(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels);
@ -1244,12 +1159,6 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
case coding_RELIC:
decode_relic(&vgmstream->ch[0], vgmstream->codec_data, buffer, samples_to_do);
break;
case coding_CRI_HCA:
decode_hca(vgmstream->codec_data, buffer, samples_to_do);
break;
case coding_TAC:
decode_tac(vgmstream, buffer, samples_to_do);
break;
case coding_ICE_RANGE:
case coding_ICE_DCT:
decode_ice(vgmstream->codec_data, buffer, samples_to_do);
@ -1482,11 +1391,6 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
case coding_CELT_FSB:
decode_celt_fsb(vgmstream, buffer, samples_to_do, vgmstream->channels);
break;
#endif
#ifdef VGM_USE_SPEEX
case coding_SPEEX:
decode_speex(vgmstream, buffer, samples_to_do);
break;
#endif
case coding_ACM:
decode_acm(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels);
@ -1656,18 +1560,10 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
decode_ubi_adpcm(vgmstream, buffer, samples_to_do);
break;
case coding_IMUSE:
decode_imuse(vgmstream, buffer, samples_to_do);
break;
case coding_ONGAKUKAN_ADPCM:
decode_ongakukan_adp(vgmstream, buffer, samples_to_do);
break;
case coding_COMPRESSWAVE:
decode_compresswave(vgmstream->codec_data, buffer, samples_to_do);
break;
case coding_EA_MT:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_ea_mt(vgmstream, buffer+ch, vgmstream->channels, samples_to_do, ch);

View file

@ -330,7 +330,7 @@ static STREAMFILE* get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM* v
}
if (vgmstream->coding_type == coding_COMPRESSWAVE) {
return compresswave_get_streamfile(vgmstream->codec_data);
return compresswave_get_streamfile(vgmstream);
}
#ifdef VGM_USE_VORBIS

View file

@ -116,7 +116,7 @@ void mixer_process(mixer_t* mixer, sbuf_t* sbuf, int32_t current_pos) {
setup_mixbuf(mixer, sbuf);
// apply mixing ops in order. channesl in mixersmix may increase or decrease per op
// apply mixing ops in order. channels in mixers may increase or decrease per op (set in sbuf)
// - 2ch w/ "1+2,1u" = ch1+ch2, ch1(add and push rest) = 3ch: ch1' ch1+ch2 ch2
// - 2ch w/ "1u" = downmix to 1ch (current_channels decreases once)
for (int m = 0; m < mixer->chain_count; m++) {

View file

@ -125,8 +125,11 @@ void mixer_op_fade(mixer_t* mixer, mix_op_t* mix) {
//TODO optimize for case 0?
for (int s = 0; s < smix->filled; s++) {
bool fade_applies = get_fade_gain(mix, &new_gain, current_subpos);
if (!fade_applies) //TODO optimize?
if (!fade_applies) { //TODO optimize?
dst += channels;
current_subpos++;
continue;
}
if (mix->ch_dst < 0) {
for (int ch = 0; ch < channels; ch++) {

View file

@ -7,6 +7,7 @@
#include "mixer.h"
#include "mixer_priv.h"
#include "sbuf.h"
#include "codec_info.h"
/* Wrapper/helpers for vgmstream's "mixer", which does main sample buffer transformations */
@ -143,9 +144,20 @@ void mixing_info(VGMSTREAM* vgmstream, int* p_input_channels, int* p_output_chan
}
sfmt_t mixing_get_input_sample_type(VGMSTREAM* vgmstream) {
const codec_info_t* codec_info = codec_get_info(vgmstream);
if (codec_info) {
if (codec_info->sample_type)
return codec_info->sample_type;
if (codec_info->get_sample_type)
return codec_info->get_sample_type(vgmstream);
}
// TODO: on layered/segments, detect biggest value and use that (ex. if one of the layers uses flt > flt)
switch(vgmstream->coding_type) {
case coding_KA1A:
#ifdef VGM_USE_VORBIS
case coding_VORBIS_custom:
#endif
return SFMT_FLT;
default:
return SFMT_S16;

View file

@ -569,7 +569,7 @@ void mixing_macro_downmix(VGMSTREAM* vgmstream, int max /*, mapping_t output_map
void mixing_macro_output_sample_format(VGMSTREAM* vgmstream, sfmt_t type) {
mixer_t* mixer = vgmstream->mixer;
if (!mixer)
if (!mixer || !type)
return;
// optimization (may skip initializing mixer)
@ -577,4 +577,5 @@ void mixing_macro_output_sample_format(VGMSTREAM* vgmstream, sfmt_t type) {
if (input_fmt == type)
return;
mixer->force_type = type;
mixer->has_non_fade = true;
}

View file

@ -1,10 +1,16 @@
#include <stdlib.h>
#include <string.h>
//#include <math.h>
#include "../util.h"
#include "sbuf.h"
#include "../util/log.h"
// float-to-int modes
//#define PCM16_ROUNDING_LRINT // potentially faster in some systems/compilers and much slower in others
//#define PCM16_ROUNDING_HALF // rounding half + down (vorbis-style), more 'accurate' but slower
#ifdef PCM16_ROUNDING_HALF
#include <math.h>
#endif
void sbuf_init(sbuf_t* sbuf, sfmt_t format, void* buf, int samples, int channels) {
memset(sbuf, 0, sizeof(sbuf_t));
@ -48,6 +54,8 @@ void* sbuf_get_filled_buf(sbuf_t* sbuf) {
}
void sbuf_consume(sbuf_t* sbuf, int samples) {
if (samples == 0) //some discards
return;
int sample_size = sfmt_get_sample_size(sbuf->fmt);
if (sample_size <= 0) //???
return;
@ -67,7 +75,7 @@ void sbuf_consume(sbuf_t* sbuf, int samples) {
* alts for more accurate rounding could be:
* - (int)floor(f)
* - (int)(f < 0 ? f - 0.5f : f + 0.5f)
* - (((int) (f1 + 32768.5)) - 32768)
* - (((int) (f1 + 32767.5)) - 32767)
* - etc
* but since +-1 isn't really audible we'll just cast, as it's the fastest
*
@ -77,22 +85,22 @@ void sbuf_consume(sbuf_t* sbuf, int samples) {
* It's slightly faster (~5%) but causes fuzzy PCM<>float<>PCM conversions.
*/
static inline int float_to_int(float val) {
#if 1
return (int)val;
#if PCM16_ROUNDING_LRINT
return lrintf(val);
#elif defined(_MSC_VER)
return (int)val;
#else
return lrintf(val);
return (int)val;
#endif
}
static inline int double_to_int(double val) {
#if 1
return (int)val;
#if PCM16_ROUNDING_LRINT
return lrint(val);
#elif defined(_MSC_VER)
return (int)val;
#else
return lrint(val);
return (int)val;
#endif
}
@ -122,7 +130,7 @@ void sbuf_copy_to_f32(float* dst, sbuf_t* sbuf) {
case SFMT_FLT: {
float* src = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = src[s] * 32768.0f;
dst[s] = src[s] * 32767.0f;
}
break;
}
@ -150,7 +158,7 @@ void sbuf_copy_from_f32(sbuf_t* sbuf, float* src) {
case SFMT_FLT: {
float* dst = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = src[s] / 32768.0f;
dst[s] = src[s] / 32767.0f;
}
break;
}
@ -175,14 +183,26 @@ int sbuf_get_copy_max(sbuf_t* sdst, sbuf_t* ssrc) {
dst[dst_pos++] = src[src_pos++]; \
}
#define sbuf_copy_segments_internal_f16(dst, src, src_pos, dst_pos, src_max) \
while (src_pos < src_max) { \
dst[dst_pos++] = clamp16(float_to_int(src[src_pos++])); \
}
#ifdef PCM16_ROUNDING_HALF
#define sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, value) \
while (src_pos < src_max) { \
dst[dst_pos++] = clamp16(float_to_int( floor(src[src_pos++] * value + 0.5f) )); \
}
#else
#define sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, value) \
while (src_pos < src_max) { \
dst[dst_pos++] = clamp16(float_to_int(src[src_pos++] * value)); \
}
#endif
#define sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, value) \
while (src_pos < src_max) { \
dst[dst_pos++] = float_to_int(src[src_pos++] * value); \
dst[dst_pos++] = (src[src_pos++] * value); \
}
// copy N samples from ssrc into dst (should be clamped externally)
@ -191,7 +211,7 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
if (ssrc->channels != sdst->channels) {
// 0'd other channels first (uncommon so probably fine albeit slower-ish)
sbuf_silence_part(sdst, sdst->filled, samples_copy);
sbuf_copy_layers(sdst, ssrc, 0, ssrc->filled);
sbuf_copy_layers(sdst, ssrc, 0, samples_copy);
#if 0
// "faster" but lots of extra ifs per sample format, not worth it
while (src_pos < src_max) {
@ -210,49 +230,54 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
int src_max = samples_copy * ssrc->channels;
// define all posible combos, probably there is a better way to handle this but...
if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_S16) {
int16_t* dst = sdst->buf;
// s16 > s16
if (ssrc->fmt == SFMT_S16 && sdst->fmt == SFMT_S16) {
int16_t* src = ssrc->buf;
int16_t* dst = sdst->buf;
sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max);
}
else if (sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_S16) {
float* dst = sdst->buf;
// s16 > f32
else if (ssrc->fmt == SFMT_S16 && sdst->fmt == SFMT_F32) {
int16_t* src = ssrc->buf;
float* dst = sdst->buf;
sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max);
}
else if ((sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_F32) || (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_FLT)) {
// s16 > flt
else if (ssrc->fmt == SFMT_S16 && sdst->fmt == SFMT_FLT) {
int16_t* src = ssrc->buf;
float* dst = sdst->buf;
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, (1.0f / 32767.0f));
}
// f32 > f32 / flt > flt
else if ((ssrc->fmt == SFMT_F32 && sdst->fmt == SFMT_F32) ||
(ssrc->fmt == SFMT_FLT && sdst->fmt == SFMT_FLT)) {
float* src = ssrc->buf;
float* dst = sdst->buf;
sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max);
}
// to s16
else if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_F32) {
// f32 > s16
else if (ssrc->fmt == SFMT_F32 && sdst->fmt == SFMT_S16) {
float* src = ssrc->buf;
int16_t* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, 1.0f);
sbuf_copy_segments_internal_f16(dst, src, src_pos, dst_pos, src_max);
}
else if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_FLT) {
// flt > s16
else if (ssrc->fmt == SFMT_FLT && sdst->fmt == SFMT_S16) {
float* src = ssrc->buf;
int16_t* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, 32768.0f);
sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, 32767.0f);
}
// to f32
else if (sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_FLT) {
float* dst = sdst->buf;
// f32 > flt
else if (ssrc->fmt == SFMT_F32 && sdst->fmt == SFMT_FLT) {
float* src = ssrc->buf;
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, 32768.0f);
}
// to flt
else if (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_S16) {
float* dst = sdst->buf;
int16_t* src = ssrc->buf;
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, (1/32768.0f));
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, (1.0f / 32767.0f));
}
else if (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_F32) {
float* dst = sdst->buf;
// flt > f32
else if (ssrc->fmt == SFMT_FLT && sdst->fmt == SFMT_F32) {
float* src = ssrc->buf;
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, (1/32768.0f));
float* dst = sdst->buf;
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, 32767.0f);
}
//TODO: may want to handle externally?
@ -260,6 +285,14 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
}
#define sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step) \
for (int s = src_filled; s < dst_expected; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = 0; \
} \
dst_pos += dst_ch_step; \
}
//TODO fix missing ->channels
/* ugly thing to avoid repeating functions */
#define sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step) \
@ -270,14 +303,32 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
dst_pos += dst_ch_step; \
} \
\
for (int s = src_filled; s < dst_expected; s++) { \
sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
// float +-1.0 <> pcm +-32767.0
#define sbuf_copy_layers_internal_f16(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step) \
for (int s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = 0; \
dst[dst_pos++] = clamp16(float_to_int(src[src_pos++])); \
} \
dst_pos += dst_ch_step; \
}
} \
\
sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
// float +-1.0 <> pcm +-32768.0
#ifdef PCM16_ROUNDING_HALF
// float +-1.0 <> pcm +-32767.0
#define sbuf_copy_layers_internal_s16(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, value) \
for (int s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = clamp16(float_to_int( floor(src[src_pos++] * value + 0.5f) )); \
} \
dst_pos += dst_ch_step; \
} \
\
sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
#else
// float +-1.0 <> pcm +-32767.0
#define sbuf_copy_layers_internal_s16(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, value) \
for (int s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
@ -286,14 +337,10 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
dst_pos += dst_ch_step; \
} \
\
for (int s = src_filled; s < dst_expected; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = 0; \
} \
dst_pos += dst_ch_step; \
}
sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
#endif
// float +-1.0 <> pcm +-32768.0
// float +-1.0 <> pcm +-32767.0
#define sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, value) \
for (int s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
@ -302,68 +349,72 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
dst_pos += dst_ch_step; \
} \
\
for (int s = src_filled; s < dst_expected; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = 0; \
} \
dst_pos += dst_ch_step; \
}
sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
/* copy interleaving: dst ch1 ch2 ch3 ch4 w/ src ch1 ch2 ch1 ch2 = only fill dst ch1 ch2 */
// dst_channels == src_channels isn't likely so ignore that optimization
// copy interleaving: dst ch1 ch2 ch3 ch4 w/ src ch1 ch2 ch1 ch2 = only fill dst ch1 ch2
// dst_channels == src_channels isn't likely so ignore that optimization (dst must be >= than src).
// dst_ch_start indicates it should write to dst's chN,chN+1,etc
// sometimes one layer has less samples than others and need to 0-fill rest
void sbuf_copy_layers(sbuf_t* sdst, sbuf_t* ssrc, int dst_ch_start, int dst_expected) {
int src_filled = ssrc->filled;
void sbuf_copy_layers(sbuf_t* sdst, sbuf_t* ssrc, int dst_ch_start, int dst_max) {
int src_copy = dst_max;
int src_channels = ssrc->channels;
int dst_ch_step = (sdst->channels - ssrc->channels); \
int dst_ch_step = (sdst->channels - ssrc->channels);
int src_pos = 0;
int dst_pos = sdst->filled * sdst->channels + dst_ch_start;
if (src_copy > ssrc->filled)
src_copy = ssrc->filled;
if (ssrc->channels > sdst->channels) {
VGM_LOG("SBUF: wrong copy\n");
return;
}
// define all posible combos, probably there is a better way to handle this but...
// 1:1
if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_S16) {
int16_t* dst = sdst->buf;
int16_t* src = ssrc->buf;
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step);
}
else if (sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_S16) {
float* dst = sdst->buf;
int16_t* src = ssrc->buf;
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step);
}
else if ((sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_F32) || (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_FLT)) {
float* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step);
}
// to s16
else if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_F32) {
int16_t* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_layers_internal_s16(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, 1.0f);
sbuf_copy_layers_internal_f16(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step);
}
else if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_FLT) {
int16_t* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_layers_internal_s16(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, 32768.0f);
sbuf_copy_layers_internal_s16(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step, 32767.0f);
}
// to f32
else if (sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_FLT) {
float* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, 32768.0f);
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step, 32767.0f);
}
// to flt
else if (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_S16) {
float* dst = sdst->buf;
int16_t* src = ssrc->buf;
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, (1/32768.0f));
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step, (1.0f / 32767.0f));
}
else if (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_F32) {
float* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, (1/32768.0f));
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step, (1.0f / 32767.0f));
}
}
@ -428,3 +479,29 @@ void sbuf_fadeout(sbuf_t* sbuf, int start, int to_do, int fade_pos, int fade_dur
int count = sbuf->filled - (start + to_do);
sbuf_silence_part(sbuf, start + to_do, count);
}
void sbuf_interleave(sbuf_t* sbuf, float** ibuf) {
if (sbuf->fmt != SFMT_FLT)
return;
// copy multidimensional buf (pcm[0]=[ch0,ch0,...], pcm[1]=[ch1,ch1,...])
// to interleaved buf (buf[0]=ch0, sbuf[1]=ch1, sbuf[2]=ch0, sbuf[3]=ch1, ...)
for (int ch = 0; ch < sbuf->channels; ch++) {
/* channels should be in standard order unlike Ogg Vorbis (at least in FSB) */
float* ptr = sbuf->buf;
float* channel = ibuf[ch];
ptr += ch;
for (int s = 0; s < sbuf->filled; s++) {
float val = channel[s];
#if 0 //to pcm16 //from vorbis)
int val = (int)floor(channel[s] * 32767.0f + 0.5f);
if (val > 32767) val = 32767;
else if (val < -32768) val = -32768;
#endif
*ptr = val;
ptr += sbuf->channels;
}
}
}

View file

@ -57,4 +57,6 @@ void sbuf_silence_part(sbuf_t* sbuf, int from, int count);
void sbuf_fadeout(sbuf_t* sbuf, int start, int to_do, int fade_pos, int fade_duration);
void sbuf_interleave(sbuf_t* sbuf, float** ibuf);
#endif

View file

@ -15,8 +15,7 @@ typedef struct {
static size_t api_read(API_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) {
void* user_data = sf->libsf->user_data;
sf->libsf->seek(sf->libsf->user_data, offset, LIBSTREAMFILE_SEEK_SET);
return sf->libsf->read(user_data, dst, length);
return sf->libsf->read(user_data, dst, offset, length);
}
static size_t api_get_size(API_STREAMFILE* sf) {

View file

@ -288,13 +288,8 @@ int32_t ubi_adpcm_get_samples(ubi_adpcm_codec_data* data);
/* imuse_decoder */
typedef struct imuse_codec_data imuse_codec_data;
imuse_codec_data* init_imuse(STREAMFILE* sf, int channels);
void decode_imuse(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do);
void reset_imuse(imuse_codec_data* data);
void seek_imuse(imuse_codec_data* data, int32_t num_sample);
void free_imuse(imuse_codec_data* data);
void* init_imuse_mcomp(STREAMFILE* sf, int channels);
void* init_imuse_aifc(STREAMFILE* sf, uint32_t start_offset, int channels);
/* ongakukan_adp_decoder */
typedef struct ongakukan_adp_data ongakukan_adp_data;
@ -308,14 +303,8 @@ void free_ongakukan_adp(ongakukan_adp_data* data);
int32_t ongakukan_adp_get_samples(ongakukan_adp_data* data);
/* compresswave_decoder */
typedef struct compresswave_codec_data compresswave_codec_data;
compresswave_codec_data* init_compresswave(STREAMFILE* sf);
void decode_compresswave(compresswave_codec_data* data, sample_t* outbuf, int32_t samples_to_do);
void reset_compresswave(compresswave_codec_data* data);
void seek_compresswave(compresswave_codec_data* data, int32_t num_sample);
void free_compresswave(compresswave_codec_data* data);
STREAMFILE* compresswave_get_streamfile(compresswave_codec_data* data);
void* init_compresswave(STREAMFILE* sf);
STREAMFILE* compresswave_get_streamfile(VGMSTREAM* v);
/* ea_mt_decoder*/
@ -346,10 +335,8 @@ int32_t relic_bytes_to_samples(size_t bytes, int channels, int bitrate);
typedef struct hca_codec_data hca_codec_data;
hca_codec_data* init_hca(STREAMFILE* sf);
void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do);
void reset_hca(hca_codec_data* data);
void loop_hca(hca_codec_data* data, int32_t num_sample);
void free_hca(hca_codec_data* data);
void free_hca(void* data);
clHCA_stInfo* hca_get_info(hca_codec_data* data);
typedef struct {
@ -369,13 +356,7 @@ STREAMFILE* hca_get_streamfile(hca_codec_data* data);
/* tac_decoder */
typedef struct tac_codec_data tac_codec_data;
tac_codec_data* init_tac(STREAMFILE* sf);
void decode_tac(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do);
void reset_tac(tac_codec_data* data);
void seek_tac(tac_codec_data* data, int32_t num_sample);
void free_tac(tac_codec_data* data);
void* init_tac(STREAMFILE* sf);
/* ice_decoder */
@ -389,13 +370,13 @@ void free_ice(ice_codec_data* data);
/* ka1a_decoder */
typedef struct ka1a_codec_data ka1a_codec_data;
void* init_ka1a(int bitrate_mode, int channels_tracks);
ka1a_codec_data* init_ka1a(int bitrate_mode, int channels_tracks);
void free_ka1a(ka1a_codec_data* data);
void reset_ka1a(ka1a_codec_data* data);
bool decode_ka1a_frame(VGMSTREAM* vgmstream);
void seek_ka1a(VGMSTREAM* v, int32_t num_sample);
/* ubimpeg_decoder */
void* init_ubimpeg(uint32_t mode);
/* mio_decoder */
void* init_mio(STREAMFILE* sf, int* p_loop_point);
#ifdef VGM_USE_VORBIS
@ -438,6 +419,7 @@ typedef enum {
VORBIS_SK, /* Silicon Knights AUD: "OggS" replaced by "SK" */
VORBIS_VID1, /* Neversoft VID1: custom packet blocks/headers */
VORBIS_AWC, /* Rockstar AWC: custom packet blocks/headers */
VORBIS_OOR, /* Age .OOR: custom bitpacked pages (custom header + setup) */
} vorbis_custom_t;
/* config for Wwise Vorbis (3 types for flexibility though not all combinations exist) */
@ -466,14 +448,13 @@ typedef struct {
/* output (kinda ugly here but to simplify) */
off_t data_start_offset;
int64_t last_granule;
} vorbis_custom_config;
vorbis_custom_codec_data* init_vorbis_custom(STREAMFILE* sf, off_t start_offset, vorbis_custom_t type, vorbis_custom_config* config);
void decode_vorbis_custom(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels);
void reset_vorbis_custom(VGMSTREAM* vgmstream);
void seek_vorbis_custom(VGMSTREAM* vgmstream, int32_t num_sample);
void free_vorbis_custom(vorbis_custom_codec_data* data);
void free_vorbis_custom(void* data);
int32_t vorbis_custom_get_samples(VGMSTREAM* v);
#endif
typedef struct {
@ -622,14 +603,8 @@ void free_celt_fsb(celt_codec_data* data);
#ifdef VGM_USE_SPEEX
/* speex_decoder */
typedef struct speex_codec_data speex_codec_data;
speex_codec_data* init_speex_ea(int channels);
speex_codec_data* init_speex_torus(int channels);
void decode_speex(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do);
void reset_speex(speex_codec_data* data);
void seek_speex(VGMSTREAM* vgmstream, int32_t num_sample);
void free_speex(speex_codec_data* data);
void* init_speex_ea(int channels);
void* init_speex_torus(int channels);
#endif

View file

@ -1,60 +0,0 @@
#ifndef _CODING_UTILS_SAMPLES_
#define _CODING_UTILS_SAMPLES_
/* sample helpers */
//TODO maybe move to .c
// (as .h can be inlined but these probably aren't called enough times that there is a notable boost)
typedef struct {
int16_t* samples; /* current samples (pointer is moved once consumed) */
int filled; /* samples left */
int channels; /* max channels sample buf handles */
//TODO may be more useful with filled+consumed and not moving *samples?
} s16buf_t;
static inline void s16buf_silence(sample_t** p_outbuf, int32_t* p_samples_silence, int channels) {
int samples_silence;
samples_silence = *p_samples_silence;
memset(*p_outbuf, 0, samples_silence * channels * sizeof(int16_t));
*p_outbuf += samples_silence * channels;
*p_samples_silence -= samples_silence;
}
static inline void s16buf_discard(sample_t** p_outbuf, s16buf_t* sbuf, int32_t* p_samples_discard) {
int samples_discard;
samples_discard = *p_samples_discard;
if (samples_discard > sbuf->filled)
samples_discard = sbuf->filled;
/* just ignore part of samples */
sbuf->samples += samples_discard * sbuf->channels;
sbuf->filled -= samples_discard;
*p_samples_discard -= samples_discard;
}
/* copy, move and mark consumed samples */
static inline void s16buf_consume(sample_t** p_outbuf, s16buf_t* sbuf, int32_t* p_samples_consume) {
int samples_consume;
samples_consume = *p_samples_consume;
if (samples_consume > sbuf->filled)
samples_consume = sbuf->filled;
/* memcpy is safe when filled/samples_copy is 0 (but must pass non-NULL bufs) */
memcpy(*p_outbuf, sbuf->samples, samples_consume * sbuf->channels * sizeof(int16_t));
sbuf->samples += samples_consume * sbuf->channels;
sbuf->filled -= samples_consume;
*p_outbuf += samples_consume * sbuf->channels;
*p_samples_consume -= samples_consume;
}
#endif /* _CODING_UTILS_SAMPLES_ */

View file

@ -1,27 +1,45 @@
#include "coding.h"
#include "coding_utils_samples.h"
#include "../base/decode_state.h"
#include "../base/codec_info.h"
#include "libs/compresswave_lib.h"
#define COMPRESSWAVE_MAX_FRAME_SAMPLES 0x1000 /* arbitrary but should be multiple of 2 for 22050 mode */
#define COMPRESSWAVE_MAX_FRAME_SAMPLES 512 // arbitrary, but should be multiple of 2 for 22050 mode
#define COMPRESSWAVE_MAX_CHANNELS 2
/* opaque struct */
struct compresswave_codec_data {
/* config */
typedef struct {
STREAMFILE* sf;
TCompressWaveData* cw;
TCompressWaveData* handle;
/* frame state */
int16_t* samples;
int frame_samples;
int16_t pbuf[COMPRESSWAVE_MAX_FRAME_SAMPLES * COMPRESSWAVE_MAX_CHANNELS];
int discard;
} compresswave_codec_data;
/* frame state */
s16buf_t sbuf;
int samples_discard;
};
static void reset_compresswave(void* priv_data) {
compresswave_codec_data* data = priv_data;
if (!data) return;
/* actual way to reset internal flags */
TCompressWaveData_Stop(data->handle);
TCompressWaveData_Play(data->handle, 0);
compresswave_codec_data* init_compresswave(STREAMFILE* sf) {
data->discard = 0;
return;
}
static void free_compresswave(void* priv_data) {
compresswave_codec_data* data = priv_data;
if (!data)
return;
TCompressWaveData_Free(data->handle);
close_streamfile(data->sf);
free(data);
}
void* init_compresswave(STREAMFILE* sf) {
compresswave_codec_data* data = NULL;
data = calloc(1, sizeof(compresswave_codec_data));
@ -30,15 +48,10 @@ compresswave_codec_data* init_compresswave(STREAMFILE* sf) {
data->sf = reopen_streamfile(sf, 0);
if (!data->sf) goto fail;
data->frame_samples = COMPRESSWAVE_MAX_FRAME_SAMPLES;
data->samples = malloc(2 * data->frame_samples * sizeof(int16_t)); /* always stereo */
if (!data->samples) goto fail;
data->handle = TCompressWaveData_Create();
if (!data->handle) goto fail;
data->cw = TCompressWaveData_Create();
if (!data->cw) goto fail;
TCompressWaveData_LoadFromStream(data->cw, data->sf);
TCompressWaveData_LoadFromStream(data->handle, data->sf);
reset_compresswave(data);
@ -49,90 +62,46 @@ fail:
}
static int decode_frame(compresswave_codec_data* data, int32_t samples_to_do) {
uint32_t Len;
int ok;
static bool decode_frame_compresswave(VGMSTREAM* v) {
compresswave_codec_data* data = v->codec_data;
decode_state_t* ds = v->decode_state;
data->sbuf.samples = data->samples;
data->sbuf.channels = 2;
data->sbuf.filled = 0;
int samples = COMPRESSWAVE_MAX_FRAME_SAMPLES;
//if (samples % 2 && samples > 1)
// samples -= 1; /* 22khz does 2 samples at once */
if (samples_to_do > data->frame_samples)
samples_to_do = data->frame_samples;
if (samples_to_do % 2 && samples_to_do > 1)
samples_to_do -= 1; /* 22khz does 2 samples at once */
Len = samples_to_do * sizeof(int16_t) * 2; /* forced stereo */
uint32_t len = samples * sizeof(int16_t) * 2; /* forced stereo */
ok = TCompressWaveData_Rendering(data->cw, data->sbuf.samples, Len);
if (!ok) goto fail;
int ok = TCompressWaveData_Rendering(data->handle, data->pbuf, len);
if (!ok) return false;
data->sbuf.filled = samples_to_do;
sbuf_init_s16(&ds->sbuf, data->pbuf, samples, v->channels);
ds->sbuf.filled = ds->sbuf.samples;
return 1;
fail:
return 0;
return true;
}
void decode_compresswave(compresswave_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
int ok;
while (samples_to_do > 0) {
s16buf_t* sbuf = &data->sbuf;
if (sbuf->filled <= 0) {
ok = decode_frame(data, samples_to_do);
if (!ok) goto fail;
}
if (data->samples_discard)
s16buf_discard(&outbuf, sbuf, &data->samples_discard);
else
s16buf_consume(&outbuf, sbuf, &samples_to_do);
}
return;
fail:
VGM_LOG("COMPRESSWAVE: decode fail, missing %i samples\n", samples_to_do);
s16buf_silence(&outbuf, &samples_to_do, 2);
}
void reset_compresswave(compresswave_codec_data* data) {
if (!data) return;
/* actual way to reset internal flags */
TCompressWaveData_Stop(data->cw);
TCompressWaveData_Play(data->cw, 0);
data->sbuf.filled = 0;
data->samples_discard = 0;
return;
}
void seek_compresswave(compresswave_codec_data* data, int32_t num_sample) {
void seek_compresswave(VGMSTREAM* v, int32_t num_sample) {
compresswave_codec_data* data = v->codec_data;
if (!data) return;
reset_compresswave(data);
data->samples_discard += num_sample;
data->discard += num_sample;
}
void free_compresswave(compresswave_codec_data* data) {
if (!data)
return;
TCompressWaveData_Free(data->cw);
close_streamfile(data->sf);
free(data->samples);
free(data);
}
STREAMFILE* compresswave_get_streamfile(compresswave_codec_data* data) {
STREAMFILE* compresswave_get_streamfile(VGMSTREAM* v) {
compresswave_codec_data* data = v->codec_data;
if (!data) return NULL;
return data->sf;
}
const codec_info_t compresswave_decoder = {
.sample_type = SFMT_S16,
.decode_frame = decode_frame_compresswave,
.free = free_compresswave,
.reset = reset_compresswave,
.seek = seek_compresswave,
//.frame_samples = 2-4 (lib handles arbitrary calls)
//.frame_size = VBR / huffman codes
};

View file

@ -1,26 +1,44 @@
#include "coding.h"
#include "../base/decode_state.h"
#include "libs/clhca.h"
#include "../base/codec_info.h"
struct hca_codec_data {
STREAMFILE* sf;
clHCA_stInfo info;
signed short* sample_buffer;
size_t samples_filled;
size_t samples_consumed;
size_t samples_to_discard;
void* data_buffer;
void* buf;
float* fbuf;
int current_delay;
unsigned int current_block;
void* handle;
};
static void reset_hca(void* priv) {
hca_codec_data* data = priv;
clHCA_DecodeReset(data->handle);
data->current_block = 0;
data->current_delay = data->info.encoderDelay;
}
void free_hca(void* priv) {
hca_codec_data* data = priv;
if (!data) return;
close_streamfile(data->sf);
clHCA_done(data->handle);
free(data->handle);
free(data->buf);
free(data->fbuf);
free(data);
}
/* init a HCA stream; STREAMFILE will be duplicated for internal use. */
hca_codec_data* init_hca(STREAMFILE* sf) {
uint8_t header_buffer[0x2000]; /* hca header buffer data (probable max ~0x400) */
uint8_t header_buffer[0x1000]; /* hca header buffer data (probable max ~0x400) */
hca_codec_data* data = NULL; /* vgmstream HCA context */
int header_size;
int status;
@ -51,11 +69,11 @@ hca_codec_data* init_hca(STREAMFILE* sf) {
status = clHCA_getInfo(data->handle, &data->info); /* extract header info */
if (status < 0) goto fail;
data->data_buffer = malloc(data->info.blockSize);
if (!data->data_buffer) goto fail;
data->buf = malloc(data->info.blockSize);
if (!data->buf) goto fail;
data->sample_buffer = malloc(sizeof(signed short) * data->info.channelCount * data->info.samplesPerBlock);
if (!data->sample_buffer) goto fail;
data->fbuf = malloc(sizeof(float) * data->info.channelCount * data->info.samplesPerBlock);
if (!data->fbuf) goto fail;
/* load streamfile for reads */
data->sf = reopen_streamfile(sf, 0);
@ -71,86 +89,64 @@ fail:
return NULL;
}
void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
int samples_done = 0;
const unsigned int channels = data->info.channelCount;
const unsigned int blockSize = data->info.blockSize;
static bool read_packet(VGMSTREAM* v) {
hca_codec_data* data = v->codec_data;
// EOF/error
if (data->current_block >= data->info.blockCount)
return false;
while (samples_done < samples_to_do) {
// single block of frames
const unsigned int block_size = data->info.blockSize;
//VGMSTREAMCHANNEL* vs = &v->ch[0];
off_t offset = data->info.headerSize + data->current_block * block_size; //vs->offset
if (data->samples_filled) {
int samples_to_get = data->samples_filled;
if (data->samples_to_discard) {
/* discard samples for looping */
if (samples_to_get > data->samples_to_discard)
samples_to_get = data->samples_to_discard;
data->samples_to_discard -= samples_to_get;
int bytes = read_streamfile(data->buf, offset, block_size, data->sf);
if (bytes != block_size) {
VGM_LOG("HCA: read %x vs expected %x bytes at %x\n", bytes, block_size, (uint32_t)offset);
return false;
}
else {
/* get max samples and copy */
if (samples_to_get > samples_to_do - samples_done)
samples_to_get = samples_to_do - samples_done;
memcpy(outbuf + samples_done*channels,
data->sample_buffer + data->samples_consumed*channels,
samples_to_get*channels * sizeof(sample_t));
samples_done += samples_to_get;
}
/* mark consumed samples */
data->samples_consumed += samples_to_get;
data->samples_filled -= samples_to_get;
}
else {
off_t offset = data->info.headerSize + data->current_block * blockSize;
int status;
size_t bytes;
/* EOF/error */
if (data->current_block >= data->info.blockCount) {
memset(outbuf, 0, (samples_to_do - samples_done) * channels * sizeof(sample_t));
break;
}
/* read frame */
bytes = read_streamfile(data->data_buffer, offset, blockSize, data->sf);
if (bytes != blockSize) {
VGM_LOG("HCA: read %x vs expected %x bytes at %x\n", bytes, blockSize, (uint32_t)offset);
break;
}
data->current_block++;
return true;
}
bool decode_frame_hca(VGMSTREAM* v) {
bool ok = read_packet(v);
if (!ok)
return false;
decode_state_t* ds = v->decode_state;
hca_codec_data* data = v->codec_data;
const unsigned int block_size = data->info.blockSize;
/* decode frame */
status = clHCA_DecodeBlock(data->handle, (void*)(data->data_buffer), blockSize);
int status = clHCA_DecodeBlock(data->handle, data->buf, block_size);
if (status < 0) {
VGM_LOG("HCA: decode fail at %x, code=%i\n", (uint32_t)offset, status);
break;
VGM_LOG("HCA: decode fail, code=%i\n", status);
return false;
}
/* extract samples */
clHCA_ReadSamples16(data->handle, data->sample_buffer);
clHCA_ReadSamples(data->handle, data->fbuf);
data->samples_consumed = 0;
data->samples_filled += data->info.samplesPerBlock;
}
}
int samples = data->info.samplesPerBlock;
sbuf_init_flt(&ds->sbuf, data->fbuf, samples, v->channels);
ds->sbuf.filled = samples;
if (data->current_delay) {
ds->discard += data->current_delay;
data->current_delay = 0;
}
void reset_hca(hca_codec_data* data) {
if (!data) return;
clHCA_DecodeReset(data->handle);
data->current_block = 0;
data->samples_filled = 0;
data->samples_consumed = 0;
data->samples_to_discard = data->info.encoderDelay;
return true;
}
void loop_hca(hca_codec_data* data, int32_t num_sample) {
if (!data) return;
void seek_hca(VGMSTREAM* v, int32_t num_sample) {
hca_codec_data* data = v->codec_data;
//decode_state_t* ds = v->decode_state;
//TODO handle arbitrary seek points to block N
/* manually calc loop values if not set (should only happen with installed/forced looping,
* as actual files usually pad encoder delay so earliest loopStartBlock becomes 1-2,
@ -163,20 +159,9 @@ void loop_hca(hca_codec_data* data, int32_t num_sample) {
}
data->current_block = data->info.loopStartBlock;
data->samples_filled = 0;
data->samples_consumed = 0;
data->samples_to_discard = data->info.loopStartDelay;
}
data->current_delay = data->info.loopStartDelay;
//ds->discard = data->info.loopStartDelay //overwritten on decode
void free_hca(hca_codec_data* data) {
if (!data) return;
close_streamfile(data->sf);
clHCA_done(data->handle);
free(data->handle);
free(data->data_buffer);
free(data->sample_buffer);
free(data);
}
clHCA_stInfo* hca_get_info(hca_codec_data* data) {
@ -235,14 +220,14 @@ static int test_hca_score(hca_codec_data* data, hca_keytest_t* hk) {
size_t bytes;
/* read and test frame */
bytes = read_streamfile(data->data_buffer, offset, block_size, data->sf);
bytes = read_streamfile(data->buf, offset, block_size, data->sf);
if (bytes != block_size) {
/* normally this shouldn't happen, but pre-fetch ACB stop with frames in half, so just keep score */
//total_score = -1;
break;
}
score = clHCA_TestBlock(data->handle, data->data_buffer, block_size);
score = clHCA_TestBlock(data->handle, data->buf, block_size);
/* get first non-blank frame */
if (!hk->start_offset && score != 0) {
@ -315,3 +300,13 @@ void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode, uint64_t sub
}
clHCA_SetKey(data->handle, (unsigned long long)keycode);
}
const codec_info_t hca_decoder = {
.sample_type = SFMT_FLT,
.decode_frame = decode_frame_hca,
.free = free_hca,
.reset = reset_hca,
.seek = seek_hca,
// frame_samples: 1024 + discard
// frame_size: variable
};

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,31 @@
#include "coding.h"
#include "../base/decode_state.h"
#include "../base/codec_info.h"
#include "libs/ka1a_dec.h"
/* opaque struct */
struct ka1a_codec_data {
typedef struct {
uint8_t* buf;
float* fbuf;
int frame_size;
void* handle;
};
} ka1a_codec_data;
ka1a_codec_data* init_ka1a(int bitrate_mode, int channels_tracks) {
static void free_ka1a(void* priv_data) {
ka1a_codec_data* data = priv_data;
if (!data) return;
if (data->handle)
ka1a_free(data->handle);
free(data->buf);
free(data->fbuf);
free(data);
}
void* init_ka1a(int bitrate_mode, int channels_tracks) {
ka1a_codec_data* data = NULL;
int buf_size;
@ -39,7 +51,7 @@ fail:
return NULL;
}
static bool read_ka1a_frame(VGMSTREAM* v) {
static bool read_frame(VGMSTREAM* v) {
ka1a_codec_data* data = v->codec_data;
int bytes;
@ -72,8 +84,8 @@ static bool read_ka1a_frame(VGMSTREAM* v) {
return true;
}
bool decode_ka1a_frame(VGMSTREAM* v) {
bool ok = read_ka1a_frame(v);
bool decode_frame_ka1a(VGMSTREAM* v) {
bool ok = read_frame(v);
if (!ok)
return false;
@ -90,13 +102,14 @@ bool decode_ka1a_frame(VGMSTREAM* v) {
return true;
}
void reset_ka1a(ka1a_codec_data* data) {
static void reset_ka1a(void* priv_data) {
ka1a_codec_data* data = priv_data;
if (!data || !data->handle) return;
ka1a_reset(data->handle);
}
void seek_ka1a(VGMSTREAM* v, int32_t num_sample) {
static void seek_ka1a(VGMSTREAM* v, int32_t num_sample) {
ka1a_codec_data* data = v->codec_data;
decode_state_t* ds = v->decode_state;
if (!data) return;
@ -135,12 +148,10 @@ void seek_ka1a(VGMSTREAM* v, int32_t num_sample) {
#endif
}
void free_ka1a(ka1a_codec_data* data) {
if (!data) return;
if (data->handle)
ka1a_free(data->handle);
free(data->buf);
free(data->fbuf);
free(data);
}
const codec_info_t ka1a_decoder = {
.sample_type = SFMT_FLT,
.decode_frame = decode_frame_ka1a,
.free = free_ka1a,
.reset = reset_ka1a,
.seek = seek_ka1a,
};

View file

@ -329,19 +329,16 @@ int clHCA_getInfo(clHCA* hca, clHCA_stInfo *info) {
}
//HCADecoder_DecodeBlockInt32
void clHCA_ReadSamples16(clHCA* hca, signed short *samples) {
void clHCA_ReadSamples16(clHCA* hca, short* samples) {
const float scale_f = 32768.0f;
float f;
signed int s;
unsigned int i, j, k;
/* PCM output is generally unused, but lib functions seem to use SIMD for f32 to s32 + round to zero */
for (i = 0; i < HCA_SUBFRAMES; i++) {
for (j = 0; j < HCA_SAMPLES_PER_SUBFRAME; j++) {
for (k = 0; k < hca->channels; k++) {
f = hca->channel[k].wave[i][j];
for (int i = 0; i < HCA_SUBFRAMES; i++) {
for (int j = 0; j < HCA_SAMPLES_PER_SUBFRAME; j++) {
for (int k = 0; k < hca->channels; k++) {
float f = hca->channel[k].wave[i][j];
//f = f * hca->rva_volume; /* rare, won't apply for now */
s = (signed int)(f * scale_f);
int s = (signed int)(f * scale_f);
if (s > 32767)
s = 32767;
else if (s < -32768)
@ -352,6 +349,20 @@ void clHCA_ReadSamples16(clHCA* hca, signed short *samples) {
}
}
void clHCA_ReadSamples(clHCA* hca, float* samples) {
/* interleave output */
for (int i = 0; i < HCA_SUBFRAMES; i++) {
for (int j = 0; j < HCA_SAMPLES_PER_SUBFRAME; j++) {
for (int k = 0; k < hca->channels; k++) {
float f = hca->channel[k].wave[i][j];
//f = f * hca->rva_volume; /* rare, won't apply for now */
*samples++ = f;
}
}
}
}
//--------------------------------------------------
// Allocation and creation

View file

@ -64,7 +64,9 @@ int clHCA_DecodeBlock(clHCA* hca, void* data, unsigned int size);
/* Extracts signed and clipped 16 bit samples into sample buffer.
* May be called after clHCA_DecodeBlock, and will return the same data until
* next decode. Buffer must be at least (samplesPerBlock*channels) long. */
void clHCA_ReadSamples16(clHCA* hca, short* outSamples);
void clHCA_ReadSamples16(clHCA* hca, short* samples);
void clHCA_ReadSamples(clHCA* hca, float* samples);
/* Sets a 64 bit encryption key, to properly decode blocks. This may be called
* multiple times to change the key, before or after clHCA_DecodeHeader.

View file

@ -695,7 +695,10 @@ int TCompressWaveData_Rendering(TCompressWaveData* self, int16_t* buf, uint32_t
}
else { //in case of playback without loop
self->FPlay = CW_FALSE;
return result; //exit
//return result; //exit
// OG lib returns error if requested more than avaiable, return partial buf here
break;
}
}
@ -762,9 +765,9 @@ int TCompressWaveData_Rendering(TCompressWaveData* self, int16_t* buf, uint32_t
}
// remainder calcs
//depending on buffer lenght remainder may happen
// depending on buffer length remainder may happen
// example: 44100 / 4 = 11025...OK 44100 / 8 = 5512.5...NG
// in that case appear as noise
// in that case it appears as noise
if (Len % 8 == 4) {
TCompressWaveData_Rendering_WriteWave(self, &buf1, RVol, LVol);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,869 @@
/*****************************************************************************
E R I S A - L i b r a r y
-----------------------------------------------------------------------------
Copyright (C) 2002-2003 Leshade Entis, Entis-soft. All rights reserved.
*****************************************************************************/
#include <stdlib.h>
#include "mio_xerisa.h"
#define MIO_ERISA_SYMBOL_ERROR -1
/************************/
/* huffman tree helpers */
/************************/
static void EHT_Initialize(ERINA_HUFFMAN_TREE* tree) {
for (int i = 0; i < MIO_HUFFMAN_SYMBOLS; i++) {
tree->m_iSymLookup[i] = ERINA_HUFFMAN_NULL;
}
tree->m_iEscape = ERINA_HUFFMAN_NULL;
tree->m_iTreePointer = ERINA_HUFFMAN_ROOT;
tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight = 0;
tree->m_hnTree[ERINA_HUFFMAN_ROOT].parent = ERINA_HUFFMAN_NULL;
tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code = ERINA_HUFFMAN_NULL;
}
static void EHT_RecountOccuredCount(ERINA_HUFFMAN_TREE* tree, int iParent) {
int iChild = tree->m_hnTree[iParent].child_code;
tree->m_hnTree[iParent].weight = tree->m_hnTree[iChild].weight + tree->m_hnTree[iChild + 1].weight;
}
static void EHT_Normalize(ERINA_HUFFMAN_TREE* tree, int iEntry) {
while (iEntry < ERINA_HUFFMAN_ROOT) {
// find swap entry
int iSwap = iEntry + 1;
WORD weight = tree->m_hnTree[iEntry].weight;
while (iSwap < ERINA_HUFFMAN_ROOT) {
if (tree->m_hnTree[iSwap].weight >= weight) break;
++iSwap;
}
if (iEntry == --iSwap) {
iEntry = tree->m_hnTree[iEntry].parent;
EHT_RecountOccuredCount(tree, iEntry);
continue;
}
// swap
int iChild, nCode;
if (!(tree->m_hnTree[iEntry].child_code & ERINA_CODE_FLAG)) {
iChild = tree->m_hnTree[iEntry].child_code;
tree->m_hnTree[iChild].parent = iSwap;
tree->m_hnTree[iChild + 1].parent = iSwap;
}
else {
nCode = tree->m_hnTree[iEntry].child_code & ~ERINA_CODE_FLAG;
if (nCode != ERINA_HUFFMAN_ESCAPE)
tree->m_iSymLookup[nCode & 0xFF] = iSwap;
else
tree->m_iEscape = iSwap;
}
if (!(tree->m_hnTree[iSwap].child_code & ERINA_CODE_FLAG)) {
int iChild = tree->m_hnTree[iSwap].child_code;
tree->m_hnTree[iChild].parent = iEntry;
tree->m_hnTree[iChild + 1].parent = iEntry;
}
else {
int nCode = tree->m_hnTree[iSwap].child_code & ~ERINA_CODE_FLAG;
if (nCode != ERINA_HUFFMAN_ESCAPE)
tree->m_iSymLookup[nCode & 0xFF] = iEntry;
else
tree->m_iEscape = iEntry;
}
ERINA_HUFFMAN_NODE node;
WORD iEntryParent = tree->m_hnTree[iEntry].parent;
WORD iSwapParent = tree->m_hnTree[iSwap].parent;
node = tree->m_hnTree[iSwap];
tree->m_hnTree[iSwap] = tree->m_hnTree[iEntry];
tree->m_hnTree[iEntry] = node;
tree->m_hnTree[iSwap].parent = iSwapParent;
tree->m_hnTree[iEntry].parent = iEntryParent;
// recalc parent weight
EHT_RecountOccuredCount(tree, iSwapParent);
iEntry = iSwapParent;
}
}
static void EHT_AddNewEntry(ERINA_HUFFMAN_TREE* tree, int nNewCode) {
if (tree->m_iTreePointer > 0) {
// reserve 2 areas
int i = tree->m_iTreePointer = tree->m_iTreePointer - 2;
// setup new entry
ERINA_HUFFMAN_NODE* phnNew = &tree->m_hnTree[i];
phnNew->weight = 1;
phnNew->child_code = ERINA_CODE_FLAG | nNewCode;
tree->m_iSymLookup[nNewCode & 0xFF] = i;
ERINA_HUFFMAN_NODE* phnRoot = &tree->m_hnTree[ERINA_HUFFMAN_ROOT];
if (phnRoot->child_code != ERINA_HUFFMAN_NULL) {
// add new entry
ERINA_HUFFMAN_NODE* phnParent = &tree->m_hnTree[i + 2];
ERINA_HUFFMAN_NODE* phnChild = &tree->m_hnTree[i + 1];
tree->m_hnTree[i + 1] = tree->m_hnTree[i + 2];
if (phnChild->child_code & ERINA_CODE_FLAG) {
int nCode = phnChild->child_code & ~ERINA_CODE_FLAG;
if (nCode != ERINA_HUFFMAN_ESCAPE)
tree->m_iSymLookup[nCode & 0xFF] = i + 1;
else
tree->m_iEscape = i + 1;
}
phnParent->weight = phnNew->weight + phnChild->weight;
phnParent->parent = phnChild->parent;
phnParent->child_code = i;
phnNew->parent = phnChild->parent = i + 2;
// fix parent entry
EHT_Normalize(tree, i + 2);
}
else {
// create initial tree state
phnNew->parent = ERINA_HUFFMAN_ROOT;
ERINA_HUFFMAN_NODE* phnEscape = &tree->m_hnTree[tree->m_iEscape = i + 1];
phnEscape->weight = 1;
phnEscape->parent = ERINA_HUFFMAN_ROOT;
phnEscape->child_code = ERINA_CODE_FLAG | ERINA_HUFFMAN_ESCAPE;
phnRoot->weight = 2;
phnRoot->child_code = i;
}
}
else {
// replace least ocurring symbol with new symbol
int i = tree->m_iTreePointer;
ERINA_HUFFMAN_NODE* phnEntry = &tree->m_hnTree[i];
if (phnEntry->child_code == (ERINA_CODE_FLAG | ERINA_HUFFMAN_ESCAPE)) {
phnEntry = &tree->m_hnTree[i + 1];
}
phnEntry->child_code = ERINA_CODE_FLAG | nNewCode;
}
}
static void EHT_HalfAndRebuild(ERINA_HUFFMAN_TREE* tree) {
// halve ocurrence count and rebuild the tree
int iNextEntry = ERINA_HUFFMAN_ROOT;
for (int i = ERINA_HUFFMAN_ROOT - 1; i >= tree->m_iTreePointer; i--) {
if (tree->m_hnTree[i].child_code & ERINA_CODE_FLAG) {
tree->m_hnTree[i].weight = (tree->m_hnTree[i].weight + 1) >> 1;
tree->m_hnTree[iNextEntry--] = tree->m_hnTree[i];
}
}
++iNextEntry;
// rebuild tree
int iChild, nCode;
int i = tree->m_iTreePointer;
for (;;) {
// put the smallest 2 entries into the huffman tree
tree->m_hnTree[i] = tree->m_hnTree[iNextEntry];
tree->m_hnTree[i + 1] = tree->m_hnTree[iNextEntry + 1];
iNextEntry += 2;
ERINA_HUFFMAN_NODE* phnChild1 = &tree->m_hnTree[i];
ERINA_HUFFMAN_NODE* phnChild2 = &tree->m_hnTree[i + 1];
if (!(phnChild1->child_code & ERINA_CODE_FLAG)) {
iChild = phnChild1->child_code;
tree->m_hnTree[iChild].parent = i;
tree->m_hnTree[iChild + 1].parent = i;
}
else {
nCode = phnChild1->child_code & ~ERINA_CODE_FLAG;
if (nCode == ERINA_HUFFMAN_ESCAPE)
tree->m_iEscape = i;
else
tree->m_iSymLookup[nCode & 0xFF] = i;
}
if (!(phnChild2->child_code & ERINA_CODE_FLAG)) {
iChild = phnChild2->child_code;
tree->m_hnTree[iChild].parent = i + 1;
tree->m_hnTree[iChild + 1].parent = i + 1;
}
else {
nCode = phnChild2->child_code & ~ERINA_CODE_FLAG;
if (nCode == ERINA_HUFFMAN_ESCAPE)
tree->m_iEscape = i + 1;
else
tree->m_iSymLookup[nCode & 0xFF] = i + 1;
}
WORD weight = phnChild1->weight + phnChild2->weight;
// include parent entry in list
if (iNextEntry <= ERINA_HUFFMAN_ROOT) {
int j = iNextEntry;
for (;;) {
if (weight <= tree->m_hnTree[j].weight) {
tree->m_hnTree[j - 1].weight = weight;
tree->m_hnTree[j - 1].child_code = i;
break;
}
tree->m_hnTree[j - 1] = tree->m_hnTree[j];
if (++j > ERINA_HUFFMAN_ROOT) {
tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight = weight;
tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code = i;
break;
}
}
--iNextEntry;
}
else {
tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight = weight;
tree->m_hnTree[ERINA_HUFFMAN_ROOT].parent = ERINA_HUFFMAN_NULL;
tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code = i;
phnChild1->parent = ERINA_HUFFMAN_ROOT;
phnChild2->parent = ERINA_HUFFMAN_ROOT;
break;
}
i += 2;
}
}
static void EHT_IncreaseOccuredCount(ERINA_HUFFMAN_TREE* tree, int iEntry) {
tree->m_hnTree[iEntry].weight++;
EHT_Normalize(tree, iEntry);
if (tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight >= ERINA_HUFFMAN_MAX) {
EHT_HalfAndRebuild(tree);
}
}
/*****************************/
/* arithmetic coding helpers */
/*****************************/
static void EPM_Initialize(ERISA_PROB_MODEL* prob) {
prob->dwTotalCount = ERISA_SYMBOL_SORTS;
prob->dwSymbolSorts = ERISA_SYMBOL_SORTS;
for (int i = 0; i < 0x100; i++) {
prob->acsSymTable[i].wOccured = 1;
prob->acsSymTable[i].wSymbol = (SWORD)(BYTE)i;
}
prob->acsSymTable[0x100].wOccured = 1;
prob->acsSymTable[0x100].wSymbol = (SWORD)ERISA_ESCAPE_CODE;
for (int i = 0; i < ERISA_SUB_SORT_MAX; i++) {
prob->acsSubModel[i].wOccured = 0;
prob->acsSubModel[i].wSymbol = (SWORD)-1;
}
}
static void EPM_HalfOccuredCount(ERISA_PROB_MODEL* prob) {
UDWORD i;
prob->dwTotalCount = 0;
for (i = 0; i < prob->dwSymbolSorts; i++) {
prob->dwTotalCount += prob->acsSymTable[i].wOccured = ((prob->acsSymTable[i].wOccured + 1) >> 1);
}
for (i = 0; i < ERISA_SUB_SORT_MAX; i++) {
prob->acsSubModel[i].wOccured >>= 1;
}
}
static int EPM_IncreaseSymbol(ERISA_PROB_MODEL* prob, int index) {
WORD wOccured = ++prob->acsSymTable[index].wOccured;
SWORD wSymbol = prob->acsSymTable[index].wSymbol;
while (--index >= 0) {
if (prob->acsSymTable[index].wOccured >= wOccured)
break;
prob->acsSymTable[index + 1] = prob->acsSymTable[index];
}
prob->acsSymTable[++index].wOccured = wOccured;
prob->acsSymTable[index].wSymbol = wSymbol;
if (++prob->dwTotalCount >= ERISA_TOTAL_LIMIT) {
EPM_HalfOccuredCount(prob);
}
return index;
}
/**************************/
/* general decode context */
/**************************/
ULONG MIOContext_DecodeSymbolBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount) {
/* (assert) */
if (context->m_pfnDecodeSymbolBytes == NULL)
return 0;
return (context->m_pfnDecodeSymbolBytes)(context, ptrDst, nCount);
}
static const SBYTE /*BYTE*/ nGammaCodeLookup[512] = {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 6, 8, 6, 8, 6, 8, 6, 16, 8, -1, -1, 17, 8, -1, -1, 9, 6, 9, 6, 9, 6, 9, 6, 18,
8, -1, -1, 19, 8, -1, -1, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4,
5, 4, 10, 6, 10, 6, 10, 6, 10, 6, 20, 8, -1, -1, 21, 8, -1, -1, 11, 6, 11, 6, 11, 6, 11, 6, 22, 8, -1, -1, 23, 8, -1, -1, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2,
3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2,
3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6,
4, 6, 4, 6, 4, 6, 4, 6, 4, 12, 6, 12, 6, 12, 6, 12, 6, 24, 8, -1, -1, 25, 8, -1, -1, 13, 6, 13, 6, 13, 6, 13, 6, 26, 8, -1, -1,
27, 8, -1, -1, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 14,
6, 14, 6, 14, 6, 14, 6, 28, 8, -1, -1, 29, 8, -1, -1, 15, 6, 15, 6, 15, 6, 15, 6, 30, 8, -1, -1, 31, 8, -1, -1
};
static ESLError MIOContext_PrefetchBuffer(MIOContext* context) {
if (context->m_nIntBufCount != 0)
return eslErrSuccess;
if (context->m_pFilePos >= context->m_pFileLength)
return eslErrGeneral;
// read next int32 BE
int dwLeft = context->m_pFileLength - context->m_pFilePos;
if (dwLeft < 4) {
// read partially at buffer edge
context->m_dwIntBuffer = 0;
for (int i = 0; i < dwLeft; i++) {
context->m_dwIntBuffer |= (UDWORD)context->m_pFileBuf[context->m_pFilePos + i] << (24 - 8*i);
}
context->m_pFilePos += dwLeft;
}
else {
context->m_dwIntBuffer =
((UDWORD)context->m_pFileBuf[context->m_pFilePos + 0] << 24) |
((UDWORD)context->m_pFileBuf[context->m_pFilePos + 1] << 16) |
((UDWORD)context->m_pFileBuf[context->m_pFilePos + 2] << 8) |
((UDWORD)context->m_pFileBuf[context->m_pFilePos + 3]);
context->m_pFilePos += 4;
}
// get next int32
context->m_nIntBufCount = 32;
return eslErrSuccess;
}
int MIOContext_GetABit(MIOContext* context) {
if (MIOContext_PrefetchBuffer(context)) {
return 1; // on error does return 1
}
// returns one bit ("0 or -1" according to original comment)
int nValue = (int)(((SDWORD)context->m_dwIntBuffer) >> 31);
--context->m_nIntBufCount;
context->m_dwIntBuffer <<= 1;
return nValue;
}
UINT MIOContext_GetNBits(MIOContext* context, int n) {
UINT nCode = 0;
while (n != 0) {
if (MIOContext_PrefetchBuffer(context))
break;
int nCopyBits = n;
if (nCopyBits > context->m_nIntBufCount)
nCopyBits = context->m_nIntBufCount;
nCode = (nCode << nCopyBits) | (context->m_dwIntBuffer >> (32 - nCopyBits));
n -= nCopyBits;
context->m_nIntBufCount -= nCopyBits;
context->m_dwIntBuffer <<= nCopyBits;
}
return nCode;
}
static int MIOContext_GetGammaCode(MIOContext* context) {
// test 1
if (MIOContext_PrefetchBuffer(context)) {
return 0;
}
/*register*/ UDWORD dwIntBuf;
context->m_nIntBufCount--;
dwIntBuf = context->m_dwIntBuffer;
context->m_dwIntBuffer <<= 1;
if (!(dwIntBuf & 0x80000000)) {
return 1;
}
// test end code
if (MIOContext_PrefetchBuffer(context)) {
return 0;
}
if ((~context->m_dwIntBuffer & 0x55000000) && (context->m_nIntBufCount >= 8)) {
int i = (context->m_dwIntBuffer >> 24) << 1;
int nCode = nGammaCodeLookup[i];
int nBitCount = nGammaCodeLookup[i + 1];
/* (assert) */
if (nBitCount > context->m_nIntBufCount || nCode <= 0)
return 0;
context->m_nIntBufCount -= nBitCount;
context->m_dwIntBuffer <<= nBitCount;
return nCode;
}
// regular routine
int nCode = 0, nBase = 2;
for (;;) {
if (context->m_nIntBufCount >= 2) {
// process 2 bits
dwIntBuf = context->m_dwIntBuffer;
context->m_dwIntBuffer <<= 2;
nCode = (nCode << 1) | (dwIntBuf >> 31);
context->m_nIntBufCount -= 2;
if (!(dwIntBuf & 0x40000000)) {
return nCode + nBase;
}
nBase <<= 1;
}
else {
// extract 1-bit
if (MIOContext_PrefetchBuffer(context)) {
return 0;
}
nCode = (nCode << 1) | (context->m_dwIntBuffer >> 31);
context->m_nIntBufCount--;
context->m_dwIntBuffer <<= 1;
// test end code
if (MIOContext_PrefetchBuffer(context)) {
return 0;
}
dwIntBuf = context->m_dwIntBuffer;
context->m_nIntBufCount--;
context->m_dwIntBuffer <<= 1;
if (!(dwIntBuf & 0x80000000)) {
return nCode + nBase;
}
nBase <<= 1;
}
}
}
/* original clones this into 2 functions with different escape codes but here we use a flag */
static int MIOContext_GetHuffmanCommon(MIOContext* context, ERINA_HUFFMAN_TREE* tree, int escapeGamma) {
// get one huffman code
int nCode;
if (tree->m_iEscape != ERINA_HUFFMAN_NULL) {
int iEntry = ERINA_HUFFMAN_ROOT;
int iChild = tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code;
// decode codes
do {
if (MIOContext_PrefetchBuffer(context)) {
return ERINA_HUFFMAN_ESCAPE;
}
// extract 1-bit
iEntry = iChild + (context->m_dwIntBuffer >> 31);
--context->m_nIntBufCount;
iChild = tree->m_hnTree[iEntry].child_code;
context->m_dwIntBuffer <<= 1;
} while (!(iChild & ERINA_CODE_FLAG));
// increase code occurence
if ((context->m_dwERINAFlags != ERINAEncodingFlag_efERINAOrder0) || (tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight < ERINA_HUFFMAN_MAX - 1)) {
EHT_IncreaseOccuredCount(tree, iEntry);
}
// regular code
nCode = iChild & ~ERINA_CODE_FLAG;
if (nCode != ERINA_HUFFMAN_ESCAPE) {
return nCode;
}
}
if (escapeGamma) {
// escape code: gamma code
nCode = MIOContext_GetGammaCode(context);
if (nCode == -1) {
return ERINA_HUFFMAN_ESCAPE;
}
}
else {
// escape code: 8-bit code
nCode = MIOContext_GetNBits(context, 8);
}
EHT_AddNewEntry(tree, nCode);
return nCode;
}
// get one "regular huffman" code
static int MIOContext_GetHuffmanCode(MIOContext* context, ERINA_HUFFMAN_TREE* tree) {
return MIOContext_GetHuffmanCommon(context, tree, 0);
}
// get one "length huffman" code
static int MIOContext_GetHuffmanLength(MIOContext* context, ERINA_HUFFMAN_TREE* tree) {
return MIOContext_GetHuffmanCommon(context, tree, 1);
}
//////////////////////////////////////////////////////////////////////////////
/* decode ERINA (huffman-coded) */
ULONG MIOContext_DecodeERINACodeBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount) {
ERINA_HUFFMAN_TREE* tree = context->m_pLastHuffmanTree;
int symbol, length;
ULONG i = 0;
if (context->m_nLength > 0) {
length = context->m_nLength;
if (length > (int)nCount) {
length = nCount;
}
context->m_nLength -= length;
do {
ptrDst[i++] = 0;
} while (--length);
}
while (i < nCount) {
symbol = MIOContext_GetHuffmanCode(context, tree);
if (symbol == ERINA_HUFFMAN_ESCAPE) {
break;
}
ptrDst[i++] = (SBYTE)symbol;
if (symbol == 0) {
length = MIOContext_GetHuffmanLength(context, context->m_ppHuffmanTree[0x100]);
if (length == ERINA_HUFFMAN_ESCAPE) {
break;
}
if (--length) {
context->m_nLength = length;
if (i + length > nCount) {
length = nCount - i;
}
context->m_nLength -= length;
if (length > 0) {
do {
ptrDst[i++] = 0;
} while (--length);
}
}
}
tree = context->m_ppHuffmanTree[symbol & 0xFF];
}
context->m_pLastHuffmanTree = tree;
return i;
}
static int MIOContext_DecodeERISACodeIndex(MIOContext* context, ERISA_PROB_MODEL* pModel) {
// serach via index
UDWORD dwAcc = context->m_dwCodeRegister * pModel->dwTotalCount / context->m_dwAugendRegister;
if (dwAcc >= ERISA_TOTAL_LIMIT) {
return MIO_ERISA_SYMBOL_ERROR;
}
int iSym = 0;
WORD wAcc = (WORD)dwAcc;
WORD wFs = 0;
WORD wOccured;
for (;;) {
wOccured = pModel->acsSymTable[iSym].wOccured;
if (wAcc < wOccured) {
break;
}
wAcc -= wOccured;
wFs += wOccured;
if ((UDWORD)++iSym >= pModel->dwSymbolSorts) {
return MIO_ERISA_SYMBOL_ERROR;
}
}
// update code and augend registers
context->m_dwCodeRegister -= (context->m_dwAugendRegister * wFs + pModel->dwTotalCount - 1) / pModel->dwTotalCount;
context->m_dwAugendRegister = context->m_dwAugendRegister * wOccured / pModel->dwTotalCount;
/* (assert) */
if (context->m_dwAugendRegister == 0)
return MIO_ERISA_SYMBOL_ERROR;
// normalize augend register and load into code register
while (!(context->m_dwAugendRegister & 0x8000)) {
int nNextBit = MIOContext_GetABit(context);
if (nNextBit == 1) {
if ((++context->m_nPostBitCount) >= 256) {
return MIO_ERISA_SYMBOL_ERROR;
}
nNextBit = 0;
}
context->m_dwCodeRegister = (context->m_dwCodeRegister << 1) | (nNextBit & 0x01);
context->m_dwAugendRegister <<= 1;
}
/* (assert) */
if ((context->m_dwAugendRegister & 0x8000) == 0)
return MIO_ERISA_SYMBOL_ERROR;
context->m_dwCodeRegister &= 0xFFFF;
return iSym;
}
/* decode ERISA (arithmetic-coded, using designated statistical model) */
int MIOContext_DecodeERISACode(MIOContext* context, ERISA_PROB_MODEL* pModel) {
int iSym = MIOContext_DecodeERISACodeIndex(context, pModel);
int nSymbol = ERISA_ESCAPE_CODE;
if (iSym >= 0) {
nSymbol = pModel->acsSymTable[iSym].wSymbol;
EPM_IncreaseSymbol(pModel, iSym);
}
return nSymbol;
}
//////////////////////////////////////////////////////////////////////////////
MIOContext* MIOContext_Open() {
MIOContext* context = malloc(sizeof(MIOContext));
if (!context) return NULL;
context->m_nIntBufCount = 0;
context->m_pfnDecodeSymbolBytes = NULL;
context->m_ppHuffmanTree = NULL;
context->m_pPhraseLenProb = NULL;
context->m_pPhraseIndexProb = NULL;
context->m_pRunLenProb = NULL;
context->m_ppTableERISA = NULL;
return context;
}
void MIOContext_Close(MIOContext* context) {
if (!context) return;
free(context->m_ppHuffmanTree);
free(context->m_pPhraseLenProb);
free(context->m_pPhraseIndexProb);
free(context->m_pRunLenProb);
free(context->m_ppTableERISA);
free(context);
}
void MIOContext_AttachInputFile(MIOContext* context, uint8_t* pFileBuf, int pFileLength) {
context->m_pFileBuf = pFileBuf;
context->m_pFileLength = pFileLength;
context->m_pFilePos = 0;
}
void MIOContext_FlushBuffer(MIOContext* context) {
context->m_nIntBufCount = 0;
}
//////////////////////////////////////////////////////////////////////////////
ESLError MIOContext_PrepareToDecodeERINACode(MIOContext* context, UDWORD dwFlags) {
if (context->m_ppHuffmanTree == NULL) {
UDWORD dwSize = (sizeof(ERINA_HUFFMAN_TREE*) + sizeof(ERINA_HUFFMAN_TREE)) * 0x101;
dwSize = (dwSize + 0x0F) & ~0x0F;
context->m_ppHuffmanTree = (ERINA_HUFFMAN_TREE**)malloc(dwSize);
if (!context->m_ppHuffmanTree)
return eslErrGeneral;
BYTE* ptrBuf = (BYTE*)(context->m_ppHuffmanTree + 0x101);
for (int i = 0; i < 0x101; i++) {
void* ptrTmp = ptrBuf;
context->m_ppHuffmanTree[i] = ptrTmp;
ptrBuf += sizeof(ERINA_HUFFMAN_TREE);
}
}
// init huffman
context->m_dwERINAFlags = dwFlags;
context->m_nLength = 0;
if (dwFlags == ERINAEncodingFlag_efERINAOrder0) { // not used in audio actually
EHT_Initialize(context->m_ppHuffmanTree[0]);
EHT_Initialize(context->m_ppHuffmanTree[0x100]);
for (int i = 1; i < 0x100; i++) {
context->m_ppHuffmanTree[i] = context->m_ppHuffmanTree[0];
}
}
else {
for (int i = 0; i < 0x101; i++) {
EHT_Initialize(context->m_ppHuffmanTree[i]);
}
}
context->m_pLastHuffmanTree = context->m_ppHuffmanTree[0];
context->m_pfnDecodeSymbolBytes = &MIOContext_DecodeERINACodeBytes;
return eslErrSuccess;
}
ESLError MIOContext_PrepareToDecodeERISACode(MIOContext* context) {
// init memory
if (context->m_ppTableERISA == NULL) { //TODO improve
UDWORD dwBytes = sizeof(ERISA_PROB_MODEL*) * 0x104 + sizeof(ERISA_PROB_MODEL) * 0x101;
dwBytes = (dwBytes + 0x100F) & (~0xFFF);
context->m_ppTableERISA = (ERISA_PROB_MODEL**)malloc(dwBytes);
if (!context->m_ppTableERISA)
return eslErrGeneral;
}
if (context->m_pPhraseLenProb == NULL)
context->m_pPhraseLenProb = malloc(sizeof(ERISA_PROB_MODEL));
if (context->m_pPhraseIndexProb == NULL)
context->m_pPhraseIndexProb = malloc(sizeof(ERISA_PROB_MODEL));
if (context->m_pRunLenProb == NULL)
context->m_pRunLenProb = malloc(sizeof(ERISA_PROB_MODEL));
if (!context->m_pPhraseLenProb || !context->m_pPhraseIndexProb || !context->m_pRunLenProb)
return eslErrGeneral;
// init probability model
ERISA_PROB_MODEL* pNextProb = (ERISA_PROB_MODEL*)(context->m_ppTableERISA + 0x104);
context->m_pLastERISAProb = pNextProb;
for (int i = 0; i < 0x101; i++) {
EPM_Initialize(pNextProb);
context->m_ppTableERISA[i] = pNextProb;
pNextProb++;
}
EPM_Initialize(context->m_pPhraseLenProb);
EPM_Initialize(context->m_pPhraseIndexProb);
EPM_Initialize(context->m_pRunLenProb);
// init register
context->m_nLength = 0;
context->m_dwCodeRegister = MIOContext_GetNBits(context, 32);
context->m_dwAugendRegister = 0xFFFF;
context->m_nPostBitCount = 0;
context->m_pfnDecodeSymbolBytes = &MIOContext_DecodeERISACodeBytes;
return eslErrSuccess;
}
// init "arithtmetic code"
void MIOContext_InitializeERISACode(MIOContext* context) {
context->m_nLength = 0;
context->m_dwCodeRegister = MIOContext_GetNBits(context, 32);
context->m_dwAugendRegister = 0xFFFF;
context->m_nPostBitCount = 0;
}
ULONG MIOContext_DecodeERISACodeBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount) {
ERISA_PROB_MODEL* pProb = context->m_pLastERISAProb;
int nSymbol, iSym;
int i = 0;
while ((ULONG)i < nCount) {
if (context->m_nLength > 0) {
// zero-length
ULONG nCurrent = nCount - i;
if (nCurrent > context->m_nLength)
nCurrent = context->m_nLength;
context->m_nLength -= nCurrent;
for (ULONG j = 0; j < nCurrent; j++) {
ptrDst[i++] = 0;
}
continue;
}
// decode next arithmetic code
iSym = MIOContext_DecodeERISACodeIndex(context, pProb);
if (iSym < 0)
break;
nSymbol = pProb->acsSymTable[iSym].wSymbol;
EPM_IncreaseSymbol(pProb, iSym);
ptrDst[i++] = (SBYTE)nSymbol;
if (nSymbol == 0) {
// get zero-length
iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pRunLenProb);
if (iSym < 0)
break;
context->m_nLength = context->m_pRunLenProb->acsSymTable[iSym].wSymbol;
EPM_IncreaseSymbol(context->m_pRunLenProb, iSym);
}
pProb = context->m_ppTableERISA[(nSymbol & 0xFF)];
}
context->m_pLastERISAProb = pProb;
return i;
}
ULONG MIOContext_DecodeERISACodeWords(MIOContext* context, SWORD* ptrDst, ULONG nCount) {
ERISA_PROB_MODEL* pProb = context->m_pLastERISAProb;
int nSymbol, iSym;
int i = 0;
while ((ULONG)i < nCount) {
if (context->m_nLength > 0) {
// zero-length
ULONG nCurrent = nCount - i;
if (nCurrent > context->m_nLength)
nCurrent = context->m_nLength;
context->m_nLength -= nCurrent;
for (ULONG j = 0; j < nCurrent; j++) {
ptrDst[i++] = 0;
}
continue;
}
// decode next arithmetic code
iSym = MIOContext_DecodeERISACodeIndex(context, pProb);
if (iSym < 0)
break;
nSymbol = pProb->acsSymTable[iSym].wSymbol;
EPM_IncreaseSymbol(pProb, iSym);
if (nSymbol == ERISA_ESCAPE_CODE) {
iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pPhraseIndexProb);
if (iSym < 0)
break;
nSymbol = context->m_pPhraseIndexProb->acsSymTable[iSym].wSymbol;
EPM_IncreaseSymbol(context->m_pPhraseIndexProb, iSym);
iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pPhraseLenProb);
if (iSym < 0)
break;
nSymbol = (nSymbol << 8) | (context->m_pPhraseLenProb->acsSymTable[iSym].wSymbol & 0xFF);
EPM_IncreaseSymbol(context->m_pPhraseLenProb, iSym);
ptrDst[i++] = (SWORD)nSymbol;
pProb = context->m_ppTableERISA[0x100];
}
else {
ptrDst[i++] = (SWORD)(SBYTE)nSymbol;
pProb = context->m_ppTableERISA[(nSymbol & 0xFF)];
if (nSymbol == 0) {
// get zero-length
iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pRunLenProb);
if (iSym < 0)
break;
context->m_nLength = context->m_pRunLenProb->acsSymTable[iSym].wSymbol;
EPM_IncreaseSymbol(context->m_pRunLenProb, iSym);
}
}
}
context->m_pLastERISAProb = pProb;
return i;
}

View file

@ -0,0 +1,123 @@
/* Handles bitreading from blocks and code unpacking (huffman/arithmetical decoding).
*/
#ifndef _MIO_ERISA_CONTEXT_H_
#define _MIO_ERISA_CONTEXT_H_
/* tree for huffman coding ("ERINA" codes) */
#define ERINA_CODE_FLAG 0x80000000u
#define ERINA_HUFFMAN_ESCAPE 0x7FFFFFFF
#define ERINA_HUFFMAN_NULL 0x8000u
#define ERINA_HUFFMAN_MAX 0x4000
#define ERINA_HUFFMAN_ROOT 0x200
#define MIO_HUFFMAN_SYMBOLS 256
typedef struct {
uint16_t weight;
uint16_t parent;
uint32_t child_code;
} ERINA_HUFFMAN_NODE;
typedef struct {
ERINA_HUFFMAN_NODE m_hnTree[0x201];
int m_iSymLookup[MIO_HUFFMAN_SYMBOLS];
int m_iEscape;
int m_iTreePointer;
} ERINA_HUFFMAN_TREE;
/* probability model for arithmetic coding ("ERISA" codes) */
#define ERISA_TOTAL_LIMIT 0x2000 // parameter limit
#define ERISA_SYMBOL_SORTS 0x101 // max types
#define ERISA_SUB_SORT_MAX 0x80
#define ERISA_PROB_SLOT_MAX 0x800 // max slots for probability model
#define ERISA_ESCAPE_CODE (-1)
typedef struct {
WORD wOccured; // symbol occurence count
SWORD wSymbol; // symbol (lower 8-bit only
} ERISA_CODE_SYMBOL;
typedef struct {
UDWORD dwTotalCount; // param < 2000H
UDWORD dwSymbolSorts; // number of symbol types
ERISA_CODE_SYMBOL acsSymTable[ERISA_SYMBOL_SORTS]; // probability model
ERISA_CODE_SYMBOL acsSubModel[ERISA_SUB_SORT_MAX]; // sub-probability model index
} ERISA_PROB_MODEL;
typedef enum {
ERINAEncodingFlag_efERINAOrder0 = 0x0000,
ERINAEncodingFlag_efERINAOrder1 = 0x0001
} ERINAEncodingFlag;
/* coding context for the decoder (AKA ERISADecodeContext), used to extract codes from a bitstream buffer */
typedef struct MIOContext MIOContext;
struct MIOContext {
// bitstream buffer
int m_nIntBufCount; // helper input buffer bitpos
UDWORD m_dwIntBuffer; // helper input buffer
uint8_t* m_pFileBuf;
int m_pFileLength;
int m_pFilePos;
// current symbol expansion
ULONG (*m_pfnDecodeSymbolBytes)(MIOContext* context, SBYTE* ptrDst, ULONG nCount);
// for run-length encoding
ULONG m_nLength;
// ERINA (huffman) code context
UDWORD m_dwERINAFlags;
ERINA_HUFFMAN_TREE* m_pLastHuffmanTree;
ERINA_HUFFMAN_TREE** m_ppHuffmanTree;
// ERISA (arithmetic) code context
UDWORD m_dwCodeRegister; // 16-bit
UDWORD m_dwAugendRegister; // 16-bit
int m_nPostBitCount; // end bit buffer counter
// ERISA-N context
ERISA_PROB_MODEL* m_pPhraseLenProb;
ERISA_PROB_MODEL* m_pPhraseIndexProb;
ERISA_PROB_MODEL* m_pRunLenProb;
ERISA_PROB_MODEL* m_pLastERISAProb;
ERISA_PROB_MODEL** m_ppTableERISA;
};
MIOContext* MIOContext_Open();
void MIOContext_Close(MIOContext* context);
void MIOContext_AttachInputFile(MIOContext* context, uint8_t* pFileBuf, int pFileLength);
int MIOContext_GetABit(MIOContext* context);
UINT MIOContext_GetNBits(MIOContext* context, int n);
void MIOContext_FlushBuffer(MIOContext* context);
ULONG MIOContext_DecodeSymbolBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount);
ESLError MIOContext_PrepareToDecodeERINACode(MIOContext* context, UDWORD dwFlags);
// (indirect call)
ULONG MIOContext_DecodeERINACodeBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount);
ESLError MIOContext_PrepareToDecodeERISACode(MIOContext* context);
void MIOContext_InitializeERISACode(MIOContext* context);
int MIOContext_DecodeERISACode(MIOContext* context, ERISA_PROB_MODEL* pModel);
//int MIOContext_DecodeERISACodeIndex(MIOContext* context, ERISA_PROB_MODEL* pModel);
// (indirect call)
ULONG MIOContext_DecodeERISACodeBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount);
ULONG MIOContext_DecodeERISACodeWords(MIOContext* context, SWORD* ptrDst, ULONG nCount);
#endif

View file

@ -0,0 +1,375 @@
/*****************************************************************************
E R I S A - L i b r a r y
-----------------------------------------------------------------------------
Copyright (C) 2002-2003 Leshade Entis, Entis-soft. All rights reserved.
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "mio_xerisa.h"
#include "../../util/reader_get.h"
#define MIO_PACKET_BUFFER_MAX 0x20000 /* observed max is ~0x1d000 */
#define MIO_PACKET_HEADER_SIZE 0x08
#define MIO_PACKET_BYTES_MAX (32768 * 2 * 2) /* observed max: samples * channels * pcm16 */
static inline /*const*/ uint64_t get_id64le(const char* s) {
return (uint64_t)(
((uint64_t)s[7] << 56) |
((uint64_t)s[6] << 48) |
((uint64_t)s[5] << 40) |
((uint64_t)s[4] << 32) |
((uint64_t)s[3] << 24) |
((uint64_t)s[2] << 16) |
((uint64_t)s[1] << 8) |
((uint64_t)s[0] << 0)
);
}
MIOFile* MIOFile_Open() {
MIOFile* mf = calloc(1, sizeof(MIOFile));
if (!mf)
return NULL;
return mf;
}
void MIOFile_Close(MIOFile* mf) {
if (!mf) return;
free(mf->ptrWaveBuf);
free(mf->desc);
free(mf->buf);
free(mf);
}
static int read_chunk(EMC_RECORD_HEADER* rh, io_callback_t* file) {
uint8_t chunk[0x10];
int len = file->read(chunk, 1, 0x10, file->arg);
if (len != 0x10) goto fail;
rh->nRecordID = get_u64le(chunk + 0x00);
rh->nRecLength = get_u64le(chunk + 0x08);
return 1;
fail:
return 0;
}
/* reads string (possibly utf16) in the form of "KEY\r\nVAL\r\n" */
static int read_tag(char* tag, int tag_len, char* buf, int buf_len, int is_utf16le) {
int step = is_utf16le ? 2 : 1;
int buf_pos = 0;
int tag_pos = 0;
tag[0] = '\0';
while (1) {
if (buf_pos + step >= buf_len)
break;
if (tag_pos + 1 >= tag_len)
break;
char elem = buf[buf_pos++];
if (is_utf16le) /* ignore high byte for now (only seen simple tags) */
buf_pos++;
if (elem == '\0')
break;
tag[tag_pos++] = elem;
}
tag[tag_pos] = '\0';
return buf_pos;
}
static int read_int(const char* params, UDWORD *value) {
int n,m;
int temp;
m = sscanf(params, " %d%n", &temp,&n);
if (m != 1 || temp < 0)
return 0;
*value = temp;
return n;
}
/* Originally this is parsed into a list then returned when requested (ex. ERIFile::ETagInfo::GetRewindPoint)
* but pre-read to simplify. Tags format:
* - optional BOM (text is char16, possibly SHIFT-JIS), only seen files with utf-16
* - key\r\nvalue\r\n (keys usually start with '#') xN (probably null-separated but only seen 1 tag)
* - null padding (tag block is usually 0x80 even if only one short string is used) */
static void read_tags(MIOFile* mf) {
char tag[128];
int tag_len = sizeof(tag);
char* desc = mf->desc;
int desc_len = mf->desc_len;
int is_utf16le = 0;
if (desc[0] == '\xff' && desc[1] == '\xfe') {
is_utf16le = 1;
}
desc += 2;
desc_len -= 2;
while (1) {
int read = read_tag(tag, tag_len, desc, desc_len, is_utf16le);
if (read <= 0)
break;
if (memcmp(tag, "#rewind-point\r\n", 15) == 0)
read_int(tag + 15, &mf->mioih.rewindPoint);
desc += read;
desc_len -= read;
}
}
ESLError MIOFile_Initialize(MIOFile* mf, io_callback_t* file) {
EMC_RECORD_HEADER rh;
uint8_t buf[0x40];
int len, ok;
int size, to_read;
file->seek(file->arg, 0, IO_CALLBACK_SEEK_SET);
/* read base chunk */
{
to_read = 0x40;
len = file->read(buf, 1, to_read, file->arg);
if (len < to_read) goto fail;
mf->emcfh.cHeader = get_u64le(buf + 0x00);
mf->emcfh.dwFileID = get_u32le(buf + 0x08);
mf->emcfh.dwReserved = get_u32le(buf + 0x0c);
memcpy(mf->emcfh.cFormatDesc, buf + 0x10, 0x20);
/* 0x30: extra info 0x10 */
if (mf->emcfh.cHeader != get_id64le("Entis\x1a\x00\x00"))
goto fail;
/* each format has a fixed description, not checked in OG lib though */
if (memcmp(mf->emcfh.cFormatDesc, "Music Interleaved and Orthogonal", 0x20) != 0)
goto fail;
/* older files end with " transformed\0\0\0\0", and newer with null + data size */
}
/* read header chunks */
{
ok = read_chunk(&rh, file);
if (!ok) goto fail;
if (rh.nRecordID != get_id64le("Header "))
goto fail;
size = rh.nRecLength;
while (size > 0) {
ok = read_chunk(&rh, file);
if (!ok) goto fail;
size -= 0x10;
/* common info */
if (rh.nRecordID == get_id64le("FileHdr ")) {
to_read = rh.nRecLength;
if (to_read > sizeof(buf) || to_read != 0x14) goto fail;
len = file->read(buf, 1, to_read, file->arg);
if (len != to_read) goto fail;
mf->erifh.dwVersion = get_u32le(buf + 0x00);
mf->erifh.dwContainedFlag = get_u32le(buf + 0x04);
mf->erifh.dwKeyFrameCount = get_u32le(buf + 0x08);
mf->erifh.dwFrameCount = get_u32le(buf + 0x0c);
mf->erifh.dwAllFrameTime = get_u32le(buf + 0x10);
}
/* audio header */
if (rh.nRecordID == get_id64le("SoundInf")) {
to_read = rh.nRecLength;
if (to_read > sizeof(buf) || to_read != 0x28) goto fail;
len = file->read(buf, 1, to_read, file->arg);
if (len != to_read) goto fail;
mf->mioih.dwVersion = get_u32le(buf + 0x00);
mf->mioih.fdwTransformation= get_u32le(buf + 0x04);
mf->mioih.dwArchitecture = get_u32le(buf + 0x08);
mf->mioih.dwChannelCount = get_u32le(buf + 0x0c);
mf->mioih.dwSamplesPerSec = get_u32le(buf + 0x10);
mf->mioih.dwBlocksetCount = get_u32le(buf + 0x14);
mf->mioih.dwSubbandDegree = get_u32le(buf + 0x18);
mf->mioih.dwAllSampleCount = get_u32le(buf + 0x1c);
mf->mioih.dwLappedDegree = get_u32le(buf + 0x20);
mf->mioih.dwBitsPerSample = get_u32le(buf + 0x24);
}
/* other defaults */
mf->mioih.rewindPoint = -1; /* not looped (since #rewind-point 0 means loop from the beginning) */
/* tags */
if (rh.nRecordID == get_id64le("descript")) {
/* OG lib supports:
"title", "vocal-player", "composer", "arranger", "source", "track", "release-date", "genre",
"rewind-point" (loop start), "hot-spot", "resolution", "comment", "words" (lyrics)
Only seen loops though.
*/
/* sometimes chunk exists with just size 0x02 (empty but probably for BOM) */
to_read = rh.nRecLength;
if (to_read < 0x02 || to_read > 0x10000) goto fail;
mf->desc = calloc(1, to_read + 2);
if (!mf->desc) goto fail;
len = file->read(mf->desc, 1, to_read, file->arg);
if (len != to_read) goto fail;
/* doesn't always end with null */
mf->desc[to_read+0] = '\0';
mf->desc[to_read+1] = '\0';
mf->desc_len = to_read;
read_tags(mf);
}
/* other chunks (not seen / for other non-MIO formats?):
* - "PrevwInf" (image preview)
* - "ImageInf" (image header)
* - "Sequence" (image?)
* - "cpyright" (text info)
*/
size -= rh.nRecLength;
}
if (mf->erifh.dwVersion > 0x00020100) {
goto fail;
}
}
/* read file data */
{
ok = read_chunk(&rh, file);
if (!ok) goto fail;
if (rh.nRecordID != get_id64le("Stream "))
goto fail;
//printf("stream chunk reached\n");
/* packets are in "SoundStm" chunks ("ImageFrm" in images) */
mf->start = file->tell(file->arg);
}
return eslErrSuccess;
fail:
return eslErrGeneral;
}
ESLError MIOFile_Reset(MIOFile* mf, io_callback_t* file) {
if (!mf) goto fail;
file->seek(file->arg, mf->start, IO_CALLBACK_SEEK_SET);
return eslErrSuccess;
fail:
return eslErrGeneral;
}
static int parse_packet_header(uint8_t* buf, int buf_size, MIO_DATA_HEADER* dh) {
if (buf_size < MIO_PACKET_HEADER_SIZE)
goto fail;
dh->bytVersion = get_u8(buf + 0x00);
dh->bytFlags = get_u8(buf + 0x01);
dh->bytReserved1 = get_u8(buf + 0x02);
dh->bytReserved2 = get_u8(buf + 0x03);
dh->dwSampleCount = get_u32le(buf + 0x04);
return 1;
fail:
return 0;
}
ESLError MIOFile_NextPacket(MIOFile* mf, io_callback_t* file) {
EMC_RECORD_HEADER rh;
int ok, len;
ok = read_chunk(&rh, file);
if (!ok) return eslErrEof;
if (rh.nRecordID != get_id64le("SoundStm"))
goto fail;
/* prepare buf */
if (mf->buf_size < rh.nRecLength) {
if (rh.nRecLength > MIO_PACKET_BUFFER_MAX)
goto fail;
if (rh.nRecLength <= MIO_PACKET_HEADER_SIZE)
goto fail;
free(mf->buf);
mf->buf_size = rh.nRecLength;
mf->buf = malloc(mf->buf_size);
if (!mf->buf) goto fail;
}
len = file->read(mf->buf, 1, rh.nRecLength, file->arg);
if (len != rh.nRecLength) goto fail;
ok = parse_packet_header(mf->buf, rh.nRecLength, &mf->miodh);
if (!ok) goto fail;
mf->packet = mf->buf + MIO_PACKET_HEADER_SIZE;
mf->packet_size = rh.nRecLength - MIO_PACKET_HEADER_SIZE;
return eslErrSuccess;
fail:
return eslErrGeneral;
}
int MIOFile_GetTagLoop(MIOFile* mf, const char* tag) {
return mf->mioih.rewindPoint;
}
void* MIOFile_GetCurrentWaveBuffer(MIOFile* mf) {
int channels = mf->mioih.dwChannelCount;
int bps = mf->mioih.dwBitsPerSample;
int bytes_per_sample = channels * (bps / 8);
int chunk_samples = mf->miodh.dwSampleCount;
/* usually same for all except less in last packet */
UDWORD dwBytesAudio = chunk_samples * bytes_per_sample;
if (dwBytesAudio > MIO_PACKET_BYTES_MAX) goto fail;
if (dwBytesAudio > mf->ptrWaveBuf_len) {
free(mf->ptrWaveBuf);
mf->ptrWaveBuf = malloc(dwBytesAudio);
if (!mf->ptrWaveBuf) goto fail;
mf->ptrWaveBuf_len = dwBytesAudio;
}
return mf->ptrWaveBuf;
fail:
return NULL;
}
int MIOFile_GetCurrentWaveBufferCount(MIOFile* mf) {
int channels = mf->mioih.dwChannelCount;
int chunk_samples = mf->miodh.dwSampleCount;
return chunk_samples * channels;
}

View file

@ -0,0 +1,40 @@
/* iDTC/iLOT/etc helper functions.
*/
#ifndef _MIO_ERISA_FILE_H_
#define _MIO_ERISA_FILE_H_
/* custom IO (OG lib uses FILEs) */
#include "../../util/io_callback.h"
typedef struct {
EMC_FILE_HEADER emcfh; // base header (EMC = Entis Media Complex)
ERI_FILE_HEADER erifh; // common file chunk
MIO_INFO_HEADER mioih; // audio audio chunk
uint32_t start;
char* desc; // text info
int desc_len; // extra
MIO_DATA_HEADER miodh; // packet info
uint8_t* buf;
int buf_size;
uint8_t* packet; //m_ptrBuffer
int packet_size;
void* ptrWaveBuf; // not part of the original code but to simplify usage
int ptrWaveBuf_len;
} MIOFile;
MIOFile* MIOFile_Open();
void MIOFile_Close(MIOFile* mf);
ESLError MIOFile_Initialize(MIOFile* mf, io_callback_t* file);
ESLError MIOFile_Reset(MIOFile* mf, io_callback_t* file);
ESLError MIOFile_NextPacket(MIOFile* mf, io_callback_t* file);
int MIOFile_GetTagLoop(MIOFile* mf, const char* tag);
// extra
void* MIOFile_GetCurrentWaveBuffer(MIOFile* mf);
int MIOFile_GetCurrentWaveBufferCount(MIOFile* mf);
#endif

View file

@ -0,0 +1,392 @@
/*****************************************************************************
E R I S A - L i b r a r y
----------------------------------------------------------------------------
Copyright (C) 2000-2003 Leshade Entis. All rights reserved.
*****************************************************************************/
#include <stdlib.h>
#include <math.h>
#include "mio_xerisa.h"
static volatile int g_eri_initialized = 0; //extra, not really that important but..
void ERI_eriInitializeLibrary(void) {
if (g_eri_initialized)
return;
EMT_eriInitializeMatrix();
g_eri_initialized = 1;
}
void ERI_eriCloseLibrary(void) {
}
//
static int round_f32(float r) {
if (r >= 0.0) {
return (int)floor(r + 0.5);
}
else {
return (int)ceil(r - 0.5);
}
}
void EMT_eriRoundR32ToWordArray(SWORD* ptrDst, int nStep, const float* ptrSrc, int nCount) {
for (int i = 0; i < nCount; i++) {
int nValue = round_f32(ptrSrc[i]);
if (nValue <= -0x8000) {
*ptrDst = -0x8000;
}
else if (nValue >= 0x7FFF) {
*ptrDst = 0x7FFF;
}
else {
*ptrDst = (SWORD)nValue;
}
ptrDst += nStep;
}
}
static const double ERI_PI = 3.141592653589; // = π
static const float ERI_rHalf = 0.5F; // = 1/2
//static const float ERI_r2 = 2.0F; // = 2.0
// revolve 2-point matrix (for MSS)
void EMT_eriRevolve2x2(float* ptrBuf1, float* ptrBuf2, float rSin, float rCos, unsigned int nStep, unsigned int nCount) {
for (int i = 0; i < nCount; i++) {
float r1 = *ptrBuf1;
float r2 = *ptrBuf2;
*ptrBuf1 = r1 * rCos - r2 * rSin;
*ptrBuf2 = r1 * rSin + r2 * rCos;
ptrBuf1 += nStep;
ptrBuf2 += nStep;
}
}
// create rotation matrix parameter for LOT transformation
ERI_SIN_COS* EMT_eriCreateRevolveParameter(unsigned int nDegreeDCT) {
int i, nDegreeNum;
nDegreeNum = 1 << nDegreeDCT;
int lc = 1, n = nDegreeNum / 2;
while (n >= 8) {
n /= 8;
++lc;
}
ERI_SIN_COS* ptrRevolve = malloc(lc * 8 * sizeof(ERI_SIN_COS));
if (!ptrRevolve)
return NULL;
double k = ERI_PI / (nDegreeNum * 2);
ERI_SIN_COS* ptrNextRev = ptrRevolve;
int nStep = 2;
do {
for (i = 0; i < 7; i++) {
double ws = 1.0;
double a = 0.0;
for (int j = 0; j < i; j++) {
a += nStep;
ws = ws * ptrNextRev[j].rSin + ptrNextRev[j].rCos * cos(a * k);
}
double r = atan2(ws, cos((a + nStep) * k));
ptrNextRev[i].rSin = (float)sin(r);
ptrNextRev[i].rCos = (float)cos(r);
}
ptrNextRev += 7;
nStep *= 8;
}
while (nStep < nDegreeNum);
return ptrRevolve;
}
void EMT_eriOddGivensInverseMatrix(float* ptrSrc, const ERI_SIN_COS* ptrRevolve, unsigned int nDegreeDCT) {
int i, j, k;
int nDegreeNum = 1 << nDegreeDCT;
// odd number rotate operation
int nStep, lc, index;
index = 1;
nStep = 2;
lc = (nDegreeNum / 2) / 8;
for (;;) {
ptrRevolve += 7;
index += nStep * 7;
nStep *= 8;
if (lc <= 8)
break;
lc /= 8;
}
k = index + nStep * (lc - 2);
for (j = lc - 2; j >= 0; j--) {
float r1 = ptrSrc[k];
float r2 = ptrSrc[k + nStep];
ptrSrc[k] = r1 * ptrRevolve[j].rCos + r2 * ptrRevolve[j].rSin;
ptrSrc[k + nStep] = r2 * ptrRevolve[j].rCos - r1 * ptrRevolve[j].rSin;
k -= nStep;
}
for (;;) {
if (lc > (nDegreeNum / 2) / 8)
break;
ptrRevolve -= 7;
nStep /= 8;
index -= nStep * 7;
for (i = 0; i < lc; i++) {
k = i * (nStep * 8) + index + nStep * 6;
for (j = 6; j >= 0; j--) {
float r1 = ptrSrc[k];
float r2 = ptrSrc[k + nStep];
ptrSrc[k] = r1 * ptrRevolve[j].rCos + r2 * ptrRevolve[j].rSin;
ptrSrc[k + nStep] = r2 * ptrRevolve[j].rCos - r1 * ptrRevolve[j].rSin;
k -= nStep;
}
}
lc *= 8;
}
}
// Inverse Previous LOT
void EMT_eriFastIPLOT(float* ptrSrc, unsigned int nDegreeDCT) {
unsigned int nDegreeNum = 1 << nDegreeDCT;
// divide odd and even freqs
for (int i = 0; i < nDegreeNum; i += 2) {
float r1 = ptrSrc[i];
float r2 = ptrSrc[i + 1];
ptrSrc[i] = ERI_rHalf * (r1 + r2);
ptrSrc[i + 1] = ERI_rHalf * (r1 - r2);
}
}
// Inverse LOT
void EMT_eriFastILOT(float* ptrDst, const float* ptrSrc1, const float* ptrSrc2, unsigned int nDegreeDCT) {
unsigned int nDegreeNum = 1 << nDegreeDCT;
// reverse duplication
for (int i = 0; i < nDegreeNum; i += 2) {
float r1 = ptrSrc1[i];
float r2 = ptrSrc2[i + 1];
ptrDst[i] = r1 + r2;
ptrDst[i + 1] = r1 - r2;
}
}
//////////////////////////////////////////////////////////////////////////////
static float ERI_rCosPI4; // = cos(pi/4)
static float ERI_r2CosPI4; // = 2*cos(pi/4)
// matrix coefs: k(n,i) = cos( (2*i+1) / (4*n) )
//
static float ERI_DCTofK2[2]; // = cos( (2*i+1) / 8 )
static float ERI_DCTofK4[4]; // = cos( (2*i+1) / 16 )
static float ERI_DCTofK8[8]; // = cos( (2*i+1) / 32 )
static float ERI_DCTofK16[16]; // = cos( (2*i+1) / 64 )
static float ERI_DCTofK32[32]; // = cos( (2*i+1) / 128 )
static float ERI_DCTofK64[64]; // = cos( (2*i+1) / 256 )
static float ERI_DCTofK128[128]; // = cos( (2*i+1) / 512 )
static float ERI_DCTofK256[256]; // = cos( (2*i+1) / 1024 )
static float ERI_DCTofK512[512]; // = cos( (2*i+1) / 2048 )
static float ERI_DCTofK1024[1024]; // = cos( (2*i+1) / 4096 )
static float ERI_DCTofK2048[2048]; // = cos( (2*i+1) / 8192 )
// matrix coefs table
static float* ERI_pMatrixDCTofK[MAX_DCT_DEGREE] = {
NULL,
ERI_DCTofK2,
ERI_DCTofK4,
ERI_DCTofK8,
ERI_DCTofK16,
ERI_DCTofK32,
ERI_DCTofK64,
ERI_DCTofK128,
ERI_DCTofK256,
ERI_DCTofK512,
ERI_DCTofK1024,
ERI_DCTofK2048
};
// initialize tables for DCT matrix operations
void EMT_eriInitializeMatrix(void) {
// prepare special constants
ERI_rCosPI4 = (float)cos(ERI_PI * 0.25);
ERI_r2CosPI4 = 2.0F * ERI_rCosPI4;
// matrix coefs init
for (int i = 1; i < MAX_DCT_DEGREE; i++) {
int n = (1 << i);
float* pDCTofK = ERI_pMatrixDCTofK[i];
double nr = ERI_PI / (4.0 * n);
double dr = nr + nr;
double ir = nr;
for (int j = 0; j < n; j++) {
pDCTofK[j] = (float)cos(ir);
ir += dr;
}
}
}
static void eriFastDCT(float* ptrDst, unsigned int nDstInterval, float* ptrSrc, float* ptrWorkBuf, unsigned int nDegreeDCT) {
if (nDegreeDCT < MIN_DCT_DEGREE || nDegreeDCT > MAX_DCT_DEGREE)
return;
if (nDegreeDCT == MIN_DCT_DEGREE) {
// 4th order DCT
float r32Buf[4];
// cross ops
r32Buf[0] = ptrSrc[0] + ptrSrc[3];
r32Buf[2] = ptrSrc[0] - ptrSrc[3];
r32Buf[1] = ptrSrc[1] + ptrSrc[2];
r32Buf[3] = ptrSrc[1] - ptrSrc[2];
// first half: A2 * DCT2
ptrDst[0] = ERI_rHalf * (r32Buf[0] + r32Buf[1]);
ptrDst[nDstInterval * 2] = ERI_rCosPI4 * (r32Buf[0] - r32Buf[1]);
// last half: R2 * 2 * A2 * DCT2 * K2
r32Buf[2] = ERI_DCTofK2[0] * r32Buf[2];
r32Buf[3] = ERI_DCTofK2[1] * r32Buf[3];
r32Buf[0] = r32Buf[2] + r32Buf[3];
r32Buf[1] = ERI_r2CosPI4 * (r32Buf[2] - r32Buf[3]);
r32Buf[1] -= r32Buf[0];
ptrDst[nDstInterval] = r32Buf[0];
ptrDst[nDstInterval * 3] = r32Buf[1];
}
else {
// regular DCT
//////////////////////////////////////////////////////////////////////
// | I J |
// cross ops = | |
// | I -J |
unsigned int nDegreeNum = (1 << nDegreeDCT);
unsigned int nHalfDegree = (nDegreeNum >> 1);
for (int i = 0; i < nHalfDegree; i++) {
ptrWorkBuf[i] = ptrSrc[i] + ptrSrc[nDegreeNum - i - 1];
ptrWorkBuf[i + nHalfDegree] = ptrSrc[i] - ptrSrc[nDegreeNum - i - 1];
}
// first half DCT : A * DCT
unsigned int nDstStep = (nDstInterval << 1);
eriFastDCT(ptrDst, nDstStep, ptrWorkBuf, ptrSrc, (nDegreeDCT - 1));
// last half DCT-IV : R * 2 * A * DCT * K
float* pDCTofK = ERI_pMatrixDCTofK[nDegreeDCT - 1];
ptrSrc = ptrWorkBuf + nHalfDegree;
ptrDst += nDstInterval;
for (int i = 0; i < nHalfDegree; i++) {
ptrSrc[i] *= pDCTofK[i];
}
eriFastDCT(ptrDst, nDstStep, ptrSrc, ptrWorkBuf, (nDegreeDCT - 1));
float* ptrNext = ptrDst;
for (int i = 0; i < nHalfDegree; i++) {
*ptrNext += *ptrNext;
ptrNext += nDstStep;
}
ptrNext = ptrDst;
for (int i = 1; i < nHalfDegree; i++) {
ptrNext[nDstStep] -= *ptrNext;
ptrNext += nDstStep;
}
}
}
void EMT_eriFastIDCT(float* ptrDst, float* ptrSrc, unsigned int nSrcInterval, float* ptrWorkBuf, unsigned int nDegreeDCT) {
if (nDegreeDCT < MIN_DCT_DEGREE || nDegreeDCT > MAX_DCT_DEGREE)
return;
if (nDegreeDCT == MIN_DCT_DEGREE) {
// 4th order IDCT
float r32Buf1[2];
float r32Buf2[4];
// even rows: IDCT2
r32Buf1[0] = ptrSrc[0];
r32Buf1[1] = ERI_rCosPI4 * ptrSrc[nSrcInterval * 2];
r32Buf2[0] = r32Buf1[0] + r32Buf1[1];
r32Buf2[1] = r32Buf1[0] - r32Buf1[1];
// odd rows: R * 2 * A * DCT * K
r32Buf1[0] = ERI_DCTofK2[0] * ptrSrc[nSrcInterval];
r32Buf1[1] = ERI_DCTofK2[1] * ptrSrc[nSrcInterval * 3];
r32Buf2[2] = r32Buf1[0] + r32Buf1[1];
r32Buf2[3] = ERI_r2CosPI4 * (r32Buf1[0] - r32Buf1[1]);
r32Buf2[3] -= r32Buf2[2];
// cross ops
ptrDst[0] = r32Buf2[0] + r32Buf2[2];
ptrDst[3] = r32Buf2[0] - r32Buf2[2];
ptrDst[1] = r32Buf2[1] + r32Buf2[3];
ptrDst[2] = r32Buf2[1] - r32Buf2[3];
}
else {
// regular IDCT
//////////////////////////////////////////////////////////////////////
// even rows: IDCT
unsigned int nDegreeNum = (1 << nDegreeDCT);
unsigned int nHalfDegree = (nDegreeNum >> 1);
unsigned int nSrcStep = (nSrcInterval << 1);
EMT_eriFastIDCT(ptrDst, ptrSrc, nSrcStep, ptrWorkBuf, (nDegreeDCT - 1));
// odd rows: R * 2 * A * DCT * K
float* pDCTofK = ERI_pMatrixDCTofK[nDegreeDCT - 1];
float* pOddSrc = ptrSrc + nSrcInterval;
float* pOddDst = ptrDst + nHalfDegree;
float* ptrNext = pOddSrc;
for (int i = 0; i < nHalfDegree; i++) {
ptrWorkBuf[i] = *ptrNext * pDCTofK[i];
ptrNext += nSrcStep;
}
eriFastDCT(pOddDst, 1, ptrWorkBuf, (ptrWorkBuf + nHalfDegree), (nDegreeDCT - 1));
for (int i = 0; i < nHalfDegree; i++) {
pOddDst[i] += pOddDst[i];
}
for (int i = 1; i < nHalfDegree; i++) {
pOddDst[i] -= pOddDst[i - 1];
}
// | I I |
// cross ops = | |
// | J -J |
float r32Buf[4];
unsigned int nQuadDegree = (nHalfDegree >> 1);
for (int i = 0; i < nQuadDegree; i++) {
r32Buf[0] = ptrDst[i] + ptrDst[nHalfDegree + i];
r32Buf[3] = ptrDst[i] - ptrDst[nHalfDegree + i];
r32Buf[1] = ptrDst[nHalfDegree - 1 - i] + ptrDst[nDegreeNum - 1 - i];
r32Buf[2] = ptrDst[nHalfDegree - 1 - i] - ptrDst[nDegreeNum - 1 - i];
ptrDst[i] = r32Buf[0];
ptrDst[nHalfDegree - 1 - i] = r32Buf[1];
ptrDst[nHalfDegree + i] = r32Buf[2];
ptrDst[nDegreeNum - 1 - i] = r32Buf[3];
}
}
}

View file

@ -0,0 +1,30 @@
/* Handles file ops like parsing header and reading blocks.
*/
#ifndef _MIO_ERISA_MATRIX_H_
#define _MIO_ERISA_MATRIX_H_
#define MIN_DCT_DEGREE 2
#define MAX_DCT_DEGREE 12
typedef struct {
float rSin;
float rCos;
} ERI_SIN_COS;
void EMT_eriInitializeMatrix(void);
void EMT_eriRoundR32ToWordArray(SWORD* ptrDst, int nStep, const float* ptrSrc, int nCount);
void EMT_eriRevolve2x2(float* ptrBuf1, float* ptrBuf2, float rSin, float rCos, unsigned int nStep, unsigned int nCount);
ERI_SIN_COS* EMT_eriCreateRevolveParameter(unsigned int nDegreeDCT);
void EMT_eriOddGivensInverseMatrix(float* ptrSrc, const ERI_SIN_COS* ptrRevolve, unsigned int nDegreeDCT);
void EMT_eriFastIPLOT(float* ptrSrc, unsigned int nDegreeDCT);
void EMT_eriFastILOT(float* ptrDst, const float* ptrSrc1, const float* ptrSrc2, unsigned int nDegreeDCT);
void EMT_eriFastIDCT(float* ptrDst, float* ptrSrc, unsigned int nSrcInterval, float* ptrWorkBuf, unsigned int nDegreeDCT);
#endif

View file

@ -0,0 +1,991 @@
/*****************************************************************************
E R I S A - L i b r a r y
-----------------------------------------------------------------------------
Copyright (C) 2002-2003 Leshade Entis, Entis-soft. All rights reserved.
*****************************************************************************/
#include <stdlib.h>
#include <math.h>
#include "mio_xerisa.h"
static const double ERI_PI = 3.141592653589;
#define MIO_MAX_CHANNELS 2
/*******************/
/* audio converter */
/*******************/
MIODecoder* MIODecoder_Open() {
MIODecoder* dec = calloc(1, sizeof(MIODecoder));
if (!dec)
return NULL;
dec->m_nBufLength = 0;
dec->m_ptrBuffer1 = NULL;
dec->m_ptrBuffer2 = NULL;
dec->m_ptrBuffer3 = NULL;
dec->m_ptrDivisionTable = NULL;
dec->m_ptrRevolveCode = NULL;
dec->m_ptrWeightCode = NULL;
dec->m_ptrCoefficient = NULL;
dec->m_ptrMatrixBuf = NULL;
dec->m_ptrInternalBuf = NULL;
dec->m_ptrWorkBuf = NULL;
dec->m_ptrWeightTable = NULL;
dec->m_ptrLastDCT = NULL;
dec->m_pRevolveParam = NULL;
return dec;
}
static void MIODecoder_Delete(MIODecoder* dec) {
free(dec->m_ptrBuffer1);
dec->m_ptrBuffer1 = NULL;
free(dec->m_ptrBuffer2);
dec->m_ptrBuffer2 = NULL;
free(dec->m_ptrBuffer3);
dec->m_ptrBuffer3 = NULL;
free(dec->m_ptrDivisionTable);
dec->m_ptrDivisionTable = NULL;
free(dec->m_ptrRevolveCode);
dec->m_ptrRevolveCode = NULL;
free(dec->m_ptrWeightCode);
dec->m_ptrWeightCode = NULL;
free(dec->m_ptrCoefficient);
dec->m_ptrCoefficient = NULL;
free(dec->m_ptrMatrixBuf);
dec->m_ptrMatrixBuf = NULL;
free(dec->m_ptrInternalBuf);
dec->m_ptrInternalBuf = NULL;
free(dec->m_ptrWorkBuf);
dec->m_ptrWorkBuf = NULL;
free(dec->m_ptrWeightTable);
dec->m_ptrWeightTable = NULL;
free(dec->m_ptrLastDCT);
dec->m_ptrLastDCT = NULL;
free(dec->m_pRevolveParam);
dec->m_pRevolveParam = NULL;
dec->m_nBufLength = 0;
}
void MIODecoder_Close(MIODecoder* dec) {
if (!dec)
return;
MIODecoder_Delete(dec);
free(dec);
}
// recalculate matrix size when params change
static int MIODecoder_InitializeWithDegree(MIODecoder* dec, unsigned int nSubbandDegree) {
free(dec->m_pRevolveParam);
dec->m_pRevolveParam = EMT_eriCreateRevolveParameter(nSubbandDegree);
if (!dec->m_pRevolveParam) return eslErrGeneral;
// params for inverse quantization
static const int freq_width[7] = { -6, -6, -5, -4, -3, -2, -1 };
for (int i = 0, j = 0; i < 7; i++) {
int nFrequencyWidth = 1 << (nSubbandDegree + freq_width[i]);
dec->m_nFrequencyPoint[i] = j + (nFrequencyWidth / 2);
j += nFrequencyWidth;
}
dec->m_nSubbandDegree = nSubbandDegree;
dec->m_nDegreeNum = (1 << nSubbandDegree);
return eslErrSuccess;
}
ESLError MIODecoder_Initialize(MIODecoder* dec, const MIO_INFO_HEADER* infhdr) {
MIODecoder_Delete(dec);
dec->m_mioih = *infhdr; /* copy */
if (dec->m_mioih.fdwTransformation == CVTYPE_LOSSLESS_ERI) {
if (dec->m_mioih.dwArchitecture != ERI_RUNLENGTH_HUFFMAN)
return eslErrGeneral;
if ((dec->m_mioih.dwChannelCount != 1) && (dec->m_mioih.dwChannelCount != 2))
return eslErrGeneral;
if ((dec->m_mioih.dwBitsPerSample != 8) && (dec->m_mioih.dwBitsPerSample != 16))
return eslErrGeneral;
}
else if ((dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI) || (dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI_MSS)) {
if ((dec->m_mioih.dwArchitecture != ERI_RUNLENGTH_GAMMA) &&
(dec->m_mioih.dwArchitecture != ERI_RUNLENGTH_HUFFMAN) &&
(dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE))
return eslErrGeneral; /* unknown code format */
if ((dec->m_mioih.dwChannelCount != 1) && (dec->m_mioih.dwChannelCount != 2))
return eslErrGeneral;
if (dec->m_mioih.dwBitsPerSample != 16)
return eslErrGeneral;
if ((dec->m_mioih.dwSubbandDegree < 8) || (dec->m_mioih.dwSubbandDegree > MAX_DCT_DEGREE))
return eslErrGeneral;
if (dec->m_mioih.dwLappedDegree != 1)
return eslErrGeneral;
// DCT buffers
{
int channel_size = sizeof(float) << dec->m_mioih.dwSubbandDegree;
int buf_size = dec->m_mioih.dwChannelCount * channel_size;
dec->m_ptrBuffer1 = malloc(buf_size);
dec->m_ptrMatrixBuf = malloc(buf_size);
dec->m_ptrInternalBuf = malloc(buf_size);
dec->m_ptrWorkBuf = malloc(channel_size);
if (!dec->m_ptrBuffer1 || !dec->m_ptrMatrixBuf || !dec->m_ptrInternalBuf || !dec->m_ptrWorkBuf)
return eslErrGeneral;
}
// dequantization buffers
{
int channel_size = sizeof(float) << dec->m_mioih.dwSubbandDegree;
dec->m_ptrWeightTable = malloc(channel_size);
if (!dec->m_ptrWeightTable)
return eslErrGeneral;
}
// LOT buffers
{
int nBlocksetSamples = dec->m_mioih.dwChannelCount << dec->m_mioih.dwSubbandDegree;
int nLappedSamples = nBlocksetSamples * dec->m_mioih.dwLappedDegree;
if (nLappedSamples > 0) {
dec->m_ptrLastDCT = malloc(sizeof(float) * nLappedSamples);
if (!dec->m_ptrLastDCT)
return eslErrGeneral;
for (int i = 0; i < nLappedSamples; i++) {
dec->m_ptrLastDCT[i] = 0.0F;
}
}
}
if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree))
return eslErrGeneral;
}
else {
return eslErrGeneral;
}
return eslErrSuccess;
}
static ESLError MIODecoder_DecodeSoundPCM8(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) {
unsigned int nSampleCount = datahdr->dwSampleCount;
unsigned int nChannelCount = dec->m_mioih.dwChannelCount;
unsigned int nAllSampleCount = nSampleCount * nChannelCount;
ULONG nBytes = nAllSampleCount * sizeof(BYTE);
if (nSampleCount > dec->m_nBufLength) {
free(dec->m_ptrBuffer1);
dec->m_ptrBuffer1 = malloc(nBytes);
if (!dec->m_ptrBuffer1)
return eslErrGeneral;
dec->m_nBufLength = nSampleCount;
}
// prepare huffman codes
if (datahdr->bytFlags & MIO_LEAD_BLOCK) {
ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1);
if (err != eslErrSuccess) return err;
}
if (MIOContext_DecodeSymbolBytes(context, (SBYTE*)dec->m_ptrBuffer1, nBytes) < nBytes) {
return eslErrGeneral;
}
// differential processing output
BYTE* ptrSrcBuf = dec->m_ptrBuffer1;
BYTE* ptrDstBuf;
unsigned int nStep = nChannelCount;
unsigned int i, j;
for (i = 0; i < dec->m_mioih.dwChannelCount; i++) {
ptrDstBuf = ptrWaveBuf;
ptrDstBuf += i;
BYTE bytValue = 0;
for (j = 0; j < nSampleCount; j++) {
bytValue += *(ptrSrcBuf++);
*ptrDstBuf = bytValue;
ptrDstBuf += nStep;
}
}
return eslErrSuccess;
}
static ESLError MIODecoder_DecodeSoundPCM16(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) {
unsigned int i, j;
unsigned int nSampleCount = datahdr->dwSampleCount;
unsigned int nChannelCount = dec->m_mioih.dwChannelCount;
unsigned int nAllSampleCount = nSampleCount * nChannelCount;
ULONG nBytes = nAllSampleCount * sizeof(SWORD);
if (nSampleCount > dec->m_nBufLength) {
free(dec->m_ptrBuffer1);
free(dec->m_ptrBuffer2);
dec->m_ptrBuffer1 = malloc(nBytes);
dec->m_ptrBuffer2 = malloc(nBytes);
if (!dec->m_ptrBuffer1 || !dec->m_ptrBuffer2)
return eslErrGeneral;
dec->m_nBufLength = nSampleCount;
}
// prepare huffman codes
if (datahdr->bytFlags & MIO_LEAD_BLOCK) {
ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1);
if (err != eslErrSuccess) return err;
}
if (MIOContext_DecodeSymbolBytes(context, (SBYTE*)dec->m_ptrBuffer1, nBytes) < nBytes) {
return eslErrGeneral;
}
// pack hi/lo bytes
BYTE* pbytSrcBuf1;
BYTE* pbytSrcBuf2;
BYTE* pbytDstBuf;
for (i = 0; i < nChannelCount; i++) {
unsigned int nOffset = i * nSampleCount * sizeof(SWORD);
pbytSrcBuf1 = ((BYTE*)dec->m_ptrBuffer1) + nOffset;
pbytSrcBuf2 = pbytSrcBuf1 + nSampleCount;
pbytDstBuf = ((BYTE*)dec->m_ptrBuffer2) + nOffset;
for (j = 0; j < nSampleCount; j++) {
SBYTE bytLow = pbytSrcBuf2[j];
SBYTE bytHigh = pbytSrcBuf1[j];
pbytDstBuf[j * sizeof(SWORD) + 0] = bytLow;
pbytDstBuf[j * sizeof(SWORD) + 1] = bytHigh ^ (bytLow >> 7);
}
}
// differential processing output
SWORD* ptrSrcBuf = dec->m_ptrBuffer2;
SWORD* ptrDstBuf;
unsigned int nStep = dec->m_mioih.dwChannelCount;
for (i = 0; i < dec->m_mioih.dwChannelCount; i++) {
ptrDstBuf = ptrWaveBuf;
ptrDstBuf += i;
SWORD wValue = 0;
SWORD wDelta = 0;
for (j = 0; j < nSampleCount; j++) {
wDelta += *(ptrSrcBuf++);
wValue += wDelta;
*ptrDstBuf = wValue;
ptrDstBuf += nStep;
}
}
return eslErrSuccess;
}
//////////////////////////////////////////////////////////////////////////////
static void MIODecoder_IQuantumize(MIODecoder* dec, float* ptrDestination, const INT* ptrQuantumized, int nDegreeNum, SDWORD nWeightCode, int nCoefficient) {
int i, j;
double rMatrixScale = sqrt(2.0 / nDegreeNum);
double rCoefficient = rMatrixScale * nCoefficient;
// generate weight table
double rAvgRatio[7];
for (i = 0; i < 6; i++) {
rAvgRatio[i] = 1.0 / pow(2.0, (((nWeightCode >> (i * 5)) & 0x1F) - 15) * 0.5);
}
rAvgRatio[6] = 1.0;
for (i = 0; i < dec->m_nFrequencyPoint[0]; i++) {
dec->m_ptrWeightTable[i] = (float)rAvgRatio[0];
}
for (j = 1; j < 7; j++) {
double a = rAvgRatio[j - 1];
double k = (rAvgRatio[j] - a) / (dec->m_nFrequencyPoint[j] - dec->m_nFrequencyPoint[j - 1]);
while (i < dec->m_nFrequencyPoint[j]) {
dec->m_ptrWeightTable[i] = (float)(k * (i - dec->m_nFrequencyPoint[j - 1]) + a);
i++;
}
}
while (i < nDegreeNum) {
dec->m_ptrWeightTable[i] = (float)rAvgRatio[6];
i++;
}
float rOddWeight = (float)((((nWeightCode >> 30) & 0x03) + 0x02) / 2.0);
for (i = 15; i < nDegreeNum; i += 16) {
dec->m_ptrWeightTable[i] *= rOddWeight;
}
dec->m_ptrWeightTable[nDegreeNum - 1] = (float)nCoefficient;
for (i = 0; i < nDegreeNum; i++) {
dec->m_ptrWeightTable[i] = 1.0F / dec->m_ptrWeightTable[i];
}
// dequantize
for (i = 0; i < nDegreeNum; i++) {
ptrDestination[i] = (float)(rCoefficient * dec->m_ptrWeightTable[i] * ptrQuantumized[i]);
}
}
//////////////////////////////////////////////////////////////////////////////
/* Dequantizes and transforms block frames. Lib divides them into "lead" (keyframes),
* "internal" (standard) and "post" blocks, handled slightly differently. All of them can be MSS
* blocks, which OG code handles in a separate function (presumably as a minor optimization to
* avoid setting extra FORs), but here are handled with a flag since they are very similar. */
static ESLError MIODecoder_DecodeLeadBlock_All(MIODecoder* dec, int is_mss) {
unsigned int ch, i;
unsigned int nHalfDegree = dec->m_nDegreeNum / 2;
int internal_channels = is_mss ? 2 : 1;
//int output_channels = is_mss ? 2 : dec->m_mioih.dwChannelCount;
SDWORD nWeightCode = *(dec->m_ptrNextWeight++);
int nCoefficient = *(dec->m_ptrNextCoefficient++);
float* ptrLapBuf;
// dequantize
ptrLapBuf = dec->m_ptrLastDCTBuf;
for (ch = 0; ch < internal_channels; ch++) {
INT* ptrTempBuf = dec->m_ptrBuffer1;
for (i = 0; i < nHalfDegree; i++) {
ptrTempBuf[i * 2] = 0;
ptrTempBuf[i * 2 + 1] = *(dec->m_ptrNextSource++);
}
MIODecoder_IQuantumize(dec, ptrLapBuf, ptrTempBuf, dec->m_nDegreeNum, nWeightCode, nCoefficient);
ptrLapBuf += dec->m_nDegreeNum;
}
// revolve
if (is_mss) {
float rSin, rCos;
int nRevCode = *(dec->m_ptrNextRevCode++);
float* ptrLapBuf1 = dec->m_ptrLastDCT;
float* ptrLapBuf2 = dec->m_ptrLastDCT + dec->m_nDegreeNum;
rSin = (float)sin(nRevCode * ERI_PI / 8);
rCos = (float)cos(nRevCode * ERI_PI / 8);
EMT_eriRevolve2x2(ptrLapBuf1, ptrLapBuf2, rSin, rCos, 1, dec->m_nDegreeNum);
}
// set duplicate parameters
ptrLapBuf = dec->m_ptrLastDCTBuf;
for (ch = 0; ch < internal_channels; ch++) {
EMT_eriOddGivensInverseMatrix(ptrLapBuf, dec->m_pRevolveParam, dec->m_nSubbandDegree);
for (i = 0; i < dec->m_nDegreeNum; i += 2) {
ptrLapBuf[i] = ptrLapBuf[i + 1];
}
EMT_eriFastIPLOT(ptrLapBuf, dec->m_nSubbandDegree);
ptrLapBuf += dec->m_nDegreeNum;
}
return eslErrSuccess;
}
static ESLError MIODecoder_DecodeInternalBlock_All(MIODecoder* dec, SWORD* ptrDst, unsigned int nSamples, int is_mss) {
unsigned int ch, i;
int internal_channels = is_mss ? 2 : 1;
int output_channels = is_mss ? 2 : dec->m_mioih.dwChannelCount;
SDWORD nWeightCode = *(dec->m_ptrNextWeight++);
int nCoefficient = *(dec->m_ptrNextCoefficient++);
float* ptrLapBuf;
float* ptrSrcBuf;
// dequantize
ptrSrcBuf = dec->m_ptrMatrixBuf;
for (ch = 0; ch < internal_channels; ch++) {
MIODecoder_IQuantumize(dec, ptrSrcBuf, dec->m_ptrNextSource, dec->m_nDegreeNum, nWeightCode, nCoefficient);
dec->m_ptrNextSource += dec->m_nDegreeNum;
ptrSrcBuf += dec->m_nDegreeNum;
}
// revolve
if (is_mss) {
float rSin, rCos;
int nRevCode = *(dec->m_ptrNextRevCode++);
int nRevCode1 = (nRevCode >> 2) & 0x03;
int nRevCode2 = (nRevCode & 0x03);
float* ptrSrcBuf1 = dec->m_ptrMatrixBuf;
float* ptrSrcBuf2 = dec->m_ptrMatrixBuf + dec->m_nDegreeNum;
rSin = (float)sin(nRevCode1 * ERI_PI / 8);
rCos = (float)cos(nRevCode1 * ERI_PI / 8);
EMT_eriRevolve2x2(ptrSrcBuf1, ptrSrcBuf2, rSin, rCos, 2, dec->m_nDegreeNum / 2);
rSin = (float)sin(nRevCode2 * ERI_PI / 8);
rCos = (float)cos(nRevCode2 * ERI_PI / 8);
EMT_eriRevolve2x2(ptrSrcBuf1 + 1, ptrSrcBuf2 + 1, rSin, rCos, 2, dec->m_nDegreeNum / 2);
}
// inverse LOT + DCT
ptrLapBuf = dec->m_ptrLastDCTBuf;
ptrSrcBuf = dec->m_ptrMatrixBuf;
for (ch = 0; ch < internal_channels; ch++) {
EMT_eriOddGivensInverseMatrix(ptrSrcBuf, dec->m_pRevolveParam, dec->m_nSubbandDegree);
EMT_eriFastIPLOT(ptrSrcBuf, dec->m_nSubbandDegree);
EMT_eriFastILOT(dec->m_ptrWorkBuf, ptrLapBuf, ptrSrcBuf, dec->m_nSubbandDegree);
for (i = 0; i < dec->m_nDegreeNum; i++) {
ptrLapBuf[i] = ptrSrcBuf[i];
ptrSrcBuf[i] = dec->m_ptrWorkBuf[i];
}
EMT_eriFastIDCT(dec->m_ptrInternalBuf, ptrSrcBuf, 1, dec->m_ptrWorkBuf, dec->m_nSubbandDegree);
EMT_eriRoundR32ToWordArray(ptrDst + ch, output_channels, dec->m_ptrInternalBuf, nSamples);
ptrLapBuf += dec->m_nDegreeNum;
ptrSrcBuf += dec->m_nDegreeNum;
}
return eslErrSuccess;
}
static ESLError MIODecoder_DecodePostBlock_All(MIODecoder* dec, SWORD* ptrDst, unsigned int nSamples, int is_mss) {
unsigned int ch, i;
unsigned int nHalfDegree = dec->m_nDegreeNum / 2;
int internal_channels = is_mss ? 2 : 1;
int output_channels = is_mss ? 2 : dec->m_mioih.dwChannelCount;
SDWORD nWeightCode = *(dec->m_ptrNextWeight++);
int nCoefficient = *(dec->m_ptrNextCoefficient++);
float* ptrLapBuf;
float* ptrSrcBuf;
// dequantize
ptrSrcBuf = dec->m_ptrMatrixBuf;
for (ch = 0; ch < internal_channels; ch++) {
INT* ptrTempBuf = dec->m_ptrBuffer1;
for (i = 0; i < nHalfDegree; i++) {
ptrTempBuf[i * 2] = 0;
ptrTempBuf[i * 2 + 1] = *(dec->m_ptrNextSource++);
}
MIODecoder_IQuantumize(dec, ptrSrcBuf, ptrTempBuf, dec->m_nDegreeNum, nWeightCode, nCoefficient);
ptrSrcBuf += dec->m_nDegreeNum;
}
// revolve
if (is_mss) {
float rSin, rCos;
int nRevCode = *(dec->m_ptrNextRevCode++);
float* ptrSrcBuf1 = dec->m_ptrMatrixBuf; //L
float* ptrSrcBuf2 = dec->m_ptrMatrixBuf + dec->m_nDegreeNum; //R
rSin = (float)sin(nRevCode * ERI_PI / 8);
rCos = (float)cos(nRevCode * ERI_PI / 8);
EMT_eriRevolve2x2(ptrSrcBuf1, ptrSrcBuf2, rSin, rCos, 1, dec->m_nDegreeNum);
}
// inverse LOT + DCT
ptrLapBuf = dec->m_ptrLastDCTBuf;
ptrSrcBuf = dec->m_ptrMatrixBuf;
for (ch = 0; ch < internal_channels; ch++) {
EMT_eriOddGivensInverseMatrix(ptrSrcBuf, dec->m_pRevolveParam, dec->m_nSubbandDegree);
for (i = 0; i < dec->m_nDegreeNum; i += 2) {
ptrSrcBuf[i] = -ptrSrcBuf[i + 1];
}
EMT_eriFastIPLOT(ptrSrcBuf, dec->m_nSubbandDegree);
EMT_eriFastILOT(dec->m_ptrWorkBuf, ptrLapBuf, ptrSrcBuf, dec->m_nSubbandDegree);
for (i = 0; i < dec->m_nDegreeNum; i++) {
ptrSrcBuf[i] = dec->m_ptrWorkBuf[i];
}
EMT_eriFastIDCT(dec->m_ptrInternalBuf, ptrSrcBuf, 1, dec->m_ptrWorkBuf, dec->m_nSubbandDegree);
EMT_eriRoundR32ToWordArray(ptrDst + ch, output_channels, dec->m_ptrInternalBuf, nSamples);
ptrLapBuf += dec->m_nDegreeNum;
ptrSrcBuf += dec->m_nDegreeNum;
}
return eslErrSuccess;
}
//////////////////////////////////////////////////////////////////////////////
static ESLError MIODecoder_DecodeSoundDCT_Std(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) {
unsigned int i, j, k;
unsigned int nDegreeWidth = (1 << dec->m_mioih.dwSubbandDegree);
unsigned int nSampleCount = (datahdr->dwSampleCount + nDegreeWidth - 1) & ~(nDegreeWidth - 1);
unsigned int nSubbandCount = (nSampleCount >> dec->m_mioih.dwSubbandDegree);
unsigned int nChannelCount = dec->m_mioih.dwChannelCount;
unsigned int nAllSampleCount = nSampleCount * nChannelCount;
unsigned int nAllSubbandCount = nSubbandCount * nChannelCount;
if (nSampleCount > dec->m_nBufLength) {
free(dec->m_ptrBuffer2);
free(dec->m_ptrBuffer3);
free(dec->m_ptrDivisionTable);
free(dec->m_ptrWeightCode);
free(dec->m_ptrCoefficient);
dec->m_ptrBuffer2 = malloc(nAllSampleCount * sizeof(INT));
dec->m_ptrBuffer3 = malloc(nAllSampleCount * sizeof(SWORD));
dec->m_ptrDivisionTable = malloc(nAllSubbandCount * sizeof(BYTE));
dec->m_ptrWeightCode = malloc(nAllSubbandCount * 5 * sizeof(SDWORD));
dec->m_ptrCoefficient = malloc(nAllSubbandCount * 5 * sizeof(INT));
if (!dec->m_ptrBuffer2 || !dec->m_ptrBuffer3 || !dec->m_ptrDivisionTable || !dec->m_ptrWeightCode || !dec->m_ptrCoefficient)
return eslErrGeneral;
dec->m_nBufLength = nSampleCount;
}
// decode quantization table
if (MIOContext_GetABit(context) != 0) {
return eslErrGeneral;
}
unsigned int pLastDivision[MIO_MAX_CHANNELS];
for (i = 0; i < nChannelCount; i++) {
pLastDivision[i] = -1;
}
dec->m_ptrNextDivision = dec->m_ptrDivisionTable;
dec->m_ptrNextWeight = dec->m_ptrWeightCode;
dec->m_ptrNextCoefficient = dec->m_ptrCoefficient;
for (i = 0; i < nSubbandCount; i++) {
for (j = 0; j < nChannelCount; j++) {
unsigned int nDivisionCode = MIOContext_GetNBits(context, 2);
*(dec->m_ptrNextDivision++) = (BYTE)nDivisionCode;
if (nDivisionCode != pLastDivision[j]) {
if (i != 0) {
*(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32);
*(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16);
}
pLastDivision[j] = nDivisionCode;
}
unsigned int nDivisionCount = (1 << nDivisionCode);
for (k = 0; k < nDivisionCount; k++) {
*(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32);
*(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16);
}
}
}
if (nSubbandCount > 0) {
for (i = 0; i < nChannelCount; i++) {
*(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32);
*(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16);
}
}
/* sync? */
if (MIOContext_GetABit(context) != 0) {
return eslErrGeneral;
}
// init code model if needed
if (datahdr->bytFlags & MIO_LEAD_BLOCK) {
if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) {
ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1);
if (err != eslErrSuccess) return err;
}
else {
ESLError err = MIOContext_PrepareToDecodeERISACode(context);
if (err != eslErrSuccess) return err;
}
}
else if (dec->m_mioih.dwArchitecture == ERISA_NEMESIS_CODE) {
MIOContext_InitializeERISACode(context);
}
// decode and deinterleave
if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) {
if (MIOContext_DecodeSymbolBytes(context, dec->m_ptrBuffer3, nAllSampleCount * 2) < nAllSampleCount * 2) {
return eslErrGeneral;
}
SBYTE* ptrHBuf = dec->m_ptrBuffer3;
SBYTE* ptrLBuf = ptrHBuf + nAllSampleCount;
for (i = 0; i < nDegreeWidth; i++) {
INT* ptrQuantumized = ((INT*)dec->m_ptrBuffer2) + i;
for (j = 0; j < nAllSubbandCount; j++) {
INT nLow = *(ptrLBuf++);
INT nHigh = *(ptrHBuf++) ^ (nLow >> 8);
*ptrQuantumized = (nLow & 0xFF) | (nHigh << 8);
ptrQuantumized += nDegreeWidth;
}
}
}
else {
if (MIOContext_DecodeERISACodeWords(context, (SWORD*)dec->m_ptrBuffer3, nAllSampleCount) < nAllSampleCount) {
return eslErrGeneral;
}
SWORD* ptrTmp = dec->m_ptrBuffer3;
for (i = 0; i < nAllSampleCount; i++) {
((INT*)dec->m_ptrBuffer2)[i] = (ptrTmp)[i];
}
}
// apply iDCT to subband units
unsigned int nSamples;
unsigned int pRestSamples[MIO_MAX_CHANNELS];
SWORD* ptrDstBuf[MIO_MAX_CHANNELS];
dec->m_ptrNextDivision = dec->m_ptrDivisionTable;
dec->m_ptrNextWeight = dec->m_ptrWeightCode;
dec->m_ptrNextCoefficient = dec->m_ptrCoefficient;
dec->m_ptrNextSource = dec->m_ptrBuffer2;
for (i = 0; i < nChannelCount; i++) {
pLastDivision[i] = -1;
pRestSamples[i] = datahdr->dwSampleCount;
ptrDstBuf[i] = ((SWORD*)ptrWaveBuf) + i;
}
unsigned int nCurrentDivision = -1;
for (i = 0; i < nSubbandCount; i++) {
for (j = 0; j < nChannelCount; j++) {
// get division/decomposition code
unsigned int nDivisionCode = *(dec->m_ptrNextDivision++);
unsigned int nDivisionCount = (1 << nDivisionCode);
// get buffer for duplicate processing
int nChannelStep = nDegreeWidth * dec->m_mioih.dwLappedDegree * j;
dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT + nChannelStep;
// processing when matrix size changes
int bLeadBlock = 0;
if (pLastDivision[j] != nDivisionCode) {
// complete until last moment
if (i != 0) {
if (nCurrentDivision != pLastDivision[j]) {
if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - pLastDivision[j]))
return eslErrGeneral;
nCurrentDivision = pLastDivision[j];
}
nSamples = pRestSamples[j];
if (nSamples > dec->m_nDegreeNum) {
nSamples = dec->m_nDegreeNum;
}
if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf[j], nSamples, 0)) {
return eslErrGeneral;
}
pRestSamples[j] -= nSamples;
ptrDstBuf[j] += nSamples * nChannelCount;
}
// set params to change matrix size
pLastDivision[j] = nDivisionCode;
bLeadBlock = 1;
}
if (nCurrentDivision != nDivisionCode) {
if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - nDivisionCode))
return eslErrGeneral;
nCurrentDivision = nDivisionCode;
}
// perform sequential iLOT
for (k = 0; k < nDivisionCount; k++) {
if (bLeadBlock) {
// decode lead block
if (MIODecoder_DecodeLeadBlock_All(dec, 0)) {
return eslErrGeneral;
}
bLeadBlock = 0;
}
else {
// decode regular block
nSamples = pRestSamples[j];
if (nSamples > dec->m_nDegreeNum) {
nSamples = dec->m_nDegreeNum;
}
if (MIODecoder_DecodeInternalBlock_All(dec, ptrDstBuf[j], nSamples, 0)) {
return eslErrGeneral;
}
pRestSamples[j] -= nSamples;
ptrDstBuf[j] += nSamples * nChannelCount;
}
}
}
}
// complete the matrix
if (nSubbandCount > 0) {
for (i = 0; i < nChannelCount; i++) {
int nChannelStep = nDegreeWidth * dec->m_mioih.dwLappedDegree * i;
dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT + nChannelStep;
if (nCurrentDivision != pLastDivision[i]) {
if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - pLastDivision[i]))
return eslErrGeneral;
nCurrentDivision = pLastDivision[i];
}
nSamples = pRestSamples[i];
if (nSamples > dec->m_nDegreeNum) {
nSamples = dec->m_nDegreeNum;
}
if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf[i], nSamples, 0)) {
return eslErrGeneral;
}
pRestSamples[i] -= nSamples;
ptrDstBuf[i] += nSamples * nChannelCount;
}
}
return eslErrSuccess;
}
static ESLError MIODecoder_DecodeSoundDCT_MSS(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) {
unsigned int i, j, k;
unsigned int nDegreeWidth = (1 << dec->m_mioih.dwSubbandDegree);
unsigned int nSampleCount = (datahdr->dwSampleCount + nDegreeWidth - 1) & ~(nDegreeWidth - 1);
unsigned int nSubbandCount = (nSampleCount >> dec->m_mioih.dwSubbandDegree);
unsigned int nChannelCount = dec->m_mioih.dwChannelCount; // usually 2
unsigned int nAllSampleCount = nSampleCount * nChannelCount;
unsigned int nAllSubbandCount = nSubbandCount;
if (nSampleCount > dec->m_nBufLength) {
free(dec->m_ptrBuffer2);
free(dec->m_ptrBuffer3);
free(dec->m_ptrDivisionTable);
free(dec->m_ptrRevolveCode);
free(dec->m_ptrWeightCode);
free(dec->m_ptrCoefficient);
dec->m_ptrBuffer2 = malloc(nAllSampleCount * sizeof(INT));
dec->m_ptrBuffer3 = malloc(nAllSampleCount * sizeof(SWORD));
dec->m_ptrDivisionTable = malloc(nAllSubbandCount * sizeof(BYTE));
dec->m_ptrRevolveCode = malloc(nAllSubbandCount * 10 * sizeof(BYTE));
dec->m_ptrWeightCode = malloc(nAllSubbandCount * 10 * sizeof(SDWORD));
dec->m_ptrCoefficient = malloc(nAllSubbandCount * 10 * sizeof(INT));
if (!dec->m_ptrBuffer2 || !dec->m_ptrBuffer3 || !dec->m_ptrDivisionTable || !dec->m_ptrRevolveCode || !dec->m_ptrWeightCode || !dec->m_ptrCoefficient)
return eslErrGeneral;
dec->m_nBufLength = nSampleCount;
}
// decode quantization table
if (MIOContext_GetABit(context) != 0) {
return eslErrGeneral;
}
unsigned int nLastDivision = -1;
dec->m_ptrNextDivision = dec->m_ptrDivisionTable;
dec->m_ptrNextRevCode = dec->m_ptrRevolveCode;
dec->m_ptrNextWeight = dec->m_ptrWeightCode;
dec->m_ptrNextCoefficient = dec->m_ptrCoefficient;
for (i = 0; i < nSubbandCount; i++) {
unsigned int nDivisionCode = MIOContext_GetNBits(context, 2);
*(dec->m_ptrNextDivision++) = (BYTE)nDivisionCode;
int bLeadBlock = 0;
if (nDivisionCode != nLastDivision) {
if (i != 0) {
*(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 2);
*(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32);
*(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16);
}
bLeadBlock = 1;
nLastDivision = nDivisionCode;
}
unsigned int nDivisionCount = (1 << nDivisionCode);
for (k = 0; k < nDivisionCount; k++) {
if (bLeadBlock) {
*(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 2);
bLeadBlock = 0;
}
else {
*(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 4);
}
*(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32);
*(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16);
}
}
if (nSubbandCount > 0) {
*(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 2);
*(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32);
*(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16);
}
if (MIOContext_GetABit(context) != 0) {
return eslErrGeneral;
}
if (datahdr->bytFlags & MIO_LEAD_BLOCK) {
if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) {
ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1);
if (err != eslErrSuccess) return err;
}
else {
ESLError err = MIOContext_PrepareToDecodeERISACode(context);
if (err != eslErrSuccess) return err;
}
}
else if (dec->m_mioih.dwArchitecture == ERISA_NEMESIS_CODE) {
MIOContext_InitializeERISACode(context);
}
// decode and deinterleave
if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) {
if (MIOContext_DecodeSymbolBytes(context, dec->m_ptrBuffer3, nAllSampleCount * 2) < nAllSampleCount * 2) {
return eslErrGeneral;
}
SBYTE* ptrHBuf = dec->m_ptrBuffer3;
SBYTE* ptrLBuf = ptrHBuf + nAllSampleCount;
for (i = 0; i < nDegreeWidth * 2; i++) {
INT* ptrQuantumized = ((INT*)dec->m_ptrBuffer2) + i;
for (j = 0; j < nAllSubbandCount; j++) {
INT nLow = *(ptrLBuf++);
INT nHigh = *(ptrHBuf++) ^ (nLow >> 8);
*ptrQuantumized = (nLow & 0xFF) | (nHigh << 8);
ptrQuantumized += nDegreeWidth * 2;
}
}
}
else {
if (MIOContext_DecodeERISACodeWords(context, (SWORD*)dec->m_ptrBuffer3, nAllSampleCount) < nAllSampleCount) {
return eslErrGeneral;
}
SWORD* ptrTmp = dec->m_ptrBuffer3;
for (i = 0; i < nAllSampleCount; i++) {
((INT*)dec->m_ptrBuffer2)[i] = (ptrTmp)[i];
}
}
// apply iDCT to subband units
unsigned int nSamples;
unsigned int nRestSamples = datahdr->dwSampleCount;
SWORD* ptrDstBuf = ptrWaveBuf;
nLastDivision = -1;
dec->m_ptrNextDivision = dec->m_ptrDivisionTable;
dec->m_ptrNextRevCode = dec->m_ptrRevolveCode;
dec->m_ptrNextWeight = dec->m_ptrWeightCode;
dec->m_ptrNextCoefficient = dec->m_ptrCoefficient;
dec->m_ptrNextSource = dec->m_ptrBuffer2;
for (i = 0; i < nSubbandCount; i++) {
// get division/decomposition code
unsigned int nDivisionCode = *(dec->m_ptrNextDivision++);
unsigned int nDivisionCount = (1 << nDivisionCode);
// processing when matrix size changes
int bLeadBlock = 0;
dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT;
if (nLastDivision != nDivisionCode) {
// complete until last moment
if (i != 0) {
nSamples = nRestSamples;
if (nSamples > dec->m_nDegreeNum) {
nSamples = dec->m_nDegreeNum;
}
if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf, nSamples, 1)) {
return eslErrGeneral;
}
nRestSamples -= nSamples;
ptrDstBuf += nSamples * nChannelCount;
}
// set params to change matrix size
if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - nDivisionCode))
return eslErrGeneral;
nLastDivision = nDivisionCode;
bLeadBlock = 1;
}
// perform sequential iLOT
for (k = 0; k < nDivisionCount; k++) {
if (bLeadBlock) {
// decode lead block
if (MIODecoder_DecodeLeadBlock_All(dec, 1)) {
return eslErrGeneral;
}
bLeadBlock = 0;
}
else {
// decode regular block
nSamples = nRestSamples;
if (nSamples > dec->m_nDegreeNum) {
nSamples = dec->m_nDegreeNum;
}
if (MIODecoder_DecodeInternalBlock_All(dec, ptrDstBuf, nSamples, 1)) {
return eslErrGeneral;
}
nRestSamples -= nSamples;
ptrDstBuf += nSamples * nChannelCount;
}
}
}
// complete the matrix
if (nSubbandCount > 0) {
dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT;
nSamples = nRestSamples;
if (nSamples > dec->m_nDegreeNum)
nSamples = dec->m_nDegreeNum;
if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf, nSamples, 1)) {
return eslErrGeneral;
}
nRestSamples -= nSamples;
ptrDstBuf += nSamples * nChannelCount;
}
return eslErrSuccess;
}
ESLError MIODecoder_DecodeSound(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) {
MIOContext_FlushBuffer(context);
if (dec->m_mioih.fdwTransformation == CVTYPE_LOSSLESS_ERI) {
if (dec->m_mioih.dwBitsPerSample == 8) {
return MIODecoder_DecodeSoundPCM8(dec, context, datahdr, ptrWaveBuf);
}
else if (dec->m_mioih.dwBitsPerSample == 16) {
return MIODecoder_DecodeSoundPCM16(dec, context, datahdr, ptrWaveBuf);
}
}
else if ((dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI) || (dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI_MSS)) {
if ((dec->m_mioih.dwChannelCount != 2) || (dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI)) {
return MIODecoder_DecodeSoundDCT_Std(dec, context, datahdr, ptrWaveBuf);
}
else {
return MIODecoder_DecodeSoundDCT_MSS(dec, context, datahdr, ptrWaveBuf);
}
}
return eslErrGeneral;
}

View file

@ -0,0 +1,49 @@
/* Decodes audio context data into samples.
*/
#ifndef _MIO_ERISA_SOUND_H_
#define _MIO_ERISA_SOUND_H_
typedef struct {
MIO_INFO_HEADER m_mioih; // voice info header (current file)
unsigned int m_nBufLength; // block's sample count
// various internal (alloc'd) bufs
void* m_ptrBuffer1; // processing
void* m_ptrBuffer2; // reordering
void* m_ptrBuffer3; // interleave
BYTE* m_ptrDivisionTable; // block's division codes
BYTE* m_ptrRevolveCode; // block's revolve codes
SDWORD* m_ptrWeightCode; // block's quant weights
INT* m_ptrCoefficient; // block's scales
float* m_ptrMatrixBuf; // matrix ops
float* m_ptrInternalBuf; // ops helper
float* m_ptrWorkBuf; // DCT work buf
float* m_ptrWeightTable; // freq weights
float* m_ptrLastDCT; // previous DCT values
// temp pointers for the above (current pos)
BYTE* m_ptrNextDivision;
BYTE* m_ptrNextRevCode;
SDWORD* m_ptrNextWeight;
INT* m_ptrNextCoefficient;
INT* m_ptrNextSource;
float* m_ptrLastDCTBuf;
// file degree config
unsigned int m_nSubbandDegree; // matrix size (N)
unsigned int m_nDegreeNum; // derived matrix size (2^N)
ERI_SIN_COS* m_pRevolveParam; //
int m_nFrequencyPoint[7]; // freq center points
} MIODecoder;
MIODecoder* MIODecoder_Open();
void MIODecoder_Close(MIODecoder* dec);
ESLError MIODecoder_Initialize(MIODecoder* dec, const MIO_INFO_HEADER* infhdr);
ESLError MIODecoder_DecodeSound(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf);
#endif

View file

@ -0,0 +1,103 @@
/*****************************************************************************
E R I S A - L i b r a r y
-----------------------------------------------------------------------------
Copyright (C) 2002-2004 Leshade Entis, Entis-soft. All rights reserved.
*****************************************************************************/
#ifndef _MIO_ERISALIB_H_
#define _MIO_ERISALIB_H_
#include <stdint.h>
//#include <stdbool.h>
typedef unsigned char BYTE; //, *PBYTE;
typedef unsigned short int WORD; //, *PWORD;
typedef unsigned int UDWORD;
typedef signed int INT; //, *PINT;
typedef unsigned int UINT;
//typedef signed long int LONG; //, *PLONG;
typedef unsigned long int ULONG;
typedef signed char SBYTE;
typedef signed short int SWORD;
typedef signed int SDWORD;
typedef enum {
eslErrSuccess = 0,
eslErrGeneral = 1,
eslErrEof = 2, //extra
} ESLError;
void ERI_eriInitializeLibrary(void);
void ERI_eriCloseLibrary(void);
typedef struct {
uint64_t cHeader; // signature
UDWORD dwFileID;
UDWORD dwReserved; // 0
char cFormatDesc[0x30]; // format name
} EMC_FILE_HEADER;
typedef struct {
uint64_t nRecordID;
uint64_t nRecLength;
} EMC_RECORD_HEADER;
typedef struct {
UDWORD dwVersion;
UDWORD dwContainedFlag;
UDWORD dwKeyFrameCount;
UDWORD dwFrameCount;
UDWORD dwAllFrameTime;
} ERI_FILE_HEADER;
/* transformation (either lossless or LOT) */
#define CVTYPE_LOSSLESS_ERI 0x03020000
#define CVTYPE_DCT_ERI 0x00000001 // not used in audio
#define CVTYPE_LOT_ERI 0x00000005
#define CVTYPE_LOT_ERI_MSS 0x00000105
/* architecture (huffman for lossless or gamma/nemesis for LOT) */
#define ERI_ARITHMETIC_CODE 32 // not used in audio?
#define ERI_RUNLENGTH_GAMMA 0xFFFFFFFF //same as huffman with "gamma escape codes"
#define ERI_RUNLENGTH_HUFFMAN 0xFFFFFFFC
#define ERISA_NEMESIS_CODE 0xFFFFFFF0 // arithmetic coding (sliding window?)
// per file
typedef struct {
UDWORD dwVersion;
UDWORD fdwTransformation;
UDWORD dwArchitecture;
UDWORD dwChannelCount;
UDWORD dwSamplesPerSec; // input sample rate (output is fixed)
UDWORD dwBlocksetCount;
UDWORD dwSubbandDegree;
UDWORD dwAllSampleCount;
UDWORD dwLappedDegree;
UDWORD dwBitsPerSample;
// extra from comments
UDWORD rewindPoint;
} MIO_INFO_HEADER;
// per chunk
typedef struct {
BYTE bytVersion;
BYTE bytFlags;
BYTE bytReserved1;
BYTE bytReserved2;
UDWORD dwSampleCount;
} MIO_DATA_HEADER;
// Block is a "keyframe" and can be user to start decoding after flush/seek.
// Starting to decode in a non-keyframe returns an error.
#define MIO_LEAD_BLOCK 0x01
#include "mio_erisacontext.h"
#include "mio_erisafile.h"
#include "mio_erisamatrix.h"
#include "mio_erisasound.h"
#endif

View file

@ -0,0 +1,254 @@
#ifdef VGM_USE_VORBIS
#include <string.h>
#include <math.h>
#include "oor_helpers.h"
// .oor is divided into pages like "OggS", but simplified (variable sized)
// - v0: 0x01
// - v1: 0x0A
void oor_read_page(bitstream_t* is, oor_page_t* page) {
uint32_t granule_hi = 0, granule_lo = 0; //bitreader only handles 32b
page->version = bm_read(is, 2);
page->flags = bm_read(is, 4); // vorbis packet flags
// extra fields in V1
switch(page->version) {
case 0:
page->granule = 0;
page->padding1 = 0;
page->padding2 = 0;
// bitstream ends with into bit 6 of current byte
break;
case 1:
page->padding1 = bm_read(is, 2); // padding as granule must be byte-aligned
granule_hi = bm_read(is, 32);
granule_lo = bm_read(is, 32);
page->granule = ((uint64_t)granule_hi << 32) | granule_lo;
page->padding2 = bm_read(is, 6); // padding to leave bitstream into bit 6, like v0
break;
default: // unknown version
break;
}
}
// each .oor page except the first (header) has N packets:
// size is variable but theoretical max is ~0x200 (plus page header)
void oor_read_size(bitstream_t* is, oor_size_t* size) {
// right after page info (meaning 6 bits into bitstream)
size->vps_bits = bm_read(is, 4);
size->padding1 = bm_read(is, 1);
size->packet_count = bm_read(is, 8);
size->bps_selector = bm_read(is, 2);
switch(size->bps_selector) {
case 0: size->base_packet_size = 0; break; // 0 bits
case 1: size->base_packet_size = bm_read(is, 8); break;
case 2: size->base_packet_size = bm_read(is, 11); break;
case 3: //undefined
default:
size->base_packet_size = 0;
break;
}
for (int i = 0; i < size->packet_count; i++) {
if (size->vps_bits) {
size->variable_packet_size[i] = bm_read(is, size->vps_bits);
}
else {
size->variable_packet_size[i] = 0; //reset in case of reusing struct
}
}
uint32_t bit_pos = bm_pos(is) % 8;
if (bit_pos > 0) {
size->post_padding = bm_read(is, 8 - bit_pos); // aligned to next byte
}
else {
size->post_padding = 0;
}
// bitstream is now byte-aligned, and next is N packets of base + variable packet sizes (in bytes)
}
// bit-packed header (variable-sized):
// - v0 (sr_selector!=3): 0x02
// - v0 (sr_selector==3): 0x03
// - v1 (sr_selector!=3): 0x12
// - v1 (sr_selector==3): 0x13
void oor_read_header(bitstream_t* is, oor_header_t* hdr) {
hdr->pre_padding = bm_read(is, 2); // from first page, header is byte-aligned
hdr->version = bm_read(is, 2);
hdr->channels = bm_read(is, 3);
int sr_selector = bm_read(is, 2);
if (sr_selector == 3) {
int sr_index = bm_read(is, 8);
// few known modes, though they have 8 bits
// seems v1 lib can handle v0 files but sample rate is not compatible, maybe an oversight
// (note that some games somehow have both v0 and v1 files)
switch(hdr->version) {
case 0:
switch(sr_index) {
case 3: hdr->sample_rate = 32000; break;
case 4: hdr->sample_rate = 48000; break;
case 5: hdr->sample_rate = 96000; break;
default: hdr->sample_rate = 0; break;
}
case 1:
switch(sr_index) {
case 4: hdr->sample_rate = 32000; break;
case 5: hdr->sample_rate = 48000; break;
case 6: hdr->sample_rate = 64000; break;
case 7: hdr->sample_rate = 88200; break;
case 8: hdr->sample_rate = 96000; break;
default: hdr->sample_rate = 0; break;
}
break;
default:
break;
}
// shouldn't happen, but allow to catch missing cases
if (hdr->sample_rate == 0) // && sr_index < 256
hdr->sample_rate = 8000;
}
else {
hdr->sample_rate = 11025 * pow(2, sr_selector);
}
if (hdr->version == 1) {
uint32_t granule_hi = 0, granule_lo = 0; //bitreader only handles 32b
hdr->unknown1 = bm_read(is, 1); // always 1?
hdr->unknown2 = bm_read(is, 1); // always 1?
hdr->unknown3 = bm_read(is, 7); // always 0?
granule_hi = bm_read(is, 32);
granule_lo = bm_read(is, 32);
hdr->last_granule = ((uint64_t)granule_hi << 32) | granule_lo;
}
else {
hdr->unknown1 = 0;
hdr->unknown2 = 0;
hdr->unknown3 = 0;
hdr->last_granule = 0;
}
hdr->blocksize1_exp = bm_read(is, 4);
hdr->blocksize0_exp = bm_read(is, 4);
hdr->framing = bm_read(is, 1); //always 1
uint32_t bit_pos = bm_pos(is) % 8;
if (bit_pos > 0) {
hdr->post_padding = bm_read(is, 8 - bit_pos); // aligned to next byte
}
else {
hdr->post_padding = 0;
}
}
// bit-packed setup (should be byte-aligned)
void oor_read_setup(bitstream_t* is, oor_setup_t* setup) {
setup->type = bm_read(is, 2);
setup->codebook_id = bm_read(is, 6);
// known codebooks:
// 1~6: common on PC games
// 7: Muv-Luv, Muv-Luv Alternative (Vita)
}
// extra validations since bitpacket headers are a bit simple
bool oor_validate_header_page(oor_page_t* page, oor_header_t* hdr) {
if (page->version > 1 || page->flags != 0x02)
return false;
if (page->granule != 0 || page->padding1 != 0 || page->padding2 != 0)
return false;
if (hdr->pre_padding != 0 || hdr->version > 1 || hdr->version != page->version)
return false;
if (hdr->channels == 0 || hdr->sample_rate == 0)
return false;
//if (hdr->channels > OOR_MAX_CHANNELS) // known max is 2, allow to detect other cases
// return false;
if (hdr->version == 1 && hdr->last_granule == 0)
return false;
if (hdr->blocksize0_exp < 6 || hdr->blocksize0_exp > 13 || hdr->blocksize1_exp < 6 || hdr->blocksize1_exp > 13)
return false;
if (hdr->framing != 1)
return false;
if (hdr->post_padding != 0)
return false;
return true;
}
bool oor_validate_setup_page(oor_page_t* page, oor_size_t* size, oor_header_t* hdr) {
if (page->version != hdr->version)
return false;
// oddly enough codebooks may be split into other pages using OOR_FLAG_PARTIAL
if (page->flags & OOR_FLAG_CONTINUED || page->flags & OOR_FLAG_BOS || page->flags & OOR_FLAG_EOS)
return false;
if (page->granule != 0 || page->padding1 != 0 || page->padding2 != 0)
return false;
if (size->padding1 != 0 || size->bps_selector == 3)
return false;
if (size->post_padding != 0)
return false;
//if (setup->type != 0x01)
// return false;
//if (setup->codebook_id > OOR_MAX_CODEBOOK_ID) // known max is 7, allow to detect other cases
// return false;
return true;
}
bool oor_validate_setup_info(oor_page_t* page, oor_size_t* size, oor_setup_t* setup) {
// setup packet always has 2 packets: setup info + vorbis codebook
if (size->packet_count != 2)
return false;
int packet0_size = size->base_packet_size + size->variable_packet_size[0];
int packet1_size = size->base_packet_size + size->variable_packet_size[1];
if (packet0_size != 0x01)
return false;
// size is 0 when using codebook ids
if ((setup->codebook_id > 0 && packet1_size != 0) || (setup->codebook_id == 0 && packet1_size == 0))
return false;
return true;
}
bool oor_validate_audio_page(oor_page_t* page, oor_size_t* size, oor_header_t* hdr) {
if (hdr != NULL && page->version != hdr->version)
return false;
if (page->flags & OOR_FLAG_BOS)
return false;
if (page->padding1 != 0 || page->padding2 != 0)
return false;
if (size->padding1 != 0 || size->bps_selector == 3)
return false;
if (size->post_padding != 0)
return false;
if (size->packet_count == 0)
return false;
return true;
}
#endif

View file

@ -0,0 +1,77 @@
#ifndef _OOR_HELPERS_H
#define _OOR_HELPERS_H
#include <stdint.h>
#include <stdbool.h>
#include "../../util/bitstream_msb.h"
/**
* OOR has custom pages similar to OggS but not quite equivalent (needs to fiddle with packets).
* Header and setup packets are custom, but audio packets are standard.
* Format is bitpacked and some parts may be ambiguous, but it should fail midway on bad data.
* Lib expects the whole file in memory and isn't well tuned for streaming though.
*
* Info from:
* - mostly https://github.com/tsudoko/deoptimizeobs (FORMAT doc describes .oor, but some info is slightly off)
* - some bits from decompilation
*/
#define OOR_FLAG_CONTINUED (1<<3) // 1000 = continued (first packet in page is part of last; equivalent to OggS 0x01)
#define OOR_FLAG_PARTIAL (1<<2) // 0100 = partial (last packet in page is not complete and must be merged with prev; OggS uses size 0xFF for this)
#define OOR_FLAG_BOS (1<<1) // 0010 = beginning-of-stream (irst page, OggS 0x02)
#define OOR_FLAG_EOS (1<<0) // 0001 = end-of-stream (last page, OggS 0x04)
//#define OOR_FLAG_NORMAL 0 // any other regular packet
typedef struct {
uint8_t version;
uint8_t flags;
int64_t granule;
int padding1;
int padding2;
} oor_page_t;
typedef struct {
uint8_t vps_bits;
uint8_t padding1;
uint8_t packet_count;
uint8_t bps_selector;
int16_t base_packet_size; // max 7FF (may be 0)
int16_t variable_packet_size[256]; // max 7FFF of N packet_count (may be 0)
uint8_t post_padding;
} oor_size_t;
typedef struct {
uint8_t pre_padding;
uint8_t version;
uint8_t channels;
int sample_rate;
uint8_t unknown1;
uint8_t unknown2;
uint8_t unknown3;
int64_t last_granule;
uint8_t blocksize0_exp;
uint8_t blocksize1_exp;
uint8_t framing;
uint8_t post_padding;
} oor_header_t;
// codebooks are set in plugin with a table of size + codebook
typedef struct {
int type;
int codebook_id;
//int codebook_size;
//uint8_t* codebook;
} oor_setup_t;
// page headers, assumes buf in bitstream (probable max ~0x200)
void oor_read_page(bitstream_t* is, oor_page_t* page);
void oor_read_size(bitstream_t* is, oor_size_t* size);
void oor_read_header(bitstream_t* is, oor_header_t* hdr);
void oor_read_setup(bitstream_t* is, oor_setup_t* setup);
bool oor_validate_header_page(oor_page_t* page, oor_header_t* hdr);
bool oor_validate_setup_page(oor_page_t* page, oor_size_t* size, oor_header_t* hdr);
bool oor_validate_setup_info(oor_page_t* page, oor_size_t* size, oor_setup_t* setup);
bool oor_validate_audio_page(oor_page_t* page, oor_size_t* size, oor_header_t* hdr);
#endif

View file

@ -1260,12 +1260,11 @@ static inline int16_t clamp16f(float sample) {
}
void tac_get_samples_pcm16(tac_handle_t* handle, int16_t* dst) {
int ch, i;
int chs = TAC_CHANNELS;
for (ch = 0; ch < chs; ch++) {
for (int ch = 0; ch < chs; ch++) {
int s = 0;
for (i = 0; i < TAC_FRAME_SAMPLES / 4; i++) {
for (int i = 0; i < TAC_FRAME_SAMPLES / 4; i++) {
dst[(s+0)*chs + ch] = clamp16f(handle->wave[ch][i].f.x);
dst[(s+1)*chs + ch] = clamp16f(handle->wave[ch][i].f.y);
dst[(s+2)*chs + ch] = clamp16f(handle->wave[ch][i].f.z);
@ -1275,6 +1274,21 @@ void tac_get_samples_pcm16(tac_handle_t* handle, int16_t* dst) {
}
}
// TAC originally returns PCM16 but allow internal floats for flexility
void tac_get_samples_float(tac_handle_t* handle, float* dst) {
int chs = TAC_CHANNELS;
for (int ch = 0; ch < chs; ch++) {
int s = 0;
for (int i = 0; i < TAC_FRAME_SAMPLES / 4; i++) {
dst[(s+0)*chs + ch] = (handle->wave[ch][i].f.x);
dst[(s+1)*chs + ch] = (handle->wave[ch][i].f.y);
dst[(s+2)*chs + ch] = (handle->wave[ch][i].f.z);
dst[(s+3)*chs + ch] = (handle->wave[ch][i].f.w);
s += 4;
}
}
}
void tac_set_loop(tac_handle_t* handle) {
handle->frame_number = handle->header.loop_frame;

View file

@ -49,6 +49,7 @@ void tac_free(tac_handle_t* handle);
int tac_decode_frame(tac_handle_t* handle, const uint8_t* block);
void tac_get_samples_pcm16(tac_handle_t* handle, int16_t* dst);
void tac_get_samples_float(tac_handle_t* handle, float* dst);
void tac_set_loop(tac_handle_t* handle);

View file

@ -0,0 +1,393 @@
/* Handles Ubi-MPEG, a modified VBR MP2 (format seems to be called simply 'MPEG').
*
* Sync is slightly different and MPEG config is fixed (info removed from the bitstream). Frames
* are also not byte-aligned, meaning a new frame starts right after prev ends in the bitstream
* (in practice frames are aligned to 4-bits though so recognizable in plain sight).
* It also has a mode where 1 stereo frame + 1 mono frame are used make surround(?) output.
*
* TODO: this doesn't handle surround modes at the moment, so it isn't fully accurate.
*
* Partially reverse engineered from DLLs.
* - MPGMXBVR.DLL: regular version, seems to (mostly) not use simd (ex. sub_10001400)
* - MPGMXSVR.DLL: xmm version
*
* Info+crosschecking from spec and libmpg123/various:
* - http://www.mp3-tech.org/programmer/frame_header.html
* - https://github.com/dreamerc/mpg123/blob/master/src/libmpg123/layer2.c
*/
//TODO: test if files have encoding delay, but some files seem to have very few spare samples vs declared block samples
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "ubi_mpeg_helpers.h"
#include "../../util/log.h"
// forced size to simplify (explained later): (144 * bitrate * 1000 / sample_rate) + (1 optional padding byte)
//#define UBIMPEG_STEREO_FRAME_SIZE 0x20B // 128~160kkbps
//#define UBIMPEG_MONO_FRAME_SIZE 0x106 // 64~80kbps
#define UBIMPEG_FIXED_FRAME_SIZE 0x300 // ~256kbps at 48000hz
// standard MPEG modes
#define CH_MODE_MONO 3
#define CH_MODE_JOINT 1
#define CH_MODE_STEREO 0
#define MAX_BANDS 32 //30?
#define MAX_GRANULES 12
// band <> used allocation bits
// table 0 for 27 subbands (out of ~4); Ubi-MPEG only has this table.
// (spec's Table 3-B.2a, though we separate it into multiple tables for clarity)
static const uint8_t BITALLOC_TABLE_0[32] = {
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 0, 0, 0, 0, 0,
};
// index of "number of steps" to the "bits per codeword" (qbit) table, [band][index]
static const uint8_t QINDEX_TABLE_0[32][16] = {
{ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, },
{ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, },
{ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
};
// "bits per codeword" (qbit) table, number of bits used to quantize a value
// usually negative has a special meaning of "3 grouped qs"
static const int8_t QBITS_TABLE_0[17] = {
-5, -7, 3, -10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
};
#if 0
// often QBITS_TABLE uses negative values meaning "grouping" to avoid this table (-5, -7, 3, -10, ...)
static const int8_t GROUPING_TABLE[17] = {
3, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
#endif
// bands in the bitstream, fixed to index 0 in Ubi MPEG
static const int MAX_SUBBANDS[5] = { 27, 30, 8, 12, 30 };
// number of subbands that are regular stereo, depending on mode extension (rest are intensity stereo)
static int JOINT_BOUNDS[4] = { 4, 8, 12, 16 };
// most Ubi MPEG files have frames right after other, but sometimes they'll have some
// of padding. This doesn't seem a bitreading issue, their OG libs do seem to manually
// try to find sync until EOF on every new frame.
static int find_sync(bitstream_t* is) {
// read until some limit rather than EOF
int tests = 0;
while (tests < 32) {
//TODO: OG lib seems to advance bit-by-bit, but this seems to work
uint16_t sync = bm_read(is, 12); // 12 bits unlike 11 in MPEG
if (sync != 0)
return sync;
tests++;
}
return 0;
}
// reads a UBI-MPEG frame and transforms it into a regular MP2 frame
// Note that UBI-MPEG simply reads and decodes it by itself while handling surround modes,
// so this is just a quick hack.
int ubimpeg_transform_frame(bitstream_t* is, bitstream_t* os) {
//uint32_t offset = bm_pos(is) / 8;
// config per sample rae + bitrate + channels, fixed in Ubi MPEG
const int table = 0;
// bit info about how samples in subband are quantized
uint8_t bit_alloc[MAX_BANDS][2] = {0};//todo invert ch, todo 'allocation'
uint32_t scfsi[MAX_BANDS][2] = {0};
/* read 16-bit Ubi-MPEG header */
uint16_t sync = find_sync(is);
if (sync != 0xFFF) {
//VGM_LOG("UBI-MPEG: sync not found at %x (+ %i), value=%x\n", is->b_off / 8, is->b_off % 8, sync);
return 0;
}
uint8_t mode = bm_read(is, 4);
int extmode = (mode >> 0) & 0x03;
int ch_mode = (mode >> 2) & 0x03;
int channels = (ch_mode == CH_MODE_MONO) ? 1 : 2;
int subbands = MAX_SUBBANDS[table];
int joint_bound = (ch_mode != CH_MODE_JOINT) ? subbands : JOINT_BOUNDS[extmode]; // boundary of non-js bands
// Ubi-MPEG uses VBR and settings close to 44100 + 128~160kbps (stereo) / 64~80kbps (mono). However some
// frames spill into 1 more byte than the 0x20b allowed by 160kbps (even with padding bit). Sample rate + bitrate
// combo must end up using certain tables in decoders, so use a setting that allows a consistenct bitrate.
// Free bitrate (br_index 0) is usable too but decoders need several frames to detect sizes.
int frame_size = UBIMPEG_FIXED_FRAME_SIZE;
int br_index = 12; // 256kbps
int sr_index = 1; // fixed to 48000 (Ubi MPEG is 44100 but shouldn't affect decoding)
int padding = 0;
// real-ish settings, but doesn't work for all frames
//frame_size = (channels == 2) ? UBIMPEG_STEREO_FRAME_SIZE : UBIMPEG_MONO_FRAME_SIZE;
//br_index = (channels == 2) ? 9 : 5; // 160kbps / 80kbps
//sr_index = 0; // fixed to 44100
//padding = 1;
/* write 32-bit MPEG frame header */
bm_put(os, 11, 0x7FF); // sync
bm_put(os, 2, 3); // MPEG 1 index
bm_put(os, 2, 2); // layer II index
bm_put(os, 1, 1); // "no CRC" flag
bm_put(os, 4, br_index); // bitrate index
bm_put(os, 2, sr_index); // sample rate index
bm_put(os, 1, padding); // padding
bm_put(os, 1, 0); // private
bm_put(os, 2, ch_mode); // channel mode
bm_put(os, 2, extmode); // mode extension
bm_put(os, 1, 1); // copyrighted
bm_put(os, 1, 1); // original
bm_put(os, 2, 0); // emphasis
// step I: read allocation bits
for (int i = 0; i < joint_bound; i++) {
int ba_bits = BITALLOC_TABLE_0[i];
for (int ch = 0; ch < channels; ch++) {
bit_alloc[i][ch] = bm_read(is, ba_bits);
bm_put(os, ba_bits, bit_alloc[i][ch]);
}
}
// step I: read rest of joint stereo allocation bits (same for L and R)
for (int i = joint_bound; i < subbands; i++) {
int ba_bits = BITALLOC_TABLE_0[i];
bit_alloc[i][0] = bm_read(is, ba_bits);
bit_alloc[i][1] = bit_alloc[i][0];
bm_put(os, ba_bits, bit_alloc[i][0]);
}
// step I: read scalefactor selector information (how many scalefactors are included)
for (int i = 0; i < subbands; i++) {
for (int ch = 0; ch < channels; ch++) {
if (bit_alloc[i][ch] == 0)
continue;
scfsi[i][ch] = bm_read(is, 2);
bm_put(os, 2, scfsi[i][ch]);
}
}
// step I: read scalefactors from scfsi indexes
for (int i = 0; i < subbands; i++) {
for (int ch = 0; ch < channels; ch++) {
if (bit_alloc[i][ch] == 0)
continue;
int scf;
switch(scfsi[i][ch]) {
case 0: // 3 scalefactors
scf = bm_read(is, 6);
bm_put(os, 6, scf);
scf = bm_read(is, 6);
bm_put(os, 6, scf);
scf = bm_read(is, 6);
bm_put(os, 6, scf);
break;
case 1: // 2 scalefactors (reuses 1st for 2nd)
case 3: // 2 scalefactors (reuses 2nd for 3rd)
scf = bm_read(is, 6);
bm_put(os, 6, scf);
scf = bm_read(is, 6);
bm_put(os, 6, scf);
break;
case 2: // 1 scalefactor (reuses all 3)
scf = bm_read(is, 6);
bm_put(os, 6, scf);
break;
default:
break;
}
}
}
// step II: read quantized DCT coefficients
// (restored to 3 samples per granule and up to 32 subbands)
for (int gr = 0; gr < MAX_GRANULES; gr++) {
// regular quants
for (int i = 0; i < joint_bound; i++) {
for (int ch = 0; ch < channels; ch++) {
int ba_index = bit_alloc[i][ch];
if (ba_index == 0)
continue;
int qb_index = QINDEX_TABLE_0[i][ba_index - 1];
int qbits = QBITS_TABLE_0[qb_index];
int qs;
if (qbits < 0) { // grouping used
qbits = -qbits; // remove flag
qs = 1; // same value for 3 codes
}
else {
qs = 3; // 3 distinct codes
}
for (int q = 0; q < qs; q++) {
int qcode = bm_read(is, qbits);
bm_put(os, qbits, qcode);
}
}
}
// joint stereo quants (1 channel only)
for (int i = joint_bound; i < subbands; i++) {
{
int ba_index = bit_alloc[i][0];
if (ba_index == 0)
continue;
int qb_index = QINDEX_TABLE_0[i][ba_index - 1];
int qbits = QBITS_TABLE_0[qb_index];
int qs;
if (qbits < 0) { // grouping used
qbits = -qbits; // remove flag
qs = 1; // same value for 3 codes
}
else {
qs = 3; // 3 distinct codes
}
for (int q = 0; q < qs; q++) {
int qcode = bm_read(is, qbits);
bm_put(os, qbits, qcode);
}
}
}
}
// real MPEG frames are byte padded, but not Ubi-MPEG's (usually)
uint32_t bitpos = bm_pos(os);
if (bitpos % 8) {
bm_skip(os, 8 - (bitpos % 8));
}
//uint32_t end_offset = bm_pos(is) / 8;
//VGM_LOG("frame: ch_mode=%x, extmode=%x = chs=%i, reg_bands=%i, o=%x + %x\n", ch_mode, extmode, channels, joint_bound, offset, end_offset - offset);
// 0-pad as may confuse decoders otherwise
uint32_t obuf_done = bm_pos(os) / 8;
if (obuf_done > frame_size) {
//VGM_LOG("error: buf done=%x (%i) vs %x\n", obuf_done, bm_pos(os), frame_size);
return 0;
}
else {
memset(os->buf + obuf_done, 0x00, frame_size - obuf_done);
}
return frame_size;
}
#if 0
static bool parse_file(uint8_t* buf, int buf_size, FILE* outfile_mp2a, FILE* outfile_mp2b, FILE* outfile0_wav, FILE* outfile1_wav) {
printf("UBI-MPEG: samples=%i, 2rus=%i, 1rus=%i\n", samples, is_2rus, is_1rus);
bitstream_t is;
bm_setup(&is, buf, buf_size);
bm_skip(&is, 0x04 * 8);
if (is_1rus || is_2rus)
bm_skip(&is, 0x04 * 8);
uint8_t obuf[0x800];
bitstream_t os;
mp3dec_t mp3d0;
mp3dec_init(&mp3d0);
mp3dec_frame_info_t info0;
short pcm0[MINIMP3_MAX_SAMPLES_PER_FRAME];
mp3dec_t mp3d1;
mp3dec_init(&mp3d1);
mp3dec_frame_info_t info1;
short pcm1[MINIMP3_MAX_SAMPLES_PER_FRAME];
int frames = 0;
int done = 0;
int obuf_size;
while (1) {
// 1st frame
{
bm_setup(&os, obuf, sizeof(obuf));
obuf_size = ubimpeg_transform_frame(&is, &os);
if (!obuf_size) break;
frames++;
fwrite(obuf, sizeof(uint8_t), obuf_size, outfile_mp2a);
int pcm0_samples = mp3dec_decode_frame(&mp3d0, obuf, obuf_size, pcm0, &info0);
printf("mpeg0: pcm=%i, br=%i, ch=%i, by=%x\n", pcm0_samples, info0.bitrate_kbps, info0.channels, info0.frame_bytes);
fwrite(pcm0, sizeof(short), pcm0_samples * info0.channels, outfile0_wav);
}
// 2nd frame
if (is_1rus || is_2rus) {
bm_setup(&os, obuf, sizeof(obuf));
obuf_size = ubimpeg_transform_frame(&is, &os);
if (!obuf_size) break;
frames++;
fwrite(obuf, sizeof(uint8_t), obuf_size, outfile_mp2b);
int pcm1_samples = mp3dec_decode_frame(&mp3d1, obuf, obuf_size, pcm1, &info1);
printf("mpeg1: pcm=%i, br=%i, ch=%i, by=%x\n", pcm1_samples, info1.bitrate_kbps, info1.channels, info1.frame_bytes);
fwrite(pcm1, sizeof(short), pcm1_samples * info1.channels, outfile1_wav);
}
done += 1152;
printf("samples: %i / %i, obuf=%x (%x)\n", done, samples, obuf_size);
if (done >= samples)
break;
}
printf("frames: done=%i (%x) / samples=%i (%x)\n", done, done, samples, samples);
return true;
}
#endif

View file

@ -0,0 +1,9 @@
#ifndef _UBI_MPEG_HELPERS_H
#define _UBI_MPEG_HELPERS_H
#include "../../util/bitstream_msb.h"
int ubimpeg_transform_frame(bitstream_t* is, bitstream_t* os);
#endif

View file

@ -0,0 +1,777 @@
#ifndef _VORBIS_CODEBOOKS_OOR_H_
#define _VORBIS_CODEBOOKS_OOR_H_
#include "../../util/vorbis_codebooks.h"
/**
* Codebooks can be found like this packed in executables or riooor lib
* (with a table of size + offset to binary, ID is just an index to entry N though).
* Bigger .oor use codebooks in file so there aren't many setups.
*/
/* ******************************************** */
/* autogenerated */
/* ******************************************** */
static const uint8_t vcb_1[] = {
0x1F,0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x9C,0x73,0x9A,0x31,0x87,0x99,0x62,0x94,0x52,0x89,0x21,0x94,0xDE,0x39,0x68,0x19,0x63,0x94,0x52,0x69,0x29,0xA5,0x5A,
0x4A,0xA9,0xA1,0x83,0x16,0x6B,0xAB,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0x1D,0x73,0x94,0x31,0x46,0x95,0x52,0x52,0x4A,0xA9,0x9D,0x73,0x96,0x31,0x47,
0x15,0x63,0x52,0x4A,0x89,0xA5,0x94,0x56,0x42,0x68,0x21,0x84,0xD6,0x62,0xAB,0xBD,0xF7,0xDE,0x6B,0xEF,0xB5,0xF6,0xDE,0x7B,0xEF,0x99,0x42,0x4C,0x29,0xA4,0x14,0x42,
0x08,0x4A,0x28,0x1D,0x53,0x8C,0x29,0xA4,0x94,0x42,0x4A,0x4A,0x08,0x25,0x64,0x0E,0x3A,0xC6,0x1C,0x53,0x8C,0x52,0x09,0x3D,0xD6,0x5E,0x6B,0xCC,0xBD,0xB6,0xD8,0x7B,
0xED,0xA1,0x63,0xCE,0x39,0xE6,0x1C,0x53,0x4C,0x4A,0x68,0x21,0x74,0x0E,0x3A,0xE6,0x9C,0x53,0x4C,0x4A,0x68,0xA9,0x84,0x52,0x42,0x06,0xA1,0x53,0xD0,0x52,0x89,0xAD,
0xF7,0xDE,0x62,0xEB,0xB9,0xA5,0xDA,0x7B,0xEF,0x81,0xD0,0x90,0x55,0x00,0x00,0x01,0x00,0xC0,0x40,0x10,0x1A,0xB2,0x0A,0x00,0x50,0x00,0x00,0x10,0x8A,0xA1,0x18,0x8A,
0x02,0x84,0x86,0xAC,0x02,0x00,0x32,0x00,0x00,0x04,0xE0,0x28,0x8E,0xE3,0x38,0x8E,0xE2,0x38,0x92,0x62,0x39,0x16,0x10,0x1A,0xB2,0x0A,0x00,0x00,0x02,0x00,0x10,0x00,
0x00,0xC0,0x90,0x0C,0x4B,0xB1,0x14,0xCD,0xD1,0x24,0x4D,0xD2,0x2C,0xCF,0x13,0x4D,0xD3,0x37,0x7D,0xD3,0x36,0x6D,0x55,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x20,
0x34,0x64,0x15,0x00,0x00,0x01,0x00,0x40,0x40,0xA7,0x19,0xA6,0x1A,0x20,0xC2,0x8C,0x64,0x16,0x08,0x0D,0x59,0x05,0x00,0x20,0x00,0x00,0x00,0x44,0x20,0xC3,0x14,0x03,
0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x00,0x52,0x24,0x39,0x49,0xA2,0xE4,0xA4,0x94,0x52,0x0E,0x83,0x64,0x31,0x49,0x2A,0xE5,0xA4,0x94,0x52,0x1E,0xC5,0xE4,0x51,
0x4D,0x32,0x06,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x0A,0x83,0x64,0x39,0x4A,0x2A,0xE5,0xA4,0x94,0x52,0x12,0xA3,0x64,0x31,0x4A,0xAA,
0xD4,0xA4,0x94,0x52,0x1E,0xE5,0xE4,0x49,0x4D,0x32,0xF6,0xA4,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x16,0xA4,0xE4,0x49,0x4B,0xBA,0x06,0xA5,
0x94,0x52,0x92,0xA3,0xA4,0x41,0x4B,0x36,0xF5,0xA4,0x94,0x52,0xA2,0x14,0x25,0x4A,0x4E,0xB6,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x3E,0x28,0xE5,0x83,0x50,0x4A,0x29,0xA5,0x94,0x52,0xAE,0xF6,0xE4,0x5A,0x4F,0x4A,0x29,0xA5,0x94,0x52,0xC6,0x28,0x25,0x7C,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x32,0x82,0xD0,0x90,0x55,0x00,0x00,0x10,0x00,0x00,0x60,0x9C,0x35,0xCA,0xA1,0xE8,0x24,0x3A,0x5F,0x9C,0xA1,0x9C,0x69,0x0A,0x92,
0x0A,0xA5,0x09,0xDD,0x9B,0xE4,0x28,0x79,0x4E,0x72,0x2B,0x2D,0x37,0xA7,0x9B,0x70,0xCE,0xE9,0xE6,0x94,0x73,0x3E,0x39,0xE7,0x9C,0x20,0x34,0x64,0x15,0x00,0x00,0x08,
0x00,0x00,0x21,0x84,0x14,0x52,0x48,0x21,0x85,0x14,0x52,0x48,0x21,0x85,0x14,0x62,0x88,0x21,0x86,0x1C,0x72,0xCA,0x29,0xA8,0xA0,0x82,0x4A,0x2A,0xA9,0xA8,0xA2,0x8A,
0x2A,0xAB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x3A,0xEB,0xA8,0xA3,0xCE,0x42,0x0A,0xA1,0xA4,0xD0,0x42,0x6B,0x35,0xC6,0x1A,0x63,0x6C,
0xB5,0x37,0x27,0x6D,0xCD,0x51,0x4A,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x73,0xCE,0x39,0x27,0x08,0x0D,0x59,0x05,0x00,0x80,0x00,0x00,0x10,0x08,0x19,0x64,0x90,0x41,
0x46,0x19,0x85,0x14,0x62,0x88,0x29,0xA7,0x9C,0x72,0x0A,0x2A,0xA9,0xA4,0x02,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x44,0xC9,0x74,0x4C,0x47,
0x74,0x44,0x45,0x74,0x44,0x47,0x74,0x44,0x47,0x74,0x44,0xC7,0x73,0x3C,0xC7,0x93,0x44,0x49,0xB4,0x3C,0x4B,0xD4,0x4C,0xCF,0x14,0x4D,0xD3,0x74,0x55,0xD9,0x95,0x65,
0x5D,0xB6,0x65,0xDB,0xD5,0x65,0xDD,0xD6,0x65,0xDF,0xF6,0x6D,0xDD,0xB6,0x6D,0x5F,0x37,0x76,0xE3,0x37,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,
0x8E,0xE3,0x18,0x82,0xD0,0x90,0x55,0x00,0x00,0x08,0x00,0x00,0x80,0x10,0x42,0x08,0x21,0x85,0x14,0x52,0x48,0x21,0xA5,0x98,0x62,0xCC,0x39,0xE8,0x20,0x84,0x50,0x4A,
0x20,0x34,0x64,0x15,0x00,0x00,0x08,0x00,0x20,0x00,0x00,0x00,0x40,0x51,0x1C,0xC5,0x71,0x24,0x47,0x92,0x24,0xC9,0x92,0x2C,0x4B,0xB3,0x34,0x4D,0xD3,0x34,0xCD,0x13,
0x3D,0xD1,0x33,0x3D,0xD5,0x73,0x45,0x59,0xB4,0x45,0xDB,0x73,0x3D,0x5B,0xB4,0x3D,0xD7,0x53,0x3D,0xD5,0x53,0x45,0xD5,0x54,0x4D,0xD7,0x74,0x55,0xD7,0x75,0x5D,0x57,
0x75,0x55,0x59,0x95,0x5D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0x19,0x08,0x0D,0x59,0x05,0x00,0x48,0x00,0x00,0xE8,0x48,0x8E,
0xA4,0x48,0x8A,0xA4,0x48,0x8E,0xE3,0x48,0x8E,0x24,0x01,0xA1,0x21,0xAB,0x00,0x00,0x19,0x00,0x00,0x01,0x00,0x28,0x8A,0xA2,0x38,0x8E,0x23,0x39,0x96,0x64,0x49,0x9A,
0x24,0x4A,0xA6,0xA5,0x5A,0xAE,0x26,0x7B,0xBA,0xA7,0x8B,0xBA,0xA8,0x03,0xA1,0x21,0xAB,0x00,0x00,0x40,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x18,0xA2,0x21,0x1A,
0xA2,0x23,0x5A,0xA2,0x26,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,
0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x1E,0x10,0x1A,0xB2,0x0A,0x00,0x90,0x00,0x00,0xD0,
0x91,0x1C,0xC9,0xB1,0x14,0x4B,0x91,0x14,0x49,0xB1,0x1C,0xCB,0x01,0x42,0x43,0x56,0x01,0x00,0x32,0x00,0x00,0x02,0x00,0x70,0x0C,0xC7,0x90,0x14,0xC9,0xB1,0x2C,0xCB,
0xD2,0x34,0xCD,0xF3,0x3C,0xCF,0x13,0x3D,0x51,0x14,0x45,0xD1,0x34,0x55,0x53,0x05,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x50,0x14,
0xC5,0x72,0x2C,0x47,0x92,0x34,0xC7,0x93,0x44,0x47,0x94,0x44,0x49,0xB4,0x44,0x49,0xD4,0x44,0x4D,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,
0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x20,0x34,0x64,0x25,0x00,0x00,0x04,
0x00,0x40,0x49,0x6A,0xB1,0xB5,0xD6,0x28,0x05,0xA1,0xA4,0x98,0x18,0xC2,0x94,0x93,0x1C,0x31,0x06,0x1D,0xA4,0x5E,0x31,0xE4,0x10,0x93,0x9E,0x39,0x06,0x15,0x93,0x5E,
0x2A,0x82,0x0C,0x62,0x1E,0x3B,0xC4,0x14,0x93,0x1C,0x08,0x0D,0x59,0x11,0x00,0x44,0x01,0x00,0x00,0xC6,0x20,0xC7,0x10,0x73,0xC8,0x39,0x47,0xA9,0x93,0x14,0x39,0xE7,
0xA4,0x74,0x94,0x1A,0xE7,0x1C,0xA5,0x8E,0x52,0x47,0x29,0xC5,0x9A,0x62,0xCD,0x28,0x95,0xDA,0x52,0xAC,0x8D,0x73,0x8E,0x52,0x47,0xA9,0xA3,0x94,0x6A,0x2C,0x2D,0x76,
0xD4,0x52,0xAD,0xA9,0xC6,0x02,0x00,0x00,0x02,0x1C,0x00,0x00,0x02,0x2C,0x84,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x84,0x31,0x48,0x29,0xA4,0x14,0x62,0x8A,0x39,
0xA7,0x98,0x43,0x8A,0x29,0xC7,0x98,0x73,0x88,0x31,0xE6,0x1C,0x73,0x8E,0x39,0xE7,0xA0,0x74,0x52,0x2A,0xE7,0x98,0x74,0x4E,0x4A,0xC4,0x18,0x73,0x8E,0x39,0xA7,0x9C,
0x73,0x52,0x32,0x27,0x95,0x73,0x4E,0x4A,0x27,0xA1,0x00,0x00,0x80,0x00,0x07,0x00,0x80,0x00,0x0B,0xA1,0xD0,0x90,0x15,0x01,0x40,0x9C,0x00,0x80,0x41,0x92,0x3C,0x4F,
0xD2,0x34,0x51,0x94,0x34,0x4F,0x14,0x3D,0x53,0x74,0x55,0x4F,0x34,0x55,0xD7,0xF2,0x3C,0xD3,0xF4,0x4C,0x53,0x55,0x3D,0xD1,0x54,0x55,0xD3,0x55,0x65,0xD9,0x54,0x55,
0x59,0xB6,0x3C,0xCF,0x34,0x3D,0x53,0x54,0x55,0xCF,0x34,0x55,0xD5,0x54,0x55,0x59,0x36,0x55,0x55,0x96,0x45,0x55,0xD5,0x6D,0xD3,0x55,0x75,0xDB,0x74,0x55,0xDD,0x76,
0x6D,0xD9,0xD7,0x5D,0x59,0x16,0x76,0x51,0x55,0x6D,0xDB,0x54,0x5D,0x5B,0x37,0x55,0xD7,0x16,0x5E,0xD9,0xD6,0x7D,0x59,0xB6,0x75,0x61,0xF2,0x3C,0x55,0xF5,0x4C,0xD3,
0x75,0x3D,0xD3,0x74,0x5D,0xD5,0x75,0x75,0x5B,0x75,0x5D,0x5B,0xF7,0x4C,0x53,0x76,0x4D,0xD7,0x95,0x65,0xD3,0x75,0x6D,0xDB,0x95,0x65,0x5D,0x57,0x65,0x59,0xF7,0x35,
0xD3,0x74,0x5D,0xD1,0x55,0x6D,0xD9,0x74,0x5D,0xD9,0x76,0x65,0x57,0xD7,0x5D,0x59,0xF6,0x85,0xD3,0x75,0x75,0xDF,0x95,0x65,0x61,0x57,0x65,0x59,0xF8,0x75,0x5D,0x17,
0x86,0x59,0xF7,0x8D,0x63,0x74,0x5D,0x5D,0x58,0x65,0xD7,0xF7,0x55,0x59,0xF6,0x8D,0x5B,0xB7,0x7D,0x5F,0xD6,0x75,0xE1,0x98,0x3C,0x4F,0x55,0x3D,0xD3,0x74,0x5D,0xCF,
0x34,0x5D,0xD7,0x74,0x5D,0x5D,0x57,0x5D,0xD7,0xD6,0x35,0xD3,0x74,0x5D,0xD3,0x75,0x6D,0x5B,0x54,0x5D,0x59,0x76,0x65,0xD9,0xF7,0x5D,0x57,0xD6,0x75,0xCF,0x34,0x5D,
0xD9,0x74,0x5D,0xD9,0x36,0x5D,0x57,0x96,0x5D,0x59,0xF6,0x7D,0x57,0x96,0x75,0xDD,0x74,0x5D,0xDD,0x57,0x65,0x59,0xF8,0x55,0x57,0x16,0x7E,0x59,0xD7,0x8D,0xE5,0xB6,
0x6D,0xE1,0x37,0x5D,0x57,0xD7,0x55,0x59,0xD6,0x7D,0x55,0x96,0x75,0x61,0xD6,0x75,0xE3,0xB9,0x75,0x5D,0x18,0x3E,0x55,0xD5,0x7D,0x53,0x76,0x85,0xDF,0x74,0x65,0x5F,
0xD8,0x7D,0xDD,0x59,0x6E,0xDD,0x37,0x96,0xD1,0x75,0x75,0x61,0x95,0x6D,0xE3,0x58,0x65,0x5B,0x18,0x7E,0xE1,0x58,0x96,0xDD,0x37,0x96,0x67,0x74,0x5D,0xDF,0x57,0x6D,
0x57,0x18,0x56,0x59,0xF6,0x95,0xDD,0xD7,0x9D,0x65,0xD7,0x75,0x65,0x78,0x6D,0xDB,0x58,0x6E,0x5D,0x57,0x8E,0x59,0xD7,0x8D,0x61,0x38,0x96,0xA7,0xEE,0x0B,0x4F,0x57,
0xB7,0x85,0x63,0xF6,0x6D,0xE7,0x99,0x7D,0x5D,0x39,0x7E,0x67,0x78,0x96,0x5F,0xF8,0x29,0x9F,0xAA,0xEA,0xBA,0xE9,0xBA,0xC2,0x70,0xBA,0xB2,0xEF,0xCB,0xB6,0x2E,0x0C,
0xBB,0x2F,0x2C,0xCB,0xE8,0xBA,0xBE,0xB0,0xCA,0xB2,0xF1,0xAB,0xB2,0xEC,0x0B,0xB7,0xEE,0x2B,0xC7,0xEE,0x0B,0xC3,0x31,0xBA,0xAE,0xF0,0xAB,0xB6,0xEC,0xFB,0xAE,0x2D,
0x0B,0xC7,0xED,0xEB,0xC6,0x32,0x0C,0xC3,0x72,0xBC,0xB6,0xAD,0x0C,0xB3,0xAE,0x0B,0x65,0xDB,0x47,0xF7,0x7D,0xA5,0xEF,0x2B,0x4B,0x57,0xB7,0x95,0x63,0xD6,0x75,0xA5,
0xED,0xEB,0x94,0x5D,0x18,0x2A,0xC3,0x31,0x54,0x06,0x00,0x00,0x0C,0x38,0x00,0x00,0x04,0x98,0x50,0x06,0x0A,0x0D,0x59,0x11,0x00,0xC4,0x09,0x00,0x30,0x08,0x39,0x87,
0x98,0x82,0x10,0x29,0x06,0x21,0x84,0x90,0x52,0x08,0x21,0xA5,0x88,0x31,0x08,0x99,0x73,0x52,0x2A,0xE6,0xA0,0x94,0x52,0x52,0x0B,0xA5,0xA4,0x16,0x31,0x06,0xA1,0x72,
0x4C,0x4A,0xE6,0x9C,0x94,0x50,0x4A,0x4B,0xA5,0x94,0x96,0x42,0x29,0xAD,0x95,0x54,0x62,0x0C,0xA5,0xC4,0xD8,0x5A,0xAB,0x35,0xB5,0x56,0x6B,0x28,0xA5,0xB5,0x50,0x4A,
0x8C,0xA5,0x94,0x16,0x53,0x6B,0xB5,0xB6,0xD8,0x6A,0x8D,0x18,0x93,0x92,0x39,0x27,0x25,0x73,0x4E,0x4A,0x29,0x25,0xB6,0x52,0x4A,0x6B,0x99,0x73,0x54,0x3A,0x07,0x25,
0x75,0x10,0x52,0x2A,0x25,0xB5,0x58,0x52,0x8A,0xB5,0x72,0x4E,0x4A,0x06,0x1D,0x95,0x0E,0x42,0x4A,0x25,0x95,0x98,0x4A,0x4A,0x31,0x96,0x54,0x62,0x2C,0x25,0xC5,0x5A,
0x52,0xAA,0xB1,0xA5,0xD8,0x6A,0x8B,0x31,0xE7,0x50,0x4A,0x8C,0x25,0x95,0x18,0x4B,0x4A,0xB1,0xB6,0x98,0x72,0x6B,0x31,0xD6,0x1C,0x31,0x26,0x21,0x73,0x4E,0x4A,0xE6,
0x9C,0x94,0x52,0x4A,0x6B,0xA5,0x94,0x16,0x2B,0xE7,0xA4,0x74,0x10,0x52,0xCA,0x1C,0x94,0x54,0x52,0x8A,0xB1,0x94,0x94,0x6A,0xE6,0x9C,0x94,0x0E,0x42,0x4A,0x1D,0x74,
0x54,0x4A,0x4A,0x31,0x96,0x54,0x62,0x0A,0xA5,0xC4,0x58,0x52,0xAA,0xB1,0x94,0xD4,0x62,0x8C,0x31,0xD7,0x96,0x62,0xCB,0xA1,0xA4,0x18,0x4B,0x4A,0xB1,0x96,0x54,0x62,
0x6C,0x31,0xE6,0xDC,0x62,0xCA,0xAD,0x93,0x12,0x5B,0x49,0x29,0xC6,0x50,0x52,0x8C,0x31,0xC6,0x9C,0x5B,0x8C,0x39,0x87,0x52,0x62,0x2C,0x29,0xC5,0x5A,0x52,0xAA,0x31,
0xC6,0x5A,0x73,0x8C,0xB1,0xE6,0x50,0x4A,0x8C,0x25,0x95,0x1A,0x4B,0x4A,0xB1,0xC6,0x1A,0x73,0x6D,0x31,0xD6,0x9C,0x62,0xCC,0x35,0xA5,0x58,0x73,0xAB,0x31,0xE7,0xD8,
0x72,0xEB,0xB5,0xE6,0xE0,0x53,0x6B,0x35,0xA7,0x98,0x72,0x6D,0x31,0xE6,0x5C,0x6B,0x0B,0xB2,0xE6,0x5C,0x7C,0x27,0x25,0xB6,0x50,0x4A,0x8C,0xA5,0xA4,0x18,0x5B,0x8C,
0xB5,0xB6,0x18,0x73,0x0E,0xA5,0xC4,0x58,0x52,0xAA,0xB1,0x94,0x14,0x6B,0x8B,0x31,0xE8,0xD6,0x62,0xED,0xA1,0x94,0x18,0x4B,0x4A,0x31,0x96,0x54,0x6A,0x8C,0x31,0xD6,
0x1C,0x6B,0xCC,0x39,0xC5,0x56,0x6B,0x8B,0xB1,0xD7,0xD4,0x62,0xCE,0x35,0xF7,0x60,0x6C,0xCB,0xB5,0xA7,0x16,0x6B,0x6E,0x31,0xE6,0x9E,0x62,0xCA,0xB5,0xF6,0xDA,0x83,
0xCD,0xAD,0xB7,0x02,0x00,0x00,0x06,0x1C,0x00,0x00,0x02,0x4C,0x28,0x03,0x85,0x86,0xAC,0x04,0x00,0xA2,0x00,0x00,0x00,0x63,0x18,0x73,0x0E,0x42,0xA3,0x90,0x73,0xCE,
0x49,0x69,0x90,0x72,0xCE,0x39,0x29,0x99,0x73,0x10,0x42,0x48,0x29,0x73,0x0E,0x42,0x08,0x29,0x75,0xCE,0x49,0x28,0xA9,0xB5,0xCE,0x39,0x08,0x29,0xB5,0x16,0x4A,0x49,
0xA9,0xB5,0x18,0x43,0x29,0x29,0xB5,0x16,0x63,0x01,0x00,0x00,0x05,0x0E,0x00,0x00,0x01,0x36,0x68,0x4A,0x2C,0x0E,0x50,0x68,0xC8,0x4A,0x00,0x20,0x15,0x00,0xC0,0xE0,
0x38,0x96,0xE5,0x79,0xA6,0x68,0x9A,0xB6,0xED,0x58,0x92,0xE7,0x89,0xA2,0x69,0xAA,0xAA,0x6D,0x3B,0x92,0xE5,0x79,0xA2,0x68,0x9A,0xAA,0x6A,0xDB,0x9A,0xE7,0x89,0xA2,
0x69,0xAA,0xAA,0xEB,0xEA,0xBA,0xE6,0x79,0xA2,0x68,0x9A,0xAA,0xEA,0xBA,0xB6,0x2E,0x8A,0xA2,0x69,0xAA,0xAA,0xAB,0xBA,0xAE,0xEE,0x8B,0xA2,0x68,0x9A,0xAA,0xAA,0xAA,
0xAE,0xAB,0xEB,0xA6,0x69,0xAA,0xAA,0xAB,0xBA,0xAE,0x2C,0xFB,0xBE,0x69,0x9A,0xAA,0xEA,0xBA,0xAE,0x2B,0xCB,0xBE,0xB0,0xAA,0xAE,0xEB,0xCA,0xB2,0x2D,0xDB,0xB6,0x31,
0xAC,0xAA,0xEA,0xBA,0xAE,0x2B,0xDB,0xB6,0x6D,0x1C,0xB7,0x6D,0xEB,0xBA,0xEE,0xFB,0xBE,0x30,0x54,0x6E,0xDB,0xD6,0x75,0x5F,0xF8,0x85,0x61,0x58,0x0A,0x00,0x00,0x4F,
0x70,0x00,0x00,0x2A,0xB0,0x61,0x75,0x84,0x93,0xA2,0xB1,0xC0,0x42,0x43,0x56,0x02,0x00,0x19,0x00,0x00,0x84,0x31,0x08,0x19,0x84,0x10,0x32,0x08,0x21,0x84,0x94,0x52,
0x0A,0x29,0xA5,0x94,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,0x2B,0x02,0x80,0x38,0x01,0x00,0x00,0x21,0x4A,0x21,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0xD4,0x51,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x42,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x4A,0x1D,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x4A,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x2A,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x00,0x80,
0x54,0x84,0x03,0x80,0xD4,0x83,0x09,0x65,0xA0,0xD0,0x90,0x95,0x00,0x40,0x2A,0x00,0x00,0x60,0x8C,0x52,0x8C,0x39,0x07,0xA1,0x94,0x86,0x31,0xE7,0x9C,0x83,0x90,0x4A,
0x4B,0x8D,0x62,0xCE,0x31,0x07,0xA1,0xA4,0x96,0x32,0xE7,0x20,0x94,0x92,0x52,0x4B,0x31,0x66,0xCE,0x41,0x29,0x25,0xA5,0xD6,0x5A,0xCC,0x9C,0x93,0xD2,0x5A,0x6C,0x3D,
0xC6,0x9A,0x39,0x27,0xA9,0xB5,0xD8,0x62,0xAC,0xB5,0x83,0xD2,0x5A,0x8D,0x3D,0xF7,0xDE,0x73,0x27,0xA5,0xB5,0x1A,0x6B,0xEE,0x3D,0xF7,0x92,0x5A,0xAD,0xB5,0xF6,0xD8,
0x73,0xEF,0x25,0xB5,0x18,0x73,0xAD,0xB9,0xF7,0x5A,0x63,0x8D,0xB9,0xF7,0x9E,0x73,0xEF,0xBD,0xA7,0x5C,0x7B,0xAF,0xB5,0xE7,0x5E,0x7B,0x2E,0x00,0x00,0xA7,0xC1,0x01,
0x00,0xF4,0xC0,0x86,0xD5,0x11,0x4E,0x8A,0xC6,0x02,0x0B,0x0D,0x59,0x09,0x00,0xA4,0x02,0x00,0x10,0x08,0x29,0xC5,0x98,0x73,0xCE,0x39,0x87,0x90,0x62,0xCC,0x39,0xE7,
0x20,0x84,0x10,0x21,0xC4,0x98,0x73,0xCE,0x41,0x08,0xA1,0x62,0x8C,0x39,0xE7,0x20,0x84,0x10,0x42,0xC5,0x98,0x63,0xCE,0x41,0x08,0x21,0x84,0xCE,0x39,0xE7,0x9C,0x83,
0x10,0x42,0x08,0x9D,0x73,0xCE,0x39,0x07,0x21,0x84,0x10,0x3A,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x74,0x0E,0x42,0x08,0x1D,0x84,0x10,0x42,0xE8,0x20,0x84,0x10,0x42,
0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0xA1,0x83,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x02,0x00,0x00,0x0B,
0x1C,0x00,0x00,0x02,0x6C,0x58,0x1D,0xE1,0xA4,0x68,0x2C,0xB0,0xD0,0x90,0x95,0x00,0x00,0x10,0x00,0x00,0xC2,0xAC,0xE4,0x12,0x8A,0x24,0x90,0x72,0x0C,0x9A,0x69,0x8C,
0x52,0x8E,0x9A,0x88,0x14,0x62,0x0A,0x9A,0xCA,0x10,0x43,0x4C,0x9A,0xA9,0x98,0x52,0xCA,0x81,0xE8,0x24,0x63,0x08,0x81,0x2A,0xCA,0xC6,0xD0,0x91,0x00,0x00,0x00,0x04,
0x01,0x00,0x01,0x26,0x80,0xC0,0x00,0x41,0xC1,0x17,0x42,0x40,0x8C,0x01,0x00,0x08,0x42,0x64,0x86,0x48,0x28,0xAC,0x82,0x05,0x06,0x65,0xD0,0xE0,0x30,0x0F,0x00,0x1E,
0x20,0x22,0x24,0x02,0x80,0xC4,0x04,0x45,0xDA,0xC5,0x05,0x74,0x19,0xE0,0x82,0x2E,0xEE,0x3A,0x10,0x42,0x10,0x82,0x10,0xC4,0xE2,0x00,0x0A,0x48,0xC0,0xC1,0x09,0x37,
0x3C,0xF1,0x86,0x27,0xDC,0xE0,0x04,0x9D,0xA2,0x52,0x07,0x01,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x00,0x00,0x07,0x05,0x10,0x11,0xD1,0x5C,0x85,0xC5,0x05,0x46,
0x86,0xC6,0x06,0x47,0x87,0x47,0x00,0x00,0x00,0x00,0x00,0xB8,0x00,0xC0,0x07,0x00,0xC0,0xF1,0x01,0x44,0x44,0x34,0x57,0x61,0x71,0x81,0x91,0xA1,0xB1,0xC1,0xD1,0xE1,
0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x04,
};
static const uint8_t vcb_2[] = {
0x1F,0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x9C,0x73,0x9A,0x31,0x87,0x99,0x62,0x94,0x52,0x89,0x21,0x94,0xDE,0x39,0x68,0x19,0x63,0x94,0x52,0x69,0x29,0xA5,0x5A,
0x4A,0xA9,0xA1,0x83,0x16,0x6B,0xAB,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0x1D,0x73,0x94,0x31,0x46,0x95,0x52,0x52,0x4A,0xA9,0x9D,0x73,0x96,0x31,0x47,
0x15,0x63,0x52,0x4A,0x89,0xA5,0x94,0x56,0x42,0x68,0x21,0x84,0xD6,0x62,0xAB,0xBD,0xF7,0xDE,0x6B,0xEF,0xB5,0xF6,0xDE,0x7B,0xEF,0x99,0x42,0x4C,0x29,0xA4,0x14,0x42,
0x08,0x4A,0x28,0x1D,0x53,0x8C,0x29,0xA4,0x94,0x42,0x4A,0x4A,0x08,0x25,0x64,0x0E,0x3A,0xC6,0x1C,0x53,0x8C,0x52,0x09,0x3D,0xD6,0x5E,0x6B,0xCC,0xBD,0xB6,0xD8,0x7B,
0xED,0xA1,0x63,0xCE,0x39,0xE6,0x1C,0x53,0x4C,0x4A,0x68,0x21,0x74,0x0E,0x3A,0xE6,0x9C,0x53,0x4C,0x4A,0x68,0xA9,0x84,0x52,0x42,0x06,0xA1,0x53,0xD0,0x52,0x89,0xAD,
0xF7,0xDE,0x62,0xEB,0xB9,0xA5,0xDA,0x7B,0xEF,0x81,0xD0,0x90,0x55,0x00,0x00,0x01,0x00,0xC0,0x40,0x10,0x1A,0xB2,0x0A,0x00,0x50,0x00,0x00,0x10,0x8A,0xA1,0x18,0x8A,
0x02,0x84,0x86,0xAC,0x02,0x00,0x32,0x00,0x00,0x04,0xE0,0x28,0x8E,0xE3,0x38,0x8E,0xE2,0x38,0x92,0x62,0x39,0x16,0x10,0x1A,0xB2,0x0A,0x00,0x00,0x02,0x00,0x10,0x00,
0x00,0xC0,0x90,0x0C,0x4B,0xB1,0x14,0xCD,0xD1,0x24,0x4D,0xD2,0x2C,0xCF,0x13,0x4D,0xD3,0x37,0x7D,0xD3,0x36,0x6D,0x55,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x20,
0x34,0x64,0x15,0x00,0x00,0x01,0x00,0x40,0x40,0xA7,0x19,0xA6,0x1A,0x20,0xC2,0x8C,0x64,0x16,0x08,0x0D,0x59,0x05,0x00,0x20,0x00,0x00,0x00,0x44,0x20,0xC3,0x14,0x03,
0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x00,0x52,0x24,0x39,0x49,0xA2,0xE4,0xA4,0x94,0x52,0x0E,0x83,0x64,0x31,0x49,0x2A,0xE5,0xA4,0x94,0x52,0x1E,0xC5,0xE4,0x51,
0x4D,0x32,0x06,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x0A,0x83,0x64,0x39,0x4A,0x2A,0xE5,0xA4,0x94,0x52,0x12,0xA3,0x64,0x31,0x4A,0xAA,
0xD4,0xA4,0x94,0x52,0x1E,0xE5,0xE4,0x49,0x4D,0x32,0xF6,0xA4,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x16,0xA4,0xE4,0x49,0x4B,0xBA,0x06,0xA5,
0x94,0x52,0x92,0xA3,0xA4,0x41,0x4B,0x36,0xF5,0xA4,0x94,0x52,0xA2,0x14,0x25,0x4A,0x4E,0xB6,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x3E,0x28,0xE5,0x83,0x50,0x4A,0x29,0xA5,0x94,0x52,0xAE,0xF6,0xE4,0x5A,0x4F,0x4A,0x29,0xA5,0x94,0x52,0xC6,0x28,0x25,0x7C,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x32,0x82,0xD0,0x90,0x55,0x00,0x00,0x10,0x00,0x00,0x60,0x9C,0x35,0xCA,0xA1,0xE8,0x24,0x3A,0x5F,0x9C,0xA1,0x9C,0x69,0x0A,0x92,
0x0A,0xA5,0x09,0xDD,0x9B,0xE4,0x28,0x79,0x4E,0x72,0x2B,0x2D,0x37,0xA7,0x9B,0x70,0xCE,0xE9,0xE6,0x94,0x73,0x3E,0x39,0xE7,0x9C,0x20,0x34,0x64,0x15,0x00,0x00,0x08,
0x00,0x00,0x21,0x84,0x14,0x52,0x48,0x21,0x85,0x14,0x52,0x48,0x21,0x85,0x14,0x62,0x88,0x21,0x86,0x1C,0x72,0xCA,0x29,0xA8,0xA0,0x82,0x4A,0x2A,0xA9,0xA8,0xA2,0x8A,
0x2A,0xAB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x3A,0xEB,0xA8,0xA3,0xCE,0x42,0x0A,0xA1,0xA4,0xD0,0x42,0x6B,0x35,0xC6,0x1A,0x63,0x6C,
0xB5,0x37,0x27,0x6D,0xCD,0x51,0x4A,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x73,0xCE,0x39,0x27,0x08,0x0D,0x59,0x05,0x00,0x80,0x00,0x00,0x10,0x08,0x19,0x64,0x90,0x41,
0x46,0x19,0x85,0x14,0x62,0x88,0x29,0xA7,0x9C,0x72,0x0A,0x2A,0xA9,0xA4,0x02,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x44,0xC9,0x74,0x4C,0x47,
0x74,0x44,0x45,0x74,0x44,0x47,0x74,0x44,0x47,0x74,0x44,0xC7,0x73,0x3C,0xC7,0x93,0x44,0x49,0xB4,0x3C,0x4B,0xD4,0x4C,0xCF,0x14,0x4D,0xD3,0x74,0x55,0xD9,0x95,0x65,
0x5D,0xB6,0x65,0xDB,0xD5,0x65,0xDD,0xD6,0x65,0xDF,0xF6,0x6D,0xDD,0xB6,0x6D,0x5F,0x37,0x76,0xE3,0x37,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,
0x8E,0xE3,0x18,0x82,0xD0,0x90,0x55,0x00,0x00,0x08,0x00,0x00,0x80,0x10,0x42,0x08,0x21,0x85,0x14,0x52,0x48,0x21,0xA5,0x98,0x62,0xCC,0x39,0xE8,0x20,0x84,0x50,0x4A,
0x20,0x34,0x64,0x15,0x00,0x00,0x08,0x00,0x20,0x00,0x00,0x00,0x40,0x51,0x1C,0xC5,0x71,0x24,0x47,0x92,0x24,0xC9,0x92,0x2C,0x4B,0xB3,0x34,0x4D,0xD3,0x34,0xCD,0x13,
0x3D,0xD1,0x33,0x3D,0xD5,0x73,0x45,0x59,0xB4,0x45,0xDB,0x73,0x3D,0x5B,0xB4,0x3D,0xD7,0x53,0x3D,0xD5,0x53,0x45,0xD5,0x54,0x4D,0xD7,0x74,0x55,0xD7,0x75,0x5D,0x57,
0x75,0x55,0x59,0x95,0x5D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0x19,0x08,0x0D,0x59,0x05,0x00,0x48,0x00,0x00,0xE8,0x48,0x8E,
0xA4,0x48,0x8A,0xA4,0x48,0x8E,0xE3,0x48,0x8E,0x24,0x01,0xA1,0x21,0xAB,0x00,0x00,0x19,0x00,0x00,0x01,0x00,0x28,0x8A,0xA2,0x38,0x8E,0x23,0x39,0x96,0x64,0x49,0x9A,
0x24,0x4A,0xA6,0xA5,0x5A,0xAE,0x26,0x7B,0xBA,0xA7,0x8B,0xBA,0xA8,0x03,0xA1,0x21,0xAB,0x00,0x00,0x40,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x18,0xA2,0x21,0x1A,
0xA2,0x23,0x5A,0xA2,0x26,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,
0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x1E,0x10,0x1A,0xB2,0x0A,0x00,0x90,0x00,0x00,0xD0,
0x91,0x1C,0xC9,0xB1,0x14,0x4B,0x91,0x14,0x49,0xB1,0x1C,0xCB,0x01,0x42,0x43,0x56,0x01,0x00,0x32,0x00,0x00,0x02,0x00,0x70,0x0C,0xC7,0x90,0x14,0xC9,0xB1,0x2C,0xCB,
0xD2,0x34,0xCD,0xF3,0x3C,0xCF,0x13,0x3D,0x51,0x14,0x45,0xD1,0x34,0x55,0x53,0x05,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x50,0x14,
0xC5,0x72,0x2C,0x47,0x92,0x34,0xC7,0x93,0x44,0x47,0x94,0x44,0x49,0xB4,0x44,0x49,0xD4,0x44,0x4D,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,
0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x20,0x34,0x64,0x25,0x00,0x00,0x04,
0x00,0x80,0x59,0xAB,0x3D,0xB6,0x5C,0x41,0x89,0x29,0xB5,0xD6,0x20,0xE4,0x10,0x83,0x56,0x31,0x27,0x1D,0xA4,0x1E,0x21,0xC3,0x0C,0x62,0x5C,0x21,0xE4,0x10,0x52,0xDC,
0x31,0xC3,0x88,0x41,0x9E,0x53,0xE5,0x90,0x72,0x1E,0x08,0x0D,0x59,0x11,0x00,0x44,0x01,0x00,0x00,0xC6,0x20,0xC7,0x10,0x73,0xC8,0x39,0x47,0xA9,0x93,0x14,0x39,0xE7,
0xA8,0x74,0x94,0x1A,0xE7,0x1C,0xA5,0x8E,0x52,0x47,0x29,0xC5,0x9A,0x62,0xED,0x28,0x95,0x9A,0x52,0xAC,0x8D,0x73,0x8E,0x52,0x47,0x29,0xA3,0x94,0x6A,0x2C,0x2D,0x76,
0x94,0x52,0xAD,0xA9,0xC6,0x02,0x00,0x00,0x02,0x1C,0x00,0x00,0x02,0x2C,0x84,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x04,0x42,0x48,0x29,0xA4,0x14,0x52,0x8A,0x39,
0xA7,0x98,0x43,0x4A,0x29,0xC7,0x98,0x73,0x48,0x29,0xE6,0x9C,0x72,0x8E,0x39,0xE7,0xA0,0x74,0x10,0x2A,0xE7,0x18,0x74,0x0E,0x4A,0xA4,0x94,0x72,0x8E,0x39,0xA7,0x9C,
0x73,0x12,0x32,0x07,0x99,0x73,0x0E,0x42,0x27,0xA1,0x00,0x00,0x80,0x00,0x07,0x00,0x80,0x00,0x0B,0xA1,0xD0,0x90,0x15,0x01,0x40,0x9C,0x00,0x80,0x43,0x72,0x34,0x4D,
0xD2,0x34,0xD1,0x93,0x34,0xCD,0x13,0x3D,0x51,0x54,0x55,0x4F,0x14,0x55,0x55,0xD2,0x34,0xD3,0xD4,0x44,0x51,0x35,0x35,0x51,0x34,0x4D,0x51,0x35,0x65,0x57,0x34,0x4D,
0x57,0x96,0x34,0xCD,0x14,0x35,0x51,0x54,0x4D,0x4D,0x14,0x4D,0x55,0x34,0x4D,0xD7,0x35,0x4D,0xD5,0x95,0x3D,0xD3,0xB4,0x65,0x51,0x55,0x75,0x59,0x54,0x55,0x5D,0x76,
0x6D,0xD7,0xB7,0x5D,0xD9,0xD5,0x6D,0xCF,0x34,0x65,0x5B,0x54,0x55,0xD9,0x36,0x55,0x55,0xD6,0x5D,0x57,0xB6,0x75,0x57,0xB6,0x6D,0x5F,0xD2,0x34,0xD3,0xD4,0x44,0x51,
0x55,0x35,0x51,0x54,0x5D,0x53,0x55,0x6D,0xDB,0x54,0x55,0xDB,0xD6,0x44,0xD1,0x75,0x45,0x55,0x95,0x5D,0x51,0x55,0x65,0xD9,0x75,0x5D,0xDB,0x56,0x5D,0x59,0xD7,0x35,
0x51,0x74,0x55,0x51,0x35,0x5D,0x57,0x54,0x55,0x57,0x56,0x5D,0xD5,0xB6,0x55,0xD7,0xD5,0x7D,0x51,0x55,0x75,0x5D,0x75,0x5D,0x5F,0x37,0x5D,0xD7,0xD7,0x6D,0x5D,0x17,
0x7E,0xD9,0xB6,0x85,0x61,0x54,0x55,0x5B,0x37,0x5D,0x55,0xD7,0x4D,0xD7,0xD5,0x85,0xD9,0x96,0x7D,0x5D,0xB6,0x75,0x61,0x98,0x34,0xCD,0x34,0x35,0x51,0x74,0x55,0x4D,
0x14,0x55,0xD7,0x54,0x55,0xDB,0x36,0x55,0x55,0xB6,0x35,0x51,0x54,0x5D,0x51,0x55,0x65,0x59,0x34,0x55,0xD7,0x55,0x5D,0x57,0xD7,0x55,0xD7,0x95,0x6D,0xCD,0x14,0x5D,
0x57,0x54,0x55,0x59,0x16,0x55,0xD5,0x75,0x55,0xD7,0xF5,0x75,0xD5,0x75,0x6D,0x5B,0x54,0x55,0xDD,0x36,0x5D,0xD7,0xD7,0x4D,0xD5,0xD5,0x75,0xD9,0xB6,0x85,0x63,0x96,
0x6D,0xDD,0x17,0x55,0x55,0xF7,0x4D,0xD7,0xD5,0x75,0xD5,0x75,0x6D,0x61,0xB6,0x6D,0x61,0xB8,0x6D,0xDB,0x37,0x36,0xD3,0xB4,0x75,0xD3,0x75,0x7D,0xDD,0x54,0x5D,0xDF,
0xB7,0x7D,0xDD,0x18,0x66,0xDD,0x16,0x96,0x51,0x75,0x7D,0x5D,0x95,0x65,0xE1,0x37,0x65,0xD9,0xF7,0x75,0xDF,0x17,0x96,0x59,0xD7,0x85,0xE1,0x53,0x55,0x5D,0x37,0x65,
0xD5,0xF7,0x4D,0x59,0xF6,0x85,0xDB,0xD7,0x8D,0x65,0xD6,0x75,0x61,0x78,0x6D,0xDB,0x38,0x66,0x5B,0x37,0x96,0xD7,0xD6,0x85,0xE3,0x37,0x8E,0xA5,0xAD,0xFB,0xC6,0xB1,
0xDA,0xB2,0x70,0xBC,0xBE,0xAD,0x2C,0xAF,0x6E,0x33,0x76,0xE1,0x37,0x86,0x5B,0xF8,0x8D,0x63,0x33,0x4D,0xDD,0x36,0x5D,0xD5,0xF7,0x4D,0xD5,0xF5,0x7D,0x59,0xB7,0x95,
0xE3,0xD6,0x7D,0xE3,0xF8,0x54,0x55,0xD7,0x4D,0xD9,0x15,0x7E,0xD3,0x95,0x7D,0xE1,0xB6,0x75,0xE5,0xB8,0x75,0xDF,0x28,0xAA,0xAA,0xAF,0xAB,0xB2,0xAB,0xFB,0xAA,0x2C,
0xFB,0xBE,0xAD,0xDB,0x84,0xDD,0xF7,0x95,0x63,0xB5,0x6D,0x63,0x78,0x6D,0x5D,0x18,0x5E,0x59,0x27,0xDC,0xBA,0x6F,0x0C,0xBF,0x70,0x0C,0xCB,0x6A,0xCB,0xC2,0xF2,0xEA,
0xB6,0xB1,0xCC,0xBE,0x4D,0xB9,0x85,0x9D,0xB1,0x1B,0x3F,0x02,0x00,0x00,0x06,0x1C,0x00,0x00,0x02,0x4C,0x28,0x03,0x85,0x86,0xAC,0x08,0x00,0xE2,0x04,0x00,0x18,0x84,
0x9C,0x53,0x4C,0x41,0xA8,0x14,0x83,0x10,0x42,0x48,0x29,0x84,0x90,0x52,0xC5,0x18,0x84,0xCC,0x39,0x29,0x15,0x73,0x50,0x4A,0x29,0xA9,0x85,0x50,0x52,0xAB,0x18,0x83,
0x50,0x39,0x26,0x21,0x73,0x4E,0x4A,0x28,0xA1,0xA5,0x52,0x4A,0x4B,0xA1,0x94,0xD6,0x4A,0x29,0xB1,0x85,0x52,0x5A,0x6B,0xAD,0xD5,0x9A,0x5A,0x8B,0x35,0x94,0xD2,0x5A,
0x28,0x25,0xB6,0x52,0x4A,0x8B,0xAD,0xB5,0x1A,0x5B,0x6B,0xB5,0x46,0x8C,0x41,0xC8,0x1C,0x93,0x92,0x31,0x27,0xA5,0x94,0xD2,0x5A,0x29,0xA5,0xB5,0xCC,0x39,0x29,0x9D,
0x83,0x92,0x3A,0xE7,0x28,0x95,0x92,0x52,0x2C,0x29,0xB5,0x58,0x31,0x26,0x25,0x73,0x8E,0x4A,0xE7,0x20,0xA5,0x92,0x4A,0x4C,0x25,0xA5,0xD8,0x4A,0x2A,0xB1,0x95,0x92,
0x62,0x2C,0x29,0xC5,0xD8,0x52,0x6C,0xB5,0xC5,0x98,0x73,0x28,0xA5,0xC5,0x92,0x4A,0x8C,0x25,0xA5,0x58,0x5B,0x4C,0xB5,0xB5,0x18,0x6B,0x8E,0x18,0x83,0x92,0x39,0x26,
0x25,0x63,0x4E,0x4A,0x29,0xA5,0xB5,0x52,0x4A,0x6B,0x15,0x63,0x52,0x3A,0xE8,0x28,0x65,0xCE,0x49,0x2A,0x29,0xB5,0x58,0x4A,0x4A,0x31,0x73,0x4E,0x4A,0xE7,0x1C,0xA5,
0x0E,0x3A,0x2A,0x25,0x95,0xD8,0x4A,0x2A,0xB1,0x85,0x52,0x62,0x2B,0x29,0xC5,0x18,0x4A,0x69,0x31,0xC6,0x98,0x6B,0x4B,0xB1,0xE5,0x52,0x52,0x8B,0x25,0xA5,0x18,0x4B,
0x2A,0x31,0xB6,0x18,0x73,0x6E,0x31,0xD5,0xD6,0x49,0x68,0x2D,0x94,0x12,0x63,0x28,0x25,0xC6,0x18,0x63,0xCD,0xAD,0xB5,0x5A,0x43,0x29,0xB1,0x95,0x94,0x62,0x2C,0x29,
0xC5,0x16,0x63,0xAD,0xBD,0xC5,0x98,0x6B,0x28,0x25,0xC6,0x92,0x4A,0x8C,0x25,0xA5,0x18,0x63,0x6D,0xB9,0xB6,0x18,0x6B,0x6E,0xAD,0xD5,0x9A,0x5A,0xAB,0xB9,0xC5,0x98,
0x6B,0x6D,0xB9,0xF5,0x5A,0x73,0xF0,0xA9,0xB5,0x5A,0x53,0x4B,0xB9,0xB6,0x18,0x73,0x8E,0xB5,0xF5,0x58,0x6B,0x0E,0xBE,0x93,0xD2,0x5A,0x28,0x25,0xB6,0x52,0x4A,0x8C,
0x2D,0xB6,0x5A,0x5B,0x8C,0xB9,0x86,0x52,0x62,0x2C,0x29,0xC5,0x58,0x4A,0x6A,0x31,0xC6,0x98,0x73,0x6B,0xB1,0xE6,0x50,0x4A,0x8B,0x25,0xA5,0x16,0x4B,0x2A,0x31,0xB6,
0x18,0x6B,0x8E,0x35,0xE6,0x9A,0x5A,0xCB,0xB5,0xC5,0x98,0x6B,0x6A,0xAD,0xE6,0x5A,0x6B,0xD0,0xB1,0xE5,0xD8,0x5B,0x6B,0x35,0xB7,0x18,0x6B,0x4E,0xAD,0xE5,0x5A,0x73,
0xED,0x41,0xE6,0xD6,0x5B,0x01,0x00,0x00,0x03,0x0E,0x00,0x00,0x01,0x26,0x94,0x81,0x42,0x43,0x56,0x02,0x00,0x51,0x00,0x00,0x80,0x31,0x8C,0x39,0x27,0xA5,0x51,0xC8,
0x39,0xE7,0xA4,0x34,0x48,0x39,0xE7,0x9C,0x94,0xCC,0x31,0x08,0x21,0xA4,0x94,0x39,0x07,0x21,0x84,0x94,0x3A,0xE7,0x20,0x94,0xD4,0x5A,0xE7,0x20,0x84,0x52,0x5A,0x2B,
0xA5,0xA4,0xD4,0x5A,0x8C,0xA5,0x94,0x94,0x5A,0x8B,0xB1,0x00,0x00,0x80,0x02,0x07,0x00,0x80,0x00,0x1B,0x34,0x25,0x16,0x07,0x28,0x34,0x64,0x25,0x00,0x90,0x0A,0x00,
0x60,0x70,0x1C,0x4D,0x13,0x3D,0x53,0x54,0x4D,0x5B,0x76,0x24,0xC9,0xF3,0x44,0x51,0x55,0x55,0xD5,0xB6,0x1D,0x49,0xF2,0x3C,0x51,0x34,0x55,0x55,0xB5,0x6D,0xCD,0xF3,
0x44,0x51,0x35,0x55,0xD5,0x75,0x7D,0x5D,0xF3,0x3C,0x51,0x34,0x55,0x55,0x75,0x5D,0x5D,0x17,0x4D,0x53,0x55,0x55,0xD5,0x75,0x65,0xD9,0xF7,0x45,0xD3,0x54,0x55,0x55,
0x75,0x5D,0x57,0xF6,0x75,0x53,0x55,0x55,0xD5,0x75,0x65,0x59,0x96,0x7D,0xE1,0x54,0x55,0x55,0x75,0x5D,0xD7,0x95,0x6D,0xDF,0x57,0x5D,0xD7,0x75,0x65,0xD9,0xB6,0x6D,
0xDD,0x18,0x56,0xD7,0x75,0x5D,0x59,0x96,0x6D,0x5B,0x37,0x8E,0xDD,0xD6,0x75,0xDD,0xF7,0x85,0xE1,0x18,0x9E,0xE7,0xD6,0x75,0x5D,0xF7,0x85,0xE1,0x37,0x2A,0x05,0x00,
0x80,0x27,0x38,0x00,0x00,0x15,0xD8,0xB0,0x3A,0xC2,0x49,0xD1,0x58,0x60,0xA1,0x21,0x2B,0x01,0x80,0x0C,0x00,0x00,0xC2,0x18,0x84,0x0C,0x42,0x0A,0x19,0x84,0x90,0x42,
0x0A,0x29,0x85,0x90,0x52,0x4A,0x00,0x00,0xC0,0x80,0x03,0x00,0x40,0x80,0x09,0x65,0xA0,0xD0,0x90,0x95,0x00,0x40,0x0C,0x00,0x00,0x40,0x08,0x84,0x10,0x22,0xC6,0x20,
0x84,0x10,0x29,0xE5,0x9C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0x27,0x00,0x60,0x3F,0xC2,0x01,0x40,0xEA,0xC1,
0xC4,0xC4,0x14,0x16,0x1A,0xB2,0x12,0x00,0x48,0x05,0x00,0x00,0x8C,0x51,0x4A,0x31,0xE7,0x20,0xA4,0xD2,0x30,0xE6,0x9C,0x73,0x10,0x52,0x69,0xA9,0x51,0xCC,0x39,0xE7,
0xA4,0x94,0xD4,0x52,0xE6,0x1C,0x84,0x52,0x52,0x6A,0x2D,0xC6,0xCC,0x39,0x08,0xA5,0xA4,0xD4,0x5A,0x8C,0x99,0x73,0x52,0x62,0x8B,0xB1,0xC7,0x58,0x33,0xE7,0x24,0xB5,
0x16,0x63,0xAD,0xB5,0x76,0x52,0x62,0x8B,0xB1,0xD7,0x9C,0x7B,0xEE,0x24,0xB5,0x18,0x63,0xEC,0xB9,0xF7,0x5A,0x5A,0xAC,0x39,0xD7,0x5A,0x73,0xCF,0xBD,0xA4,0x16,0x63,
0xCE,0xBD,0xF7,0xDA,0x7B,0x8B,0x31,0xD7,0x5C,0x73,0xAE,0xB9,0xF7,0x54,0x6B,0xAE,0x3D,0xF7,0x9A,0x7B,0xCD,0x05,0x00,0xE0,0x34,0x38,0x00,0x80,0x1E,0xD8,0xB0,0x3A,
0xC2,0x49,0xD1,0x58,0x60,0xA1,0x21,0x2B,0x01,0x80,0x54,0x00,0x00,0x02,0x21,0xA5,0x18,0x73,0xCE,0x39,0xE7,0x90,0x52,0x8A,0x39,0xE6,0x9C,0x83,0x10,0x22,0xA5,0x18,
0x73,0xCE,0x39,0xE7,0x1C,0x54,0x8C,0x31,0xE6,0x9C,0x83,0x10,0x42,0xA8,0x18,0x63,0xCC,0x39,0x08,0x21,0x84,0x90,0x39,0xE7,0x9C,0x73,0xD0,0x41,0x08,0x21,0x73,0xCE,
0x39,0xE7,0x20,0x84,0x10,0x42,0xE7,0x20,0x84,0x0E,0x42,0x08,0x21,0x84,0xCE,0x39,0x08,0xA1,0x83,0x10,0x42,0x08,0x1D,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x3A,0x08,
0x21,0x84,0x10,0x42,0x08,0x21,0x74,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x50,0x00,0x00,0x60,0x81,0x03,0x00,0x40,0x80,0x0D,
0xAB,0x23,0x9C,0x14,0x8D,0x05,0x16,0x1A,0xB2,0x12,0x00,0x00,0x02,0x00,0x60,0x1C,0xA6,0x9A,0x4A,0xAD,0x08,0x52,0x8E,0x41,0x6D,0x0D,0x51,0x88,0x49,0x51,0x95,0x52,
0x4A,0x39,0x8F,0x99,0x51,0x46,0x41,0x52,0x95,0x42,0x08,0x31,0x2F,0x1D,0x64,0x50,0x19,0x4B,0xBD,0x28,0x63,0x32,0x0A,0x00,0x00,0x80,0x20,0x00,0x20,0xC0,0x04,0x10,
0x18,0x20,0x28,0xF8,0x42,0x08,0x88,0x31,0x00,0x00,0x41,0x88,0xCC,0x10,0x09,0x85,0x55,0xB0,0xC0,0xA0,0x0C,0x1A,0x1C,0xE6,0x01,0xC0,0x03,0x44,0x84,0x44,0x00,0x90,
0x98,0xA0,0x48,0xBB,0xB8,0x80,0x2E,0x03,0x5C,0xD0,0xC5,0x5D,0x07,0x42,0x08,0x42,0x10,0x82,0x58,0x1C,0x40,0x01,0x09,0x38,0x38,0xE1,0x86,0x27,0xDE,0xF0,0x84,0x1B,
0x9C,0xA0,0x53,0x54,0xEA,0x20,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0xE0,0x01,0x00,0xE0,0xA0,0x00,0x22,0x22,0x9A,0xAB,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,
0x08,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xF8,0x00,0x00,0x38,0x3E,0x80,0x88,0x88,0xE6,0x2A,0x2C,0x2E,0x30,0x32,0x34,0x36,0x38,0x3A,0x3C,0x02,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x80,0x80,
};
static const uint8_t vcb_3[] = {
0x24,0x42,0x43,0x56,0x01,0x00,0x40,0x00,0x00,0x18,0x42,0x10,0x2A,0x05,0xAD,0x63,0x8E,0x3A,0xC8,0x15,0x21,0x8C,0x19,0xA2,0xA0,0x42,0xCA,0x29,0xC7,0x1D,0x42,0xD0,
0x21,0xA3,0x24,0x43,0x88,0x3A,0xC6,0x35,0xC7,0x18,0x63,0x47,0xB9,0x64,0x8A,0x42,0xC9,0x81,0xD0,0x90,0x55,0x00,0x00,0x40,0x00,0x00,0xA4,0x1C,0x57,0x50,0x72,0x49,
0x2D,0xE7,0x9C,0x73,0xA3,0x18,0x57,0xCC,0x71,0xE8,0x20,0xE7,0x9C,0x73,0xE5,0x20,0x67,0xCC,0x71,0x09,0x25,0xE7,0x9C,0x73,0x8E,0x39,0xE7,0x92,0x72,0x8E,0x31,0xE7,
0x9C,0x73,0xA3,0x18,0x57,0x0E,0x72,0x29,0x2D,0xE7,0x9C,0x73,0x81,0x14,0x47,0x8A,0x71,0xA7,0x18,0xE7,0x9C,0x73,0xA4,0x1C,0x47,0x8A,0x71,0xA8,0x18,0xE7,0x9C,0x73,
0x6D,0x31,0xB7,0x92,0x72,0xCE,0x39,0xE7,0x9C,0x73,0xE6,0x20,0x87,0x52,0x72,0xAE,0x35,0xE7,0x9C,0x73,0xA4,0x18,0x67,0x0E,0x72,0x0B,0x25,0xE7,0x9C,0x73,0xC6,0x20,
0x67,0xCC,0x71,0xEB,0x20,0xE7,0x9C,0x73,0x8C,0x35,0xB7,0xD4,0x72,0xCE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0x8C,0x31,0xE7,0x9C,
0x73,0xCE,0x39,0xE7,0x9C,0x73,0x6E,0x31,0xE7,0x16,0x73,0xAE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0xE7,0x1C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0x20,0x34,0x64,0x15,0x00,0x90,
0x00,0x00,0xA0,0xA1,0x28,0x8A,0xE2,0x28,0x0E,0x10,0x1A,0xB2,0x0A,0x00,0xC8,0x00,0x00,0x10,0x40,0x71,0x14,0x47,0x91,0x14,0x4B,0xB1,0x1C,0xCB,0xD1,0x24,0x0D,0x08,
0x0D,0x59,0x05,0x00,0x00,0x01,0x00,0x08,0x00,0x00,0xA0,0x48,0x86,0xA4,0x48,0x8A,0xA5,0x58,0x8E,0x66,0x69,0x9E,0x26,0x7A,0xA2,0x28,0x9A,0xA2,0x2A,0xAB,0xB2,0x69,
0xCA,0xB2,0x2C,0xCB,0xB2,0xEB,0xBA,0x2E,0x10,0x1A,0xB2,0x0A,0x00,0x48,0x00,0x00,0x50,0x51,0x14,0xC5,0x70,0x14,0x07,0x08,0x0D,0x59,0x05,0x00,0x64,0x00,0x00,0x08,
0x60,0x28,0x8A,0xA3,0x38,0x8E,0xE4,0x58,0x92,0xA5,0x59,0x9E,0x07,0x84,0x86,0xAC,0x02,0x00,0x80,0x00,0x00,0x04,0x00,0x00,0x50,0x0C,0x47,0xB1,0x14,0x4D,0xF1,0x24,
0xCF,0xF2,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0x0D,0x08,0x0D,0x59,0x05,0x00,0x20,0x00,0x00,0x00,0x82,
0x28,0x64,0x18,0x03,0x42,0x43,0x56,0x01,0x00,0x40,0x00,0x00,0x08,0x21,0x1A,0x19,0x43,0x9D,0x52,0x12,0x5C,0x0A,0x16,0x42,0x1C,0x11,0x43,0x1D,0x42,0xCE,0x43,0xA9,
0xA5,0x83,0xE0,0x29,0x85,0x25,0x63,0xD2,0x53,0xAC,0x41,0x08,0x21,0x7C,0xEF,0x3D,0xF7,0xDE,0x7B,0xEF,0x81,0xD0,0x90,0x55,0x00,0x00,0x10,0x00,0x00,0x61,0x14,0x38,
0x88,0x81,0xC7,0x24,0x08,0x21,0x84,0x62,0x14,0x27,0x44,0x71,0xA6,0x20,0x08,0x21,0x84,0xE5,0x24,0x58,0xCA,0x79,0xE8,0x24,0x08,0xDD,0x83,0x10,0x42,0xB8,0x9C,0x7B,
0xCB,0xB9,0xF7,0xDE,0x7B,0x20,0x34,0x64,0x15,0x00,0x00,0x08,0x00,0xC0,0x20,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x29,0xA4,0x94,0x52,0x48,0x29,0xA6,0x98,
0x62,0x8A,0x29,0xC7,0x1C,0x73,0xCC,0x31,0xC7,0x20,0x83,0x0C,0x32,0xE8,0xA0,0x93,0x4E,0x3A,0xC9,0xA4,0x92,0x4E,0x3A,0xCA,0x24,0xA3,0x8E,0x52,0x6B,0x29,0xB5,0x14,
0x53,0x4C,0xB1,0xE5,0x16,0x63,0xAD,0xB5,0xD6,0x9C,0x73,0xAF,0x41,0x29,0x63,0x8C,0x31,0xC6,0x18,0x63,0x8C,0x31,0xC6,0x18,0x63,0x8C,0x31,0xC6,0x18,0x23,0x08,0x0D,
0x59,0x05,0x00,0x80,0x00,0x00,0x10,0x06,0x19,0x64,0x90,0x41,0x08,0x21,0x84,0x14,0x52,0x48,0x29,0xA6,0x98,0x72,0xCC,0x31,0xC7,0x1C,0x03,0x42,0x43,0x56,0x01,0x00,
0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x1C,0x45,0x52,0x24,0x47,0x72,0x24,0x47,0x92,0x24,0xC9,0x92,0x2C,0x49,0x93,0x3C,0xCB,0xB3,0x3C,0xCB,0xB3,0x3C,0x4D,0xD4,0x44,
0x4D,0x15,0x55,0xD5,0x55,0x6D,0xD7,0xF6,0x6D,0x5F,0xF6,0x6D,0xDF,0xD5,0x65,0xDF,0xF6,0x65,0xDB,0xD5,0x65,0x5D,0x96,0x65,0xDD,0xB5,0x6D,0x5D,0xD6,0x5D,0x5D,0xD7,
0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x81,0xD0,0x90,0x55,0x00,0x80,0x04,0x00,0x80,0x8E,0xE4,0x38,0x8E,0xE4,0x38,0x8E,0xE4,
0x48,0x8E,0xA4,0x48,0x0A,0x10,0x1A,0xB2,0x0A,0x00,0x90,0x01,0x00,0x10,0x00,0x80,0xA3,0x38,0x8A,0xE3,0x48,0x8E,0xE4,0x58,0x8E,0x25,0x59,0x92,0x26,0x69,0x96,0x67,
0x79,0x96,0xA7,0x79,0x9A,0xA8,0x89,0x1E,0x10,0x1A,0xB2,0x0A,0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x80,0xA2,0x28,0x8A,0xA3,0x38,0x8E,0x24,0x59,0x96,
0xA6,0x69,0x9E,0xA7,0x7A,0xA2,0x28,0x9A,0xAA,0xAA,0x8A,0xA6,0xA9,0xAA,0xAA,0x6A,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,
0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x02,0xA1,0x21,0xAB,0x00,0x00,0x09,0x00,0x00,0x1D,0xC7,0x71,0x1C,0x47,0x71,
0x1C,0xC7,0x71,0x24,0x47,0x92,0x24,0x20,0x34,0x64,0x15,0x00,0x20,0x03,0x00,0x20,0x00,0x00,0x43,0x51,0x1C,0x45,0x72,0x2C,0xC7,0x92,0x34,0x4B,0xB3,0x3C,0xCB,0xD3,
0x44,0xCF,0xF4,0x5C,0x51,0x36,0x75,0x53,0x57,0x6D,0x20,0x34,0x64,0x15,0x00,0x00,0x08,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0xC7,0x73,0x3C,0xC7,0x73,0x3C,0xC9,
0x93,0x3C,0xCB,0x73,0x3C,0xC7,0x93,0x3C,0x49,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,
0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0x03,0x42,0x43,0x56,0x02,0x00,0x64,0x00,0x00,0x1C,0xB5,0x56,0x73,
0xEF,0xBD,0x87,0x8C,0x39,0x48,0xB1,0xF6,0x1E,0x33,0xA5,0x18,0xB4,0x98,0x7B,0xCE,0x14,0x32,0x4A,0x52,0xED,0xAD,0x63,0x46,0x18,0x26,0xB5,0xA7,0x90,0x21,0x62,0x14,
0xD4,0x9E,0x4A,0xC8,0x10,0x52,0xD0,0x7B,0x29,0xA1,0x53,0x8A,0x49,0xEF,0x29,0xA5,0x52,0x4A,0xAA,0xBD,0xF7,0x5A,0x63,0xED,0xBD,0xF7,0x1E,0x08,0x0D,0x59,0x11,0x00,
0x44,0x01,0x00,0x00,0x08,0x21,0xC6,0x10,0x63,0x88,0x31,0x06,0x21,0x83,0x10,0x31,0xC6,0x20,0x64,0x10,0x22,0xC6,0x1C,0x84,0x0C,0x42,0x06,0x21,0x94,0x12,0x4A,0xC9,
0x20,0x84,0x52,0x42,0x49,0x11,0x73,0x0E,0x42,0x07,0x21,0x83,0x10,0x4A,0x09,0xA1,0x64,0x10,0x42,0x29,0x21,0x95,0x02,0x00,0x00,0x02,0x1C,0x00,0x00,0x02,0x2C,0x84,
0x42,0x43,0x56,0x04,0x00,0x71,0x02,0x00,0x08,0x42,0xCE,0x21,0xC6,0x20,0x44,0x8C,0x41,0x08,0x25,0xA4,0x14,0x42,0x48,0x29,0x62,0x0C,0x42,0xE6,0x9C,0x94,0xCC,0x39,
0x29,0xA5,0x94,0xD6,0x42,0x29,0xA9,0x45,0x8C,0x41,0xC8,0x9C,0x93,0x92,0x39,0x27,0x25,0x94,0xD2,0x52,0x29,0xA5,0xB5,0x50,0x4A,0x6B,0x25,0x95,0xD8,0x42,0x29,0xAD,
0xB5,0xD6,0x6A,0x4D,0xAD,0xC5,0x1A,0x4A,0x69,0x2D,0x94,0xD2,0x5A,0x29,0xA5,0xB5,0xD4,0x5A,0x8D,0x2D,0xB6,0x5A,0x23,0xC6,0x20,0x64,0xCE,0x49,0xC9,0x9C,0x93,0x52,
0x52,0x69,0xAD,0x94,0xD4,0x5A,0xE6,0x9C,0x94,0x0E,0x42,0x4A,0x1D,0x84,0x94,0x52,0x4A,0x2D,0x96,0x94,0x5A,0xCC,0x9C,0x93,0xD2,0x41,0x47,0xA5,0x83,0x90,0x52,0x49,
0x25,0xB6,0x92,0x52,0x8C,0x21,0x95,0x18,0x4B,0x4A,0x31,0x96,0x94,0x62,0x6C,0x2D,0xC6,0xDC,0x5A,0xAC,0x39,0x94,0xD2,0x5A,0x49,0x25,0xB6,0x92,0x52,0x8C,0x29,0xA6,
0x1A,0x5B,0x8C,0x39,0x47,0x8C,0x41,0xC8,0x9C,0x93,0x92,0x39,0x27,0xA5,0x94,0xD2,0x5A,0x29,0xA9,0xB5,0xCC,0x39,0x29,0x1D,0x84,0x94,0x3A,0x07,0x25,0x95,0x94,0x62,
0x2C,0x25,0xB5,0x98,0x39,0x27,0xA9,0x83,0x90,0x52,0x07,0x21,0xA5,0x92,0x52,0x6C,0x29,0xA5,0xD8,0x42,0x29,0xAD,0x95,0x94,0x62,0x2C,0x25,0xB5,0xD8,0x62,0xCC,0x35,
0xA5,0xD8,0x6A,0x29,0x29,0xC6,0x92,0x52,0x8C,0x25,0xA5,0x18,0x5B,0x8C,0xB5,0xB6,0xD8,0x6A,0xEC,0x24,0xB4,0x16,0x52,0x89,0x31,0x94,0xD2,0x62,0x8B,0xB1,0xD6,0xD6,
0x62,0xAD,0x21,0x95,0x18,0x4B,0x4A,0x31,0x96,0x94,0x62,0x6C,0x31,0xE6,0x1C,0x63,0xAC,0x39,0x94,0xD2,0x62,0x49,0x25,0xB6,0x92,0x52,0x8C,0x2D,0xB6,0x5C,0x63,0x8C,
0x35,0xA7,0xD6,0x72,0x6D,0x2D,0xE6,0xDC,0x62,0xCC,0xB5,0xC6,0x5C,0x7B,0xAC,0xB9,0xF7,0xD4,0x5A,0xAD,0xA9,0xB5,0x5C,0x5B,0x8C,0x39,0xC7,0x1A,0x7B,0xAD,0xB5,0xF6,
0xDE,0x41,0x68,0x2D,0x94,0x12,0x5B,0x28,0x25,0xC6,0xD6,0x5A,0xAD,0xAD,0xC5,0x9C,0x43,0x29,0xB1,0x95,0x94,0x62,0x2C,0x25,0xC5,0xDA,0x62,0xCC,0xB9,0xB5,0x58,0x73,
0x28,0x25,0xC6,0x92,0x52,0x8C,0x25,0xA5,0x18,0x5B,0x8C,0xB5,0xC6,0x1A,0x73,0x4D,0xAD,0xD5,0xDA,0x62,0xCC,0x35,0xB5,0x56,0x73,0xAD,0xB5,0xE7,0xD8,0x6A,0xED,0xA9,
0xC5,0x9A,0x5B,0x8C,0xB5,0xB7,0xD8,0x72,0x8D,0xB9,0xF6,0x5E,0x73,0xEC,0xB1,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,0x2B,0x01,0x80,0x28,
0x00,0x00,0xC2,0x18,0xA5,0x18,0x83,0xD0,0x20,0xA4,0x94,0x63,0x10,0x1A,0x84,0x94,0x62,0x0E,0x42,0xA5,0x14,0x63,0xCE,0x49,0xA9,0x94,0x62,0xCC,0x39,0x28,0x99,0x63,
0xCE,0x41,0x28,0x25,0x73,0xCE,0x39,0x08,0xA5,0x84,0x10,0x4A,0x28,0x25,0xA5,0x10,0x42,0x29,0xA5,0xA4,0x54,0x00,0x00,0x40,0x81,0x03,0x00,0x40,0x80,0x0D,0x9A,0x12,
0x8B,0x03,0x14,0x1A,0xB2,0x12,0x00,0x08,0x09,0x00,0x20,0x8C,0x51,0x8A,0x31,0xE7,0x20,0x94,0x92,0x52,0x4A,0x11,0x42,0x8C,0x39,0x07,0x21,0x84,0x52,0x52,0x6A,0x29,
0x42,0x88,0x31,0xE7,0x20,0x84,0x50,0x4A,0x4A,0xAD,0x55,0x8C,0x31,0xE6,0x1C,0x84,0x10,0x4A,0x49,0xA9,0xB5,0x8A,0x31,0xC6,0x9C,0x83,0x10,0x42,0x29,0x29,0xB5,0x96,
0x39,0xE7,0x1C,0x84,0x10,0x4A,0x49,0xA9,0xB5,0xD6,0x32,0xE7,0x9C,0x83,0x10,0x42,0x29,0x29,0xA5,0xD6,0x5A,0x08,0x21,0x84,0x50,0x4A,0x29,0x25,0xA5,0xD6,0x62,0xEC,
0x20,0x84,0x50,0x42,0x29,0xA5,0xA4,0xD4,0x5A,0x8C,0x21,0x84,0x10,0x4A,0x29,0x25,0xA5,0xD4,0x5A,0x8B,0x31,0x84,0x10,0x42,0x29,0xA5,0xA4,0xD4,0x52,0x6B,0x31,0x96,
0x52,0x4A,0x49,0x29,0xA5,0xD4,0x5A,0x6B,0x31,0xD6,0x52,0x4A,0x29,0x29,0xA5,0xD4,0x52,0x6B,0xB1,0xC5,0x98,0x52,0x4A,0xA9,0xB5,0xD6,0x5A,0x8B,0x31,0xC6,0x5A,0x53,
0x4A,0x29,0xB5,0xD6,0x5A,0x6B,0xB1,0xC5,0x58,0x6B,0x6A,0xAD,0xB5,0xD6,0x62,0x8C,0x31,0xC6,0x5A,0x6B,0x4D,0xAD,0xB5,0xD6,0x5A,0x8C,0x31,0xD6,0x58,0x6B,0xAD,0x05,
0x00,0x00,0x1C,0x38,0x00,0x00,0x04,0x18,0x41,0x27,0x19,0x55,0x16,0x61,0xA3,0x09,0x17,0x1E,0x80,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x80,0x31,0x88,0x31,0xC4,
0x18,0x82,0x8E,0x49,0xC8,0x24,0x44,0x0E,0x32,0x28,0x19,0x94,0x06,0x42,0x48,0xA9,0xA3,0x94,0x51,0x2A,0x25,0x96,0x1A,0x33,0x4A,0x25,0xA6,0x12,0x6B,0x04,0xA1,0xA3,
0x14,0x52,0xCA,0x28,0x95,0x1A,0x4B,0xAB,0x19,0xA5,0x12,0x63,0x89,0xA5,0x00,0x00,0xB0,0x03,0x07,0x00,0xB0,0x03,0x0B,0xA1,0xD0,0x90,0x95,0x00,0x40,0x1E,0x00,0x00,
0x81,0x90,0x52,0x8C,0x39,0xE7,0x1C,0x42,0x88,0x31,0xC6,0x9C,0x73,0x0E,0x21,0xC5,0x18,0x63,0xCE,0x39,0xA7,0x18,0x63,0xCC,0x39,0xE7,0x9C,0x53,0x8C,0x31,0xE6,0x9C,
0x73,0xCE,0x31,0xC6,0x9C,0x73,0x0E,0x42,0x08,0x19,0x63,0xCE,0x39,0x07,0x21,0x84,0xCE,0x39,0xE7,0x20,0x84,0x10,0x42,0xE7,0x9C,0x73,0x10,0x42,0x08,0xA1,0x73,0xCE,
0x39,0x08,0x21,0x84,0xD0,0x39,0xE7,0x1C,0x84,0x10,0x42,0x28,0x00,0x00,0xA8,0xC0,0x01,0x00,0x20,0xC0,0x46,0x91,0xCD,0x09,0x46,0x82,0x0A,0x0D,0x59,0x09,0x00,0xA4,
0x02,0x00,0x00,0xC6,0x30,0xE6,0x9C,0x73,0x10,0x4A,0x69,0x94,0x72,0x0E,0x42,0x08,0xA5,0xB4,0xD4,0x28,0xE5,0x1C,0x84,0x10,0x4A,0x49,0x2D,0x73,0x0E,0x42,0x29,0xA5,
0xB4,0x16,0x5B,0xE6,0x1C,0x84,0x52,0x4A,0x49,0xAD,0xB5,0x0E,0x42,0x29,0x29,0xA5,0xD4,0x5A,0x8C,0x1D,0x84,0x52,0x52,0x4A,0xA9,0xC5,0x18,0x3B,0x08,0xA5,0xA4,0xD4,
0x5A,0x8C,0xB5,0x76,0x10,0x4A,0x49,0xA9,0xB5,0x18,0x6B,0x0D,0xA5,0xA4,0x16,0x5B,0xAC,0xB5,0xD6,0x1A,0x4A,0x49,0xAD,0xC5,0x18,0x6B,0xAD,0xB5,0xA4,0xD4,0x5A,0x8C,
0xB5,0xE6,0x9C,0x73,0x49,0xA9,0xB5,0x18,0x6B,0xAD,0x35,0xE7,0x02,0x00,0xC0,0x13,0x1C,0x00,0x80,0x0A,0x6C,0x58,0x1D,0xE1,0xA4,0x68,0x2C,0xB0,0xD0,0x90,0x95,0x00,
0x40,0x06,0x00,0x00,0x61,0x0C,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x94,0x42,0x08,0x29,0x25,0x00,0x00,0x60,0xC0,0x01,0x00,0x20,0xC0,0x84,0x32,0x50,0x68,
0xC8,0x4A,0x00,0x20,0x15,0x00,0x00,0x30,0x86,0x31,0xC6,0x9C,0x83,0x50,0x4A,0xA3,0x14,0x84,0x10,0x42,0x28,0x25,0xA5,0x46,0x29,0x07,0x21,0x84,0x50,0x52,0x4B,0x99,
0x83,0x52,0x4A,0x49,0x25,0xB5,0x16,0x33,0x08,0xA5,0x94,0x52,0x4A,0x6A,0x31,0x66,0xD0,0x49,0x49,0x29,0xB5,0x16,0x63,0xCD,0x20,0x94,0x92,0x52,0x6A,0x31,0xC6,0xD8,
0x41,0x28,0x29,0xB5,0xD6,0x62,0x8C,0xB1,0x83,0x50,0x52,0x4A,0xAD,0xC5,0x58,0x6B,0x28,0xA5,0xA5,0x16,0x63,0xAC,0x31,0xC6,0x50,0x4A,0x4A,0xAD,0xC5,0x1A,0x63,0x8D,
0x25,0xA5,0x16,0x6B,0xAD,0xB9,0xD6,0x5A,0x4B,0x4A,0xAD,0xC5,0x18,0x6B,0xAD,0xB9,0x16,0x00,0x80,0xD0,0xE0,0x00,0x00,0x76,0x60,0xC3,0xEA,0x08,0x27,0x45,0x63,0x81,
0x85,0x86,0xAC,0x04,0x00,0xF2,0x00,0x00,0x10,0x84,0x94,0x62,0x8C,0x31,0xC6,0x90,0x52,0x8C,0x31,0xC6,0x98,0x73,0x48,0x29,0xA5,0x18,0x63,0xCC,0x39,0xA5,0x18,0x63,
0x8E,0x39,0xE7,0x9C,0x62,0x8C,0x31,0xC6,0x9C,0x73,0x8E,0x31,0xC6,0x98,0x73,0xCE,0x39,0xC7,0x18,0x63,0xCE,0x39,0xE7,0x9C,0x63,0x8C,0x39,0xE7,0x9C,0x73,0xCE,0x31,
0xC6,0x9C,0x73,0xCE,0x39,0xE7,0x98,0x73,0xCE,0x39,0xE7,0x9C,0x73,0xCC,0x39,0xE7,0x9C,0x73,0xCE,0x39,0x01,0x00,0x40,0x05,0x0E,0x00,0x00,0x01,0x36,0x8A,0x6C,0x4E,
0x30,0x12,0x54,0x68,0xC8,0x4A,0x00,0x20,0x1C,0x00,0x00,0x40,0x88,0x31,0xE7,0x18,0x73,0x4E,0x42,0x4A,0x8D,0x52,0xCE,0x49,0x08,0x1D,0x84,0x52,0x5A,0x6D,0x14,0x73,
0x10,0x4A,0xE8,0x20,0x94,0xD6,0x52,0xE6,0x9C,0x94,0x52,0x42,0x28,0x25,0xC5,0xD8,0x32,0xE7,0x20,0xA5,0x12,0x42,0x2A,0x2D,0xA5,0xDA,0x41,0x48,0x25,0xA5,0x52,0x52,
0x8A,0xAD,0xB6,0x0E,0x42,0x6A,0x29,0x95,0xD2,0x52,0x6B,0xAD,0x66,0xCE,0x41,0x28,0xA5,0xA4,0x96,0x62,0xAC,0x2D,0x73,0x10,0x42,0x29,0x29,0xA5,0xD6,0x6A,0xAD,0x9D,
0x84,0x92,0x52,0x4A,0xB5,0xB5,0x58,0x6B,0x0C,0x21,0x94,0x94,0x52,0x6B,0xAD,0xB6,0x1A,0x6B,0x29,0xA5,0xA5,0x96,0x6A,0xAC,0xB1,0xD6,0x58,0x43,0x29,0xA9,0xA5,0xD8,
0x62,0xAC,0xB5,0xC6,0x5A,0x62,0x6C,0x2D,0xB5,0x1A,0x6B,0xAC,0xAD,0xC6,0x92,0x52,0x4B,0xAD,0xD5,0x5A,0x63,0xAD,0xB5,0x16,0x00,0x60,0xF2,0xE0,0x00,0x00,0x95,0x60,
0xE3,0x0C,0x2B,0x49,0x67,0x85,0xA3,0xC1,0x85,0x86,0xAC,0x04,0x00,0x72,0x03,0x00,0x08,0x84,0x18,0x73,0xCE,0x39,0x08,0x25,0x94,0x10,0x42,0x29,0xA5,0x44,0x4A,0x31,
0xE6,0x1C,0x84,0x10,0x4A,0x28,0xA5,0x94,0x52,0x52,0x89,0x94,0x62,0xCC,0x39,0x07,0xA1,0x94,0x52,0x4A,0x29,0xA5,0x94,0x92,0x31,0xE6,0x1C,0x74,0x10,0x4A,0x28,0xA5,
0x94,0x52,0x52,0x49,0x25,0x63,0xCC,0x39,0x07,0x21,0x94,0x50,0x4A,0x29,0xA5,0x94,0x52,0x4A,0xE7,0x1C,0x84,0x10,0x4A,0x28,0xA5,0x94,0x52,0x4A,0x2A,0x25,0x95,0xCE,
0x39,0x07,0x21,0x84,0x52,0x4A,0x29,0xA5,0x94,0x92,0x52,0x29,0x1D,0x84,0x10,0x42,0x28,0xA5,0x94,0x52,0x52,0x49,0x25,0x95,0x54,0x3A,0x08,0x21,0x84,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x52,0x2A,0xA5,0x84,0x12,0x42,0x29,0x25,0x95,0x52,0x4A,0x29,0xA5,0xA4,0x94,0x52,0x0A,0x21,0x94,0x50,0x4A,0x29,0xA5,0xA4,0x92,0x4A,0x4A,0x29,0x95,
0x12,0x4A,0x28,0xA5,0x94,0x54,0x4A,0x29,0x25,0x95,0x54,0x52,0x29,0x29,0x94,0x52,0x4A,0x29,0xA5,0x94,0x54,0x4A,0x4A,0x25,0xA5,0x94,0x52,0x08,0xA5,0x94,0x52,0x52,
0x29,0xA9,0x94,0x54,0x4A,0x4A,0x29,0xA5,0x50,0x4A,0x29,0xA5,0x94,0x54,0x52,0x49,0x25,0xA5,0x94,0x52,0x49,0xA5,0x94,0x52,0x4A,0x29,0x25,0xA5,0x94,0x52,0x4A,0x29,
0x95,0x94,0x4A,0x29,0xA5,0xA4,0x52,0x4A,0x2A,0x29,0xA5,0x54,0x5A,0x4A,0xA9,0x94,0x52,0x4A,0x49,0xA5,0x94,0x94,0x5A,0x4A,0x29,0xA5,0x94,0x52,0x2A,0xA5,0xA4,0x92,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x54,0x4A,0x49,0x25,0x95,0x92,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0xA5,0x94,0x52,0x4A,0x49,0xA9,0xA4,0x54,0x52,0x2A,
0x29,0xA5,0x92,0x52,0x01,0x00,0x40,0x07,0x0E,0x00,0x00,0x01,0x46,0x54,0x5A,0x88,0x9D,0x66,0x5C,0x79,0x04,0x8E,0x28,0x64,0x98,0x80,0x0A,0x0D,0x59,0x09,0x00,0x84,
0x03,0x00,0x00,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x89,0x8C,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x1A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x54,0x0A,0x49,0x29,0x25,0x84,0x10,0x42,0x08,0x21,0x42,0x02,0x40,0xBA,0x32,0x1C,0x00,0x00,0x02,0xAC,0x49,0x57,0x2F,0x52,0x5D,0xC6,0xE8,0x60,
0x74,0xE9,0xCA,0x2E,0x68,0x74,0x78,0x91,0xA3,0x43,0x00,0x0A,0x00,0x90,0xAE,0x91,0xD5,0x84,0x25,0x34,0x64,0x25,0x00,0x90,0x16,0x00,0x00,0x58,0x69,0xA5,0x95,0x96,
0x5A,0x6B,0xAD,0xB5,0xD6,0x22,0x04,0xA5,0xA5,0xD4,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0x25,0x84,0x14,0x52,0x6A,0xA9,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xCE,0x49,0x0A,
0x2D,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0xE8,0x24,0xB5,0xD4,0x52,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0x83,0x94,0x4A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,
0x16,0x4A,0x6A,0xA9,0xA5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x0B,0x21,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,
0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,
0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x8A,0x1C,0x84,0x8E,0x42,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x11,0x32,0xCE,0x39,0x27,0xA1,0x94,0x94,0x52,0x4A,0x29,0xA5,0xC8,0x08,0x00,0x40,0x8C,
0x70,0x00,0x00,0x08,0xB0,0x84,0xD8,0x55,0xB9,0x99,0xA4,0x5E,0x3D,0x1B,0x12,0xC3,0xE4,0x24,0x7D,0x8A,0xE1,0x6A,0x0C,0xDF,0x02,0x00,0x31,0x61,0x8C,0x09,0x0D,0x59,
0x05,0x00,0xC4,0x00,0x00,0x00,0x84,0x18,0xC6,0x98,0x63,0x8C,0x31,0xE7,0x9C,0x63,0xCE,0x39,0xE7,0x9C,0x73,0x8E,0x41,0xE8,0x20,0x84,0xCE,0x39,0xE7,0x9C,0x73,0xCE,
0x39,0x67,0xAD,0xA4,0x02,0x00,0x00,0x13,0x1C,0x00,0x00,0x02,0xAC,0x60,0x57,0x66,0x69,0xD5,0x46,0x71,0x53,0x27,0x79,0xD1,0x07,0x81,0x4F,0xE8,0x88,0xCD,0xC8,0x90,
0x4B,0xA9,0x98,0xC9,0x89,0xA0,0x47,0x6A,0xA8,0xC5,0x4A,0xB0,0x43,0x2B,0xB8,0xC1,0x0B,0xC0,0x42,0x43,0x56,0x02,0x00,0x64,0x00,0x00,0x10,0x93,0x52,0x52,0x8A,0x45,
0x59,0x08,0x29,0xE6,0xA0,0x25,0xE5,0x21,0x63,0x14,0x83,0x98,0x94,0x87,0x8C,0x41,0xCA,0x59,0x50,0x1A,0x42,0xC6,0x20,0x66,0xC5,0x78,0x8C,0x29,0x84,0x94,0x14,0x23,
0x42,0xE8,0x14,0x52,0x50,0x8C,0x8A,0x31,0x76,0x8C,0x41,0x2F,0x32,0x18,0x9F,0x42,0x08,0xC1,0xE8,0x62,0x8C,0x8E,0xB1,0x16,0x23,0x00,0x00,0x00,0x41,0x00,0x80,0x80,
0x90,0x00,0x00,0x03,0x04,0x05,0x33,0x00,0xC0,0xE0,0x00,0x61,0xE4,0x40,0xA0,0x23,0x80,0xC0,0xA1,0x0D,0x00,0x30,0x10,0x21,0x33,0x81,0x41,0x21,0x34,0x38,0xC8,0x04,
0x80,0x07,0x88,0x08,0xA9,0x00,0x20,0x31,0x41,0x51,0xBA,0xD0,0x05,0x21,0x44,0x90,0x2E,0x82,0x2C,0x1E,0xB8,0x70,0xE2,0xC6,0x13,0x37,0x9C,0xD0,0xA1,0x0D,0x02,0x00,
0x00,0x00,0x00,0x00,0x02,0x00,0x3E,0x00,0x00,0x12,0x0A,0x20,0x22,0x9A,0x99,0xB9,0x0A,0x8B,0x0B,0x8C,0x0C,0x8D,0x0D,0x8E,0x0E,0x8F,0x0F,0x90,0x10,0x91,0x91,0x00,
0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x0F,0x00,0x80,0x84,0x04,0x88,0x88,0x66,0x66,0xAE,0xC2,0xE2,0x02,0x23,0x43,0x63,0x83,0xA3,0xC3,0xE3,0x03,0x24,0x44,0x64,0x24,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x08,
};
static const uint8_t vcb_4[] = {
0x29,0x42,0x43,0x56,0x01,0x00,0x08,0x00,0x00,0x80,0x22,0x4C,0x20,0xC3,0x80,0xD0,0x90,0x55,0x00,0x00,0x10,0x00,0x00,0x80,0xA8,0x36,0x14,0x6B,0xA9,0xB1,0xD6,0x1A,
0x63,0xA1,0x28,0x46,0xD4,0x62,0x6A,0x31,0xC6,0x18,0x63,0xE3,0x2C,0x46,0x90,0x62,0x8B,0x31,0xC6,0x18,0x63,0x8C,0x31,0xC6,0x18,0x63,0x8C,0x31,0xC6,0x18,0x63,0x20,
0x34,0x64,0x15,0x00,0x00,0x04,0x00,0x40,0x31,0xEA,0x15,0x93,0x9E,0x42,0xCC,0x39,0xE7,0xDC,0x18,0xA6,0x8D,0x51,0xDA,0x29,0xC7,0x39,0xE7,0xDC,0x18,0xC5,0x89,0x30,
0x58,0x21,0xA5,0xB9,0xA5,0x9A,0x52,0xCC,0xA1,0x93,0x9C,0x4A,0xCA,0x39,0xE7,0x1C,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x40,0x48,0x21,0x85,0x14,0x52,0x48,0x21,
0x85,0x14,0x52,0x48,0x21,0x85,0x14,0x52,0x4A,0x29,0xA5,0x94,0x62,0x8A,0x29,0xA6,0x98,0x62,0x8A,0x29,0xA6,0x98,0x72,0xCC,0x31,0xC7,0x1C,0x83,0x0C,0x32,0xE8,0xA4,
0x93,0x4E,0x3A,0xE9,0x24,0xA4,0x90,0x42,0x09,0xA5,0xA4,0x92,0x52,0x4A,0xAD,0xC5,0x1A,0x6B,0xEF,0xBD,0xF7,0x9E,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,
0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xCF,0x39,0x07,0x42,0x43,0x56,0x01,0x00,0x20,0x00,0x00,0x04,0x42,0x06,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x14,0x52,0x48,0x21,0xA6,
0x98,0x62,0xCA,0x29,0xA7,0x80,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x4B,0xB1,0x14,0x4D,0xD1,0x1C,0xCF,0xF1,0x1C,0xCF,0x11,0x1D,0x53,0x12,
0x25,0x53,0x32,0x25,0x53,0x72,0x2D,0xD7,0x32,0x2D,0x53,0x33,0x3D,0xD3,0x33,0x45,0x55,0x74,0x55,0x53,0x55,0x65,0xD7,0x75,0x65,0x53,0x36,0x65,0x53,0x36,0x65,0x55,
0x36,0x65,0x53,0x36,0x65,0x53,0x36,0x65,0xD5,0x95,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x20,0x34,0x64,0x15,0x00,0x20,
0x01,0x00,0xA0,0x23,0x39,0x92,0x23,0x29,0x8E,0xE2,0x38,0x8E,0xE3,0x48,0x92,0x04,0x84,0x86,0xAC,0x02,0x00,0x64,0x00,0x00,0x04,0x00,0x60,0x28,0x8A,0xA3,0x48,0x8E,
0x24,0x59,0x92,0x65,0x59,0x96,0x67,0x99,0x9A,0xE9,0x99,0x9E,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x09,0x84,0x86,0xAC,0x02,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,
0x00,0xA0,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0x66,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,
0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x40,0x68,0xC8,0x2A,
0x00,0x40,0x02,0x00,0x40,0xC7,0x71,0x1C,0xC7,0x71,0x1C,0xC7,0x71,0x1C,0x47,0x72,0x24,0x07,0x08,0x0D,0x59,0x05,0x00,0xC8,0x00,0x00,0x08,0x00,0x40,0x52,0x24,0xC5,
0x72,0x34,0x47,0x73,0x34,0xC7,0x73,0x3C,0x47,0x74,0x44,0x47,0x94,0x4C,0x49,0x95,0x5C,0x4B,0xB6,0x64,0x0D,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x08,0x00,0x00,
0x00,0x00,0x00,0x40,0x33,0x2C,0x43,0x53,0x3C,0x47,0xB3,0x44,0x4D,0xD4,0x44,0x51,0xF4,0x44,0x4F,0x14,0x45,0xD1,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,
0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x80,0xD0,
0x90,0x55,0x00,0x00,0x04,0x00,0x00,0x01,0x9D,0x66,0x98,0x6A,0x80,0x08,0x33,0x92,0x59,0x20,0x34,0x64,0x15,0x00,0x80,0x00,0x00,0x00,0x10,0x81,0x0C,0x53,0x0C,0x08,
0x0D,0x59,0x05,0x00,0x00,0x04,0x00,0x00,0x48,0x91,0xE4,0x24,0x89,0x92,0x93,0x52,0x4A,0x39,0x0C,0x92,0xC5,0x24,0xA9,0x94,0x93,0x52,0x4A,0x79,0x14,0x93,0x47,0x35,
0xC9,0x18,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0x0C,0x92,0xE5,0x28,0xA9,0x94,0x93,0x52,0x4A,0x49,0x8C,0x92,0xC5,0x28,0xA9,0x52,
0x93,0x52,0x4A,0x79,0x94,0x93,0x27,0x35,0xC9,0xD8,0x93,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x59,0x90,0x92,0x27,0x2D,0xE9,0x1A,0x94,0x52,
0x4A,0x49,0x8E,0x92,0x06,0x2D,0xD9,0xD4,0x93,0x52,0x4A,0x89,0x52,0x94,0x28,0x39,0xD9,0x9E,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0xF9,
0xA0,0x94,0x0F,0x42,0x29,0xA5,0x94,0x52,0x4A,0xB9,0xDA,0x93,0x6B,0x3D,0x29,0xA5,0x94,0x52,0x4A,0x19,0xA3,0x94,0xF0,0x49,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0xCA,0x08,0x42,0x43,0x56,0x01,0x00,0x40,0x00,0x00,0x80,0x71,0xD6,0x28,0x87,0xA2,0x93,0xE8,0x7C,0x71,0x86,0x72,0xA6,0x29,0x48,0x2A,
0x94,0x26,0x74,0x6F,0x92,0xA3,0xE4,0x39,0xC9,0xAD,0xB4,0xDC,0x9C,0x6E,0xC2,0x39,0xA7,0x9B,0x53,0xCE,0xF9,0xE4,0x9C,0x73,0x82,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,
0x00,0x84,0x10,0x52,0x48,0x21,0x85,0x14,0x52,0x48,0x21,0x85,0x14,0x52,0x88,0x21,0x86,0x18,0x72,0xC8,0x29,0xA7,0xA0,0x82,0x0A,0x2A,0xA9,0xA4,0xA2,0x8A,0x2A,0xAA,
0xAC,0xB2,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x32,0xEB,0xAC,0xA3,0x8E,0x3A,0x0B,0x29,0x84,0x92,0x42,0x0B,0xAD,0xD5,0x18,0x6B,0x8C,0xB1,0xD5,
0xDE,0x9C,0xB4,0x35,0x47,0x29,0x9D,0x94,0x52,0x4A,0x29,0xA5,0x94,0xCE,0x39,0xE7,0x9C,0x20,0x34,0x64,0x15,0x00,0x00,0x02,0x00,0x40,0x20,0x64,0x90,0x41,0x06,0x19,
0x65,0x14,0x52,0x88,0x21,0xA6,0x9C,0x72,0xCA,0x29,0xA8,0xA4,0x92,0x0A,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x00,0x10,0x25,0xD3,0x31,0x1D,0xD1,
0x11,0x15,0xD1,0x11,0x1D,0xD1,0x11,0x1D,0xD1,0x11,0x1D,0xCF,0xF1,0x1C,0x4F,0x12,0x25,0xD1,0xF2,0x2C,0x51,0x33,0x3D,0x53,0x34,0x4D,0xD3,0x55,0x65,0x57,0x96,0x75,
0xD9,0x96,0x6D,0x57,0x97,0x75,0x5B,0x97,0x7D,0xDB,0xB7,0x75,0xDB,0xB6,0x7D,0xDD,0xD8,0x8D,0xDF,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,
0x8E,0x63,0x08,0x42,0x43,0x56,0x01,0x00,0x20,0x00,0x00,0x00,0x42,0x08,0x21,0x84,0x14,0x52,0x48,0x21,0x85,0x94,0x62,0x8A,0x31,0xE7,0xA0,0x83,0x10,0x42,0x29,0x81,
0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x45,0x71,0x14,0xC7,0x91,0x1C,0x49,0x92,0x24,0x4B,0xB2,0x2C,0xCD,0xD2,0x34,0x4D,0xD3,0x34,0x4F,0xF4,
0x44,0xCF,0xF4,0x54,0xCF,0x15,0x65,0xD1,0x16,0x6D,0xCF,0xF5,0x6C,0xD1,0xF6,0x5C,0x4F,0xF5,0x54,0x4F,0x15,0x55,0x53,0x35,0x5D,0xD3,0x55,0x5D,0xD7,0x75,0x5D,0xD5,
0x55,0x65,0x55,0x76,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x65,0x20,0x34,0x64,0x15,0x00,0x20,0x01,0x00,0xA0,0x23,0x39,0x92,
0x22,0x29,0x92,0x22,0x39,0x8E,0x23,0x39,0x92,0x04,0x84,0x86,0xAC,0x02,0x00,0x64,0x00,0x00,0x04,0x00,0xA0,0x28,0x8A,0xE2,0x38,0x8E,0xE4,0x58,0x92,0x25,0x69,0x92,
0x28,0x99,0x96,0x6A,0xB9,0x9A,0xEC,0xE9,0x9E,0x2E,0xEA,0xA2,0x0E,0x84,0x86,0xAC,0x02,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x60,0x88,0x86,0x68,0x88,
0x8E,0x68,0x89,0x9A,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,
0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x40,0x68,0xC8,0x2A,0x00,0x40,0x02,0x00,0x40,0x47,
0x72,0x24,0xC7,0x52,0x2C,0x45,0x52,0x24,0xC5,0x72,0x2C,0x07,0x08,0x0D,0x59,0x05,0x00,0xC8,0x00,0x00,0x08,0x00,0xC0,0x31,0x1C,0x43,0x52,0x24,0xC7,0xB2,0x2C,0x4B,
0xD3,0x34,0xCF,0xF3,0x3C,0x4F,0xF4,0x44,0x51,0x14,0x45,0xD3,0x54,0x4D,0x15,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x40,0x51,0x14,
0xCB,0xB1,0x1C,0x49,0xD2,0x1C,0x4F,0x12,0x1D,0x51,0x12,0x25,0xD1,0x12,0x25,0x51,0x13,0x35,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,
0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x81,0xD0,0x90,0x95,0x00,0x00,0x19,0x00,
0x00,0x03,0xB1,0xF5,0xD4,0x72,0xEE,0x8D,0xA0,0x48,0x2A,0x47,0xB5,0xC6,0xD4,0x51,0xE6,0x24,0x06,0x61,0x1A,0x8A,0xA0,0x82,0x18,0x84,0x0C,0x15,0x44,0x88,0x51,0x0E,
0x26,0x62,0x0A,0x19,0x26,0x39,0x97,0x0C,0x3A,0xA6,0x98,0xD4,0x18,0x4B,0x2A,0x1D,0x73,0x52,0x6B,0x4B,0x25,0x54,0x48,0x41,0x0C,0x36,0xA6,0x52,0x29,0xE5,0xA8,0x07,
0x42,0x43,0x56,0x08,0x00,0xA1,0x19,0x00,0x0E,0xC7,0x01,0x24,0xCD,0x02,0x24,0x4B,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x49,0xD3,0x00,0xCD,0xF3,0x00,0xCD,0xF3,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xD2,0x34,0xC0,0xF2,0x3C,0x40,0xF3,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x4D,0x03,0x34,0xD1,0x03,0x34,0xCF,0x03,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x4D,0xF4,0x00,0x4F,0x34,0x01,0x4F,0x14,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xF2,0x3C,0xC0,0x33,0x3D,0xC0,0x13,0x4D,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x1C,0x4D,0x03,0x34,0xCF,0x03,0x34,0xCF,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCB,0xF3,0x00,0xCF,0x14,0x01,0xCF,0x33,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x40,
0xF3,0x44,0xC0,0x13,0x45,0xC0,0x33,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x0E,0x00,0x00,0x01,0x16,0x42,0xA1,0x21,0x2B,0x02,0x80,0x38,0x01,
0x00,0x87,0x24,0x41,0x92,0x20,0x49,0xD0,0x34,0x80,0x64,0x59,0xF0,0x34,0x68,0x1A,0x4C,0x13,0x20,0x59,0x16,0x34,0x0D,0x9A,0x06,0xD3,0x04,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x40,0xD2,0x34,0x68,0x1A,0x34,0x0D,0xA2,0x08,0x90,0x34,0x0D,0x9A,0x06,0x4D,0x83,0x28,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,
0x79,0x1A,0x34,0x0D,0x9A,0x06,0x51,0x04,0x48,0x9A,0x07,0x4D,0x83,0xA6,0x41,0x14,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD0,0x4C,0x13,0xA2,0x08,0x51,
0x84,0x69,0x02,0x34,0xD3,0x84,0x28,0x42,0x14,0x61,0x9A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x80,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,0x2B,0x02,0x80,0x38,0x01,0x00,0x87,0xE2,0x58,0x16,0x00,0x00,0x38,0x92,0x63,0x59,0x00,
0x00,0xE0,0x38,0x8E,0x65,0x01,0x00,0x80,0x65,0x59,0x9A,0x06,0x00,0x00,0x96,0x65,0x69,0x1A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,
0x2B,0x01,0x80,0x28,0x00,0x00,0x87,0xA2,0x58,0x16,0x70,0x1C,0xCB,0x02,0x8E,0x63,0x59,0x40,0x92,0x2C,0x0B,0x60,0x59,0x00,0xCD,0x03,0x68,0x1A,0x40,0x14,0x01,0x80,
0x00,0x00,0x80,0x02,0x07,0x00,0x80,0x00,0x1B,0x34,0x25,0x16,0x07,0x28,0x34,0x64,0x25,0x00,0x10,0x05,0x00,0xE0,0x50,0x14,0xCB,0xD2,0x34,0x51,0xE4,0x38,0x9A,0xA6,
0x69,0xA2,0xC8,0x71,0x34,0x4D,0xD3,0x44,0x91,0x65,0x69,0x9A,0xE7,0x99,0x26,0x34,0xCD,0xF3,0x4C,0x13,0x9E,0xE7,0x79,0xA6,0x09,0xCF,0xF3,0x3C,0xD3,0x84,0x69,0x8A,
0xA2,0xAA,0x02,0x51,0x54,0x55,0x01,0x00,0x00,0x05,0x0E,0x00,0x00,0x01,0x36,0x68,0x4A,0x2C,0x0E,0x50,0x68,0xC8,0x4A,0x00,0x20,0x24,0x00,0xC0,0xE1,0x38,0x96,0xE5,
0x79,0x9E,0x27,0x8A,0xA6,0x68,0x9A,0xAA,0xCA,0x71,0x34,0xCD,0xF3,0x44,0x51,0x14,0x4D,0x53,0x55,0x55,0x95,0xE3,0x58,0x96,0xE7,0x89,0xA2,0x28,0x9A,0xA6,0xAA,0xBA,
0x2E,0xCB,0xD2,0x34,0xCF,0x13,0x45,0x51,0x34,0x4D,0x55,0x75,0x5D,0x68,0x9A,0xE7,0x89,0xA2,0x28,0x9A,0xA6,0xAA,0xBA,0x2E,0x3C,0xCF,0xF3,0x44,0xD1,0x14,0x4D,0x55,
0x55,0x5D,0x17,0x9E,0xE7,0x79,0xA2,0x68,0x9A,0xAA,0xA9,0xAA,0xAE,0x0B,0x51,0x14,0x45,0xD3,0x34,0x4D,0x55,0x55,0x55,0xD7,0x05,0xA2,0x68,0x9A,0xA6,0xA9,0xAA,0xAE,
0xEA,0xBA,0xC0,0xF3,0x44,0xD1,0x34,0x55,0xD5,0x75,0x5D,0x17,0x78,0x9E,0x28,0x9A,0xA6,0xAA,0xBA,0xAE,0xEB,0x02,0x51,0x34,0x4D,0xD5,0x54,0x55,0xD7,0x75,0x5D,0x80,
0x69,0x9A,0xA6,0xAA,0xBA,0xAE,0xEC,0x02,0x54,0x55,0x55,0x55,0xD7,0x75,0x65,0x17,0xA0,0xAA,0xAA,0xAA,0xAA,0xAE,0x2B,0xCB,0x00,0x55,0x75,0x5D,0xD7,0x75,0x5D,0x59,
0x06,0xA0,0xAA,0xAE,0xEB,0xBA,0xB2,0x2C,0x00,0x00,0xE0,0xC0,0x01,0x00,0x20,0xC0,0x08,0x3A,0xC9,0xA8,0xB2,0x08,0x1B,0x4D,0xB8,0xF0,0x00,0x14,0x1A,0xB2,0x22,0x00,
0x88,0x02,0x00,0x00,0x8C,0x51,0x4A,0x31,0xA5,0x0C,0x63,0x12,0x42,0x09,0x21,0x62,0x4C,0x42,0x28,0x21,0x54,0x52,0x4A,0x29,0xA9,0x94,0x0A,0x42,0x29,0xA5,0x94,0x50,
0x41,0x28,0xA1,0xA4,0x10,0x32,0x29,0x29,0xA5,0x54,0x4A,0x05,0xA1,0x84,0x50,0x4A,0xA8,0x20,0x94,0x52,0x4A,0x29,0x05,0x00,0x80,0x1D,0x38,0x00,0x80,0x1D,0x58,0x08,
0x85,0x86,0xAC,0x04,0x00,0xF2,0x00,0x00,0x08,0x63,0x94,0x62,0xCC,0x39,0xE7,0x24,0x42,0x4A,0x31,0xE6,0x9C,0x73,0x12,0x21,0xA5,0x18,0x73,0xCE,0x39,0xA9,0x14,0x63,
0xCE,0x39,0xE7,0x9C,0x94,0x92,0x31,0xE7,0x9C,0x73,0x4E,0x4A,0xC9,0x98,0x73,0xCE,0x39,0x27,0xA5,0x64,0xCC,0x39,0xE7,0x9C,0x93,0x52,0x3A,0xE7,0x9C,0x73,0xCE,0x49,
0x29,0xA5,0x74,0xCE,0x39,0xE7,0xA4,0x94,0x52,0x42,0xE8,0x9C,0x83,0x52,0x4A,0x29,0x9D,0x73,0xCE,0x39,0x01,0x00,0x40,0x05,0x0E,0x00,0x00,0x01,0x36,0x8A,0x6C,0x4E,
0x30,0x12,0x54,0x68,0xC8,0x4A,0x00,0x20,0x15,0x00,0xC0,0xE0,0x38,0x96,0xE5,0x79,0x9E,0x27,0x8A,0xA6,0x69,0x49,0x92,0xA6,0x79,0x9E,0x28,0x9A,0xA6,0xAA,0x6A,0x92,
0xA4,0x69,0x9E,0x27,0x8A,0xA6,0xA9,0xAA,0x3C,0xCF,0xF3,0x44,0x51,0x14,0x4D,0x53,0x55,0x79,0x9E,0xE7,0x89,0xA2,0x28,0x9A,0xA6,0xAA,0x72,0x5D,0x51,0x14,0x45,0xD3,
0x34,0x4D,0x55,0xE5,0xBA,0xA2,0x27,0x8A,0xA6,0xA9,0xAA,0xAE,0x0A,0xD1,0x14,0x45,0xD3,0x54,0x55,0xD7,0x85,0x69,0x8A,0xA2,0x69,0xAA,0xAA,0xEB,0x42,0x96,0x4D,0xD3,
0x54,0x5D,0xD7,0x75,0x61,0xDB,0xA6,0xA9,0xAA,0xAA,0xEA,0xBA,0x40,0x75,0x55,0xD5,0x75,0x5D,0x19,0xB8,0xAE,0xAA,0xBA,0xAE,0x2C,0x0B,0x00,0x00,0x4F,0x70,0x00,0x00,
0x2A,0xB0,0x61,0x75,0x84,0x93,0xA2,0xB1,0xC0,0x42,0x43,0x56,0x02,0x00,0x19,0x00,0x00,0x84,0x31,0x08,0x29,0x84,0x10,0x52,0x06,0x21,0xA4,0x10,0x42,0x48,0x29,0x85,
0x90,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,0x2B,0x01,0x80,0x54,0x00,0x00,0x80,0x10,0x29,0xA5,0x94,0x52,0x4A,0x29,0x11,0x63,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x22,0xE6,0xA4,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0x21,0x84,0x50,0x00,0x20,
0x76,0x85,0x03,0xC0,0x4E,0x84,0x0D,0xAB,0x23,0x9C,0x14,0x8D,0x05,0x16,0x1A,0xB2,0x12,0x00,0x08,0x07,0x00,0x00,0x8C,0x41,0x8A,0x31,0x08,0x29,0xB5,0xD6,0x62,0x85,
0x90,0x62,0xCE,0x49,0x49,0x29,0xC6,0x18,0x2B,0x84,0x18,0x73,0x8E,0x4A,0x4A,0x2D,0xB6,0x18,0x34,0xE6,0x1C,0x84,0x94,0x5A,0x6B,0x31,0xD7,0xA0,0x31,0xE7,0x20,0xA4,
0xD2,0x5A,0x8C,0x35,0x06,0xD5,0x42,0x28,0xA5,0xB5,0x18,0x6B,0xAD,0x35,0xB8,0x14,0x3A,0x2A,0xA9,0xC5,0x18,0x6B,0xAD,0x41,0x08,0x95,0x52,0x8A,0x31,0xC6,0x1A,0x73,
0x0D,0x42,0xA8,0x92,0x42,0x6C,0xB1,0xE6,0x9A,0x6B,0x10,0xC2,0xD6,0xD4,0x5A,0xAC,0xB5,0xE7,0x9C,0x83,0x10,0x3A,0xB7,0x14,0x53,0x8C,0x31,0xF7,0x1A,0x84,0x10,0x42,
0xC6,0x1A,0x6B,0xCD,0xB9,0xE7,0x20,0x84,0x10,0xB6,0xD6,0x56,0x5B,0xAF,0xB9,0x06,0x21,0x84,0xF0,0x41,0xD6,0x9A,0x73,0x0E,0x3A,0x08,0x21,0x84,0x0F,0xB2,0xD6,0x9A,
0x83,0xCE,0x05,0x00,0x98,0x3C,0x38,0x00,0x40,0x25,0xD8,0x38,0xC3,0x4A,0xD2,0x59,0xE1,0x68,0x70,0xA1,0x21,0x2B,0x01,0x80,0xDC,0x00,0x00,0x04,0x21,0xA5,0x18,0x73,
0xCE,0x39,0x07,0x21,0x84,0x10,0x42,0x08,0x29,0x42,0x8C,0x31,0xE6,0x9C,0x73,0x10,0x42,0x08,0x21,0x84,0x52,0x52,0x84,0x18,0x63,0xCC,0x39,0xE7,0x20,0x84,0x10,0x42,
0x08,0x21,0xA4,0x8C,0x31,0xE6,0x9C,0x73,0x10,0x42,0x08,0xA1,0x94,0x52,0x4A,0x49,0x29,0x65,0xCC,0x39,0xE7,0x20,0x84,0x10,0x42,0x29,0xA5,0x94,0x92,0x52,0xEA,0x9C,
0x73,0x10,0x42,0x08,0xA1,0x94,0x52,0x4A,0x29,0x25,0xA5,0xD4,0x39,0xE7,0x20,0x84,0x10,0x42,0x09,0xA5,0x94,0x52,0x4A,0x4A,0xA9,0x73,0x0E,0x42,0x08,0x21,0x84,0x52,
0x4A,0x29,0xA5,0x94,0x94,0x52,0x4A,0x9D,0x83,0x10,0x42,0x28,0xA5,0x94,0x52,0x4A,0x29,0x29,0xA5,0x94,0x42,0x08,0x21,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x52,0x4A,
0x29,0x85,0x10,0x42,0x28,0xA5,0x94,0x52,0x4A,0x29,0xA5,0xA4,0x94,0x52,0x0A,0x21,0x84,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x49,0x29,0xA5,0x94,0x52,0x08,0xA1,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x92,0x52,0x4A,0x29,0xA5,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0x25,0xA5,0x94,0x52,0x4A,0xA5,0x84,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x4A,0x29,0xA5,0x94,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x94,0x52,0x4A,0x29,0xA5,0x54,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0x29,0xA5,0x94,0x52,0x4A,0xA9,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x52,0x4A,0x29,0xA5,0x96,0x52,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0xB4,0xD4,0x5A,0x4A,0x29,0xA5,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x49,0x29,0xA5,0x94,0x52,0x4A,0x29,0x95,0x52,0x4A,0x29,0xA5,0x94,0x52,0x00,0x00,0xD0,0x81,0x03,0x00,0x40,0x80,0x11,0x95,0x16,0x62,0xA7,0x19,0x57,0x1E,0x81,
0x23,0x0A,0x19,0x26,0xA0,0x42,0x43,0x56,0x02,0x00,0x64,0x00,0x00,0x08,0xA2,0x14,0x53,0x4A,0xAD,0x45,0x82,0x2A,0xC9,0x9C,0xC4,0x5E,0x42,0x25,0x15,0x73,0x90,0x5A,
0x8A,0x28,0x93,0x4E,0x5A,0x0E,0xAE,0x43,0xD0,0x20,0xE6,0xA4,0x95,0x8A,0x39,0x84,0x94,0x93,0x54,0x3A,0x07,0x95,0x52,0x0C,0x4A,0x2A,0x21,0x75,0x4C,0x29,0x06,0x29,
0x96,0x1C,0x42,0xC6,0x98,0x93,0x9C,0x82,0x4A,0xA1,0x63,0x0E,0x00,0x00,0x00,0x41,0x00,0x00,0x81,0x90,0x09,0x04,0x0A,0xA0,0xC0,0x40,0x06,0x00,0x1C,0x20,0x24,0x48,
0x01,0x00,0x85,0x05,0x86,0x0E,0x11,0x22,0x40,0x8C,0x02,0x03,0xE3,0xE2,0xD2,0x06,0x00,0x20,0x08,0x91,0x19,0x22,0x11,0xB1,0x18,0x24,0x26,0x54,0x03,0x45,0xC5,0x74,
0x00,0xB0,0xB8,0xC0,0x90,0x0F,0x00,0x19,0x1A,0x1B,0x69,0x17,0x17,0xD0,0x65,0x80,0x0B,0xBA,0xB8,0xEB,0x40,0x08,0x41,0x08,0x42,0x10,0x8B,0x03,0x28,0x20,0x01,0x07,
0x27,0xDC,0xF0,0xC4,0x1B,0x9E,0x70,0x83,0x13,0x74,0x8A,0x4A,0x1D,0x08,0x00,0x00,0x00,0x00,0xC0,0x03,0x00,0x3C,0x00,0x00,0x24,0x1B,0x40,0x44,0x44,0x34,0x73,0x1C,
0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x02,0x00,0x00,0x00,0x00,0x80,0x07,0x00,0x1F,0x00,0x00,0x49,0x0A,0x10,0x11,0x11,0xCD,0x1C,0x47,0x87,
0xC7,0x07,0x48,0x88,0xC8,0x08,0x49,0x89,0xC9,0x09,0x4A,0x00,0x00,0x20,0x80,0x00,0x00,0x00,0x00,0x00,0x08,0x20,0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x80,0x00,
0x00,0x00,0x00,0x01,0x01,
};
static const uint8_t vcb_5[] = {
0x22,0x42,0x43,0x56,0x01,0x00,0x40,0x00,0x00,0x24,0x73,0x5A,0x32,0x66,0xA9,0x73,0xD8,0x7B,0xEF,0x1D,0x42,0x92,0x19,0xE3,0x1C,0x42,0xD0,0x7B,0xEF,0x99,0x41,0x4C,
0x11,0xA2,0x1C,0x42,0xCC,0x6B,0xEC,0x21,0x63,0x92,0x19,0xC3,0xA0,0x42,0x8A,0x63,0xAA,0x81,0xD0,0x90,0x55,0x00,0x00,0x40,0x00,0x00,0x67,0xBD,0x97,0xDA,0x7B,0xCB,
0xBD,0xF7,0xDE,0x7B,0x46,0xB9,0x67,0xD4,0x7B,0x69,0xBD,0xF7,0xDE,0x7B,0xC8,0xBD,0x87,0xD6,0x7B,0xCA,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,
0xDE,0x7B,0x25,0xB1,0x67,0x92,0x7B,0x48,0xBD,0xF7,0xDE,0x7B,0xE3,0xB0,0x47,0x8E,0x7B,0x06,0xB9,0xF7,0xDE,0x7B,0x65,0xBD,0x57,0x92,0x7B,0x28,0xB5,0xF7,0xDE,0x7B,
0xED,0xBD,0xB7,0xDA,0x7B,0xEE,0xBD,0xF7,0xDE,0x7B,0x03,0xA9,0x47,0x10,0x7B,0x06,0xB9,0xF7,0xDE,0x7B,0xC1,0xA8,0x27,0x8A,0x7A,0xC4,0xAC,0xF7,0xDE,0x7B,0x03,0xB5,
0x37,0x0C,0x7B,0xE5,0xB0,0xF7,0xDE,0x7B,0xAA,0xBD,0x97,0x5E,0x7B,0xEA,0xBD,0xF7,0xDE,0x7B,0x86,0xBD,0x87,0x98,0x7B,0x8A,0xBD,0xF7,0xDE,0x7B,0x24,0xB5,0x57,0x92,
0x7B,0x28,0xBD,0xF7,0xDE,0x7B,0x86,0xBD,0x57,0xD2,0x7B,0x68,0xBD,0xF7,0xDE,0x7B,0xEA,0xBD,0x97,0xDE,0x7B,0xEC,0xBD,0xF7,0xDE,0x7B,0x20,0x34,0x64,0x15,0x00,0x90,
0x00,0x00,0xA0,0xA2,0x28,0x8A,0xA2,0x28,0x0A,0x10,0x1A,0xB2,0x0A,0x00,0xC8,0x00,0x00,0x10,0x40,0x51,0x1C,0xC5,0x71,0x1C,0xC9,0x91,0x1C,0xC9,0xB1,0x1C,0x0B,0x08,
0x0D,0x59,0x05,0x00,0x00,0x01,0x00,0x08,0x00,0x00,0xA0,0x48,0x8A,0xA4,0x58,0x8E,0xE5,0x58,0x8E,0x25,0x59,0x92,0x25,0x59,0x92,0x25,0x49,0x92,0xA5,0x79,0xA6,0xEB,
0xBA,0xAE,0xEB,0xBA,0xAE,0xEB,0xBA,0x2E,0x10,0x1A,0xB2,0x0A,0x00,0x48,0x00,0x00,0x50,0x51,0x14,0xC5,0x70,0x14,0x07,0x08,0x0D,0x59,0x05,0x00,0x64,0x00,0x00,0x08,
0xA0,0x48,0x8A,0xA5,0x68,0x8A,0xA7,0x88,0x8A,0xA9,0xA8,0x8E,0x0A,0x84,0x86,0xAC,0x02,0x00,0x80,0x00,0x00,0x04,0x00,0x00,0x10,0x5C,0x43,0x54,0x4C,0xC7,0x95,0x5C,
0xCB,0x35,0x5D,0xD5,0x75,0x5D,0xD7,0x75,0x5D,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x15,0x08,0x0D,0x59,0x05,0x00,0x40,0x00,0x00,0x10,0xD0,
0x69,0x86,0xA9,0x06,0x88,0x30,0x23,0x99,0x05,0x42,0x43,0x56,0x01,0x00,0x08,0x00,0x00,0x00,0x11,0xC8,0x30,0xC5,0x80,0xD0,0x90,0x55,0x00,0x00,0x40,0x00,0x00,0x80,
0x14,0x49,0x4E,0x92,0x28,0x39,0x29,0xA5,0x94,0xC3,0x20,0x59,0x4C,0x92,0x4A,0x39,0x29,0xA5,0x94,0x47,0x31,0x79,0x54,0x93,0x8C,0x41,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0xC2,0x20,0x59,0x8E,0x92,0x4A,0x39,0x29,0xA5,0x94,0xC4,0x28,0x59,0x8C,0x92,0x2A,0x35,0x29,0xA5,0x94,0x47,0x39,0x79,0x52,0x93,
0x8C,0x3D,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x05,0x29,0x79,0xD2,0x92,0xAE,0x41,0x29,0xA5,0x94,0xE4,0x28,0x69,0xD0,0x92,0x4D,0x3D,
0x29,0xA5,0x94,0x28,0x45,0x89,0x92,0x93,0xED,0x49,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x0F,0x4A,0xF9,0x20,0x94,0x52,0x4A,0x29,0xA5,
0x94,0xAB,0x3D,0xB9,0xD6,0x93,0x52,0x4A,0x29,0xA5,0x94,0x31,0x4A,0x09,0x9F,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x8C,0x20,
0x34,0x64,0x15,0x00,0x00,0x04,0x00,0x00,0x18,0x67,0x8D,0x72,0x28,0x3A,0x89,0xCE,0x17,0x67,0x28,0x67,0x9A,0x82,0xA4,0x42,0x69,0x42,0xF7,0x26,0x39,0x4A,0x9E,0x93,
0xDC,0x4A,0xCB,0xCD,0xE9,0x26,0x9C,0x73,0xBA,0x39,0xE5,0x9C,0x4F,0xCE,0x39,0x27,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x40,0x08,0x21,0x85,0x14,0x52,0x48,0x21,
0x85,0x14,0x52,0x48,0x21,0x85,0x18,0x62,0x88,0x21,0x87,0x9C,0x72,0x0A,0x2A,0xA8,0xA0,0x92,0x4A,0x2A,0xAA,0xA8,0xA2,0xCA,0x2A,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,
0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCE,0x3A,0xEA,0xA8,0xB3,0x90,0x42,0x28,0x29,0xB4,0xD0,0x5A,0x8D,0xB1,0xC6,0x18,0x5B,0xED,0xCD,0x49,0x5B,0x73,0x94,0xD2,0x49,0x29,
0xA5,0x94,0x52,0x4A,0xE9,0x9C,0x73,0xCE,0x09,0x42,0x43,0x56,0x01,0x00,0x20,0x00,0x00,0x04,0x42,0x06,0x19,0x64,0x90,0x51,0x46,0x21,0x85,0x18,0x62,0xCA,0x29,0xA7,
0x9C,0x82,0x4A,0x2A,0xA9,0x80,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x51,0x32,0x1D,0xD3,0x11,0x1D,0x51,0x11,0x1D,0xD1,0x11,0x1D,0xD1,0x11,
0x1D,0xD1,0xF1,0x1C,0xCF,0xF1,0x24,0x51,0x12,0x2D,0xCF,0x12,0x35,0xD3,0x33,0x45,0xD3,0x34,0x5D,0x55,0x76,0x65,0x59,0x97,0x6D,0xD9,0x76,0x75,0x59,0xB7,0x75,0xD9,
0xB7,0x7D,0x5B,0xB7,0x6D,0xDB,0xD7,0x8D,0xDD,0xF8,0x8D,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x86,0x20,0x34,0x64,0x15,0x00,0x00,
0x02,0x00,0x00,0x20,0x84,0x10,0x42,0x48,0x21,0x85,0x14,0x52,0x48,0x29,0xA6,0x18,0x73,0x0E,0x3A,0x08,0x21,0x94,0x12,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x08,
0x00,0x00,0x00,0x50,0x14,0x47,0x71,0x1C,0xC9,0x91,0x24,0x49,0xB2,0x24,0xCB,0xD2,0x2C,0x4D,0xD3,0x34,0x4D,0xF3,0x44,0x4F,0xF4,0x4C,0x4F,0xF5,0x5C,0x51,0x16,0x6D,
0xD1,0xF6,0x5C,0xCF,0x16,0x6D,0xCF,0xF5,0x54,0x4F,0xF5,0x54,0x51,0x35,0x55,0xD3,0x35,0x5D,0xD5,0x75,0x5D,0xD7,0x55,0x5D,0x55,0x56,0x65,0xD7,0xB6,0x6D,0xDB,0xB6,
0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0x5B,0x06,0x42,0x43,0x56,0x01,0x00,0x12,0x00,0x00,0x3A,0x92,0x23,0x29,0x92,0x22,0x29,0x92,0xE3,0x38,0x92,0x23,
0x49,0x40,0x68,0xC8,0x2A,0x00,0x40,0x06,0x00,0x40,0x00,0x00,0x8A,0xA2,0x28,0x8E,0xE3,0x48,0x8E,0x25,0x59,0x92,0x26,0x89,0x92,0x69,0xA9,0x96,0xAB,0xC9,0x9E,0xEE,
0xE9,0xA2,0x2E,0xEA,0x40,0x68,0xC8,0x2A,0x00,0x00,0x10,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x68,0x88,0x86,0xE8,0x88,0x96,0xA8,0x89,0xA2,0x28,0x8A,0xA2,
0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,
0xA2,0x28,0x8A,0xA2,0xE8,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0x07,0x84,0x86,0xAC,0x02,0x00,0x24,0x00,0x00,0x74,0x24,0x47,0x72,0x2C,0xC5,0x52,0x24,0x45,0x52,
0x2C,0xC7,0x72,0x80,0xD0,0x90,0x55,0x00,0x80,0x0C,0x00,0x80,0x00,0x00,0x1C,0xC3,0x31,0x24,0x45,0x72,0x2C,0xCB,0xB2,0x34,0x4D,0xF3,0x3C,0xCF,0xF3,0x44,0x4F,0x14,
0x45,0x51,0x34,0x4D,0xD5,0x54,0x81,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x45,0xB1,0x1C,0xCB,0x91,0x24,0xCD,0xF1,0x24,0xD1,
0x11,0x25,0x51,0x12,0x2D,0x51,0x12,0x35,0x51,0x13,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,
0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x11,0x08,0x0D,0x59,0x09,0x00,0x00,0x01,0x00,0xF0,0x9C,0x7B,0xED,0xBD,0xF7,0xD0,0x51,
0x29,0x25,0xF7,0x8A,0x30,0xC4,0xA0,0xF7,0x94,0x51,0x28,0xAD,0xF7,0xD0,0x38,0x82,0x9C,0xF7,0x54,0x41,0x63,0x98,0xF7,0x14,0x41,0x42,0x90,0xF5,0x5C,0x51,0x84,0x94,
0x06,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x80,0x31,0xC8,0x31,0xC4,0x1C,0x72,0xCE,0x51,0xEA,0x24,0x45,0xCE,0x39,0x2A,0x1D,0xA5,0xC6,0x39,0x47,0xA9,0xA3,0xD4,
0x51,0x4A,0xB1,0xA6,0x18,0x3B,0x4A,0x25,0xB6,0x14,0x6B,0xE3,0x9C,0xA3,0xD4,0x51,0xCA,0x28,0xA5,0x1A,0x4B,0x8B,0x1D,0xA5,0x54,0x63,0x8A,0xB1,0x00,0x00,0x80,0x00,
0x07,0x00,0x80,0x00,0x0B,0xA1,0xD0,0x90,0x15,0x01,0x40,0x14,0x00,0x00,0x62,0x0C,0x52,0x0A,0x29,0x85,0x94,0x52,0xCE,0x29,0xE6,0x90,0x52,0xCA,0x31,0xE5,0x1C,0x52,
0x4A,0x39,0xA6,0x98,0x53,0xCE,0x39,0x08,0x1D,0x84,0xCA,0x39,0x06,0x9D,0x83,0x10,0x29,0xA5,0x9C,0x53,0xCC,0x29,0xE7,0x1C,0x84,0xCC,0x41,0xE5,0x9C,0x83,0xD0,0x41,
0x28,0x00,0x00,0x20,0xC0,0x01,0x00,0x20,0xC0,0x42,0x28,0x34,0x64,0x45,0x00,0x10,0x27,0x00,0xE0,0x70,0x1C,0xCF,0x93,0x34,0x4D,0x14,0x25,0x4D,0x13,0x45,0x4F,0x14,
0x5D,0xD7,0x13,0x4D,0xD5,0x95,0x34,0xCD,0x34,0x35,0x51,0x54,0x4D,0xCD,0x13,0x4D,0xD5,0x54,0x4D,0x5B,0x16,0x4D,0xD3,0x95,0x25,0x4D,0x33,0x4D,0x4D,0xF4,0x54,0x53,
0x13,0x45,0x55,0x15,0x4D,0x53,0x76,0x4D,0x53,0x95,0x65,0xCF,0x34,0x75,0xD9,0x54,0x55,0x5D,0x16,0x55,0xD5,0x96,0x65,0x5B,0x16,0x76,0x57,0x96,0x75,0xDD,0x33,0x4D,
0xD9,0x16,0x55,0x55,0xB6,0x4D,0xD5,0x95,0x7D,0x57,0x96,0x75,0x5D,0x96,0x6D,0x5D,0x98,0x34,0xCD,0x34,0x35,0x51,0x54,0x55,0x4D,0x14,0x55,0xD7,0x54,0x55,0xDB,0x36,
0x55,0xD7,0xB6,0x35,0x51,0x74,0x5D,0x51,0x55,0x65,0x57,0x54,0x55,0x59,0x76,0x65,0xD7,0xB6,0x55,0xD7,0xD5,0x6D,0x4D,0x14,0x5D,0x55,0x54,0x4D,0x59,0x15,0x55,0xD5,
0x95,0x55,0x57,0xB5,0x65,0xD5,0x75,0x75,0xDD,0x74,0x5D,0x5F,0x57,0x65,0xD9,0xF7,0x4D,0xD7,0xF5,0x7D,0xDB,0xB6,0x85,0x5F,0xB6,0x6D,0xE1,0x18,0x55,0xD5,0xD6,0x4D,
0x57,0xD5,0x75,0xD3,0x75,0x75,0x61,0xD6,0x65,0xE1,0x97,0x6D,0x5D,0x58,0x26,0x4D,0x33,0x4D,0x4D,0x14,0x5D,0x55,0x13,0x45,0x55,0x35,0x55,0x55,0xB7,0x4D,0xD5,0x95,
0x6D,0x4D,0x14,0x5D,0x57,0x54,0x55,0xD9,0xF5,0x4C,0xD5,0x75,0x55,0xD7,0xD5,0x75,0x55,0x75,0x6D,0x5B,0x13,0x45,0xD7,0x15,0x55,0x55,0x96,0x45,0x55,0x75,0x5D,0xD5,
0x75,0x7D,0x5D,0x75,0x65,0xDB,0x16,0x55,0xD5,0xD7,0x4D,0xD7,0xF5,0x75,0x53,0x75,0x6D,0x5B,0xB6,0x75,0x63,0x98,0x65,0xDB,0xF7,0x4D,0xD7,0xD5,0x75,0x53,0x76,0x75,
0x61,0x95,0x5D,0xDD,0x97,0x75,0x5B,0x38,0x6E,0xDD,0xD6,0x85,0xCF,0x34,0x75,0xDD,0x74,0x5D,0x61,0x37,0x5D,0x57,0xF8,0x6D,0x5F,0x17,0x86,0xD9,0xD6,0x7D,0x5F,0x54,
0x5D,0xDF,0x57,0x65,0xD9,0x17,0x56,0x59,0xF6,0x7D,0xDD,0xF7,0xB1,0x75,0x5D,0x19,0x46,0x55,0x15,0x7E,0x53,0x56,0x7D,0x5F,0x75,0x5D,0x5F,0xD8,0x7D,0x5D,0x59,0x6E,
0x5F,0x67,0xBC,0xB6,0x8E,0xAD,0xFB,0xC6,0x31,0xDB,0xBA,0x30,0xFC,0xC6,0x91,0xEE,0xFB,0xCA,0xB1,0xDA,0x32,0x63,0xF6,0x65,0x61,0x98,0x75,0x1B,0x61,0xD8,0x95,0xE3,
0xF6,0x7D,0xA5,0x67,0x9A,0xBA,0x6E,0xBA,0xAA,0xEF,0x9B,0xAA,0x2B,0xFC,0xB6,0xAE,0x0B,0xC7,0xAE,0xFB,0x88,0xAA,0xAA,0xEB,0xAA,0xEC,0xFA,0xC6,0xE9,0xCA,0xC2,0x30,
0xEB,0xBA,0xB0,0xEC,0xBA,0xAF,0x1C,0xA3,0xAB,0xF2,0x55,0xD9,0xF5,0x7D,0x55,0x96,0x7D,0xE1,0xF6,0x75,0x65,0xD9,0x75,0xDF,0x38,0x5E,0xDB,0x16,0x8E,0xD9,0xD6,0x8D,
0xB2,0xAD,0x1B,0xCB,0x2E,0xFC,0x94,0x5F,0x37,0x86,0xE5,0xB5,0x6D,0x65,0x99,0x75,0x9D,0x31,0x0B,0xBB,0x71,0xEC,0xBE,0x50,0x19,0x96,0xE3,0x28,0x00,0x00,0x60,0xC0,
0x01,0x00,0x20,0xC0,0x84,0x32,0x50,0x68,0xC8,0x8A,0x00,0x20,0x4E,0x00,0x80,0x41,0x08,0x42,0xC5,0x14,0x84,0x4A,0x31,0x08,0xA1,0x84,0x96,0x42,0x28,0xA9,0x55,0x8C,
0x49,0xC9,0x1C,0x93,0x92,0x31,0x27,0xA5,0x94,0xD2,0x5A,0x28,0x25,0xB5,0x8A,0x31,0x29,0x99,0x63,0x52,0x32,0xC6,0xA4,0x84,0x52,0x5A,0x2A,0xA5,0xB4,0x16,0x4A,0x89,
0xAD,0x94,0x12,0x63,0x29,0x25,0xB6,0xD6,0x5A,0xAD,0xAD,0xB5,0x5A,0x43,0x29,0x2D,0x86,0x52,0x62,0x2C,0xA5,0xC4,0xD8,0x5A,0xCB,0xB5,0xC5,0x56,0x6B,0xC4,0x98,0x94,
0xCC,0x31,0x29,0x19,0x73,0x52,0x4A,0x29,0xAD,0x95,0x52,0x5A,0xCB,0x9C,0x93,0xD2,0x39,0x27,0xA9,0x73,0x8E,0x4A,0x29,0x29,0xC5,0x52,0x52,0x8B,0x15,0x63,0x52,0x32,
0xC7,0xA8,0x74,0xCE,0x49,0x2A,0xA9,0xC4,0x54,0x4A,0x89,0xAD,0xA4,0x12,0x63,0x29,0xA5,0xC5,0x92,0x52,0x8C,0x2D,0xC5,0x54,0x5B,0x8C,0xB5,0x86,0x52,0x5A,0x2C,0xA5,
0xC4,0x56,0x4A,0x8A,0xB1,0xC5,0x54,0x5B,0x8C,0x31,0xD7,0x88,0x31,0x29,0x19,0x63,0x52,0x32,0xE6,0xA4,0x94,0x52,0x5A,0x2B,0xA5,0xB4,0x58,0x31,0x26,0xA5,0x73,0x8E,
0x4A,0xC6,0x9C,0xA4,0x52,0x4A,0x6B,0xA5,0xA4,0x14,0x33,0xE7,0xA4,0x64,0xCE,0x49,0xEA,0x9C,0xA3,0x52,0x52,0x89,0xAD,0xA4,0x12,0x53,0x28,0x25,0xC6,0x92,0x52,0x8C,
0xA5,0x94,0x16,0x63,0x8C,0xB5,0xB6,0x14,0x5B,0x2D,0x25,0xC5,0x58,0x52,0x8A,0xB1,0x94,0x12,0x5B,0x8B,0xB1,0xD6,0x16,0x53,0x6E,0xA1,0x94,0x18,0x4B,0x29,0x31,0x96,
0x52,0x62,0x8C,0x31,0xE6,0xDC,0x62,0xAC,0x35,0x94,0x12,0x63,0x29,0x29,0xC6,0x92,0x4A,0x6C,0xB1,0xC5,0x9A,0x63,0x8C,0xB9,0x86,0x52,0x62,0x2C,0xA5,0xC4,0x56,0x4A,
0x6A,0x31,0xC6,0x96,0x6B,0x8C,0xB1,0xD6,0x16,0x5B,0xAE,0x2D,0xB5,0x5A,0x5B,0x6C,0xB9,0xD6,0x96,0x5B,0xAF,0x35,0xF7,0xDE,0x5A,0xAB,0x39,0xB5,0x94,0x6B,0x8B,0xB1,
0xE6,0x5A,0x5B,0x8F,0xB5,0xE6,0xDE,0x43,0x29,0x31,0x96,0x52,0x62,0x2C,0xA5,0xC4,0xD8,0x62,0xAB,0x35,0xC6,0x98,0x73,0x28,0x25,0xC6,0x92,0x4A,0x6C,0xA5,0x94,0x16,
0x63,0x8C,0xB5,0xB6,0x16,0x6B,0x0E,0xA5,0xC4,0x58,0x4A,0x6A,0xB1,0xA4,0x12,0x63,0x8C,0xB1,0xE6,0x18,0x63,0xAE,0xAD,0xB5,0x5C,0x5B,0x6C,0xB9,0xA6,0xD4,0x6A,0xAE,
0xB5,0x06,0x5F,0x5B,0x8D,0xC1,0xB5,0x58,0x7B,0x8C,0x31,0xE6,0xD6,0x52,0xAD,0x35,0xD7,0xDE,0x6B,0x6D,0xBD,0x15,0x00,0x00,0x30,0xE0,0x00,0x00,0x10,0x60,0x42,0x19,
0x28,0x34,0x64,0x25,0x00,0x10,0x05,0x00,0x40,0x18,0xA3,0x14,0x63,0x10,0x1A,0x64,0x18,0x73,0x0C,0x42,0x63,0x0C,0x63,0xCC,0x41,0xA8,0x18,0x73,0xCE,0x41,0x29,0x15,
0x63,0xCE,0x41,0x27,0x25,0x73,0xCC,0x41,0x28,0x29,0x65,0xCC,0x41,0x28,0x25,0xA5,0x10,0x42,0x29,0x29,0xB5,0x16,0x42,0x28,0x25,0xA5,0xD6,0x0A,0x00,0x00,0x28,0x70,
0x00,0x00,0x08,0xB0,0x41,0x53,0x62,0x71,0x80,0x42,0x43,0x56,0x02,0x00,0xA9,0x00,0x00,0x06,0xC7,0xB1,0x2C,0xCF,0x13,0x4D,0x55,0xB5,0x6D,0xC7,0x92,0x3C,0x4F,0x14,
0x55,0x55,0x55,0x6D,0xDB,0x91,0x24,0xCF,0x13,0x45,0x53,0x55,0x5D,0xDB,0xD6,0x3C,0x4F,0x14,0x55,0x53,0x55,0x5D,0x57,0xD7,0x35,0xCF,0x13,0x45,0x55,0x55,0x55,0xD7,
0xD5,0x6D,0xD1,0x34,0x55,0x55,0x55,0x5D,0x57,0x76,0x7D,0x5F,0x34,0x4D,0x55,0x55,0x55,0xD7,0x95,0x65,0xDD,0x37,0x55,0x55,0x55,0x5D,0x57,0x96,0x65,0x59,0xF8,0x4D,
0x55,0x75,0x5D,0xD7,0x75,0x65,0xDB,0xF6,0x7D,0xD5,0x75,0x5D,0x57,0x96,0x6D,0xDB,0xB6,0x85,0x61,0x75,0x5D,0xD7,0x95,0x65,0xDB,0xD6,0x6D,0x63,0xD8,0x6D,0x5D,0xD7,
0x7D,0x5F,0x38,0x96,0x61,0xA9,0xEB,0xBA,0xAE,0xFB,0xC2,0xEF,0x1B,0x43,0x02,0x00,0xC0,0x13,0x1C,0x00,0x80,0x0A,0x6C,0x58,0x1D,0xE1,0xA4,0x68,0x2C,0xB0,0xD0,0x90,
0x95,0x00,0x40,0x06,0x00,0x00,0x61,0x0C,0x42,0x06,0x21,0x85,0x0C,0x42,0x08,0x21,0xA5,0x94,0x42,0x48,0x29,0x25,0x00,0x00,0x60,0xC0,0x01,0x00,0x20,0xC0,0x84,0x32,
0x50,0x68,0xC8,0x4A,0x00,0x20,0x0A,0x00,0x00,0x20,0x44,0x4A,0x29,0xA5,0x34,0x52,0x4A,0x29,0xA5,0x94,0x46,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x08,0x21,0x84,0x10,0x42,
0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x14,0x00,0x20,0x35,0xE1,
0x00,0x20,0xF5,0x60,0x83,0xA6,0xC4,0xE2,0x00,0x85,0x86,0xAC,0x04,0x00,0x52,0x01,0x00,0x00,0x63,0x94,0x62,0xCC,0x31,0x08,0xA5,0x34,0x4C,0x39,0xE7,0x9C,0x84,0x54,
0x5A,0x6B,0x14,0x73,0xCE,0x39,0x29,0x29,0xB5,0x96,0x39,0x27,0xA1,0x94,0x96,0x62,0x8B,0x31,0x73,0x0E,0x42,0x29,0x29,0xC5,0x58,0x73,0xE6,0xA0,0x94,0x96,0x6A,0x8C,
0xB5,0xE6,0xCC,0x41,0x29,0xA9,0xC5,0x98,0x6B,0xCD,0x9D,0x94,0x96,0x62,0xCC,0x39,0x07,0x9D,0x3B,0x29,0xA9,0xD5,0x58,0x73,0xD0,0x39,0x97,0x94,0x6A,0xAC,0x35,0xE7,
0x20,0x7C,0x30,0xA9,0xC5,0x58,0x6B,0xCD,0x3D,0xE7,0xA0,0x5A,0xAC,0xB1,0xF7,0x5E,0x83,0x0F,0x42,0xB5,0x98,0x73,0xCE,0x3D,0xE7,0x9C,0x83,0x01,0x00,0x38,0x0D,0x0E,
0x00,0xA0,0x07,0x36,0xAC,0x8E,0x70,0x52,0x34,0x16,0x58,0x68,0xC8,0x4A,0x00,0x20,0x15,0x00,0x80,0x40,0x48,0x29,0xC6,0x9C,0x73,0xCE,0x39,0xA4,0x14,0x63,0xCE,0x39,
0xE7,0x1C,0x84,0x48,0x29,0xC6,0x1C,0x73,0xCE,0x39,0xE7,0x14,0x63,0x8C,0x39,0xE7,0x1C,0x84,0x10,0x2A,0xC6,0x18,0x73,0xCE,0x39,0x08,0x21,0x64,0xCE,0x39,0xE7,0x9C,
0x83,0x10,0x42,0xC8,0x9C,0x73,0xCE,0x39,0x08,0x21,0x84,0xD0,0x39,0x07,0x1D,0x84,0x10,0x42,0x08,0xA1,0x73,0x0E,0x42,0x08,0x21,0x84,0x10,0x42,0x07,0x21,0x84,0x10,
0x42,0x08,0x21,0x84,0x0E,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x14,0x00,0x00,0x58,
0xE0,0x00,0x00,0x10,0x60,0xC3,0xEA,0x08,0x27,0x45,0x63,0x81,0x85,0x86,0xAC,0x04,0x00,0x80,0x00,0x00,0x38,0xCD,0x39,0xE8,0x16,0x63,0x62,0x98,0x63,0x8E,0x9A,0x43,
0x14,0x62,0xD0,0x73,0x85,0x94,0x52,0x8E,0x9B,0x66,0x94,0x41,0x4E,0x7C,0xA6,0x14,0x42,0x4A,0x53,0xE6,0x18,0x43,0x46,0x4A,0xCC,0x3D,0x99,0x4A,0x02,0x00,0x00,0x20,
0x08,0x00,0x10,0x10,0x12,0x00,0x60,0x80,0xA0,0x60,0x06,0x00,0x18,0x1C,0x20,0x7C,0x0E,0x82,0x4E,0x80,0xE0,0x68,0x03,0x00,0x10,0x84,0xC8,0x0C,0x91,0x68,0x58,0x08,
0x0E,0x0F,0x2A,0x01,0x22,0x62,0x2A,0x00,0x48,0x4C,0x50,0xC8,0x05,0x80,0x0A,0x8B,0x8B,0xB4,0x8B,0x0B,0xE8,0x32,0xC0,0x05,0x5D,0xDC,0x75,0x20,0x84,0x20,0x04,0x21,
0x88,0xC5,0x01,0x14,0x90,0x80,0x83,0x13,0x6E,0x78,0xE2,0x0D,0x4F,0xB8,0xC1,0x09,0x3A,0x45,0xA5,0x0E,0x02,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x1E,0x00,0x00,0x8E,
0x0B,0x20,0x22,0xA2,0x39,0x8C,0x0C,0x8D,0x0D,0x8E,0x0E,0x8F,0x0F,0x90,0x90,0x00,0x00,0x00,0x00,0x00,0x90,0x01,0x80,0x0F,0x00,0x80,0x43,0x04,0x88,0x88,0x68,0x0E,
0x23,0x43,0x63,0x83,0xA3,0xC3,0xE3,0x03,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,
0x08,
};
static const uint8_t vcb_6[] = {
0x22,0x42,0x43,0x56,0x01,0x00,0x40,0x00,0x00,0x24,0x73,0x5A,0x32,0x66,0xA9,0x73,0xD8,0x7B,0xEF,0x1D,0x42,0x92,0x19,0xE3,0x1C,0x42,0xD0,0x7B,0xEF,0x99,0x41,0x4C,
0x11,0xA2,0x1C,0x42,0xCC,0x6B,0xEC,0x21,0x63,0x92,0x19,0xC3,0xA0,0x42,0x8A,0x63,0xAA,0x81,0xD0,0x90,0x55,0x00,0x00,0x40,0x00,0x00,0x67,0xBD,0x97,0xDA,0x7B,0xCB,
0xBD,0xF7,0xDE,0x7B,0x46,0xB9,0x67,0xD4,0x7B,0x69,0xBD,0xF7,0xDE,0x7B,0xC8,0xBD,0x87,0xD6,0x7B,0xCA,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,
0xDE,0x7B,0x25,0xB1,0x67,0x92,0x7B,0x48,0xBD,0xF7,0xDE,0x7B,0xE3,0xB0,0x47,0x8E,0x7B,0x06,0xB9,0xF7,0xDE,0x7B,0x65,0xBD,0x57,0x92,0x7B,0x28,0xB5,0xF7,0xDE,0x7B,
0xED,0xBD,0xB7,0xDA,0x7B,0xEE,0xBD,0xF7,0xDE,0x7B,0x03,0xA9,0x47,0x10,0x7B,0x06,0xB9,0xF7,0xDE,0x7B,0xC1,0xA8,0x27,0x8A,0x7A,0xC4,0xAC,0xF7,0xDE,0x7B,0x03,0xB5,
0x37,0x0C,0x7B,0xE5,0xB0,0xF7,0xDE,0x7B,0xAA,0xBD,0x97,0x5E,0x7B,0xEA,0xBD,0xF7,0xDE,0x7B,0x86,0xBD,0x87,0x98,0x7B,0x8A,0xBD,0xF7,0xDE,0x7B,0x24,0xB5,0x57,0x92,
0x7B,0x28,0xBD,0xF7,0xDE,0x7B,0x86,0xBD,0x57,0xD2,0x7B,0x68,0xBD,0xF7,0xDE,0x7B,0xEA,0xBD,0x97,0xDE,0x7B,0xEC,0xBD,0xF7,0xDE,0x7B,0x20,0x34,0x64,0x15,0x00,0x90,
0x00,0x00,0xA0,0xA2,0x28,0x8A,0xA2,0x28,0x0A,0x10,0x1A,0xB2,0x0A,0x00,0xC8,0x00,0x00,0x10,0x40,0x51,0x1C,0xC5,0x71,0x1C,0xC9,0x91,0x1C,0xC9,0xB1,0x1C,0x0B,0x08,
0x0D,0x59,0x05,0x00,0x00,0x01,0x00,0x08,0x00,0x00,0xA0,0x48,0x8A,0xA4,0x58,0x8E,0xE5,0x58,0x8E,0x25,0x59,0x92,0x25,0x59,0x92,0x25,0x49,0x92,0xA5,0x79,0xA6,0xEB,
0xBA,0xAE,0xEB,0xBA,0xAE,0xEB,0xBA,0x2E,0x10,0x1A,0xB2,0x0A,0x00,0x48,0x00,0x00,0x50,0x51,0x14,0xC5,0x70,0x14,0x07,0x08,0x0D,0x59,0x05,0x00,0x64,0x00,0x00,0x08,
0xA0,0x48,0x8A,0xA5,0x68,0x8A,0xA7,0x88,0x8A,0xA9,0xA8,0x8E,0x0A,0x84,0x86,0xAC,0x02,0x00,0x80,0x00,0x00,0x04,0x00,0x00,0x10,0x5C,0x43,0x54,0x4C,0xC7,0x95,0x5C,
0xCB,0x35,0x5D,0xD5,0x75,0x5D,0xD7,0x75,0x5D,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x15,0x08,0x0D,0x59,0x05,0x00,0x40,0x00,0x00,0x10,0xD0,
0x69,0x86,0xA9,0x06,0x88,0x30,0x23,0x99,0x05,0x42,0x43,0x56,0x01,0x00,0x08,0x00,0x00,0x00,0x11,0xC8,0x30,0xC5,0x80,0xD0,0x90,0x55,0x00,0x00,0x40,0x00,0x00,0x80,
0x14,0x49,0x4E,0x92,0x28,0x39,0x29,0xA5,0x94,0xC3,0x20,0x59,0x4C,0x92,0x4A,0x39,0x29,0xA5,0x94,0x47,0x31,0x79,0x54,0x93,0x8C,0x41,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0xC2,0x20,0x59,0x8E,0x92,0x4A,0x39,0x29,0xA5,0x94,0xC4,0x28,0x59,0x8C,0x92,0x2A,0x35,0x29,0xA5,0x94,0x47,0x39,0x79,0x52,0x93,
0x8C,0x3D,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x05,0x29,0x79,0xD2,0x92,0xAE,0x41,0x29,0xA5,0x94,0xE4,0x28,0x69,0xD0,0x92,0x4D,0x3D,
0x29,0xA5,0x94,0x28,0x45,0x89,0x92,0x93,0xED,0x49,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x0F,0x4A,0xF9,0x20,0x94,0x52,0x4A,0x29,0xA5,
0x94,0xAB,0x3D,0xB9,0xD6,0x93,0x52,0x4A,0x29,0xA5,0x94,0x31,0x4A,0x09,0x9F,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x8C,0x20,
0x34,0x64,0x15,0x00,0x00,0x04,0x00,0x00,0x18,0x67,0x8D,0x72,0x28,0x3A,0x89,0xCE,0x17,0x67,0x28,0x67,0x9A,0x82,0xA4,0x42,0x69,0x42,0xF7,0x26,0x39,0x4A,0x9E,0x93,
0xDC,0x4A,0xCB,0xCD,0xE9,0x26,0x9C,0x73,0xBA,0x39,0xE5,0x9C,0x4F,0xCE,0x39,0x27,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x40,0x08,0x21,0x85,0x14,0x52,0x48,0x21,
0x85,0x14,0x52,0x48,0x21,0x85,0x18,0x62,0x88,0x21,0x87,0x9C,0x72,0x0A,0x2A,0xA8,0xA0,0x92,0x4A,0x2A,0xAA,0xA8,0xA2,0xCA,0x2A,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,
0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCE,0x3A,0xEA,0xA8,0xB3,0x90,0x42,0x28,0x29,0xB4,0xD0,0x5A,0x8D,0xB1,0xC6,0x18,0x5B,0xED,0xCD,0x49,0x5B,0x73,0x94,0xD2,0x49,0x29,
0xA5,0x94,0x52,0x4A,0xE9,0x9C,0x73,0xCE,0x09,0x42,0x43,0x56,0x01,0x00,0x20,0x00,0x00,0x04,0x42,0x06,0x19,0x64,0x90,0x51,0x46,0x21,0x85,0x18,0x62,0xCA,0x29,0xA7,
0x9C,0x82,0x4A,0x2A,0xA9,0x80,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x51,0x32,0x1D,0xD3,0x11,0x1D,0x51,0x11,0x1D,0xD1,0x11,0x1D,0xD1,0x11,
0x1D,0xD1,0xF1,0x1C,0xCF,0xF1,0x24,0x51,0x12,0x2D,0xCF,0x12,0x35,0xD3,0x33,0x45,0xD3,0x34,0x5D,0x55,0x76,0x65,0x59,0x97,0x6D,0xD9,0x76,0x75,0x59,0xB7,0x75,0xD9,
0xB7,0x7D,0x5B,0xB7,0x6D,0xDB,0xD7,0x8D,0xDD,0xF8,0x8D,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x86,0x20,0x34,0x64,0x15,0x00,0x00,
0x02,0x00,0x00,0x20,0x84,0x10,0x42,0x48,0x21,0x85,0x14,0x52,0x48,0x29,0xA6,0x18,0x73,0x0E,0x3A,0x08,0x21,0x94,0x12,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x08,
0x00,0x00,0x00,0x50,0x14,0x47,0x71,0x1C,0xC9,0x91,0x24,0x49,0xB2,0x24,0xCB,0xD2,0x2C,0x4D,0xD3,0x34,0x4D,0xF3,0x44,0x4F,0xF4,0x4C,0x4F,0xF5,0x5C,0x51,0x16,0x6D,
0xD1,0xF6,0x5C,0xCF,0x16,0x6D,0xCF,0xF5,0x54,0x4F,0xF5,0x54,0x51,0x35,0x55,0xD3,0x35,0x5D,0xD5,0x75,0x5D,0xD7,0x55,0x5D,0x55,0x56,0x65,0xD7,0xB6,0x6D,0xDB,0xB6,
0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0x5B,0x06,0x42,0x43,0x56,0x01,0x00,0x12,0x00,0x00,0x3A,0x92,0x23,0x29,0x92,0x22,0x29,0x92,0xE3,0x38,0x92,0x23,
0x49,0x40,0x68,0xC8,0x2A,0x00,0x40,0x06,0x00,0x40,0x00,0x00,0x8A,0xA2,0x28,0x8E,0xE3,0x48,0x8E,0x25,0x59,0x92,0x26,0x89,0x92,0x69,0xA9,0x96,0xAB,0xC9,0x9E,0xEE,
0xE9,0xA2,0x2E,0xEA,0x40,0x68,0xC8,0x2A,0x00,0x00,0x10,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x68,0x88,0x86,0xE8,0x88,0x96,0xA8,0x89,0xA2,0x28,0x8A,0xA2,
0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,
0xA2,0x28,0x8A,0xA2,0xE8,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0x07,0x84,0x86,0xAC,0x02,0x00,0x24,0x00,0x00,0x74,0x24,0x47,0x72,0x2C,0xC5,0x52,0x24,0x45,0x52,
0x2C,0xC7,0x72,0x80,0xD0,0x90,0x55,0x00,0x80,0x0C,0x00,0x80,0x00,0x00,0x1C,0xC3,0x31,0x24,0x45,0x72,0x2C,0xCB,0xB2,0x34,0x4D,0xF3,0x3C,0xCF,0xF3,0x44,0x4F,0x14,
0x45,0x51,0x34,0x4D,0xD5,0x54,0x81,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x45,0xB1,0x1C,0xCB,0x91,0x24,0xCD,0xF1,0x24,0xD1,
0x11,0x25,0x51,0x12,0x2D,0x51,0x12,0x35,0x51,0x13,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,
0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x11,0x08,0x0D,0x59,0x09,0x00,0x00,0x01,0x00,0xF0,0x9C,0x7B,0xED,0xBD,0xF7,0xD0,0x51,
0x29,0x25,0xF7,0x8A,0x30,0xC4,0xA0,0xF7,0x94,0x51,0x28,0xAD,0xF7,0xD0,0x38,0x82,0x9C,0xF7,0x54,0x41,0x63,0x98,0xF7,0x14,0x41,0x42,0x90,0xF5,0x5C,0x51,0x84,0x94,
0x06,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x80,0x31,0xC8,0x31,0xC4,0x1C,0x72,0xCE,0x51,0xEA,0x24,0x45,0xCE,0x39,0x2A,0x1D,0xA5,0xC6,0x39,0x47,0xA9,0xA3,0xD4,
0x51,0x4A,0xB1,0xA6,0x18,0x3B,0x4A,0x25,0xB6,0x14,0x6B,0xE3,0x9C,0xA3,0xD4,0x51,0xCA,0x28,0xA5,0x1A,0x4B,0x8B,0x1D,0xA5,0x54,0x63,0x8A,0xB1,0x00,0x00,0x80,0x00,
0x07,0x00,0x80,0x00,0x0B,0xA1,0xD0,0x90,0x15,0x01,0x40,0x14,0x00,0x00,0x62,0x0C,0x52,0x0A,0x29,0x85,0x94,0x52,0xCE,0x29,0xE6,0x90,0x52,0xCA,0x31,0xE5,0x1C,0x52,
0x4A,0x39,0xA6,0x98,0x53,0xCE,0x39,0x08,0x1D,0x84,0xCA,0x39,0x06,0x9D,0x83,0x10,0x29,0xA5,0x9C,0x53,0xCC,0x29,0xE7,0x1C,0x84,0xCC,0x41,0xE5,0x9C,0x83,0xD0,0x41,
0x28,0x00,0x00,0x20,0xC0,0x01,0x00,0x20,0xC0,0x42,0x28,0x34,0x64,0x45,0x00,0x10,0x27,0x00,0xE0,0x70,0x1C,0xCF,0x93,0x34,0x4D,0x14,0x25,0x4D,0x13,0x45,0x4F,0x14,
0x5D,0xD7,0x13,0x4D,0xD5,0x95,0x34,0xCD,0x34,0x35,0x51,0x54,0x4D,0xCD,0x13,0x4D,0xD5,0x54,0x4D,0x5B,0x16,0x4D,0xD3,0x95,0x25,0x4D,0x33,0x4D,0x4D,0xF4,0x54,0x53,
0x13,0x45,0x55,0x15,0x4D,0x53,0x76,0x4D,0x53,0x95,0x65,0xCF,0x34,0x75,0xD9,0x54,0x55,0x5D,0x16,0x55,0xD5,0x96,0x65,0x5B,0x16,0x76,0x57,0x96,0x75,0xDD,0x33,0x4D,
0xD9,0x16,0x55,0x55,0xB6,0x4D,0xD5,0x95,0x7D,0x57,0x96,0x75,0x5D,0x96,0x6D,0x5D,0x98,0x34,0xCD,0x34,0x35,0x51,0x54,0x55,0x4D,0x14,0x55,0xD7,0x54,0x55,0xDB,0x36,
0x55,0xD7,0xB6,0x35,0x51,0x74,0x5D,0x51,0x55,0x65,0x57,0x54,0x55,0x59,0x76,0x65,0xD7,0xB6,0x55,0xD7,0xD5,0x6D,0x4D,0x14,0x5D,0x55,0x54,0x4D,0x59,0x15,0x55,0xD5,
0x95,0x55,0x57,0xB5,0x65,0xD5,0x75,0x75,0xDD,0x74,0x5D,0x5F,0x57,0x65,0xD9,0xF7,0x4D,0xD7,0xF5,0x7D,0xDB,0xB6,0x85,0x5F,0xB6,0x6D,0xE1,0x18,0x55,0xD5,0xD6,0x4D,
0x57,0xD5,0x75,0xD3,0x75,0x75,0x61,0xD6,0x65,0xE1,0x97,0x6D,0x5D,0x58,0x26,0x4D,0x33,0x4D,0x4D,0x14,0x5D,0x55,0x13,0x45,0x55,0x35,0x55,0x55,0xB7,0x4D,0xD5,0x95,
0x6D,0x4D,0x14,0x5D,0x57,0x54,0x55,0xD9,0xF5,0x4C,0xD5,0x75,0x55,0xD7,0xD5,0x75,0x55,0x75,0x6D,0x5B,0x13,0x45,0xD7,0x15,0x55,0x55,0x96,0x45,0x55,0x75,0x5D,0xD5,
0x75,0x7D,0x5D,0x75,0x65,0xDB,0x16,0x55,0xD5,0xD7,0x4D,0xD7,0xF5,0x75,0x53,0x75,0x6D,0x5B,0xB6,0x75,0x63,0x98,0x65,0xDB,0xF7,0x4D,0xD7,0xD5,0x75,0x53,0x76,0x75,
0x61,0x95,0x5D,0xDD,0x97,0x75,0x5B,0x38,0x6E,0xDD,0xD6,0x85,0xCF,0x34,0x75,0xDD,0x74,0x5D,0x61,0x37,0x5D,0x57,0xF8,0x6D,0x5F,0x17,0x86,0xD9,0xD6,0x7D,0x5F,0x54,
0x5D,0xDF,0x57,0x65,0xD9,0x17,0x56,0x59,0xF6,0x7D,0xDD,0xF7,0xB1,0x75,0x5D,0x19,0x46,0x55,0x15,0x7E,0x53,0x56,0x7D,0x5F,0x75,0x5D,0x5F,0xD8,0x7D,0x5D,0x59,0x6E,
0x5F,0x67,0xBC,0xB6,0x8E,0xAD,0xFB,0xC6,0x31,0xDB,0xBA,0x30,0xFC,0xC6,0x91,0xEE,0xFB,0xCA,0xB1,0xDA,0x32,0x63,0xF6,0x65,0x61,0x98,0x75,0x1B,0x61,0xD8,0x95,0xE3,
0xF6,0x7D,0xA5,0x67,0x9A,0xBA,0x6E,0xBA,0xAA,0xEF,0x9B,0xAA,0x2B,0xFC,0xB6,0xAE,0x0B,0xC7,0xAE,0xFB,0x88,0xAA,0xAA,0xEB,0xAA,0xEC,0xFA,0xC6,0xE9,0xCA,0xC2,0x30,
0xEB,0xBA,0xB0,0xEC,0xBA,0xAF,0x1C,0xA3,0xAB,0xF2,0x55,0xD9,0xF5,0x7D,0x55,0x96,0x7D,0xE1,0xF6,0x75,0x65,0xD9,0x75,0xDF,0x38,0x5E,0xDB,0x16,0x8E,0xD9,0xD6,0x8D,
0xB2,0xAD,0x1B,0xCB,0x2E,0xFC,0x94,0x5F,0x37,0x86,0xE5,0xB5,0x6D,0x65,0x99,0x75,0x9D,0x31,0x0B,0xBB,0x71,0xEC,0xBE,0x50,0x19,0x96,0xE3,0x28,0x00,0x00,0x60,0xC0,
0x01,0x00,0x20,0xC0,0x84,0x32,0x50,0x68,0xC8,0x8A,0x00,0x20,0x4E,0x00,0x80,0x41,0x08,0x42,0xC5,0x14,0x84,0x4A,0x31,0x08,0xA1,0x84,0x96,0x42,0x28,0xA9,0x55,0x8C,
0x49,0xC9,0x1C,0x93,0x92,0x31,0x27,0xA5,0x94,0xD2,0x5A,0x28,0x25,0xB5,0x8A,0x31,0x29,0x99,0x63,0x52,0x32,0xC6,0xA4,0x84,0x52,0x5A,0x2A,0xA5,0xB4,0x16,0x4A,0x89,
0xAD,0x94,0x12,0x63,0x29,0x25,0xB6,0xD6,0x5A,0xAD,0xAD,0xB5,0x5A,0x43,0x29,0x2D,0x86,0x52,0x62,0x2C,0xA5,0xC4,0xD8,0x5A,0xCB,0xB5,0xC5,0x56,0x6B,0xC4,0x98,0x94,
0xCC,0x31,0x29,0x19,0x73,0x52,0x4A,0x29,0xAD,0x95,0x52,0x5A,0xCB,0x9C,0x93,0xD2,0x39,0x27,0xA9,0x73,0x8E,0x4A,0x29,0x29,0xC5,0x52,0x52,0x8B,0x15,0x63,0x52,0x32,
0xC7,0xA8,0x74,0xCE,0x49,0x2A,0xA9,0xC4,0x54,0x4A,0x89,0xAD,0xA4,0x12,0x63,0x29,0xA5,0xC5,0x92,0x52,0x8C,0x2D,0xC5,0x54,0x5B,0x8C,0xB5,0x86,0x52,0x5A,0x2C,0xA5,
0xC4,0x56,0x4A,0x8A,0xB1,0xC5,0x54,0x5B,0x8C,0x31,0xD7,0x88,0x31,0x29,0x19,0x63,0x52,0x32,0xE6,0xA4,0x94,0x52,0x5A,0x2B,0xA5,0xB4,0x58,0x31,0x26,0xA5,0x73,0x8E,
0x4A,0xC6,0x9C,0xA4,0x52,0x4A,0x6B,0xA5,0xA4,0x14,0x33,0xE7,0xA4,0x64,0xCE,0x49,0xEA,0x9C,0xA3,0x52,0x52,0x89,0xAD,0xA4,0x12,0x53,0x28,0x25,0xC6,0x92,0x52,0x8C,
0xA5,0x94,0x16,0x63,0x8C,0xB5,0xB6,0x14,0x5B,0x2D,0x25,0xC5,0x58,0x52,0x8A,0xB1,0x94,0x12,0x5B,0x8B,0xB1,0xD6,0x16,0x53,0x6E,0xA1,0x94,0x18,0x4B,0x29,0x31,0x96,
0x52,0x62,0x8C,0x31,0xE6,0xDC,0x62,0xAC,0x35,0x94,0x12,0x63,0x29,0x29,0xC6,0x92,0x4A,0x6C,0xB1,0xC5,0x9A,0x63,0x8C,0xB9,0x86,0x52,0x62,0x2C,0xA5,0xC4,0x56,0x4A,
0x6A,0x31,0xC6,0x96,0x6B,0x8C,0xB1,0xD6,0x16,0x5B,0xAE,0x2D,0xB5,0x5A,0x5B,0x6C,0xB9,0xD6,0x96,0x5B,0xAF,0x35,0xF7,0xDE,0x5A,0xAB,0x39,0xB5,0x94,0x6B,0x8B,0xB1,
0xE6,0x5A,0x5B,0x8F,0xB5,0xE6,0xDE,0x43,0x29,0x31,0x96,0x52,0x62,0x2C,0xA5,0xC4,0xD8,0x62,0xAB,0x35,0xC6,0x98,0x73,0x28,0x25,0xC6,0x92,0x4A,0x6C,0xA5,0x94,0x16,
0x63,0x8C,0xB5,0xB6,0x16,0x6B,0x0E,0xA5,0xC4,0x58,0x4A,0x6A,0xB1,0xA4,0x12,0x63,0x8C,0xB1,0xE6,0x18,0x63,0xAE,0xAD,0xB5,0x5C,0x5B,0x6C,0xB9,0xA6,0xD4,0x6A,0xAE,
0xB5,0x06,0x5F,0x5B,0x8D,0xC1,0xB5,0x58,0x7B,0x8C,0x31,0xE6,0xD6,0x52,0xAD,0x35,0xD7,0xDE,0x6B,0x6D,0xBD,0x15,0x00,0x00,0x30,0xE0,0x00,0x00,0x10,0x60,0x42,0x19,
0x28,0x34,0x64,0x25,0x00,0x10,0x05,0x00,0x40,0x18,0xA3,0x14,0x63,0x10,0x1A,0x64,0x18,0x73,0x0C,0x42,0x63,0x0C,0x63,0xCC,0x41,0xA8,0x18,0x73,0xCE,0x41,0x29,0x15,
0x63,0xCE,0x41,0x27,0x25,0x73,0xCC,0x41,0x28,0x29,0x65,0xCC,0x41,0x28,0x25,0xA5,0x10,0x42,0x29,0x29,0xB5,0x16,0x42,0x28,0x25,0xA5,0xD6,0x0A,0x00,0x00,0x28,0x70,
0x00,0x00,0x08,0xB0,0x41,0x53,0x62,0x71,0x80,0x42,0x43,0x56,0x02,0x00,0xA9,0x00,0x00,0x06,0xC7,0xB1,0x2C,0xCF,0x13,0x4D,0x55,0xB5,0x6D,0xC7,0x92,0x3C,0x4F,0x14,
0x55,0x55,0x55,0x6D,0xDB,0x91,0x24,0xCF,0x13,0x45,0x53,0x55,0x5D,0xDB,0xD6,0x3C,0x4F,0x14,0x55,0x53,0x55,0x5D,0x57,0xD7,0x35,0xCF,0x13,0x45,0x55,0x55,0x55,0xD7,
0xD5,0x6D,0xD1,0x34,0x55,0x55,0x55,0x5D,0x57,0x76,0x7D,0x5F,0x34,0x4D,0x55,0x55,0x55,0xD7,0x95,0x65,0xDD,0x37,0x55,0x55,0x55,0x5D,0x57,0x96,0x65,0x59,0xF8,0x4D,
0x55,0x75,0x5D,0xD7,0x75,0x65,0xDB,0xF6,0x7D,0xD5,0x75,0x5D,0x57,0x96,0x6D,0xDB,0xB6,0x85,0x61,0x75,0x5D,0xD7,0x95,0x65,0xDB,0xD6,0x6D,0x63,0xD8,0x6D,0x5D,0xD7,
0x7D,0x5F,0x38,0x96,0x61,0xA9,0xEB,0xBA,0xAE,0xFB,0xC2,0xEF,0x1B,0x43,0x02,0x00,0xC0,0x13,0x1C,0x00,0x80,0x0A,0x6C,0x58,0x1D,0xE1,0xA4,0x68,0x2C,0xB0,0xD0,0x90,
0x95,0x00,0x40,0x06,0x00,0x00,0x61,0x0C,0x42,0x06,0x21,0x85,0x0C,0x42,0x08,0x21,0xA5,0x94,0x42,0x48,0x29,0x25,0x00,0x00,0x60,0xC0,0x01,0x00,0x20,0xC0,0x84,0x32,
0x50,0x68,0xC8,0x4A,0x00,0x20,0x0A,0x00,0x00,0x20,0x44,0x4A,0x29,0xA5,0x34,0x52,0x4A,0x29,0xA5,0x94,0x46,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x08,0x21,0x84,0x10,0x42,
0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x14,0x00,0x20,0x35,0xE1,
0x00,0x20,0xF5,0x60,0x83,0xA6,0xC4,0xE2,0x00,0x85,0x86,0xAC,0x04,0x00,0x52,0x01,0x00,0x00,0x63,0x94,0x62,0xCC,0x31,0x08,0xA5,0x34,0x4C,0x39,0xE7,0x9C,0x84,0x54,
0x5A,0x6B,0x14,0x73,0xCE,0x39,0x29,0x29,0xB5,0x96,0x39,0x27,0xA1,0x94,0x96,0x62,0x8B,0x31,0x73,0x0E,0x42,0x29,0x29,0xC5,0x58,0x73,0xE6,0xA0,0x94,0x96,0x6A,0x8C,
0xB5,0xE6,0xCC,0x41,0x29,0xA9,0xC5,0x98,0x6B,0xCD,0x9D,0x94,0x96,0x62,0xCC,0x39,0x07,0x9D,0x3B,0x29,0xA9,0xD5,0x58,0x73,0xD0,0x39,0x97,0x94,0x6A,0xAC,0x35,0xE7,
0x20,0x7C,0x30,0xA9,0xC5,0x58,0x6B,0xCD,0x3D,0xE7,0xA0,0x5A,0xAC,0xB1,0xF7,0x5E,0x83,0x0F,0x42,0xB5,0x98,0x73,0xCE,0x3D,0xE7,0x9C,0x83,0x01,0x00,0x38,0x0D,0x0E,
0x00,0xA0,0x07,0x36,0xAC,0x8E,0x70,0x52,0x34,0x16,0x58,0x68,0xC8,0x4A,0x00,0x20,0x15,0x00,0x80,0x40,0x48,0x29,0xC6,0x9C,0x73,0xCE,0x39,0xA4,0x14,0x63,0xCE,0x39,
0xE7,0x1C,0x84,0x48,0x29,0xC6,0x1C,0x73,0xCE,0x39,0xE7,0x14,0x63,0x8C,0x39,0xE7,0x1C,0x84,0x10,0x2A,0xC6,0x18,0x73,0xCE,0x39,0x08,0x21,0x64,0xCE,0x39,0xE7,0x9C,
0x83,0x10,0x42,0xC8,0x9C,0x73,0xCE,0x39,0x08,0x21,0x84,0xD0,0x39,0x07,0x1D,0x84,0x10,0x42,0x08,0xA1,0x73,0x0E,0x42,0x08,0x21,0x84,0x10,0x42,0x07,0x21,0x84,0x10,
0x42,0x08,0x21,0x84,0x0E,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x14,0x00,0x00,0x58,
0xE0,0x00,0x00,0x10,0x60,0xC3,0xEA,0x08,0x27,0x45,0x63,0x81,0x85,0x86,0xAC,0x04,0x00,0x80,0x00,0x00,0x38,0xCD,0x39,0xE8,0x16,0x63,0x62,0x98,0x63,0x8E,0x9A,0x43,
0x14,0x62,0xD0,0x73,0x85,0x94,0x52,0x8E,0x9B,0x66,0x94,0x41,0x4E,0x7C,0xA6,0x14,0x42,0x4A,0x53,0xE6,0x18,0x43,0x46,0x4A,0xCC,0x3D,0x99,0x4A,0x02,0x00,0x00,0x20,
0x08,0x00,0x10,0x10,0x12,0x00,0x60,0x80,0xA0,0x60,0x06,0x00,0x18,0x1C,0x20,0x7C,0x0E,0x82,0x4E,0x80,0xE0,0x68,0x03,0x00,0x10,0x84,0xC8,0x0C,0x91,0x68,0x58,0x08,
0x0E,0x0F,0x2A,0x01,0x22,0x62,0x2A,0x00,0x48,0x4C,0x50,0xC8,0x05,0x80,0x0A,0x8B,0x8B,0xB4,0x8B,0x0B,0xE8,0x32,0xC0,0x05,0x5D,0xDC,0x75,0x20,0x84,0x20,0x04,0x21,
0x88,0xC5,0x01,0x14,0x90,0x80,0x83,0x13,0x6E,0x78,0xE2,0x0D,0x4F,0xB8,0xC1,0x09,0x3A,0x45,0xA5,0x0E,0x02,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x1E,0x00,0x00,0x8E,
0x0B,0x20,0x22,0xA2,0x39,0x8C,0x0C,0x8D,0x0D,0x8E,0x0E,0x8F,0x0F,0x90,0x90,0x00,0x00,0x00,0x00,0x00,0x70,0x01,0x80,0x0F,0x00,0x80,0x43,0x04,0x88,0x88,0x68,0x0E,
0x23,0x43,0x63,0x83,0xA3,0xC3,0xE3,0x03,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,
0x08,
};
static const uint8_t vcb_7[] = {
0x1F,0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x9C,0x73,0x9A,0x31,0x87,0x99,0x62,0x94,0x52,0x89,0x21,0x94,0xDE,0x39,0x68,0x19,0x63,0x94,0x52,0x69,0x29,0xA5,0x5A,
0x4A,0xA9,0xA1,0x83,0x16,0x6B,0xAB,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0x1D,0x73,0x94,0x31,0x46,0x95,0x52,0x52,0x4A,0xA9,0x9D,0x73,0x96,0x31,0x47,
0x15,0x63,0x52,0x4A,0x89,0xA5,0x94,0x56,0x42,0x68,0x21,0x84,0xD6,0x62,0xAB,0xBD,0xF7,0xDE,0x6B,0xEF,0xB5,0xF6,0xDE,0x7B,0xEF,0x99,0x42,0x4C,0x29,0xA4,0x14,0x42,
0x08,0x4A,0x28,0x1D,0x53,0x8C,0x29,0xA4,0x94,0x42,0x4A,0x4A,0x08,0x25,0x64,0x0E,0x3A,0xC6,0x1C,0x53,0x8C,0x52,0x09,0x3D,0xD6,0x5E,0x6B,0xCC,0xBD,0xB6,0xD8,0x7B,
0xED,0xA1,0x63,0xCE,0x39,0xE6,0x1C,0x53,0x4C,0x4A,0x68,0x21,0x74,0x0E,0x3A,0xE6,0x9C,0x53,0x4C,0x4A,0x68,0xA9,0x84,0x52,0x42,0x06,0xA1,0x53,0xD0,0x52,0x89,0xAD,
0xF7,0xDE,0x62,0xEB,0xB9,0xA5,0xDA,0x7B,0xEF,0x81,0xD0,0x90,0x55,0x00,0x00,0x01,0x00,0xC0,0x40,0x10,0x1A,0xB2,0x0A,0x00,0x50,0x00,0x00,0x10,0x8A,0xA1,0x18,0x8A,
0x02,0x84,0x86,0xAC,0x02,0x00,0x32,0x00,0x00,0x04,0xE0,0x28,0x8E,0xE3,0x38,0x8E,0xE2,0x38,0x92,0x62,0x39,0x16,0x10,0x1A,0xB2,0x0A,0x00,0x00,0x02,0x00,0x10,0x00,
0x00,0xC0,0x90,0x0C,0x4B,0xB1,0x14,0xCD,0xD1,0x24,0x4D,0xD2,0x2C,0xCF,0x13,0x4D,0xD3,0x37,0x7D,0xD3,0x36,0x6D,0x55,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x20,
0x34,0x64,0x15,0x00,0x00,0x01,0x00,0x40,0x40,0xA7,0x19,0xA6,0x1A,0x20,0xC2,0x8C,0x64,0x16,0x08,0x0D,0x59,0x05,0x00,0x20,0x00,0x00,0x00,0x44,0x20,0xC3,0x14,0x03,
0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x00,0x52,0x24,0x39,0x49,0xA2,0xE4,0xA4,0x94,0x52,0x0E,0x83,0x64,0x31,0x49,0x2A,0xE5,0xA4,0x94,0x52,0x1E,0xC5,0xE4,0x51,
0x4D,0x32,0x06,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x0A,0x83,0x64,0x39,0x4A,0x2A,0xE5,0xA4,0x94,0x52,0x12,0xA3,0x64,0x31,0x4A,0xAA,
0xD4,0xA4,0x94,0x52,0x1E,0xE5,0xE4,0x49,0x4D,0x32,0xF6,0xA4,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x16,0xA4,0xE4,0x49,0x4B,0xBA,0x06,0xA5,
0x94,0x52,0x92,0xA3,0xA4,0x41,0x4B,0x36,0xF5,0xA4,0x94,0x52,0xA2,0x14,0x25,0x4A,0x4E,0xB6,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x3E,0x28,0xE5,0x83,0x50,0x4A,0x29,0xA5,0x94,0x52,0xAE,0xF6,0xE4,0x5A,0x4F,0x4A,0x29,0xA5,0x94,0x52,0xC6,0x28,0x25,0x7C,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x32,0x82,0xD0,0x90,0x55,0x00,0x00,0x10,0x00,0x00,0x60,0x9C,0x35,0xCA,0xA1,0xE8,0x24,0x3A,0x5F,0x9C,0xA1,0x9C,0x69,0x0A,0x92,
0x0A,0xA5,0x09,0xDD,0x9B,0xE4,0x28,0x79,0x4E,0x72,0x2B,0x2D,0x37,0xA7,0x9B,0x70,0xCE,0xE9,0xE6,0x94,0x73,0x3E,0x39,0xE7,0x9C,0x20,0x34,0x64,0x15,0x00,0x00,0x08,
0x00,0x00,0x21,0x84,0x14,0x52,0x48,0x21,0x85,0x14,0x52,0x48,0x21,0x85,0x14,0x62,0x88,0x21,0x86,0x1C,0x72,0xCA,0x29,0xA8,0xA0,0x82,0x4A,0x2A,0xA9,0xA8,0xA2,0x8A,
0x2A,0xAB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x3A,0xEB,0xA8,0xA3,0xCE,0x42,0x0A,0xA1,0xA4,0xD0,0x42,0x6B,0x35,0xC6,0x1A,0x63,0x6C,
0xB5,0x37,0x27,0x6D,0xCD,0x51,0x4A,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x73,0xCE,0x39,0x27,0x08,0x0D,0x59,0x05,0x00,0x80,0x00,0x00,0x10,0x08,0x19,0x64,0x90,0x41,
0x46,0x19,0x85,0x14,0x62,0x88,0x29,0xA7,0x9C,0x72,0x0A,0x2A,0xA9,0xA4,0x02,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x44,0xC9,0x74,0x4C,0x47,
0x74,0x44,0x45,0x74,0x44,0x47,0x74,0x44,0x47,0x74,0x44,0xC7,0x73,0x3C,0xC7,0x93,0x44,0x49,0xB4,0x3C,0x4B,0xD4,0x4C,0xCF,0x14,0x4D,0xD3,0x74,0x55,0xD9,0x95,0x65,
0x5D,0xB6,0x65,0xDB,0xD5,0x65,0xDD,0xD6,0x65,0xDF,0xF6,0x6D,0xDD,0xB6,0x6D,0x5F,0x37,0x76,0xE3,0x37,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,
0x8E,0xE3,0x18,0x82,0xD0,0x90,0x55,0x00,0x00,0x08,0x00,0x00,0x80,0x10,0x42,0x08,0x21,0x85,0x14,0x52,0x48,0x21,0xA5,0x98,0x62,0xCC,0x39,0xE8,0x20,0x84,0x50,0x4A,
0x20,0x34,0x64,0x15,0x00,0x00,0x08,0x00,0x20,0x00,0x00,0x00,0x40,0x51,0x1C,0xC5,0x71,0x24,0x47,0x92,0x24,0xC9,0x92,0x2C,0x4B,0xB3,0x34,0x4D,0xD3,0x34,0xCD,0x13,
0x3D,0xD1,0x33,0x3D,0xD5,0x73,0x45,0x59,0xB4,0x45,0xDB,0x73,0x3D,0x5B,0xB4,0x3D,0xD7,0x53,0x3D,0xD5,0x53,0x45,0xD5,0x54,0x4D,0xD7,0x74,0x55,0xD7,0x75,0x5D,0x57,
0x75,0x55,0x59,0x95,0x5D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0x19,0x08,0x0D,0x59,0x05,0x00,0x48,0x00,0x00,0xE8,0x48,0x8E,
0xA4,0x48,0x8A,0xA4,0x48,0x8E,0xE3,0x48,0x8E,0x24,0x01,0xA1,0x21,0xAB,0x00,0x00,0x19,0x00,0x00,0x01,0x00,0x28,0x8A,0xA2,0x38,0x8E,0x23,0x39,0x96,0x64,0x49,0x9A,
0x24,0x4A,0xA6,0xA5,0x5A,0xAE,0x26,0x7B,0xBA,0xA7,0x8B,0xBA,0xA8,0x03,0xA1,0x21,0xAB,0x00,0x00,0x40,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x18,0xA2,0x21,0x1A,
0xA2,0x23,0x5A,0xA2,0x26,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,
0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x1E,0x10,0x1A,0xB2,0x0A,0x00,0x90,0x00,0x00,0xD0,
0x91,0x1C,0xC9,0xB1,0x14,0x4B,0x91,0x14,0x49,0xB1,0x1C,0xCB,0x01,0x42,0x43,0x56,0x01,0x00,0x32,0x00,0x00,0x02,0x00,0x70,0x0C,0xC7,0x90,0x14,0xC9,0xB1,0x2C,0xCB,
0xD2,0x34,0xCD,0xF3,0x3C,0xCF,0x13,0x3D,0x51,0x14,0x45,0xD1,0x34,0x55,0x53,0x05,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x50,0x14,
0xC5,0x72,0x2C,0x47,0x92,0x34,0xC7,0x93,0x44,0x47,0x94,0x44,0x49,0xB4,0x44,0x49,0xD4,0x44,0x4D,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,
0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x20,0x34,0x64,0x25,0x00,0x00,0x04,
0x00,0x40,0x49,0x6A,0xB1,0xB5,0xD6,0x28,0x05,0xA1,0xA4,0x98,0x18,0xC2,0x94,0x93,0x1C,0x31,0x06,0x1D,0xA4,0x5E,0x31,0xE4,0x10,0x93,0x9E,0x39,0x06,0x15,0x93,0x5E,
0x2A,0x82,0x0C,0x62,0x1E,0x3B,0xC4,0x14,0x93,0x1C,0x08,0x0D,0x59,0x11,0x00,0x44,0x01,0x00,0x00,0xC6,0x20,0xC7,0x10,0x73,0xC8,0x39,0x47,0xA9,0x93,0x14,0x39,0xE7,
0xA4,0x74,0x94,0x1A,0xE7,0x1C,0xA5,0x8E,0x52,0x47,0x29,0xC5,0x9A,0x62,0xCD,0x28,0x95,0xDA,0x52,0xAC,0x8D,0x73,0x8E,0x52,0x47,0xA9,0xA3,0x94,0x6A,0x2C,0x2D,0x76,
0xD4,0x52,0xAD,0xA9,0xC6,0x02,0x00,0x00,0x02,0x1C,0x00,0x00,0x02,0x2C,0x84,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x84,0x31,0x48,0x29,0xA4,0x14,0x62,0x8A,0x39,
0xA7,0x98,0x43,0x8A,0x29,0xC7,0x98,0x73,0x88,0x31,0xE6,0x1C,0x73,0x8E,0x39,0xE7,0xA0,0x74,0x52,0x2A,0xE7,0x98,0x74,0x4E,0x4A,0xC4,0x18,0x73,0x8E,0x39,0xA7,0x9C,
0x73,0x52,0x32,0x27,0x95,0x73,0x4E,0x4A,0x27,0xA1,0x00,0x00,0x80,0x00,0x07,0x00,0x80,0x00,0x0B,0xA1,0xD0,0x90,0x15,0x01,0x40,0x9C,0x00,0x80,0x41,0x92,0x3C,0x4F,
0xD2,0x34,0x51,0x94,0x34,0x4F,0x14,0x3D,0x53,0x74,0x55,0x4F,0x34,0x55,0xD7,0xF2,0x3C,0xD3,0xF4,0x4C,0x53,0x55,0x3D,0xD1,0x54,0x55,0xD3,0x55,0x65,0xD9,0x54,0x55,
0x59,0xB6,0x3C,0xCF,0x34,0x3D,0x53,0x54,0x55,0xCF,0x34,0x55,0xD5,0x54,0x55,0x59,0x36,0x55,0x55,0x96,0x45,0x55,0xD5,0x6D,0xD3,0x55,0x75,0xDB,0x74,0x55,0xDD,0x76,
0x6D,0xD9,0xD7,0x5D,0x59,0x16,0x76,0x51,0x55,0x6D,0xDB,0x54,0x5D,0x5B,0x37,0x55,0xD7,0x16,0x5E,0xD9,0xD6,0x7D,0x59,0xB6,0x75,0x61,0xF2,0x3C,0x55,0xF5,0x4C,0xD3,
0x75,0x3D,0xD3,0x74,0x5D,0xD5,0x75,0x75,0x5B,0x75,0x5D,0x5B,0xF7,0x4C,0x53,0x76,0x4D,0xD7,0x95,0x65,0xD3,0x75,0x6D,0xDB,0x95,0x65,0x5D,0x57,0x65,0x59,0xF7,0x35,
0xD3,0x74,0x5D,0xD1,0x55,0x6D,0xD9,0x74,0x5D,0xD9,0x76,0x65,0x57,0xD7,0x5D,0x59,0xF6,0x85,0xD3,0x75,0x75,0xDF,0x95,0x65,0x61,0x57,0x65,0x59,0xF8,0x75,0x5D,0x17,
0x86,0x59,0xF7,0x8D,0x63,0x74,0x5D,0x5D,0x58,0x65,0xD7,0xF7,0x55,0x59,0xF6,0x8D,0x5B,0xB7,0x7D,0x5F,0xD6,0x75,0xE1,0x98,0x3C,0x4F,0x55,0x3D,0xD3,0x74,0x5D,0xCF,
0x34,0x5D,0xD7,0x74,0x5D,0x5D,0x57,0x5D,0xD7,0xD6,0x35,0xD3,0x74,0x5D,0xD3,0x75,0x6D,0x5B,0x54,0x5D,0x59,0x76,0x65,0xD9,0xF7,0x5D,0x57,0xD6,0x75,0xCF,0x34,0x5D,
0xD9,0x74,0x5D,0xD9,0x36,0x5D,0x57,0x96,0x5D,0x59,0xF6,0x7D,0x57,0x96,0x75,0xDD,0x74,0x5D,0xDD,0x57,0x65,0x59,0xF8,0x55,0x57,0x16,0x7E,0x59,0xD7,0x8D,0xE5,0xB6,
0x6D,0xE1,0x37,0x5D,0x57,0xD7,0x55,0x59,0xD6,0x7D,0x55,0x96,0x75,0x61,0xD6,0x75,0xE3,0xB9,0x75,0x5D,0x18,0x3E,0x55,0xD5,0x7D,0x53,0x76,0x85,0xDF,0x74,0x65,0x5F,
0xD8,0x7D,0xDD,0x59,0x6E,0xDD,0x37,0x96,0xD1,0x75,0x75,0x61,0x95,0x6D,0xE3,0x58,0x65,0x5B,0x18,0x7E,0xE1,0x58,0x96,0xDD,0x37,0x96,0x67,0x74,0x5D,0xDF,0x57,0x6D,
0x57,0x18,0x56,0x59,0xF6,0x95,0xDD,0xD7,0x9D,0x65,0xD7,0x75,0x65,0x78,0x6D,0xDB,0x58,0x6E,0x5D,0x57,0x8E,0x59,0xD7,0x8D,0x61,0x38,0x96,0xA7,0xEE,0x0B,0x4F,0x57,
0xB7,0x85,0x63,0xF6,0x6D,0xE7,0x99,0x7D,0x5D,0x39,0x7E,0x67,0x78,0x96,0x5F,0xF8,0x29,0x9F,0xAA,0xEA,0xBA,0xE9,0xBA,0xC2,0x70,0xBA,0xB2,0xEF,0xCB,0xB6,0x2E,0x0C,
0xBB,0x2F,0x2C,0xCB,0xE8,0xBA,0xBE,0xB0,0xCA,0xB2,0xF1,0xAB,0xB2,0xEC,0x0B,0xB7,0xEE,0x2B,0xC7,0xEE,0x0B,0xC3,0x31,0xBA,0xAE,0xF0,0xAB,0xB6,0xEC,0xFB,0xAE,0x2D,
0x0B,0xC7,0xED,0xEB,0xC6,0x32,0x0C,0xC3,0x72,0xBC,0xB6,0xAD,0x0C,0xB3,0xAE,0x0B,0x65,0xDB,0x47,0xF7,0x7D,0xA5,0xEF,0x2B,0x4B,0x57,0xB7,0x95,0x63,0xD6,0x75,0xA5,
0xED,0xEB,0x94,0x5D,0x18,0x2A,0xC3,0x31,0x54,0x06,0x00,0x00,0x0C,0x38,0x00,0x00,0x04,0x98,0x50,0x06,0x0A,0x0D,0x59,0x11,0x00,0xC4,0x09,0x00,0x30,0x08,0x39,0x87,
0x98,0x82,0x10,0x29,0x06,0x21,0x84,0x90,0x52,0x08,0x21,0xA5,0x88,0x31,0x08,0x99,0x73,0x52,0x2A,0xE6,0xA0,0x94,0x52,0x52,0x0B,0xA5,0xA4,0x16,0x31,0x06,0xA1,0x72,
0x4C,0x4A,0xE6,0x9C,0x94,0x50,0x4A,0x4B,0xA5,0x94,0x96,0x42,0x29,0xAD,0x95,0x54,0x62,0x0C,0xA5,0xC4,0xD8,0x5A,0xAB,0x35,0xB5,0x56,0x6B,0x28,0xA5,0xB5,0x50,0x4A,
0x8C,0xA5,0x94,0x16,0x53,0x6B,0xB5,0xB6,0xD8,0x6A,0x8D,0x18,0x93,0x92,0x39,0x27,0x25,0x73,0x4E,0x4A,0x29,0x25,0xB6,0x52,0x4A,0x6B,0x99,0x73,0x54,0x3A,0x07,0x25,
0x75,0x10,0x52,0x2A,0x25,0xB5,0x58,0x52,0x8A,0xB5,0x72,0x4E,0x4A,0x06,0x1D,0x95,0x0E,0x42,0x4A,0x25,0x95,0x98,0x4A,0x4A,0x31,0x96,0x54,0x62,0x2C,0x25,0xC5,0x5A,
0x52,0xAA,0xB1,0xA5,0xD8,0x6A,0x8B,0x31,0xE7,0x50,0x4A,0x8C,0x25,0x95,0x18,0x4B,0x4A,0xB1,0xB6,0x98,0x72,0x6B,0x31,0xD6,0x1C,0x31,0x26,0x21,0x73,0x4E,0x4A,0xE6,
0x9C,0x94,0x52,0x4A,0x6B,0xA5,0x94,0x16,0x2B,0xE7,0xA4,0x74,0x10,0x52,0xCA,0x1C,0x94,0x54,0x52,0x8A,0xB1,0x94,0x94,0x6A,0xE6,0x9C,0x94,0x0E,0x42,0x4A,0x1D,0x74,
0x54,0x4A,0x4A,0x31,0x96,0x54,0x62,0x0A,0xA5,0xC4,0x58,0x52,0xAA,0xB1,0x94,0xD4,0x62,0x8C,0x31,0xD7,0x96,0x62,0xCB,0xA1,0xA4,0x18,0x4B,0x4A,0xB1,0x96,0x54,0x62,
0x6C,0x31,0xE6,0xDC,0x62,0xCA,0xAD,0x93,0x12,0x5B,0x49,0x29,0xC6,0x50,0x52,0x8C,0x31,0xC6,0x9C,0x5B,0x8C,0x39,0x87,0x52,0x62,0x2C,0x29,0xC5,0x5A,0x52,0xAA,0x31,
0xC6,0x5A,0x73,0x8C,0xB1,0xE6,0x50,0x4A,0x8C,0x25,0x95,0x1A,0x4B,0x4A,0xB1,0xC6,0x1A,0x73,0x6D,0x31,0xD6,0x9C,0x62,0xCC,0x35,0xA5,0x58,0x73,0xAB,0x31,0xE7,0xD8,
0x72,0xEB,0xB5,0xE6,0xE0,0x53,0x6B,0x35,0xA7,0x98,0x72,0x6D,0x31,0xE6,0x5C,0x6B,0x0B,0xB2,0xE6,0x5C,0x7C,0x27,0x25,0xB6,0x50,0x4A,0x8C,0xA5,0xA4,0x18,0x5B,0x8C,
0xB5,0xB6,0x18,0x73,0x0E,0xA5,0xC4,0x58,0x52,0xAA,0xB1,0x94,0x14,0x6B,0x8B,0x31,0xE8,0xD6,0x62,0xED,0xA1,0x94,0x18,0x4B,0x4A,0x31,0x96,0x54,0x6A,0x8C,0x31,0xD6,
0x1C,0x6B,0xCC,0x39,0xC5,0x56,0x6B,0x8B,0xB1,0xD7,0xD4,0x62,0xCE,0x35,0xF7,0x60,0x6C,0xCB,0xB5,0xA7,0x16,0x6B,0x6E,0x31,0xE6,0x9E,0x62,0xCA,0xB5,0xF6,0xDA,0x83,
0xCD,0xAD,0xB7,0x02,0x00,0x00,0x06,0x1C,0x00,0x00,0x02,0x4C,0x28,0x03,0x85,0x86,0xAC,0x04,0x00,0xA2,0x00,0x00,0x00,0x63,0x18,0x73,0x0E,0x42,0xA3,0x90,0x73,0xCE,
0x49,0x69,0x90,0x72,0xCE,0x39,0x29,0x99,0x73,0x10,0x42,0x48,0x29,0x73,0x0E,0x42,0x08,0x29,0x75,0xCE,0x49,0x28,0xA9,0xB5,0xCE,0x39,0x08,0x29,0xB5,0x16,0x4A,0x49,
0xA9,0xB5,0x18,0x43,0x29,0x29,0xB5,0x16,0x63,0x01,0x00,0x00,0x05,0x0E,0x00,0x00,0x01,0x36,0x68,0x4A,0x2C,0x0E,0x50,0x68,0xC8,0x4A,0x00,0x20,0x15,0x00,0xC0,0xE0,
0x38,0x96,0xE5,0x79,0xA6,0x68,0x9A,0xB6,0xED,0x58,0x92,0xE7,0x89,0xA2,0x69,0xAA,0xAA,0x6D,0x3B,0x92,0xE5,0x79,0xA2,0x68,0x9A,0xAA,0x6A,0xDB,0x9A,0xE7,0x89,0xA2,
0x69,0xAA,0xAA,0xEB,0xEA,0xBA,0xE6,0x79,0xA2,0x68,0x9A,0xAA,0xEA,0xBA,0xB6,0x2E,0x8A,0xA2,0x69,0xAA,0xAA,0xAB,0xBA,0xAE,0xEE,0x8B,0xA2,0x68,0x9A,0xAA,0xAA,0xAA,
0xAE,0xAB,0xEB,0xA6,0x69,0xAA,0xAA,0xAB,0xBA,0xAE,0x2C,0xFB,0xBE,0x69,0x9A,0xAA,0xEA,0xBA,0xAE,0x2B,0xCB,0xBE,0xB0,0xAA,0xAE,0xEB,0xCA,0xB2,0x2D,0xDB,0xB6,0x31,
0xAC,0xAA,0xEA,0xBA,0xAE,0x2B,0xDB,0xB6,0x6D,0x1C,0xB7,0x6D,0xEB,0xBA,0xEE,0xFB,0xBE,0x30,0x54,0x6E,0xDB,0xD6,0x75,0x5F,0xF8,0x85,0x61,0x58,0x0A,0x00,0x00,0x4F,
0x70,0x00,0x00,0x2A,0xB0,0x61,0x75,0x84,0x93,0xA2,0xB1,0xC0,0x42,0x43,0x56,0x02,0x00,0x19,0x00,0x00,0x84,0x31,0x08,0x19,0x84,0x10,0x32,0x08,0x21,0x84,0x94,0x52,
0x0A,0x29,0xA5,0x94,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,0x2B,0x02,0x80,0x38,0x01,0x00,0x00,0x21,0x4A,0x21,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0xD4,0x51,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x42,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x4A,0x1D,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x4A,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x2A,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x00,0x80,
0x54,0x84,0x03,0x80,0xD4,0x83,0x09,0x65,0xA0,0xD0,0x90,0x95,0x00,0x40,0x2A,0x00,0x00,0x60,0x8C,0x52,0x8C,0x39,0x07,0xA1,0x94,0x86,0x31,0xE7,0x9C,0x83,0x90,0x4A,
0x4B,0x8D,0x62,0xCE,0x31,0x07,0xA1,0xA4,0x96,0x32,0xE7,0x20,0x94,0x92,0x52,0x4B,0x31,0x66,0xCE,0x41,0x29,0x25,0xA5,0xD6,0x5A,0xCC,0x9C,0x93,0xD2,0x5A,0x6C,0x3D,
0xC6,0x9A,0x39,0x27,0xA9,0xB5,0xD8,0x62,0xAC,0xB5,0x83,0xD2,0x5A,0x8D,0x3D,0xF7,0xDE,0x73,0x27,0xA5,0xB5,0x1A,0x6B,0xEE,0x3D,0xF7,0x92,0x5A,0xAD,0xB5,0xF6,0xD8,
0x73,0xEF,0x25,0xB5,0x18,0x73,0xAD,0xB9,0xF7,0x5A,0x63,0x8D,0xB9,0xF7,0x9E,0x73,0xEF,0xBD,0xA7,0x5C,0x7B,0xAF,0xB5,0xE7,0x5E,0x7B,0x2E,0x00,0x00,0xA7,0xC1,0x01,
0x00,0xF4,0xC0,0x86,0xD5,0x11,0x4E,0x8A,0xC6,0x02,0x0B,0x0D,0x59,0x09,0x00,0xA4,0x02,0x00,0x10,0x08,0x29,0xC5,0x98,0x73,0xCE,0x39,0x87,0x90,0x62,0xCC,0x39,0xE7,
0x20,0x84,0x10,0x21,0xC4,0x98,0x73,0xCE,0x41,0x08,0xA1,0x62,0x8C,0x39,0xE7,0x20,0x84,0x10,0x42,0xC5,0x98,0x63,0xCE,0x41,0x08,0x21,0x84,0xCE,0x39,0xE7,0x9C,0x83,
0x10,0x42,0x08,0x9D,0x73,0xCE,0x39,0x07,0x21,0x84,0x10,0x3A,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x74,0x0E,0x42,0x08,0x1D,0x84,0x10,0x42,0xE8,0x20,0x84,0x10,0x42,
0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0xA1,0x83,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x02,0x00,0x00,0x0B,
0x1C,0x00,0x00,0x02,0x6C,0x58,0x1D,0xE1,0xA4,0x68,0x2C,0xB0,0xD0,0x90,0x95,0x00,0x00,0x10,0x00,0x00,0xC2,0xAC,0xE4,0x12,0x8A,0x24,0x90,0x72,0x0C,0x9A,0x69,0x8C,
0x52,0x8E,0x9A,0x88,0x14,0x62,0x0A,0x9A,0xCA,0x10,0x43,0x4C,0x9A,0xA9,0x98,0x52,0xCA,0x81,0xE8,0x24,0x63,0x08,0x81,0x2A,0xCA,0xC6,0xD0,0x91,0x00,0x00,0x00,0x04,
0x01,0x00,0x01,0x26,0x80,0xC0,0x00,0x41,0xC1,0x17,0x42,0x40,0x8C,0x01,0x00,0x08,0x42,0x64,0x86,0x48,0x28,0xAC,0x82,0x05,0x06,0x65,0xD0,0xE0,0x30,0x0F,0x00,0x1E,
0x20,0x22,0x24,0x02,0x80,0xC4,0x04,0x45,0xDA,0xC5,0x05,0x74,0x19,0xE0,0x82,0x2E,0xEE,0x3A,0x10,0x42,0x10,0x82,0x10,0xC4,0xE2,0x00,0x0A,0x48,0xC0,0xC1,0x09,0x37,
0x3C,0xF1,0x86,0x27,0xDC,0xE0,0x04,0x9D,0xA2,0x52,0x07,0x01,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x00,0x00,0x07,0x05,0x10,0x11,0xD1,0x5C,0x85,0xC5,0x05,0x46,
0x86,0xC6,0x06,0x47,0x87,0x47,0x00,0x00,0x00,0x00,0x00,0xA8,0x00,0xC0,0x07,0x00,0xC0,0xF1,0x01,0x44,0x44,0x34,0x57,0x61,0x71,0x81,0x91,0xA1,0xB1,0xC1,0xD1,0xE1,
0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x04,
};
static const vcb_info_t vcb_list[] = {
{0x01,0x0CD8,vcb_1},
{0x02,0x0B72,vcb_2},
{0x03,0x0DF7,vcb_3},
{0x04,0x1025,vcb_4},
{0x05,0x0C01,vcb_5},
{0x06,0x0C01,vcb_6},
{0x07,0x0CD8,vcb_7},
};
static const int vcb_list_count = sizeof(vcb_list) / sizeof(vcb_list[0]);
#endif

View file

@ -0,0 +1,181 @@
#include "coding.h"
#include "../base/decode_state.h"
#include "../base/codec_info.h"
#include "libs/mio_xerisa.h"
//#include "Source/reader_get.h"
#include "../util/io_callback_sf.h"
/* opaque struct */
typedef struct {
MIOFile* miofile;
MIODecoder* miodec;
MIOContext* mioctx;
/* current buf */
void* sbuf;
int samples;
int channels;
int fmtsize;
io_callback_t cb;
io_priv_t io_priv;
int start_offset;
} mio_codec_data;
static void free_mio(void* priv_data) {
mio_codec_data* data = priv_data;
if (!data) return;
MIOFile_Close(data->miofile);
MIODecoder_Close(data->miodec);
MIOContext_Close(data->mioctx);
ERI_eriCloseLibrary();
free(data);
}
void* init_mio(STREAMFILE* sf, int* p_loop_start) {
ERI_eriInitializeLibrary();
mio_codec_data* data = calloc(1, sizeof(mio_codec_data));
if (!data) return NULL;
io_callbacks_set_sf(&data->cb, &data->io_priv);
data->io_priv.offset = 0;
data->io_priv.sf = sf; //temp, will be updated later
data->miofile = MIOFile_Open();
if (!data->miofile) goto fail;
if (MIOFile_Initialize(data->miofile, &data->cb))
goto fail;
data->miodec = MIODecoder_Open();
if (!data->miodec) goto fail;
if (MIODecoder_Initialize(data->miodec, &data->miofile->mioih))
goto fail;
data->mioctx = MIOContext_Open();
if (!data->mioctx) goto fail;
data->start_offset = data->io_priv.offset;
//TODO: lowest quality files allow 8-bit PCM
if (data->miofile->mioih.dwBitsPerSample == 8) {
goto fail;
}
//TODO: improve get info from libs
if (p_loop_start) {
*p_loop_start = data->miofile->mioih.rewindPoint;
}
return data;
fail:
free_mio(data);
return NULL;
}
static bool read_frame(mio_codec_data* data, STREAMFILE* sf) {
data->io_priv.sf = sf;
//data->io_priv.offset = ...; // persists between calls
// read new packet into buffer
int err = MIOFile_NextPacket(data->miofile, &data->cb);
if (err == eslErrEof)
return false;
if (err) {
VGM_LOG("MIO: decode packet error\n");
return false;
}
// current block is keyframe and can be used to seek/decode start
// number depends on coding mode but usually 1 keyframe per 3-7 non-keyframe blocks (~32768 samples per block)
//if (data->miofile->miodh.bytFlags & MIO_LEAD_BLOCK) {
// ...
//}
return true;
}
static bool decode_frame(mio_codec_data* data, sbuf_t* sbuf) {
// calculate current buffer size
void* ptrWaveBuf = MIOFile_GetCurrentWaveBuffer(data->miofile);
if (!ptrWaveBuf) {
VGM_LOG("MIO: buffer error\n");
return false;
}
// pass buffer to context (bitreader)
MIOContext_AttachInputFile(data->mioctx, data->miofile->packet, data->miofile->packet_size);
// convert data into samples
if (MIODecoder_DecodeSound(data->miodec, data->mioctx, &data->miofile->miodh, ptrWaveBuf)) {
VGM_LOG("MIO: decode error\n");
return false;
}
//int bufferCount = MIOFile_GetCurrentWaveBufferCount(hnd->miofile);
int samples = data->miofile->miodh.dwSampleCount;
int channels = data->miofile->mioih.dwChannelCount;
sfmt_t format = SFMT_S16;
//int fmtsize = data->miofile->mioih.dwBitsPerSample / 8;
//if (fmtsize == 8)
// format = SFMT_S8;
sbuf_init(sbuf, format, ptrWaveBuf, samples, channels);
sbuf->filled = samples;
return true;
}
bool decode_frame_mio(VGMSTREAM* v) {
VGMSTREAMCHANNEL* vs = &v->ch[0];
mio_codec_data* data = v->codec_data;
decode_state_t* ds = v->decode_state;
bool ok = read_frame(data, vs->streamfile);
if (!ok)
return false;
ok = decode_frame(data, &ds->sbuf);
if (!ok)
return false;
return true;
}
static void reset_mio(void* priv_data) {
mio_codec_data* data = priv_data;
if (!data) return;
data->io_priv.offset = data->start_offset;
MIOContext_FlushBuffer(data->mioctx);
MIOFile_Reset(data->miofile, &data->cb);
}
static void seek_mio(VGMSTREAM* v, int32_t num_sample) {
mio_codec_data* data = v->codec_data;
decode_state_t* ds = v->decode_state;
if (!data) return;
reset_mio(data);
// (due to implicit encode delay the above is byte-exact equivalent vs a discard loop)
ds->discard = num_sample;
}
const codec_info_t mio_decoder = {
.sample_type = SFMT_S16,
.decode_frame = decode_frame_mio,
.free = free_mio,
.reset = reset_mio,
.seek = seek_mio,
};

View file

@ -1,82 +1,92 @@
#include "coding.h"
#include "coding_utils_samples.h"
#include "../base/decode_state.h"
#include "../base/codec_info.h"
#ifdef VGM_USE_SPEEX
#include "speex/speex.h"
#define SPEEX_MAX_FRAME_SIZE 0x100 /* frame sizes are stored in a byte */
#define SPEEX_MAX_FRAME_SAMPLES 640 /* nb=160, wb/uwb=320*2 */
#define SPEEX_MAX_CHANNELS 1 /* nb=160, wb/uwb=320*2 */
#define SPEEX_CTL_OK 0 /* -1=request unknown, -2=invalid param */
#define SPEEX_DECODE_OK 0 /* -1 for end of stream, -2 corrupt stream */
typedef enum { EA, TORUS } type_t;
typedef enum { EA, TORUS } speex_type_t;
/* opaque struct */
struct speex_codec_data {
type_t type;
typedef struct {
speex_type_t type;
/* config */
int channels;
int samples_discard;
int encoder_delay;
int samples_discard;
uint8_t buf[SPEEX_MAX_FRAME_SIZE];
int frame_size;
int16_t* samples;
short pbuf[SPEEX_MAX_FRAME_SAMPLES * SPEEX_MAX_CHANNELS];
int frame_samples;
/* frame state */
s16buf_t sbuf;
void* state;
void* handle;
SpeexBits bits;
};
} speex_codec_data;
/* raw SPEEX */
static speex_codec_data* init_speex(type_t type, int channels) {
static void free_speex(void* priv_data) {
speex_codec_data* data = priv_data;
if (!data)
return;
if (data->handle) {
speex_decoder_destroy(data->handle);
speex_bits_destroy(&data->bits);
}
free(data);
}
// raw-ish SPEEX (without Ogg)
static speex_codec_data* init_speex(speex_type_t type, int channels) {
int res, sample_rate;
speex_codec_data* data = NULL;
// not seen, unknown layout (known cases use xN mono decoders)
if (channels > SPEEX_MAX_CHANNELS)
return NULL;
data = calloc(1, sizeof(speex_codec_data));
if (!data) goto fail;
data->type = type;
//TODO: unknown layout (known samples are mono, EA: N decoders, Torus: N too?)
data->channels = channels;
if (channels != 1)
goto fail;
/* Modes: narrowband=nb, wideband=wb, ultrawideband=uwb modes.
* EASpeex seem to always use uwb so use that for now until config is needed.
* Examples normally use &speex_*_mode but export seem problematic? */
data->state = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_UWB));
if (!data->state) goto fail;
// Modes: narrowband=nb, wideband=wb, ultrawideband=uwb modes.
// Known decoders seem to always use uwb so use that for now until config is needed.
// Examples normally use &speex_*_mode but exports seem problematic?
data->handle = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_UWB));
if (!data->handle) goto fail;
speex_bits_init(&data->bits);
res = speex_decoder_ctl(data->state, SPEEX_GET_FRAME_SIZE, &data->frame_samples);
res = speex_decoder_ctl(data->handle, SPEEX_GET_FRAME_SIZE, &data->frame_samples);
if (res != SPEEX_CTL_OK) goto fail;
if (data->frame_samples > SPEEX_MAX_FRAME_SAMPLES)
goto fail;
/* forced in EA's code, doesn't seem to affect decoding (all EAAC headers use this rate too) */
// forced in EA's code, doesn't seem to affect decoding (all EAAC headers use this rate too)
sample_rate = 32000;
res = speex_decoder_ctl(data->state, SPEEX_SET_SAMPLING_RATE, &sample_rate);
res = speex_decoder_ctl(data->handle, SPEEX_SET_SAMPLING_RATE, &sample_rate);
if (res != SPEEX_CTL_OK) goto fail;
/* default "latency" for EASpeex */
data->encoder_delay = 509;
data->samples_discard = data->encoder_delay;
data->samples = malloc(channels * data->frame_samples * sizeof(int16_t));
if (!data->samples) goto fail;
return data;
fail:
@ -84,38 +94,27 @@ fail:
return NULL;
}
speex_codec_data* init_speex_ea(int channels) {
void* init_speex_ea(int channels) {
return init_speex(EA, channels);
}
speex_codec_data* init_speex_torus(int channels) {
void* init_speex_torus(int channels) {
return init_speex(TORUS, channels);
}
static int decode_frame(speex_codec_data* data) {
int res;
data->sbuf.samples = data->samples;
data->sbuf.channels = 1;
data->sbuf.filled = 0;
speex_bits_read_from(&data->bits, (const char*)data->buf, data->frame_size);
res = speex_decode_int(data->state, &data->bits, data->sbuf.samples);
if (res != SPEEX_DECODE_OK) goto fail;
// speex_decode() returns samples (F32), but internally speex decodes into pcm16
int res = speex_decode_int(data->handle, &data->bits, data->pbuf);
if (res != SPEEX_DECODE_OK) return -1;
data->sbuf.filled = data->frame_samples;
return 1;
fail:
return 0;
return data->frame_samples;
}
/* for simple style speex (seen in EA-Speex and libspeex's sampledec.c) */
static int read_frame(speex_codec_data* data, VGMSTREAMCHANNEL* stream) {
size_t bytes;
// for simple style speex (seen in EA-Speex and libspeex's sampledec.c)
static bool read_frame(speex_codec_data* data, VGMSTREAMCHANNEL* stream) {
switch(data->type) {
case EA:
data->frame_size = read_u8(stream->offset, stream->streamfile);
@ -128,87 +127,71 @@ static int read_frame(speex_codec_data* data, VGMSTREAMCHANNEL* stream) {
default:
break;
}
if (data->frame_size == 0) goto fail;
if (data->frame_size == 0)
return false;
bytes = read_streamfile(data->buf, stream->offset, data->frame_size, stream->streamfile);
size_t bytes = read_streamfile(data->buf, stream->offset, data->frame_size, stream->streamfile);
stream->offset += data->frame_size;
if (bytes != data->frame_size) goto fail;
return 1;
fail:
return 0;
if (bytes != data->frame_size)
return false;
return true;
}
void decode_speex(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do) {
VGMSTREAMCHANNEL* stream = &vgmstream->ch[0];
speex_codec_data* data = vgmstream->codec_data;
int ok;
static bool decode_frame_speex(VGMSTREAM* v) {
VGMSTREAMCHANNEL* stream = &v->ch[0];
speex_codec_data* data = v->codec_data;
decode_state_t* ds = v->decode_state;
bool ok = read_frame(data, stream);
if (!ok) return false;
while (samples_to_do > 0) {
s16buf_t* sbuf = &data->sbuf;
int samples = decode_frame(data);
if (samples < 0) return false;
if (sbuf->filled <= 0) {
ok = read_frame(data, stream);
if (!ok) goto fail;
sbuf_init_s16(&ds->sbuf, data->pbuf, samples, data->channels);
ds->sbuf.filled = ds->sbuf.samples;
ok = decode_frame(data);
if (!ok) goto fail;
if (data->samples_discard) {
ds->discard += data->samples_discard;
data->samples_discard = 0;
}
if (data->samples_discard)
s16buf_discard(&outbuf, sbuf, &data->samples_discard);
else
s16buf_consume(&outbuf, sbuf, &samples_to_do);
return true;
}
return;
fail:
/* on error just put some 0 samples */
VGM_LOG("SPEEX: decode fail at %x, missing %i samples\n", (uint32_t)stream->offset, samples_to_do);
s16buf_silence(&outbuf, &samples_to_do, data->channels);
}
void reset_speex(speex_codec_data* data) {
int res;
if (!data) return;
res = speex_decoder_ctl(data->state, SPEEX_RESET_STATE, NULL);
if (res != SPEEX_CTL_OK) goto fail;
data->sbuf.filled = 0;
data->samples_discard = data->encoder_delay;
return;
fail:
return; /* ? */
}
void seek_speex(VGMSTREAM* vgmstream, int32_t num_sample) {
speex_codec_data* data = vgmstream->codec_data;
if (!data) return;
reset_speex(data);
data->samples_discard += num_sample;
/* loop offsets are set during decode; force them to stream start so discard works */
if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
}
void free_speex(speex_codec_data* data) {
static void reset_speex(void* priv_data) {
speex_codec_data* data = priv_data;
if (!data)
return;
if (data->state) {
speex_decoder_destroy(data->state);
speex_bits_destroy(&data->bits);
int res = speex_decoder_ctl(data->handle, SPEEX_RESET_STATE, NULL);
if (res != SPEEX_CTL_OK)
return; //???
data->samples_discard = data->encoder_delay;
}
free(data->samples);
free(data);
static void seek_speex(VGMSTREAM* v, int32_t num_sample) {
decode_state_t* ds = v->decode_state;
speex_codec_data* data = v->codec_data;
if (!data) return;
reset_speex(data);
ds->discard = num_sample;
// loop offsets are set during decode; force them to stream start so discard works
if (v->loop_ch)
v->loop_ch[0].offset = v->loop_ch[0].channel_start_offset;
}
const codec_info_t speex_decoder = {
.sample_type = SFMT_S16,
.decode_frame = decode_frame_speex,
.free = free_speex,
.reset = reset_speex,
.seek = seek_speex,
};
#endif

View file

@ -1,34 +1,31 @@
#include "coding.h"
#include "coding_utils_samples.h"
#if VGM_TEST_DECODER
#include "../base/codec_info.h"
#include "../base/decode_state.h"
#endif
#include "libs/tac_lib.h"
/* opaque struct */
struct tac_codec_data {
/* config */
int channels;
int samples_discard;
int encoder_delay;
typedef struct {
uint8_t buf[TAC_BLOCK_SIZE];
bool feed_block;
off_t offset;
int16_t samples[TAC_FRAME_SAMPLES * TAC_CHANNELS];
int frame_samples;
/* frame state */
s16buf_t sbuf;
float fbuf[TAC_FRAME_SAMPLES * TAC_CHANNELS];
int discard;
void* handle;
};
} tac_codec_data;
static void free_tac(void* priv_data) {
tac_codec_data* data = priv_data;
if (!data)
return;
/* raw SPEEX */
tac_codec_data* init_tac(STREAMFILE* sf) {
tac_free(data->handle);
free(data);
}
void* init_tac(STREAMFILE* sf) {
tac_codec_data* data = NULL;
int bytes;
@ -40,13 +37,8 @@ tac_codec_data* init_tac(STREAMFILE* sf) {
data->handle = tac_init(data->buf, bytes);
if (!data->handle) goto fail;
data->feed_block = false; /* ok to use current block */
data->feed_block = false; // ok to use first block
data->offset = bytes;
data->channels = TAC_CHANNELS;
data->frame_samples = TAC_FRAME_SAMPLES;
data->encoder_delay = 0;
data->samples_discard = data->encoder_delay;
return data;
fail:
@ -55,130 +47,86 @@ fail:
}
static bool decode_frame(tac_codec_data* data) {
int err;
data->sbuf.samples = data->samples;
data->sbuf.channels = data->channels;
data->sbuf.filled = 0;
err = tac_decode_frame(data->handle, data->buf);
static int decode_frame(tac_codec_data* data) {
int err = tac_decode_frame(data->handle, data->buf);
if (err == TAC_PROCESS_NEXT_BLOCK) {
data->feed_block = true;
return true;
return 0;
}
if (err == TAC_PROCESS_DONE) {
VGM_LOG("TAC: process done (EOF) %i\n", err);
return false; /* shouldn't reach this */
return -1; // shouldn't reach this
}
if (err != TAC_PROCESS_OK) {
VGM_LOG("TAC: process error %i\n", err);
return false;
return -1;
}
tac_get_samples_pcm16(data->handle, data->sbuf.samples);
data->sbuf.filled = data->frame_samples;
return true;
tac_get_samples_float(data->handle, data->fbuf);
return TAC_FRAME_SAMPLES;
}
static bool read_frame(tac_codec_data* data, STREAMFILE* sf) {
/* new block must be read only when signaled by lib */
// new block must be read only when signaled by lib (a single block has N frames)
if (!data->feed_block)
return true;
int bytes = read_streamfile(data->buf, data->offset, sizeof(data->buf), sf);
data->offset += bytes;
data->feed_block = 0;
if (bytes <= 0) return false; /* can read less that buf near EOF */
if (bytes <= 0) return false; // will read less that buf near EOF
return true;
}
void decode_tac(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do) {
VGMSTREAMCHANNEL* stream = &vgmstream->ch[0];
tac_codec_data* data = vgmstream->codec_data;
bool ok;
bool decode_frame_tac(VGMSTREAM* v) {
VGMSTREAMCHANNEL* stream = &v->ch[0];
tac_codec_data* data = v->codec_data;
bool ok = read_frame(data, stream->streamfile);
if (!ok)
return false;
while (samples_to_do > 0) {
s16buf_t* sbuf = &data->sbuf;
decode_state_t* ds = v->decode_state;
if (sbuf->filled <= 0) {
ok = read_frame(data, stream->streamfile);
if (!ok) goto fail;
int samples = decode_frame(data);
if (samples < 0)
return false;
ok = decode_frame(data);
if (!ok) goto fail;
}
if (data->samples_discard)
s16buf_discard(&outbuf, sbuf, &data->samples_discard);
else
s16buf_consume(&outbuf, sbuf, &samples_to_do);
}
return;
fail:
/* on error just put some 0 samples */
VGM_LOG("TAC: decode fail at %x, missing %i samples\n", (uint32_t)data->offset, samples_to_do);
s16buf_silence(&outbuf, &samples_to_do, data->sbuf.channels);
}
#if VGM_TEST_DECODER
bool decode_tac_frame(VGMSTREAM* vgmstream) {
VGMSTREAMCHANNEL* stream = &vgmstream->ch[0];
tac_codec_data* data = vgmstream->codec_data;
decode_state_t* ds = vgmstream->decode_state;
sbuf_init_s16(&ds->sbuf, data->samples, TAC_FRAME_SAMPLES, vgmstream->channels);
bool ok;
ok = read_frame(data, stream->streamfile);
if (!ok) return false;
ok = decode_frame(data);
if (!ok) return false;
ds->sbuf.filled = TAC_FRAME_SAMPLES; //TODO call sbuf_fill(samples);
sbuf_init_f32(&ds->sbuf, data->fbuf, samples, v->channels);
ds->sbuf.filled = samples;
// copy and let decoder handle
if (data->samples_discard) {
ds->discard = data->samples_discard;
data->samples_discard = 0;
if (data->discard) {
ds->discard += data->discard;
data->discard = 0;
}
return true;
}
#endif
void reset_tac(tac_codec_data* data) {
static void reset_tac(void* priv_data) {
tac_codec_data* data = priv_data;
if (!data) return;
tac_reset(data->handle);
data->feed_block = true;
data->offset = 0x00;
data->sbuf.filled = 0;
data->samples_discard = data->encoder_delay;
}
void seek_tac(tac_codec_data* data, int32_t num_sample) {
static void seek_tac(VGMSTREAM* v, int32_t num_sample) {
tac_codec_data* data = v->codec_data;
int32_t loop_sample;
const tac_header_t* hdr;
if (!data)
return;
hdr = tac_get_header(data->handle);
const tac_header_t* hdr = tac_get_header(data->handle);
loop_sample = (hdr->loop_frame - 1) * TAC_FRAME_SAMPLES + hdr->loop_discard;
if (loop_sample == num_sample) {
@ -186,23 +134,22 @@ void seek_tac(tac_codec_data* data, int32_t num_sample) {
data->feed_block = true;
data->offset = hdr->loop_offset;
data->sbuf.filled = 0;
data->samples_discard = hdr->loop_discard;
data->discard = hdr->loop_discard;
}
else {
tac_reset(data->handle);
data->feed_block = true;
data->offset = 0x00;
data->sbuf.filled = 0;
data->samples_discard = num_sample;
data->discard = num_sample;
}
}
void free_tac(tac_codec_data* data) {
if (!data)
return;
tac_free(data->handle);
free(data);
}
const codec_info_t tac_decoder = {
.sample_type = SFMT_F32,
.decode_frame = decode_frame_tac,
.free = free_tac,
.reset = reset_tac,
.seek = seek_tac,
//frame_samples = 1024,
};

View file

@ -0,0 +1,207 @@
#include "coding.h"
#include "../base/decode_state.h"
#include "../base/codec_info.h"
#include "libs/ubi_mpeg_helpers.h"
#define MINIMP3_FLOAT_OUTPUT
//#define MINIMP3_NO_SIMD
#define MINIMP3_IMPLEMENTATION
#include "libs/minimp3.h"
//TODO: needed for smoother segments, but not sure if block samples counts this
// (usually blocks' frames have more samples than defined but not always; maybe should output delay's samples at EOF)
#define UBIMPEG_INITIAL_DISCARD 480 //observed
#define UBIMPEG_SAMPLES_PER_FRAME 1152
#define UBIMPEG_MAX_CHANNELS 2
#define UBIMPEG_INPUT_LIMIT 0x400 //enough for 2 stereo + mono frames
/* opaque struct */
typedef struct {
bool is_sur2;
bool is_sur1;
bitstream_t is;
mp3dec_t mp3d;
mp3dec_frame_info_t info;
uint8_t ibuf[0x2000]; // big enough to limit re-reading
uint8_t obuf[0x400]; // at least ~300
uint8_t rbuf[0x400]; // at least 300 * 2
float fbuf[UBIMPEG_SAMPLES_PER_FRAME * UBIMPEG_MAX_CHANNELS];
int initial_discard;
} ubimpeg_codec_data;
static void free_ubimpeg(void* priv_data) {
ubimpeg_codec_data* data = priv_data;
if (!data) return;
free(data);
}
void* init_ubimpeg(uint32_t mode) {
ubimpeg_codec_data* data = NULL;
data = calloc(1, sizeof(ubimpeg_codec_data));
if (!data) goto fail;
// data may start with 'surround mode' flag, otherwise a regular frame with a Ubi-MPEG sync
if (mode == get_id32be("2RUS")) {
data->is_sur2 = true;
}
else if (mode == get_id32be("1RUS")) {
data->is_sur1 = true;
VGM_LOG("UBI-MPEG: 1RUS found\n");
goto fail;
}
else if ((mode >> 20) != 0xFFF) {
VGM_LOG("UBI-MPEG: unknown format %x\n", mode);
goto fail;
}
data->initial_discard = UBIMPEG_INITIAL_DISCARD;
bm_setup(&data->is, data->ibuf, 0);
mp3dec_init(&data->mp3d);
return data;
fail:
free_ubimpeg(data);
return NULL;
}
// Ubi-MPEG is made to keep all data in memory, since frames go one after another.
// Here we ensure that buf is filled enough for the reader, and move data around if needed
// (maybe should make a circular buf bitreader but seems a bit too particular).
static bool setup_input_bitstream(VGMSTREAM* v) {
ubimpeg_codec_data* data = v->codec_data;
VGMSTREAMCHANNEL* vs = &v->ch[0];
//TODO maybe should clamp to block size, but overreads should result in sync error as new blocks start with samples (technically could match)
// on init should read buf size
int read_size = sizeof(data->ibuf);
int pos = 0;
if (data->is.bufsize > 0) {
uint32_t ibuf_offset = bm_pos(&data->is) / 8;
uint32_t ibuf_left = read_size - ibuf_offset;
// move buf to beginning + setup to fill it fully
if (ibuf_left < UBIMPEG_INPUT_LIMIT) {
int ibuf_bitpos = bm_pos(&data->is) % 8;
memmove(data->ibuf, data->ibuf + ibuf_offset, ibuf_left);
bm_setup(&data->is, data->ibuf, ibuf_left);
bm_skip(&data->is, ibuf_bitpos);
pos = ibuf_left;
read_size -= ibuf_left;
}
else {
// enough data in buf
return true;
}
}
int bytes = read_streamfile(data->ibuf + pos, vs->offset, read_size, vs->streamfile);
bm_fill(&data->is, bytes);
vs->offset += bytes;
return true;
}
static int read_frame_ubimpeg(VGMSTREAM* v) {
ubimpeg_codec_data* data = v->codec_data;
// prepare and read data for the bitstream, if needed
setup_input_bitstream(v) ;
// convert input data into 1 regular mpeg frame
bitstream_t os = {0};
bm_setup(&os, data->obuf, sizeof(data->obuf));
int obuf_size = ubimpeg_transform_frame(&data->is, &os);
if (!obuf_size) return 0;
// TODO: handle correctly
// Ubi-MPEG (MP2) mixes 1 stereo frame + 1 mono frame coefs before synth to (presumably) emulate M/S stereo from MP3.
// Ignoring the mono frame usually sounds ok enough (as good as 160kbps JS MP2 by 1998 encoders can sound) but
// sometimes stereo frames only have data for left channel and need the mono frame to complete R.
if (data->is_sur1 || data->is_sur2) {
// consume next frame (should be mono) in a separate buffer as otherwise confuses minimp3
bm_setup(&os, data->rbuf, sizeof(data->rbuf));
ubimpeg_transform_frame(&data->is, &os);
}
return obuf_size;
}
bool decode_frame_ubimpeg(VGMSTREAM* v) {
int obuf_size = read_frame_ubimpeg(v);
if (!obuf_size) {
return false;
}
decode_state_t* ds = v->decode_state;
ubimpeg_codec_data* data = v->codec_data;
int samples = mp3dec_decode_frame(&data->mp3d, data->obuf, obuf_size, data->fbuf, &data->info);
if (samples < 0) {
return false;
}
// TODO: voice .bnm + Ubi-MPEG sets 2 channels but uses mono frames (no xRUS). Possibly the MPEG engine
// only handle stereo, maybe should dupe L>R. sbuf copying handles this correctly.
// todo fix
if (data->info.channels != v->channels) {
VGM_LOG_ONCE("UBI MPEG: mismatched channels %i vs %i\n", data->info.channels, v->channels);
//return false;
}
sbuf_init_flt(&ds->sbuf, data->fbuf, samples, data->info.channels);
ds->sbuf.filled = samples;
if (data->initial_discard) {
ds->discard += data->initial_discard;
data->initial_discard = 0;
}
return true;
}
static void reset_ubimpeg(void* priv_data) {
ubimpeg_codec_data* data = priv_data;
if (!data) return;
data->initial_discard = UBIMPEG_INITIAL_DISCARD;
bm_setup(&data->is, data->ibuf, 0);
mp3dec_init(&data->mp3d);
}
static void seek_ubimpeg(VGMSTREAM* v, int32_t num_sample) {
ubimpeg_codec_data* data = v->codec_data;
decode_state_t* ds = v->decode_state;
if (!data) return;
reset_ubimpeg(data);
ds->discard = num_sample;
if (v->loop_ch) {
v->loop_ch[0].offset = v->loop_ch[0].channel_start_offset;
}
}
const codec_info_t ubimpeg_decoder = {
.sample_type = SFMT_FLT,
.decode_frame = decode_frame_ubimpeg,
.free = free_ubimpeg,
.reset = reset_ubimpeg,
.seek = seek_ubimpeg,
};

View file

@ -1,12 +1,31 @@
#include <math.h>
#include "../base/decode_state.h"
#include "../base/sbuf.h"
#include "../base/codec_info.h"
#include "coding.h"
#include "vorbis_custom_decoder.h"
#ifdef VGM_USE_VORBIS
#define VORBIS_DEFAULT_BUFFER_SIZE 0x8000 /* should be at least the size of the setup header, ~0x2000 */
#define VORBIS_CALL_SAMPLES 1024 // allowed frame 'blocksizes' range from 2^6 ~ 2^13 (64 ~ 8192) but we can return partial samples
#define VORBIS_DEFAULT_BUFFER_SIZE 0x8000 // at least the size of the setup header, ~0x2000
static void pcm_convert_float_to_16(sample_t* outbuf, int samples_to_do, float** pcm, int channels);
void free_vorbis_custom(void* priv_data) {
vorbis_custom_codec_data* data = priv_data;
if (!data)
return;
/* internal decoder cleanup */
vorbis_block_clear(&data->vb);
vorbis_dsp_clear(&data->vd);
vorbis_comment_clear(&data->vc);
vorbis_info_clear(&data->vi);
free(data->buffer);
free(data->fbuf);
free(data);
}
/**
* Inits a vorbis stream of some custom variety.
@ -51,9 +70,11 @@ vorbis_custom_codec_data* init_vorbis_custom(STREAMFILE* sf, off_t start_offset,
case VORBIS_SK: ok = vorbis_custom_setup_init_sk(sf, start_offset, data); break;
case VORBIS_VID1: ok = vorbis_custom_setup_init_vid1(sf, start_offset, data); break;
case VORBIS_AWC: ok = vorbis_custom_setup_init_awc(sf, start_offset, data); break;
default: goto fail;
case VORBIS_OOR: ok = vorbis_custom_setup_init_oor(sf, start_offset, data); break;
default: ok = false; break;
}
if(!ok) goto fail;
if(!ok)
goto fail;
data->op.b_o_s = 0; /* end of fake headers */
@ -63,6 +84,9 @@ vorbis_custom_codec_data* init_vorbis_custom(STREAMFILE* sf, off_t start_offset,
/* write output */
config->channels = data->config.channels;
config->sample_rate = data->config.sample_rate;
config->last_granule = data->config.last_granule;
config->data_start_offset = data->config.data_start_offset;
if (!data->config.stream_end) {
@ -77,58 +101,17 @@ fail:
return NULL;
}
/* Decodes Vorbis packets into a libvorbis sample buffer, and copies them to outbuf */
void decode_vorbis_custom(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
vorbis_custom_codec_data* data = vgmstream->codec_data;
//data->op.packet = data->buffer;/* implicit from init */
int samples_done = 0;
static bool read_packet(VGMSTREAM* v) {
VGMSTREAMCHANNEL* stream = &v->ch[0];
vorbis_custom_codec_data* data = v->codec_data;
while (samples_done < samples_to_do) {
// extra EOF check
// (may need to drain samples? not a thing in vorbis due to packet types?)
if (stream->offset >= data->config.stream_end)
return false;
if (data->samples_full) { /* read more samples */
int samples_to_get;
float **pcm;
/* get PCM samples from libvorbis buffers */
samples_to_get = vorbis_synthesis_pcmout(&data->vd, &pcm);
if (!samples_to_get) {
data->samples_full = 0; /* request more if empty*/
continue;
}
if (data->samples_to_discard) {
/* discard samples for looping */
if (samples_to_get > data->samples_to_discard)
samples_to_get = data->samples_to_discard;
data->samples_to_discard -= samples_to_get;
}
else {
/* get max samples and convert from Vorbis float pcm to 16bit pcm */
if (samples_to_get > samples_to_do - samples_done)
samples_to_get = samples_to_do - samples_done;
pcm_convert_float_to_16(outbuf + samples_done * channels, samples_to_get, pcm, data->vi.channels);
samples_done += samples_to_get;
}
/* mark consumed samples from the buffer
* (non-consumed samples are returned in next vorbis_synthesis_pcmout calls) */
vorbis_synthesis_read(&data->vd, samples_to_get);
}
else { /* read more data */
int ok, rc;
/* extra EOF check */
if (stream->offset >= data->config.stream_end) {
/* may need to drain samples? (not a thing in vorbis due to packet types?) */
goto decode_fail;
}
/* not actually needed, but feels nicer */
data->op.granulepos += samples_to_do; /* can be changed next if desired */
data->op.packetno++;
/* read/transform data into the ogg_packet buffer and advance offsets */
// read/transform data into the ogg_packet buffer and advance offsets
bool ok;
switch(data->type) {
case VORBIS_FSB: ok = vorbis_custom_parse_packet_fsb(stream, data); break;
case VORBIS_WWISE: ok = vorbis_custom_parse_packet_wwise(stream, data); break;
@ -136,95 +119,157 @@ void decode_vorbis_custom(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t sample
case VORBIS_SK: ok = vorbis_custom_parse_packet_sk(stream, data); break;
case VORBIS_VID1: ok = vorbis_custom_parse_packet_vid1(stream, data); break;
case VORBIS_AWC: ok = vorbis_custom_parse_packet_awc(stream, data); break;
default: goto decode_fail;
}
if(!ok) {
goto decode_fail;
case VORBIS_OOR: ok = vorbis_custom_parse_packet_oor(stream, data); break;
default: ok = false; break;
}
return ok;
}
/* parse the fake ogg packet into a logical vorbis block */
static bool decode_frame(VGMSTREAM* v) {
decode_state_t* ds = v->decode_state;
vorbis_custom_codec_data* data = v->codec_data;
int rc;
// parse the fake ogg packet into a logical vorbis block
rc = vorbis_synthesis(&data->vb, &data->op);
if (rc == OV_ENOTAUDIO) {
VGM_LOG("Vorbis: not an audio packet (size=0x%x) @ %x\n",(size_t)data->op.bytes,(uint32_t)stream->offset);
//VGM_LOGB(data->op.packet, (size_t)data->op.bytes,0);
continue; /* rarely happens, seems ok? */
} else if (rc != 0) goto decode_fail;
// rarely happens, seems ok?
VGM_LOG("Vorbis: not an audio packet (size=0x%x) @ %x\n", (size_t)data->op.bytes, (uint32_t)v->ch[0].offset);
ds->sbuf.filled = 0;
return true;
}
else if (rc != 0) {
return false;
}
/* finally decode the logical block into samples */
// finally decode the logical vorbis block into samples
rc = vorbis_synthesis_blockin(&data->vd,&data->vb);
if (rc != 0) goto decode_fail; /* ? */
if (rc != 0) return false; /* ? */
data->op.packetno++;
data->samples_full = 1;
}
return true;
}
return;
static int copy_samples(VGMSTREAM* v) {
decode_state_t* ds = v->decode_state;
vorbis_custom_codec_data* data = v->codec_data;
decode_fail:
/* on error just put some 0 samples */
VGM_LOG("VORBIS: decode fail at %x, missing %i samples\n", (uint32_t)stream->offset, (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample_t));
//TODO: helper?
//TODO: maybe should init in init_vorbis_custom but right now not all vorbises pass channels
if (data->fbuf == NULL) {
data->fbuf = malloc(VORBIS_CALL_SAMPLES * sizeof(float) * v->channels);
if (!data->fbuf) return -1;
}
/* converts from internal Vorbis format to standard PCM (mostly from Xiph's decoder_example.c) */
static void pcm_convert_float_to_16(sample_t* outbuf, int samples_to_do, float** pcm, int channels) {
int ch, s;
sample_t* ptr;
float* channel;
// get PCM samples from libvorbis buffers
float** pcm;
int samples = vorbis_synthesis_pcmout(&data->vd, &pcm);
if (samples > VORBIS_CALL_SAMPLES)
samples = VORBIS_CALL_SAMPLES;
/* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc)
* to 16 bit signed PCM ints (host order) and interleave + fix clipping */
for (ch = 0; ch < channels; ch++) {
/* channels should be in standard order unlike Ogg Vorbis (at least in FSB) */
ptr = outbuf + ch;
channel = pcm[ch];
for (s = 0; s < samples_to_do; s++) {
int val = (int)floor(channel[s] * 32767.0f + 0.5f);
if (val > 32767) val = 32767;
else if (val < -32768) val = -32768;
// no more samples in vorbis's buffer
if (samples == 0)
return 0;
*ptr = val;
ptr += channels;
}
}
// vorbis's planar buffer to interleaved buffer
sbuf_init_flt(&ds->sbuf, data->fbuf, samples, v->channels);
ds->sbuf.filled = samples;
sbuf_interleave(&ds->sbuf, pcm);
// mark consumed samples from the buffer
// (non-consumed samples are returned in next vorbis_synthesis_pcmout calls)
vorbis_synthesis_read(&data->vd, samples);
// TODO: useful?
//data->op.granulepos += samples; // not actually needed
if (data->current_discard) {
ds->discard += data->current_discard;
data->current_discard = 0;
}
/* ********************************************** */
void free_vorbis_custom(vorbis_custom_codec_data* data) {
if (!data)
return;
/* internal decoder cleanup */
vorbis_block_clear(&data->vb);
vorbis_dsp_clear(&data->vd);
vorbis_comment_clear(&data->vc);
vorbis_info_clear(&data->vi);
free(data->buffer);
free(data);
return samples;
}
void reset_vorbis_custom(VGMSTREAM* vgmstream) {
vorbis_custom_codec_data *data = vgmstream->codec_data;
static bool decode_frame_vorbis_custom(VGMSTREAM* v) {
// vorbis may hold samples, return them first
int ret = copy_samples(v);
if (ret < 0) return false;
if (ret > 0) return true;
// handle new frame
bool read = read_packet(v);
if (!read)
return false;
// decode current frame
bool decoded = decode_frame(v);
if (!decoded)
return false;
// samples will be copied next call
return true;
}
static void reset_vorbis_custom(void* priv_data) {
vorbis_custom_codec_data* data = priv_data;
if (!data) return;
vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = 0;
data->current_discard = 0;
data->current_packet = 0;
data->packet_count = 0;
data->flags = 0;
}
void seek_vorbis_custom(VGMSTREAM* vgmstream, int32_t num_sample) {
vorbis_custom_codec_data *data = vgmstream->codec_data;
static void seek_vorbis_custom(VGMSTREAM* v, int32_t num_sample) {
vorbis_custom_codec_data* data = v->codec_data;
if (!data) return;
/* Seeking is provided by the Ogg layer, so with custom vorbis we'd need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = num_sample;
if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
reset_vorbis_custom(data);
data->current_discard = num_sample;
if (v->loop_ch)
v->loop_ch[0].offset = v->loop_ch[0].channel_start_offset;
}
int32_t vorbis_custom_get_samples(VGMSTREAM* v) {
vorbis_custom_codec_data* data = v->codec_data;
//TODO improve (would need to change a bunch)
VGMSTREAMCHANNEL* stream = &v->ch[0];
uint32_t temp = stream->offset;
// read packets + sum samples (info from revorb: https://yirkha.fud.cz/progs/foobar2000/revorb.cpp)
int prev_blocksize = 0;
int32_t samples = 0;
while (true) {
bool ok = read_packet(v);
if (!ok || data->op.bytes == 0) //EOF probably
break;
// get blocksize (somewhat similar to samples-per-frame, but must be adjusted)
int blocksize = vorbis_packet_blocksize(&data->vi, &data->op);
if (prev_blocksize)
samples += (prev_blocksize + blocksize) / 4;
prev_blocksize = blocksize;
}
reset_vorbis_custom(data);
stream->offset = temp;
return samples;
}
const codec_info_t vorbis_custom_decoder = {
.sample_type = SFMT_FLT,
.decode_frame = decode_frame_vorbis_custom,
.free = free_vorbis_custom,
.reset = reset_vorbis_custom,
.seek = seek_vorbis_custom,
};
#endif

View file

@ -8,6 +8,8 @@
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
#define MAX_PACKET_SIZES 160 // max 256 in theory, observed max is ~65, rarely ~130 in
/* custom Vorbis without Ogg layer */
struct vorbis_custom_codec_data {
vorbis_info vi; /* stream settings */
@ -18,24 +20,28 @@ struct vorbis_custom_codec_data {
uint8_t* buffer; /* internal raw data buffer */
size_t buffer_size;
float* fbuf;
size_t samples_to_discard; /* for looping purposes */
int samples_full; /* flag, samples available in vorbis buffers */
int current_discard; /* for looping purposes */
vorbis_custom_t type; /* Vorbis subtype */
vorbis_custom_config config; /* config depending on the mode */
/* Wwise Vorbis: saved data to reconstruct modified packets */
uint8_t mode_blockflag[64+1]; /* max 6b+1; flags 'n stuff */
int mode_bits; /* bits to store mode_number */
uint8_t prev_blockflag; /* blockflag in the last decoded packet */
/* Ogg-style Vorbis: packet within a page */
/* OOR/OggS: current page info (state) */
int current_packet;
int packet_count;
uint16_t packet_size[MAX_PACKET_SIZES];
uint8_t flags;
/* reference for page/blocks */
off_t block_offset;
size_t block_size;
int prev_block_samples; /* count for optimization */
};
@ -45,6 +51,7 @@ int vorbis_custom_setup_init_ogl(STREAMFILE* sf, off_t start_offset, vorbis_cust
int vorbis_custom_setup_init_sk(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data);
int vorbis_custom_setup_init_vid1(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data);
int vorbis_custom_setup_init_awc(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data);
int vorbis_custom_setup_init_oor(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data);
int vorbis_custom_parse_packet_fsb(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
int vorbis_custom_parse_packet_wwise(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
@ -52,12 +59,15 @@ int vorbis_custom_parse_packet_ogl(VGMSTREAMCHANNEL* stream, vorbis_custom_codec
int vorbis_custom_parse_packet_sk(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
int vorbis_custom_parse_packet_vid1(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
int vorbis_custom_parse_packet_awc(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
int vorbis_custom_parse_packet_oor(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
/* other utils to make/parse vorbis stuff */
int build_header_comment(uint8_t* buf, int bufsize);
int build_header_identification(uint8_t* buf, int bufsize, vorbis_custom_config* cfg);
void load_blocksizes(vorbis_custom_config* cfg, int blocksize_short, int blocksize_long);
int vorbis_get_blocksize_exp(int blocksize);
bool load_header_packet(STREAMFILE* sf, vorbis_custom_codec_data* data, uint32_t packet_size, int packet_skip, uint32_t* p_offset);
#endif/* VGM_USE_VORBIS */
#endif/*_VORBIS_CUSTOM_DECODER_H_ */
#endif
#endif

View file

@ -1,6 +1,7 @@
#include "vorbis_custom_decoder.h"
#ifdef VGM_USE_VORBIS
int build_header_comment(uint8_t* buf, int bufsize) {
int bytes = 0x19;
@ -22,6 +23,7 @@ int build_header_identification(uint8_t* buf, int bufsize, vorbis_custom_config*
if (bytes > bufsize)
return 0;
// long (bigger frames) + short (smaller frames) blocksizes (samples per frame)
uint8_t blocksizes = (cfg->blocksize_0_exp << 4) | (cfg->blocksize_1_exp);
put_u8 (buf+0x00, 0x01); /* packet_type (id) */
@ -46,35 +48,19 @@ bool make_header_identification(vorbis_custom_codec_data* data, vorbis_custom_co
return true;
}
void load_blocksizes(vorbis_custom_config* cfg, int blocksize_short, int blocksize_long) {
uint8_t exp_blocksize_0, exp_blocksize_1;
/* guetto log2 for allowed blocksizes (2-exp), could be improved */
switch(blocksize_long) {
case 64: exp_blocksize_0 = 6; break;
case 128: exp_blocksize_0 = 7; break;
case 256: exp_blocksize_0 = 8; break;
case 512: exp_blocksize_0 = 9; break;
case 1024: exp_blocksize_0 = 10; break;
case 2048: exp_blocksize_0 = 11; break;
case 4096: exp_blocksize_0 = 12; break;
case 8192: exp_blocksize_0 = 13; break;
default: exp_blocksize_0 = 0;
// basic log2 for allowed blocksizes (2-exp)
int vorbis_get_blocksize_exp(int blocksize) {
switch(blocksize) {
case 64: return 6;
case 128: return 7;
case 256: return 8;
case 512: return 9;
case 1024: return 10;
case 2048: return 11;
case 4096: return 12;
case 8192: return 13;
default: return 0;
}
switch(blocksize_short) {
case 64: exp_blocksize_1 = 6; break;
case 128: exp_blocksize_1 = 7; break;
case 256: exp_blocksize_1 = 8; break;
case 512: exp_blocksize_1 = 9; break;
case 1024: exp_blocksize_1 = 10; break;
case 2048: exp_blocksize_1 = 11; break;
case 4096: exp_blocksize_1 = 12; break;
case 8192: exp_blocksize_1 = 13; break;
default: exp_blocksize_1 = 0;
}
cfg->blocksize_0_exp = exp_blocksize_0;
cfg->blocksize_1_exp = exp_blocksize_1;
}
bool load_header_packet(STREAMFILE* sf, vorbis_custom_codec_data* data, uint32_t packet_size, int packet_skip, uint32_t* p_offset) {
@ -90,4 +76,5 @@ bool load_header_packet(STREAMFILE* sf, vorbis_custom_codec_data* data, uint32_t
fail:
return false;
}
#endif/* VGM_USE_VORBIS */
#endif

View file

@ -3,9 +3,9 @@
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
#define FSB_VORBIS_USE_PRECOMPILED_FVS 1 /* if enabled vgmstream weights ~600kb more but doesn't need external .fvs packets */
#if FSB_VORBIS_USE_PRECOMPILED_FVS
#include "vorbis_custom_data_fsb.h"
// if enabled vgmstream weights ~600kb more but doesn't need external setup packets
#ifndef VGM_DISABLE_CODEBOOKS
#include "libs/vorbis_codebooks_fsb.h"
#endif
@ -15,11 +15,6 @@
static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
#if !(FSB_VORBIS_USE_PRECOMPILED_FVS)
static int load_fvs_file(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
#endif
static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
/* **************************************************************************** */
/* EXTERNAL API */
@ -32,11 +27,13 @@ static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREA
* fsb-vorbis-extractor (https://github.com/tmiasko/fsb-vorbis-extractor).
*/
int vorbis_custom_setup_init_fsb(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data) {
vorbis_custom_config cfg = data->config;
vorbis_custom_config* cfg = &data->config;
load_blocksizes(&cfg, 256, 2048); /* FSB default */
// load FSB default blocksizes
cfg->blocksize_0_exp = vorbis_get_blocksize_exp(2048); //long
cfg->blocksize_1_exp = vorbis_get_blocksize_exp(256); //short
data->op.bytes = build_header_identification(data->buffer, data->buffer_size, &cfg);
data->op.bytes = build_header_identification(data->buffer, data->buffer_size, cfg);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) /* identification packet */
goto fail;
@ -44,7 +41,7 @@ int vorbis_custom_setup_init_fsb(STREAMFILE* sf, off_t start_offset, vorbis_cust
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) /* comment packet */
goto fail;
data->op.bytes = build_header_setup(data->buffer, data->buffer_size, cfg.setup_id, sf);
data->op.bytes = build_header_setup(data->buffer, data->buffer_size, cfg->setup_id, sf);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) /* setup packet */
goto fail;
@ -77,27 +74,7 @@ fail:
/* INTERNAL HELPERS */
/* **************************************************************************** */
static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
int bytes;
/* try to locate from the precompiled list */
bytes = load_fvs_array(buf, bufsize, setup_id, sf);
if (bytes)
return bytes;
#if !(FSB_VORBIS_USE_PRECOMPILED_FVS)
/* try to load from external files */
bytes = load_fvs_file(buf, bufsize, setup_id, sf);
if (bytes)
return bytes;
#endif
/* not found */
VGM_LOG("FSB Vorbis: setup_id %08x not found\n", setup_id);
return 0;
}
#if !(FSB_VORBIS_USE_PRECOMPILED_FVS)
#ifdef VGM_DISABLE_CODEBOOKS
static int load_fvs_file(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
STREAMFILE* sf_setup = NULL;
@ -143,22 +120,22 @@ fail:
}
#endif
static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
#if FSB_VORBIS_USE_PRECOMPILED_FVS
int i, list_length;
static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
int bytes;
list_length = sizeof(fvs_list) / sizeof(fvs_info);
for (i=0; i < list_length; i++) {
if (fvs_list[i].id == setup_id) {
if (fvs_list[i].size > bufsize) goto fail;
/* found: copy data as-is */
memcpy(buf,fvs_list[i].setup, fvs_list[i].size);
return fvs_list[i].size;
}
}
fail:
#ifndef VGM_DISABLE_CODEBOOKS
// locate from precompiled list
bytes = vcb_load_codebook_array(buf, bufsize, setup_id, vcb_list, vcb_list_count);
if (bytes)
return bytes;
#else
// load from external files
bytes = load_fvs_file(buf, bufsize, setup_id, sf);
if (bytes)
return bytes;
#endif
VGM_LOG("FSB Vorbis: setup_id %08x not found\n", setup_id);
return 0;
}

View file

@ -0,0 +1,237 @@
#include "vorbis_custom_decoder.h"
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
#include "libs/oor_helpers.h"
// if enabled vgmstream weights ~20kb more
#ifndef VGM_DISABLE_CODEBOOKS
#include "libs/vorbis_codebooks_oor.h"
#endif
// read current page's info and save it to persist between decode calls
static int read_page_info(vorbis_custom_codec_data* data, STREAMFILE* sf, uint32_t page_offset) {
// bitreader data
uint8_t buf[0x200]; // variable but shouldn't need to be bigger than this
int buf_size = sizeof(buf);
//TODO: this will overread a bit; it's possible to load beginning + calc size + load rest, but to simplify...
int bytes = read_streamfile(buf, page_offset, buf_size, sf);
if (bytes != buf_size) return false;
bitstream_t is_tmp;
bitstream_t* is = &is_tmp;
bm_setup(is, buf, bytes);
// oor bitstream info
oor_page_t page = {0};
oor_size_t size = {0};
oor_read_page(is, &page);
oor_read_size(is, &size);
if (!oor_validate_audio_page(&page, &size, NULL))
return 0;
if (size.packet_count >= MAX_PACKET_SIZES) {
VGM_LOG("OOR: packet count %i bigger than observed max (report)\n", size.packet_count);
return 0;
}
//TODO: maybe put into a separate struct
data->flags = page.flags;
data->packet_count = size.packet_count;
for (int i = 0; i < size.packet_count; i++) {
data->packet_size[i] = size.base_packet_size + size.variable_packet_size[i];
}
int page_size = bm_pos(is) / 8; // aligned
return page_size;
}
// Reads a single packet, which may be split into multiple pages (much like OggS).
// returns current packet size but also advances offsets, given it may need to read multiple pages.
static int read_packet(uint8_t* buf, int buf_size, vorbis_custom_codec_data* data, STREAMFILE* sf, uint32_t* p_offset) {
int read_size = 0;
// handle split packets: (similar to vorbis?)
// - OOR_FLAG_CONTINUED and is last packet of a page: packet is joined with next packet
// - OOR_FLAG_PARTIAL and is first packet of a page: packet is joined with prev packet
// - otherwise: read normally
// in OOR, packets may be split like full-size (curr page) + 0-size (next page), or splitsetup packet
while (true) {
// OOR allows 0-sized packets marked as partial, but not sure if prev packet can be 0
//if ((data->flags & OOR_FLAG_CONTINUED) && read_size == 0)
// return 0;
// new page
if (data->current_packet == 0) {
// no new pages after flag is set
if (data->flags & OOR_FLAG_EOS)
return 0;
int page_size = read_page_info(data, sf, *p_offset);
if (!page_size) return 0;
*p_offset += page_size;
if (data->packet_count == 0) {
VGM_LOG("OOR: empty page found\n");
return 0;
}
}
// read chunk to buf (note that size 0 is valid in rare cases)
int packet_size = data->packet_size[data->current_packet];
data->current_packet++;
if (data->current_packet == data->packet_count)
data->current_packet = 0;
if (read_size + packet_size > buf_size) {
VGM_LOG("OOR: packet too big\n");
return 0;
}
int bytes = read_streamfile(buf + read_size, *p_offset, packet_size, sf);
if (bytes != packet_size)
return 0;
*p_offset += packet_size;
read_size += packet_size;
// packet with continued flag must be merged with next packet (typically in next page)
bool is_last = data->current_packet == 0; // was reset above
if (!(is_last && (data->flags & OOR_FLAG_PARTIAL)))
break;
}
return read_size;
}
// read header info (1st page) and extract info to init Vorbis
static int read_header_packet(vorbis_custom_codec_data* data, STREAMFILE* sf, uint32_t* p_offset) {
// bitreader data
uint8_t* buf = data->buffer;
int hdr_size = 0x20; // variable but should be smaller
if (hdr_size > data->buffer_size)
return 0;
int bytes = read_streamfile(buf, *p_offset, hdr_size, sf);
if (bytes != hdr_size) return 0;
bitstream_t is = {0};
bm_setup(&is, buf, bytes);
// oor bitstream info
oor_page_t page = {0};
oor_header_t hdr = {0};
// header page
oor_read_page(&is, &page);
oor_read_header(&is, &hdr);
if (!oor_validate_header_page(&page, &hdr))
return 0;
// load info for header (also used for output)
vorbis_custom_config* cfg = &data->config;
cfg->channels = hdr.channels;
cfg->sample_rate = hdr.sample_rate;
cfg->blocksize_0_exp = hdr.blocksize0_exp;
cfg->blocksize_1_exp = hdr.blocksize1_exp;
cfg->last_granule = hdr.last_granule;
uint32_t packet_size = (bm_pos(&is) / 8);
*p_offset += packet_size;
return packet_size;
}
// read setup info (2nd page) and load codebooks info buf
static int build_header_setup(uint8_t* buf, int buf_size, vorbis_custom_codec_data* data, STREAMFILE* sf, uint32_t* p_offset) {
// setup info packet
int info_size = read_packet(buf, buf_size, data, sf, p_offset);
if (!info_size) return 0;
if (info_size != 0x01) //fixed mini-packet
return 0;
bitstream_t is = {0};
bm_setup(&is, data->buffer, info_size);
oor_setup_t setup = {0};
oor_read_setup(&is, &setup);
// paste missing info
if (buf_size <= 0x07)
return 0;
put_u8 (buf+0x00, 0x05); // packet_type (setup)
memcpy (buf+0x01, "vorbis", 6); // id
// read actual codebook based on prev mini-packet
int setup_size;
if (setup.codebook_id) {
#ifndef VGM_DISABLE_CODEBOOKS
// load setup from data in executables
setup_size = vcb_load_codebook_array(buf + 0x07, buf_size - 0x07, setup.codebook_id, vcb_list, vcb_list_count);
if (!setup_size) return 0;
#else
setup_size = 0;
#endif
// next packet is always 0 when codebook id is set
int empty_size = read_packet(buf + 0x07 + setup_size, buf_size - 0x07 - setup_size, data, sf, p_offset);
if (empty_size != 0) return 0;
}
else {
// load setup from data in file
setup_size = read_packet(buf + 0x07, buf_size - 0x07, data, sf, p_offset);
if (!setup_size) return 0;
}
return 0x07 + setup_size;
}
int vorbis_custom_setup_init_oor(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data) {
int ret;
uint32_t offset = start_offset;
// header
int head_size = read_header_packet(data, sf, &offset);
if (!head_size) return false;
// identification packet
data->op.bytes = build_header_identification(data->buffer, data->buffer_size, &data->config);
ret = vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op);
if (ret != 0) return false;
// comment packet
data->op.bytes = build_header_comment(data->buffer, data->buffer_size);
ret = vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op);
if (ret != 0) return false;
// setup packet
data->op.bytes = build_header_setup(data->buffer, data->buffer_size, data, sf, &offset);
ret = vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op);
if (ret != 0) return false;
data->config.data_start_offset = offset;
return true;
}
int vorbis_custom_parse_packet_oor(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data) {
uint32_t offset = stream->offset;
data->op.bytes = read_packet(data->buffer, data->buffer_size, data, stream->streamfile, &offset);
stream->offset = offset;
return data->op.bytes != 0;
}
#endif

View file

@ -4,9 +4,9 @@
#include <vorbis/codec.h>
#include "../util/bitstream_lsb.h"
#define WWISE_VORBIS_USE_PRECOMPILED_WVC 1 /* if enabled vgmstream weights ~150kb more but doesn't need external .wvc packets */
#if WWISE_VORBIS_USE_PRECOMPILED_WVC
#include "vorbis_custom_data_wwise.h"
// if enabled vgmstream weights ~150kb more but doesn't need external packets
#ifndef VGM_DISABLE_CODEBOOKS
#include "libs/vorbis_codebooks_wwise.h"
#endif
@ -30,11 +30,7 @@ static size_t rebuild_setup(uint8_t* obuf, size_t obufsize, wpacket_t* wp, STREA
static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpacket_t* wp, vorbis_custom_codec_data* data);
static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis_custom_codec_data* data, size_t packet_size, STREAMFILE* sf);
static int load_wvc(uint8_t* ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE* sf);
#if !(WWISE_VORBIS_USE_PRECOMPILED_WVC)
static int load_wvc_file(uint8_t* buf, size_t bufsize, uint32_t codebook_id, STREAMFILE* sf);
#endif
static int load_wvc_array(uint8_t* buf, size_t bufsize, uint32_t codebook_id, wwise_setup_t setup_type);
static int load_codebooks(uint8_t* ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE* sf);
/* **************************************************************************** */
@ -676,7 +672,7 @@ static int ww2ogg_codebook_library_rebuild_by_id(bitstream_t* ow, uint32_t codeb
size_t cb_size;
bitstream_t iw;
cb_size = load_wvc(ibuf,ibufsize, codebook_id, setup_type, sf);
cb_size = load_codebooks(ibuf,ibufsize, codebook_id, setup_type, sf);
if (cb_size == 0) goto fail;
bl_setup(&iw, ibuf, ibufsize);
@ -1083,28 +1079,7 @@ fail:
/* INTERNAL UTILS */
/* **************************************************************************** */
/* loads an external Wwise Vorbis Codebooks file (wvc) referenced by ID and returns size */
static int load_wvc(uint8_t* ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE* sf) {
size_t bytes;
/* try to locate from the precompiled list */
bytes = load_wvc_array(ibuf, ibufsize, codebook_id, setup_type);
if (bytes)
return bytes;
#if !(WWISE_VORBIS_USE_PRECOMPILED_WVC)
/* try to load from external file (ignoring type, just use file if found) */
bytes = load_wvc_file(ibuf, ibufsize, codebook_id, sf);
if (bytes)
return bytes;
#endif
/* not found */
VGM_LOG("Wwise Vorbis: codebook_id %04x not found\n", codebook_id);
return 0;
}
#if !(WWISE_VORBIS_USE_PRECOMPILED_WVC)
#ifdef VGM_DISABLE_CODEBOOKS
static int load_wvc_file(uint8_t* buf, size_t bufsize, uint32_t codebook_id, STREAMFILE* sf) {
STREAMFILE* sf_setup = NULL;
size_t wvc_size = 0;
@ -1149,36 +1124,25 @@ fail:
}
#endif
static int load_wvc_array(uint8_t* buf, size_t bufsize, uint32_t codebook_id, wwise_setup_t setup_type) {
#if WWISE_VORBIS_USE_PRECOMPILED_WVC
/* loads an external Wwise Vorbis Codebooks file (wvc) referenced by ID and returns size */
static int load_codebooks(uint8_t* ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE* sf) {
int bytes;
/* get pointer to array */
{
int i, list_length;
const wvc_info * wvc_list;
#ifndef VGM_DISABLE_CODEBOOKS
// locate from precompiled list
switch (setup_type) {
case WWV_EXTERNAL_CODEBOOKS:
wvc_list = wvc_list_standard;
list_length = sizeof(wvc_list_standard) / sizeof(wvc_info);
bytes = vcb_load_codebook_array(ibuf, ibufsize, codebook_id, vcb_list_standard, vcb_list_count_standard);
break;
case WWV_AOTUV603_CODEBOOKS:
wvc_list = wvc_list_aotuv603;
list_length = sizeof(wvc_list_standard) / sizeof(wvc_info);
bytes = vcb_load_codebook_array(ibuf, ibufsize, codebook_id, vcb_list_aotuv603, vcb_list_count_aotuv603);
break;
default:
goto fail;
}
for (i=0; i < list_length; i++) {
if (wvc_list[i].id == codebook_id) {
if (wvc_list[i].size > bufsize) goto fail;
/* found: copy data as-is */
memcpy(buf,wvc_list[i].codebook, wvc_list[i].size);
return wvc_list[i].size;
}
}
return 0;
}
if (bytes)
return bytes;
// this can be used with 1:1 dump of the codebook file
#if 0
@ -1204,8 +1168,14 @@ static int load_wvc_array(uint8_t* buf, size_t bufsize, uint32_t codebook_id, ww
}
#endif
fail:
#else
// load from external files
bytes = load_wvc_file(ibuf, ibufsize, codebook_id, sf);
if (bytes)
return bytes;
#endif
VGM_LOG("Wwise Vorbis: codebook_id %04x not found\n", codebook_id);
return 0;
}

View file

@ -350,6 +350,7 @@ static const char* extension_list[] = {
"mi4", //fake extension for .mib (renamed, to be removed)
"mib",
"mic",
"mio",
"mnstr",
"mogg",
//"m4a", //common
@ -418,6 +419,7 @@ static const char* extension_list[] = {
"ogv",
"oma", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
"omu",
"oor",
"opu",
//"opus", //common
"opusx",
@ -667,7 +669,6 @@ static const char* extension_list[] = {
"wic", //txth/reserved [Road Rash (SAT)-videos]
"wip", //txth/reserved [Colin McRae DiRT (PC)]
"wlv", //txth/reserved [ToeJam & Earl III: Mission to Earth (DC)]
"wmus", //fake extension (to be removed)
"wp2",
"wpd",
"wsd",
@ -924,7 +925,9 @@ static const coding_info coding_info_list[] = {
{coding_TAC, "tri-Ace Codec"},
{coding_ICE_RANGE, "Inti Creates Range Codec"},
{coding_ICE_DCT, "Inti Creates DCT Codec"},
{coding_KA1A, "Koei Tecmo KA1A Codec"},
{coding_KA1A, "Koei Tecmo KA1A"},
{coding_UBI_MPEG, "Ubisoft MPEG"},
{coding_MIO, "Entis MIO"},
#ifdef VGM_USE_VORBIS
{coding_OGG_VORBIS, "Ogg Vorbis"},
@ -1178,7 +1181,6 @@ static const meta_info meta_info_list[] = {
{meta_PS2_SND, "Might and Magic SSND Header"},
{meta_SMSS, "Treasure SMSS header"},
{meta_ADS_MIDWAY, "Midway ADS header"},
{meta_PS2_MCG, "Gunvari MCG Header"},
{meta_ZSD, "Konami ZSD header"},
{meta_REDSPARK, "RedSpark header"},
{meta_RAGE_AUD, "Rockstar AUD header"},
@ -1214,7 +1216,7 @@ static const meta_info meta_info_list[] = {
{meta_WB, "Triangle Service .WB header"},
{meta_S14, "Namco .S14 raw header"},
{meta_SSS, "Namco .SSS raw header"},
{meta_PS2_GCM, "Namco GCM header"},
{meta_MCG, "Namco MCG header"},
{meta_SMPL, "Skonec SMPL header"},
{meta_MSA, "Success .MSA header"},
{meta_VOI, "Irem .VOI header"},
@ -1250,7 +1252,6 @@ static const meta_info meta_info_list[] = {
{meta_LSF_N1NJ4N, "Gizmondo Studios Helsingborg LSF header"},
{meta_XWAV, "feelplus XWAV header"},
{meta_RAW_SNDS, "PC .snds raw header"},
{meta_PS2_WMUS, "assumed The Warriors Sony ADPCM by .wmus extension"},
{meta_HYPERSCAN_KVAG, "Mattel Hyperscan KVAG"},
{meta_PSND, "Polarbit PSND header"},
{meta_ADP_WILDFIRE, "Wildfire ADP! header"},
@ -1473,7 +1474,9 @@ static const meta_info meta_info_list[] = {
{meta_XABP, "cavia XABp header"},
{meta_I3DS, "Codemasters i3DS header"},
{meta_AXHD, "Angel Studios AXHD header"},
{meta_SHAA, "Nintendo Alarmo SHAA header"}
{meta_SHAA, "Nintendo SHAA header"},
{meta_OOR, "age .OOR header"},
{meta_MIO, "Entis .MIO header"},
};
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {

View file

@ -18,9 +18,9 @@
* This may make the API a bit odd, will probably improve later. Probably.
*
* Notes:
* - now there is an API, internals (vgmstream.h) may change in the future so avoid accesing them
* - now there is an API, internals (vgmstream.h) will change in the future so avoid accesing them
* - some details described in the API may not happen at the moment (defined for future changes)
* - uses long-winded libvgmstream_* names since internals alredy use the vgmstream_* 'namespace', #define as needed
* - uses long-winded libvgmstream_* names since internals alredy use the vgmstream_* 'namespace', #define if needed
* - c-strings should be in UTF-8
*/
@ -71,20 +71,20 @@ LIBVGMSTREAM_API uint32_t libvgmstream_get_version(void);
/*****************************************************************************/
/* DECODE */
/* interleaved samples: buf[0]=ch0, buf[1]=ch1, buf[2]=ch0, buf[3]=ch0, ... */
/* available sample formats, interleaved: buf[0]=ch0, buf[1]=ch1, buf[2]=ch0, buf[3]=ch0, ... */
typedef enum {
LIBVGMSTREAM_SAMPLE_PCM16 = 1,
LIBVGMSTREAM_SAMPLE_PCM24 = 2,
LIBVGMSTREAM_SAMPLE_PCM32 = 3,
LIBVGMSTREAM_SAMPLE_FLOAT = 4,
} libvgmstream_sample_t;
LIBVGMSTREAM_SFMT_PCM16 = 1,
//LIBVGMSTREAM_SFMT_PCM24 = 2,
//LIBVGMSTREAM_SFMT_PCM32 = 3,
LIBVGMSTREAM_SFMT_FLOAT = 4,
} libvgmstream_sfmt_t;
/* current song info, may be copied around (values are info-only) */
typedef struct {
/* main (always set) */
int channels; // output channels
int sample_rate; // output sample rate
libvgmstream_sample_t sample_type; // output buffer's sample type
libvgmstream_sfmt_t sample_format; // output buffer's sample type
int sample_size; // derived from sample_type (pcm16=0x02, float=0x04, etc)
/* extra info (may be 0 if not known or not relevant) */
@ -126,8 +126,8 @@ typedef struct {
// query description and since libvgmstream returns its own copy it shouldn't be too much of a problem
// ** (may be separated later)
int format_id; // when reopening subfiles or similar formats without checking other all possible formats
// ** this value WILL change without warning between vgmstream versions/commits, but usually only add
int format_id; // current format's ID (can be set when reopening streams to load a particular format)
// ** this value WILL change without warning between vgmstream versions/commits
} libvgmstream_format_t;
@ -165,6 +165,7 @@ LIBVGMSTREAM_API void libvgmstream_free(libvgmstream_t* lib);
/* configures how vgmstream behaves internally when playing a file */
typedef struct {
bool disable_config_override; // ignore forced (TXTP) config
bool allow_play_forever; // must allow manually as some cases a TXTP may set loop forever but client may not handle it
@ -174,46 +175,39 @@ typedef struct {
bool really_force_loop; // forces full loops (0..samples) even if file has loop points
bool ignore_fade; // don't fade after N loops and play remaning stream (for files with outros)
double loop_count; // target loops (values like 1.5 are ok)
double loop_count; // target loops (values like 1.5 are ok); defaults to 1; set to -1 to remove the loop section
double fade_time; // fade period after target loops
double fade_delay; // fade delay after target loops
int stereo_track; // forces vgmstream to decode one 2ch+2ch+2ch... 'track' and discard other channels, where 0 = disabled, 1..N = Nth track
int auto_downmix_channels; // downmix if vgmstream's channels are higher than value
// ** for players that can only handle N channels
// ** this type of downmixing is very simplistic and not recommended
bool force_pcm16; // forces output buffer to be remixed into PCM16
bool force_float; // forces output buffer to be remixed into float
libvgmstream_sfmt_t force_sfmt; // forces output buffer to be remixed into some sample format
//int format_id; // force a format (for example when loading new subsong of the same archive, for a minuscule speed up)
// // ** only applies when called before _open_stream
} libvgmstream_config_t;
/* pass default config, that will be applied to song on open
* - invalid config or complex cases (ex. some TXTP) may ignore these settings
* - should be called without a song loaded (before _open or after _close)
* - without config vgmstream will decode the current stream once
/* optionally pass config to apply to next _open_stream (or current stream if already loaded and not setup previously)
* - some settings may be ignored in invalid or complex cases (ex. TXTP with pre-configured options)
* - once config is applied to current stream new _setup calls only apply to next _open_stream
* - pass NULL to clear current config
* - remember config may change format info like channels or output format (recheck if calling after loading song)
*/
LIBVGMSTREAM_API void libvgmstream_setup(libvgmstream_t* lib, libvgmstream_config_t* cfg);
/* configures how vgmstream opens the format */
typedef struct {
libstreamfile_t* libsf; // custom IO streamfile that provides reader info for vgmstream
// ** not needed after _open and should be closed, as vgmstream re-opens its own SFs internally as needed
int subsong_index; // target subsong (1..N) or 0 = default/first
// ** to check if a file has subsongs, _open first + check format->total_subsongs (then _open 2nd, 3rd, etc)
int format_id; // force a format (for example when loading new subsong of the same archive)
int stereo_track; // forces vgmstream to decode one 2ch+2ch+2ch... 'track' and discard other channels, where 0 = disabled, 1..N = Nth track
} libvgmstream_options_t;
/* Opens file based on config and prepares it to play if supported.
* - returns < 0 on error (file not recognised, invalid subsong index, etc)
* - will close currently loaded song if needed
* - libsf (custom IO) is not needed after _open and should be closed, as vgmstream re-opens as needed
* - subsong can be 1..N or 0 = default/first
* ** to check if a file has subsongs, _open default + check format->total_subsongs (then _open Nth)
*/
LIBVGMSTREAM_API int libvgmstream_open_stream(libvgmstream_t* lib, libvgmstream_options_t* open_options);
LIBVGMSTREAM_API int libvgmstream_open_stream(libvgmstream_t* lib, libstreamfile_t* libsf, int subsong);
/* Closes current song; may still use libvgmstream to open other songs
*/
@ -222,6 +216,7 @@ LIBVGMSTREAM_API void libvgmstream_close_stream(libvgmstream_t* lib);
/* Decodes next batch of samples
* - vgmstream supplies its own buffer, updated on lib->decoder->* values (may change between calls)
* - on last call will return samples + set flag lib->decoder->done (must handle last buf before quitting)
* - returns < 0 on error
*/
LIBVGMSTREAM_API int libvgmstream_render(libvgmstream_t* lib);
@ -248,6 +243,10 @@ LIBVGMSTREAM_API void libvgmstream_seek(libvgmstream_t* lib, int64_t sample);
LIBVGMSTREAM_API void libvgmstream_reset(libvgmstream_t* lib);
/* Helper: calls _init + _setup + _open_stream
*/
LIBVGMSTREAM_API libvgmstream_t* libvgmstream_create(libstreamfile_t* libsf, int subsong, libvgmstream_config_t* cfg);
/*****************************************************************************/
/* HELPERS */
@ -259,29 +258,25 @@ typedef enum {
LIBVGMSTREAM_LOG_LEVEL_NONE = 100,
} libvgmstream_loglevel_t;
typedef struct {
libvgmstream_loglevel_t level; // log level
void (*callback)(int level, const char* str); // log callback
bool stdout_callback; // use default log callback rather than user supplied
} libvgmstream_log_t;
/* Defines a global log callback, as vgmstream sometimes communicates format issues to the user.
* - note that log is currently set globally rather than per libvgmstream_t
* - call with LOG_LEVEL_NONE to disable current callback
* - call with NULL callback to use default stdout callback
*/
LIBVGMSTREAM_API void libvgmstream_set_log(libvgmstream_log_t* cfg);
LIBVGMSTREAM_API void libvgmstream_set_log(libvgmstream_loglevel_t level, void (*callback)(int level, const char* str));
/* Returns a list of supported extensions (WARNING: it's pretty big), such as "adx", "dsp", etc.
* Mainly for plugins that want to know which extensions are supported.
* - returns NULL if no size is provided
*/
LIBVGMSTREAM_API const char** libvgmstream_get_extensions(size_t* size);
LIBVGMSTREAM_API const char** libvgmstream_get_extensions(int* size);
/* Same as above, buf returns a list what vgmstream considers "common" formats (such as "wav", "ogg"),
* which usually one doesn't want to associate to vgmstream.
* - returns NULL if no size is provided
*/
LIBVGMSTREAM_API const char** libvgmstream_get_common_extensions(size_t* size);
LIBVGMSTREAM_API const char** libvgmstream_get_common_extensions(int* size);
typedef struct {
@ -301,7 +296,7 @@ LIBVGMSTREAM_API bool libvgmstream_is_valid(const char* filename, libvgmstream_v
typedef struct {
bool force_title; // TODO: what was this for?
bool force_title; // force stream name as title (by default it may be hiddedn if file has no subsongs)
bool subsong_range; // print a range of possible subsongs after title 'filename#1~N'
bool remove_extension; // remove extension from passed filename
bool remove_archive; // remove '(archive)|(subfile)' format of some plugins
@ -350,11 +345,13 @@ LIBVGMSTREAM_API void libvgmstream_tags_find(libvgmstream_tags_t* tags, const ch
/* Extracts next valid tag in tagfile to key/val.
* - returns false if no more tags are found (meant to be called repeatedly until false)
* - key/values are trimmed of beginning/end whitespaces and values are in UTF-8
* - key/values are trimmed of beginning/end whitespaces and values are UTF-8
*/
LIBVGMSTREAM_API bool libvgmstream_tags_next_tag(libvgmstream_tags_t* tags);
/* Closes tags. */
/* Closes tags.
* - passed libsf is not closed
*/
LIBVGMSTREAM_API void libvgmstream_tags_free(libvgmstream_tags_t* tags);

View file

@ -13,34 +13,23 @@
*/
enum {
LIBSTREAMFILE_SEEK_SET = 0,
LIBSTREAMFILE_SEEK_CUR = 1,
LIBSTREAMFILE_SEEK_END = 2,
//LIBSTREAMFILE_SEEK_GET_OFFSET = 3,
//LIBSTREAMFILE_SEEK_GET_SIZE = 5,
};
// should be "libvgmstream_streamfile_t" but it was getting unwieldly
typedef struct libstreamfile_t {
//uint32_t flags; // info flags for vgmstream
void* user_data; // any internal structure
/* read 'length' data at internal offset to 'dst'
/* read 'length' data at 'offset' to 'dst'
* - assumes 0 = failure/EOF
* - note that vgmstream needs to seek + read from arbitrary offset (non-linearly) fairly often
*/
int (*read)(void* user_data, uint8_t* dst, int dst_size);
/* seek to offset
* - note that vgmstream needs to seek + read fairly often (to be optimized someday)
*/
int64_t (*seek)(void* user_data, int64_t offset, int whence);
int (*read)(void* user_data, uint8_t* dst, int64_t offset, int length);
/* get max offset (typically for checks or sample calculations)
*/
int64_t (*get_size)(void* user_data);
/* get current filename (used to open same or other streamfiles and heuristics; no need to be a real path)
/* get current filename
* - used to open same or other streamfiles and heuristics; no need to be a real path but extension matters
*/
const char* (*get_name)(void* user_data);
@ -49,13 +38,14 @@ typedef struct libstreamfile_t {
*/
struct libstreamfile_t* (*open)(void* user_data, const char* filename);
/* free current SF */
/* free current SF
*/
void (*close)(struct libstreamfile_t* libsf);
} libstreamfile_t;
/* helper */
/* helpers */
static inline void libstreamfile_close(libstreamfile_t* libsf) {
if (!libsf || !libsf->close)
return;

View file

@ -0,0 +1,57 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
/* .2dx - Konami/Bemani beatmania IIDX container [beatmania IIDX 9th Style (AC) - beatmania IIDX 15 DJ TROOPERS (AC)] */
VGMSTREAM* init_vgmstream_2dx(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
int target_subsong = sf->stream_index, total_subsongs;
uint32_t meta_offset, table_offset, subfile_offset, subfile_size;
/* checks */
if (!check_extensions(sf, "2dx"))
goto fail;
/* Check for leftover crypto header */
/*
if (read_u32be(0x00, sf) == 0x25654E63 || //IIDX 9th Style
read_u32be(0x00, sf) == 0x25653130 || //IIDX 10th Style
read_u32be(0x00, sf) == 0x25653131 || //IIDX 11 RED
read_u32be(0x00, sf) == 0x25653132 || //IIDX 12 HAPPY SKY
read_u32be(0x00, sf) == 0x25686964 || //IIDX 15 DJ TROOPERS
read_u32be(0x00, sf) == 0x25694F30) //IIDX 16 EMPRESS
meta_offset = 0x18;
else */
meta_offset = 0x10;
table_offset = meta_offset + 0x38;
if (target_subsong == 0) target_subsong = 1;
total_subsongs = read_u32le(meta_offset + 0x4,sf);
if (target_subsong > total_subsongs)
goto fail;
subfile_offset = read_u32le(table_offset + 0x04 * (target_subsong - 1), sf);
subfile_size = read_u32le(subfile_offset + 0x8,sf) + 0x18;
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "2dx9");
if (!temp_sf) goto fail;
temp_sf->stream_index = 1;
vgmstream = init_vgmstream_2dx9(temp_sf);
if (!vgmstream) goto fail;
if (vgmstream->num_streams > 1)
goto fail;
vgmstream->num_streams = total_subsongs;
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -70,27 +70,27 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
off_t start_offset = 0, coef_offset = 0;
uint32_t aifx_size, file_size;
coding_t coding_type = 0;
int channels = 0, sample_count = 0, sample_size = 0, sample_rate = 0;
int interleave = 0;
int loop_flag = 0;
int32_t loop_start = 0, loop_end = 0;
int is_aiff_ext = 0, is_aifc_ext = 0, is_aiff = 0, is_aifc = 0;
int fver_found = 0, comm_found = 0, data_found = 0;
off_t mark_offset = 0, inst_offset = 0;
/* checks */
if (!is_id32be(0x00,sf, "FORM"))
return NULL;
int channels = 0, sample_count = 0, sample_size = 0, sample_rate = 0;
int interleave = 0;
int loop_flag = 0;
int32_t loop_start = 0, loop_end = 0;
off_t mark_offset = 0, inst_offset = 0;
bool is_aiff_ext = false, is_aifc_ext = false, is_aiff = false, is_aifc = false;
/* .aif: common (AIFF or AIFC)
* .wav: SimCity 3000 (Mac) (both AIFF and AIFC)
* .aiff: rare and actually AIFC (maybe renamed AIFF too) [Cro-Mag Rally (Mac)]
* (extensionless): Doom (3DO)
*
* .aifc: renamed AIFC?
* .afc: ?
* .afc: Waialae Country Club (3D0), Star Wars: Anakin's Speedway (PC)
* .cbd2: M2 games
* .bgm: Super Street Fighter II Turbo (3DO)
* .fda: Homeworld 2 (PC)
@ -106,14 +106,14 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
* .mpc: The Godfather (PC) (writercredit.mpc)
*/
if (check_extensions(sf, "aif,laif,wav,lwav,aiff,laiff,")) {
is_aifc_ext = 1;
is_aiff_ext = 1;
is_aifc_ext = true;
is_aiff_ext = true;
}
else if (check_extensions(sf, "aifc,laifc,afc,cbd2,bgm,fda,n64,xa,caf")) {
is_aifc_ext = 1;
is_aifc_ext = true;
}
else if (check_extensions(sf, "acm,adp,ai,pcm,vp6,mpc,lmpc")) {
is_aiff_ext = 1;
is_aiff_ext = true;
}
else {
return NULL;
@ -125,15 +125,15 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
/* AIFF originally allowed only PCM (non-compressed) audio, so newer AIFC was added,
* though some AIFF with other codecs exist */
if (is_id32be(0x08,sf, "AIFC")) {
if (!is_aifc_ext) goto fail;
is_aifc = 1;
if (!is_aifc_ext) return NULL;
is_aifc = true;
}
else if (is_id32be(0x08,sf, "AIFF")) {
if (!is_aiff_ext) goto fail;
is_aiff = 1;
if (!is_aiff_ext) return NULL;
is_aiff = true;
}
else {
goto fail;
return NULL;
}
/* some games have wonky sizes, selectively fix to catch bad rips and new mutations */
@ -146,31 +146,34 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
if (aifx_size + 0x08 != file_size) {
vgm_logi("AIFF: wrong reported size %x + 0x8 vs file size %x\n", aifx_size, file_size);
goto fail;
return NULL;
}
/* read through chunks to verify format and find metadata */
{
bool fver_found = false, comm_found = false, data_found = false;
off_t offset = 0x0c; /* start with first chunk within FORM */
while (offset < file_size) {
uint32_t chunk_type = read_u32be(offset + 0x00,sf);
uint32_t chunk_size = read_u32be(offset + 0x04,sf);
/* chunks must be padded to an even number of bytes but chunk
* size does not include that padding */
offset += 0x08;
if (offset + chunk_size > file_size) {
VGM_LOG("AIFF: wrong chunk_size %x + %x\n", (int)offset, chunk_size);
return NULL;
}
// Chunks must be padded to an even number of bytes but chunk size does not include that padding.
// Last chunk it may not be padded so handle after offset check (some tools only?) [Anakin's Speedway (PC)]
if (chunk_size % 2)
chunk_size++;
offset += 0x08;
if (offset + chunk_size > file_size)
goto fail;
switch(chunk_type) {
case 0x46564552: /* "FVER" (version info, officially required but some odd game ommits it [Cro-Mag Rally (Mac)]) */
if (fver_found) goto fail;
if (is_aiff) goto fail; /* plain AIFF shouldn't have */
fver_found = 1;
fver_found = true;
if (chunk_size != 4)
goto fail;
@ -181,7 +184,7 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
case 0x434F4D4D: /* "COMM" (main header) */
if (comm_found) goto fail;
comm_found = 1;
comm_found = true;
channels = read_u16be(offset + 0x00,sf);
sample_count = read_u32be(offset + 0x02,sf); /* sample_frames in theory, depends on codec */
@ -220,9 +223,10 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
case 0x434F4D50: { /* "COMP" (generic compression) */
uint8_t name_size = read_u8(offset + 0x16, sf);
if (is_str("Relic Codec v1.6", name_size, offset + 0x17, sf)) {
if (is_str("Relic Codec v1.6", name_size, offset + 0x17, sf)) { /* Homeworld 2 (PC) */
coding_type = coding_RELIC;
sample_count = sample_count * 512;
sample_rate = 44100; // fixed output
}
else {
goto fail;
@ -235,7 +239,14 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
coding_type = coding_VADPCM;
/* N64 tools don't create FVER, but it's required by the spec (could skip the check though) */
fver_found = 1;
fver_found = true;
break;
}
case 0x76696D61: { /* "vima" [Star Wars Anakin's Speedway (PC), Star Wars Early Learning Activity Center (PC)] */
/* "Variable IMA 16 bit" */
coding_type = coding_IMUSE;
sample_rate = 22050; // field has garbage (like part of the name) consistently
break;
}
@ -267,7 +278,7 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
case 0x53534E44: /* "SSND" (main data) */
case 0x4150434D: /* "APCM" (main data for XA) */
if (data_found) goto fail;
data_found = 1;
data_found = true;
/* 00: offset (for aligment, usually 0)
* 04: block size (ex. XA: 0x914) */
@ -315,7 +326,6 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
offset += chunk_size;
}
}
if (is_aifc) {
if (/*!fver_found ||*/ !comm_found || !data_found)
@ -325,6 +335,8 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
if (!comm_found || !data_found)
goto fail;
}
}
/* read loop points */
if (inst_offset && mark_offset) {
@ -399,8 +411,6 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
vgmstream->codec_data = init_relic(channels, bitrate, sample_rate);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
vgmstream->sample_rate = 44100; /* fixed output */
break;
}
@ -421,6 +431,13 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
//vgmstream->num_samples = vadpcm_bytes_to_samples(data_size, channels); /* unneeded */
break;
case coding_IMUSE: {
vgmstream->codec_data = init_imuse_aifc(sf, start_offset, channels);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
break;
}
default:
vgmstream->layout_type = (channels > 1) ? layout_interleave : layout_none;
vgmstream->interleave_block_size = interleave;

View file

@ -6,25 +6,23 @@
/* .BAF - Bizarre Creations bank file [Blur (PS3), Project Gotham Racing 4 (X360), Geometry Wars (PC)] */
VGMSTREAM* init_vgmstream_baf(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
char bank_name[0x22+1], stream_name[0x20+1], file_name[STREAM_NAME_SIZE];
off_t start_offset, header_offset, name_offset;
size_t stream_size;
uint32_t channel_count, sample_rate, num_samples, version, codec, tracks;
int loop_flag, total_subsongs, target_subsong = sf->stream_index;
int big_endian, loop_flag, total_subsongs, target_subsong = sf->stream_index;
read_u32_t read_u32;
/* checks */
if (!is_id32be(0x00, sf, "BANK"))
goto fail;
return NULL;
if (!check_extensions(sf, "baf"))
goto fail;
return NULL;
/* use BANK size to check endianness */
if (guess_endian32(0x04,sf)) {
read_u32 = read_u32be;
} else {
read_u32 = read_u32le;
}
big_endian = guess_endian32(0x04, sf);
read_u32 = big_endian ? read_u32be : read_u32le;
/* 0x04: bank size */
version = read_u32(0x08,sf);
@ -69,7 +67,7 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
tracks = 0;
switch(codec) {
case 0x03: /* PCM16LE */
case 0x03: /* PCM16 */
switch(version) {
case 0x03: /* Geometry Wars (PC) */
sample_rate = read_u32(header_offset+0x38, sf);
@ -84,6 +82,12 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
loop_flag = read_u8(header_offset+0x4b, sf);
break;
case 0x05: /* Blur 2 (X360) */
sample_rate = read_u32(header_offset+0x40, sf);
channel_count = read_u32(header_offset+0x48, sf);
loop_flag = read_u8(header_offset+0x50, sf) != 0;
break;
default:
goto fail;
}
@ -93,14 +97,14 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
case 0x07: /* PSX ADPCM (0x21 frame size) */
if (version == 0x04 && read_u32(header_offset + 0x3c, sf) != 0) {
/* Blur (Prototype) (PS3) */
/* The Club (PS3), Blur (Prototype) (PS3) */
sample_rate = read_u32(header_offset+0x3c, sf);
channel_count = read_u32(header_offset+0x44, sf);
loop_flag = read_u8(header_offset+0x4b, sf);
/* mini-header at the start of the stream */
num_samples = read_u32le(start_offset+0x04, sf) / 0x02; /* PCM size? */
start_offset += read_u32le(start_offset+0x00, sf);
num_samples = read_u32le(start_offset+0x04, sf) / channel_count;
start_offset += read_u32le(start_offset+0x00, sf); /* 0x08 */
break;
}
@ -117,14 +121,16 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
channel_count = channel_count * tracks;
}
break;
default:
goto fail;
}
break;
case 0x08: /* XMA1 */
case 0x09: /* XMA2 */
switch(version) {
case 0x04: /* Project Gotham Racing (X360) */
case 0x04: /* Project Gotham Racing 4 (X360) */
sample_rate = read_u32(header_offset+0x3c, sf);
channel_count = read_u32(header_offset+0x44, sf);
loop_flag = read_u8(header_offset+0x54, sf) != 0;
@ -160,7 +166,7 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
switch(codec) {
case 0x03:
vgmstream->coding_type = coding_PCM16LE;
vgmstream->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
@ -180,30 +186,52 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
break;
#ifdef VGM_USE_FFMPEG
case 0x08: {
vgmstream->codec_data = init_ffmpeg_xma1_raw(sf, start_offset, stream_size, vgmstream->channels, vgmstream->sample_rate, 0);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
case 0x08:
case 0x09: {
int is_xma1 = (codec == 0x08);
int block_size = 0x10000;
/* need to manually find sample offsets, it was a thing with XMA1 */
{
ms_sample_data msd = {0};
msd.xma_version = 1;
msd.xma_version = is_xma1 ? 1 : 2;
msd.channels = channel_count;
msd.data_offset = start_offset;
msd.data_size = stream_size;
msd.loop_flag = loop_flag;
switch(version) {
case 0x04:
msd.loop_start_b = read_u32(header_offset+0x4c, sf);
msd.loop_end_b = read_u32(header_offset+0x50, sf);
msd.loop_start_subframe = (read_u8(header_offset+0x55, sf) >> 0) & 0x0f;
msd.loop_end_subframe = (read_u8(header_offset+0x55, sf) >> 4) & 0x0f;
break;
case 0x05:
msd.loop_start_b = read_u32(header_offset+0x50, sf);
msd.loop_end_b = read_u32(header_offset+0x54, sf);
msd.loop_start_subframe = (read_u8(header_offset+0x59, sf) >> 0) & 0x0f;
msd.loop_end_subframe = (read_u8(header_offset+0x59, sf) >> 4) & 0x0f;
break;
default:
goto fail;
}
xma_get_samples(&msd, sf);
vgmstream->num_samples = msd.num_samples; /* also at 0x58, but unreliable? */
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = msd.num_samples; /* also at 0x58(v4)/0x5C(v5) for XMA1, but unreliable? */
vgmstream->loop_start_sample = msd.loop_start_sample;
vgmstream->loop_end_sample = msd.loop_end_sample;
vgmstream->codec_data = is_xma1
? init_ffmpeg_xma1_raw(sf, start_offset, stream_size, vgmstream->channels, vgmstream->sample_rate, 0)
: init_ffmpeg_xma2_raw(sf, start_offset, stream_size, vgmstream->num_samples, vgmstream->channels, vgmstream->sample_rate, block_size, 0);
if (!vgmstream->codec_data) goto fail;
}
xma_fix_raw_samples_ch(vgmstream, sf, start_offset, stream_size, channel_count, 1,1);
@ -216,7 +244,14 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
goto fail;
}
read_string(vgmstream->stream_name,0x20+1, name_offset,sf);
read_string(bank_name, sizeof(bank_name), (version == 0x03) ? 0x11 : 0x12, sf);
read_string(stream_name, sizeof(stream_name), name_offset, sf);
get_streamfile_basename(sf, file_name, STREAM_NAME_SIZE);
if (bank_name[0] && strcmp(file_name, bank_name) != 0)
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s/%s", bank_name, stream_name);
else
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s", stream_name);
if (!vgmstream_open_stream(vgmstream, sf, start_offset))

View file

@ -724,8 +724,10 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) {
/* searches the chunk until it finds the target name/index, or breaks at empty name */
while (read_u8(stream_name_offset, sf)) {
/* in case it goes somewhere out of bounds unexpectedly */
if (((read_u8(stream_name_offset + 0x00, sf) + read_u8(stream_name_offset + 0x04, sf) +
read_u8(stream_name_offset + 0x08, sf) + read_u8(stream_name_offset + 0x0C, sf)) & 0x1F) != i)
if (((read_u8(stream_name_offset + 0x00, sf)
+ read_u8(stream_name_offset + 0x04, sf)
+ read_u8(stream_name_offset + 0x08, sf)
+ read_u8(stream_name_offset + 0x0C, sf)) & 0x1F) != i)
goto fail;
if (read_u16(stream_name_offset + 0x10, sf) == table4_entry_id) {
read_string(h->stream_name, STREAM_NAME_SIZE, stream_name_offset, sf);
@ -735,7 +737,7 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) {
stream_name_offset += 0x14;
}
}
//goto fail; /* didn't find any valid index? */
goto fail; /* didn't find any valid index? */
loop_break:
break;

View file

@ -10,17 +10,16 @@ VGMSTREAM* init_vgmstream_compresswave(STREAMFILE *sf) {
/* checks */
if (!check_extensions(sf, "cwav"))
goto fail;
if (!is_id64be(0x00,sf, "CmpWave\0"))
goto fail;
return NULL;
if (!check_extensions(sf, "cwav"))
return NULL;
channels = 2; /* always, header channels is internal config */
start_offset = 0x00;
loop_flag = 1; //read_u8(0x430, sf) != 0; /* wrong count, see below */
/* codec allows to use a cipher value, not seen */
/* there is also title and artist, but default to "UnTitled" / "NoName" */
loop_flag = true; //read_u8(0x430, sf) != 0; /* wrong count, see below */
// codec allows to use a cipher value, not seen
// there is also title and artist, but default to "UnTitled" / "NoName"
/* build the VGMSTREAM */
@ -28,10 +27,9 @@ VGMSTREAM* init_vgmstream_compresswave(STREAMFILE *sf) {
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_COMPRESSWAVE;
vgmstream->sample_rate = 44100; /* always, header rate is internal config */
/* in PCM bytes */
vgmstream->num_samples = read_u64le(0x418, sf) / sizeof(int16_t) / channels;
/* known files have wrong loop values and just repeat */
vgmstream->sample_rate = 44100; // always, header rate is internal config
vgmstream->num_samples = read_u64le(0x418, sf) / sizeof(int16_t) / channels; // in PCM bytes
// known files have wrong loop values and just repeat
vgmstream->loop_start_sample = 0; //read_u64le(0x420, sf) / sizeof(int16_t) / channels;
vgmstream->loop_end_sample = vgmstream->num_samples; //read_u64le(0x428, sf) / sizeof(int16_t) / channels;

View file

@ -385,6 +385,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
mpeg_custom_config cfg = {0};
cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */
cfg.data_size = fsb5.stream_offset + fsb5.stream_size;
vgmstream->codec_data = init_mpeg_custom(sb, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
if (!vgmstream->codec_data) goto fail;

View file

@ -70,6 +70,7 @@ static const fsbkey_info fsbkey_list[] = {
{ MODE_FSB5, FSBKEY_ADD("3cfe772db5b55b806541d3faf894020e") }, // Final Fantasy XV: War for Eos (Android)
{ MODE_FSB5, FSBKEY_ADD("aj#$kLucf2lh}eqh") }, // Forza Motorsport 2023 (PC)
{ MODE_FSB4, FSBKEY_ADD("dpdjeoqkr") }, // AirRider CrazyRacing (PC)
{ MODE_FSB5, FSBKEY_ADD("weareAbsolutelyUnsure2018") }, // Wanderstop (PC)
/* some games use a key per file, generated from the filename
* (could add all of them but there are a lot of songs, so external .fsbkey are probably better) */

View file

@ -111,7 +111,7 @@ VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) {
/* Assumed mappings; seems correct vs Atom Viewer, that lists L/R/C/LFE/LS/RS and downmixes HCAs like that.
* USM HCA's seem to be L/R/SL/SR/C/LFE though (probably reordered at USM level, no detection done in Atom Viewer). */
{
if (vgmstream->channels <= 8) { // 8 is max but just in case
static const uint32_t hca_mappings[] = {
0,
mapping_MONO,

View file

@ -518,6 +518,7 @@ static const hcakey_info hcakey_list[] = {
{0x0c59613fc788cec7}, // music_0210025
{0xf61a0cfac4072903}, // music_0210026
{0xa316e41cc9303921}, // music_0210027
{0x61933afefe5f14c3}, // music_0210028
{0x15bb78c31db0a0b6}, // music_0220001
{0x59b1257242c40109}, // music_0220002
{0xdb402bd08d522f34}, // music_0220003
@ -711,6 +712,7 @@ static const hcakey_info hcakey_list[] = {
{0x9f37cb27968428fa}, // music_0610027
{0x36024c4a109520ec}, // music_0610028
{0x758ad666ba171bd7}, // music_0610029
{0xe3c90dcaed524e49}, // music_0610030
{0x8258ddd6a1d0849b}, // music_0620001
{0x1dd21a1244ca12f1}, // music_0620002
{0xfdec74b23d8b494b}, // music_0620003
@ -1267,6 +1269,11 @@ static const hcakey_info hcakey_list[] = {
{0x34c0f6db642145a0}, // music_5050307
{0xb7ecea9165c448da}, // music_5050308
{0xa5e9bd945c5caf2c}, // music_5050309
{0x91ff4aedae9ce2c3}, // music_5050313
{0xeaaa417505d65dd1}, // music_5050322
{0x591899d025c3beb7}, // music_5050323
{0xa57678c62ef99124}, // music_5050324
{0x925f360a8ccb4c32}, // music_5050325
{0x52c250eade92393b}, // music_9010001
{0xf66e6bb5b0599b07}, // music_9010002
{0x8582b5a60dbbf948}, // music_9010003
@ -1529,6 +1536,9 @@ static const hcakey_info hcakey_list[] = {
// Freedom Wars Remastered (Switch)
{3258660547165106863}, // 2D391680A55B32AF
// Suikoden I & II HD Remaster (PC)
{14510296783270449627u}, // C95EEE0BA85411DB
};
#endif

View file

@ -136,7 +136,7 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
vgmstream->coding_type = coding_IMUSE;
vgmstream->layout_type = layout_none;
vgmstream->codec_data = init_imuse(sf, channels);
vgmstream->codec_data = init_imuse_mcomp(sf, channels);
if (!vgmstream->codec_data) goto fail;
if (name_offset > 0)

View file

@ -1,64 +1,32 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
#include "../util/meta_utils.h"
/* KRAW (from Geometry Wars - Galaxies) */
VGMSTREAM * init_vgmstream_kraw(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
/* KRAW - from Geometry Wars: Galaxies (Wii) */
VGMSTREAM* init_vgmstream_kraw(STREAMFILE* sf) {
/* 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;
vgmstream->allow_dual_stereo = 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+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
/* checks */
if (!is_id32be(0x00,sf, "kRAW"))
return NULL;
// .kRAW: actual extension
if (!check_extensions(sf, "kraw"))
return NULL;
meta_header_t h = {0};
h.data_size = read_u32be(0x04,sf);
h.meta = meta_KRAW;
h.stream_offset = 0x08;
h.channels = 1;
h.sample_rate = 32000;
h.num_samples = pcm16_bytes_to_samples(h.data_size, h.channels);
h.allow_dual_stereo = true;
h.coding = coding_PCM16BE;
h.layout = layout_none;
h.open_stream = true;
h.sf = sf;
return alloc_metastream(&h);
}

View file

@ -512,7 +512,6 @@ static bool parse_ktsr_subfile(ktsr_header_t* ktsr, STREAMFILE* sf, uint32_t off
ktsr->stream_sizes[0] = read_u32le(offset + 0x38, sf);
}
ktsr->is_external = true;
VGM_LOG("k=%x\n", ktsr->codec_value);
break;
case 0x41FDBD4E: /* internal [Attack on Titan: Wings of Freedom (Vita)] */

View file

@ -8,7 +8,7 @@ VGMSTREAM* init_vgmstream_lp_ap_lep(STREAMFILE* sf) {
STREAMFILE* temp_sf = NULL;
off_t start_offset;
int loop_flag, channels, sample_rate, interleave;
int32_t data_size, loop_start;
uint32_t data_size, loop_start, loop_end;
uint32_t id;
@ -25,23 +25,47 @@ VGMSTREAM* init_vgmstream_lp_ap_lep(STREAMFILE* sf) {
switch (id) {
case 0x41502020: /* "AP " */
case 0x4C502020: /* "LP " */
data_size = read_u32le(0x04,sf); // end offset after header
sample_rate = read_u32le(0x08,sf);
interleave = read_u32le(0x0c,sf);
loop_start = read_u32le(0x14,sf);
data_size = read_u32le(0x18,sf);
start_offset = read_u32le(0x1C,sf);
// 10: pan/volume?
loop_start = read_u32le(0x14,sf); // absolute
loop_end = read_u32le(0x18,sf); // end offset after header
start_offset= read_u32le(0x1C,sf); // after header
// tweak values considering (applies to both PS-ADPCM and PCM):
// - start_offset with PCM starts 0x20 before data, so must be after header (not a blank frame)
// - end offset after 0x20 usually ends when padding (0xFF) starts
// - loop end is usually the same except in PCM
// - loop start is always aligned to 0x800 (meaning no loop/0 uses 0x800 w/ start offset 0x7E0 + 0x20)
// * in PS-ADPCM start after header points to a regular frame, a bit odd since PS-ADPCM should start with blank frames
// but correct as LEP starts at 0x800 without them
start_offset += 0x20;
data_size += 0x20;
loop_end += 0x20;
data_size -= start_offset;
loop_end -= start_offset;
loop_start -= start_offset;
break;
case 0x4C455020: /* "LEP " */
data_size = read_u32le(0x08,sf);
case 0x4C455020: /* "LEP " (memory data?) */
// 04: config?
data_size = read_u32le(0x08,sf); // within stream
// 10: pan/volume?
sample_rate = read_u16le(0x12,sf);
loop_start = read_u32le(0x58,sf);
loop_start = read_u32le(0x58,sf); // within stream?
// 5c: loop start?
// 60+: related to loop?
// not sure if loops are absolute, but since values are not 0x800-aligned like AP/LP assuming it's not
loop_end = data_size;
interleave = 0x10;
start_offset = 0x800;
break;
default:
goto fail;
return NULL;
}
loop_flag = loop_start != 0;
@ -61,9 +85,9 @@ VGMSTREAM* init_vgmstream_lp_ap_lep(STREAMFILE* sf) {
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 16);
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channels, 16);
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels);
vgmstream->loop_start_sample = pcm16_bytes_to_samples(loop_start, channels);
vgmstream->loop_end_sample = pcm16_bytes_to_samples(loop_end, channels);
temp_sf = setup_lp_streamfile(sf, start_offset); /* encrypted/obfuscated PCM */
if (!temp_sf) goto fail;
@ -77,7 +101,7 @@ VGMSTREAM* init_vgmstream_lp_ap_lep(STREAMFILE* sf) {
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channels);
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, channels);
break;
default:

View file

@ -2,8 +2,8 @@
#include "../util.h"
#include "../coding/coding.h"
/* .GCM - from PS2 Namco games [Gunvari Collection + Time Crisis (PS2), NamCollection (PS2)] */
VGMSTREAM* init_vgmstream_ps2_gcm(STREAMFILE* sf) {
/* MCG - from PS2 Namco games [Gunvari Collection + Time Crisis (PS2), NamCollection (PS2)] */
VGMSTREAM* init_vgmstream_mcg(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
uint32_t start_offset, name_offset;
uint32_t vagp_l_offset, vagp_r_offset, track_size, data_size, channel_size;
@ -12,11 +12,10 @@ VGMSTREAM* init_vgmstream_ps2_gcm(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00,sf, "MCG\0"))
goto fail;
/* .gcm: actual extension */
return NULL;
// .gcm: actual extension
if (!check_extensions(sf, "gcm"))
goto fail;
return NULL;
/* format is two v4 "VAGp" headers then interleaved data (even for 6ch files) */
@ -59,7 +58,7 @@ VGMSTREAM* init_vgmstream_ps2_gcm(STREAMFILE* sf) {
vgmstream = allocate_vgmstream(channels, 0);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PS2_GCM;
vgmstream->meta_type = meta_MCG;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ps_bytes_to_samples(channel_size, 1);
vgmstream->coding_type = coding_PSX;

View file

@ -366,8 +366,6 @@ VGMSTREAM* init_vgmstream_smss(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ads_midway(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_mcg(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_zsd(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_vgs_ps(STREAMFILE *streamFile);
@ -431,7 +429,7 @@ VGMSTREAM* init_vgmstream_wb(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_raw_s14_sss(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_gcm(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_mcg(STREAMFILE* streamFile);
VGMSTREAM* init_vgmstream_smpl(STREAMFILE* sf);
@ -490,8 +488,6 @@ VGMSTREAM * init_vgmstream_xwav_old(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_raw_snds(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_wmus(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_hyperscan_kvag(STREAMFILE* streamFile);
VGMSTREAM* init_vgmstream_psnd(STREAMFILE* sf);
@ -1032,4 +1028,10 @@ VGMSTREAM* init_vgmstream_shaa(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_undefind(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_oor(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_mio(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_2dx(STREAMFILE* sf);
#endif

View file

@ -0,0 +1,57 @@
#include "meta.h"
#include "../coding/coding.h"
/* .MIO - Entis's 'Music Interleaved and Orthogonal transformed' [HAYABUSA (PC), Rakuen no Kantai (PC/Android)] */
VGMSTREAM* init_vgmstream_mio(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
uint32_t start_offset;
/* checks */
if (!is_id64be(0x00,sf, "Entis\x1a\x00\x00"))
return NULL;
// all of Entis's formats have long text descriptors, will be re-checked during codec init
if (!is_id64be(0x10,sf, "Music In"))
return NULL;
if (!check_extensions(sf,"mio"))
return NULL;
// get info (abridged), could use lib though
int channels = read_s32le(0x90,sf);
int sample_rate = 44100; // there is input rate at 0x94 put output is fixed
int32_t num_samples = read_s32le(0xA0,sf);
// loops are in UTF16 tags, kinda annoying to read so get from lib below
int32_t loop_start = 0;
bool loop_flag = 1; //(loop_start > 0);
start_offset = 0x00;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_MIO;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
// .mio has multiple modes (lapped/huffman/lossless) but not that interesting to print as info
vgmstream->codec_data = init_mio(sf, &loop_start);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_MIO;
vgmstream->layout_type = layout_none;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = num_samples;
vgmstream->loop_flag = (loop_start >= 0);
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1446,7 +1446,7 @@ VGMSTREAM* init_vgmstream_dsp_wiivoice(STREAMFILE* sf) {
}
/* WIIADPCM - Exient wrapper [Need for Speed: Hot Pursuit (Wii), Angry Birds: Star Wars (WiiU)] */
/* WIIADPCM - Exient wrapper [Need for Speed: Hot Pursuit (Wii), Angry Birds: Star Wars (Wii/WiiU)] */
VGMSTREAM* init_vgmstream_dsp_wiiadpcm(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1456,18 +1456,33 @@ VGMSTREAM* init_vgmstream_dsp_wiiadpcm(STREAMFILE* sf) {
if (!check_extensions(sf, "adpcm"))
return NULL;
dspm.interleave = read_u32be(0x08,sf); /* interleave offset */
/* 0x0c: NFS = 0 when RAM (2 DSP headers), interleave size when stream (2 WIIADPCM headers)
* AB = 0 (2 WIIADPCM headers) */
dspm.channels = (dspm.interleave ? 2 : 1);
// no good flag so use v2's loop+type as other values are easy to mistake
int test = read_u32be(0x2c,sf);
if (!(test == 0x00010000 || test == 0x00000000)) {
// V1 (NFSHP)
// 08: ch2 offset
// 0c: real interleave in streams (xN WIIADPCM headers), null in memory audio (xN DSP headers)
dspm.header_offset = 0x10;
dspm.max_channels = 2;
}
else {
// V2 (ABSW)
// 08-18: chN offset
// 1c: real interleave in streams (xN WIIADPCM headers), null in memory audio (xN DSP headers)
// (interleave may be set in mono too)
dspm.header_offset = 0x20;
dspm.max_channels = 6;
}
if (read_u32be(0x10,sf) != 0)
dspm.header_offset = 0x10; /* NFSHP */
else
dspm.header_offset = 0x20; /* ABSW */
dspm.channels = 1;
for (int i = 0; i < dspm.max_channels - 1; i++) {
uint32_t offset = read_u32be(0x08 + i * 0x04, sf);
if (!offset)
break;
dspm.channels += 1;
}
dspm.interleave = read_u32be(0x08,sf); // use first channel offset as interleave
if (dspm.interleave)
dspm.interleave -= dspm.header_offset;
dspm.interleave_first_skip = 0x60 + dspm.header_offset;
@ -1476,7 +1491,6 @@ VGMSTREAM* init_vgmstream_dsp_wiiadpcm(STREAMFILE* sf) {
dspm.header_spacing = dspm.interleave;
dspm.start_offset = dspm.header_offset + 0x60;
dspm.meta_type = meta_DSP_WIIADPCM;
return init_vgmstream_dsp_common(sf, &dspm);
}

View file

@ -0,0 +1,100 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
static bool is_oor(STREAMFILE* sf);
/* .OOR ("OptimizedObsforR") - rUGP/AGES engine audio [Muv-Luv (multi), Liberation Maiden SIN (PS3/Vita)] */
VGMSTREAM* init_vgmstream_oor(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
vorbis_custom_codec_data* data = NULL;
off_t start_offset;
/* checks */
if (read_u8(0x00, sf) != 0x08 && read_u32be(0x00, sf) != 0x48000000) //v0 and v1 first page headers
return NULL;
if (!check_extensions(sf, "oor"))
return NULL;
// bitpacked header, should fail during on init with bad data but do minor validations to skip some allocs
if (!is_oor(sf))
return NULL;
#ifdef VGM_USE_VORBIS
vorbis_custom_config cfg = {0}; //loads info on success
data = init_vorbis_custom(sf, 0x00, VORBIS_OOR, &cfg);
if (!data) return NULL;
start_offset = cfg.data_start_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(cfg.channels, 0);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_OOR;
vgmstream->sample_rate = cfg.sample_rate;
vgmstream->num_samples = cfg.last_granule;
vgmstream->layout_type = layout_none;
vgmstream->coding_type = coding_VORBIS_custom;
vgmstream->codec_data = data;
data = NULL;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
//TODO: improve
// v0 files don't set last granule (must be done after opening streamfiles)
if (!cfg.last_granule)
vgmstream->num_samples = vorbis_custom_get_samples(vgmstream);
#else
goto fail;
#endif
return vgmstream;
fail:
free_vorbis_custom(data);
close_vgmstream(vgmstream);
return NULL;
}
// OOR is bitpacked but try to determine if bytes look like a .oor (will fail later if we picked a wrong candidate).
static bool is_oor(STREAMFILE* sf) {
static uint8_t empty_granule[0x09];
uint8_t data[0x10] = {0};
read_streamfile(data, 0x00, sizeof(data), sf);
int page_version;
int head_pos;
if (data[0x00] == 0x48 && memcmp(data + 0x01, empty_granule, 9) == 0) {
// V1: bits 01 0010 00 + granule + header
head_pos = 0x0A;
page_version = 1;
}
else if (data[0x00] == 0x08) {
// V0: bits 00 0010 00 + header
head_pos = 0x01;
page_version = 0;
}
else {
return false;
}
uint16_t head = (data[head_pos] << 8) | data[head_pos+1];
int version = (head >> 14) & 0x03; //2b
int channels = (head >> 11) & 0x07; //3b
int sr_selector = (head >> 9) & 0x03; //3b
int srate = (head >> 1) & 0xFF; //3b
if (version != page_version || channels == 0)
return false;
if (sr_selector == 3 && srate > 10)
return false;
return true;
}

View file

@ -1,67 +0,0 @@
#include "meta.h"
#include "../util.h"
/* GUN (Gunvari Streams) */
VGMSTREAM * init_vgmstream_ps2_mcg(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("mcg",filename_extension(filename))) goto fail;
/* check header */
if (!((read_32bitBE(0x00,streamFile) == 0x4D434700) &&
(read_32bitBE(0x20,streamFile) == 0x56414770) &&
(read_32bitBE(0x50,streamFile) == 0x56414770)))
goto fail;
loop_flag = (read_32bitLE(0x34,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 = 0x80;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x30,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = read_32bitBE(0x2C,streamFile)/16*14*channel_count;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile);
vgmstream->meta_type = meta_PS2_MCG;
if (vgmstream->loop_flag)
{
vgmstream->loop_start_sample = read_32bitLE(0x34,streamFile);
vgmstream->loop_end_sample = vgmstream->num_samples;
}
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,62 +0,0 @@
#include "meta.h"
#include "../coding/coding.h"
/* VA3 - Konami / Sony Atrac3 Container [PS2 DDR Supernova 2 Arcade] */
VGMSTREAM * init_vgmstream_va3(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
uint32_t data_size;
/* check extension, case insensitive */
if (!check_extensions(streamFile, "va3"))
goto fail;
if (read_32bitBE(0x00, streamFile) != 0x21334156) /* "!3AV" */
goto fail;
/* va3 header */
start_offset = 0x800;
data_size = read_32bitLE(0x04, streamFile);// get_streamfile_size(streamFile) - start_offset;
// pretty sure 0x4 LE 32 bit is some sort of filesize...
loop_flag = 0;
//0x18 is 1... what is this?
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VA3;
vgmstream->sample_rate = read_32bitLE(0x14, streamFile);
vgmstream->num_samples = read_32bitLE(0x08, streamFile);
vgmstream->channels = channel_count;
#ifdef VGM_USE_FFMPEG
{
int block_align, encoder_delay;
block_align = 0xC0 * vgmstream->channels;
encoder_delay = 0; //todo
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
}
#else
goto fail;
#endif
/* open the file for reading */
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,102 +0,0 @@
#include "meta.h"
#include "../util.h"
//#include <windows.h>
//#include <tchar.h>
/* WMUS - Arbitrary extension chosen for The Warriors (PS2) */
VGMSTREAM * init_vgmstream_ps2_wmus(STREAMFILE *streamFile)
{
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int loop_flag = 1;
int channel_count;
off_t start_offset;
int i;
int blockCount;
int shortBlockSize;
int lastBlockLocation;
char filenameWHED[PATH_LIMIT];
STREAMFILE * streamFileWHED = NULL;
//_TCHAR szBuffer[100];
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("wmus",filename_extension(filename)))
{
goto fail;
}
/* check for .WHED file */
strcpy(filenameWHED, filename);
strcpy(filenameWHED + strlen(filenameWHED) - 4, "WHED");
streamFileWHED = streamFile->open(streamFile, filenameWHED, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!streamFileWHED)
{
goto fail;
}
/* check loopand channel */
loop_flag = 1;
channel_count = read_32bitLE(0x14, streamFileWHED);
/* 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, streamFileWHED);
vgmstream->coding_type = coding_PSX;
vgmstream->interleave_block_size = read_32bitLE(0x18, streamFileWHED);
blockCount = read_32bitLE(0x1C, streamFileWHED) * channel_count;
shortBlockSize = read_32bitLE(0x20, streamFileWHED);
vgmstream->num_samples = (vgmstream->interleave_block_size * blockCount) / 16 / channel_count * 28;
vgmstream->loop_start_sample = 0;
lastBlockLocation = (vgmstream->interleave_block_size * blockCount) - (vgmstream->interleave_block_size - shortBlockSize);
vgmstream->loop_end_sample = lastBlockLocation / 16 / channel_count * 28;
//_stprintf(szBuffer, _T("%x"), lastBlockLocation);
//MessageBox(NULL, szBuffer, _T("Foo"), MB_OK);
vgmstream->layout_type = layout_interleave;
vgmstream->meta_type = meta_PS2_WMUS;
start_offset = 0;
/* open the file for reading by each channel */
{
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=
(off_t)(start_offset+vgmstream->interleave_block_size*i);
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (streamFileWHED) close_streamfile(streamFileWHED);
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View file

@ -4,65 +4,62 @@
/* tri-Ace codec file [Star Ocean 3 (PS2), Valkyrie Profile 2 (PS2), Radiata Stories (PS2)] */
VGMSTREAM* init_vgmstream_tac(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int loop_flag, channel_count;
uint16_t loop_frame, frame_count, loop_discard, frame_last;
uint32_t info_offset, loop_offset, stream_size, file_size;
int loop_flag, channels;
off_t start_offset;
/* checks */
// file is validated on decoder init, catch simple errors (see tac_decoder_lib.h for full header)
uint32_t info_offset = read_u32le(0x00,sf);
if (info_offset < 0x20 || info_offset > 0x4E000) /* offset points to value inside first "block" */
return NULL;
/* (extensionless): bigfiles have no known names (libs calls mention "St*" and "Sac*" though)
* .aac: fake for convenience given it's a tri-Ace AAC's grandpa (but don't use unless you must)
* .pk3/.20: extremely ugly fake extensions randomly given by an old extractor, *DON'T* */
if (!check_extensions(sf, ",aac,laac"))
goto fail;
/* file is validated on decoder init, early catch of simple errors (see tac_decoder_lib.h for full header) */
info_offset = read_u32le(0x00,sf);
if (info_offset > 0x4E000 || info_offset < 0x20) /* offset points to value inside first "block" */
goto fail;
loop_frame = read_u16le(0x08,sf);
loop_discard = read_u16le(0x0a,sf);
frame_count = read_u16le(0x0c,sf);
frame_last = read_u16le(0x0e,sf);
loop_offset = read_u32le(0x10,sf);
stream_size = read_u32le(0x14,sf);
return NULL;
uint16_t loop_frame = read_u16le(0x08,sf);
uint16_t loop_discard = read_u16le(0x0a,sf);
uint16_t frame_count = read_u16le(0x0c,sf);
uint16_t frame_last = read_u16le(0x0e,sf);
uint32_t loop_offset = read_u32le(0x10,sf);
uint32_t stream_size = read_u32le(0x14,sf);
if (stream_size % 0x4E000 != 0) /* multiple of blocks */
goto fail;
return NULL;
/* actual file can truncate last block */
file_size = get_streamfile_size(sf);
uint32_t file_size = get_streamfile_size(sf);
if (file_size > stream_size || file_size < stream_size - 0x4E000)
goto fail;
return NULL;
channel_count = 2; /* always stereo */
loop_flag = (loop_offset != stream_size); /* actual check may be loop_frame > 0? */
start_offset = 0;
channels = 2; // always stereo
loop_flag = (loop_offset != stream_size); // actual check may be loop_frame > 0?
start_offset = 0; // handled internally
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_TAC;
vgmstream->sample_rate = 48000;
/* Frame at count/loop outputs less than full 1024 samples (thus loop or count-1 + extra).
* A few files may pop when looping, but this seems to match game/emulator. */
// Frame at count/loop outputs less than full 1024 samples (thus loop or count-1 + extra).
// A few files may pop when looping, but this seems to match game/emulator.
vgmstream->num_samples = (frame_count - 1) * 1024 + (frame_last + 1);
vgmstream->loop_start_sample = (loop_frame - 1) * 1024 + loop_discard;
vgmstream->loop_end_sample = vgmstream->num_samples;
{
vgmstream->codec_data = init_tac(sf);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_TAC;
vgmstream->layout_type = layout_none;
}
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;

View file

@ -78,6 +78,11 @@ void txtp_copy_config(play_config_t* dst, play_config_t* src) {
if (!src->config_set)
return;
// "no loops" (intro only) and "ignore fade" can't work due to how decoding works, must use @body-* macros
if (src->loop_count_set && src->loop_count == 0 && src->ignore_fade) {
src->ignore_fade = false;
}
dst->config_set = 1;
copy_flag(&dst->play_forever, &src->play_forever);
copy_flag(&dst->ignore_fade, &src->ignore_fade);
@ -94,22 +99,6 @@ void txtp_copy_config(play_config_t* dst, play_config_t* src) {
copy_time(&dst->body_time_set, &dst->body_time, &dst->body_time_s, &src->body_time_set, &src->body_time, &src->body_time_s);
}
#if 0
static void init_config(VGMSTREAM* vgmstream) {
play_config_t* cfg = &vgmstream->config;
//todo only on segmented/layered?
if (cfg->play_forever
cfg->loop_count_set || cfg->fade_time_set || cfg->fade_delay_set ||
cfg->pad_begin_set || cfg->pad_end_set || cfg->trim_begin_set || cfg->trim_end_set ||
cfg->body_time_set) {
VGM_LOG("setup!\n");
}
}
#endif
void txtp_add_mixing(txtp_entry_t* entry, txtp_mix_data_t* mix, txtp_mix_t command) {
if (entry->mixing_count + 1 > TXTP_MIXING_MAX) {
VGM_LOG("TXTP: too many mixes\n");

View file

@ -21,6 +21,11 @@
#define TXTP_GROUP_REPEAT 'R'
#define TXTP_POSITION_LOOPS 'L'
#define TXTP_BODY_INTRO 1
#define TXTP_BODY_MAIN 2
#define TXTP_BODY_OUTRO 3
/* mixing info */
typedef enum {
MIX_SWAP,
@ -104,6 +109,8 @@ typedef struct {
double trim_second;
int32_t trim_sample;
int body_mode;
} txtp_entry_t;

View file

@ -384,6 +384,8 @@ static void add_settings(txtp_entry_t* current, txtp_entry_t* entry, const char*
current->loop_anchor_start = entry->loop_anchor_start;
current->loop_anchor_end = entry->loop_anchor_end;
current->body_mode = entry->body_mode;
}
//TODO use
@ -708,6 +710,16 @@ static void parse_params(txtp_entry_t* entry, char* params) {
txtp_add_mixing(entry, &mix, MACRO_DOWNMIX);
}
else if (strcmp(command,"@body-intro") == 0) {
entry->body_mode = TXTP_BODY_INTRO;
VGM_LOG("body: %x\n", entry->body_mode);
}
else if (strcmp(command,"@body-main") == 0) {
entry->body_mode = TXTP_BODY_MAIN;
}
else if (strcmp(command,"@body-outro") == 0) {
entry->body_mode = TXTP_BODY_OUTRO;
}
else if (params[nc] == ' ') {
//;VGM_LOG("TXTP: comment\n");
break; /* comment, ignore rest */
@ -1019,7 +1031,9 @@ static int parse_keyval(txtp_header_t* txtp, const char* key, const char* val) {
}
else {
goto fail;
// in rare cases a filename may contain a (blah=blah.blah), but it's hard to distinguish
// from key=val + setting with dots. Signal unknown command to treat it like a file (should fail later).
return -1;
}
return 1;
@ -1066,9 +1080,11 @@ txtp_header_t* txtp_parse(STREAMFILE* sf) {
/* try key/val (ignores lead/trail spaces, # may be commands or comments) */
ok = sscanf(line, " %[^ \t#=] = %[^\t\r\n] ", key,val);
if (ok == 2) { /* key=val */
if (!parse_keyval(txtp, key, val)) /* read key/val */
goto fail;
int ret = parse_keyval(txtp, key, val); /* read key/val */
if (ret == 0) goto fail;
if (ret > 0)
continue;
// ret < 0: try to handle as filename below
}
/* must be a filename (only remove spaces from start/end, as filenames con contain mid spaces/#/etc) */

View file

@ -13,6 +13,51 @@
/*******************************************************************************/
static void apply_settings_body(VGMSTREAM* vgmstream, txtp_entry_t* entry) {
// tweak playable part, which only makes sense
VGM_LOG("tesst: %i,%i\n", entry->body_mode , vgmstream->loop_flag);
if (!entry->body_mode || !vgmstream->loop_flag)
return;
entry->config.fade_time_set = false;
entry->config.fade_delay_set = false;
entry->config.ignore_fade = false;
entry->config.ignore_loop = true;
switch(entry->body_mode) {
case TXTP_BODY_INTRO:
if (vgmstream->loop_start_sample == 0)
return;
entry->trim_set = true;
entry->trim_sample = vgmstream->loop_start_sample;
entry->config.config_set = true;
break;
case TXTP_BODY_MAIN:
entry->config.trim_begin_set = true;
entry->config.trim_begin = vgmstream->loop_start_sample;
entry->trim_set = true;
entry->trim_sample = vgmstream->loop_end_sample;
entry->config.config_set = true;
break;
case TXTP_BODY_OUTRO:
if (vgmstream->loop_end_sample >= vgmstream->num_samples)
return;
entry->config.trim_begin_set = true;
entry->config.trim_begin = vgmstream->loop_end_sample;
entry->config.config_set = true;
break;
default:
break;
}
}
static void apply_settings(VGMSTREAM* vgmstream, txtp_entry_t* current) {
/* base settings */
@ -36,6 +81,8 @@ static void apply_settings(VGMSTREAM* vgmstream, txtp_entry_t* current) {
vgmstream_force_loop(vgmstream, current->loop_install_set, current->loop_start_sample, current->loop_end_sample);
}
apply_settings_body(vgmstream, current);
if (current->trim_set) {
if (current->trim_second != 0.0) {
/* trim sample can become 0 here when second is too small (rounded) */

View file

@ -1011,7 +1011,11 @@ static VGMSTREAM* init_vgmstream_ubi_sb_base(ubi_sb_header* sb, STREAMFILE* sf_h
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
if (vgmstream->num_samples == 0) { /* happens in .bnm */
// in .bnm samples may be null, or PCM size (similar to Ubi-MPEG)
if (sb->is_bnm)
vgmstream->num_samples = 0;
if (vgmstream->num_samples == 0) {
vgmstream->num_samples = pcm_bytes_to_samples(sb->stream_size, sb->channels, 16);
vgmstream->loop_end_sample = vgmstream->num_samples;
}
@ -1221,14 +1225,44 @@ static VGMSTREAM* init_vgmstream_ubi_sb_base(ubi_sb_header* sb, STREAMFILE* sf_h
}
break;
case FMT_MPDX:
/* a custom, chunked MPEG format (sigh)
* 0x00: samples? (related to size)
* 0x04: "2RUS" (apparently "1RUS" for mono files)
* Rest is a MPEG-like sync but not an actual MPEG header? (DLLs do refer it as MPEG)
* Files may have multiple "2RUS" or just a big one
* A companion .csb has some not-too-useful info */
case FMT_MPDX: {
/* custom MPEG (.MPD, .MPU. MPX, internal, etc):
* 0x00: samples
* 0x04: optional ID for 'surround' config ("2RUS" or "1RUS" or none)
* Data is custom-ish MP2 packets with odd surround modes
* - .MPX have multiple small streams pasted together (subsongs in .bnm point to each)
* - .MPD has 1 big-ish stream
* A companion .csb has sequence info (maybe before compiled to .bnm)
*/
int32_t block_samples = read_s32le(start_offset + 0x00, sf_data);
uint32_t mode = read_u32be(start_offset + 0x04, sf_data);
start_offset += 0x04;
if ((mode & 0x00FFFFFF) == get_id32be("\0RUS"))
start_offset += 0x04;
// for some reason num_samples is either size of PCM or 0
if (sb->num_samples && block_samples * sizeof(short) * sb->channels != sb->num_samples) {
VGM_LOG("UBI SB: wrong MPEG block samples found block=%i vs total=%i\n", block_samples, sb->num_samples);
goto fail;
}
//TODO: needed for smoother segments, but not sure if block samples counts this
// (usually blocks' frames have more samples than defined but not always; maybe should output delay's samples at EOF)
int encoder_delay = 480; //observed
vgmstream->num_samples = block_samples - encoder_delay;
vgmstream->loop_end_sample = block_samples - encoder_delay;
if (sb->loop_start) {
vgmstream->loop_start_sample = sb->loop_start / sizeof(short) / sb->channels;
}
vgmstream->codec_data = init_ubimpeg(mode);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_UBI_MPEG;
vgmstream->layout_type = layout_none;
break;
}
default:
VGM_LOG("UBI SB: unknown codec\n");
@ -3071,10 +3105,10 @@ static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf) {
sb->version = 0x00000000;
}
/* Tonic Touble beta has garbage instead of version */
/* Tonic Touble Special Edition has garbage instead of version */
if (sb->is_bnm && sb->version > 0x00000000 && sb->platform == UBI_PC) {
if (check_project_file(sf, "ED_MAIN.LCB", 0)) {
is_ttse_pc = 1;
if (check_project_file(sf, "ED_MAIN.LCB", 0) || check_project_file(sf, "../ED_MAIN.LCB", 0)) {
is_ttse_pc = true;
sb->version = 0x00000000;
}
}

View file

@ -0,0 +1,59 @@
#include "meta.h"
#include "../coding/coding.h"
/* VA3 - from Konami games [Dance Dance Revolution Supernova 2 (Arcade)] */
VGMSTREAM* init_vgmstream_va3(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
uint32_t data_size;
/* checks */
if (!is_id32be(0x00, sf, "!3AV"))
return NULL;
// .va3: actual extension
if (!check_extensions(sf, "va3"))
return NULL;
start_offset = 0x800;
data_size = read_u32le(0x04, sf);
loop_flag = 0;
channels = 2;
//0c: null (loops?)
//10: null (loops?)
//18: flag? (always 1)
//1c: always 0x0200 (channels?)
//20: always 100 (volume?)
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VA3;
vgmstream->num_samples = read_s32le(0x08, sf);
vgmstream->sample_rate = read_s32le(0x14, sf);
#ifdef VGM_USE_FFMPEG
{
int block_align = 0xC0 * vgmstream->channels;
int encoder_delay = 0; //TODO
vgmstream->codec_data = init_ffmpeg_atrac3_raw(sf, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
}
#else
goto fail;
#endif
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -28,8 +28,9 @@ VGMSTREAM* init_vgmstream_vag(STREAMFILE* sf) {
* .snd: Alien Breed (Vita)
* .svg: ModernGroove: Ministry of Sound Edition (PS2)
* (extensionless): The Urbz (PS2), The Sims series (PS2)
* .wav: Sniper Elite (PS2), The Simpsons Game (PS2/PSP) */
if (!check_extensions(sf,"vag,swag,str,vig,l,r,vas,xa2,snd,svg,,wav,lwav"))
* .wav: Sniper Elite (PS2), The Simpsons Game (PS2/PSP)
* .msv: Casper and the Ghostly Trio (PS2), Earache Extreme Metal Racing (PS2) */
if (!check_extensions(sf,"vag,swag,str,vig,l,r,vas,xa2,snd,svg,,wav,lwav,msv"))
return NULL;
file_size = get_streamfile_size(sf);

View file

@ -226,8 +226,6 @@ VGMSTREAM* init_vgmstream_vas_kceo_container(STREAMFILE* sf) {
}
}
else if (read_u32le(0x00, sf) == 0x800) { /* Xbox/PC (start?) */
VGM_STEP();
total_subsongs = read_s32le(0x04, sf);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;

View file

@ -13,7 +13,7 @@ VGMSTREAM* init_vgmstream_vig_kces(STREAMFILE* sf) {
/* checks */
if (read_u32be(0x00,sf) != 0x01006408)
return NULL;
/* .vig: actual extension from DDR exes */
/* .vig: actual extension from AC versions + PS2 exes */
if (!check_extensions(sf, "vig"))
return NULL;

View file

@ -4,27 +4,27 @@
#include "xavs_streamfile.h"
/* XAVS - Reflections audio and video+audio container [Stuntman (PS2)] */
VGMSTREAM * init_vgmstream_xavs(STREAMFILE *streamFile) {
VGMSTREAM* init_vgmstream_xavs(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
off_t start_offset;
int loop_flag, channel_count;
int total_subsongs, target_subsong = streamFile->stream_index;
STREAMFILE *temp_streamFile = NULL;
int loop_flag, channels;
int total_subsongs, target_subsong = sf->stream_index;
/* checks */
if (!check_extensions(streamFile, "xav"))
goto fail;
if (read_32bitBE(0x00, streamFile) != 0x58415653) /* "XAVS" */
goto fail;
if (!is_id32be(0x00, sf, "XAVS"))
return NULL;
if (!check_extensions(sf, "xav"))
return NULL;
loop_flag = 0;
channel_count = 2;
channels = 2;
start_offset = 0x00;
/* 0x04: 16b width + height (0 if file has no video) */
/* 0x08: related to video (0 if file has no video) */
total_subsongs = read_16bitLE(0x0c, streamFile);
total_subsongs = read_u16le(0x0c, sf);
/* 0x0c: volume? (0x50, 0x4e) */
/* 0x10: biggest video chunk? (0 if file has no video) */
/* 0x14: biggest audio chunk? */
@ -33,12 +33,12 @@ VGMSTREAM * init_vgmstream_xavs(STREAMFILE *streamFile) {
if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail;
/* could use a blocked layout, but this needs interleaved PCM within blocks which can't be done ATM */
temp_streamFile = setup_xavs_streamfile(streamFile, 0x18, target_subsong - 1);
if (!temp_streamFile) goto fail;
temp_sf = setup_xavs_streamfile(sf, 0x18, target_subsong - 1);
if (!temp_sf) goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_XAVS;
@ -50,9 +50,9 @@ VGMSTREAM * init_vgmstream_xavs(STREAMFILE *streamFile) {
/* no apparent flags, most videos use 0x41 but not all */
{
off_t offset = 0x18;
while (offset < get_streamfile_size(streamFile)) {
uint32_t chunk_id = read_32bitLE(offset+0x00, streamFile) & 0xFF;
uint32_t chunk_size = read_32bitLE(offset+0x00, streamFile) >> 8;
while (offset < get_streamfile_size(sf)) {
uint32_t chunk_id = read_u32le(offset+0x00, sf) & 0xFF;
uint32_t chunk_size = read_u32le(offset+0x00, sf) >> 8;
if ((chunk_id & 0xF0) == 0x40) {
vgmstream->sample_rate = 48000;
@ -72,16 +72,16 @@ VGMSTREAM * init_vgmstream_xavs(STREAMFILE *streamFile) {
}
}
vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(temp_streamFile), channel_count, 16);
vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(temp_sf), channels, 16);
if (!vgmstream_open_stream(vgmstream,temp_streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream, temp_sf, start_offset))
goto fail;
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -7,28 +7,27 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_body = NULL;
uint32_t offset;
uint32_t stream_type, stream_offset, stream_size;
uint32_t name_offset, name_size;
uint32_t flags;
int32_t num_samples;
int version = 0;
int loop_flag, channels, codec, sample_rate;
int total_subsongs, target_subsong = sf->stream_index;
/* checks */
if (!check_extensions(sf, "xsh"))
goto fail;
version = read_u32le(0x00, sf);
uint32_t version = read_u32le(0x00, sf);
if (version < 0x009D || version > 0x101)
return NULL;
if (read_u32le(0x04, sf) != 0)
goto fail;
return NULL;
total_subsongs = read_u32le(0x08, sf);
if (!check_extensions(sf, "xsh"))
return NULL;
int total_subsongs = read_u32le(0x08, sf);
int target_subsong = sf->stream_index;
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
uint32_t stream_type, stream_offset, stream_size, flags;
uint32_t name_offset, name_size;
int32_t num_samples;
switch(version) {
case 0x009D: /* Spider-Man 2002 (Xbox) */
offset = 0x0c + (target_subsong-1) * 0x60;
@ -74,22 +73,23 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
break;
default:
goto fail;
return NULL;
}
loop_flag = 0;
// full loop flag (ex. Spider-Man city_e.XSH#7,22)
loop_flag = (flags & 0x01) != 0;
if (stream_type < 0 || stream_type > 2)
goto fail;
if (stream_type > 2)
return NULL;
/* 0x00: floats x4 (volume/pan/etc? usually 1.0, 1.0, 10.0, 10.0) */
// 0x00: floats x4 (volume/pan/etc? usually 1.0, 1.0, 10.0, 10.0)
codec = read_u16le(offset + 0x10,sf);
channels = read_u16le(offset + 0x12,sf);
sample_rate = read_u32le(offset + 0x14,sf);
/* 0x18: avg bitrate */
/* 0x1c: block size */
/* 0x1e: bps */
/* 0x20: 2? */
// 0x18: avg bitrate
// 0x1c: block size
// 0x1e: bps
// 0x20: 2?
if (stream_type == 0) {
vgmstream = init_vgmstream_silence_container(total_subsongs);
@ -120,6 +120,11 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
vgmstream->num_streams = total_subsongs;
read_string(vgmstream->stream_name, name_size, name_offset,sf);
// external .xss shouldn't have loop info though
if (loop_flag && !vgmstream->loop_flag) {
vgmstream_force_loop(vgmstream, loop_flag, 0, vgmstream->num_samples);
}
close_streamfile(sf_body);
return vgmstream;
//break;
@ -138,7 +143,6 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
default:
goto fail;
}
}
else {
sf_body = open_streamfile_by_ext(sf,"xsd");
@ -167,6 +171,8 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
num_samples = xbox_ima_bytes_to_samples(stream_size, channels);
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = num_samples;
break;
}

View file

@ -6,17 +6,19 @@
/* Simple bitreader for MPEG/standard bit style, in 'most significant byte' (MSB) format.
* Example: with 0x1234 = 00010010 00110100, reading 5b + 6b = 00010 010001
* (first upper 5b, then next lower 3b and next upper 3b = 6b)
* Kept in .h since it's slightly faster (compiler can optimize statics better using default compile flags). */
* Kept in .h since it's slightly faster (compiler can optimize statics better using default compile flags).
* Assumes bufs aren't that big (probable max ~0x20000000)
*/
typedef struct {
uint8_t* buf; /* buffer to read/write */
size_t bufsize; /* max size */
size_t b_max; /* max size in bits */
uint32_t b_off; /* current offset in bits inside buffer */
uint8_t* buf; // buffer to read/write
uint32_t bufsize; // max size
uint32_t b_max; // max size in bits
uint32_t b_off; // current offset in bits inside buffer
} bitstream_t;
/* convenience util */
static inline void bm_setup(bitstream_t* bs, uint8_t* buf, size_t bufsize) {
static inline void bm_setup(bitstream_t* bs, uint8_t* buf, uint32_t bufsize) {
bs->buf = buf;
bs->bufsize = bufsize;
bs->b_max = bufsize * 8;
@ -136,6 +138,14 @@ fail:
return 0;
}
static inline uint32_t bm_read(bitstream_t* ib, uint32_t bits) {
uint32_t value;
int res = bm_get(ib, bits, &value);
if (!res)
return 0;
return value;
}
/* Write bits (max 32) to buf and update the bit offset. Order is BE (MSB). */
static inline int bm_put(bitstream_t* ob, uint32_t bits, uint32_t value) {
uint32_t shift, pos;

Some files were not shown because too many files have changed in this diff Show more