From ddc3da7576dfef6c27f00b8e10dc6972b712264e Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Mon, 8 Jan 2018 18:54:28 -0800 Subject: [PATCH] Updated VGMStream to r1050-925-g2b92a562, now with Atrac9 support. --- .../libatrac9.xcodeproj/project.pbxproj | 441 ++++++ Frameworks/libatrac9/libatrac9/Info.plist | 26 + .../libatrac9/LibAtrac9/.gitattributes | 63 + .../libatrac9/libatrac9/LibAtrac9/.gitignore | 261 ++++ .../libatrac9/LibAtrac9/C/band_extension.c | 191 +++ .../libatrac9/LibAtrac9/C/band_extension.h | 13 + .../libatrac9/LibAtrac9/C/bit_allocation.c | 119 ++ .../libatrac9/LibAtrac9/C/bit_allocation.h | 6 + .../libatrac9/LibAtrac9/C/bit_reader.c | 110 ++ .../libatrac9/LibAtrac9/C/bit_reader.h | 13 + .../libatrac9/libatrac9/LibAtrac9/C/decinit.c | 188 +++ .../libatrac9/libatrac9/LibAtrac9/C/decinit.h | 19 + .../libatrac9/libatrac9/LibAtrac9/C/decoder.c | 114 ++ .../libatrac9/libatrac9/LibAtrac9/C/decoder.h | 11 + .../libatrac9/LibAtrac9/C/error_codes.h | 33 + .../libatrac9/LibAtrac9/C/huffCodes.c | 152 ++ .../libatrac9/LibAtrac9/C/huffCodes.h | 1295 ++++++++++++++++ .../libatrac9/libatrac9/LibAtrac9/C/imdct.c | 80 + .../libatrac9/libatrac9/LibAtrac9/C/imdct.h | 6 + .../libatrac9/LibAtrac9/C/libatrac9.c | 33 + .../libatrac9/LibAtrac9/C/libatrac9.h | 32 + .../libatrac9/LibAtrac9/C/libatrac9.sln | 31 + .../libatrac9/LibAtrac9/C/libatrac9.vcxproj | 162 ++ .../LibAtrac9/C/libatrac9.vcxproj.filters | 105 ++ .../libatrac9/LibAtrac9/C/quantization.c | 54 + .../libatrac9/LibAtrac9/C/quantization.h | 8 + .../libatrac9/LibAtrac9/C/scale_factors.c | 146 ++ .../libatrac9/LibAtrac9/C/scale_factors.h | 8 + .../libatrac9/LibAtrac9/C/structures.h | 160 ++ .../libatrac9/libatrac9/LibAtrac9/C/tables.c | 7 + .../libatrac9/libatrac9/LibAtrac9/C/tables.h | 389 +++++ .../libatrac9/libatrac9/LibAtrac9/C/unpack.c | 423 ++++++ .../libatrac9/libatrac9/LibAtrac9/C/unpack.h | 23 + .../libatrac9/libatrac9/LibAtrac9/C/utility.c | 30 + .../libatrac9/libatrac9/LibAtrac9/C/utility.h | 15 + .../libatrac9/LibAtrac9/CSharp/LibAtrac9.sln | 42 + .../CSharp/LibAtrac9/Atrac9Config.cs | 119 ++ .../CSharp/LibAtrac9/Atrac9Decoder.cs | 127 ++ .../LibAtrac9/CSharp/LibAtrac9/Atrac9Rng.cs | 33 + .../CSharp/LibAtrac9/BandExtension.cs | 372 +++++ .../CSharp/LibAtrac9/BitAllocation.cs | 140 ++ .../LibAtrac9/CSharp/LibAtrac9/Block.cs | 91 ++ .../LibAtrac9/CSharp/LibAtrac9/Channel.cs | 48 + .../CSharp/LibAtrac9/ChannelConfig.cs | 33 + .../LibAtrac9/CSharp/LibAtrac9/Frame.cs | 20 + .../CSharp/LibAtrac9/HuffmanCodebook.cs | 62 + .../CSharp/LibAtrac9/HuffmanCodebooks.cs | 1352 +++++++++++++++++ .../CSharp/LibAtrac9/LibAtrac9.csproj | 8 + .../CSharp/LibAtrac9/Quantization.cs | 57 + .../CSharp/LibAtrac9/ScaleFactors.cs | 171 +++ .../LibAtrac9/CSharp/LibAtrac9/Stereo.cs | 33 + .../LibAtrac9/CSharp/LibAtrac9/Tables.cs | 115 ++ .../LibAtrac9/CSharp/LibAtrac9/Unpack.cs | 425 ++++++ .../CSharp/LibAtrac9/Utilities/Bit.cs | 22 + .../CSharp/LibAtrac9/Utilities/BitReader.cs | 132 ++ .../CSharp/LibAtrac9/Utilities/Helpers.cs | 50 + .../CSharp/LibAtrac9/Utilities/Mdct.cs | 177 +++ .../vgmstream.xcodeproj/project.pbxproj | 70 + .../vgmstream/src/coding/at3_decoder.c | 17 +- .../vgmstream/src/coding/atrac9_decoder.c | 219 +++ .../vgmstream/vgmstream/src/coding/coding.h | 29 +- .../src/coding/ffmpeg_decoder_utils_ea_xma.c | 13 +- .../vgmstream/src/coding/ima_decoder.c | 5 +- .../vgmstream/src/coding/mpeg_decoder.c | 4 +- .../vgmstream/src/coding/pcm_decoder.c | 114 +- .../vgmstream/src/coding/psx_decoder.c | 31 +- .../src/coding/vorbis_custom_decoder.c | 2 +- .../vgmstream/src/coding/xa_decoder.c | 4 - Frameworks/vgmstream/vgmstream/src/formats.c | 16 +- .../vgmstream/src/layout/blocked_ea_1snh.c | 63 +- .../vgmstream/src/layout/blocked_ea_schl.c | 62 +- .../vgmstream/src/layout/xa_blocked.c | 7 +- Frameworks/vgmstream/vgmstream/src/meta/ahx.c | 2 +- Frameworks/vgmstream/vgmstream/src/meta/awc.c | 2 +- .../vgmstream/vgmstream/src/meta/ea_1snh.c | 137 +- .../vgmstream/vgmstream/src/meta/ea_eaac.c | 22 +- .../vgmstream/vgmstream/src/meta/ea_schl.c | 99 +- Frameworks/vgmstream/vgmstream/src/meta/fsb.c | 2 +- .../vgmstream/vgmstream/src/meta/fsb5.c | 87 +- .../vgmstream/vgmstream/src/meta/genh.c | 2 +- Frameworks/vgmstream/vgmstream/src/meta/gtd.c | 50 +- .../vgmstream/vgmstream/src/meta/hca_keys.h | 76 +- .../vgmstream/vgmstream/src/meta/ktss.c | 49 + .../vgmstream/vgmstream/src/meta/meta.h | 4 +- .../vgmstream/vgmstream/src/meta/ngc_vid1.c | 2 +- .../vgmstream/src/meta/ogg_vorbis_file.c | 2 +- Frameworks/vgmstream/vgmstream/src/meta/ogl.c | 2 +- Frameworks/vgmstream/vgmstream/src/meta/p3d.c | 2 +- .../vgmstream/vgmstream/src/meta/ps3_msf.c | 2 +- .../vgmstream/vgmstream/src/meta/riff.c | 861 ++++------- .../vgmstream/vgmstream/src/meta/sk_aud.c | 2 +- .../vgmstream/vgmstream/src/meta/sqex_scd.c | 2 +- Frameworks/vgmstream/vgmstream/src/meta/sxd.c | 98 +- .../vgmstream/vgmstream/src/meta/ta_aac.c | 47 + .../vgmstream/vgmstream/src/meta/txth.c | 2 +- .../vgmstream/vgmstream/src/meta/ubi_raki.c | 60 +- .../vgmstream/vgmstream/src/meta/wwise.c | 27 +- Frameworks/vgmstream/vgmstream/src/meta/xnb.c | 123 ++ .../vgmstream/vgmstream/src/meta/xvag.c | 122 +- .../vgmstream/vgmstream/src/vgmstream.c | 238 +-- .../vgmstream/vgmstream/src/vgmstream.h | 461 +++--- 101 files changed, 10387 insertions(+), 1250 deletions(-) create mode 100644 Frameworks/libatrac9/libatrac9.xcodeproj/project.pbxproj create mode 100644 Frameworks/libatrac9/libatrac9/Info.plist create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/.gitattributes create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/.gitignore create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/band_extension.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/band_extension.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_allocation.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_allocation.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_reader.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_reader.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/decinit.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/decinit.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/decoder.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/decoder.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/error_codes.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/huffCodes.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/huffCodes.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/imdct.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/imdct.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.sln create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.vcxproj create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.vcxproj.filters create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/quantization.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/quantization.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/scale_factors.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/scale_factors.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/structures.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/tables.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/tables.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/unpack.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/unpack.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/utility.c create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/C/utility.h create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9.sln create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Config.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Decoder.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Rng.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/BandExtension.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/BitAllocation.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Block.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Channel.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/ChannelConfig.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Frame.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/HuffmanCodebook.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/HuffmanCodebooks.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/LibAtrac9.csproj create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Quantization.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/ScaleFactors.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Stereo.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Tables.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Unpack.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Bit.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/BitReader.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Helpers.cs create mode 100644 Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Mdct.cs create mode 100644 Frameworks/vgmstream/vgmstream/src/coding/atrac9_decoder.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ktss.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/xnb.c diff --git a/Frameworks/libatrac9/libatrac9.xcodeproj/project.pbxproj b/Frameworks/libatrac9/libatrac9.xcodeproj/project.pbxproj new file mode 100644 index 000000000..bf4b58be3 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9.xcodeproj/project.pbxproj @@ -0,0 +1,441 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 830EBDF020045FF80023AA10 /* tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDB920045FF80023AA10 /* tables.c */; }; + 830EBDF120045FF80023AA10 /* libatrac9.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDBA20045FF80023AA10 /* libatrac9.c */; }; + 830EBDF220045FF80023AA10 /* huffCodes.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDBB20045FF80023AA10 /* huffCodes.c */; }; + 830EBDF320045FF80023AA10 /* imdct.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDBC20045FF80023AA10 /* imdct.c */; }; + 830EBDF420045FF80023AA10 /* scale_factors.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDBD20045FF80023AA10 /* scale_factors.h */; }; + 830EBDF520045FF80023AA10 /* utility.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDBE20045FF80023AA10 /* utility.c */; }; + 830EBDF620045FF80023AA10 /* quantization.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDBF20045FF80023AA10 /* quantization.h */; }; + 830EBDF720045FF80023AA10 /* band_extension.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDC020045FF80023AA10 /* band_extension.c */; }; + 830EBDF820045FF80023AA10 /* unpack.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDC120045FF80023AA10 /* unpack.c */; }; + 830EBDF920045FF80023AA10 /* bit_reader.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDC220045FF80023AA10 /* bit_reader.h */; }; + 830EBDFA20045FF80023AA10 /* decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDC320045FF80023AA10 /* decoder.h */; }; + 830EBDFB20045FF80023AA10 /* decinit.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDC420045FF80023AA10 /* decinit.c */; }; + 830EBDFC20045FF80023AA10 /* bit_allocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDC520045FF80023AA10 /* bit_allocation.h */; }; + 830EBDFE20045FF80023AA10 /* libatrac9.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDC720045FF80023AA10 /* libatrac9.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 830EBDFF20045FF80023AA10 /* tables.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDC820045FF80023AA10 /* tables.h */; }; + 830EBE0020045FF80023AA10 /* scale_factors.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDC920045FF80023AA10 /* scale_factors.c */; }; + 830EBE0120045FF80023AA10 /* error_codes.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDCA20045FF80023AA10 /* error_codes.h */; }; + 830EBE0220045FF80023AA10 /* imdct.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDCB20045FF80023AA10 /* imdct.h */; }; + 830EBE0420045FF80023AA10 /* huffCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDCD20045FF80023AA10 /* huffCodes.h */; }; + 830EBE0520045FF80023AA10 /* decinit.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDCE20045FF80023AA10 /* decinit.h */; }; + 830EBE0620045FF80023AA10 /* decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDCF20045FF80023AA10 /* decoder.c */; }; + 830EBE0720045FF80023AA10 /* bit_reader.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDD020045FF80023AA10 /* bit_reader.c */; }; + 830EBE0820045FF80023AA10 /* unpack.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDD120045FF80023AA10 /* unpack.h */; }; + 830EBE0A20045FF80023AA10 /* quantization.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDD320045FF80023AA10 /* quantization.c */; }; + 830EBE0B20045FF80023AA10 /* utility.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDD420045FF80023AA10 /* utility.h */; }; + 830EBE0C20045FF80023AA10 /* band_extension.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDD520045FF80023AA10 /* band_extension.h */; }; + 830EBE0D20045FF80023AA10 /* bit_allocation.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBDD620045FF80023AA10 /* bit_allocation.c */; }; + 830EBE0E20045FF80023AA10 /* structures.h in Headers */ = {isa = PBXBuildFile; fileRef = 830EBDD720045FF80023AA10 /* structures.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 830EBD8720045F190023AA10 /* libatrac9.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = libatrac9.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 830EBD8B20045F190023AA10 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 830EBDB920045FF80023AA10 /* tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tables.c; sourceTree = ""; }; + 830EBDBA20045FF80023AA10 /* libatrac9.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libatrac9.c; sourceTree = ""; }; + 830EBDBB20045FF80023AA10 /* huffCodes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = huffCodes.c; sourceTree = ""; }; + 830EBDBC20045FF80023AA10 /* imdct.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = imdct.c; sourceTree = ""; }; + 830EBDBD20045FF80023AA10 /* scale_factors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scale_factors.h; sourceTree = ""; }; + 830EBDBE20045FF80023AA10 /* utility.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utility.c; sourceTree = ""; }; + 830EBDBF20045FF80023AA10 /* quantization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = quantization.h; sourceTree = ""; }; + 830EBDC020045FF80023AA10 /* band_extension.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = band_extension.c; sourceTree = ""; }; + 830EBDC120045FF80023AA10 /* unpack.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unpack.c; sourceTree = ""; }; + 830EBDC220045FF80023AA10 /* bit_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_reader.h; sourceTree = ""; }; + 830EBDC320045FF80023AA10 /* decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decoder.h; sourceTree = ""; }; + 830EBDC420045FF80023AA10 /* decinit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = decinit.c; sourceTree = ""; }; + 830EBDC520045FF80023AA10 /* bit_allocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_allocation.h; sourceTree = ""; }; + 830EBDC720045FF80023AA10 /* libatrac9.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libatrac9.h; sourceTree = ""; }; + 830EBDC820045FF80023AA10 /* tables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tables.h; sourceTree = ""; }; + 830EBDC920045FF80023AA10 /* scale_factors.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scale_factors.c; sourceTree = ""; }; + 830EBDCA20045FF80023AA10 /* error_codes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = error_codes.h; sourceTree = ""; }; + 830EBDCB20045FF80023AA10 /* imdct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imdct.h; sourceTree = ""; }; + 830EBDCD20045FF80023AA10 /* huffCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = huffCodes.h; sourceTree = ""; }; + 830EBDCE20045FF80023AA10 /* decinit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decinit.h; sourceTree = ""; }; + 830EBDCF20045FF80023AA10 /* decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = decoder.c; sourceTree = ""; }; + 830EBDD020045FF80023AA10 /* bit_reader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bit_reader.c; sourceTree = ""; }; + 830EBDD120045FF80023AA10 /* unpack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unpack.h; sourceTree = ""; }; + 830EBDD320045FF80023AA10 /* quantization.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = quantization.c; sourceTree = ""; }; + 830EBDD420045FF80023AA10 /* utility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utility.h; sourceTree = ""; }; + 830EBDD520045FF80023AA10 /* band_extension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = band_extension.h; sourceTree = ""; }; + 830EBDD620045FF80023AA10 /* bit_allocation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bit_allocation.c; sourceTree = ""; }; + 830EBDD720045FF80023AA10 /* structures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = structures.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 830EBD8320045F190023AA10 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 830EBD7D20045F190023AA10 = { + isa = PBXGroup; + children = ( + 830EBD8920045F190023AA10 /* libatrac9 */, + 830EBD8820045F190023AA10 /* Products */, + ); + sourceTree = ""; + }; + 830EBD8820045F190023AA10 /* Products */ = { + isa = PBXGroup; + children = ( + 830EBD8720045F190023AA10 /* libatrac9.framework */, + ); + name = Products; + sourceTree = ""; + }; + 830EBD8920045F190023AA10 /* libatrac9 */ = { + isa = PBXGroup; + children = ( + 830EBD9C20045FF80023AA10 /* LibAtrac9 */, + 830EBD8B20045F190023AA10 /* Info.plist */, + ); + path = libatrac9; + sourceTree = ""; + }; + 830EBD9C20045FF80023AA10 /* LibAtrac9 */ = { + isa = PBXGroup; + children = ( + 830EBDB820045FF80023AA10 /* C */, + ); + path = LibAtrac9; + sourceTree = ""; + }; + 830EBDB820045FF80023AA10 /* C */ = { + isa = PBXGroup; + children = ( + 830EBDC020045FF80023AA10 /* band_extension.c */, + 830EBDD520045FF80023AA10 /* band_extension.h */, + 830EBDD620045FF80023AA10 /* bit_allocation.c */, + 830EBDC520045FF80023AA10 /* bit_allocation.h */, + 830EBDD020045FF80023AA10 /* bit_reader.c */, + 830EBDC220045FF80023AA10 /* bit_reader.h */, + 830EBDC420045FF80023AA10 /* decinit.c */, + 830EBDCE20045FF80023AA10 /* decinit.h */, + 830EBDCF20045FF80023AA10 /* decoder.c */, + 830EBDC320045FF80023AA10 /* decoder.h */, + 830EBDCA20045FF80023AA10 /* error_codes.h */, + 830EBDBB20045FF80023AA10 /* huffCodes.c */, + 830EBDCD20045FF80023AA10 /* huffCodes.h */, + 830EBDBC20045FF80023AA10 /* imdct.c */, + 830EBDCB20045FF80023AA10 /* imdct.h */, + 830EBDBA20045FF80023AA10 /* libatrac9.c */, + 830EBDC720045FF80023AA10 /* libatrac9.h */, + 830EBDD320045FF80023AA10 /* quantization.c */, + 830EBDBF20045FF80023AA10 /* quantization.h */, + 830EBDC920045FF80023AA10 /* scale_factors.c */, + 830EBDBD20045FF80023AA10 /* scale_factors.h */, + 830EBDD720045FF80023AA10 /* structures.h */, + 830EBDB920045FF80023AA10 /* tables.c */, + 830EBDC820045FF80023AA10 /* tables.h */, + 830EBDC120045FF80023AA10 /* unpack.c */, + 830EBDD120045FF80023AA10 /* unpack.h */, + 830EBDBE20045FF80023AA10 /* utility.c */, + 830EBDD420045FF80023AA10 /* utility.h */, + ); + path = C; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 830EBD8420045F190023AA10 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 830EBDFE20045FF80023AA10 /* libatrac9.h in Headers */, + 830EBE0220045FF80023AA10 /* imdct.h in Headers */, + 830EBE0520045FF80023AA10 /* decinit.h in Headers */, + 830EBE0420045FF80023AA10 /* huffCodes.h in Headers */, + 830EBE0B20045FF80023AA10 /* utility.h in Headers */, + 830EBE0820045FF80023AA10 /* unpack.h in Headers */, + 830EBDF420045FF80023AA10 /* scale_factors.h in Headers */, + 830EBE0C20045FF80023AA10 /* band_extension.h in Headers */, + 830EBE0120045FF80023AA10 /* error_codes.h in Headers */, + 830EBDFA20045FF80023AA10 /* decoder.h in Headers */, + 830EBDFF20045FF80023AA10 /* tables.h in Headers */, + 830EBDF920045FF80023AA10 /* bit_reader.h in Headers */, + 830EBE0E20045FF80023AA10 /* structures.h in Headers */, + 830EBDFC20045FF80023AA10 /* bit_allocation.h in Headers */, + 830EBDF620045FF80023AA10 /* quantization.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 830EBD8620045F190023AA10 /* libatrac9 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 830EBD8F20045F190023AA10 /* Build configuration list for PBXNativeTarget "libatrac9" */; + buildPhases = ( + 830EBD8220045F190023AA10 /* Sources */, + 830EBD8320045F190023AA10 /* Frameworks */, + 830EBD8420045F190023AA10 /* Headers */, + 830EBD8520045F190023AA10 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = libatrac9; + productName = libatrac9; + productReference = 830EBD8720045F190023AA10 /* libatrac9.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 830EBD7E20045F190023AA10 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0920; + ORGANIZATIONNAME = "Christopher Snowhill"; + TargetAttributes = { + 830EBD8620045F190023AA10 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 830EBD8120045F190023AA10 /* Build configuration list for PBXProject "libatrac9" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 830EBD7D20045F190023AA10; + productRefGroup = 830EBD8820045F190023AA10 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 830EBD8620045F190023AA10 /* libatrac9 */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 830EBD8520045F190023AA10 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 830EBD8220045F190023AA10 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 830EBE0620045FF80023AA10 /* decoder.c in Sources */, + 830EBDF720045FF80023AA10 /* band_extension.c in Sources */, + 830EBE0020045FF80023AA10 /* scale_factors.c in Sources */, + 830EBDF520045FF80023AA10 /* utility.c in Sources */, + 830EBDFB20045FF80023AA10 /* decinit.c in Sources */, + 830EBE0720045FF80023AA10 /* bit_reader.c in Sources */, + 830EBE0A20045FF80023AA10 /* quantization.c in Sources */, + 830EBDF820045FF80023AA10 /* unpack.c in Sources */, + 830EBDF020045FF80023AA10 /* tables.c in Sources */, + 830EBDF320045FF80023AA10 /* imdct.c in Sources */, + 830EBDF220045FF80023AA10 /* huffCodes.c in Sources */, + 830EBDF120045FF80023AA10 /* libatrac9.c in Sources */, + 830EBE0D20045FF80023AA10 /* bit_allocation.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 830EBD8D20045F190023AA10 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INSTALL_PATH = "@loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 830EBD8E20045F190023AA10 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INSTALL_PATH = "@loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 830EBD9020045F190023AA10 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = N6E749HJ2X; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + HEADER_SEARCH_PATHS = libatrac9/LibAtrac9/C; + INFOPLIST_FILE = libatrac9/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_BUNDLE_IDENTIFIER = net.kode54.libatrac9; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 830EBD9120045F190023AA10 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = N6E749HJ2X; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + HEADER_SEARCH_PATHS = libatrac9/LibAtrac9/C; + INFOPLIST_FILE = libatrac9/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_BUNDLE_IDENTIFIER = net.kode54.libatrac9; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 830EBD8120045F190023AA10 /* Build configuration list for PBXProject "libatrac9" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 830EBD8D20045F190023AA10 /* Debug */, + 830EBD8E20045F190023AA10 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 830EBD8F20045F190023AA10 /* Build configuration list for PBXNativeTarget "libatrac9" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 830EBD9020045F190023AA10 /* Debug */, + 830EBD9120045F190023AA10 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 830EBD7E20045F190023AA10 /* Project object */; +} diff --git a/Frameworks/libatrac9/libatrac9/Info.plist b/Frameworks/libatrac9/libatrac9/Info.plist new file mode 100644 index 000000000..a351796f3 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright © 2018 Christopher Snowhill. All rights reserved. + NSPrincipalClass + + + diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/.gitattributes b/Frameworks/libatrac9/libatrac9/LibAtrac9/.gitattributes new file mode 100644 index 000000000..1ff0c4230 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/.gitignore b/Frameworks/libatrac9/libatrac9/LibAtrac9/.gitignore new file mode 100644 index 000000000..3c4efe206 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/.gitignore @@ -0,0 +1,261 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/band_extension.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/band_extension.c new file mode 100644 index 000000000..912c58848 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/band_extension.c @@ -0,0 +1,191 @@ +#include "band_extension.h" +#include "tables.h" +#include "utility.h" +#include + +void ApplyBandExtension(block* block) +{ + if (!block->BandExtensionEnabled || !block->HasExtensionData) return; + + for (int i = 0; i < block->ChannelCount; i++) + { + ApplyBandExtensionChannel(&block->Channels[i]); + } +} + +void ApplyBandExtensionChannel(channel* channel) +{ + const int groupAUnit = channel->Block->QuantizationUnitCount; + int* scaleFactors = channel->ScaleFactors; + double* spectra = channel->Spectra; + double scales[6]; + int* values = channel->BexValues; + + const bex_group* bex_info = &BexGroupInfo[channel->Block->QuantizationUnitCount - 13]; + const int bandCount = bex_info->band_count; + const int groupBUnit = bex_info->group_b_unit; + const int groupCUnit = bex_info->group_c_unit; + + const int totalUnits = max(groupCUnit, 22); + const int bexQuantUnits = totalUnits - groupAUnit; + + const int groupABin = QuantUnitToCoeffIndex[groupAUnit]; + const int groupBBin = QuantUnitToCoeffIndex[groupBUnit]; + const int groupCBin = QuantUnitToCoeffIndex[groupCUnit]; + const int totalBins = QuantUnitToCoeffIndex[totalUnits]; + + FillHighFrequencies(spectra, groupABin, groupBBin, groupCBin, totalBins); + + double groupAScale, groupBScale, groupCScale; + double rate, scale, mult; + + switch (channel->BexMode) + { + case 0: + switch (bandCount) + { + case 3: + scales[0] = BexMode0Bands3[0][values[0]]; + scales[1] = BexMode0Bands3[1][values[0]]; + scales[2] = BexMode0Bands3[2][values[1]]; + scales[3] = BexMode0Bands3[3][values[2]]; + scales[4] = BexMode0Bands3[4][values[3]]; + break; + case 4: + scales[0] = BexMode0Bands4[0][values[0]]; + scales[1] = BexMode0Bands4[1][values[0]]; + scales[2] = BexMode0Bands4[2][values[1]]; + scales[3] = BexMode0Bands4[3][values[2]]; + scales[4] = BexMode0Bands4[4][values[3]]; + break; + case 5: + scales[0] = BexMode0Bands5[0][values[0]]; + scales[1] = BexMode0Bands5[1][values[1]]; + scales[2] = BexMode0Bands5[2][values[1]]; + break; + } + + scales[bexQuantUnits - 1] = SpectrumScale[scaleFactors[groupAUnit]]; + + AddNoiseToSpectrum(channel, QuantUnitToCoeffIndex[totalUnits - 1], + QuantUnitToCoeffCount[totalUnits - 1]); + ScaleBexQuantUnits(spectra, scales, groupAUnit, totalUnits); + break; + case 1: + for (int i = groupAUnit; i < totalUnits; i++) + { + scales[i - groupAUnit] = SpectrumScale[scaleFactors[i]]; + } + + AddNoiseToSpectrum(channel, groupABin, totalBins - groupABin); + ScaleBexQuantUnits(spectra, scales, groupAUnit, totalUnits); + break; + case 2: + groupAScale = BexMode2Scale[values[0]]; + groupBScale = BexMode2Scale[values[1]]; + + for (int i = groupABin; i < groupBBin; i++) + { + spectra[i] *= groupAScale; + } + + for (int i = groupBBin; i < groupCBin; i++) + { + spectra[i] *= groupBScale; + } + return; + case 3: + rate = pow(2, BexMode3Rate[values[1]]); + scale = BexMode3Initial[values[0]]; + for (int i = groupABin; i < totalBins; i++) + { + scale *= rate; + spectra[i] *= scale; + } + return; + case 4: + mult = BexMode4Multiplier[values[0]]; + groupAScale = 0.7079468 * mult; + groupBScale = 0.5011902 * mult; + groupCScale = 0.3548279 * mult; + + for (int i = groupABin; i < groupBBin; i++) + { + spectra[i] *= groupAScale; + } + + for (int i = groupBBin; i < groupCBin; i++) + { + spectra[i] *= groupBScale; + } + + for (int i = groupCBin; i < totalBins; i++) + { + spectra[i] *= groupCScale; + } + } +} + +void ScaleBexQuantUnits(double* spectra, double* scales, int startUnit, int totalUnits) +{ + for (int i = startUnit; i < totalUnits; i++) + { + for (int k = QuantUnitToCoeffIndex[i]; k < QuantUnitToCoeffIndex[i + 1]; k++) + { + spectra[k] *= scales[i - startUnit]; + } + } +} + +void FillHighFrequencies(double* spectra, int groupABin, int groupBBin, int groupCBin, int totalBins) +{ + for (int i = 0; i < groupBBin - groupABin; i++) + { + spectra[groupABin + i] = spectra[groupABin - i - 1]; + } + + for (int i = 0; i < groupCBin - groupBBin; i++) + { + spectra[groupBBin + i] = spectra[groupBBin - i - 1]; + } + + for (int i = 0; i < totalBins - groupCBin; i++) + { + spectra[groupCBin + i] = spectra[groupCBin - i - 1]; + } +} + +void AddNoiseToSpectrum(channel* channel, int index, int count) +{ + if (!channel->rng.initialized) + { + int* sf = channel->ScaleFactors; + const unsigned short seed = (unsigned short)(543 * (sf[8] + sf[12] + sf[15] + 1)); + rng_init(&channel->rng, seed); + } + for (int i = 0; i < count; i++) + { + channel->Spectra[i + index] = rng_next(&channel->rng) / 65535.0 * 2.0 - 1.0; + } +} + +void rng_init(rng_cxt* rng, unsigned short seed) +{ + const int startValue = 0x4D93 * (seed ^ (seed >> 14)); + + rng->stateA = (unsigned short)(3 - startValue); + rng->stateB = (unsigned short)(2 - startValue); + rng->stateC = (unsigned short)(1 - startValue); + rng->stateD = (unsigned short)(0 - startValue); + rng->initialized = TRUE; +} + +unsigned short rng_next(rng_cxt* rng) +{ + const unsigned short t = (unsigned short)(rng->stateD ^ (rng->stateD << 5)); + rng->stateD = rng->stateC; + rng->stateC = rng->stateB; + rng->stateB = rng->stateA; + rng->stateA = (unsigned short)(t ^ rng->stateA ^ ((t ^ (rng->stateA >> 5)) >> 4)); + return rng->stateA; +} \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/band_extension.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/band_extension.h new file mode 100644 index 000000000..c0b6a902e --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/band_extension.h @@ -0,0 +1,13 @@ +#pragma once + +#include "structures.h" + +void ApplyBandExtension(block* block); +void ApplyBandExtensionChannel(channel* channel); + +void ScaleBexQuantUnits(double* spectra, double* scales, int startUnit, int totalUnits); +void FillHighFrequencies(double* spectra, int groupABin, int groupBBin, int groupCBin, int totalBins); +void AddNoiseToSpectrum(channel* channel, int index, int count); + +void rng_init(rng_cxt* rng, unsigned short seed); +unsigned short rng_next(rng_cxt* rng); \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_allocation.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_allocation.c new file mode 100644 index 000000000..2977efc37 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_allocation.c @@ -0,0 +1,119 @@ +#include "bit_allocation.h" +#include "tables.h" +#include "utility.h" +#include + +at9_status CreateGradient(block* block) +{ + int valueCount = block->GradientEndValue - block->GradientStartValue; + int unitCount = block->GradientEndUnit - block->GradientStartUnit; + + for (int i = 0; i < block->GradientEndUnit; i++) + { + block->Gradient[i] = block->GradientStartValue; + } + + for (int i = block->GradientEndUnit; i <= block->QuantizationUnitCount; i++) + { + block->Gradient[i] = block->GradientEndValue; + } + if (unitCount <= 0) return ERR_SUCCESS; + if (valueCount == 0) return ERR_SUCCESS; + + const unsigned char* curve = GradientCurves[unitCount - 1]; + if (valueCount <= 0) + { + double scale = (-valueCount - 1) / 31.0; + int baseVal = block->GradientStartValue - 1; + for (int i = block->GradientStartUnit; i < block->GradientEndUnit; i++) + { + block->Gradient[i] = baseVal - (int)(curve[i - block->GradientStartUnit] * scale); + } + } + else + { + double scale = (valueCount - 1) / 31.0; + int baseVal = block->GradientStartValue + 1; + for (int i = block->GradientStartUnit; i < block->GradientEndUnit; i++) + { + block->Gradient[i] = baseVal + (int)(curve[i - block->GradientStartUnit] * scale); + } + } + + return ERR_SUCCESS; +} + +void CalculateMask(channel* channel) +{ + memset(channel->PrecisionMask, 0, sizeof(channel->PrecisionMask)); + for (int i = 1; i < channel->Block->QuantizationUnitCount; i++) + { + const int delta = channel->ScaleFactors[i] - channel->ScaleFactors[i - 1]; + if (delta > 1) + { + channel->PrecisionMask[i] += min(delta - 1, 5); + } + else if (delta < -1) + { + channel->PrecisionMask[i - 1] += min(delta * -1 - 1, 5); + } + } +} + +void CalculatePrecisions(channel* channel) +{ + block* block = channel->Block; + + if (block->GradientMode != 0) + { + for (int i = 0; i < block->QuantizationUnitCount; i++) + { + channel->Precisions[i] = channel->ScaleFactors[i] + channel->PrecisionMask[i] - block->Gradient[i]; + if (channel->Precisions[i] > 0) + { + switch (block->GradientMode) + { + case 1: + channel->Precisions[i] /= 2; + break; + case 2: + channel->Precisions[i] = 3 * channel->Precisions[i] / 8; + break; + case 3: + channel->Precisions[i] /= 4; + break; + } + } + } + } + else + { + for (int i = 0; i < block->QuantizationUnitCount; i++) + { + channel->Precisions[i] = channel->ScaleFactors[i] - block->Gradient[i]; + } + } + + for (int i = 0; i < block->QuantizationUnitCount; i++) + { + if (channel->Precisions[i] < 1) + { + channel->Precisions[i] = 1; + } + } + + for (int i = 0; i < block->GradientBoundary; i++) + { + channel->Precisions[i]++; + } + + for (int i = 0; i < block->QuantizationUnitCount; i++) + { + channel->PrecisionsFine[i] = 0; + if (channel->Precisions[i] > 15) + { + channel->PrecisionsFine[i] = channel->Precisions[i] - 15; + channel->Precisions[i] = 15; + } + } +} \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_allocation.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_allocation.h new file mode 100644 index 000000000..8ab8ba208 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_allocation.h @@ -0,0 +1,6 @@ +#pragma once +#include "unpack.h" + +at9_status CreateGradient(block* block); +void CalculateMask(channel* channel); +void CalculatePrecisions(channel* channel); diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_reader.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_reader.c new file mode 100644 index 000000000..f38530562 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_reader.c @@ -0,0 +1,110 @@ +#include "bit_reader.h" +#include "utility.h" + +static int peek_int_fallback(bit_reader_cxt* br, int bit_count); + +void init_bit_reader_cxt(bit_reader_cxt* br, const void * buffer) +{ + br->buffer = buffer; + br->position = 0; +} + +int read_int(bit_reader_cxt* br, const int bits) +{ + const int value = peek_int(br, bits); + br->position += bits; + return value; +} + +int read_signed_int(bit_reader_cxt* br, const int bits) +{ + const int value = peek_int(br, bits); + br->position += bits; + return SignExtend32(value, bits); +} + +int read_offset_binary(bit_reader_cxt* br, const int bits) +{ + const int offset = 1 << (bits - 1); + const int value = peek_int(br, bits) - offset; + br->position += bits; + return value; +} + +int peek_int(bit_reader_cxt* br, const int bits) +{ + const int byte_index = br->position / 8; + const int bit_index = br->position % 8; + const unsigned char* buffer = br->buffer; + + if (bits <= 9) + { + int value = buffer[byte_index] << 8 | buffer[byte_index + 1]; + value &= 0xFFFF >> bit_index; + value >>= 16 - bits - bit_index; + return value; + } + + if (bits <= 17) + { + int value = buffer[byte_index] << 16 | buffer[byte_index + 1] << 8 | buffer[byte_index + 2]; + value &= 0xFFFFFF >> bit_index; + value >>= 24 - bits - bit_index; + return value; + } + + if (bits <= 25) + { + int value = buffer[byte_index] << 24 + | buffer[byte_index + 1] << 16 + | buffer[byte_index + 2] << 8 + | buffer[byte_index + 3]; + + value &= (int)(0xFFFFFFFF >> bit_index); + value >>= 32 - bits - bit_index; + return value; + } + return peek_int_fallback(br, bits); +} + +void align_position(bit_reader_cxt* br, const unsigned int multiple) +{ + const int position = br->position; + if (position % multiple == 0) + { + return; + } + + br->position = position + multiple - position % multiple; +} + +static int peek_int_fallback(bit_reader_cxt* br, int bit_count) +{ + int value = 0; + int byte_index = br->position / 8; + int bit_index = br->position % 8; + const unsigned char* buffer = br->buffer; + + while (bit_count > 0) + { + if (bit_index >= 8) + { + bit_index = 0; + byte_index++; + } + + int bits_to_read = bit_count; + if (bits_to_read > 8 - bit_index) + { + bits_to_read = 8 - bit_index; + } + + const int mask = 0xFF >> bit_index; + const int current_byte = (mask & buffer[byte_index]) >> (8 - bit_index - bits_to_read); + + value = (value << bits_to_read) | current_byte; + bit_index += bits_to_read; + bit_count -= bits_to_read; + } + return value; +} \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_reader.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_reader.h new file mode 100644 index 000000000..bcec9d40f --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/bit_reader.h @@ -0,0 +1,13 @@ +#pragma once + +typedef struct { + const unsigned char * buffer; + int position; +} bit_reader_cxt; + +void init_bit_reader_cxt(bit_reader_cxt* br, const void * buffer); +int peek_int(bit_reader_cxt* br, const int bits); +int read_int(bit_reader_cxt* br, const int bits); +int read_signed_int(bit_reader_cxt* br, const int bits); +int read_offset_binary(bit_reader_cxt* br, const int bits); +void align_position(bit_reader_cxt* br, const unsigned int multiple); \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decinit.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decinit.c new file mode 100644 index 000000000..c8a1945e0 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decinit.c @@ -0,0 +1,188 @@ +#include "bit_reader.h" +#include "decinit.h" +#include "error_codes.h" +#include "structures.h" +#include "tables.h" +#include +#include +#include "utility.h" + +static int BlockTypeToChannelCount(BlockType block_type); + +at9_status init_decoder(atrac9_handle* handle, unsigned char* config_data, int wlength) +{ + ERROR_CHECK(init_config_data(&handle->config, config_data)); + ERROR_CHECK(init_frame(handle)); + init_mdct_tables(handle->config.FrameSamplesPower); + init_huffman_codebooks(); + handle->wlength = wlength; + handle->initialized = 1; + return ERR_SUCCESS; +} + +at9_status init_config_data(ConfigData* config, unsigned char* config_data) +{ + memcpy(config->ConfigData, config_data, CONFIG_DATA_SIZE); + ERROR_CHECK(read_config_data(config)); + + config->FramesPerSuperframe = 1 << config->SuperframeIndex; + config->SuperframeBytes = config->FrameBytes << config->SuperframeIndex; + + config->ChannelConfig = ChannelConfigs[config->ChannelConfigIndex]; + config->ChannelCount = config->ChannelConfig.ChannelCount; + config->SampleRate = SampleRates[config->SampleRateIndex]; + config->HighSampleRate = config->SampleRateIndex > 7; + config->FrameSamplesPower = SamplingRateIndexToFrameSamplesPower[config->SampleRateIndex]; + config->FrameSamples = 1 << config->FrameSamplesPower; + config->SuperframeSamples = config->FrameSamples * config->FramesPerSuperframe; + + return ERR_SUCCESS; +} + +at9_status read_config_data(ConfigData* config) +{ + bit_reader_cxt br; + init_bit_reader_cxt(&br, &config->ConfigData); + + const int header = read_int(&br, 8); + config->SampleRateIndex = read_int(&br, 4); + config->ChannelConfigIndex = read_int(&br, 3); + const int validation_bit = read_int(&br, 1); + config->FrameBytes = read_int(&br, 11) + 1; + config->SuperframeIndex = read_int(&br, 2); + + if (header != 0xFE || validation_bit != 0) + { + return ERR_BAD_CONFIG_DATA; + } + + return ERR_SUCCESS; +} + +at9_status init_frame(atrac9_handle* handle) +{ + const int block_count = handle->config.ChannelConfig.BlockCount; + handle->frame.config = &handle->config; + + for (int i = 0; i < block_count; i++) + { + ERROR_CHECK(init_block(&handle->frame.Blocks[i], &handle->frame, i)); + } + + return ERR_SUCCESS; +} + +at9_status init_block(block* block, frame* parent_frame, int block_index) +{ + block->Frame = parent_frame; + block->BlockIndex = block_index; + block->config = parent_frame->config; + block->BlockType = block->config->ChannelConfig.Types[block_index]; + block->ChannelCount = BlockTypeToChannelCount(block->BlockType); + + for (int i = 0; i < block->ChannelCount; i++) + { + ERROR_CHECK(init_channel(&block->Channels[i], block, i)); + } + + return ERR_SUCCESS; +} + +at9_status init_channel(channel* channel, block* parent_block, int channel_index) +{ + channel->Block = parent_block; + channel->Frame = parent_block->Frame; + channel->config = parent_block->config; + channel->ChannelIndex = channel_index; + channel->mdct.bits = parent_block->config->FrameSamplesPower; + return ERR_SUCCESS; +} + +void init_huffman_codebooks() +{ + init_huffman_set(HuffmanScaleFactorsUnsigned, sizeof(HuffmanScaleFactorsUnsigned) / sizeof(HuffmanCodebook)); + init_huffman_set(HuffmanScaleFactorsSigned, sizeof(HuffmanScaleFactorsSigned) / sizeof(HuffmanCodebook)); + init_huffman_set(HuffmanSpectrum, sizeof(HuffmanSpectrum) / sizeof(HuffmanCodebook)); +} + +void init_huffman_set(const HuffmanCodebook* codebooks, int count) +{ + for (int i = 0; i < count; i++) + { + InitHuffmanCodebook(&codebooks[i]); + } +} + +void init_mdct_tables(int frameSizePower) +{ + for (int i = 0; i < 9; i++) + { + GenerateTrigTables(i); + GenerateShuffleTable(i); + } + GenerateMdctWindow(frameSizePower); + GenerateImdctWindow(frameSizePower); +} + +void GenerateTrigTables(int sizeBits) +{ + const int size = 1 << sizeBits; + double* sinTab = SinTables[sizeBits]; + double* cosTab = CosTables[sizeBits]; + + for (int i = 0; i < size; i++) + { + const double value = M_PI * (4 * i + 1) / (4 * size); + sinTab[i] = sin(value); + cosTab[i] = cos(value); + } +} + +void GenerateShuffleTable(int sizeBits) +{ + const int size = 1 << sizeBits; + int* table = ShuffleTables[sizeBits]; + + for (int i = 0; i < size; i++) + { + table[i] = BitReverse32(i ^ (i / 2), sizeBits); + } +} + +void GenerateMdctWindow(int frameSizePower) +{ + const int frameSize = 1 << frameSizePower; + double* mdct = MdctWindow[frameSizePower - 6]; + + for (int i = 0; i < frameSize; i++) + { + mdct[i] = (sin(((i + 0.5) / frameSize - 0.5) * M_PI) + 1.0) * 0.5; + } +} + +void GenerateImdctWindow(int frameSizePower) +{ + const int frameSize = 1 << frameSizePower; + double* imdct = ImdctWindow[frameSizePower - 6]; + double* mdct = MdctWindow[frameSizePower - 6]; + + for (int i = 0; i < frameSize; i++) + { + imdct[i] = mdct[i] / (mdct[frameSize - 1 - i] * mdct[frameSize - 1 - i] + mdct[i] * mdct[i]); + } +} + +static int BlockTypeToChannelCount(BlockType block_type) +{ + switch (block_type) + { + case Mono: + return 1; + case Stereo: + return 2; + case LFE: + return 1; + default: + return 0; + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decinit.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decinit.h new file mode 100644 index 000000000..3871e4fb2 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decinit.h @@ -0,0 +1,19 @@ +#pragma once + +#include "error_codes.h" +#include "structures.h" +#include "huffCodes.h" + +at9_status init_decoder(atrac9_handle* handle, unsigned char * config_data, int wlength); +at9_status init_config_data(ConfigData* config, unsigned char * config_data); +at9_status read_config_data(ConfigData* config); +at9_status init_frame(atrac9_handle* handle); +at9_status init_block(block* block, frame* parent_frame, int block_index); +at9_status init_channel(channel* channel, block* parent_block, int channel_index); +void init_huffman_codebooks(); +void init_huffman_set(const HuffmanCodebook* codebooks, int count); +void GenerateTrigTables(int sizeBits); +void GenerateShuffleTable(int sizeBits); +void init_mdct_tables(int frameSizePower); +void GenerateMdctWindow(int frameSizePower); +void GenerateImdctWindow(int frameSizePower); diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decoder.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decoder.c new file mode 100644 index 000000000..4b63cc02d --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decoder.c @@ -0,0 +1,114 @@ +#include +#include "decoder.h" +#include "unpack.h" +#include "quantization.h" +#include "tables.h" +#include "imdct.h" +#include +#include "utility.h" +#include "band_extension.h" + +at9_status Decode(atrac9_handle* handle, const unsigned char* audio, unsigned char* pcm, int* bytesUsed) +{ + handle->frame.frameNum++; + bit_reader_cxt br; + init_bit_reader_cxt(&br, audio); + ERROR_CHECK(DecodeFrame(&handle->frame, &br)); + + PcmFloatToShort(&handle->frame, (short*)pcm); + + *bytesUsed = br.position / 8; + return ERR_SUCCESS; +} + +at9_status DecodeFrame(frame* frame, bit_reader_cxt* br) +{ + ERROR_CHECK(UnpackFrame(frame, br)); + + for (int i = 0; i < frame->config->ChannelConfig.BlockCount; i++) + { + block* block = &frame->Blocks[i]; + + DequantizeSpectra(block); + ApplyIntensityStereo(block); + ScaleSpectrumBlock(block); + ApplyBandExtension(block); + ImdctBlock(block); + } + + return ERR_SUCCESS; +} + +void PcmFloatToShort(frame* frame, short* pcmOut) +{ + const int endSample = frame->config->FrameSamples; + short* dest = pcmOut; + for (int d = 0, s = 0; s < endSample; d++, s++) + { + for (int i = 0; i < frame->config->ChannelConfig.BlockCount; i++) + { + block* block = &frame->Blocks[i]; + + for (int j = 0; j < block->ChannelCount; j++) + { + channel* channel = &block->Channels[j]; + double* pcmSrc = channel->Pcm; + + const double sample = pcmSrc[d]; + const int roundedSample = (int)floor(sample + 0.5); + *dest++ = Clamp16(roundedSample); + } + } + } +} + +void ImdctBlock(block* block) +{ + for (int i = 0; i < block->ChannelCount; i++) + { + channel* channel = &block->Channels[i]; + + RunImdct(&channel->mdct, channel->Spectra, channel->Pcm); + } +} + +void ApplyIntensityStereo(block* block) +{ + if (block->BlockType != Stereo) return; + + const int totalUnits = block->QuantizationUnitCount; + const int stereoUnits = block->StereoQuantizationUnit; + if (stereoUnits >= totalUnits) return; + + channel* source = &block->Channels[block->PrimaryChannelIndex == 0 ? 0 : 1]; + channel* dest = &block->Channels[block->PrimaryChannelIndex == 0 ? 1 : 0]; + + for (int i = stereoUnits; i < totalUnits; i++) + { + const int sign = block->JointStereoSigns[i]; + for (int sb = QuantUnitToCoeffIndex[i]; sb < QuantUnitToCoeffIndex[i + 1]; sb++) + { + if (sign > 0) + { + dest->Spectra[sb] = -source->Spectra[sb]; + } + else + { + dest->Spectra[sb] = source->Spectra[sb]; + } + } + } +} + +int GetCodecInfo(atrac9_handle* handle, CodecInfo * pCodecInfo) +{ + pCodecInfo->channels = handle->config.ChannelCount; + pCodecInfo->channelConfigIndex = handle->config.ChannelConfigIndex; + pCodecInfo->samplingRate = handle->config.SampleRate; + pCodecInfo->superframeSize = handle->config.SuperframeBytes; + pCodecInfo->framesInSuperframe = handle->config.FramesPerSuperframe; + pCodecInfo->frameSamples = handle->config.FrameSamples; + pCodecInfo->wlength = handle->wlength; + memcpy(pCodecInfo->configData, handle->config.ConfigData, CONFIG_DATA_SIZE); + return ERR_SUCCESS; +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decoder.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decoder.h new file mode 100644 index 000000000..62bf7cb76 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/decoder.h @@ -0,0 +1,11 @@ +#pragma once +#include "bit_reader.h" +#include "error_codes.h" +#include "structures.h" + +at9_status Decode(atrac9_handle* handle, const unsigned char* audio, unsigned char* pcm, int* bytesUsed); +at9_status DecodeFrame(frame* frame, bit_reader_cxt* br); +void ImdctBlock(block* block); +void ApplyIntensityStereo(block* block); +void PcmFloatToShort(frame* frame, short* pcmOut); +int GetCodecInfo(atrac9_handle* handle, CodecInfo* pCodecInfo); diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/error_codes.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/error_codes.h new file mode 100644 index 000000000..d40847d1c --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/error_codes.h @@ -0,0 +1,33 @@ +#pragma once + +typedef enum at9_status +{ + ERR_SUCCESS = 0, + + ERR_NOT_IMPLEMENTED = 0x80000000, + + ERR_BAD_CONFIG_DATA = 0x81000000, + + ERR_UNPACK_SUPERFRAME_FLAG_INVALID = 0x82000000, + ERR_UNPACK_REUSE_BAND_PARAMS_INVALID, + ERR_UNPACK_BAND_PARAMS_INVALID, + + ERR_UNPACK_GRAD_BOUNDARY_INVALID = 0x82100000, + ERR_UNPACK_GRAD_START_UNIT_OOB, + ERR_UNPACK_GRAD_END_UNIT_OOB, + ERR_UNPACK_GRAD_START_VALUE_OOB, + ERR_UNPACK_GRAD_END_VALUE_OOB, + ERR_UNPACK_GRAD_END_UNIT_INVALID, // start_unit > end_unit + + ERR_UNPACK_SCALE_FACTOR_MODE_INVALID, + ERR_UNPACK_SCALE_FACTOR_OOB, + + ERR_UNPACK_EXTENSION_DATA_INVALID +} at9_status; + +#define ERROR_CHECK(x) do { \ + at9_status status = (x); \ + if (status != ERR_SUCCESS) { \ + return status; \ + } \ +} while (0) \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/huffCodes.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/huffCodes.c new file mode 100644 index 000000000..2ee97e0d4 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/huffCodes.c @@ -0,0 +1,152 @@ +#include "huffCodes.h" +#include "utility.h" + +int ReadHuffmanValue(const HuffmanCodebook* huff, bit_reader_cxt* br, int is_signed) +{ + const int code = peek_int(br, huff->MaxBitSize); + const unsigned char value = huff->Lookup[code]; + const int bits = huff->Bits[value]; + br->position += bits; + return is_signed ? SignExtend32(value, huff->ValueBits) : value; +} + +void DecodeHuffmanValues(int* spectrum, int index, int bandCount, const HuffmanCodebook* huff, const int* values) +{ + const int valueCount = bandCount >> huff->ValueCountPower; + const int mask = (1 << huff->ValueBits) - 1; + + for (int i = 0; i < valueCount; i++) + { + int value = values[i]; + for (int j = 0; j < huff->ValueCount; j++) + { + spectrum[index++] = SignExtend32(value & mask, huff->ValueBits); + value >>= huff->ValueBits; + } + } +} + +void InitHuffmanCodebook(const HuffmanCodebook* codebook) +{ + const int huffLength = codebook->Length; + if (huffLength == 0) return; + + unsigned char* dest = codebook->Lookup; + + for (int i = 0; i < huffLength; i++) + { + if (codebook->Bits[i] == 0) continue; + const int unusedBits = codebook->MaxBitSize - codebook->Bits[i]; + + const int start = codebook->Codes[i] << unusedBits; + const int length = 1 << unusedBits; + const int end = start + length; + + for (int j = start; j < end; j++) + { + dest[j] = i; + } + } +} + +HuffmanCodebook HuffmanScaleFactorsUnsigned[7] = { + {0}, + {ScaleFactorsA1Bits, ScaleFactorsA1Codes, ScaleFactorsA1Lookup, 2, 1, 0, 1, 2, 1}, + {ScaleFactorsA2Bits, ScaleFactorsA2Codes, ScaleFactorsA2Lookup, 4, 1, 0, 2, 4, 3}, + {ScaleFactorsA3Bits, ScaleFactorsA3Codes, ScaleFactorsA3Lookup, 8, 1, 0, 3, 8, 6}, + {ScaleFactorsA4Bits, ScaleFactorsA4Codes, ScaleFactorsA4Lookup, 16, 1, 0, 4, 16, 8}, + {ScaleFactorsA5Bits, ScaleFactorsA5Codes, ScaleFactorsA5Lookup, 32, 1, 0, 5, 32, 8}, + {ScaleFactorsA6Bits, ScaleFactorsA6Codes, ScaleFactorsA6Lookup, 64, 1, 0, 6, 64, 8}, +}; + +HuffmanCodebook HuffmanScaleFactorsSigned[6] = { + {0}, + {0}, + {ScaleFactorsB2Bits, ScaleFactorsB2Codes, ScaleFactorsB2Lookup, 4, 1, 0, 2, 4, 2}, + {ScaleFactorsB3Bits, ScaleFactorsB3Codes, ScaleFactorsB3Lookup, 8, 1, 0, 3, 8, 6}, + {ScaleFactorsB4Bits, ScaleFactorsB4Codes, ScaleFactorsB4Lookup, 16, 1, 0, 4, 16, 8}, + {ScaleFactorsB5Bits, ScaleFactorsB5Codes, ScaleFactorsB5Lookup, 32, 1, 0, 5, 32, 8}, +}; + +HuffmanCodebook HuffmanSpectrum[2][8][4] = { + { + {0}, + {0}, + { + {SpectrumA21Bits, SpectrumA21Codes, SpectrumA21Lookup, 16, 2, 1, 2, 4, 3}, + {SpectrumA22Bits, SpectrumA22Codes, SpectrumA22Lookup, 256, 4, 2, 2, 4, 8}, + {SpectrumA23Bits, SpectrumA23Codes, SpectrumA23Lookup, 256, 4, 2, 2, 4, 9}, + {SpectrumA24Bits, SpectrumA24Codes, SpectrumA24Lookup, 256, 4, 2, 2, 4, 10} + }, + { + {SpectrumA31Bits, SpectrumA31Codes, SpectrumA31Lookup, 64, 2, 1, 3, 8, 7}, + {SpectrumA32Bits, SpectrumA32Codes, SpectrumA32Lookup, 64, 2, 1, 3, 8, 7}, + {SpectrumA33Bits, SpectrumA33Codes, SpectrumA33Lookup, 64, 2, 1, 3, 8, 8}, + {SpectrumA34Bits, SpectrumA34Codes, SpectrumA34Lookup, 64, 2, 1, 3, 8, 10} + }, + { + {SpectrumA41Bits, SpectrumA41Codes, SpectrumA41Lookup, 256, 2, 1, 4, 16, 9}, + {SpectrumA42Bits, SpectrumA42Codes, SpectrumA42Lookup, 256, 2, 1, 4, 16, 10}, + {SpectrumA43Bits, SpectrumA43Codes, SpectrumA43Lookup, 256, 2, 1, 4, 16, 10}, + {SpectrumA44Bits, SpectrumA44Codes, SpectrumA44Lookup, 256, 2, 1, 4, 16, 10} + }, + { + {SpectrumA51Bits, SpectrumA51Codes, SpectrumA51Lookup, 32, 1, 0, 5, 32, 6}, + {SpectrumA52Bits, SpectrumA52Codes, SpectrumA52Lookup, 32, 1, 0, 5, 32, 6}, + {SpectrumA53Bits, SpectrumA53Codes, SpectrumA53Lookup, 32, 1, 0, 5, 32, 7}, + {SpectrumA54Bits, SpectrumA54Codes, SpectrumA54Lookup, 32, 1, 0, 5, 32, 8} + }, + { + {SpectrumA61Bits, SpectrumA61Codes, SpectrumA61Lookup, 64, 1, 0, 6, 64, 7}, + {SpectrumA62Bits, SpectrumA62Codes, SpectrumA62Lookup, 64, 1, 0, 6, 64, 7}, + {SpectrumA63Bits, SpectrumA63Codes, SpectrumA63Lookup, 64, 1, 0, 6, 64, 8}, + {SpectrumA64Bits, SpectrumA64Codes, SpectrumA64Lookup, 64, 1, 0, 6, 64, 9} + }, + { + {SpectrumA71Bits, SpectrumA71Codes, SpectrumA71Lookup, 128, 1, 0, 7, 128, 8}, + {SpectrumA72Bits, SpectrumA72Codes, SpectrumA72Lookup, 128, 1, 0, 7, 128, 8}, + {SpectrumA73Bits, SpectrumA73Codes, SpectrumA73Lookup, 128, 1, 0, 7, 128, 9}, + {SpectrumA74Bits, SpectrumA74Codes, SpectrumA74Lookup, 128, 1, 0, 7, 128, 10} + } + }, + { + {0}, + {0}, + { + {0}, + {SpectrumB22Bits, SpectrumB22Codes, SpectrumB22Lookup, 256, 4, 2, 2, 4, 10}, + {SpectrumB23Bits, SpectrumB23Codes, SpectrumB23Lookup, 256, 4, 2, 2, 4, 10}, + {SpectrumB24Bits, SpectrumB24Codes, SpectrumB24Lookup, 256, 4, 2, 2, 4, 10} + }, + { + {0}, + {SpectrumB32Bits, SpectrumB32Codes, SpectrumB32Lookup, 64, 2, 1, 3, 8, 9}, + {SpectrumB33Bits, SpectrumB33Codes, SpectrumB33Lookup, 64, 2, 1, 3, 8, 10}, + {SpectrumB34Bits, SpectrumB34Codes, SpectrumB34Lookup, 64, 2, 1, 3, 8, 10} + }, + { + {0}, + {SpectrumB42Bits, SpectrumB42Codes, SpectrumB42Lookup, 256, 2, 1, 4, 16, 10}, + {SpectrumB43Bits, SpectrumB43Codes, SpectrumB43Lookup, 256, 2, 1, 4, 16, 10}, + {SpectrumB44Bits, SpectrumB44Codes, SpectrumB44Lookup, 256, 2, 1, 4, 16, 10} + }, + { + {0}, + {SpectrumB52Bits, SpectrumB52Codes, SpectrumB52Lookup, 32, 1, 0, 5, 32, 7}, + {SpectrumB53Bits, SpectrumB53Codes, SpectrumB53Lookup, 32, 1, 0, 5, 32, 8}, + {SpectrumB54Bits, SpectrumB54Codes, SpectrumB54Lookup, 32, 1, 0, 5, 32, 9} + }, + { + {0}, + {SpectrumB62Bits, SpectrumB62Codes, SpectrumB62Lookup, 64, 1, 0, 6, 64, 8}, + {SpectrumB63Bits, SpectrumB63Codes, SpectrumB63Lookup, 64, 1, 0, 6, 64, 9}, + {SpectrumB64Bits, SpectrumB64Codes, SpectrumB64Lookup, 64, 1, 0, 6, 64, 10} + }, + { + {0}, + {SpectrumB72Bits, SpectrumB72Codes, SpectrumB72Lookup, 128, 1, 0, 7, 128, 9}, + {SpectrumB73Bits, SpectrumB73Codes, SpectrumB73Lookup, 128, 1, 0, 7, 128, 10}, + {SpectrumB74Bits, SpectrumB74Codes, SpectrumB74Lookup, 128, 1, 0, 7, 128, 10} + } + } +}; diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/huffCodes.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/huffCodes.h new file mode 100644 index 000000000..a2fef16c2 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/huffCodes.h @@ -0,0 +1,1295 @@ +#pragma once +#include +#include "bit_reader.h" + +typedef struct +{ + const unsigned char* Bits; + const short* Codes; + unsigned char* Lookup; + const int Length; + const int ValueCount; + const int ValueCountPower; + const int ValueBits; + const int ValueMax; + const int MaxBitSize; +} HuffmanCodebook; + +int ReadHuffmanValue(const HuffmanCodebook* huff, bit_reader_cxt* br, int is_signed); +void DecodeHuffmanValues(int* spectrum, int index, int bandCount, const HuffmanCodebook* huff, const int* values); +void InitHuffmanCodebook(const HuffmanCodebook* codebook); + +extern HuffmanCodebook HuffmanScaleFactorsUnsigned[7]; +extern HuffmanCodebook HuffmanScaleFactorsSigned[6]; +extern HuffmanCodebook HuffmanSpectrum[2][8][4]; + +static const uint8_t ScaleFactorsA1Bits[2] = +{ + 1, 1 +}; + +static const uint16_t ScaleFactorsA1Codes[2] = +{ + 0x00, 0x01 +}; + +static const uint8_t ScaleFactorsA2Bits[4] = +{ + 1, 3, 3, 2 +}; + +static const uint16_t ScaleFactorsA2Codes[4] = +{ + 0x00, 0x06, 0x07, 0x02 +}; + +static const uint8_t ScaleFactorsA3Bits[8] = +{ + 2, 2, 4, 6, 6, 5, 3, 2 +}; + +static const uint16_t ScaleFactorsA3Codes[8] = +{ + 0x00, 0x01, 0x0E, 0x3E, 0x3F, 0x1E, 0x06, 0x02 +}; + +static const uint8_t ScaleFactorsA4Bits[16] = +{ + 2, 2, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 6, 5, 4, 2 +}; + +static const uint16_t ScaleFactorsA4Codes[16] = +{ + 0x01, 0x02, 0x00, 0x06, 0x0F, 0x13, 0x23, 0x24, 0x25, 0x22, 0x21, 0x20, 0x0E, 0x05, 0x01, 0x03 +}; + +static const uint8_t ScaleFactorsA5Bits[32] = +{ + 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 6, 5, 5, 4, 3 +}; + +static const uint16_t ScaleFactorsA5Codes[32] = +{ + 0x02, 0x01, 0x07, 0x0D, 0x0C, 0x18, 0x1B, 0x21, 0x3F, 0x6A, 0x6B, 0x68, 0x73, 0x79, 0x7C, 0x7D, + 0x7A, 0x7B, 0x78, 0x72, 0x44, 0x45, 0x47, 0x46, 0x69, 0x38, 0x20, 0x1D, 0x19, 0x09, 0x05, 0x00 +}; + +static const uint8_t ScaleFactorsA6Bits[64] = +{ + 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 4, 4, 4 +}; + +static const uint16_t ScaleFactorsA6Codes[64] = +{ + 0x00, 0x01, 0x04, 0x05, 0x12, 0x13, 0x2E, 0x2F, 0x30, 0x66, 0x67, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, + 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, + 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, + 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x68, 0x69, 0x6A, 0x31, 0x32, 0x14, 0x15, 0x16, 0x06, 0x07, 0x08 +}; + +static const uint8_t ScaleFactorsB2Bits[4] = +{ + 1, 2, 0, 2 +}; + +static const uint16_t ScaleFactorsB2Codes[4] = +{ + 0x00, 0x03, 0x00, 0x02 +}; + +static const uint8_t ScaleFactorsB3Bits[8] = +{ + 1, 3, 5, 6, 0, 6, 4, 2 +}; + +static const uint16_t ScaleFactorsB3Codes[8] = +{ + 0x01, 0x00, 0x04, 0x0B, 0x00, 0x0A, 0x03, 0x01 +}; + +static const uint8_t ScaleFactorsB4Bits[16] = +{ + 1, 3, 4, 5, 5, 7, 8, 8, 0, 8, 8, 7, 6, 6, 4, 3 +}; + +static const uint16_t ScaleFactorsB4Codes[16] = +{ + 0x01, 0x01, 0x04, 0x0E, 0x0F, 0x2C, 0x5A, 0x5D, 0x00, 0x5C, 0x5B, 0x2F, 0x15, 0x14, 0x06, 0x00 +}; + +static const uint8_t ScaleFactorsB5Bits[32] = +{ + 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 6, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 3 +}; + +static const uint16_t ScaleFactorsB5Codes[32] = +{ + 0x00, 0x05, 0x07, 0x0C, 0x04, 0x02, 0x03, 0x05, 0x09, 0x10, 0x23, 0x33, 0x36, 0x6E, 0x60, 0x65, + 0x62, 0x61, 0x63, 0x64, 0x6F, 0x6D, 0x6C, 0x6B, 0x6A, 0x68, 0x69, 0x45, 0x44, 0x37, 0x1A, 0x07 +}; + +static const uint8_t SpectrumA21Bits[16] = +{ + 0, 3, 0, 3, 3, 3, 0, 3, 0, 0, 0, 0, 3, 3, 0, 3 +}; + +static const uint16_t SpectrumA21Codes[16] = +{ + 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x06 +}; + +static const uint8_t SpectrumA22Bits[256] = +{ + 0, 4, 0, 4, 5, 6, 0, 6, 0, 0, 0, 0, 5, 6, 0, 6, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 6, 7, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 6, 7, 0, 7, + 5, 6, 0, 6, 7, 7, 0, 7, 0, 0, 0, 0, 6, 7, 0, 7, + 6, 7, 0, 7, 7, 8, 0, 8, 0, 0, 0, 0, 7, 8, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 7, 0, 7, 7, 8, 0, 8, 0, 0, 0, 0, 7, 7, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 7, 7, 0, 7, + 6, 7, 0, 7, 7, 8, 0, 7, 0, 0, 0, 0, 7, 8, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 7, 0, 7, 7, 7, 0, 8, 0, 0, 0, 0, 7, 8, 0, 8 +}; + +static const uint16_t SpectrumA22Codes[256] = +{ + 0x00, 0x02, 0x00, 0x03, 0x10, 0x3C, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x11, 0x3E, 0x00, 0x3D, + 0x0E, 0x00, 0x00, 0x39, 0x18, 0x26, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x24, 0x00, 0x6D, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x38, 0x00, 0x01, 0x1A, 0x6C, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x19, 0x74, 0x00, 0x27, + 0x16, 0x14, 0x00, 0x17, 0x76, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x35, 0x64, 0x00, 0x6F, + 0x26, 0x04, 0x00, 0x63, 0x22, 0xA2, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x67, 0xA0, 0x00, 0x0D, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2B, 0x52, 0x00, 0x0B, 0x20, 0x92, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x61, 0x0E, 0x00, 0x95, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x17, 0x16, 0x00, 0x15, 0x34, 0x6E, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x77, 0x08, 0x00, 0x07, + 0x2A, 0x0A, 0x00, 0x53, 0x60, 0x94, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x21, 0x90, 0x00, 0x93, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x62, 0x00, 0x05, 0x66, 0x0C, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x23, 0x96, 0x00, 0xA3 +}; + +static const uint8_t SpectrumA23Bits[256] = +{ + 3, 4, 0, 4, 5, 6, 0, 6, 0, 0, 0, 0, 5, 6, 0, 6, + 5, 7, 0, 6, 6, 8, 0, 7, 0, 0, 0, 0, 6, 8, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 7, 6, 7, 0, 8, 0, 0, 0, 0, 6, 7, 0, 8, + 5, 6, 0, 6, 7, 8, 0, 8, 0, 0, 0, 0, 6, 7, 0, 7, + 6, 8, 0, 7, 8, 9, 0, 9, 0, 0, 0, 0, 7, 9, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 8, 0, 8, 8, 9, 0, 9, 0, 0, 0, 0, 7, 8, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 7, 8, 0, 8, + 6, 8, 0, 8, 7, 9, 0, 8, 0, 0, 0, 0, 8, 9, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 7, 0, 8, 7, 8, 0, 9, 0, 0, 0, 0, 8, 9, 0, 9 +}; + +static const uint16_t SpectrumA23Codes[256] = +{ + 0x006, 0x002, 0x000, 0x003, 0x016, 0x01E, 0x000, 0x021, 0x000, 0x000, 0x000, 0x000, + 0x017, 0x020, 0x000, 0x01F, 0x01C, 0x054, 0x000, 0x027, 0x010, 0x0A6, 0x000, 0x027, + 0x000, 0x000, 0x000, 0x000, 0x015, 0x0A4, 0x000, 0x02D, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01D, 0x026, 0x000, 0x055, 0x014, 0x02C, 0x000, 0x0A5, 0x000, 0x000, 0x000, 0x000, + 0x011, 0x026, 0x000, 0x0A7, 0x01E, 0x000, 0x000, 0x003, 0x04A, 0x074, 0x000, 0x071, + 0x000, 0x000, 0x000, 0x000, 0x023, 0x00A, 0x000, 0x009, 0x018, 0x072, 0x000, 0x00D, + 0x0A2, 0x15A, 0x000, 0x123, 0x000, 0x000, 0x000, 0x000, 0x00F, 0x158, 0x000, 0x05D, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x01B, 0x0AE, 0x000, 0x077, 0x092, 0x140, 0x000, 0x121, + 0x000, 0x000, 0x000, 0x000, 0x025, 0x05E, 0x000, 0x143, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01F, 0x002, 0x000, 0x001, 0x022, 0x008, 0x000, 0x00B, 0x000, 0x000, 0x000, 0x000, + 0x04B, 0x070, 0x000, 0x075, 0x01A, 0x076, 0x000, 0x0AF, 0x024, 0x142, 0x000, 0x05F, + 0x000, 0x000, 0x000, 0x000, 0x093, 0x120, 0x000, 0x141, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x019, 0x00C, 0x000, 0x073, 0x00E, 0x05C, 0x000, 0x159, 0x000, 0x000, 0x000, 0x000, + 0x0A3, 0x122, 0x000, 0x15B +}; + +static const uint8_t SpectrumA24Bits[256] = +{ + 2, 4, 0, 4, 5, 6, 0, 6, 0, 0, 0, 0, 5, 6, 0, 6, + 5, 7, 0, 6, 6, 8, 0, 8, 0, 0, 0, 0, 6, 8, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 7, 6, 8, 0, 8, 0, 0, 0, 0, 6, 8, 0, 8, + 5, 7, 0, 7, 7, 9, 0, 9, 0, 0, 0, 0, 6, 8, 0, 8, + 6, 9, 0, 8, 8, 10, 0, 10, 0, 0, 0, 0, 8, 10, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 8, 0, 9, 9, 10, 0, 10, 0, 0, 0, 0, 8, 9, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 7, 0, 7, 6, 8, 0, 8, 0, 0, 0, 0, 7, 9, 0, 9, + 6, 9, 0, 8, 8, 10, 0, 9, 0, 0, 0, 0, 9, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 8, 0, 9, 8, 9, 0, 10, 0, 0, 0, 0, 8, 10, 0, 10 +}; + +static const uint16_t SpectrumA24Codes[256] = +{ + 0x002, 0x002, 0x000, 0x003, 0x01E, 0x010, 0x000, 0x013, 0x000, 0x000, 0x000, 0x000, + 0x01F, 0x012, 0x000, 0x011, 0x01A, 0x030, 0x000, 0x01B, 0x000, 0x064, 0x000, 0x0C1, + 0x000, 0x000, 0x000, 0x000, 0x003, 0x052, 0x000, 0x07D, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01B, 0x01A, 0x000, 0x031, 0x002, 0x07C, 0x000, 0x053, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x0C0, 0x000, 0x065, 0x01C, 0x062, 0x000, 0x065, 0x02A, 0x198, 0x000, 0x19B, + 0x000, 0x000, 0x000, 0x000, 0x017, 0x078, 0x000, 0x07B, 0x004, 0x0FE, 0x000, 0x077, + 0x050, 0x33A, 0x000, 0x1F9, 0x000, 0x000, 0x000, 0x000, 0x073, 0x338, 0x000, 0x0E1, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x007, 0x066, 0x000, 0x187, 0x19E, 0x308, 0x000, 0x30B, + 0x000, 0x000, 0x000, 0x000, 0x075, 0x0E2, 0x000, 0x1FB, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01D, 0x064, 0x000, 0x063, 0x016, 0x07A, 0x000, 0x079, 0x000, 0x000, 0x000, 0x000, + 0x02B, 0x19A, 0x000, 0x199, 0x006, 0x186, 0x000, 0x067, 0x074, 0x1FA, 0x000, 0x0E3, + 0x000, 0x000, 0x000, 0x000, 0x19F, 0x30A, 0x000, 0x309, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x005, 0x076, 0x000, 0x0FF, 0x072, 0x0E0, 0x000, 0x339, 0x000, 0x000, 0x000, 0x000, + 0x051, 0x1F8, 0x000, 0x33B +}; + +static const uint8_t SpectrumA31Bits[64] = +{ + 0, 0, 4, 5, 0, 5, 4, 0, 0, 0, 5, 5, 0, 5, 5, 0, + 5, 5, 6, 6, 0, 6, 5, 5, 5, 6, 6, 7, 0, 7, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 6, 7, 0, 7, 6, 6, + 5, 5, 5, 6, 0, 6, 6, 5, 0, 0, 5, 5, 0, 5, 5, 0 +}; + +static const uint16_t SpectrumA31Codes[64] = +{ + 0x00, 0x00, 0x02, 0x18, 0x00, 0x19, 0x03, 0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x09, 0x15, 0x00, + 0x1A, 0x0A, 0x3E, 0x2C, 0x00, 0x2F, 0x01, 0x0D, 0x0E, 0x38, 0x20, 0x78, 0x00, 0x7B, 0x23, 0x3B, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x3A, 0x22, 0x7A, 0x00, 0x79, 0x21, 0x39, + 0x1B, 0x0C, 0x00, 0x2E, 0x00, 0x2D, 0x3F, 0x0B, 0x00, 0x00, 0x14, 0x08, 0x00, 0x03, 0x13, 0x00 +}; + +static const uint8_t SpectrumA32Bits[64] = +{ + 4, 5, 5, 6, 0, 6, 5, 5, 5, 6, 5, 6, 0, 6, 5, 5, + 5, 5, 6, 7, 0, 7, 6, 5, 6, 6, 7, 7, 0, 7, 7, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 7, 7, 0, 7, 7, 6, + 5, 5, 6, 7, 0, 7, 6, 5, 5, 5, 5, 6, 0, 6, 5, 6 +}; + +static const uint16_t SpectrumA32Codes[64] = +{ + 0x0D, 0x18, 0x16, 0x3A, 0x00, 0x3B, 0x17, 0x19, 0x12, 0x3E, 0x08, 0x1C, 0x00, 0x1B, 0x07, 0x01, + 0x10, 0x02, 0x28, 0x78, 0x00, 0x7B, 0x1F, 0x05, 0x2A, 0x16, 0x72, 0x2A, 0x00, 0x29, 0x71, 0x19, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x18, 0x70, 0x28, 0x00, 0x2B, 0x73, 0x17, + 0x11, 0x04, 0x1E, 0x7A, 0x00, 0x79, 0x29, 0x03, 0x13, 0x00, 0x06, 0x1A, 0x00, 0x1D, 0x09, 0x3F +}; + +static const uint8_t SpectrumA33Bits[64] = +{ + 3, 4, 5, 6, 0, 6, 5, 4, 4, 5, 6, 7, 0, 7, 6, 5, + 5, 6, 6, 7, 0, 7, 6, 6, 6, 7, 8, 8, 0, 8, 8, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 8, 0, 8, 8, 7, + 5, 6, 6, 7, 0, 7, 6, 6, 4, 5, 6, 7, 0, 7, 6, 5 +}; + +static const uint16_t SpectrumA33Codes[64] = +{ + 0x05, 0x06, 0x10, 0x08, 0x00, 0x09, 0x11, 0x07, 0x04, 0x12, 0x3E, 0x6A, 0x00, 0x6D, 0x3D, 0x19, + 0x06, 0x3A, 0x06, 0x02, 0x00, 0x01, 0x05, 0x39, 0x02, 0x16, 0xDC, 0x2A, 0x00, 0x29, 0xDF, 0x69, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x68, 0xDE, 0x28, 0x00, 0x2B, 0xDD, 0x17, + 0x07, 0x38, 0x04, 0x00, 0x00, 0x03, 0x07, 0x3B, 0x05, 0x18, 0x3C, 0x6C, 0x00, 0x6B, 0x3F, 0x13 +}; + +static const uint8_t SpectrumA34Bits[64] = +{ + 2, 4, 5, 7, 0, 7, 5, 4, 4, 5, 6, 8, 0, 8, 6, 5, + 5, 6, 7, 8, 0, 8, 7, 6, 7, 8, 8, 10, 0, 10, 9, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 10, 0, 10, 8, 8, + 5, 6, 7, 8, 0, 8, 7, 6, 4, 5, 6, 8, 0, 8, 6, 5 +}; + +static const uint16_t SpectrumA34Codes[64] = +{ + 0x000, 0x00A, 0x00A, 0x034, 0x000, 0x035, 0x00B, 0x00B, 0x008, 0x01C, 0x032, 0x0DA, + 0x000, 0x0DD, 0x035, 0x01F, 0x008, 0x01E, 0x03A, 0x06C, 0x000, 0x063, 0x039, 0x031, + 0x032, 0x06E, 0x060, 0x37A, 0x000, 0x379, 0x1BF, 0x0D9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x033, 0x0D8, 0x1BE, 0x378, 0x000, 0x37B, 0x061, 0x06F, + 0x009, 0x030, 0x038, 0x062, 0x000, 0x06D, 0x03B, 0x01F, 0x009, 0x01E, 0x034, 0x0DC, + 0x000, 0x0DB, 0x033, 0x01D +}; + +static const uint8_t SpectrumA41Bits[256] = +{ + 0, 0, 0, 0, 6, 6, 7, 7, 0, 7, 7, 6, 6, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 7, 0, 7, 7, 7, 6, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 8, 0, 8, 7, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 8, 8, 0, 8, 8, 7, 7, 0, 0, 0, + 7, 7, 7, 8, 7, 8, 8, 8, 0, 8, 8, 8, 7, 8, 7, 7, + 7, 7, 7, 7, 8, 8, 8, 9, 0, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 8, 8, 8, 8, 9, 9, 0, 9, 8, 8, 8, 8, 8, 7, + 8, 8, 8, 8, 8, 9, 9, 9, 0, 9, 9, 9, 8, 8, 8, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 9, 9, 9, 0, 9, 9, 9, 8, 8, 8, 8, + 7, 7, 8, 8, 8, 8, 8, 9, 0, 9, 9, 8, 8, 8, 8, 7, + 7, 7, 7, 7, 8, 8, 8, 8, 0, 9, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 8, 7, 8, 8, 8, 0, 8, 8, 8, 7, 8, 7, 7, + 0, 0, 0, 0, 7, 7, 8, 8, 0, 8, 8, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 8, 0, 8, 7, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 6, 7, 7, 7, 0, 7, 7, 7, 7, 0, 0, 0 +}; + +static const uint16_t SpectrumA41Codes[256] = +{ + 0x000, 0x000, 0x000, 0x000, 0x018, 0x00E, 0x05E, 0x028, 0x000, 0x029, 0x05F, 0x00F, + 0x019, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x076, 0x06E, 0x03E, 0x004, + 0x000, 0x017, 0x045, 0x07B, 0x013, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x04A, 0x048, 0x010, 0x0CE, 0x000, 0x0E1, 0x023, 0x055, 0x053, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x008, 0x018, 0x0D6, 0x09E, 0x000, 0x09D, 0x0E5, 0x02B, + 0x01B, 0x000, 0x000, 0x000, 0x07C, 0x05C, 0x038, 0x0FC, 0x002, 0x0D2, 0x09A, 0x05C, + 0x000, 0x06B, 0x0A3, 0x0D9, 0x00F, 0x0FF, 0x03D, 0x061, 0x074, 0x056, 0x036, 0x000, + 0x0CC, 0x08C, 0x058, 0x1E2, 0x000, 0x00F, 0x05F, 0x0A1, 0x0D5, 0x00D, 0x03B, 0x059, + 0x040, 0x014, 0x0DA, 0x0B6, 0x084, 0x040, 0x1E0, 0x196, 0x000, 0x1A1, 0x00D, 0x043, + 0x087, 0x0C7, 0x0E3, 0x00B, 0x0F2, 0x0C4, 0x08E, 0x05A, 0x024, 0x1CC, 0x194, 0x168, + 0x000, 0x16B, 0x1A3, 0x1CF, 0x027, 0x069, 0x099, 0x0C9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x0F3, 0x0C8, 0x098, 0x068, 0x026, 0x1CE, 0x1A2, 0x16A, 0x000, 0x169, 0x195, 0x1CD, + 0x025, 0x05B, 0x08F, 0x0C5, 0x041, 0x00A, 0x0E2, 0x0C6, 0x086, 0x042, 0x00C, 0x1A0, + 0x000, 0x197, 0x1E1, 0x041, 0x085, 0x0B7, 0x0DB, 0x015, 0x075, 0x058, 0x03A, 0x00C, + 0x0D4, 0x0A0, 0x05E, 0x00E, 0x000, 0x1E3, 0x059, 0x08D, 0x0CD, 0x001, 0x037, 0x057, + 0x07D, 0x060, 0x03C, 0x0FE, 0x00E, 0x0D8, 0x0A2, 0x06A, 0x000, 0x05D, 0x09B, 0x0D3, + 0x003, 0x0FD, 0x039, 0x05D, 0x000, 0x000, 0x000, 0x000, 0x01A, 0x02A, 0x0E4, 0x09C, + 0x000, 0x09F, 0x0D7, 0x019, 0x009, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x052, 0x054, 0x022, 0x0E0, 0x000, 0x0CF, 0x011, 0x049, 0x04B, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x012, 0x07A, 0x044, 0x016, 0x000, 0x005, 0x03F, 0x06F, + 0x077, 0x000, 0x000, 0x000 +}; + +static const uint8_t SpectrumA42Bits[256] = +{ + 5, 6, 7, 7, 7, 7, 8, 8, 0, 8, 8, 7, 7, 7, 7, 6, + 6, 7, 7, 8, 7, 7, 8, 8, 0, 8, 8, 7, 7, 8, 7, 7, + 7, 7, 8, 8, 7, 8, 8, 9, 0, 9, 8, 8, 7, 8, 8, 7, + 8, 8, 8, 8, 8, 8, 8, 9, 0, 9, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 8, 8, 8, 9, 9, 0, 9, 9, 8, 8, 8, 7, 7, + 7, 7, 8, 8, 8, 9, 9, 9, 0, 9, 9, 9, 8, 8, 8, 7, + 8, 8, 8, 8, 9, 9, 9, 10, 0, 10, 9, 9, 9, 8, 8, 8, + 8, 8, 9, 9, 9, 9, 10, 10, 0, 10, 10, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 9, 9, 9, 9, 10, 10, 0, 10, 10, 9, 9, 9, 9, 8, + 8, 8, 8, 8, 9, 9, 9, 10, 0, 10, 9, 9, 9, 8, 8, 8, + 7, 7, 8, 8, 8, 9, 9, 9, 0, 9, 9, 9, 8, 8, 8, 7, + 7, 7, 7, 8, 8, 8, 9, 9, 0, 9, 9, 8, 8, 8, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 9, 0, 9, 8, 8, 8, 8, 8, 8, + 7, 7, 8, 8, 7, 8, 8, 9, 0, 9, 8, 8, 7, 8, 8, 7, + 6, 7, 7, 8, 7, 7, 8, 8, 0, 8, 8, 7, 7, 8, 7, 7 +}; + +static const uint16_t SpectrumA42Codes[256] = +{ + 0x003, 0x018, 0x058, 0x000, 0x066, 0x03C, 0x0D6, 0x07C, 0x000, 0x07D, 0x0D7, 0x03D, + 0x067, 0x001, 0x059, 0x019, 0x002, 0x064, 0x036, 0x0DA, 0x04C, 0x01C, 0x0BE, 0x02C, + 0x000, 0x037, 0x0C5, 0x029, 0x04B, 0x0E7, 0x03B, 0x069, 0x044, 0x02E, 0x0FA, 0x092, + 0x020, 0x0F8, 0x086, 0x1FC, 0x000, 0x1E7, 0x07F, 0x0F5, 0x023, 0x0AD, 0x0FD, 0x02D, + 0x0F6, 0x0DC, 0x09C, 0x03E, 0x0F0, 0x0B6, 0x026, 0x186, 0x000, 0x18D, 0x02F, 0x0B5, + 0x0E1, 0x03D, 0x0AF, 0x0D9, 0x054, 0x040, 0x014, 0x0EC, 0x0BC, 0x054, 0x1C6, 0x108, + 0x000, 0x10B, 0x1C5, 0x069, 0x0B9, 0x0DF, 0x019, 0x047, 0x026, 0x008, 0x0E4, 0x0A2, + 0x056, 0x1DC, 0x142, 0x06A, 0x000, 0x091, 0x123, 0x1DF, 0x04B, 0x0A7, 0x0EB, 0x00B, + 0x0C0, 0x09E, 0x06A, 0x022, 0x1AA, 0x140, 0x092, 0x3CA, 0x000, 0x3A7, 0x04B, 0x121, + 0x18F, 0x007, 0x071, 0x0A5, 0x020, 0x004, 0x1A8, 0x174, 0x0E4, 0x068, 0x3A4, 0x2EE, + 0x000, 0x2ED, 0x3C9, 0x049, 0x0E7, 0x185, 0x1D1, 0x1FF, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x021, 0x1FE, 0x1D0, 0x184, 0x0E6, 0x048, 0x3C8, 0x2EC, 0x000, 0x2EF, 0x3A5, 0x069, + 0x0E5, 0x175, 0x1A9, 0x005, 0x0C1, 0x0A4, 0x070, 0x006, 0x18E, 0x120, 0x04A, 0x3A6, + 0x000, 0x3CB, 0x093, 0x141, 0x1AB, 0x023, 0x06B, 0x09F, 0x027, 0x00A, 0x0EA, 0x0A6, + 0x04A, 0x1DE, 0x122, 0x090, 0x000, 0x06B, 0x143, 0x1DD, 0x057, 0x0A3, 0x0E5, 0x009, + 0x055, 0x046, 0x018, 0x0DE, 0x0B8, 0x068, 0x1C4, 0x10A, 0x000, 0x109, 0x1C7, 0x055, + 0x0BD, 0x0ED, 0x015, 0x041, 0x0F7, 0x0D8, 0x0AE, 0x03C, 0x0E0, 0x0B4, 0x02E, 0x18C, + 0x000, 0x187, 0x027, 0x0B7, 0x0F1, 0x03F, 0x09D, 0x0DD, 0x045, 0x02C, 0x0FC, 0x0AC, + 0x022, 0x0F4, 0x07E, 0x1E6, 0x000, 0x1FD, 0x087, 0x0F9, 0x021, 0x093, 0x0FB, 0x02F, + 0x003, 0x068, 0x03A, 0x0E6, 0x04A, 0x028, 0x0C4, 0x036, 0x000, 0x02D, 0x0BF, 0x01D, + 0x04D, 0x0DB, 0x037, 0x065 +}; + +static const uint8_t SpectrumA43Bits[256] = +{ + 4, 6, 6, 7, 7, 8, 8, 9, 0, 9, 8, 8, 7, 7, 6, 6, + 5, 6, 7, 7, 7, 8, 8, 9, 0, 9, 8, 8, 7, 7, 7, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 0, 9, 9, 8, 8, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 9, 10, 0, 10, 9, 9, 8, 8, 7, 7, + 7, 7, 8, 8, 8, 9, 10, 10, 0, 10, 10, 9, 8, 8, 8, 7, + 8, 8, 8, 9, 9, 9, 10, 10, 0, 10, 10, 9, 9, 9, 8, 8, + 8, 9, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 9, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 8, 9, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 9, + 8, 8, 8, 9, 9, 9, 10, 10, 0, 10, 10, 9, 9, 9, 8, 8, + 7, 7, 8, 8, 8, 9, 10, 10, 0, 10, 10, 9, 8, 8, 8, 7, + 7, 7, 7, 8, 8, 9, 9, 10, 0, 10, 9, 8, 8, 8, 7, 7, + 6, 7, 7, 7, 8, 8, 9, 9, 0, 9, 9, 8, 8, 7, 7, 7, + 5, 6, 7, 7, 7, 8, 8, 9, 0, 9, 8, 8, 7, 7, 7, 6 +}; + +static const uint16_t SpectrumA43Codes[256] = +{ + 0x002, 0x03E, 0x016, 0x060, 0x04E, 0x0DC, 0x04A, 0x130, 0x000, 0x131, 0x04B, 0x0DD, + 0x04F, 0x061, 0x017, 0x03F, 0x002, 0x02C, 0x076, 0x042, 0x034, 0x0CE, 0x002, 0x0E8, + 0x000, 0x0CF, 0x001, 0x0D1, 0x037, 0x045, 0x07B, 0x02F, 0x014, 0x072, 0x052, 0x01A, + 0x0E0, 0x080, 0x198, 0x01E, 0x000, 0x01D, 0x19B, 0x083, 0x0DF, 0x019, 0x055, 0x079, + 0x050, 0x03C, 0x004, 0x0C4, 0x096, 0x00C, 0x0EA, 0x34A, 0x000, 0x34F, 0x0ED, 0x1D7, + 0x095, 0x0AF, 0x003, 0x03F, 0x046, 0x026, 0x0D6, 0x092, 0x046, 0x15A, 0x3A8, 0x108, + 0x000, 0x10F, 0x3A3, 0x135, 0x039, 0x091, 0x0D9, 0x031, 0x0D4, 0x0CA, 0x072, 0x1C6, + 0x136, 0x090, 0x2B2, 0x104, 0x000, 0x103, 0x111, 0x08B, 0x133, 0x1D3, 0x071, 0x0C9, + 0x03E, 0x1B4, 0x18C, 0x0CC, 0x38A, 0x2B0, 0x106, 0x0F2, 0x000, 0x0EF, 0x101, 0x113, + 0x3A1, 0x0CB, 0x18F, 0x1B7, 0x0EE, 0x092, 0x388, 0x348, 0x10A, 0x0F4, 0x0F0, 0x0EA, + 0x000, 0x0E9, 0x0ED, 0x0F7, 0x10D, 0x34D, 0x3AB, 0x0C9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x0EF, 0x0C8, 0x3AA, 0x34C, 0x10C, 0x0F6, 0x0EC, 0x0E8, 0x000, 0x0EB, 0x0F1, 0x0F5, + 0x10B, 0x349, 0x389, 0x093, 0x03F, 0x1B6, 0x18E, 0x0CA, 0x3A0, 0x112, 0x100, 0x0EE, + 0x000, 0x0F3, 0x107, 0x2B1, 0x38B, 0x0CD, 0x18D, 0x1B5, 0x0D5, 0x0C8, 0x070, 0x1D2, + 0x132, 0x08A, 0x110, 0x102, 0x000, 0x105, 0x2B3, 0x091, 0x137, 0x1C7, 0x073, 0x0CB, + 0x047, 0x030, 0x0D8, 0x090, 0x038, 0x134, 0x3A2, 0x10E, 0x000, 0x109, 0x3A9, 0x15B, + 0x047, 0x093, 0x0D7, 0x027, 0x051, 0x03E, 0x002, 0x0AE, 0x094, 0x1D6, 0x0EC, 0x34E, + 0x000, 0x34B, 0x0EB, 0x00D, 0x097, 0x0C5, 0x005, 0x03D, 0x015, 0x078, 0x054, 0x018, + 0x0DE, 0x082, 0x19A, 0x01C, 0x000, 0x01F, 0x199, 0x081, 0x0E1, 0x01B, 0x053, 0x073, + 0x003, 0x02E, 0x07A, 0x044, 0x036, 0x0D0, 0x000, 0x0CE, 0x000, 0x0E9, 0x003, 0x0CF, + 0x035, 0x043, 0x077, 0x02D +}; + +static const uint8_t SpectrumA44Bits[256] = +{ + 4, 5, 6, 7, 7, 8, 9, 10, 0, 10, 9, 8, 7, 7, 6, 5, + 5, 6, 6, 7, 7, 8, 9, 10, 0, 10, 9, 8, 7, 7, 6, 6, + 6, 6, 7, 7, 8, 9, 10, 10, 0, 10, 10, 9, 8, 7, 7, 6, + 7, 7, 7, 8, 8, 9, 10, 10, 0, 10, 10, 9, 8, 8, 7, 7, + 7, 8, 8, 8, 9, 10, 10, 10, 0, 10, 10, 10, 9, 8, 8, 7, + 8, 8, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 8, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 8, 8, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 8, + 7, 7, 8, 8, 9, 10, 10, 10, 0, 10, 10, 10, 9, 8, 8, 8, + 7, 7, 7, 8, 8, 9, 10, 10, 0, 10, 10, 9, 8, 8, 7, 7, + 6, 6, 7, 7, 8, 9, 10, 10, 0, 10, 10, 9, 8, 7, 7, 6, + 5, 6, 6, 7, 7, 8, 9, 10, 0, 10, 9, 8, 7, 7, 6, 6 +}; + +static const uint16_t SpectrumA44Codes[256] = +{ + 0x00A, 0x012, 0x030, 0x06E, 0x024, 0x074, 0x0EC, 0x07E, 0x000, 0x07F, 0x0ED, 0x075, + 0x025, 0x06F, 0x031, 0x013, 0x010, 0x03C, 0x018, 0x05A, 0x002, 0x046, 0x09E, 0x07C, + 0x000, 0x079, 0x0E5, 0x04D, 0x007, 0x065, 0x01B, 0x03F, 0x02E, 0x016, 0x072, 0x01A, + 0x0D6, 0x1C6, 0x3B4, 0x066, 0x000, 0x06B, 0x3B7, 0x1D9, 0x0D5, 0x021, 0x075, 0x015, + 0x06C, 0x03E, 0x01E, 0x0CC, 0x044, 0x0F2, 0x082, 0x05C, 0x000, 0x05F, 0x087, 0x0F5, + 0x031, 0x0CF, 0x017, 0x059, 0x01C, 0x0EE, 0x0D0, 0x024, 0x1C0, 0x08E, 0x06E, 0x048, + 0x000, 0x04D, 0x06D, 0x089, 0x0F7, 0x033, 0x0D3, 0x001, 0x070, 0x028, 0x1C2, 0x0F0, + 0x08A, 0x074, 0x054, 0x040, 0x000, 0x043, 0x053, 0x073, 0x099, 0x0EF, 0x1C5, 0x02B, + 0x0E6, 0x04E, 0x08C, 0x080, 0x068, 0x058, 0x046, 0x02A, 0x000, 0x029, 0x045, 0x051, + 0x065, 0x085, 0x09B, 0x09D, 0x07A, 0x076, 0x060, 0x056, 0x04E, 0x02C, 0x024, 0x022, + 0x000, 0x021, 0x027, 0x02F, 0x04B, 0x05B, 0x063, 0x071, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x07B, 0x070, 0x062, 0x05A, 0x04A, 0x02E, 0x026, 0x020, 0x000, 0x023, 0x025, 0x02D, + 0x04F, 0x057, 0x061, 0x077, 0x0E7, 0x09C, 0x09A, 0x084, 0x064, 0x050, 0x044, 0x028, + 0x000, 0x02B, 0x047, 0x059, 0x069, 0x081, 0x08D, 0x04F, 0x071, 0x02A, 0x1C4, 0x0EE, + 0x098, 0x072, 0x052, 0x042, 0x000, 0x041, 0x055, 0x075, 0x08B, 0x0F1, 0x1C3, 0x029, + 0x01D, 0x000, 0x0D2, 0x032, 0x0F6, 0x088, 0x06C, 0x04C, 0x000, 0x049, 0x06F, 0x08F, + 0x1C1, 0x025, 0x0D1, 0x0EF, 0x06D, 0x058, 0x016, 0x0CE, 0x030, 0x0F4, 0x086, 0x05E, + 0x000, 0x05D, 0x083, 0x0F3, 0x045, 0x0CD, 0x01F, 0x03F, 0x02F, 0x014, 0x074, 0x020, + 0x0D4, 0x1D8, 0x3B6, 0x06A, 0x000, 0x067, 0x3B5, 0x1C7, 0x0D7, 0x01B, 0x073, 0x017, + 0x011, 0x03E, 0x01A, 0x064, 0x006, 0x04C, 0x0E4, 0x078, 0x000, 0x07D, 0x09F, 0x047, + 0x003, 0x05B, 0x019, 0x03D +}; + +static const uint8_t SpectrumA51Bits[32] = +{ + 5, 5, 5, 5, 5, 6, 6, 6, 4, 4, 5, 5, 5, 5, 5, 5, + 0, 5, 5, 5, 5, 5, 5, 4, 4, 6, 6, 6, 5, 5, 5, 5 +}; + +static const uint16_t SpectrumA51Codes[32] = +{ + 0x19, 0x16, 0x12, 0x0E, 0x06, 0x3A, 0x38, 0x30, 0x00, 0x04, 0x1E, 0x1A, 0x14, 0x10, 0x0C, 0x04, + 0x00, 0x05, 0x0D, 0x11, 0x15, 0x1B, 0x1F, 0x05, 0x01, 0x31, 0x39, 0x3B, 0x07, 0x0F, 0x13, 0x17 +}; + +static const uint8_t SpectrumA52Bits[32] = +{ + 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, + 0, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4 +}; + +static const uint16_t SpectrumA52Codes[32] = +{ + 0x09, 0x04, 0x00, 0x1E, 0x1A, 0x14, 0x0C, 0x06, 0x18, 0x16, 0x0E, 0x04, 0x3A, 0x38, 0x22, 0x20, + 0x00, 0x21, 0x23, 0x39, 0x3B, 0x05, 0x0F, 0x17, 0x19, 0x07, 0x0D, 0x15, 0x1B, 0x1F, 0x01, 0x05 +}; + +static const uint8_t SpectrumA53Bits[32] = +{ + 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 7, + 0, 7, 7, 7, 7, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4 +}; + +static const uint16_t SpectrumA53Codes[32] = +{ + 0x00, 0x0C, 0x08, 0x04, 0x1E, 0x16, 0x14, 0x06, 0x0C, 0x04, 0x38, 0x1E, 0x76, 0x74, 0x3A, 0x38, + 0x00, 0x39, 0x3B, 0x75, 0x77, 0x1F, 0x39, 0x05, 0x0D, 0x07, 0x15, 0x17, 0x1F, 0x05, 0x09, 0x0D +}; + +static const uint8_t SpectrumA54Bits[32] = +{ + 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, + 0, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4 +}; + +static const uint16_t SpectrumA54Codes[32] = +{ + 0x02, 0x0E, 0x0A, 0x08, 0x02, 0x1A, 0x0E, 0x02, 0x00, 0x30, 0x18, 0x66, 0x36, 0x34, 0xCA, 0xC8, + 0x00, 0xC9, 0xCB, 0x35, 0x37, 0x67, 0x19, 0x31, 0x01, 0x03, 0x0F, 0x1B, 0x03, 0x09, 0x0B, 0x0F +}; + +static const uint8_t SpectrumA61Bits[64] = +{ + 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, + 5, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6 +}; + +static const uint16_t SpectrumA61Codes[64] = +{ + 0x35, 0x30, 0x2A, 0x28, 0x24, 0x20, 0x18, 0x0E, 0x0C, 0x7E, 0x7C, 0x72, 0x70, 0x68, 0x5E, 0x5C, + 0x04, 0x0E, 0x08, 0x00, 0x3C, 0x3A, 0x36, 0x32, 0x2C, 0x26, 0x22, 0x1A, 0x16, 0x14, 0x06, 0x04, + 0x00, 0x05, 0x07, 0x15, 0x17, 0x1B, 0x23, 0x27, 0x2D, 0x33, 0x37, 0x3B, 0x3D, 0x01, 0x09, 0x0F, + 0x05, 0x5D, 0x5F, 0x69, 0x71, 0x73, 0x7D, 0x7F, 0x0D, 0x0F, 0x19, 0x21, 0x25, 0x29, 0x2B, 0x31 +}; + +static const uint8_t SpectrumA62Bits[64] = +{ + 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 0, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 +}; + +static const uint16_t SpectrumA62Codes[64] = +{ + 0x14, 0x0E, 0x08, 0x04, 0x02, 0x3E, 0x3C, 0x38, 0x34, 0x30, 0x2A, 0x24, 0x1A, 0x18, 0x0E, 0x02, + 0x32, 0x36, 0x2C, 0x26, 0x20, 0x16, 0x0C, 0x00, 0x76, 0x74, 0x5E, 0x5C, 0x46, 0x44, 0x2A, 0x28, + 0x00, 0x29, 0x2B, 0x45, 0x47, 0x5D, 0x5F, 0x75, 0x77, 0x01, 0x0D, 0x17, 0x21, 0x27, 0x2D, 0x37, + 0x33, 0x03, 0x0F, 0x19, 0x1B, 0x25, 0x2B, 0x31, 0x35, 0x39, 0x3D, 0x3F, 0x03, 0x05, 0x09, 0x0F +}; + +static const uint8_t SpectrumA63Bits[64] = +{ + 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, + 0, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5 +}; + +static const uint16_t SpectrumA63Codes[64] = +{ + 0x00, 0x1C, 0x18, 0x14, 0x10, 0x0A, 0x08, 0x02, 0x3E, 0x36, 0x2E, 0x2C, 0x24, 0x1C, 0x0E, 0x08, + 0x1E, 0x1A, 0x0C, 0x7A, 0x6A, 0x68, 0x4C, 0x32, 0x16, 0x14, 0xF2, 0xF0, 0x9E, 0x9C, 0x62, 0x60, + 0x00, 0x61, 0x63, 0x9D, 0x9F, 0xF1, 0xF3, 0x15, 0x17, 0x33, 0x4D, 0x69, 0x6B, 0x7B, 0x0D, 0x1B, + 0x1F, 0x09, 0x0F, 0x1D, 0x25, 0x2D, 0x2F, 0x37, 0x3F, 0x03, 0x09, 0x0B, 0x11, 0x15, 0x19, 0x1D +}; + +static const uint8_t SpectrumA64Bits[64] = +{ + 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, + 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, + 6, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4 +}; + +static const uint16_t SpectrumA64Codes[64] = +{ + 0x006, 0x002, 0x01C, 0x01A, 0x016, 0x012, 0x00E, 0x00A, 0x002, 0x03E, 0x032, 0x02A, + 0x022, 0x020, 0x010, 0x07A, 0x000, 0x078, 0x060, 0x050, 0x024, 0x006, 0x0C6, 0x0C4, + 0x0A4, 0x04E, 0x00A, 0x008, 0x14E, 0x14C, 0x09A, 0x098, 0x000, 0x099, 0x09B, 0x14D, + 0x14F, 0x009, 0x00B, 0x04F, 0x0A5, 0x0C5, 0x0C7, 0x007, 0x025, 0x051, 0x061, 0x079, + 0x001, 0x07B, 0x011, 0x021, 0x023, 0x02B, 0x033, 0x03F, 0x003, 0x00B, 0x00F, 0x013, + 0x017, 0x01B, 0x01D, 0x003 +}; + +static const uint8_t SpectrumA71Bits[128] = +{ + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, + 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static const uint16_t SpectrumA71Codes[128] = +{ + 0x6C, 0x66, 0x62, 0x5C, 0x56, 0x50, 0x52, 0x4E, 0x48, 0x3E, 0x36, 0x34, 0x2A, 0x26, 0x1E, 0x16, + 0x0E, 0x08, 0x00, 0xF6, 0xF4, 0xEE, 0xEC, 0xE2, 0xE0, 0xDA, 0xD2, 0xD0, 0xBE, 0xBC, 0xB2, 0xB0, + 0x0C, 0x20, 0x1C, 0x16, 0x10, 0x08, 0x02, 0x7E, 0x7C, 0x78, 0x74, 0x72, 0x6E, 0x6A, 0x64, 0x60, + 0x5A, 0x54, 0x4C, 0x4A, 0x46, 0x44, 0x3C, 0x32, 0x30, 0x28, 0x24, 0x1C, 0x14, 0x0C, 0x0A, 0x02, + 0x00, 0x03, 0x0B, 0x0D, 0x15, 0x1D, 0x25, 0x29, 0x31, 0x33, 0x3D, 0x45, 0x47, 0x4B, 0x4D, 0x55, + 0x5B, 0x61, 0x65, 0x6B, 0x6F, 0x73, 0x75, 0x79, 0x7D, 0x7F, 0x03, 0x09, 0x11, 0x17, 0x1D, 0x21, + 0x0D, 0xB1, 0xB3, 0xBD, 0xBF, 0xD1, 0xD3, 0xDB, 0xE1, 0xE3, 0xED, 0xEF, 0xF5, 0xF7, 0x01, 0x09, + 0x0F, 0x17, 0x1F, 0x27, 0x2B, 0x35, 0x37, 0x3F, 0x49, 0x4F, 0x53, 0x51, 0x57, 0x5D, 0x63, 0x67 +}; + +static const uint8_t SpectrumA72Bits[128] = +{ + 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6 +}; + +static const uint16_t SpectrumA72Codes[128] = +{ + 0x2A, 0x24, 0x1C, 0x18, 0x12, 0x0E, 0x0A, 0x06, 0x02, 0x7E, 0x7C, 0x7A, 0x76, 0x72, 0x70, 0x6A, + 0x68, 0x62, 0x5C, 0x5A, 0x52, 0x4E, 0x46, 0x42, 0x3C, 0x34, 0x2A, 0x28, 0x20, 0x12, 0x10, 0x08, + 0x66, 0x74, 0x6C, 0x64, 0x5E, 0x58, 0x50, 0x44, 0x40, 0x36, 0x2C, 0x22, 0x1A, 0x0A, 0x02, 0x00, + 0xF2, 0xF0, 0xDE, 0xDC, 0xC2, 0xC0, 0xAE, 0xAC, 0x9A, 0x98, 0x7E, 0x7C, 0x5E, 0x5C, 0x32, 0x30, + 0x00, 0x31, 0x33, 0x5D, 0x5F, 0x7D, 0x7F, 0x99, 0x9B, 0xAD, 0xAF, 0xC1, 0xC3, 0xDD, 0xDF, 0xF1, + 0xF3, 0x01, 0x03, 0x0B, 0x1B, 0x23, 0x2D, 0x37, 0x41, 0x45, 0x51, 0x59, 0x5F, 0x65, 0x6D, 0x75, + 0x67, 0x09, 0x11, 0x13, 0x21, 0x29, 0x2B, 0x35, 0x3D, 0x43, 0x47, 0x4F, 0x53, 0x5B, 0x5D, 0x63, + 0x69, 0x6B, 0x71, 0x73, 0x77, 0x7B, 0x7D, 0x7F, 0x03, 0x07, 0x0B, 0x0F, 0x13, 0x19, 0x1D, 0x25 +}; + +static const uint8_t SpectrumA73Bits[128] = +{ + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 +}; + +static const uint16_t SpectrumA73Codes[128] = +{ + 0x003, 0x03E, 0x038, 0x034, 0x030, 0x02C, 0x028, 0x024, 0x020, 0x01C, 0x016, 0x014, + 0x00E, 0x00A, 0x004, 0x000, 0x07A, 0x076, 0x06E, 0x06C, 0x064, 0x05E, 0x056, 0x04E, + 0x04C, 0x044, 0x036, 0x030, 0x022, 0x018, 0x012, 0x004, 0x03C, 0x03E, 0x032, 0x024, + 0x020, 0x010, 0x0F2, 0x0F0, 0x0E8, 0x0CE, 0x0BA, 0x0B8, 0x0A8, 0x08C, 0x06A, 0x04E, + 0x04C, 0x034, 0x00E, 0x00C, 0x1D6, 0x1D4, 0x19A, 0x198, 0x156, 0x154, 0x11E, 0x11C, + 0x0D2, 0x0D0, 0x06E, 0x06C, 0x000, 0x06D, 0x06F, 0x0D1, 0x0D3, 0x11D, 0x11F, 0x155, + 0x157, 0x199, 0x19B, 0x1D5, 0x1D7, 0x00D, 0x00F, 0x035, 0x04D, 0x04F, 0x06B, 0x08D, + 0x0A9, 0x0B9, 0x0BB, 0x0CF, 0x0E9, 0x0F1, 0x0F3, 0x011, 0x021, 0x025, 0x033, 0x03F, + 0x03D, 0x005, 0x013, 0x019, 0x023, 0x031, 0x037, 0x045, 0x04D, 0x04F, 0x057, 0x05F, + 0x065, 0x06D, 0x06F, 0x077, 0x07B, 0x001, 0x005, 0x00B, 0x00F, 0x015, 0x017, 0x01D, + 0x021, 0x025, 0x029, 0x02D, 0x031, 0x035, 0x039, 0x03F +}; + +static const uint8_t SpectrumA74Bits[128] = +{ + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5 +}; + +static const uint16_t SpectrumA74Codes[128] = +{ + 0x00D, 0x00A, 0x004, 0x000, 0x03A, 0x036, 0x032, 0x030, 0x02C, 0x028, 0x026, 0x022, + 0x01E, 0x018, 0x012, 0x00E, 0x006, 0x07E, 0x07A, 0x070, 0x06A, 0x05E, 0x056, 0x054, + 0x048, 0x040, 0x038, 0x022, 0x01A, 0x00A, 0x0F8, 0x0E6, 0x008, 0x0FA, 0x0F0, 0x0D2, + 0x0BA, 0x0B8, 0x094, 0x084, 0x074, 0x042, 0x032, 0x1E6, 0x1CA, 0x1C8, 0x1A2, 0x12E, + 0x10E, 0x10C, 0x0EC, 0x082, 0x062, 0x060, 0x3CA, 0x3C8, 0x342, 0x340, 0x25A, 0x258, + 0x1DE, 0x1DC, 0x102, 0x100, 0x000, 0x101, 0x103, 0x1DD, 0x1DF, 0x259, 0x25B, 0x341, + 0x343, 0x3C9, 0x3CB, 0x061, 0x063, 0x083, 0x0ED, 0x10D, 0x10F, 0x12F, 0x1A3, 0x1C9, + 0x1CB, 0x1E7, 0x033, 0x043, 0x075, 0x085, 0x095, 0x0B9, 0x0BB, 0x0D3, 0x0F1, 0x0FB, + 0x009, 0x0E7, 0x0F9, 0x00B, 0x01B, 0x023, 0x039, 0x041, 0x049, 0x055, 0x057, 0x05F, + 0x06B, 0x071, 0x07B, 0x07F, 0x007, 0x00F, 0x013, 0x019, 0x01F, 0x023, 0x027, 0x029, + 0x02D, 0x031, 0x033, 0x037, 0x03B, 0x001, 0x005, 0x00B +}; + +static const uint8_t SpectrumB22Bits[256] = +{ + 0, 4, 0, 4, 4, 5, 0, 5, 0, 0, 0, 0, 4, 5, 0, 5, + 4, 7, 0, 6, 6, 9, 0, 7, 0, 0, 0, 0, 6, 9, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 6, 0, 7, 6, 7, 0, 9, 0, 0, 0, 0, 6, 7, 0, 9, + 4, 8, 0, 8, 8, 10, 0, 10, 0, 0, 0, 0, 6, 9, 0, 9, + 5, 10, 0, 9, 9, 10, 0, 10, 0, 0, 0, 0, 7, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 9, 0, 10, 9, 10, 0, 10, 0, 0, 0, 0, 7, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 8, 0, 8, 6, 9, 0, 9, 0, 0, 0, 0, 8, 10, 0, 10, + 6, 10, 0, 9, 7, 10, 0, 10, 0, 0, 0, 0, 9, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 9, 0, 10, 7, 10, 0, 10, 0, 0, 0, 0, 9, 10, 0, 10 +}; + +static const uint16_t SpectrumB22Codes[256] = +{ + 0x000, 0x00E, 0x000, 0x00F, 0x008, 0x006, 0x000, 0x00B, 0x000, 0x000, 0x000, 0x000, + 0x009, 0x00A, 0x000, 0x007, 0x006, 0x00A, 0x000, 0x029, 0x006, 0x158, 0x000, 0x023, + 0x000, 0x000, 0x000, 0x000, 0x013, 0x174, 0x000, 0x021, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x007, 0x028, 0x000, 0x00B, 0x012, 0x020, 0x000, 0x175, 0x000, 0x000, 0x000, 0x000, + 0x007, 0x022, 0x000, 0x159, 0x00C, 0x0BC, 0x000, 0x0BF, 0x022, 0x2B8, 0x000, 0x2BB, + 0x000, 0x000, 0x000, 0x000, 0x00B, 0x170, 0x000, 0x15B, 0x000, 0x04E, 0x000, 0x15F, + 0x042, 0x04A, 0x000, 0x041, 0x000, 0x000, 0x000, 0x000, 0x055, 0x044, 0x000, 0x04D, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x02D, 0x172, 0x000, 0x2ED, 0x040, 0x042, 0x000, 0x047, + 0x000, 0x000, 0x000, 0x000, 0x013, 0x2EE, 0x000, 0x049, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x00D, 0x0BE, 0x000, 0x0BD, 0x00A, 0x15A, 0x000, 0x171, 0x000, 0x000, 0x000, 0x000, + 0x023, 0x2BA, 0x000, 0x2B9, 0x02C, 0x2EC, 0x000, 0x173, 0x012, 0x048, 0x000, 0x2EF, + 0x000, 0x000, 0x000, 0x000, 0x041, 0x046, 0x000, 0x043, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x15E, 0x000, 0x04F, 0x054, 0x04C, 0x000, 0x045, 0x000, 0x000, 0x000, 0x000, + 0x043, 0x040, 0x000, 0x04B +}; + +static const uint8_t SpectrumB23Bits[256] = +{ + 2, 4, 0, 4, 4, 6, 0, 6, 0, 0, 0, 0, 4, 6, 0, 6, + 4, 9, 0, 7, 7, 9, 0, 8, 0, 0, 0, 0, 7, 9, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 7, 0, 9, 7, 8, 0, 9, 0, 0, 0, 0, 7, 8, 0, 9, + 4, 8, 0, 8, 9, 10, 0, 10, 0, 0, 0, 0, 7, 10, 0, 10, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 9, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 8, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 8, 0, 8, 7, 10, 0, 10, 0, 0, 0, 0, 9, 10, 0, 10, + 7, 10, 0, 10, 8, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 10, 0, 10, 9, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10 +}; + +static const uint16_t SpectrumB23Codes[256] = +{ + 0x003, 0x008, 0x000, 0x009, 0x002, 0x018, 0x000, 0x01B, 0x000, 0x000, 0x000, 0x000, + 0x003, 0x01A, 0x000, 0x019, 0x000, 0x17C, 0x000, 0x055, 0x056, 0x0E8, 0x000, 0x07D, + 0x000, 0x000, 0x000, 0x000, 0x059, 0x0F6, 0x000, 0x07F, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x054, 0x000, 0x17D, 0x058, 0x07E, 0x000, 0x0F7, 0x000, 0x000, 0x000, 0x000, + 0x057, 0x07C, 0x000, 0x0E9, 0x004, 0x0A2, 0x000, 0x0A1, 0x17A, 0x1DA, 0x000, 0x1D9, + 0x000, 0x000, 0x000, 0x000, 0x053, 0x1E8, 0x000, 0x2F3, 0x05C, 0x1D6, 0x000, 0x1E7, + 0x1EA, 0x1E2, 0x000, 0x1CF, 0x000, 0x000, 0x000, 0x000, 0x17F, 0x1CA, 0x000, 0x1DD, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x05B, 0x2F0, 0x000, 0x1DF, 0x1E4, 0x1CC, 0x000, 0x1D5, + 0x000, 0x000, 0x000, 0x000, 0x071, 0x1E0, 0x000, 0x1C9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x005, 0x0A0, 0x000, 0x0A3, 0x052, 0x2F2, 0x000, 0x1E9, 0x000, 0x000, 0x000, 0x000, + 0x17B, 0x1D8, 0x000, 0x1DB, 0x05A, 0x1DE, 0x000, 0x2F1, 0x070, 0x1C8, 0x000, 0x1E1, + 0x000, 0x000, 0x000, 0x000, 0x1E5, 0x1D4, 0x000, 0x1CD, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x05D, 0x1E6, 0x000, 0x1D7, 0x17E, 0x1DC, 0x000, 0x1CB, 0x000, 0x000, 0x000, 0x000, + 0x1EB, 0x1CE, 0x000, 0x1E3 +}; + +static const uint8_t SpectrumB24Bits[256] = +{ + 1, 4, 0, 4, 5, 7, 0, 7, 0, 0, 0, 0, 5, 7, 0, 7, + 5, 9, 0, 7, 8, 10, 0, 9, 0, 0, 0, 0, 7, 10, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 7, 0, 9, 7, 9, 0, 10, 0, 0, 0, 0, 8, 9, 0, 10, + 5, 9, 0, 8, 9, 10, 0, 10, 0, 0, 0, 0, 7, 10, 0, 10, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 8, 0, 9, 7, 10, 0, 10, 0, 0, 0, 0, 9, 10, 0, 10, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10 +}; + +static const uint16_t SpectrumB24Codes[256] = +{ + 0x001, 0x000, 0x000, 0x001, 0x00A, 0x01C, 0x000, 0x033, 0x000, 0x000, 0x000, 0x000, + 0x00B, 0x032, 0x000, 0x01D, 0x008, 0x0D8, 0x000, 0x031, 0x06E, 0x0FA, 0x000, 0x0D7, + 0x000, 0x000, 0x000, 0x000, 0x011, 0x0F4, 0x000, 0x0D5, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x009, 0x030, 0x000, 0x0D9, 0x010, 0x0D4, 0x000, 0x0F5, 0x000, 0x000, 0x000, 0x000, + 0x06F, 0x0D6, 0x000, 0x0FB, 0x00E, 0x0DA, 0x000, 0x025, 0x0D2, 0x0D4, 0x000, 0x0DB, + 0x000, 0x000, 0x000, 0x000, 0x017, 0x0FE, 0x000, 0x0FD, 0x014, 0x0DC, 0x000, 0x0F9, + 0x0F2, 0x0D6, 0x000, 0x09B, 0x000, 0x000, 0x000, 0x000, 0x1A3, 0x09C, 0x000, 0x0D3, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x019, 0x0F6, 0x000, 0x0D9, 0x0F0, 0x09E, 0x000, 0x0D1, + 0x000, 0x000, 0x000, 0x000, 0x1A1, 0x0DE, 0x000, 0x099, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x00F, 0x024, 0x000, 0x0DB, 0x016, 0x0FC, 0x000, 0x0FF, 0x000, 0x000, 0x000, 0x000, + 0x0D3, 0x0DA, 0x000, 0x0D5, 0x018, 0x0D8, 0x000, 0x0F7, 0x1A0, 0x098, 0x000, 0x0DF, + 0x000, 0x000, 0x000, 0x000, 0x0F1, 0x0D0, 0x000, 0x09F, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x015, 0x0F8, 0x000, 0x0DD, 0x1A2, 0x0D2, 0x000, 0x09D, 0x000, 0x000, 0x000, 0x000, + 0x0F3, 0x09A, 0x000, 0x0D7 +}; + +static const uint8_t SpectrumB32Bits[64] = +{ + 2, 4, 5, 6, 0, 6, 5, 4, 5, 6, 6, 7, 0, 6, 5, 6, + 5, 6, 7, 7, 0, 8, 7, 6, 6, 7, 8, 9, 0, 9, 8, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 0, 9, 8, 7, + 5, 6, 7, 8, 0, 7, 7, 6, 5, 6, 5, 6, 0, 7, 6, 6 +}; + +static const uint16_t SpectrumB32Codes[64] = +{ + 0x001, 0x002, 0x01E, 0x02A, 0x000, 0x02B, 0x01F, 0x003, 0x016, 0x020, 0x03A, 0x064, + 0x000, 0x005, 0x001, 0x023, 0x01A, 0x026, 0x070, 0x00C, 0x000, 0x0CF, 0x073, 0x031, + 0x024, 0x00E, 0x0CC, 0x146, 0x000, 0x145, 0x0A1, 0x053, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x025, 0x052, 0x0A0, 0x144, 0x000, 0x147, 0x0CD, 0x00F, + 0x01B, 0x030, 0x072, 0x0CE, 0x000, 0x00D, 0x071, 0x027, 0x017, 0x022, 0x000, 0x004, + 0x000, 0x065, 0x03B, 0x021 +}; + +static const uint8_t SpectrumB33Bits[64] = +{ + 2, 4, 5, 7, 0, 7, 5, 4, 4, 5, 6, 8, 0, 7, 6, 5, + 5, 6, 7, 9, 0, 8, 7, 6, 7, 8, 9, 10, 0, 10, 9, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 10, 0, 10, 9, 8, + 5, 6, 7, 8, 0, 9, 7, 6, 4, 5, 6, 7, 0, 8, 6, 5 +}; + +static const uint16_t SpectrumB33Codes[64] = +{ + 0x003, 0x008, 0x014, 0x05E, 0x000, 0x05F, 0x015, 0x009, 0x004, 0x002, 0x01C, 0x0BA, + 0x000, 0x011, 0x01F, 0x001, 0x00C, 0x00C, 0x014, 0x166, 0x000, 0x02D, 0x013, 0x00F, + 0x05A, 0x0B0, 0x05E, 0x0B8, 0x000, 0x0BB, 0x165, 0x0B9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x05B, 0x0B8, 0x164, 0x0BA, 0x000, 0x0B9, 0x05F, 0x0B1, + 0x00D, 0x00E, 0x012, 0x02C, 0x000, 0x167, 0x015, 0x00D, 0x005, 0x000, 0x01E, 0x010, + 0x000, 0x0BB, 0x01D, 0x003 +}; + +static const uint8_t SpectrumB34Bits[64] = +{ + 1, 4, 6, 8, 0, 8, 6, 4, 4, 6, 7, 9, 0, 8, 7, 6, + 6, 7, 8, 10, 0, 10, 8, 7, 8, 9, 10, 10, 0, 10, 10, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 10, 0, 10, 10, 9, + 6, 7, 8, 10, 0, 10, 8, 7, 4, 6, 7, 8, 0, 9, 7, 6 +}; + +static const uint16_t SpectrumB34Codes[64] = +{ + 0x000, 0x00A, 0x038, 0x0EE, 0x000, 0x0EF, 0x039, 0x00B, 0x008, 0x03C, 0x06E, 0x1D8, + 0x000, 0x0C1, 0x075, 0x03F, 0x032, 0x068, 0x0C4, 0x358, 0x000, 0x30F, 0x0C7, 0x06D, + 0x0D4, 0x1AE, 0x30C, 0x308, 0x000, 0x30B, 0x35B, 0x1DB, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x0D5, 0x1DA, 0x35A, 0x30A, 0x000, 0x309, 0x30D, 0x1AF, + 0x033, 0x06C, 0x0C6, 0x30E, 0x000, 0x359, 0x0C5, 0x069, 0x009, 0x03E, 0x074, 0x0C0, + 0x000, 0x1D9, 0x06F, 0x03D +}; + +static const uint8_t SpectrumB42Bits[256] = +{ + 4, 5, 6, 8, 6, 7, 8, 8, 0, 8, 8, 7, 6, 8, 6, 5, + 5, 6, 7, 8, 7, 7, 8, 9, 0, 8, 8, 7, 7, 8, 7, 6, + 7, 7, 8, 9, 7, 8, 9, 9, 0, 9, 9, 8, 7, 9, 8, 7, + 8, 9, 9, 10, 8, 8, 9, 10, 0, 10, 9, 8, 8, 10, 9, 8, + 6, 7, 8, 8, 9, 9, 10, 10, 0, 10, 10, 9, 9, 8, 8, 7, + 7, 7, 8, 9, 9, 10, 10, 10, 0, 10, 10, 10, 9, 9, 8, 7, + 8, 8, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 8, + 8, 9, 9, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 9, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 9, 9, + 8, 8, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 8, + 7, 7, 8, 9, 9, 10, 10, 10, 0, 10, 10, 10, 9, 9, 8, 7, + 6, 7, 8, 8, 9, 9, 10, 10, 0, 10, 10, 9, 9, 8, 8, 7, + 8, 8, 9, 10, 8, 8, 9, 10, 0, 10, 9, 8, 8, 10, 9, 9, + 7, 7, 8, 9, 7, 8, 9, 9, 0, 9, 9, 8, 7, 9, 8, 7, + 5, 6, 7, 8, 7, 7, 8, 8, 0, 9, 8, 7, 7, 8, 7, 6 +}; + +static const uint16_t SpectrumB42Codes[256] = +{ + 0x00E, 0x018, 0x010, 0x0F0, 0x024, 0x05A, 0x0F6, 0x078, 0x000, 0x079, 0x0F7, 0x05B, + 0x025, 0x0F1, 0x011, 0x019, 0x00C, 0x014, 0x01C, 0x036, 0x05C, 0x012, 0x09E, 0x1E4, + 0x000, 0x00B, 0x0A9, 0x03B, 0x05F, 0x071, 0x019, 0x017, 0x06E, 0x000, 0x03E, 0x114, + 0x002, 0x0B0, 0x1AA, 0x07A, 0x000, 0x099, 0x1E7, 0x0B3, 0x00B, 0x131, 0x07F, 0x00D, + 0x0D8, 0x1FE, 0x112, 0x22E, 0x086, 0x010, 0x134, 0x35C, 0x000, 0x35F, 0x133, 0x013, + 0x081, 0x22D, 0x119, 0x07B, 0x00A, 0x050, 0x0F8, 0x04E, 0x1B4, 0x154, 0x3EC, 0x0D2, + 0x000, 0x0D7, 0x3D7, 0x137, 0x1FD, 0x073, 0x0FD, 0x057, 0x052, 0x010, 0x08E, 0x1E8, + 0x11A, 0x3EE, 0x0F2, 0x03C, 0x000, 0x03F, 0x0F1, 0x3D5, 0x111, 0x1F5, 0x09D, 0x025, + 0x0D2, 0x082, 0x1A0, 0x0F8, 0x36E, 0x0D4, 0x072, 0x03A, 0x000, 0x027, 0x071, 0x07D, + 0x36D, 0x0FB, 0x1AD, 0x085, 0x00C, 0x1A8, 0x03C, 0x346, 0x0D0, 0x076, 0x024, 0x020, + 0x000, 0x023, 0x039, 0x075, 0x07F, 0x345, 0x09B, 0x157, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x00D, 0x156, 0x09A, 0x344, 0x07E, 0x074, 0x038, 0x022, 0x000, 0x021, 0x025, 0x077, + 0x0D1, 0x347, 0x03D, 0x1A9, 0x0D3, 0x084, 0x1AC, 0x0FA, 0x36C, 0x07C, 0x070, 0x026, + 0x000, 0x03B, 0x073, 0x0D5, 0x36F, 0x0F9, 0x1A1, 0x083, 0x053, 0x024, 0x09C, 0x1F4, + 0x110, 0x3D4, 0x0F0, 0x03E, 0x000, 0x03D, 0x0F3, 0x3EF, 0x11B, 0x1E9, 0x08F, 0x011, + 0x00B, 0x056, 0x0FC, 0x072, 0x1FC, 0x136, 0x3D6, 0x0D6, 0x000, 0x0D3, 0x3ED, 0x155, + 0x1B5, 0x04F, 0x0F9, 0x051, 0x0D9, 0x07A, 0x118, 0x22C, 0x080, 0x012, 0x132, 0x35E, + 0x000, 0x35D, 0x135, 0x011, 0x087, 0x22F, 0x113, 0x1FF, 0x06F, 0x00C, 0x07E, 0x130, + 0x00A, 0x0B2, 0x1E6, 0x098, 0x000, 0x07B, 0x1AB, 0x0B1, 0x003, 0x115, 0x03F, 0x001, + 0x00D, 0x016, 0x018, 0x070, 0x05E, 0x03A, 0x0A8, 0x00A, 0x000, 0x1E5, 0x09F, 0x013, + 0x05D, 0x037, 0x01D, 0x015 +}; + +static const uint8_t SpectrumB43Bits[256] = +{ + 2, 5, 6, 7, 7, 8, 8, 9, 0, 9, 8, 8, 7, 7, 6, 5, + 5, 6, 7, 8, 7, 8, 9, 10, 0, 10, 9, 8, 7, 8, 7, 6, + 6, 7, 8, 9, 8, 9, 10, 10, 0, 10, 10, 9, 8, 9, 8, 7, + 7, 8, 9, 10, 9, 9, 10, 10, 0, 10, 10, 10, 9, 10, 9, 8, + 7, 8, 8, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 8, 7, + 8, 8, 9, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 9, 8, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 8, 8, 9, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 9, 8, + 7, 7, 8, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 8, 8, + 7, 8, 9, 10, 9, 10, 10, 10, 0, 10, 10, 9, 9, 10, 9, 8, + 6, 7, 8, 9, 8, 9, 10, 10, 0, 10, 10, 9, 8, 9, 8, 7, + 5, 6, 7, 8, 7, 8, 9, 10, 0, 10, 9, 8, 7, 8, 7, 6 +}; + +static const uint16_t SpectrumB43Codes[256] = +{ + 0x001, 0x01E, 0x022, 0x018, 0x064, 0x0EC, 0x008, 0x100, 0x000, 0x101, 0x009, 0x0ED, + 0x065, 0x019, 0x023, 0x01F, 0x01A, 0x030, 0x056, 0x09A, 0x00A, 0x090, 0x12C, 0x0A6, + 0x000, 0x0A9, 0x12F, 0x093, 0x00F, 0x09F, 0x059, 0x039, 0x00E, 0x054, 0x0BC, 0x19E, + 0x082, 0x176, 0x0AC, 0x088, 0x000, 0x08B, 0x0AF, 0x19D, 0x095, 0x1D1, 0x0BF, 0x051, + 0x002, 0x098, 0x1D4, 0x0B8, 0x170, 0x046, 0x090, 0x060, 0x000, 0x067, 0x095, 0x0BD, + 0x173, 0x0B5, 0x1D3, 0x09D, 0x052, 0x0EE, 0x034, 0x174, 0x0BA, 0x09C, 0x080, 0x044, + 0x000, 0x047, 0x06D, 0x099, 0x0BF, 0x16F, 0x085, 0x001, 0x0CC, 0x036, 0x16C, 0x0B0, + 0x09A, 0x084, 0x04E, 0x03E, 0x000, 0x037, 0x04B, 0x06B, 0x0A1, 0x0B3, 0x16B, 0x087, + 0x1D6, 0x102, 0x0A4, 0x092, 0x068, 0x04C, 0x034, 0x030, 0x000, 0x02D, 0x03D, 0x049, + 0x083, 0x097, 0x0AB, 0x169, 0x0B6, 0x09E, 0x06E, 0x064, 0x040, 0x038, 0x02E, 0x02A, + 0x000, 0x029, 0x033, 0x03B, 0x043, 0x063, 0x087, 0x0A3, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x0B7, 0x0A2, 0x086, 0x062, 0x042, 0x03A, 0x032, 0x028, 0x000, 0x02B, 0x02F, 0x039, + 0x041, 0x065, 0x06F, 0x09F, 0x1D7, 0x168, 0x0AA, 0x096, 0x082, 0x048, 0x03C, 0x02C, + 0x000, 0x031, 0x035, 0x04D, 0x069, 0x093, 0x0A5, 0x103, 0x0CD, 0x086, 0x16A, 0x0B2, + 0x0A0, 0x06A, 0x04A, 0x036, 0x000, 0x03F, 0x04F, 0x085, 0x09B, 0x0B1, 0x16D, 0x037, + 0x053, 0x000, 0x084, 0x16E, 0x0BE, 0x098, 0x06C, 0x046, 0x000, 0x045, 0x081, 0x09D, + 0x0BB, 0x175, 0x035, 0x0EF, 0x003, 0x09C, 0x1D2, 0x0B4, 0x172, 0x0BC, 0x094, 0x066, + 0x000, 0x061, 0x091, 0x047, 0x171, 0x0B9, 0x1D5, 0x099, 0x00F, 0x050, 0x0BE, 0x1D0, + 0x094, 0x19C, 0x0AE, 0x08A, 0x000, 0x089, 0x0AD, 0x177, 0x083, 0x19F, 0x0BD, 0x055, + 0x01B, 0x038, 0x058, 0x09E, 0x00E, 0x092, 0x12E, 0x0A8, 0x000, 0x0A7, 0x12D, 0x091, + 0x00B, 0x09B, 0x057, 0x031 +}; + +static const uint8_t SpectrumB44Bits[256] = +{ + 2, 4, 6, 7, 7, 8, 10, 10, 0, 10, 10, 8, 7, 7, 6, 4, + 5, 5, 7, 8, 8, 10, 10, 10, 0, 10, 10, 10, 8, 8, 7, 5, + 6, 7, 8, 9, 9, 10, 10, 10, 0, 10, 10, 10, 10, 9, 8, 7, + 8, 8, 9, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 8, + 8, 8, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 8, + 9, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 9, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 8, + 8, 8, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 9, 8, + 6, 7, 8, 9, 10, 10, 10, 10, 0, 10, 10, 10, 9, 9, 8, 7, + 5, 5, 7, 8, 8, 10, 10, 10, 0, 10, 10, 10, 8, 8, 7, 5 +}; + +static const uint16_t SpectrumB44Codes[256] = +{ + 0x002, 0x002, 0x030, 0x000, 0x002, 0x00C, 0x1D2, 0x1AE, 0x000, 0x1AF, 0x1D3, 0x00D, + 0x003, 0x001, 0x031, 0x003, 0x01E, 0x002, 0x070, 0x0C8, 0x07E, 0x1E8, 0x1C0, 0x176, + 0x000, 0x17F, 0x1C3, 0x1EB, 0x0CF, 0x0D3, 0x073, 0x009, 0x018, 0x06A, 0x0EC, 0x1DE, + 0x1A2, 0x1CA, 0x1AA, 0x164, 0x000, 0x16D, 0x1AD, 0x1D1, 0x1EF, 0x1DD, 0x0EB, 0x06D, + 0x0E8, 0x0CA, 0x1BE, 0x1CE, 0x1DA, 0x1B6, 0x170, 0x154, 0x000, 0x153, 0x173, 0x1B1, + 0x1D7, 0x1D5, 0x343, 0x0CD, 0x0DC, 0x078, 0x340, 0x1CC, 0x1BA, 0x1A8, 0x156, 0x148, + 0x000, 0x145, 0x15F, 0x1A1, 0x1BD, 0x1D9, 0x1ED, 0x07D, 0x1BC, 0x1DC, 0x1C4, 0x1B2, + 0x17C, 0x15A, 0x14A, 0x03A, 0x000, 0x039, 0x147, 0x16B, 0x17B, 0x1B5, 0x1C9, 0x1DF, + 0x1C6, 0x1B8, 0x1A2, 0x168, 0x160, 0x14C, 0x02E, 0x024, 0x000, 0x027, 0x03D, 0x151, + 0x15D, 0x16F, 0x1A7, 0x1BF, 0x1A4, 0x174, 0x162, 0x14E, 0x140, 0x02C, 0x02A, 0x022, + 0x000, 0x021, 0x029, 0x03F, 0x143, 0x159, 0x167, 0x179, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x1A5, 0x178, 0x166, 0x158, 0x142, 0x03E, 0x028, 0x020, 0x000, 0x023, 0x02B, 0x02D, + 0x141, 0x14F, 0x163, 0x175, 0x1C7, 0x1BE, 0x1A6, 0x16E, 0x15C, 0x150, 0x03C, 0x026, + 0x000, 0x025, 0x02F, 0x14D, 0x161, 0x169, 0x1A3, 0x1B9, 0x1BD, 0x1DE, 0x1C8, 0x1B4, + 0x17A, 0x16A, 0x146, 0x038, 0x000, 0x03B, 0x14B, 0x15B, 0x17D, 0x1B3, 0x1C5, 0x1DD, + 0x0DD, 0x07C, 0x1EC, 0x1D8, 0x1BC, 0x1A0, 0x15E, 0x144, 0x000, 0x149, 0x157, 0x1A9, + 0x1BB, 0x1CD, 0x341, 0x079, 0x0E9, 0x0CC, 0x342, 0x1D4, 0x1D6, 0x1B0, 0x172, 0x152, + 0x000, 0x155, 0x171, 0x1B7, 0x1DB, 0x1CF, 0x1BF, 0x0CB, 0x019, 0x06C, 0x0EA, 0x1DC, + 0x1EE, 0x1D0, 0x1AC, 0x16C, 0x000, 0x165, 0x1AB, 0x1CB, 0x1A3, 0x1DF, 0x0ED, 0x06B, + 0x01F, 0x008, 0x072, 0x0D2, 0x0CE, 0x1EA, 0x1C2, 0x17E, 0x000, 0x177, 0x1C1, 0x1E9, + 0x07F, 0x0C9, 0x071, 0x003 +}; + +static const uint8_t SpectrumB52Bits[32] = +{ + 3, 4, 4, 4, 5, 5, 6, 6, 5, 5, 5, 6, 6, 6, 7, 7, + 0, 7, 7, 6, 6, 6, 5, 5, 5, 6, 6, 5, 5, 4, 4, 4 +}; + +static const uint16_t SpectrumB52Codes[32] = +{ + 0x06, 0x0E, 0x06, 0x00, 0x0A, 0x04, 0x2C, 0x12, 0x14, 0x10, 0x06, 0x2E, 0x24, 0x10, 0x4E, 0x4C, + 0x00, 0x4D, 0x4F, 0x11, 0x25, 0x2F, 0x07, 0x11, 0x15, 0x13, 0x2D, 0x05, 0x0B, 0x01, 0x07, 0x0F +}; + +static const uint8_t SpectrumB53Bits[32] = +{ + 2, 3, 4, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 8, 8, + 0, 8, 8, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 4, 3 +}; + +static const uint16_t SpectrumB53Codes[32] = +{ + 0x02, 0x00, 0x06, 0x1C, 0x18, 0x3E, 0x16, 0x10, 0x3C, 0x36, 0x14, 0x6A, 0x26, 0x24, 0xD2, 0xD0, + 0x00, 0xD1, 0xD3, 0x25, 0x27, 0x6B, 0x15, 0x37, 0x3D, 0x11, 0x17, 0x3F, 0x19, 0x1D, 0x07, 0x01 +}; + +static const uint8_t SpectrumB54Bits[32] = +{ + 2, 3, 4, 4, 5, 6, 6, 7, 6, 6, 7, 8, 8, 8, 9, 9, + 0, 9, 9, 8, 8, 8, 7, 6, 6, 7, 6, 6, 5, 4, 4, 3 +}; + +static const uint16_t SpectrumB54Codes[32] = +{ + 0x003, 0x002, 0x008, 0x000, 0x014, 0x02E, 0x00E, 0x05A, 0x00A, 0x008, 0x01A, 0x0B2, + 0x032, 0x030, 0x162, 0x160, 0x000, 0x161, 0x163, 0x031, 0x033, 0x0B3, 0x01B, 0x009, + 0x00B, 0x05B, 0x00F, 0x02F, 0x015, 0x001, 0x009, 0x003 +}; + +static const uint8_t SpectrumB62Bits[64] = +{ + 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 0, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4 +}; + +static const uint16_t SpectrumB62Codes[64] = +{ + 0x0D, 0x06, 0x1C, 0x14, 0x0A, 0x04, 0x3E, 0x2E, 0x22, 0x0E, 0x06, 0x00, 0x5A, 0x4E, 0x40, 0x20, + 0x30, 0x32, 0x24, 0x12, 0x0C, 0x02, 0x78, 0x58, 0x42, 0x22, 0x0A, 0x08, 0xF6, 0xF4, 0x9A, 0x98, + 0x00, 0x99, 0x9B, 0xF5, 0xF7, 0x09, 0x0B, 0x23, 0x43, 0x59, 0x79, 0x03, 0x0D, 0x13, 0x25, 0x33, + 0x31, 0x21, 0x41, 0x4F, 0x5B, 0x01, 0x07, 0x0F, 0x23, 0x2F, 0x3F, 0x05, 0x0B, 0x15, 0x1D, 0x07 +}; + +static const uint8_t SpectrumB63Bits[64] = +{ + 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, + 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, + 6, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4 +}; + +static const uint16_t SpectrumB63Codes[64] = +{ + 0x006, 0x00E, 0x004, 0x014, 0x010, 0x006, 0x000, 0x026, 0x01C, 0x018, 0x004, 0x05C, + 0x04A, 0x03C, 0x016, 0x0BC, 0x006, 0x008, 0x058, 0x03E, 0x036, 0x014, 0x0B6, 0x0B4, + 0x090, 0x068, 0x17E, 0x17C, 0x126, 0x124, 0x0D6, 0x0D4, 0x000, 0x0D5, 0x0D7, 0x125, + 0x127, 0x17D, 0x17F, 0x069, 0x091, 0x0B5, 0x0B7, 0x015, 0x037, 0x03F, 0x059, 0x009, + 0x007, 0x0BD, 0x017, 0x03D, 0x04B, 0x05D, 0x005, 0x019, 0x01D, 0x027, 0x001, 0x007, + 0x011, 0x015, 0x005, 0x00F +}; + +static const uint8_t SpectrumB64Bits[64] = +{ + 3, 3, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, + 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, 8, 7, 7, + 7, 8, 7, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4, 3 +}; + +static const uint16_t SpectrumB64Codes[64] = +{ + 0x007, 0x000, 0x008, 0x01A, 0x014, 0x00C, 0x032, 0x02E, 0x01E, 0x014, 0x062, 0x05A, + 0x03A, 0x026, 0x020, 0x0B2, 0x038, 0x02C, 0x022, 0x0C0, 0x05E, 0x04A, 0x186, 0x184, + 0x160, 0x0BA, 0x092, 0x090, 0x2C6, 0x2C4, 0x172, 0x170, 0x000, 0x171, 0x173, 0x2C5, + 0x2C7, 0x091, 0x093, 0x0BB, 0x161, 0x185, 0x187, 0x04B, 0x05F, 0x0C1, 0x023, 0x02D, + 0x039, 0x0B3, 0x021, 0x027, 0x03B, 0x05B, 0x063, 0x015, 0x01F, 0x02F, 0x033, 0x00D, + 0x015, 0x01B, 0x009, 0x001 +}; + +static const uint8_t SpectrumB72Bits[128] = +{ + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5 +}; + +static const uint16_t SpectrumB72Codes[128] = +{ + 0x01E, 0x016, 0x00C, 0x000, 0x038, 0x032, 0x028, 0x022, 0x01C, 0x012, 0x00E, 0x006, + 0x076, 0x06C, 0x060, 0x04E, 0x03E, 0x02A, 0x022, 0x01A, 0x012, 0x00A, 0x0FC, 0x0DC, + 0x0C6, 0x0A8, 0x094, 0x086, 0x058, 0x042, 0x040, 0x02A, 0x068, 0x07C, 0x06A, 0x056, + 0x048, 0x040, 0x02E, 0x028, 0x016, 0x010, 0x008, 0x0EA, 0x0DE, 0x0AA, 0x09A, 0x096, + 0x07A, 0x078, 0x05A, 0x032, 0x030, 0x028, 0x1FE, 0x1FC, 0x1D2, 0x1D0, 0x18A, 0x188, + 0x132, 0x130, 0x10A, 0x108, 0x000, 0x109, 0x10B, 0x131, 0x133, 0x189, 0x18B, 0x1D1, + 0x1D3, 0x1FD, 0x1FF, 0x029, 0x031, 0x033, 0x05B, 0x079, 0x07B, 0x097, 0x09B, 0x0AB, + 0x0DF, 0x0EB, 0x009, 0x011, 0x017, 0x029, 0x02F, 0x041, 0x049, 0x057, 0x06B, 0x07D, + 0x069, 0x02B, 0x041, 0x043, 0x059, 0x087, 0x095, 0x0A9, 0x0C7, 0x0DD, 0x0FD, 0x00B, + 0x013, 0x01B, 0x023, 0x02B, 0x03F, 0x04F, 0x061, 0x06D, 0x077, 0x007, 0x00F, 0x013, + 0x01D, 0x023, 0x029, 0x033, 0x039, 0x001, 0x00D, 0x017 +}; + +static const uint8_t SpectrumB73Bits[128] = +{ + 3, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, + 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 7, + 8, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 4 +}; + +static const uint16_t SpectrumB73Codes[128] = +{ + 0x000, 0x006, 0x018, 0x010, 0x004, 0x03A, 0x034, 0x02A, 0x026, 0x014, 0x010, 0x07E, + 0x072, 0x06E, 0x05C, 0x052, 0x04A, 0x02C, 0x024, 0x018, 0x0F4, 0x0E0, 0x0DA, 0x0B6, + 0x0B2, 0x0A0, 0x05E, 0x04E, 0x038, 0x034, 0x1E6, 0x1B2, 0x0FA, 0x01E, 0x0F8, 0x0F0, + 0x0BE, 0x0B4, 0x0A2, 0x090, 0x04C, 0x03A, 0x1EE, 0x1E4, 0x1C6, 0x1B0, 0x178, 0x162, + 0x126, 0x124, 0x0B8, 0x06C, 0x3DA, 0x3D8, 0x38A, 0x388, 0x2F6, 0x2F4, 0x2C2, 0x2C0, + 0x176, 0x174, 0x0DC, 0x0DE, 0x000, 0x0DF, 0x0DD, 0x175, 0x177, 0x2C1, 0x2C3, 0x2F5, + 0x2F7, 0x389, 0x38B, 0x3D9, 0x3DB, 0x06D, 0x0B9, 0x125, 0x127, 0x163, 0x179, 0x1B1, + 0x1C7, 0x1E5, 0x1EF, 0x03B, 0x04D, 0x091, 0x0A3, 0x0B5, 0x0BF, 0x0F1, 0x0F9, 0x01F, + 0x0FB, 0x1B3, 0x1E7, 0x035, 0x039, 0x04F, 0x05F, 0x0A1, 0x0B3, 0x0B7, 0x0DB, 0x0E1, + 0x0F5, 0x019, 0x025, 0x02D, 0x04B, 0x053, 0x05D, 0x06F, 0x073, 0x07F, 0x011, 0x015, + 0x027, 0x02B, 0x035, 0x03B, 0x005, 0x011, 0x019, 0x007 +}; + +static const uint8_t SpectrumB74Bits[128] = +{ + 3, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, + 8, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4 +}; + +static const uint16_t SpectrumB74Codes[128] = +{ + 0x001, 0x008, 0x01E, 0x018, 0x00C, 0x002, 0x03A, 0x034, 0x02C, 0x01E, 0x016, 0x012, + 0x072, 0x06E, 0x05E, 0x056, 0x050, 0x038, 0x022, 0x004, 0x0E2, 0x0DA, 0x0BA, 0x0A8, + 0x076, 0x054, 0x050, 0x002, 0x000, 0x1C0, 0x1B0, 0x156, 0x0A4, 0x0A6, 0x074, 0x052, + 0x004, 0x1C2, 0x1B2, 0x170, 0x154, 0x0AE, 0x0AC, 0x086, 0x2E6, 0x2E4, 0x10A, 0x108, + 0x106, 0x104, 0x102, 0x100, 0x03E, 0x03A, 0x03C, 0x038, 0x036, 0x034, 0x032, 0x030, + 0x01E, 0x01A, 0x01C, 0x018, 0x000, 0x019, 0x01D, 0x01B, 0x01F, 0x031, 0x033, 0x035, + 0x037, 0x039, 0x03D, 0x03B, 0x03F, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x2E5, + 0x2E7, 0x087, 0x0AD, 0x0AF, 0x155, 0x171, 0x1B3, 0x1C3, 0x005, 0x053, 0x075, 0x0A7, + 0x0A5, 0x157, 0x1B1, 0x1C1, 0x001, 0x003, 0x051, 0x055, 0x077, 0x0A9, 0x0BB, 0x0DB, + 0x0E3, 0x005, 0x023, 0x039, 0x051, 0x057, 0x05F, 0x06F, 0x073, 0x013, 0x017, 0x01F, + 0x02D, 0x035, 0x03B, 0x003, 0x00D, 0x019, 0x01F, 0x009 +}; + +static uint8_t ScaleFactorsA1Lookup[2]; +static uint8_t ScaleFactorsA2Lookup[8]; +static uint8_t ScaleFactorsA3Lookup[64]; +static uint8_t ScaleFactorsA4Lookup[256]; +static uint8_t ScaleFactorsA5Lookup[256]; +static uint8_t ScaleFactorsA6Lookup[256]; +static uint8_t ScaleFactorsB2Lookup[4]; +static uint8_t ScaleFactorsB3Lookup[64]; +static uint8_t ScaleFactorsB4Lookup[256]; +static uint8_t ScaleFactorsB5Lookup[256]; +static uint8_t SpectrumA21Lookup[8]; +static uint8_t SpectrumA22Lookup[256]; +static uint8_t SpectrumA23Lookup[512]; +static uint8_t SpectrumA24Lookup[1024]; +static uint8_t SpectrumA31Lookup[128]; +static uint8_t SpectrumA32Lookup[128]; +static uint8_t SpectrumA33Lookup[256]; +static uint8_t SpectrumA34Lookup[1024]; +static uint8_t SpectrumA41Lookup[512]; +static uint8_t SpectrumA42Lookup[1024]; +static uint8_t SpectrumA43Lookup[1024]; +static uint8_t SpectrumA44Lookup[1024]; +static uint8_t SpectrumA51Lookup[64]; +static uint8_t SpectrumA52Lookup[64]; +static uint8_t SpectrumA53Lookup[128]; +static uint8_t SpectrumA54Lookup[256]; +static uint8_t SpectrumA61Lookup[128]; +static uint8_t SpectrumA62Lookup[128]; +static uint8_t SpectrumA63Lookup[256]; +static uint8_t SpectrumA64Lookup[512]; +static uint8_t SpectrumA71Lookup[256]; +static uint8_t SpectrumA72Lookup[256]; +static uint8_t SpectrumA73Lookup[512]; +static uint8_t SpectrumA74Lookup[1024]; +static uint8_t SpectrumB22Lookup[1024]; +static uint8_t SpectrumB23Lookup[1024]; +static uint8_t SpectrumB24Lookup[1024]; +static uint8_t SpectrumB32Lookup[512]; +static uint8_t SpectrumB33Lookup[1024]; +static uint8_t SpectrumB34Lookup[1024]; +static uint8_t SpectrumB42Lookup[1024]; +static uint8_t SpectrumB43Lookup[1024]; +static uint8_t SpectrumB44Lookup[1024]; +static uint8_t SpectrumB52Lookup[128]; +static uint8_t SpectrumB53Lookup[256]; +static uint8_t SpectrumB54Lookup[512]; +static uint8_t SpectrumB62Lookup[256]; +static uint8_t SpectrumB63Lookup[512]; +static uint8_t SpectrumB64Lookup[1024]; +static uint8_t SpectrumB72Lookup[512]; +static uint8_t SpectrumB73Lookup[1024]; +static uint8_t SpectrumB74Lookup[1024]; diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/imdct.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/imdct.c new file mode 100644 index 000000000..29bf3dfd7 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/imdct.c @@ -0,0 +1,80 @@ +#include "imdct.h" +#include "tables.h" + +void RunImdct(mdct* mdct, double* input, double* output) +{ + const int size = 1 << mdct->bits; + const int half = size / 2; + double dctOut[MAX_FRAME_SAMPLES]; + const double* window = ImdctWindow[mdct->bits - 6]; + double* previous = mdct->_imdctPrevious; + + Dct4(mdct, input, dctOut); + + for (int i = 0; i < half; i++) + { + output[i] = window[i] * dctOut[i + half] + previous[i]; + output[i + half] = window[i + half] * -dctOut[size - 1 - i] - previous[i + half]; + previous[i] = window[size - 1 - i] * -dctOut[half - i - 1]; + previous[i + half] = window[half - i - 1] * dctOut[i]; + } +} + +void Dct4(mdct* mdct, double* input, double* output) +{ + int MdctBits = mdct->bits; + int MdctSize = 1 << MdctBits; + const int* shuffleTable = ShuffleTables[MdctBits]; + const double* sinTable = SinTables[MdctBits]; + const double* cosTable = CosTables[MdctBits]; + double dctTemp[MAX_FRAME_SAMPLES]; + + int size = MdctSize; + int lastIndex = size - 1; + int halfSize = size / 2; + + for (int i = 0; i < halfSize; i++) + { + int i2 = i * 2; + double a = input[i2]; + double b = input[lastIndex - i2]; + double sin = sinTable[i]; + double cos = cosTable[i]; + dctTemp[i2] = a * cos + b * sin; + dctTemp[i2 + 1] = a * sin - b * cos; + } + int stageCount = MdctBits - 1; + + for (int stage = 0; stage < stageCount; stage++) + { + int blockCount = 1 << stage; + int blockSizeBits = stageCount - stage; + int blockHalfSizeBits = blockSizeBits - 1; + int blockSize = 1 << blockSizeBits; + int blockHalfSize = 1 << blockHalfSizeBits; + sinTable = SinTables[blockHalfSizeBits]; + cosTable = CosTables[blockHalfSizeBits]; + + for (int block = 0; block < blockCount; block++) + { + for (int i = 0; i < blockHalfSize; i++) + { + int frontPos = (block * blockSize + i) * 2; + int backPos = frontPos + blockSize; + double a = dctTemp[frontPos] - dctTemp[backPos]; + double b = dctTemp[frontPos + 1] - dctTemp[backPos + 1]; + double sin = sinTable[i]; + double cos = cosTable[i]; + dctTemp[frontPos] += dctTemp[backPos]; + dctTemp[frontPos + 1] += dctTemp[backPos + 1]; + dctTemp[backPos] = a * cos + b * sin; + dctTemp[backPos + 1] = a * sin - b * cos; + } + } + } + + for (int i = 0; i < MdctSize; i++) + { + output[i] = dctTemp[shuffleTable[i]]; + } +} \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/imdct.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/imdct.h new file mode 100644 index 000000000..e8c3bf3c6 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/imdct.h @@ -0,0 +1,6 @@ +#pragma once + +#include "structures.h" + +void RunImdct(mdct* mdct, double* input, double* output); +void Dct4(mdct* mdct, double* input, double* output); \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.c new file mode 100644 index 000000000..2dbe1cd7e --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.c @@ -0,0 +1,33 @@ +#include "libatrac9.h" +#include "structures.h" +#include +#include +#include "decinit.h" +#include "decoder.h" + +void* Atrac9GetHandle() +{ + struct atrac9_handle* handle = malloc(sizeof(atrac9_handle)); + memset(handle, 0, sizeof(atrac9_handle)); + return handle; +} + +void Atrac9ReleaseHandle(void* handle) +{ + free(handle); +} + +int Atrac9InitDecoder(void* handle, unsigned char * pConfigData) +{ + return init_decoder(handle, pConfigData, 16); +} + +int Atrac9Decode(void* handle, const unsigned char *pAtrac9Buffer, short *pPcmBuffer, int *pNBytesUsed) +{ + return Decode(handle, pAtrac9Buffer, (unsigned char*)pPcmBuffer, pNBytesUsed); +} + +int Atrac9GetCodecInfo(void* handle, Atrac9CodecInfo * pCodecInfo) +{ + return GetCodecInfo(handle, (CodecInfo*)pCodecInfo); +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.h new file mode 100644 index 000000000..977f80444 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.h @@ -0,0 +1,32 @@ +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#define ATRAC9_CONFIG_DATA_SIZE 4 + +typedef struct { + int channels; + int channelConfigIndex; + int samplingRate; + int superframeSize; + int framesInSuperframe; + int frameSamples; + int wlength; + unsigned char configData[ATRAC9_CONFIG_DATA_SIZE]; + + double MdctWindow[3][256]; + double ImdctWindow[3][256]; +} Atrac9CodecInfo; + +void* Atrac9GetHandle(void); +void Atrac9ReleaseHandle(void* handle); + +int Atrac9InitDecoder(void* handle, unsigned char *pConfigData); +int Atrac9Decode(void* handle, const unsigned char *pAtrac9Buffer, short *pPcmBuffer, int *pNBytesUsed); + +int Atrac9GetCodecInfo(void* handle, Atrac9CodecInfo *pCodecInfo); + +#ifdef __cplusplus +} +#endif diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.sln b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.sln new file mode 100644 index 000000000..8c7c6bfdf --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2010 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libatrac9", "libatrac9.vcxproj", "{2425F2CC-BB1B-4069-BC10-1C7F535EF8E8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2425F2CC-BB1B-4069-BC10-1C7F535EF8E8}.Debug|x64.ActiveCfg = Debug|x64 + {2425F2CC-BB1B-4069-BC10-1C7F535EF8E8}.Debug|x64.Build.0 = Debug|x64 + {2425F2CC-BB1B-4069-BC10-1C7F535EF8E8}.Debug|x86.ActiveCfg = Debug|Win32 + {2425F2CC-BB1B-4069-BC10-1C7F535EF8E8}.Debug|x86.Build.0 = Debug|Win32 + {2425F2CC-BB1B-4069-BC10-1C7F535EF8E8}.Release|x64.ActiveCfg = Release|x64 + {2425F2CC-BB1B-4069-BC10-1C7F535EF8E8}.Release|x64.Build.0 = Release|x64 + {2425F2CC-BB1B-4069-BC10-1C7F535EF8E8}.Release|x86.ActiveCfg = Release|Win32 + {2425F2CC-BB1B-4069-BC10-1C7F535EF8E8}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BB003D83-77D8-4E7B-896D-7C9ADA458F73} + EndGlobalSection +EndGlobal diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.vcxproj b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.vcxproj new file mode 100644 index 000000000..8830bda95 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.vcxproj @@ -0,0 +1,162 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {2425F2CC-BB1B-4069-BC10-1C7F535EF8E8} + libatrac9 + 10.0.16299.0 + libatrac9 + + + + DynamicLibrary + true + v141 + MultiByte + + + DynamicLibrary + false + v141 + true + MultiByte + + + DynamicLibrary + true + v141 + MultiByte + + + DynamicLibrary + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + true + _WINDLL;COMPILING_DLL;%(PreprocessorDefinitions) + CompileAsC + + + + + Level3 + Disabled + true + true + CompileAsC + _WINDLL;COMPILING_DLL;%(PreprocessorDefinitions) + + + + + Level3 + MaxSpeed + true + true + true + true + CompileAsC + _WINDLL;COMPILING_DLL;%(PreprocessorDefinitions) + Sync + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + CompileAsC + _WINDLL;COMPILING_DLL;%(PreprocessorDefinitions) + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.vcxproj.filters b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.vcxproj.filters new file mode 100644 index 000000000..24c4233a8 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/libatrac9.vcxproj.filters @@ -0,0 +1,105 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/quantization.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/quantization.c new file mode 100644 index 000000000..6d95e62ab --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/quantization.c @@ -0,0 +1,54 @@ +#include "quantization.h" +#include +#include "tables.h" + +void DequantizeSpectra(block* block) +{ + for (int i = 0; i < block->ChannelCount; i++) + { + channel* channel = &block->Channels[i]; + memset(channel->Spectra, 0, sizeof(channel->Spectra)); + + for (int j = 0; j < channel->CodedQuantUnits; j++) + { + DequantizeQuantUnit(channel, j); + } + } +} + + void DequantizeQuantUnit(channel* channel, int band) +{ + const int subBandIndex = QuantUnitToCoeffIndex[band]; + const int subBandCount = QuantUnitToCoeffCount[band]; + const double stepSize = QuantizerStepSize[channel->Precisions[band]]; + const double stepSizeFine = QuantizerFineStepSize[channel->PrecisionsFine[band]]; + + for (int sb = 0; sb < subBandCount; sb++) + { + const double coarse = channel->QuantizedSpectra[subBandIndex + sb] * stepSize; + const double fine = channel->QuantizedSpectraFine[subBandIndex + sb] * stepSizeFine; + channel->Spectra[subBandIndex + sb] = coarse + fine; + } +} + +void ScaleSpectrumBlock(block* block) + { + for (int i = 0; i < block->ChannelCount; i++) + { + ScaleSpectrumChannel(&block->Channels[i]); + } + } + +void ScaleSpectrumChannel(channel* channel) +{ + const int quantUnitCount = channel->Block->QuantizationUnitCount; + double* spectra = channel->Spectra; + + for (int i = 0; i < quantUnitCount; i++) + { + for (int sb = QuantUnitToCoeffIndex[i]; sb < QuantUnitToCoeffIndex[i + 1]; sb++) + { + spectra[sb] *= SpectrumScale[channel->ScaleFactors[i]]; + } + } + } \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/quantization.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/quantization.h new file mode 100644 index 000000000..d9de74a3e --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/quantization.h @@ -0,0 +1,8 @@ +#pragma once + +#include "structures.h" + +void DequantizeSpectra(block* block); +void DequantizeQuantUnit(channel* channel, int band); +void ScaleSpectrumBlock(block* block); +void ScaleSpectrumChannel(channel* channel); \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/scale_factors.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/scale_factors.c new file mode 100644 index 000000000..ee812414a --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/scale_factors.c @@ -0,0 +1,146 @@ +#include +#include "huffCodes.h" +#include "scale_factors.h" +#include "tables.h" +#include "utility.h" + +at9_status read_scale_factors(channel * channel, bit_reader_cxt * br) +{ + memset(channel->ScaleFactors, 0, sizeof(channel->ScaleFactors)); + + channel->ScaleFactorCodingMode = read_int(br, 2); + if (channel->ChannelIndex == 0) + { + switch (channel->ScaleFactorCodingMode) + { + case 0: + ReadVlcDeltaOffset(channel, br); + break; + case 1: + ReadClcOffset(channel, br); + break; + case 2: + if (channel->Block->FirstInSuperframe) return ERR_UNPACK_SCALE_FACTOR_MODE_INVALID; + ReadVlcDistanceToBaseline(channel, br, channel->ScaleFactorsPrev, channel->Block->QuantizationUnitsPrev); + break; + case 3: + if (channel->Block->FirstInSuperframe) return ERR_UNPACK_SCALE_FACTOR_MODE_INVALID; + ReadVlcDeltaOffsetWithBaseline(channel, br, channel->ScaleFactorsPrev, channel->Block->QuantizationUnitsPrev); + break; + } + } + else + { + switch (channel->ScaleFactorCodingMode) + { + case 0: + ReadVlcDeltaOffset(channel, br); + break; + case 1: + ReadVlcDistanceToBaseline(channel, br, channel->Block->Channels[0].ScaleFactors, channel->Block->ExtensionUnit); + break; + case 2: + ReadVlcDeltaOffsetWithBaseline(channel, br, channel->Block->Channels[0].ScaleFactors, channel->Block->ExtensionUnit); + break; + case 3: + if (channel->Block->FirstInSuperframe) return ERR_UNPACK_SCALE_FACTOR_MODE_INVALID; + ReadVlcDistanceToBaseline(channel, br, channel->ScaleFactorsPrev, channel->Block->QuantizationUnitsPrev); + break; + } + } + + for (int i = 0; i < channel->Block->ExtensionUnit; i++) + { + if (channel->ScaleFactors[i] < 0 || channel->ScaleFactors[i] > 31) + { + return ERR_UNPACK_SCALE_FACTOR_OOB; + } + } + + memcpy(channel->ScaleFactorsPrev, channel->ScaleFactors, sizeof(channel->ScaleFactors)); + + return ERR_SUCCESS; +} + +void ReadClcOffset(channel* channel, bit_reader_cxt* br) +{ + const int maxBits = 5; + int* sf = channel->ScaleFactors; + const int bitLength = read_int(br, 2) + 2; + const int baseValue = bitLength < maxBits ? read_int(br, maxBits) : 0; + + for (int i = 0; i < channel->Block->ExtensionUnit; i++) + { + sf[i] = read_int(br, bitLength) + baseValue; + } +} + +void ReadVlcDeltaOffset(channel* channel, bit_reader_cxt* br) +{ + const int weightIndex = read_int(br, 3); + const unsigned char* weights = ScaleFactorWeights[weightIndex]; + + int* sf = channel->ScaleFactors; + const int baseValue = read_int(br, 5); + const int bitLength = read_int(br, 2) + 3; + const HuffmanCodebook* codebook = &HuffmanScaleFactorsUnsigned[bitLength]; + + sf[0] = read_int(br, bitLength); + + for (int i = 1; i < channel->Block->ExtensionUnit; i++) + { + const int delta = ReadHuffmanValue(codebook, br, 0); + sf[i] = (sf[i - 1] + delta) & (codebook->ValueMax - 1); + } + + for (int i = 0; i < channel->Block->ExtensionUnit; i++) + { + sf[i] += baseValue - weights[i]; + } +} + +void ReadVlcDistanceToBaseline(channel* channel, bit_reader_cxt* br, int* baseline, int baselineLength) +{ + int* sf = channel->ScaleFactors; + const int bit_length = read_int(br, 2) + 2; + const HuffmanCodebook* codebook = &HuffmanScaleFactorsSigned[bit_length]; + const int unitCount = min(channel->Block->ExtensionUnit, baselineLength); + + for (int i = 0; i < unitCount; i++) + { + const int distance = ReadHuffmanValue(codebook, br, TRUE); + sf[i] = (baseline[i] + distance) & 31; + } + + for (int i = unitCount; i < channel->Block->ExtensionUnit; i++) + { + sf[i] = read_int(br, 5); + } +} + +void ReadVlcDeltaOffsetWithBaseline(channel* channel, bit_reader_cxt* br, int* baseline, int baselineLength) +{ + int* sf = channel->ScaleFactors; + const int baseValue = read_offset_binary(br, 5); + const int bitLength = read_int(br, 2) + 1; + const HuffmanCodebook* codebook = &HuffmanScaleFactorsUnsigned[bitLength]; + const int unitCount = min(channel->Block->ExtensionUnit, baselineLength); + + sf[0] = read_int(br, bitLength); + + for (int i = 1; i < unitCount; i++) + { + const int delta = ReadHuffmanValue(codebook, br, FALSE); + sf[i] = (sf[i - 1] + delta) & (codebook->ValueMax - 1); + } + + for (int i = 0; i < unitCount; i++) + { + sf[i] += baseValue + baseline[i]; + } + + for (int i = unitCount; i < channel->Block->ExtensionUnit; i++) + { + sf[i] = read_int(br, 5); + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/scale_factors.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/scale_factors.h new file mode 100644 index 000000000..557c83436 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/scale_factors.h @@ -0,0 +1,8 @@ +#pragma once +#include "bit_allocation.h" + +at9_status read_scale_factors(channel* channel, bit_reader_cxt* br); +void ReadClcOffset(channel* channel, bit_reader_cxt* br); +void ReadVlcDeltaOffset(channel* channel, bit_reader_cxt* br); +void ReadVlcDistanceToBaseline(channel* channel, bit_reader_cxt* br, int* baseline, int baselineLength); +void ReadVlcDeltaOffsetWithBaseline(channel* channel, bit_reader_cxt* br, int* baseline, int baselineLength); diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/structures.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/structures.h new file mode 100644 index 000000000..05a9b3049 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/structures.h @@ -0,0 +1,160 @@ +#pragma once + +#define CONFIG_DATA_SIZE 4 +#define MAX_BLOCK_COUNT 5 +#define MAX_BLOCK_CHANNEL_COUNT 2 +#define MAX_FRAME_SAMPLES 256 +#define MAX_BEX_VALUES 4 + +#define MAX_QUANT_UNITS 30 + +typedef struct frame frame; +typedef struct block block; + +typedef enum BlockType { + Mono = 0, + Stereo = 1, + LFE = 2 +} BlockType; + +typedef struct { + int BlockCount; + int ChannelCount; + enum BlockType Types[MAX_BLOCK_COUNT]; +} ChannelConfig; + +typedef struct { + unsigned char ConfigData[CONFIG_DATA_SIZE]; + int SampleRateIndex; + int ChannelConfigIndex; + int FrameBytes; + int SuperframeIndex; + + ChannelConfig ChannelConfig; + int ChannelCount; + int SampleRate; + int HighSampleRate; + int FramesPerSuperframe; + int FrameSamplesPower; + int FrameSamples; + int SuperframeBytes; + int SuperframeSamples; +} ConfigData; + +typedef struct { + int initialized; + unsigned short stateA; + unsigned short stateB; + unsigned short stateC; + unsigned short stateD; +} rng_cxt; + +typedef struct { + int bits; + int size; + double scale; + double _imdctPrevious[MAX_FRAME_SAMPLES]; + double* window; + double* sinTable; + double* cosTable; +} mdct; + +typedef struct { + frame* Frame; + block* Block; + ConfigData* config; + int ChannelIndex; + + mdct mdct; + + double Pcm[MAX_FRAME_SAMPLES]; + double Spectra[MAX_FRAME_SAMPLES]; + + int CodedQuantUnits; + int ScaleFactorCodingMode; + + int ScaleFactors[31]; + int ScaleFactorsPrev[31]; + + int Precisions[MAX_QUANT_UNITS]; + int PrecisionsFine[MAX_QUANT_UNITS]; + int PrecisionMask[MAX_QUANT_UNITS]; + + int CodebookSet[MAX_QUANT_UNITS]; + + int QuantizedSpectra[MAX_FRAME_SAMPLES]; + int QuantizedSpectraFine[MAX_FRAME_SAMPLES]; + + int BexMode; + int BexValueCount; + int BexValues[MAX_BEX_VALUES]; + + rng_cxt rng; +} channel; + +struct block { + frame* Frame; + ConfigData* config; + enum BlockType BlockType; + int BlockIndex; + channel Channels[MAX_BLOCK_CHANNEL_COUNT]; + int ChannelCount; + int FirstInSuperframe; + int ReuseBandParams; + + int BandCount; + int StereoBand; + int ExtensionBand; + int QuantizationUnitCount; + int StereoQuantizationUnit; + int ExtensionUnit; + int QuantizationUnitsPrev; + + int Gradient[31]; + int GradientMode; + int GradientStartUnit; + int GradientStartValue; + int GradientEndUnit; + int GradientEndValue; + int GradientBoundary; + + int PrimaryChannelIndex; + int HasJointStereoSigns; + int JointStereoSigns[MAX_QUANT_UNITS]; + + int BandExtensionEnabled; + int HasExtensionData; + int BexDataLength; + int BexMode; +}; + +struct frame { + ConfigData* config; + int FrameIndex; + block Blocks[MAX_BLOCK_COUNT]; + int frameNum; +}; + +typedef struct { + int initialized; + int wlength; + ConfigData config; + frame frame; +} atrac9_handle; + +typedef struct { + int group_b_unit; + int group_c_unit; + int band_count; +} bex_group; + +typedef struct { + int channels; + int channelConfigIndex; + int samplingRate; + int superframeSize; + int framesInSuperframe; + int frameSamples; + int wlength; + unsigned char configData[CONFIG_DATA_SIZE]; +} CodecInfo; diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/tables.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/tables.c new file mode 100644 index 000000000..35d9ad6ee --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/tables.c @@ -0,0 +1,7 @@ +#include "tables.h" + +double MdctWindow[3][256]; +double ImdctWindow[3][256]; +double SinTables[9][256]; +double CosTables[9][256]; +int ShuffleTables[9][256]; diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/tables.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/tables.h new file mode 100644 index 000000000..7be2ebf05 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/tables.h @@ -0,0 +1,389 @@ +#pragma once + +#include "structures.h" + +static const ChannelConfig ChannelConfigs[6] = +{ + {1, 1, Mono}, + {2, 2, Mono, Mono}, + {1, 2, Stereo}, + {4, 6, Stereo, Mono, LFE, Stereo}, + {5, 8, Stereo, Mono, LFE, Stereo, Stereo}, + {2, 4, Stereo, Stereo}, +}; + +static const int MaxHuffPrecision[2] = { 7, 1 }; +static const int MinBandCount[2] = { 3, 1 }; +static const int MaxExtensionBand[2] = { 18, 16 }; + +static const int SamplingRateIndexToFrameSamplesPower[16] = +{ 6, 6, 7, 7, 7, 8, 8, 8, 6, 6, 7, 7, 7, 8, 8, 8 }; + +static const int MaxBandCount[16] = +{ 8, 8, 12, 12, 12, 18, 18, 18, 8, 8, 12, 12, 12, 16, 16, 16 }; + +static const int BandToQuantUnitCount[19] = +{ 0, 4, 8, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 28, 30 }; + +static const int QuantUnitToCoeffCount[30] = +{ + 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 8, 8, 8, + 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 +}; + +static const int QuantUnitToCoeffIndex[31] = +{ + 0, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, + 64, 72, 80, 88, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256 +}; + +static const int QuantUnitToCodebookIndex[30] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 +}; + +static const int SampleRates[16] = +{ + 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, + 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 +}; + +static const unsigned char GradientCurves[48][48] = { + { 1 }, + { 1, 16 }, + { 1, 7, 25 }, + { 1, 4, 16, 27 }, + { 1, 3, 10, 21, 28 }, + { 1, 3, 7, 16, 25, 29 }, + { 1, 2, 5, 11, 20, 26, 29 }, + { 1, 2, 4, 9, 16, 23, 27, 29 }, + { 1, 2, 3, 7, 12, 19, 25, 28, 29 }, + { 1, 2, 3, 5, 10, 16, 21, 26, 28, 29 }, + { 1, 2, 3, 5, 8, 12, 19, 23, 26, 28, 29 }, + { 1, 2, 3, 4, 7, 11, 16, 21, 25, 27, 29, 30 }, + { 1, 1, 2, 4, 5, 9, 13, 18, 22, 26, 27, 29, 30 }, + { 1, 1, 2, 3, 5, 8, 11, 16, 20, 23, 26, 28, 29, 30 }, + { 1, 1, 2, 3, 4, 7, 10, 13, 18, 21, 25, 27, 28, 29, 30 }, + { 1, 1, 2, 3, 4, 6, 9, 12, 16, 20, 23, 26, 27, 28, 29, 30 }, + { 1, 1, 2, 3, 4, 5, 7, 10, 13, 18, 21, 24, 26, 27, 28, 29, 30 }, + { 1, 1, 2, 3, 3, 5, 7, 9, 12, 16, 19, 22, 25, 26, 28, 29, 29, 30 }, + { 1, 1, 2, 2, 3, 4, 6, 8, 11, 13, 18, 20, 23, 25, 27, 28, 29, 29, 30 }, + { 1, 1, 2, 2, 3, 4, 5, 7, 10, 12, 16, 19, 21, 24, 26, 27, 28, 29, 29, 30 }, + { 1, 1, 2, 2, 3, 4, 5, 7, 9, 11, 13, 18, 20, 22, 25, 26, 27, 28, 29, 29, 30 }, + { 1, 1, 2, 2, 3, 3, 5, 6, 8, 10, 12, 16, 19, 21, 23, 25, 26, 28, 28, 29, 29, + 30 }, + { 1, 1, 2, 2, 3, 3, 4, 5, 7, 9, 11, 13, 18, 20, 22, 24, 26, 27, 28, 28, 29, + 29, 30 }, + { 1, 1, 2, 2, 3, 3, 4, 5, 7, 9, 11, 13, 16, 19, 21, 23, 25, 26, 27, 28, 29, + 29, 30, 30 }, + { 1, 1, 1, 2, 2, 3, 4, 5, 6, 8, 10, 12, 15, 16, 19, 21, 23, 25, 26, 27, 28, + 29, 29, 30, 30 }, + { 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 9, 11, 13, 16, 18, 20, 22, 24, 26, 27, 27, + 28, 29, 29, 30, 30 }, + { 1, 1, 1, 2, 2, 3, 3, 4, 5, 7, 8, 10, 12, 15, 16, 19, 21, 23, 25, 26, 27, + 28, 28, 29, 29, 30, 30 }, + { 1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 8, 9, 11, 13, 16, 18, 20, 22, 23, 25, 26, 27, + 28, 28, 29, 29, 30, 30 }, + { 1, 1, 1, 2, 2, 3, 3, 4, 5, 5, 7, 9, 10, 12, 15, 16, 19, 21, 22, 24, 26, 26, + 27, 28, 28, 29, 29, 30, 30 }, + { 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 10, 11, 13, 16, 18, 20, 21, 23, 25, 26, + 27, 27, 28, 29, 29, 29, 30, 30 }, + { 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6, 8, 9, 11, 12, 15, 16, 19, 20, 22, 23, 25, + 26, 27, 28, 28, 29, 29, 29, 30, 30 }, + { 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 13, 16, 18, 20, 21, 23, 24, + 26, 26, 27, 28, 28, 29, 29, 29, 30, 30 }, + { 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 5, 7, 8, 9, 11, 12, 15, 16, 19, 20, 22, 23, + 25, 26, 26, 27, 28, 28, 29, 29, 29, 30, 30 }, + { 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6, 7, 9, 10, 12, 13, 16, 18, 19, 21, 22, + 24, 25, 26, 27, 27, 28, 28, 29, 29, 29, 30, 30 }, + { 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 5, 6, 7, 8, 10, 11, 12, 15, 16, 19, 20, 21, + 23, 24, 25, 26, 27, 28, 28, 28, 29, 29, 29, 30, 30 }, + { 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 7, 8, 9, 11, 12, 13, 16, 18, 19, 21, + 22, 23, 25, 26, 26, 27, 28, 28, 29, 29, 29, 30, 30, 30 }, + { 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6, 7, 9, 10, 11, 13, 15, 16, 18, 20, + 21, 22, 24, 25, 26, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30 }, + { 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 11, 12, 13, 16, 18, 19, 20, + 22, 23, 24, 25, 26, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30 }, + { 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 7, 8, 9, 10, 11, 13, 15, 16, 18, 20, + 21, 22, 23, 25, 26, 26, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30 }, + { 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 7, 9, 10, 11, 12, 13, 16, 18, 19, + 20, 21, 23, 24, 25, 26, 26, 27, 28, 28, 28, 29, 29, 29, 30, 30, 30 }, + { 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 16, 18, + 19, 21, 22, 23, 24, 25, 26, 27, 27, 28, 28, 28, 29, 29, 29, 30, 30, 30 }, + { 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 7, 8, 9, 10, 11, 12, 13, 16, 18, + 19, 20, 21, 22, 23, 25, 26, 26, 27, 27, 28, 28, 29, 29, 29, 29, 30, 30, + 30 }, + { 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, + 18, 19, 20, 22, 23, 24, 25, 26, 26, 27, 27, 28, 28, 29, 29, 29, 29, 30, 30, + 30 }, + { 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 28, 28, 29, 29, 29, 29, 30, + 30, 30 }, + { 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 7, 8, 9, 10, 11, 12, 13, 15, + 16, 18, 19, 20, 21, 22, 23, 25, 26, 26, 27, 27, 28, 28, 28, 29, 29, 29, 29, + 30, 30, 30 }, + { 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 27, 28, 28, 28, 29, 29, 29, + 29, 30, 30, 30 }, + { 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 27, 28, 28, 28, 29, 29, + 29, 29, 30, 30, 30 }, + { 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 27, 28, 28, 28, 29, 29, + 29, 29, 30, 30, 30, 30 } +}; + +static const unsigned char ScaleFactorWeights[8][32] = { + { 0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 10, 12, 12, 12 }, + { 3, 2, 2, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 2, 3, + 3, 4, 5, 7, 10, 10, 10 }, + { 0, 2, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 8, 9, 12, 12, 12 }, + { 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 8, 8, 10, + 11, 11, 12, 13, 13, 13, 13 }, + { 0, 2, 2, 3, 3, 4, 4, 5, 4, 5, 5, 5, 5, 6, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, + 11, 12, 12, 13, 13, 14, 14, 14 }, + { 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, + 6, 7, 7, 9, 11, 11, 11 }, + { 0, 5, 8, 10, 11, 11, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 12, 12, 12, 12, 13, 15, 15, 15 }, + { 0, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11, 11, + 11, 12, 12, 12, 12, 13, 13, 15, 15, 15 } +}; + +static const double SpectrumScale[32] = +{ + 3.0517578125e-5, 6.1035156250e-5, 1.2207031250e-4, 2.4414062500e-4, + 4.8828125000e-4, 9.7656250000e-4, 1.9531250000e-3, 3.9062500000e-3, + 7.8125000000e-3, 1.5625000000e-2, 3.1250000000e-2, 6.2500000000e-2, + 1.2500000000e-1, 2.5000000000e-1, 5.0000000000e-1, 1.0000000000e+0, + 2.0000000000e+0, 4.0000000000e+0, 8.0000000000e+0, 1.6000000000e+1, + 3.2000000000e+1, 6.4000000000e+1, 1.2800000000e+2, 2.5600000000e+2, + 5.1200000000e+2, 1.0240000000e+3, 2.0480000000e+3, 4.0960000000e+3, + 8.1920000000e+3, 1.6384000000e+4, 3.2768000000e+4, 6.5536000000e+4 +}; + +static const double QuantizerInverseStepSize[16] = +{ + 0.5, 1.5, 3.5, 7.5, 15.5, 31.5, 63.5, 127.5, + 255.5, 511.5, 1023.5, 2047.5, 4095.5, 8191.5, 16383.5, 32767.5 +}; + +static const double QuantizerStepSize[16] = +{ + 2.0000000000000000e+0, 6.6666666666666663e-1, 2.8571428571428570e-1, 1.3333333333333333e-1, + 6.4516129032258063e-2, 3.1746031746031744e-2, 1.5748031496062992e-2, 7.8431372549019607e-3, + 3.9138943248532287e-3, 1.9550342130987292e-3, 9.7703957010258913e-4, 4.8840048840048840e-4, + 2.4417043096081065e-4, 1.2207776353537203e-4, 6.1037018951994385e-5, 3.0518043793392844e-5 +}; + +static const double QuantizerFineStepSize[16] = +{ + 3.0518043793392844e-05, 1.0172681264464281e-05, 4.3597205419132631e-06, 2.0345362528928561e-06, + 9.8445302559331759e-07, 4.8441339354591809e-07, 2.4029955742829012e-07, 1.1967860311134448e-07, + 5.9722199204291275e-08, 2.9831909866464167e-08, 1.4908668194134265e-08, 7.4525137468602791e-09, + 3.7258019525568114e-09, 1.8627872668859698e-09, 9.3136520869755679e-10, 4.6567549848772173e-10 +}; + +static const bex_group BexGroupInfo[8] = +{ + { 16, 21, 0 }, + { 18, 22, 1 }, + { 20, 22, 2 }, + { 21, 22, 3 }, + { 21, 22, 3 }, + { 23, 24, 4 }, + { 23, 24, 4 }, + { 24, 24, 5 } +}; + +static const int BexEncodedValueCounts[5][6] = +{ + {0, 0, 0, 4, 4, 2}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 2, 2, 1}, + {0, 0, 0, 2, 2, 2}, + {1, 1, 1, 0, 0, 0} +}; + +// [mode][bands][valueIndex] +static const int BexDataLengths[5][6][4] = +{ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {5, 4, 3, 3}, + {4, 4, 3, 4}, + {4, 5, 0, 0} + }, { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {6, 6, 0, 0}, + {6, 6, 0, 0}, + {6, 0, 0, 0} + }, { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {4, 4, 0, 0}, + {4, 4, 0, 0}, + {4, 4, 0, 0} + }, { + {3, 0, 0, 0}, + {3, 0, 0, 0}, + {3, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + } +}; + +static const double BexMode0Bands3[5][32] = +{ + { + 0.000000e+0, 1.988220e-1, 2.514343e-1, 2.960510e-1, + 3.263550e-1, 3.771362e-1, 3.786926e-1, 4.540405e-1, + 4.877625e-1, 5.262451e-1, 5.447083e-1, 5.737000e-1, + 6.212158e-1, 6.222839e-1, 6.560974e-1, 6.896667e-1, + 7.555542e-1, 7.677917e-1, 7.918091e-1, 7.971497e-1, + 8.188171e-1, 8.446045e-1, 9.790649e-1, 9.822083e-1, + 9.846191e-1, 9.859314e-1, 9.863586e-1, 9.863892e-1, + 9.873352e-1, 9.881287e-1, 9.898682e-1, 9.913330e-1 + }, { + 0.000000e+0, 9.982910e-1, 7.592773e-2, 7.179565e-1, + 9.851379e-1, 5.340271e-1, 9.013672e-1, 6.349182e-1, + 7.226257e-1, 1.948547e-1, 7.628174e-1, 9.873657e-1, + 8.112183e-1, 2.715454e-1, 9.734192e-1, 1.443787e-1, + 4.640198e-1, 3.249207e-1, 3.790894e-1, 8.276367e-2, + 5.954590e-1, 2.864380e-1, 9.806824e-1, 7.929077e-1, + 6.292114e-1, 4.887085e-1, 2.905273e-1, 1.301880e-1, + 3.140869e-1, 5.482483e-1, 4.210815e-1, 1.182861e-1 + }, { + 0.000000e+0, 3.155518e-2, 8.581543e-2, 1.364746e-1, + 1.858826e-1, 2.368469e-1, 2.888184e-1, 3.432617e-1, + 4.012451e-1, 4.623108e-1, 5.271301e-1, 5.954895e-1, + 6.681213e-1, 7.448425e-1, 8.245239e-1, 9.097290e-1 + }, { + 0.000000e+0, 4.418945e-2, 1.303711e-1, 2.273560e-1, + 3.395996e-1, 4.735718e-1, 6.267090e-1, 8.003845e-1 + }, { + 0.000000e+0, 2.804565e-2, 9.683228e-2, 1.849976e-1, + 3.005981e-1, 4.470520e-1, 6.168518e-1, 8.007813e-1 + } +}; + +static const double BexMode0Bands4[5][16] = +{ + { + 0.000000e+0, 2.708740e-1, 3.479614e-1, 3.578186e-1, + 5.083618e-1, 5.299072e-1, 5.819092e-1, 6.381836e-1, + 7.276917e-1, 7.595520e-1, 7.878723e-1, 9.707336e-1, + 9.713135e-1, 9.736023e-1, 9.759827e-1, 9.832458e-1 + }, { + 0.000000e+0, 2.330627e-1, 5.891418e-1, 7.170410e-1, + 2.036438e-1, 1.613464e-1, 6.668701e-1, 9.481201e-1, + 9.769897e-1, 5.111694e-1, 3.522644e-1, 8.209534e-1, + 2.933960e-1, 9.757690e-1, 5.289917e-1, 4.372253e-1 + }, { + 0.000000e+0, 4.360962e-2, 1.056519e-1, 1.590576e-1, + 2.078857e-1, 2.572937e-1, 3.082581e-1, 3.616028e-1, + 4.191589e-1, 4.792175e-1, 5.438538e-1, 6.125183e-1, + 6.841125e-1, 7.589417e-1, 8.365173e-1, 9.148254e-1 + }, { + 0.000000e+0, 4.074097e-2, 1.164551e-1, 2.077026e-1, + 3.184509e-1, 4.532166e-1, 6.124268e-1, 7.932129e-1 + }, { + 0.000000e+0, 8.880615e-3, 2.932739e-2, 5.593872e-2, + 8.825684e-2, 1.259155e-1, 1.721497e-1, 2.270813e-1, + 2.901611e-1, 3.579712e-1, 4.334106e-1, 5.147095e-1, + 6.023254e-1, 6.956177e-1, 7.952881e-1, 8.977356e-1 + } +}; + +static const double BexMode0Bands5[3][32] = +{ + { + 0.000000e+0, 7.379150e-2, 1.806335e-1, 2.687073e-1, + 3.407898e-1, 4.047546e-1, 4.621887e-1, 5.168762e-1, + 5.703125e-1, 6.237488e-1, 6.763611e-1, 7.288208e-1, + 7.808533e-1, 8.337708e-1, 8.874512e-1, 9.418030e-1 + }, { + 0.000000e+0, 7.980347e-2, 1.615295e-1, 1.665649e-1, + 1.822205e-1, 2.185669e-1, 2.292175e-1, 2.456665e-1, + 2.666321e-1, 3.306580e-1, 3.330688e-1, 3.765259e-1, + 4.085083e-1, 4.400024e-1, 4.407654e-1, 4.817505e-1, + 4.924011e-1, 5.320740e-1, 5.893860e-1, 6.131287e-1, + 6.212463e-1, 6.278076e-1, 6.308899e-1, 7.660828e-1, + 7.850647e-1, 7.910461e-1, 7.929382e-1, 8.038330e-1, + 9.834900e-1, 9.846191e-1, 9.852295e-1, 9.862671e-1 + }, { + 0.000000e+0, 6.084290e-1, 3.672791e-1, 3.151855e-1, + 1.488953e-1, 2.571716e-1, 5.103455e-1, 3.311157e-1, + 5.426025e-2, 4.254456e-1, 7.998352e-1, 7.873230e-1, + 5.418701e-1, 2.925110e-1, 8.468628e-2, 1.410522e-1, + 9.819641e-1, 9.609070e-1, 3.530884e-2, 9.729004e-2, + 5.758362e-1, 9.941711e-1, 7.215576e-1, 7.183228e-1, + 2.028809e-1, 9.588623e-2, 2.032166e-1, 1.338806e-1, + 5.003357e-1, 1.874390e-1, 9.804993e-1, 1.107788e-1 + } +}; + +static const double BexMode2Scale[64] = +{ + 4.272461e-4, 1.312256e-3, 2.441406e-3, 3.692627e-3, + 4.913330e-3, 6.134033e-3, 7.507324e-3, 8.972168e-3, + 1.049805e-2, 1.223755e-2, 1.406860e-2, 1.599121e-2, + 1.800537e-2, 2.026367e-2, 2.264404e-2, 2.517700e-2, + 2.792358e-2, 3.073120e-2, 3.344727e-2, 3.631592e-2, + 3.952026e-2, 4.275513e-2, 4.608154e-2, 4.968262e-2, + 5.355835e-2, 5.783081e-2, 6.195068e-2, 6.677246e-2, + 7.196045e-2, 7.745361e-2, 8.319092e-2, 8.993530e-2, + 9.759521e-2, 1.056213e-1, 1.138916e-1, 1.236267e-1, + 1.348267e-1, 1.470337e-1, 1.603394e-1, 1.755676e-1, + 1.905823e-1, 2.071228e-1, 2.245178e-1, 2.444153e-1, + 2.658997e-1, 2.897644e-1, 3.146057e-1, 3.450012e-1, + 3.766174e-1, 4.122620e-1, 4.505615e-1, 4.893799e-1, + 5.305481e-1, 5.731201e-1, 6.157837e-1, 6.580811e-1, + 6.985168e-1, 7.435303e-1, 7.865906e-1, 8.302612e-1, + 8.718567e-1, 9.125671e-1, 9.575806e-1, 9.996643e-1 +}; + +static const double BexMode3Initial[16] = +{ + 3.491211e-1, 5.371094e-1, 6.782227e-1, 7.910156e-1, + 9.057617e-1, 1.024902e+0, 1.156250e+0, 1.290527e+0, + 1.458984e+0, 1.664551e+0, 1.929688e+0, 2.278320e+0, + 2.831543e+0, 3.659180e+0, 5.257813e+0, 8.373047e+0 +}; + +static const double BexMode3Rate[16] = +{ + -2.913818e-1, -2.541504e-1, -1.664429e-1, -1.476440e-1, + -1.342163e-1, -1.220703e-1, -1.117554e-1, -1.026611e-1, + -9.436035e-2, -8.483887e-2, -7.476807e-2, -6.304932e-2, + -4.492188e-2, -2.447510e-2, +1.831055e-4, +4.174805e-2 +}; + +static const double BexMode4Multiplier[8] = +{ + 3.610229e-2, 1.260681e-1, 2.227478e-1, 3.338318e-1, + 4.662170e-1, 6.221313e-1, 7.989197e-1, 9.939575e-1 +}; + +extern double MdctWindow[3][256]; +extern double ImdctWindow[3][256]; +extern double SinTables[9][256]; +extern double CosTables[9][256]; +extern int ShuffleTables[9][256]; + diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/unpack.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/unpack.c new file mode 100644 index 000000000..d65cab9c2 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/unpack.c @@ -0,0 +1,423 @@ +#include "tables.h" +#include "unpack.h" +#include "bit_allocation.h" +#include +#include "scale_factors.h" +#include "utility.h" +#include "huffCodes.h" + +at9_status UnpackFrame(frame* frame, bit_reader_cxt* br) +{ + const int block_count = frame->config->ChannelConfig.BlockCount; + + for (int i = 0; i < block_count; i++) + { + ERROR_CHECK(UnpackBlock(&frame->Blocks[i], br)); + } + return ERR_SUCCESS; +} + +at9_status UnpackBlock(block* block, bit_reader_cxt* br) +{ + ERROR_CHECK(ReadBlockHeader(block, br)); + + if (block->BlockType == LFE) + { + ERROR_CHECK(UnpackLfeBlock(block, br)); + } + else + { + ERROR_CHECK(UnpackStandardBlock(block, br)); + } + + align_position(br, 8); + return ERR_SUCCESS; +} + +at9_status ReadBlockHeader(block* block, bit_reader_cxt* br) +{ + int firstInSuperframe = block->Frame->FrameIndex == 0; + block->FirstInSuperframe = !read_int(br, 1); + block->ReuseBandParams = read_int(br, 1); + + if (block->FirstInSuperframe && block->ReuseBandParams && block->BlockType != LFE) + { + return ERR_UNPACK_REUSE_BAND_PARAMS_INVALID; + } + + return ERR_SUCCESS; +} + +at9_status UnpackStandardBlock(block* block, bit_reader_cxt* br) +{ + if (!block->ReuseBandParams) + { + ERROR_CHECK(ReadBandParams(block, br)); + } + + ERROR_CHECK(ReadGradientParams(block, br)); + ERROR_CHECK(CreateGradient(block)); + ERROR_CHECK(ReadStereoParams(block, br)); + ERROR_CHECK(ReadExtensionParams(block, br)); + + for (int i = 0; i < block->ChannelCount; i++) + { + channel* channel = &block->Channels[i]; + UpdateCodedUnits(channel); + + ERROR_CHECK(read_scale_factors(channel, br)); + CalculateMask(channel); + CalculatePrecisions(channel); + CalculateSpectrumCodebookIndex(channel); + + ERROR_CHECK(ReadSpectra(channel, br)); + ERROR_CHECK(ReadSpectraFine(channel, br)); + } + + block->QuantizationUnitsPrev = block->BandExtensionEnabled ? block->ExtensionUnit : block->QuantizationUnitCount; + return ERR_SUCCESS; +} + +at9_status ReadBandParams(block* block, bit_reader_cxt* br) +{ + const int minBandCount = MinBandCount[block->config->HighSampleRate]; + const int maxExtensionBand = MaxExtensionBand[block->config->HighSampleRate]; + block->BandCount = read_int(br, 4) + minBandCount; + block->QuantizationUnitCount = BandToQuantUnitCount[block->BandCount]; + + if (block->BandCount < minBandCount || block->BandCount > + MaxBandCount[block->config->SampleRateIndex]) + { + return ERR_SUCCESS; + } + + if (block->BlockType == Stereo) + { + block->StereoBand = read_int(br, 4); + block->StereoBand += minBandCount; + block->StereoQuantizationUnit = BandToQuantUnitCount[block->StereoBand]; + } + else + { + block->StereoBand = block->BandCount; + } + + block->BandExtensionEnabled = read_int(br, 1); + if (block->BandExtensionEnabled) + { + block->ExtensionBand = read_int(br, 4); + block->ExtensionBand += minBandCount; + + if (block->ExtensionBand < block->BandCount || block->ExtensionBand > maxExtensionBand) + { + return ERR_UNPACK_BAND_PARAMS_INVALID; + } + + block->ExtensionUnit = BandToQuantUnitCount[block->ExtensionBand]; + } + else + { + block->ExtensionBand = block->BandCount; + block->ExtensionUnit = block->QuantizationUnitCount; + } + + return ERR_SUCCESS; +} + +at9_status ReadGradientParams(block* block, bit_reader_cxt* br) +{ + block->GradientMode = read_int(br, 2); + if (block->GradientMode > 0) + { + block->GradientEndUnit = 31; + block->GradientEndValue = 31; + block->GradientStartUnit = read_int(br, 5); + block->GradientStartValue = read_int(br, 5); + } + else + { + block->GradientStartUnit = read_int(br, 6); + block->GradientEndUnit = read_int(br, 6) + 1; + block->GradientStartValue = read_int(br, 5); + block->GradientEndValue = read_int(br, 5); + } + block->GradientBoundary = read_int(br, 4); + + if (block->GradientBoundary > block->QuantizationUnitCount) + { + return ERR_UNPACK_GRAD_BOUNDARY_INVALID; + } + if (block->GradientStartUnit < 1 || block->GradientStartUnit >= 48) + { + return ERR_UNPACK_GRAD_START_UNIT_OOB; + } + if (block->GradientEndUnit < 1 || block->GradientEndUnit >= 48) + { + return ERR_UNPACK_GRAD_END_UNIT_OOB; + } + if (block->GradientStartUnit > block->GradientEndUnit) + { + return ERR_UNPACK_GRAD_END_UNIT_INVALID; + } + if (block->GradientStartValue < 0 || block->GradientStartValue >= 32) + { + return ERR_UNPACK_GRAD_START_VALUE_OOB; + } + if (block->GradientEndValue < 0 || block->GradientEndValue >= 32) + { + return ERR_UNPACK_GRAD_END_VALUE_OOB; + } + + return ERR_SUCCESS; +} + +at9_status ReadStereoParams(block* block, bit_reader_cxt* br) +{ + if (block->BlockType != Stereo) return ERR_SUCCESS; + + block->PrimaryChannelIndex = read_int(br, 1); + block->HasJointStereoSigns = read_int(br, 1); + if (block->HasJointStereoSigns) + { + for (int i = block->StereoQuantizationUnit; i < block->QuantizationUnitCount; i++) + { + block->JointStereoSigns[i] = read_int(br, 1); + } + } + else + { + memset(block->JointStereoSigns, 0, sizeof(block->JointStereoSigns)); + } + + return ERR_SUCCESS; +} + +void BexReadHeader(channel* channel, bit_reader_cxt* br, int bexBand) +{ + const int bexMode = read_int(br, 2); + channel->BexMode = bexBand > 2 ? bexMode : 4; + channel->BexValueCount = BexEncodedValueCounts[channel->BexMode][bexBand]; +} + +void BexReadData(channel* channel, bit_reader_cxt* br, int bexBand) +{ + for (int i = 0; i < channel->BexValueCount; i++) + { + const int dataLength = BexDataLengths[channel->BexMode][bexBand][i]; + channel->BexValues[i] = read_int(br, dataLength); + } +} + +at9_status ReadExtensionParams(block* block, bit_reader_cxt* br) +{ + int bexBand = 0; + if (block->BandExtensionEnabled) + { + bexBand = BexGroupInfo[block->QuantizationUnitCount - 13].band_count; + if (block->BlockType == Stereo) + { + BexReadHeader(&block->Channels[1], br, bexBand); + } + else + { + br->position += 1; + } + } + block->HasExtensionData = read_int(br, 1); + + if (!block->HasExtensionData) return ERR_SUCCESS; + if (!block->BandExtensionEnabled) + { + block->BexMode = read_int(br, 2); + block->BexDataLength = read_int(br, 5); + br->position += block->BexDataLength; + return ERR_SUCCESS; + } + + BexReadHeader(&block->Channels[0], br, bexBand); + + block->BexDataLength = read_int(br, 5); + if (block->BexDataLength <= 0) return ERR_SUCCESS; + const int bexDataEnd = br->position + block->BexDataLength; + + BexReadData(&block->Channels[0], br, bexBand); + + if (block->BlockType == Stereo) + { + BexReadData(&block->Channels[1], br, bexBand); + } + + // Make sure we didn't read too many bits + if (br->position > bexDataEnd) + { + return ERR_UNPACK_EXTENSION_DATA_INVALID; + } + + return ERR_SUCCESS; +} + +void UpdateCodedUnits(channel* channel) +{ + if (channel->Block->PrimaryChannelIndex == channel->ChannelIndex) + { + channel->CodedQuantUnits = channel->Block->QuantizationUnitCount; + } + else + { + channel->CodedQuantUnits = channel->Block->StereoQuantizationUnit; + } +} + +void CalculateSpectrumCodebookIndex(channel* channel) +{ + memset(channel->CodebookSet, 0, sizeof(channel->CodebookSet)); + const int quantUnits = channel->CodedQuantUnits; + int* sf = channel->ScaleFactors; + + if (quantUnits <= 1) return; + if (channel->config->HighSampleRate) return; + + // Temporarily setting this value allows for simpler code by + // making the last value a non-special case. + const int originalScaleTmp = sf[quantUnits]; + sf[quantUnits] = sf[quantUnits - 1]; + + int avg = 0; + if (quantUnits > 12) + { + for (int i = 0; i < 12; i++) + { + avg += sf[i]; + } + avg = (avg + 6) / 12; + } + + for (int i = 8; i < quantUnits; i++) + { + const int prevSf = sf[i - 1]; + const int nextSf = sf[i + 1]; + const int minSf = min(prevSf, nextSf); + if (sf[i] - minSf >= 3 || sf[i] - prevSf + sf[i] - nextSf >= 3) + { + channel->CodebookSet[i] = 1; + } + } + + for (int i = 12; i < quantUnits; i++) + { + if (channel->CodebookSet[i] == 0) + { + const int minSf = min(sf[i - 1], sf[i + 1]); + if (sf[i] - minSf >= 2 && sf[i] >= avg - (QuantUnitToCoeffCount[i] == 16 ? 1 : 0)) + { + channel->CodebookSet[i] = 1; + } + } + } + + sf[quantUnits] = originalScaleTmp; +} + +at9_status ReadSpectra(channel* channel, bit_reader_cxt* br) +{ + int values[16]; + memset(channel->QuantizedSpectra, 0, sizeof(channel->QuantizedSpectra)); + const int maxHuffPrecision = MaxHuffPrecision[channel->config->HighSampleRate]; + + for (int i = 0; i < channel->CodedQuantUnits; i++) + { + const int subbandCount = QuantUnitToCoeffCount[i]; + const int precision = channel->Precisions[i] + 1; + if (precision <= maxHuffPrecision) + { + const HuffmanCodebook* huff = &HuffmanSpectrum[channel->CodebookSet[i]][precision][QuantUnitToCodebookIndex[i]]; + const int groupCount = subbandCount >> huff->ValueCountPower; + for (int j = 0; j < groupCount; j++) + { + values[j] = ReadHuffmanValue(huff, br, FALSE); + } + + DecodeHuffmanValues(channel->QuantizedSpectra, QuantUnitToCoeffIndex[i], subbandCount, huff, values); + } + else + { + const int subbandIndex = QuantUnitToCoeffIndex[i]; + for (int j = subbandIndex; j < QuantUnitToCoeffIndex[i + 1]; j++) + { + channel->QuantizedSpectra[j] = read_signed_int(br, precision); + } + } + } + + return ERR_SUCCESS; +} + +at9_status ReadSpectraFine(channel* channel, bit_reader_cxt* br) +{ + memset(channel->QuantizedSpectraFine, 0, sizeof(channel->QuantizedSpectraFine)); + + for (int i = 0; i < channel->CodedQuantUnits; i++) + { + if (channel->PrecisionsFine[i] > 0) + { + const int overflowBits = channel->PrecisionsFine[i] + 1; + const int startSubband = QuantUnitToCoeffIndex[i]; + const int endSubband = QuantUnitToCoeffIndex[i + 1]; + + for (int j = startSubband; j < endSubband; j++) + { + channel->QuantizedSpectraFine[j] = read_signed_int(br, overflowBits); + } + } + } + return ERR_SUCCESS; +} + +at9_status UnpackLfeBlock(block* block, bit_reader_cxt* br) +{ + channel* channel = &block->Channels[0]; + block->QuantizationUnitCount = 2; + + DecodeLfeScaleFactors(channel, br); + CalculateLfePrecision(channel); + channel->CodedQuantUnits = block->QuantizationUnitCount; + ReadLfeSpectra(channel, br); + + return ERR_SUCCESS; +} + +void DecodeLfeScaleFactors(channel* channel, bit_reader_cxt* br) +{ + memset(channel->ScaleFactors, 0, sizeof(channel->ScaleFactors)); + for (int i = 0; i < channel->Block->QuantizationUnitCount; i++) + { + channel->ScaleFactors[i] = read_int(br, 5); + } +} + +void CalculateLfePrecision(channel* channel) +{ + block* block = channel->Block; + const int precision = block->ReuseBandParams ? 8 : 4; + for (int i = 0; i < block->QuantizationUnitCount; i++) + { + channel->Precisions[i] = precision; + channel->PrecisionsFine[i] = 0; + } +} + +void ReadLfeSpectra(channel* channel, bit_reader_cxt* br) +{ + memset(channel->QuantizedSpectra, 0, sizeof(channel->QuantizedSpectra)); + + for (int i = 0; i < channel->CodedQuantUnits; i++) + { + if (channel->Precisions[i] <= 0) continue; + + const int precision = channel->Precisions[i] + 1; + for (int j = QuantUnitToCoeffIndex[i]; j < QuantUnitToCoeffIndex[i + 1]; j++) + { + channel->QuantizedSpectra[j] = read_signed_int(br, precision); + } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/unpack.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/unpack.h new file mode 100644 index 000000000..53a4c2b3d --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/unpack.h @@ -0,0 +1,23 @@ +#pragma once +#include "bit_reader.h" +#include "error_codes.h" +#include "structures.h" + +at9_status UnpackFrame(frame* frame, bit_reader_cxt* br); +at9_status UnpackBlock(block* block, bit_reader_cxt* br); +at9_status ReadBlockHeader(block* block, bit_reader_cxt* br); +at9_status UnpackStandardBlock(block* block, bit_reader_cxt* br); +at9_status ReadBandParams(block* block, bit_reader_cxt* br); +at9_status ReadGradientParams(block* block, bit_reader_cxt* br); +at9_status ReadStereoParams(block* block, bit_reader_cxt* br); +at9_status ReadExtensionParams(block* block, bit_reader_cxt* br); +void UpdateCodedUnits(channel* channel); +void CalculateSpectrumCodebookIndex(channel* channel); + +at9_status ReadSpectra(channel* channel, bit_reader_cxt* br); +at9_status ReadSpectraFine(channel* channel, bit_reader_cxt* br); + +at9_status UnpackLfeBlock(block* block, bit_reader_cxt* br); +void DecodeLfeScaleFactors(channel* channel, bit_reader_cxt* br); +void CalculateLfePrecision(channel* channel); +void ReadLfeSpectra(channel* channel, bit_reader_cxt* br); diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/utility.c b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/utility.c new file mode 100644 index 000000000..b440ce126 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/utility.c @@ -0,0 +1,30 @@ +#include "utility.h" +#include + +int max(int a, int b) { return a > b ? a : b; } +int min(int a, int b) { return a > b ? b : a; } + +unsigned int BitReverse32(unsigned int value, int bitCount) +{ + value = ((value & 0xaaaaaaaa) >> 1) | ((value & 0x55555555) << 1); + value = ((value & 0xcccccccc) >> 2) | ((value & 0x33333333) << 2); + value = ((value & 0xf0f0f0f0) >> 4) | ((value & 0x0f0f0f0f) << 4); + value = ((value & 0xff00ff00) >> 8) | ((value & 0x00ff00ff) << 8); + value = (value >> 16) | (value << 16); + return value >> (32 - bitCount); +} + +int SignExtend32(int value, int bits) +{ + const int shift = 8 * sizeof(int) - bits; + return (value << shift) >> shift; +} + +short Clamp16(int value) +{ + if (value > SHRT_MAX) + return SHRT_MAX; + if (value < SHRT_MIN) + return SHRT_MIN; + return (short)value; +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/C/utility.h b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/utility.h new file mode 100644 index 000000000..489b54da4 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/C/utility.h @@ -0,0 +1,15 @@ +#pragma once + +#define FALSE 0 +#define TRUE 1 +#define NULL 0 + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +int max(int a, int b); +int min(int a, int b); +unsigned int BitReverse32(unsigned int value, int bitCount); +int SignExtend32(int value, int bits); +short Clamp16(int value); diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9.sln b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9.sln new file mode 100644 index 000000000..5310f9132 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9.sln @@ -0,0 +1,42 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2003 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibAtrac9", "LibAtrac9\LibAtrac9.csproj", "{2414DAA9-779C-4E7E-A97F-4DE09B22B88F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Debug|ARM.ActiveCfg = Debug|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Debug|ARM.Build.0 = Debug|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Debug|x64.ActiveCfg = Debug|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Debug|x64.Build.0 = Debug|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Debug|x86.ActiveCfg = Debug|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Debug|x86.Build.0 = Debug|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Release|Any CPU.Build.0 = Release|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Release|ARM.ActiveCfg = Release|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Release|ARM.Build.0 = Release|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Release|x64.ActiveCfg = Release|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Release|x64.Build.0 = Release|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Release|x86.ActiveCfg = Release|Any CPU + {2414DAA9-779C-4E7E-A97F-4DE09B22B88F}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2AFD09F0-D995-47ED-AA86-FFA93824A514} + EndGlobalSection +EndGlobal diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Config.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Config.cs new file mode 100644 index 000000000..8d1e4357d --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Config.cs @@ -0,0 +1,119 @@ +using System.IO; +using LibAtrac9.Utilities; + +namespace LibAtrac9 +{ + /// + /// Stores the configuration data needed to decode or encode an ATRAC9 stream. + /// + public class Atrac9Config + { + /// + /// The 4-byte ATRAC9 configuration data. + /// + public byte[] ConfigData { get; } + + /// + /// A 4-bit value specifying one of 16 sample rates. + /// + public int SampleRateIndex { get; } + /// + /// A 3-bit value specifying one of 6 substream channel mappings. + /// + public int ChannelConfigIndex { get; } + /// + /// An 11-bit value containing the average size of a single frame. + /// + public int FrameBytes { get; } + /// + /// A 2-bit value indicating how many frames are in each superframe. + /// + public int SuperframeIndex { get; } + + /// + /// The channel mapping used by the ATRAC9 stream. + /// + public ChannelConfig ChannelConfig { get; } + /// + /// The total number of channels in the ATRAC9 stream. + /// + public int ChannelCount { get; } + /// + /// The sample rate of the ATRAC9 stream. + /// + public int SampleRate { get; } + /// + /// Indicates whether the ATRAC9 stream has a of 8 or above. + /// + public bool HighSampleRate { get; } + + /// + /// The number of frames in each superframe. + /// + public int FramesPerSuperframe { get; } + /// + /// The number of samples in one frame as an exponent of 2. + /// = 2^. + /// + public int FrameSamplesPower { get; } + /// + /// The number of samples in one frame. + /// + public int FrameSamples { get; } + /// + /// The number of bytes in one superframe. + /// + public int SuperframeBytes { get; } + /// + /// The number of samples in one superframe. + /// + public int SuperframeSamples { get; } + + /// + /// Reads ATRAC9 configuration data and calculates the stream parameters from it. + /// + /// The processed ATRAC9 configuration. + public Atrac9Config(byte[] configData) + { + if (configData == null || configData.Length != 4) + { + throw new InvalidDataException("Config data must be 4 bytes long"); + } + + ReadConfigData(configData, out int a, out int b, out int c, out int d); + SampleRateIndex = a; + ChannelConfigIndex = b; + FrameBytes = c; + SuperframeIndex = d; + ConfigData = configData; + + FramesPerSuperframe = 1 << SuperframeIndex; + SuperframeBytes = FrameBytes << SuperframeIndex; + ChannelConfig = Tables.ChannelConfig[ChannelConfigIndex]; + + ChannelCount = ChannelConfig.ChannelCount; + SampleRate = Tables.SampleRates[SampleRateIndex]; + HighSampleRate = SampleRateIndex > 7; + FrameSamplesPower = Tables.SamplingRateIndexToFrameSamplesPower[SampleRateIndex]; + FrameSamples = 1 << FrameSamplesPower; + SuperframeSamples = FrameSamples * FramesPerSuperframe; + } + + private static void ReadConfigData(byte[] configData, out int sampleRateIndex, out int channelConfigIndex, out int frameBytes, out int superframeIndex) + { + var reader = new BitReader(configData); + + int header = reader.ReadInt(8); + sampleRateIndex = reader.ReadInt(4); + channelConfigIndex = reader.ReadInt(3); + int validationBit = reader.ReadInt(1); + frameBytes = reader.ReadInt(11) + 1; + superframeIndex = reader.ReadInt(2); + + if (header != 0xFE || validationBit != 0) + { + throw new InvalidDataException("ATRAC9 Config Data is invalid"); + } + } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Decoder.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Decoder.cs new file mode 100644 index 000000000..fb2fb344b --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Decoder.cs @@ -0,0 +1,127 @@ +using System; +using LibAtrac9.Utilities; + +namespace LibAtrac9 +{ + /// + /// Decodes an ATRAC9 stream into 16-bit PCM. + /// + public class Atrac9Decoder + { + /// + /// The config data for the current ATRAC9 stream. + /// + public Atrac9Config Config { get; private set; } + + private Frame Frame { get; set; } + private BitReader Reader { get; set; } + private bool _initialized; + + /// + /// Sets up the decoder to decode an ATRAC9 stream based on the information in . + /// + /// A 4-byte value containing information about the ATRAC9 stream. + public void Initialize(byte[] configData) + { + Config = new Atrac9Config(configData); + Frame = new Frame(Config); + Reader = new BitReader(null); + _initialized = true; + } + + /// + /// Decodes one superframe of ATRAC9 data. + /// + /// The ATRAC9 data to decode. The array must be at least + /// . bytes long. + /// A buffer that the decoded PCM data will be placed in. + /// The array must have dimensions of at least [.] + /// [.]. + public void Decode(byte[] atrac9Data, short[][] pcmOut) + { + if (!_initialized) throw new InvalidOperationException("Decoder must be initialized before decoding."); + + ValidateDecodeBuffers(atrac9Data, pcmOut); + Reader.SetBuffer(atrac9Data); + DecodeSuperFrame(pcmOut); + } + + private void ValidateDecodeBuffers(byte[] atrac9Buffer, short[][] pcmBuffer) + { + if (atrac9Buffer == null) throw new ArgumentNullException(nameof(atrac9Buffer)); + if (pcmBuffer == null) throw new ArgumentNullException(nameof(pcmBuffer)); + + if (atrac9Buffer.Length < Config.SuperframeBytes) + { + throw new ArgumentException("ATRAC9 buffer is too small"); + } + + if (pcmBuffer.Length < Config.ChannelCount) + { + throw new ArgumentException("PCM buffer is too small"); + } + + for (int i = 0; i < Config.ChannelCount; i++) + { + if (pcmBuffer[i]?.Length < Config.SuperframeSamples) + { + throw new ArgumentException("PCM buffer is too small"); + } + } + } + + private void DecodeSuperFrame(short[][] pcmOut) + { + for (int i = 0; i < Config.FramesPerSuperframe; i++) + { + Frame.FrameIndex = i; + DecodeFrame(Reader, Frame); + PcmFloatToShort(pcmOut, i * Config.FrameSamples); + Reader.AlignPosition(8); + } + } + + private void PcmFloatToShort(short[][] pcmOut, int start) + { + int endSample = start + Config.FrameSamples; + int channelNum = 0; + foreach (Block block in Frame.Blocks) + { + foreach (Channel channel in block.Channels) + { + double[] pcmSrc = channel.Pcm; + short[] pcmDest = pcmOut[channelNum++]; + for (int d = 0, s = start; s < endSample; d++, s++) + { + double sample = pcmSrc[d]; + // Not using Math.Round because it's ~20x slower on 64-bit + int roundedSample = (int)Math.Floor(sample + 0.5); + pcmDest[s] = Helpers.Clamp16(roundedSample); + } + } + } + } + + private static void DecodeFrame(BitReader reader, Frame frame) + { + Unpack.UnpackFrame(reader, frame); + + foreach (Block block in frame.Blocks) + { + Quantization.DequantizeSpectra(block); + Stereo.ApplyIntensityStereo(block); + Quantization.ScaleSpectrum(block); + BandExtension.ApplyBandExtension(block); + ImdctBlock(block); + } + } + + private static void ImdctBlock(Block block) + { + foreach (Channel channel in block.Channels) + { + channel.Mdct.RunImdct(channel.Spectra, channel.Pcm); + } + } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Rng.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Rng.cs new file mode 100644 index 000000000..072a61391 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Atrac9Rng.cs @@ -0,0 +1,33 @@ +namespace LibAtrac9 +{ + /// + /// An Xorshift RNG used by the ATRAC9 codec + /// + internal class Atrac9Rng + { + private ushort _stateA; + private ushort _stateB; + private ushort _stateC; + private ushort _stateD; + + public Atrac9Rng(ushort seed) + { + int startValue = 0x4D93 * (seed ^ (seed >> 14)); + + _stateA = (ushort)(3 - startValue); + _stateB = (ushort)(2 - startValue); + _stateC = (ushort)(1 - startValue); + _stateD = (ushort)(0 - startValue); + } + + public ushort Next() + { + ushort t = (ushort)(_stateD ^ (_stateD << 5)); + _stateD = _stateC; + _stateC = _stateB; + _stateB = _stateA; + _stateA = (ushort)(t ^ _stateA ^ ((t ^ (_stateA >> 5)) >> 4)); + return _stateA; + } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/BandExtension.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/BandExtension.cs new file mode 100644 index 000000000..297c79bfa --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/BandExtension.cs @@ -0,0 +1,372 @@ +using System; + +namespace LibAtrac9 +{ + internal static class BandExtension + { + public static void ApplyBandExtension(Block block) + { + if (!block.BandExtensionEnabled || !block.HasExtensionData) return; + + foreach (Channel channel in block.Channels) + { + ApplyBandExtensionChannel(channel); + } + } + + private static void ApplyBandExtensionChannel(Channel channel) + { + int groupAUnit = channel.Block.QuantizationUnitCount; + int[] scaleFactors = channel.ScaleFactors; + double[] spectra = channel.Spectra; + double[] scales = channel.BexScales; + int[] values = channel.BexValues; + + GetBexBandInfo(out int bandCount, out int groupBUnit, out int groupCUnit, groupAUnit); + int totalUnits = Math.Max(groupCUnit, 22); + + int groupABin = Tables.QuantUnitToCoeffIndex[groupAUnit]; + int groupBBin = Tables.QuantUnitToCoeffIndex[groupBUnit]; + int groupCBin = Tables.QuantUnitToCoeffIndex[groupCUnit]; + int totalBins = Tables.QuantUnitToCoeffIndex[totalUnits]; + + FillHighFrequencies(spectra, groupABin, groupBBin, groupCBin, totalBins); + + switch (channel.BexMode) + { + case 0: + int bexQuantUnits = totalUnits - groupAUnit; + + switch (bandCount) + { + case 3: + scales[0] = BexMode0Bands3[0][values[0]]; + scales[1] = BexMode0Bands3[1][values[0]]; + scales[2] = BexMode0Bands3[2][values[1]]; + scales[3] = BexMode0Bands3[3][values[2]]; + scales[4] = BexMode0Bands3[4][values[3]]; + break; + case 4: + scales[0] = BexMode0Bands4[0][values[0]]; + scales[1] = BexMode0Bands4[1][values[0]]; + scales[2] = BexMode0Bands4[2][values[1]]; + scales[3] = BexMode0Bands4[3][values[2]]; + scales[4] = BexMode0Bands4[4][values[3]]; + break; + case 5: + scales[0] = BexMode0Bands5[0][values[0]]; + scales[1] = BexMode0Bands5[1][values[1]]; + scales[2] = BexMode0Bands5[2][values[1]]; + break; + } + + scales[bexQuantUnits - 1] = Tables.SpectrumScale[scaleFactors[groupAUnit]]; + + AddNoiseToSpectrum(channel, Tables.QuantUnitToCoeffIndex[totalUnits - 1], + Tables.QuantUnitToCoeffCount[totalUnits - 1]); + ScaleBexQuantUnits(spectra, scales, groupAUnit, totalUnits); + break; + case 1: + for (int i = groupAUnit; i < totalUnits; i++) + { + scales[i - groupAUnit] = Tables.SpectrumScale[scaleFactors[i]]; + } + + AddNoiseToSpectrum(channel, groupABin, totalBins - groupABin); + ScaleBexQuantUnits(spectra, scales, groupAUnit, totalUnits); + break; + case 2: + double groupAScale2 = BexMode2Scale[values[0]]; + double groupBScale2 = BexMode2Scale[values[1]]; + + for (int i = groupABin; i < groupBBin; i++) + { + spectra[i] *= groupAScale2; + } + + for (int i = groupBBin; i < groupCBin; i++) + { + spectra[i] *= groupBScale2; + } + return; + case 3: + double rate = Math.Pow(2, BexMode3Rate[values[1]]); + double scale = BexMode3Initial[values[0]]; + for (int i = groupABin; i < totalBins; i++) + { + scale *= rate; + spectra[i] *= scale; + } + return; + case 4: + double mult = BexMode4Multiplier[values[0]]; + double groupAScale4 = 0.7079468 * mult; + double groupBScale4 = 0.5011902 * mult; + double groupCScale4 = 0.3548279 * mult; + + for (int i = groupABin; i < groupBBin; i++) + { + spectra[i] *= groupAScale4; + } + + for (int i = groupBBin; i < groupCBin; i++) + { + spectra[i] *= groupBScale4; + } + + for (int i = groupCBin; i < totalBins; i++) + { + spectra[i] *= groupCScale4; + } + return; + } + } + + private static void ScaleBexQuantUnits(double[] spectra, double[] scales, int startUnit, int totalUnits) + { + for (int i = startUnit; i < totalUnits; i++) + { + for (int k = Tables.QuantUnitToCoeffIndex[i]; k < Tables.QuantUnitToCoeffIndex[i + 1]; k++) + { + spectra[k] *= scales[i - startUnit]; + } + } + } + + private static void FillHighFrequencies(double[] spectra, int groupABin, int groupBBin, int groupCBin, int totalBins) + { + for (int i = 0; i < groupBBin - groupABin; i++) + { + spectra[groupABin + i] = spectra[groupABin - i - 1]; + } + + for (int i = 0; i < groupCBin - groupBBin; i++) + { + spectra[groupBBin + i] = spectra[groupBBin - i - 1]; + } + + for (int i = 0; i < totalBins - groupCBin; i++) + { + spectra[groupCBin + i] = spectra[groupCBin - i - 1]; + } + } + + private static void AddNoiseToSpectrum(Channel channel, int index, int count) + { + if (channel.Rng == null) + { + int[] sf = channel.ScaleFactors; + ushort seed = (ushort)(543 * (sf[8] + sf[12] + sf[15] + 1)); + channel.Rng = new Atrac9Rng(seed); + } + for (int i = 0; i < count; i++) + { + channel.Spectra[i + index] = channel.Rng.Next() / 65535.0 * 2.0 - 1.0; + } + } + + public static void GetBexBandInfo(out int bandCount, out int groupAUnit, out int groupBUnit, int quantUnits) + { + groupAUnit = BexGroupInfo[quantUnits - 13][0]; + groupBUnit = BexGroupInfo[quantUnits - 13][1]; + bandCount = BexGroupInfo[quantUnits - 13][2]; + } + + public static readonly byte[][] BexGroupInfo = + { + new byte[] {16, 21, 0}, + new byte[] {18, 22, 1}, + new byte[] {20, 22, 2}, + new byte[] {21, 22, 3}, + new byte[] {21, 22, 3}, + new byte[] {23, 24, 4}, + new byte[] {23, 24, 4}, + new byte[] {24, 24, 5} + }; + + // [mode][bands] + + public static readonly byte[][] BexEncodedValueCounts = + { + new byte[] {0, 0, 0, 4, 4, 2}, + new byte[] {0, 0, 0, 0, 0, 0}, + new byte[] {0, 0, 0, 2, 2, 1}, + new byte[] {0, 0, 0, 2, 2, 2}, + new byte[] {1, 1, 1, 0, 0, 0} + }; + + // [mode][bands][valueIndex] + + public static readonly byte[][][] BexDataLengths = + { + new[] { + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {5, 4, 3, 3}, + new byte[] {4, 4, 3, 4}, + new byte[] {4, 5, 0, 0} + }, new[] { + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0} + }, new[] { + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {6, 6, 0, 0}, + new byte[] {6, 6, 0, 0}, + new byte[] {6, 0, 0, 0} + }, new[] { + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {4, 4, 0, 0}, + new byte[] {4, 4, 0, 0}, + new byte[] {4, 4, 0, 0} + }, new[] { + new byte[] {3, 0, 0, 0}, + new byte[] {3, 0, 0, 0}, + new byte[] {3, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0} + } + }; + + public static readonly double[][] BexMode0Bands3 = + { + new[] { + 0.000000e+0, 1.988220e-1, 2.514343e-1, 2.960510e-1, + 3.263550e-1, 3.771362e-1, 3.786926e-1, 4.540405e-1, + 4.877625e-1, 5.262451e-1, 5.447083e-1, 5.737000e-1, + 6.212158e-1, 6.222839e-1, 6.560974e-1, 6.896667e-1, + 7.555542e-1, 7.677917e-1, 7.918091e-1, 7.971497e-1, + 8.188171e-1, 8.446045e-1, 9.790649e-1, 9.822083e-1, + 9.846191e-1, 9.859314e-1, 9.863586e-1, 9.863892e-1, + 9.873352e-1, 9.881287e-1, 9.898682e-1, 9.913330e-1 + }, new[] { + 0.000000e+0, 9.982910e-1, 7.592773e-2, 7.179565e-1, + 9.851379e-1, 5.340271e-1, 9.013672e-1, 6.349182e-1, + 7.226257e-1, 1.948547e-1, 7.628174e-1, 9.873657e-1, + 8.112183e-1, 2.715454e-1, 9.734192e-1, 1.443787e-1, + 4.640198e-1, 3.249207e-1, 3.790894e-1, 8.276367e-2, + 5.954590e-1, 2.864380e-1, 9.806824e-1, 7.929077e-1, + 6.292114e-1, 4.887085e-1, 2.905273e-1, 1.301880e-1, + 3.140869e-1, 5.482483e-1, 4.210815e-1, 1.182861e-1 + }, new[] { + 0.000000e+0, 3.155518e-2, 8.581543e-2, 1.364746e-1, + 1.858826e-1, 2.368469e-1, 2.888184e-1, 3.432617e-1, + 4.012451e-1, 4.623108e-1, 5.271301e-1, 5.954895e-1, + 6.681213e-1, 7.448425e-1, 8.245239e-1, 9.097290e-1 + }, new[] { + 0.000000e+0, 4.418945e-2, 1.303711e-1, 2.273560e-1, + 3.395996e-1, 4.735718e-1, 6.267090e-1, 8.003845e-1 + }, new[] { + 0.000000e+0, 2.804565e-2, 9.683228e-2, 1.849976e-1, + 3.005981e-1, 4.470520e-1, 6.168518e-1, 8.007813e-1 + } + }; + + public static readonly double[][] BexMode0Bands4 = + { + new[] { + 0.000000e+0, 2.708740e-1, 3.479614e-1, 3.578186e-1, + 5.083618e-1, 5.299072e-1, 5.819092e-1, 6.381836e-1, + 7.276917e-1, 7.595520e-1, 7.878723e-1, 9.707336e-1, + 9.713135e-1, 9.736023e-1, 9.759827e-1, 9.832458e-1 + }, new[] { + 0.000000e+0, 2.330627e-1, 5.891418e-1, 7.170410e-1, + 2.036438e-1, 1.613464e-1, 6.668701e-1, 9.481201e-1, + 9.769897e-1, 5.111694e-1, 3.522644e-1, 8.209534e-1, + 2.933960e-1, 9.757690e-1, 5.289917e-1, 4.372253e-1 + }, new[] { + 0.000000e+0, 4.360962e-2, 1.056519e-1, 1.590576e-1, + 2.078857e-1, 2.572937e-1, 3.082581e-1, 3.616028e-1, + 4.191589e-1, 4.792175e-1, 5.438538e-1, 6.125183e-1, + 6.841125e-1, 7.589417e-1, 8.365173e-1, 9.148254e-1 + }, new[] { + 0.000000e+0, 4.074097e-2, 1.164551e-1, 2.077026e-1, + 3.184509e-1, 4.532166e-1, 6.124268e-1, 7.932129e-1 + }, new[] { + 0.000000e+0, 8.880615e-3, 2.932739e-2, 5.593872e-2, + 8.825684e-2, 1.259155e-1, 1.721497e-1, 2.270813e-1, + 2.901611e-1, 3.579712e-1, 4.334106e-1, 5.147095e-1, + 6.023254e-1, 6.956177e-1, 7.952881e-1, 8.977356e-1 + } + }; + + public static readonly double[][] BexMode0Bands5 = + { + new[] { + 0.000000e+0, 7.379150e-2, 1.806335e-1, 2.687073e-1, + 3.407898e-1, 4.047546e-1, 4.621887e-1, 5.168762e-1, + 5.703125e-1, 6.237488e-1, 6.763611e-1, 7.288208e-1, + 7.808533e-1, 8.337708e-1, 8.874512e-1, 9.418030e-1 + }, new[] { + 0.000000e+0, 7.980347e-2, 1.615295e-1, 1.665649e-1, + 1.822205e-1, 2.185669e-1, 2.292175e-1, 2.456665e-1, + 2.666321e-1, 3.306580e-1, 3.330688e-1, 3.765259e-1, + 4.085083e-1, 4.400024e-1, 4.407654e-1, 4.817505e-1, + 4.924011e-1, 5.320740e-1, 5.893860e-1, 6.131287e-1, + 6.212463e-1, 6.278076e-1, 6.308899e-1, 7.660828e-1, + 7.850647e-1, 7.910461e-1, 7.929382e-1, 8.038330e-1, + 9.834900e-1, 9.846191e-1, 9.852295e-1, 9.862671e-1 + }, new[] { + 0.000000e+0, 6.084290e-1, 3.672791e-1, 3.151855e-1, + 1.488953e-1, 2.571716e-1, 5.103455e-1, 3.311157e-1, + 5.426025e-2, 4.254456e-1, 7.998352e-1, 7.873230e-1, + 5.418701e-1, 2.925110e-1, 8.468628e-2, 1.410522e-1, + 9.819641e-1, 9.609070e-1, 3.530884e-2, 9.729004e-2, + 5.758362e-1, 9.941711e-1, 7.215576e-1, 7.183228e-1, + 2.028809e-1, 9.588623e-2, 2.032166e-1, 1.338806e-1, + 5.003357e-1, 1.874390e-1, 9.804993e-1, 1.107788e-1 + } + }; + + public static readonly double[] BexMode2Scale = + { + 4.272461e-4, 1.312256e-3, 2.441406e-3, 3.692627e-3, + 4.913330e-3, 6.134033e-3, 7.507324e-3, 8.972168e-3, + 1.049805e-2, 1.223755e-2, 1.406860e-2, 1.599121e-2, + 1.800537e-2, 2.026367e-2, 2.264404e-2, 2.517700e-2, + 2.792358e-2, 3.073120e-2, 3.344727e-2, 3.631592e-2, + 3.952026e-2, 4.275513e-2, 4.608154e-2, 4.968262e-2, + 5.355835e-2, 5.783081e-2, 6.195068e-2, 6.677246e-2, + 7.196045e-2, 7.745361e-2, 8.319092e-2, 8.993530e-2, + 9.759521e-2, 1.056213e-1, 1.138916e-1, 1.236267e-1, + 1.348267e-1, 1.470337e-1, 1.603394e-1, 1.755676e-1, + 1.905823e-1, 2.071228e-1, 2.245178e-1, 2.444153e-1, + 2.658997e-1, 2.897644e-1, 3.146057e-1, 3.450012e-1, + 3.766174e-1, 4.122620e-1, 4.505615e-1, 4.893799e-1, + 5.305481e-1, 5.731201e-1, 6.157837e-1, 6.580811e-1, + 6.985168e-1, 7.435303e-1, 7.865906e-1, 8.302612e-1, + 8.718567e-1, 9.125671e-1, 9.575806e-1, 9.996643e-1 + }; + + public static readonly double[] BexMode3Initial = + { + 3.491211e-1, 5.371094e-1, 6.782227e-1, 7.910156e-1, + 9.057617e-1, 1.024902e+0, 1.156250e+0, 1.290527e+0, + 1.458984e+0, 1.664551e+0, 1.929688e+0, 2.278320e+0, + 2.831543e+0, 3.659180e+0, 5.257813e+0, 8.373047e+0 + }; + + public static readonly double[] BexMode3Rate = + { + -2.913818e-1, -2.541504e-1, -1.664429e-1, -1.476440e-1, + -1.342163e-1, -1.220703e-1, -1.117554e-1, -1.026611e-1, + -9.436035e-2, -8.483887e-2, -7.476807e-2, -6.304932e-2, + -4.492188e-2, -2.447510e-2, +1.831055e-4, +4.174805e-2 + }; + + public static readonly double[] BexMode4Multiplier = + { + 3.610229e-2, 1.260681e-1, 2.227478e-1, 3.338318e-1, + 4.662170e-1, 6.221313e-1, 7.989197e-1, 9.939575e-1 + }; + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/BitAllocation.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/BitAllocation.cs new file mode 100644 index 000000000..1775b32d5 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/BitAllocation.cs @@ -0,0 +1,140 @@ +using System; + +namespace LibAtrac9 +{ + internal static class BitAllocation + { + public static void CreateGradient(Block block) + { + int valueCount = block.GradientEndValue - block.GradientStartValue; + int unitCount = block.GradientEndUnit - block.GradientStartUnit; + + for (int i = 0; i < block.GradientEndUnit; i++) + { + block.Gradient[i] = block.GradientStartValue; + } + + for (int i = block.GradientEndUnit; i <= block.QuantizationUnitCount; i++) + { + block.Gradient[i] = block.GradientEndValue; + } + if (unitCount <= 0) return; + if (valueCount == 0) return; + + byte[] curve = Tables.GradientCurves[unitCount - 1]; + if (valueCount <= 0) + { + double scale = (-valueCount - 1) / 31.0; + int baseVal = block.GradientStartValue - 1; + for (int i = block.GradientStartUnit; i < block.GradientEndUnit; i++) + { + block.Gradient[i] = baseVal - (int)(curve[i - block.GradientStartUnit] * scale); + } + } + else + { + double scale = (valueCount - 1) / 31.0; + int baseVal = block.GradientStartValue + 1; + for (int i = block.GradientStartUnit; i < block.GradientEndUnit; i++) + { + block.Gradient[i] = baseVal + (int)(curve[i - block.GradientStartUnit] * scale); + } + } + } + + public static void CalculateMask(Channel channel) + { + Array.Clear(channel.PrecisionMask, 0, channel.PrecisionMask.Length); + for (int i = 1; i < channel.Block.QuantizationUnitCount; i++) + { + int delta = channel.ScaleFactors[i] - channel.ScaleFactors[i - 1]; + if (delta > 1) + { + channel.PrecisionMask[i] += Math.Min(delta - 1, 5); + } + else if (delta < -1) + { + channel.PrecisionMask[i - 1] += Math.Min(delta * -1 - 1, 5); + } + } + } + + public static void CalculatePrecisions(Channel channel) + { + Block block = channel.Block; + + if (block.GradientMode != 0) + { + for (int i = 0; i < block.QuantizationUnitCount; i++) + { + channel.Precisions[i] = channel.ScaleFactors[i] + channel.PrecisionMask[i] - block.Gradient[i]; + if (channel.Precisions[i] > 0) + { + switch (block.GradientMode) + { + case 1: + channel.Precisions[i] /= 2; + break; + case 2: + channel.Precisions[i] = 3 * channel.Precisions[i] / 8; + break; + case 3: + channel.Precisions[i] /= 4; + break; + } + } + } + } + else + { + for (int i = 0; i < block.QuantizationUnitCount; i++) + { + channel.Precisions[i] = channel.ScaleFactors[i] - block.Gradient[i]; + } + } + + for (int i = 0; i < block.QuantizationUnitCount; i++) + { + if (channel.Precisions[i] < 1) + { + channel.Precisions[i] = 1; + } + } + + for (int i = 0; i < block.GradientBoundary; i++) + { + channel.Precisions[i]++; + } + + for (int i = 0; i < block.QuantizationUnitCount; i++) + { + channel.PrecisionsFine[i] = 0; + if (channel.Precisions[i] > 15) + { + channel.PrecisionsFine[i] = channel.Precisions[i] - 15; + channel.Precisions[i] = 15; + } + } + } + + public static byte[][] GenerateGradientCurves() + { + byte[] main = + { + 01, 01, 01, 01, 02, 02, 02, 02, 03, 03, 03, 04, 04, 05, 05, 06, 07, 08, 09, 10, 11, 12, 13, 15, + 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 27, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30 + }; + var curves = new byte[main.Length][]; + + for (int length = 1; length <= main.Length; length++) + { + curves[length - 1] = new byte[length]; + for (int i = 0; i < length; i++) + { + curves[length - 1][i] = main[i * main.Length / length]; + } + } + return curves; + } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Block.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Block.cs new file mode 100644 index 000000000..fc5d0db24 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Block.cs @@ -0,0 +1,91 @@ +namespace LibAtrac9 +{ + internal class Block + { + public Atrac9Config Config { get; } + public BlockType BlockType { get; } + public int BlockIndex { get; } + public Frame Frame { get; } + + public Channel[] Channels { get; } + public int ChannelCount { get; } + + public bool FirstInSuperframe { get; set; } + public bool ReuseBandParams { get; set; } + + public int BandCount { get; set; } + public int StereoBand { get; set; } + public int ExtensionBand { get; set; } + public int QuantizationUnitCount { get; set; } + public int StereoQuantizationUnit { get; set; } + public int ExtensionUnit { get; set; } + public int QuantizationUnitsPrev { get; set; } + + public int[] Gradient { get; } = new int[31]; + public int GradientMode { get; set; } + public int GradientStartUnit { get; set; } + public int GradientStartValue { get; set; } + public int GradientEndUnit { get; set; } + public int GradientEndValue { get; set; } + public int GradientBoundary { get; set; } + + public int PrimaryChannelIndex { get; set; } + public int[] JointStereoSigns { get; } = new int[30]; + public bool HasJointStereoSigns { get; set; } + public Channel PrimaryChannel => Channels[PrimaryChannelIndex == 0 ? 0 : 1]; + public Channel SecondaryChannel => Channels[PrimaryChannelIndex == 0 ? 1 : 0]; + + public bool BandExtensionEnabled { get; set; } + public bool HasExtensionData { get; set; } + public int BexDataLength { get; set; } + public int BexMode { get; set; } + + public Block(Frame parentFrame, int blockIndex) + { + Frame = parentFrame; + BlockIndex = blockIndex; + Config = parentFrame.Config; + BlockType = Config.ChannelConfig.BlockTypes[blockIndex]; + ChannelCount = BlockTypeToChannelCount(BlockType); + Channels = new Channel[ChannelCount]; + for (int i = 0; i < ChannelCount; i++) + { + Channels[i] = new Channel(this, i); + } + } + + public static int BlockTypeToChannelCount(BlockType blockType) + { + switch (blockType) + { + case BlockType.Mono: + return 1; + case BlockType.Stereo: + return 2; + case BlockType.LFE: + return 1; + default: + return 0; + } + } + } + + /// + /// An ATRAC9 block (substream) type + /// + public enum BlockType + { + /// + /// Mono ATRAC9 block + /// + Mono = 0, + /// + /// Stereo ATRAC9 block + /// + Stereo = 1, + /// + /// Low-frequency effects ATRAC9 block + /// + LFE = 2 + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Channel.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Channel.cs new file mode 100644 index 000000000..4b77f6a98 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Channel.cs @@ -0,0 +1,48 @@ +using LibAtrac9.Utilities; + +namespace LibAtrac9 +{ + internal class Channel + { + public Atrac9Config Config { get; } + public int ChannelIndex { get; } + public bool IsPrimary => Block.PrimaryChannelIndex == ChannelIndex; + public Block Block { get; } + public Mdct Mdct { get; } + + public double[] Pcm { get; } = new double[256]; + public double[] Spectra { get; } = new double[256]; + + public int CodedQuantUnits { get; set; } + public int ScaleFactorCodingMode { get; set; } + public int[] ScaleFactors { get; } = new int[31]; + public int[] ScaleFactorsPrev { get; } = new int[31]; + + public int[] Precisions { get; } = new int[30]; + public int[] PrecisionsFine { get; } = new int[30]; + public int[] PrecisionMask { get; } = new int[30]; + + public int[] SpectraValuesBuffer { get; } = new int[16]; + public int[] CodebookSet { get; } = new int[30]; + + public int[] QuantizedSpectra { get; } = new int[256]; + public int[] QuantizedSpectraFine { get; } = new int[256]; + + public int BexMode { get; set; } + public int BexValueCount { get; set; } + public int[] BexValues { get; } = new int[4]; + public double[] BexScales { get; } = new double[6]; + public Atrac9Rng Rng { get; set; } + + public Channel(Block parentBlock, int channelIndex) + { + Block = parentBlock; + ChannelIndex = channelIndex; + Config = parentBlock.Config; + Mdct = new Mdct(Config.FrameSamplesPower, Tables.ImdctWindow[Config.FrameSamplesPower - 6]); + } + + public void UpdateCodedUnits() => + CodedQuantUnits = IsPrimary ? Block.QuantizationUnitCount : Block.StereoQuantizationUnit; + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/ChannelConfig.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/ChannelConfig.cs new file mode 100644 index 000000000..6854c7fee --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/ChannelConfig.cs @@ -0,0 +1,33 @@ +namespace LibAtrac9 +{ + /// + /// Describes the channel mapping for an ATRAC9 stream + /// + public class ChannelConfig + { + internal ChannelConfig(params BlockType[] blockTypes) + { + BlockCount = blockTypes.Length; + BlockTypes = blockTypes; + foreach (BlockType type in blockTypes) + { + ChannelCount += Block.BlockTypeToChannelCount(type); + } + } + + /// + /// The number of blocks or substreams in the ATRAC9 stream + /// + public int BlockCount { get; } + + /// + /// The type of each block or substream in the ATRAC9 stream + /// + public BlockType[] BlockTypes { get; } + + /// + /// The number of channels in the ATRAC9 stream + /// + public int ChannelCount { get; } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Frame.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Frame.cs new file mode 100644 index 000000000..46feb1bbb --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Frame.cs @@ -0,0 +1,20 @@ +namespace LibAtrac9 +{ + internal class Frame + { + public Atrac9Config Config { get; } + public int FrameIndex { get; set; } + public Block[] Blocks { get; } + + public Frame(Atrac9Config config) + { + Config = config; + Blocks = new Block[config.ChannelConfig.BlockCount]; + + for (int i = 0; i < config.ChannelConfig.BlockCount; i++) + { + Blocks[i] = new Block(this, i); + } + } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/HuffmanCodebook.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/HuffmanCodebook.cs new file mode 100644 index 000000000..8a900b54c --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/HuffmanCodebook.cs @@ -0,0 +1,62 @@ +using System; +using LibAtrac9.Utilities; + +namespace LibAtrac9 +{ + internal class HuffmanCodebook + { + public HuffmanCodebook(short[] codes, byte[] bits, byte valueCountPower) + { + Codes = codes; + Bits = bits; + if (Codes == null || Bits == null) return; + + ValueCount = 1 << valueCountPower; + ValueCountPower = valueCountPower; + ValueBits = Helpers.Log2(codes.Length) >> valueCountPower; + ValueMax = 1 << ValueBits; + + int max = 0; + foreach (byte bitSize in bits) + { + max = Math.Max(max, bitSize); + } + + MaxBitSize = max; + Lookup = CreateLookupTable(); + } + + private byte[] CreateLookupTable() + { + if (Codes == null || Bits == null) return null; + + int tableSize = 1 << MaxBitSize; + var dest = new byte[tableSize]; + + for (int i = 0; i < Bits.Length; i++) + { + if (Bits[i] == 0) continue; + int unusedBits = MaxBitSize - Bits[i]; + + int start = Codes[i] << unusedBits; + int length = 1 << unusedBits; + int end = start + length; + + for (int j = start; j < end; j++) + { + dest[j] = (byte)i; + } + } + return dest; + } + + public short[] Codes { get; } + public byte[] Bits { get; } + public byte[] Lookup { get; } + public int ValueCount { get; } + public int ValueCountPower { get; } + public int ValueBits { get; } + public int ValueMax { get; } + public int MaxBitSize { get; } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/HuffmanCodebooks.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/HuffmanCodebooks.cs new file mode 100644 index 000000000..8c350d098 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/HuffmanCodebooks.cs @@ -0,0 +1,1352 @@ +namespace LibAtrac9 +{ + internal static class HuffmanCodebooks + { + public static HuffmanCodebook[][] GenerateHuffmanCodebooks(short[][][] codes, byte[][][] bits, byte[][] groupCounts) + { + var tables = new HuffmanCodebook[bits.Length][]; + for (int i = 0; i < tables.Length; i++) + { + if (codes[i] != null) + { + tables[i] = GenerateHuffmanCodebooks(codes[i], bits[i], groupCounts[i]); + } + } + return tables; + } + + public static HuffmanCodebook[] GenerateHuffmanCodebooks(short[][] codes, byte[][] bits, byte[] groupCounts) + { + var tables = new HuffmanCodebook[bits.Length]; + for (int i = 0; i < tables.Length; i++) + { + if (codes[i] != null) + { + tables[i] = new HuffmanCodebook(codes[i], bits[i], groupCounts[i]); + } + } + return tables; + } + + // For scale factor table names, {letter}{number} correspond to the signedness and word length + private static readonly byte[] ScaleFactorsA1Bits = + { + 1, 1 + }; + + private static readonly short[] ScaleFactorsA1Codes = + { + 0x00, 0x01 + }; + + private static readonly byte[] ScaleFactorsA2Bits = + { + 1, 3, 3, 2 + }; + + private static readonly short[] ScaleFactorsA2Codes = + { + 0x00, 0x06, 0x07, 0x02 + }; + + private static readonly byte[] ScaleFactorsA3Bits = + { + 2, 2, 4, 6, 6, 5, 3, 2 + }; + + private static readonly short[] ScaleFactorsA3Codes = + { + 0x00, 0x01, 0x0E, 0x3E, 0x3F, 0x1E, 0x06, 0x02 + }; + + private static readonly byte[] ScaleFactorsA4Bits = + { + 2, 2, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 6, 5, 4, 2 + }; + + private static readonly short[] ScaleFactorsA4Codes = + { + 0x01, 0x02, 0x00, 0x06, 0x0F, 0x13, 0x23, 0x24, 0x25, 0x22, 0x21, 0x20, 0x0E, 0x05, 0x01, 0x03 + }; + + private static readonly byte[] ScaleFactorsA5Bits = + { + 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 6, 5, 5, 4, 3 + }; + + private static readonly short[] ScaleFactorsA5Codes = + { + 0x02, 0x01, 0x07, 0x0D, 0x0C, 0x18, 0x1B, 0x21, 0x3F, 0x6A, 0x6B, 0x68, 0x73, 0x79, 0x7C, 0x7D, + 0x7A, 0x7B, 0x78, 0x72, 0x44, 0x45, 0x47, 0x46, 0x69, 0x38, 0x20, 0x1D, 0x19, 0x09, 0x05, 0x00 + }; + + private static readonly byte[] ScaleFactorsA6Bits = + { + 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 4, 4, 4 + }; + + private static readonly short[] ScaleFactorsA6Codes = + { + 0x00, 0x01, 0x04, 0x05, 0x12, 0x13, 0x2E, 0x2F, 0x30, 0x66, 0x67, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, + 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, + 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, + 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x68, 0x69, 0x6A, 0x31, 0x32, 0x14, 0x15, 0x16, 0x06, 0x07, 0x08 + }; + + private static readonly byte[] ScaleFactorsB2Bits = + { + 1, 2, 0, 2 + }; + + private static readonly short[] ScaleFactorsB2Codes = + { + 0x00, 0x03, 0x00, 0x02 + }; + + private static readonly byte[] ScaleFactorsB3Bits = + { + 1, 3, 5, 6, 0, 6, 4, 2 + }; + + private static readonly short[] ScaleFactorsB3Codes = + { + 0x01, 0x00, 0x04, 0x0B, 0x00, 0x0A, 0x03, 0x01 + }; + + private static readonly byte[] ScaleFactorsB4Bits = + { + 1, 3, 4, 5, 5, 7, 8, 8, 0, 8, 8, 7, 6, 6, 4, 3 + }; + + private static readonly short[] ScaleFactorsB4Codes = + { + 0x01, 0x01, 0x04, 0x0E, 0x0F, 0x2C, 0x5A, 0x5D, 0x00, 0x5C, 0x5B, 0x2F, 0x15, 0x14, 0x06, 0x00 + }; + + private static readonly byte[] ScaleFactorsB5Bits = + { + 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 6, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 3 + }; + + private static readonly short[] ScaleFactorsB5Codes = + { + 0x00, 0x05, 0x07, 0x0C, 0x04, 0x02, 0x03, 0x05, 0x09, 0x10, 0x23, 0x33, 0x36, 0x6E, 0x60, 0x65, + 0x62, 0x61, 0x63, 0x64, 0x6F, 0x6D, 0x6C, 0x6B, 0x6A, 0x68, 0x69, 0x45, 0x44, 0x37, 0x1A, 0x07 + }; + + // For spectrum table names, {letter}{number}{number} correspond to the + // codebook set, word length, and band group + private static readonly byte[] SpectrumA21Bits = + { + 0, 3, 0, 3, 3, 3, 0, 3, 0, 0, 0, 0, 3, 3, 0, 3 + }; + + private static readonly short[] SpectrumA21Codes = + { + 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x06 + }; + + private static readonly byte[] SpectrumA22Bits = + { + 0, 4, 0, 4, 5, 6, 0, 6, 0, 0, 0, 0, 5, 6, 0, 6, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 6, 7, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 6, 7, 0, 7, + 5, 6, 0, 6, 7, 7, 0, 7, 0, 0, 0, 0, 6, 7, 0, 7, + 6, 7, 0, 7, 7, 8, 0, 8, 0, 0, 0, 0, 7, 8, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 7, 0, 7, 7, 8, 0, 8, 0, 0, 0, 0, 7, 7, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 7, 7, 0, 7, + 6, 7, 0, 7, 7, 8, 0, 7, 0, 0, 0, 0, 7, 8, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 7, 0, 7, 7, 7, 0, 8, 0, 0, 0, 0, 7, 8, 0, 8 + }; + + private static readonly short[] SpectrumA22Codes = + { + 0x00, 0x02, 0x00, 0x03, 0x10, 0x3C, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x11, 0x3E, 0x00, 0x3D, + 0x0E, 0x00, 0x00, 0x39, 0x18, 0x26, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x24, 0x00, 0x6D, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x38, 0x00, 0x01, 0x1A, 0x6C, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x19, 0x74, 0x00, 0x27, + 0x16, 0x14, 0x00, 0x17, 0x76, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x35, 0x64, 0x00, 0x6F, + 0x26, 0x04, 0x00, 0x63, 0x22, 0xA2, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x67, 0xA0, 0x00, 0x0D, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2B, 0x52, 0x00, 0x0B, 0x20, 0x92, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x61, 0x0E, 0x00, 0x95, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x17, 0x16, 0x00, 0x15, 0x34, 0x6E, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x77, 0x08, 0x00, 0x07, + 0x2A, 0x0A, 0x00, 0x53, 0x60, 0x94, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x21, 0x90, 0x00, 0x93, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x62, 0x00, 0x05, 0x66, 0x0C, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x23, 0x96, 0x00, 0xA3 + }; + + private static readonly byte[] SpectrumA23Bits = + { + 3, 4, 0, 4, 5, 6, 0, 6, 0, 0, 0, 0, 5, 6, 0, 6, + 5, 7, 0, 6, 6, 8, 0, 7, 0, 0, 0, 0, 6, 8, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 7, 6, 7, 0, 8, 0, 0, 0, 0, 6, 7, 0, 8, + 5, 6, 0, 6, 7, 8, 0, 8, 0, 0, 0, 0, 6, 7, 0, 7, + 6, 8, 0, 7, 8, 9, 0, 9, 0, 0, 0, 0, 7, 9, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 8, 0, 8, 8, 9, 0, 9, 0, 0, 0, 0, 7, 8, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 7, 8, 0, 8, + 6, 8, 0, 8, 7, 9, 0, 8, 0, 0, 0, 0, 8, 9, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 7, 0, 8, 7, 8, 0, 9, 0, 0, 0, 0, 8, 9, 0, 9 + }; + + private static readonly short[] SpectrumA23Codes = + { + 0x006, 0x002, 0x000, 0x003, 0x016, 0x01E, 0x000, 0x021, 0x000, 0x000, 0x000, 0x000, + 0x017, 0x020, 0x000, 0x01F, 0x01C, 0x054, 0x000, 0x027, 0x010, 0x0A6, 0x000, 0x027, + 0x000, 0x000, 0x000, 0x000, 0x015, 0x0A4, 0x000, 0x02D, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01D, 0x026, 0x000, 0x055, 0x014, 0x02C, 0x000, 0x0A5, 0x000, 0x000, 0x000, 0x000, + 0x011, 0x026, 0x000, 0x0A7, 0x01E, 0x000, 0x000, 0x003, 0x04A, 0x074, 0x000, 0x071, + 0x000, 0x000, 0x000, 0x000, 0x023, 0x00A, 0x000, 0x009, 0x018, 0x072, 0x000, 0x00D, + 0x0A2, 0x15A, 0x000, 0x123, 0x000, 0x000, 0x000, 0x000, 0x00F, 0x158, 0x000, 0x05D, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x01B, 0x0AE, 0x000, 0x077, 0x092, 0x140, 0x000, 0x121, + 0x000, 0x000, 0x000, 0x000, 0x025, 0x05E, 0x000, 0x143, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01F, 0x002, 0x000, 0x001, 0x022, 0x008, 0x000, 0x00B, 0x000, 0x000, 0x000, 0x000, + 0x04B, 0x070, 0x000, 0x075, 0x01A, 0x076, 0x000, 0x0AF, 0x024, 0x142, 0x000, 0x05F, + 0x000, 0x000, 0x000, 0x000, 0x093, 0x120, 0x000, 0x141, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x019, 0x00C, 0x000, 0x073, 0x00E, 0x05C, 0x000, 0x159, 0x000, 0x000, 0x000, 0x000, + 0x0A3, 0x122, 0x000, 0x15B + }; + + private static readonly byte[] SpectrumA24Bits = + { + 02, 04, 00, 04, 05, 06, 00, 06, 00, 00, 00, 00, 05, 06, 00, 06, + 05, 07, 00, 06, 06, 08, 00, 08, 00, 00, 00, 00, 06, 08, 00, 08, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 05, 06, 00, 07, 06, 08, 00, 08, 00, 00, 00, 00, 06, 08, 00, 08, + 05, 07, 00, 07, 07, 09, 00, 09, 00, 00, 00, 00, 06, 08, 00, 08, + 06, 09, 00, 08, 08, 10, 00, 10, 00, 00, 00, 00, 08, 10, 00, 09, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 06, 08, 00, 09, 09, 10, 00, 10, 00, 00, 00, 00, 08, 09, 00, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 05, 07, 00, 07, 06, 08, 00, 08, 00, 00, 00, 00, 07, 09, 00, 09, + 06, 09, 00, 08, 08, 10, 00, 09, 00, 00, 00, 00, 09, 10, 00, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 06, 08, 00, 09, 08, 09, 00, 10, 00, 00, 00, 00, 08, 10, 00, 10 + }; + + private static readonly short[] SpectrumA24Codes = + { + 0x002, 0x002, 0x000, 0x003, 0x01E, 0x010, 0x000, 0x013, 0x000, 0x000, 0x000, 0x000, + 0x01F, 0x012, 0x000, 0x011, 0x01A, 0x030, 0x000, 0x01B, 0x000, 0x064, 0x000, 0x0C1, + 0x000, 0x000, 0x000, 0x000, 0x003, 0x052, 0x000, 0x07D, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01B, 0x01A, 0x000, 0x031, 0x002, 0x07C, 0x000, 0x053, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x0C0, 0x000, 0x065, 0x01C, 0x062, 0x000, 0x065, 0x02A, 0x198, 0x000, 0x19B, + 0x000, 0x000, 0x000, 0x000, 0x017, 0x078, 0x000, 0x07B, 0x004, 0x0FE, 0x000, 0x077, + 0x050, 0x33A, 0x000, 0x1F9, 0x000, 0x000, 0x000, 0x000, 0x073, 0x338, 0x000, 0x0E1, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x007, 0x066, 0x000, 0x187, 0x19E, 0x308, 0x000, 0x30B, + 0x000, 0x000, 0x000, 0x000, 0x075, 0x0E2, 0x000, 0x1FB, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01D, 0x064, 0x000, 0x063, 0x016, 0x07A, 0x000, 0x079, 0x000, 0x000, 0x000, 0x000, + 0x02B, 0x19A, 0x000, 0x199, 0x006, 0x186, 0x000, 0x067, 0x074, 0x1FA, 0x000, 0x0E3, + 0x000, 0x000, 0x000, 0x000, 0x19F, 0x30A, 0x000, 0x309, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x005, 0x076, 0x000, 0x0FF, 0x072, 0x0E0, 0x000, 0x339, 0x000, 0x000, 0x000, 0x000, + 0x051, 0x1F8, 0x000, 0x33B + }; + + private static readonly byte[] SpectrumA31Bits = + { + 0, 0, 4, 5, 0, 5, 4, 0, 0, 0, 5, 5, 0, 5, 5, 0, + 5, 5, 6, 6, 0, 6, 5, 5, 5, 6, 6, 7, 0, 7, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 6, 7, 0, 7, 6, 6, + 5, 5, 5, 6, 0, 6, 6, 5, 0, 0, 5, 5, 0, 5, 5, 0 + }; + + private static readonly short[] SpectrumA31Codes = + { + 0x00, 0x00, 0x02, 0x18, 0x00, 0x19, 0x03, 0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x09, 0x15, 0x00, + 0x1A, 0x0A, 0x3E, 0x2C, 0x00, 0x2F, 0x01, 0x0D, 0x0E, 0x38, 0x20, 0x78, 0x00, 0x7B, 0x23, 0x3B, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x3A, 0x22, 0x7A, 0x00, 0x79, 0x21, 0x39, + 0x1B, 0x0C, 0x00, 0x2E, 0x00, 0x2D, 0x3F, 0x0B, 0x00, 0x00, 0x14, 0x08, 0x00, 0x03, 0x13, 0x00 + }; + + private static readonly byte[] SpectrumA32Bits = + { + 4, 5, 5, 6, 0, 6, 5, 5, 5, 6, 5, 6, 0, 6, 5, 5, + 5, 5, 6, 7, 0, 7, 6, 5, 6, 6, 7, 7, 0, 7, 7, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 7, 7, 0, 7, 7, 6, + 5, 5, 6, 7, 0, 7, 6, 5, 5, 5, 5, 6, 0, 6, 5, 6 + }; + + private static readonly short[] SpectrumA32Codes = + { + 0x0D, 0x18, 0x16, 0x3A, 0x00, 0x3B, 0x17, 0x19, 0x12, 0x3E, 0x08, 0x1C, 0x00, 0x1B, 0x07, 0x01, + 0x10, 0x02, 0x28, 0x78, 0x00, 0x7B, 0x1F, 0x05, 0x2A, 0x16, 0x72, 0x2A, 0x00, 0x29, 0x71, 0x19, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x18, 0x70, 0x28, 0x00, 0x2B, 0x73, 0x17, + 0x11, 0x04, 0x1E, 0x7A, 0x00, 0x79, 0x29, 0x03, 0x13, 0x00, 0x06, 0x1A, 0x00, 0x1D, 0x09, 0x3F + }; + + private static readonly byte[] SpectrumA33Bits = + { + 3, 4, 5, 6, 0, 6, 5, 4, 4, 5, 6, 7, 0, 7, 6, 5, + 5, 6, 6, 7, 0, 7, 6, 6, 6, 7, 8, 8, 0, 8, 8, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 8, 0, 8, 8, 7, + 5, 6, 6, 7, 0, 7, 6, 6, 4, 5, 6, 7, 0, 7, 6, 5 + }; + + private static readonly short[] SpectrumA33Codes = + { + 0x05, 0x06, 0x10, 0x08, 0x00, 0x09, 0x11, 0x07, 0x04, 0x12, 0x3E, 0x6A, 0x00, 0x6D, 0x3D, 0x19, + 0x06, 0x3A, 0x06, 0x02, 0x00, 0x01, 0x05, 0x39, 0x02, 0x16, 0xDC, 0x2A, 0x00, 0x29, 0xDF, 0x69, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x68, 0xDE, 0x28, 0x00, 0x2B, 0xDD, 0x17, + 0x07, 0x38, 0x04, 0x00, 0x00, 0x03, 0x07, 0x3B, 0x05, 0x18, 0x3C, 0x6C, 0x00, 0x6B, 0x3F, 0x13 + }; + + private static readonly byte[] SpectrumA34Bits = + { + 02, 04, 05, 07, 00, 07, 05, 04, 04, 05, 06, 08, 00, 08, 06, 05, + 05, 06, 07, 08, 00, 08, 07, 06, 07, 08, 08, 10, 00, 10, 09, 08, + 00, 00, 00, 00, 00, 00, 00, 00, 07, 08, 09, 10, 00, 10, 08, 08, + 05, 06, 07, 08, 00, 08, 07, 06, 04, 05, 06, 08, 00, 08, 06, 05 + }; + + private static readonly short[] SpectrumA34Codes = + { + 0x000, 0x00A, 0x00A, 0x034, 0x000, 0x035, 0x00B, 0x00B, 0x008, 0x01C, 0x032, 0x0DA, + 0x000, 0x0DD, 0x035, 0x01F, 0x008, 0x01E, 0x03A, 0x06C, 0x000, 0x063, 0x039, 0x031, + 0x032, 0x06E, 0x060, 0x37A, 0x000, 0x379, 0x1BF, 0x0D9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x033, 0x0D8, 0x1BE, 0x378, 0x000, 0x37B, 0x061, 0x06F, + 0x009, 0x030, 0x038, 0x062, 0x000, 0x06D, 0x03B, 0x01F, 0x009, 0x01E, 0x034, 0x0DC, + 0x000, 0x0DB, 0x033, 0x01D + }; + + private static readonly byte[] SpectrumA41Bits = + { + 0, 0, 0, 0, 6, 6, 7, 7, 0, 7, 7, 6, 6, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 7, 0, 7, 7, 7, 6, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 8, 0, 8, 7, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 8, 8, 0, 8, 8, 7, 7, 0, 0, 0, + 7, 7, 7, 8, 7, 8, 8, 8, 0, 8, 8, 8, 7, 8, 7, 7, + 7, 7, 7, 7, 8, 8, 8, 9, 0, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 8, 8, 8, 8, 9, 9, 0, 9, 8, 8, 8, 8, 8, 7, + 8, 8, 8, 8, 8, 9, 9, 9, 0, 9, 9, 9, 8, 8, 8, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 9, 9, 9, 0, 9, 9, 9, 8, 8, 8, 8, + 7, 7, 8, 8, 8, 8, 8, 9, 0, 9, 9, 8, 8, 8, 8, 7, + 7, 7, 7, 7, 8, 8, 8, 8, 0, 9, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 8, 7, 8, 8, 8, 0, 8, 8, 8, 7, 8, 7, 7, + 0, 0, 0, 0, 7, 7, 8, 8, 0, 8, 8, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 8, 0, 8, 7, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 6, 7, 7, 7, 0, 7, 7, 7, 7, 0, 0, 0 + }; + + private static readonly short[] SpectrumA41Codes = + { + 0x000, 0x000, 0x000, 0x000, 0x018, 0x00E, 0x05E, 0x028, 0x000, 0x029, 0x05F, 0x00F, + 0x019, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x076, 0x06E, 0x03E, 0x004, + 0x000, 0x017, 0x045, 0x07B, 0x013, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x04A, 0x048, 0x010, 0x0CE, 0x000, 0x0E1, 0x023, 0x055, 0x053, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x008, 0x018, 0x0D6, 0x09E, 0x000, 0x09D, 0x0E5, 0x02B, + 0x01B, 0x000, 0x000, 0x000, 0x07C, 0x05C, 0x038, 0x0FC, 0x002, 0x0D2, 0x09A, 0x05C, + 0x000, 0x06B, 0x0A3, 0x0D9, 0x00F, 0x0FF, 0x03D, 0x061, 0x074, 0x056, 0x036, 0x000, + 0x0CC, 0x08C, 0x058, 0x1E2, 0x000, 0x00F, 0x05F, 0x0A1, 0x0D5, 0x00D, 0x03B, 0x059, + 0x040, 0x014, 0x0DA, 0x0B6, 0x084, 0x040, 0x1E0, 0x196, 0x000, 0x1A1, 0x00D, 0x043, + 0x087, 0x0C7, 0x0E3, 0x00B, 0x0F2, 0x0C4, 0x08E, 0x05A, 0x024, 0x1CC, 0x194, 0x168, + 0x000, 0x16B, 0x1A3, 0x1CF, 0x027, 0x069, 0x099, 0x0C9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x0F3, 0x0C8, 0x098, 0x068, 0x026, 0x1CE, 0x1A2, 0x16A, 0x000, 0x169, 0x195, 0x1CD, + 0x025, 0x05B, 0x08F, 0x0C5, 0x041, 0x00A, 0x0E2, 0x0C6, 0x086, 0x042, 0x00C, 0x1A0, + 0x000, 0x197, 0x1E1, 0x041, 0x085, 0x0B7, 0x0DB, 0x015, 0x075, 0x058, 0x03A, 0x00C, + 0x0D4, 0x0A0, 0x05E, 0x00E, 0x000, 0x1E3, 0x059, 0x08D, 0x0CD, 0x001, 0x037, 0x057, + 0x07D, 0x060, 0x03C, 0x0FE, 0x00E, 0x0D8, 0x0A2, 0x06A, 0x000, 0x05D, 0x09B, 0x0D3, + 0x003, 0x0FD, 0x039, 0x05D, 0x000, 0x000, 0x000, 0x000, 0x01A, 0x02A, 0x0E4, 0x09C, + 0x000, 0x09F, 0x0D7, 0x019, 0x009, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x052, 0x054, 0x022, 0x0E0, 0x000, 0x0CF, 0x011, 0x049, 0x04B, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x012, 0x07A, 0x044, 0x016, 0x000, 0x005, 0x03F, 0x06F, + 0x077, 0x000, 0x000, 0x000 + }; + + private static readonly byte[] SpectrumA42Bits = + { + 05, 06, 07, 07, 07, 07, 08, 08, 00, 08, 08, 07, 07, 07, 07, 06, + 06, 07, 07, 08, 07, 07, 08, 08, 00, 08, 08, 07, 07, 08, 07, 07, + 07, 07, 08, 08, 07, 08, 08, 09, 00, 09, 08, 08, 07, 08, 08, 07, + 08, 08, 08, 08, 08, 08, 08, 09, 00, 09, 08, 08, 08, 08, 08, 08, + 07, 07, 07, 08, 08, 08, 09, 09, 00, 09, 09, 08, 08, 08, 07, 07, + 07, 07, 08, 08, 08, 09, 09, 09, 00, 09, 09, 09, 08, 08, 08, 07, + 08, 08, 08, 08, 09, 09, 09, 10, 00, 10, 09, 09, 09, 08, 08, 08, + 08, 08, 09, 09, 09, 09, 10, 10, 00, 10, 10, 09, 09, 09, 09, 09, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 08, 09, 09, 09, 09, 09, 10, 10, 00, 10, 10, 09, 09, 09, 09, 08, + 08, 08, 08, 08, 09, 09, 09, 10, 00, 10, 09, 09, 09, 08, 08, 08, + 07, 07, 08, 08, 08, 09, 09, 09, 00, 09, 09, 09, 08, 08, 08, 07, + 07, 07, 07, 08, 08, 08, 09, 09, 00, 09, 09, 08, 08, 08, 07, 07, + 08, 08, 08, 08, 08, 08, 08, 09, 00, 09, 08, 08, 08, 08, 08, 08, + 07, 07, 08, 08, 07, 08, 08, 09, 00, 09, 08, 08, 07, 08, 08, 07, + 06, 07, 07, 08, 07, 07, 08, 08, 00, 08, 08, 07, 07, 08, 07, 07 + }; + + private static readonly short[] SpectrumA42Codes = + { + 0x003, 0x018, 0x058, 0x000, 0x066, 0x03C, 0x0D6, 0x07C, 0x000, 0x07D, 0x0D7, 0x03D, + 0x067, 0x001, 0x059, 0x019, 0x002, 0x064, 0x036, 0x0DA, 0x04C, 0x01C, 0x0BE, 0x02C, + 0x000, 0x037, 0x0C5, 0x029, 0x04B, 0x0E7, 0x03B, 0x069, 0x044, 0x02E, 0x0FA, 0x092, + 0x020, 0x0F8, 0x086, 0x1FC, 0x000, 0x1E7, 0x07F, 0x0F5, 0x023, 0x0AD, 0x0FD, 0x02D, + 0x0F6, 0x0DC, 0x09C, 0x03E, 0x0F0, 0x0B6, 0x026, 0x186, 0x000, 0x18D, 0x02F, 0x0B5, + 0x0E1, 0x03D, 0x0AF, 0x0D9, 0x054, 0x040, 0x014, 0x0EC, 0x0BC, 0x054, 0x1C6, 0x108, + 0x000, 0x10B, 0x1C5, 0x069, 0x0B9, 0x0DF, 0x019, 0x047, 0x026, 0x008, 0x0E4, 0x0A2, + 0x056, 0x1DC, 0x142, 0x06A, 0x000, 0x091, 0x123, 0x1DF, 0x04B, 0x0A7, 0x0EB, 0x00B, + 0x0C0, 0x09E, 0x06A, 0x022, 0x1AA, 0x140, 0x092, 0x3CA, 0x000, 0x3A7, 0x04B, 0x121, + 0x18F, 0x007, 0x071, 0x0A5, 0x020, 0x004, 0x1A8, 0x174, 0x0E4, 0x068, 0x3A4, 0x2EE, + 0x000, 0x2ED, 0x3C9, 0x049, 0x0E7, 0x185, 0x1D1, 0x1FF, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x021, 0x1FE, 0x1D0, 0x184, 0x0E6, 0x048, 0x3C8, 0x2EC, 0x000, 0x2EF, 0x3A5, 0x069, + 0x0E5, 0x175, 0x1A9, 0x005, 0x0C1, 0x0A4, 0x070, 0x006, 0x18E, 0x120, 0x04A, 0x3A6, + 0x000, 0x3CB, 0x093, 0x141, 0x1AB, 0x023, 0x06B, 0x09F, 0x027, 0x00A, 0x0EA, 0x0A6, + 0x04A, 0x1DE, 0x122, 0x090, 0x000, 0x06B, 0x143, 0x1DD, 0x057, 0x0A3, 0x0E5, 0x009, + 0x055, 0x046, 0x018, 0x0DE, 0x0B8, 0x068, 0x1C4, 0x10A, 0x000, 0x109, 0x1C7, 0x055, + 0x0BD, 0x0ED, 0x015, 0x041, 0x0F7, 0x0D8, 0x0AE, 0x03C, 0x0E0, 0x0B4, 0x02E, 0x18C, + 0x000, 0x187, 0x027, 0x0B7, 0x0F1, 0x03F, 0x09D, 0x0DD, 0x045, 0x02C, 0x0FC, 0x0AC, + 0x022, 0x0F4, 0x07E, 0x1E6, 0x000, 0x1FD, 0x087, 0x0F9, 0x021, 0x093, 0x0FB, 0x02F, + 0x003, 0x068, 0x03A, 0x0E6, 0x04A, 0x028, 0x0C4, 0x036, 0x000, 0x02D, 0x0BF, 0x01D, + 0x04D, 0x0DB, 0x037, 0x065 + }; + + private static readonly byte[] SpectrumA43Bits = + { + 04, 06, 06, 07, 07, 08, 08, 09, 00, 09, 08, 08, 07, 07, 06, 06, + 05, 06, 07, 07, 07, 08, 08, 09, 00, 09, 08, 08, 07, 07, 07, 06, + 06, 07, 07, 07, 08, 08, 09, 09, 00, 09, 09, 08, 08, 07, 07, 07, + 07, 07, 07, 08, 08, 08, 09, 10, 00, 10, 09, 09, 08, 08, 07, 07, + 07, 07, 08, 08, 08, 09, 10, 10, 00, 10, 10, 09, 08, 08, 08, 07, + 08, 08, 08, 09, 09, 09, 10, 10, 00, 10, 10, 09, 09, 09, 08, 08, + 08, 09, 09, 09, 10, 10, 10, 10, 00, 10, 10, 10, 10, 09, 09, 09, + 09, 09, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 09, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 09, 09, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 09, + 08, 09, 09, 09, 10, 10, 10, 10, 00, 10, 10, 10, 10, 09, 09, 09, + 08, 08, 08, 09, 09, 09, 10, 10, 00, 10, 10, 09, 09, 09, 08, 08, + 07, 07, 08, 08, 08, 09, 10, 10, 00, 10, 10, 09, 08, 08, 08, 07, + 07, 07, 07, 08, 08, 09, 09, 10, 00, 10, 09, 08, 08, 08, 07, 07, + 06, 07, 07, 07, 08, 08, 09, 09, 00, 09, 09, 08, 08, 07, 07, 07, + 05, 06, 07, 07, 07, 08, 08, 09, 00, 09, 08, 08, 07, 07, 07, 06 + }; + + private static readonly short[] SpectrumA43Codes = + { + 0x002, 0x03E, 0x016, 0x060, 0x04E, 0x0DC, 0x04A, 0x130, 0x000, 0x131, 0x04B, 0x0DD, + 0x04F, 0x061, 0x017, 0x03F, 0x002, 0x02C, 0x076, 0x042, 0x034, 0x0CE, 0x002, 0x0E8, + 0x000, 0x0CF, 0x001, 0x0D1, 0x037, 0x045, 0x07B, 0x02F, 0x014, 0x072, 0x052, 0x01A, + 0x0E0, 0x080, 0x198, 0x01E, 0x000, 0x01D, 0x19B, 0x083, 0x0DF, 0x019, 0x055, 0x079, + 0x050, 0x03C, 0x004, 0x0C4, 0x096, 0x00C, 0x0EA, 0x34A, 0x000, 0x34F, 0x0ED, 0x1D7, + 0x095, 0x0AF, 0x003, 0x03F, 0x046, 0x026, 0x0D6, 0x092, 0x046, 0x15A, 0x3A8, 0x108, + 0x000, 0x10F, 0x3A3, 0x135, 0x039, 0x091, 0x0D9, 0x031, 0x0D4, 0x0CA, 0x072, 0x1C6, + 0x136, 0x090, 0x2B2, 0x104, 0x000, 0x103, 0x111, 0x08B, 0x133, 0x1D3, 0x071, 0x0C9, + 0x03E, 0x1B4, 0x18C, 0x0CC, 0x38A, 0x2B0, 0x106, 0x0F2, 0x000, 0x0EF, 0x101, 0x113, + 0x3A1, 0x0CB, 0x18F, 0x1B7, 0x0EE, 0x092, 0x388, 0x348, 0x10A, 0x0F4, 0x0F0, 0x0EA, + 0x000, 0x0E9, 0x0ED, 0x0F7, 0x10D, 0x34D, 0x3AB, 0x0C9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x0EF, 0x0C8, 0x3AA, 0x34C, 0x10C, 0x0F6, 0x0EC, 0x0E8, 0x000, 0x0EB, 0x0F1, 0x0F5, + 0x10B, 0x349, 0x389, 0x093, 0x03F, 0x1B6, 0x18E, 0x0CA, 0x3A0, 0x112, 0x100, 0x0EE, + 0x000, 0x0F3, 0x107, 0x2B1, 0x38B, 0x0CD, 0x18D, 0x1B5, 0x0D5, 0x0C8, 0x070, 0x1D2, + 0x132, 0x08A, 0x110, 0x102, 0x000, 0x105, 0x2B3, 0x091, 0x137, 0x1C7, 0x073, 0x0CB, + 0x047, 0x030, 0x0D8, 0x090, 0x038, 0x134, 0x3A2, 0x10E, 0x000, 0x109, 0x3A9, 0x15B, + 0x047, 0x093, 0x0D7, 0x027, 0x051, 0x03E, 0x002, 0x0AE, 0x094, 0x1D6, 0x0EC, 0x34E, + 0x000, 0x34B, 0x0EB, 0x00D, 0x097, 0x0C5, 0x005, 0x03D, 0x015, 0x078, 0x054, 0x018, + 0x0DE, 0x082, 0x19A, 0x01C, 0x000, 0x01F, 0x199, 0x081, 0x0E1, 0x01B, 0x053, 0x073, + 0x003, 0x02E, 0x07A, 0x044, 0x036, 0x0D0, 0x000, 0x0CE, 0x000, 0x0E9, 0x003, 0x0CF, + 0x035, 0x043, 0x077, 0x02D + }; + + private static readonly byte[] SpectrumA44Bits = + { + 04, 05, 06, 07, 07, 08, 09, 10, 00, 10, 09, 08, 07, 07, 06, 05, + 05, 06, 06, 07, 07, 08, 09, 10, 00, 10, 09, 08, 07, 07, 06, 06, + 06, 06, 07, 07, 08, 09, 10, 10, 00, 10, 10, 09, 08, 07, 07, 06, + 07, 07, 07, 08, 08, 09, 10, 10, 00, 10, 10, 09, 08, 08, 07, 07, + 07, 08, 08, 08, 09, 10, 10, 10, 00, 10, 10, 10, 09, 08, 08, 07, + 08, 08, 09, 09, 10, 10, 10, 10, 00, 10, 10, 10, 10, 09, 09, 08, + 09, 09, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 09, + 10, 10, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 10, 10, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 10, + 09, 09, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 09, + 08, 08, 09, 09, 10, 10, 10, 10, 00, 10, 10, 10, 10, 09, 09, 08, + 07, 07, 08, 08, 09, 10, 10, 10, 00, 10, 10, 10, 09, 08, 08, 08, + 07, 07, 07, 08, 08, 09, 10, 10, 00, 10, 10, 09, 08, 08, 07, 07, + 06, 06, 07, 07, 08, 09, 10, 10, 00, 10, 10, 09, 08, 07, 07, 06, + 05, 06, 06, 07, 07, 08, 09, 10, 00, 10, 09, 08, 07, 07, 06, 06 + }; + + private static readonly short[] SpectrumA44Codes = + { + 0x00A, 0x012, 0x030, 0x06E, 0x024, 0x074, 0x0EC, 0x07E, 0x000, 0x07F, 0x0ED, 0x075, + 0x025, 0x06F, 0x031, 0x013, 0x010, 0x03C, 0x018, 0x05A, 0x002, 0x046, 0x09E, 0x07C, + 0x000, 0x079, 0x0E5, 0x04D, 0x007, 0x065, 0x01B, 0x03F, 0x02E, 0x016, 0x072, 0x01A, + 0x0D6, 0x1C6, 0x3B4, 0x066, 0x000, 0x06B, 0x3B7, 0x1D9, 0x0D5, 0x021, 0x075, 0x015, + 0x06C, 0x03E, 0x01E, 0x0CC, 0x044, 0x0F2, 0x082, 0x05C, 0x000, 0x05F, 0x087, 0x0F5, + 0x031, 0x0CF, 0x017, 0x059, 0x01C, 0x0EE, 0x0D0, 0x024, 0x1C0, 0x08E, 0x06E, 0x048, + 0x000, 0x04D, 0x06D, 0x089, 0x0F7, 0x033, 0x0D3, 0x001, 0x070, 0x028, 0x1C2, 0x0F0, + 0x08A, 0x074, 0x054, 0x040, 0x000, 0x043, 0x053, 0x073, 0x099, 0x0EF, 0x1C5, 0x02B, + 0x0E6, 0x04E, 0x08C, 0x080, 0x068, 0x058, 0x046, 0x02A, 0x000, 0x029, 0x045, 0x051, + 0x065, 0x085, 0x09B, 0x09D, 0x07A, 0x076, 0x060, 0x056, 0x04E, 0x02C, 0x024, 0x022, + 0x000, 0x021, 0x027, 0x02F, 0x04B, 0x05B, 0x063, 0x071, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x07B, 0x070, 0x062, 0x05A, 0x04A, 0x02E, 0x026, 0x020, 0x000, 0x023, 0x025, 0x02D, + 0x04F, 0x057, 0x061, 0x077, 0x0E7, 0x09C, 0x09A, 0x084, 0x064, 0x050, 0x044, 0x028, + 0x000, 0x02B, 0x047, 0x059, 0x069, 0x081, 0x08D, 0x04F, 0x071, 0x02A, 0x1C4, 0x0EE, + 0x098, 0x072, 0x052, 0x042, 0x000, 0x041, 0x055, 0x075, 0x08B, 0x0F1, 0x1C3, 0x029, + 0x01D, 0x000, 0x0D2, 0x032, 0x0F6, 0x088, 0x06C, 0x04C, 0x000, 0x049, 0x06F, 0x08F, + 0x1C1, 0x025, 0x0D1, 0x0EF, 0x06D, 0x058, 0x016, 0x0CE, 0x030, 0x0F4, 0x086, 0x05E, + 0x000, 0x05D, 0x083, 0x0F3, 0x045, 0x0CD, 0x01F, 0x03F, 0x02F, 0x014, 0x074, 0x020, + 0x0D4, 0x1D8, 0x3B6, 0x06A, 0x000, 0x067, 0x3B5, 0x1C7, 0x0D7, 0x01B, 0x073, 0x017, + 0x011, 0x03E, 0x01A, 0x064, 0x006, 0x04C, 0x0E4, 0x078, 0x000, 0x07D, 0x09F, 0x047, + 0x003, 0x05B, 0x019, 0x03D + }; + + private static readonly byte[] SpectrumA51Bits = + { + 5, 5, 5, 5, 5, 6, 6, 6, 4, 4, 5, 5, 5, 5, 5, 5, + 0, 5, 5, 5, 5, 5, 5, 4, 4, 6, 6, 6, 5, 5, 5, 5 + }; + + private static readonly short[] SpectrumA51Codes = + { + 0x19, 0x16, 0x12, 0x0E, 0x06, 0x3A, 0x38, 0x30, 0x00, 0x04, 0x1E, 0x1A, 0x14, 0x10, 0x0C, 0x04, + 0x00, 0x05, 0x0D, 0x11, 0x15, 0x1B, 0x1F, 0x05, 0x01, 0x31, 0x39, 0x3B, 0x07, 0x0F, 0x13, 0x17 + }; + + private static readonly byte[] SpectrumA52Bits = + { + 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, + 0, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4 + }; + + private static readonly short[] SpectrumA52Codes = + { + 0x09, 0x04, 0x00, 0x1E, 0x1A, 0x14, 0x0C, 0x06, 0x18, 0x16, 0x0E, 0x04, 0x3A, 0x38, 0x22, 0x20, + 0x00, 0x21, 0x23, 0x39, 0x3B, 0x05, 0x0F, 0x17, 0x19, 0x07, 0x0D, 0x15, 0x1B, 0x1F, 0x01, 0x05 + }; + + private static readonly byte[] SpectrumA53Bits = + { + 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 7, + 0, 7, 7, 7, 7, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4 + }; + + private static readonly short[] SpectrumA53Codes = + { + 0x00, 0x0C, 0x08, 0x04, 0x1E, 0x16, 0x14, 0x06, 0x0C, 0x04, 0x38, 0x1E, 0x76, 0x74, 0x3A, 0x38, + 0x00, 0x39, 0x3B, 0x75, 0x77, 0x1F, 0x39, 0x05, 0x0D, 0x07, 0x15, 0x17, 0x1F, 0x05, 0x09, 0x0D + }; + + private static readonly byte[] SpectrumA54Bits = + { + 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, + 0, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4 + }; + + private static readonly short[] SpectrumA54Codes = + { + 0x02, 0x0E, 0x0A, 0x08, 0x02, 0x1A, 0x0E, 0x02, 0x00, 0x30, 0x18, 0x66, 0x36, 0x34, 0xCA, 0xC8, + 0x00, 0xC9, 0xCB, 0x35, 0x37, 0x67, 0x19, 0x31, 0x01, 0x03, 0x0F, 0x1B, 0x03, 0x09, 0x0B, 0x0F + }; + + private static readonly byte[] SpectrumA61Bits = + { + 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, + 5, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6 + }; + + private static readonly short[] SpectrumA61Codes = + { + 0x35, 0x30, 0x2A, 0x28, 0x24, 0x20, 0x18, 0x0E, 0x0C, 0x7E, 0x7C, 0x72, 0x70, 0x68, 0x5E, 0x5C, + 0x04, 0x0E, 0x08, 0x00, 0x3C, 0x3A, 0x36, 0x32, 0x2C, 0x26, 0x22, 0x1A, 0x16, 0x14, 0x06, 0x04, + 0x00, 0x05, 0x07, 0x15, 0x17, 0x1B, 0x23, 0x27, 0x2D, 0x33, 0x37, 0x3B, 0x3D, 0x01, 0x09, 0x0F, + 0x05, 0x5D, 0x5F, 0x69, 0x71, 0x73, 0x7D, 0x7F, 0x0D, 0x0F, 0x19, 0x21, 0x25, 0x29, 0x2B, 0x31 + }; + + private static readonly byte[] SpectrumA62Bits = + { + 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 0, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 + }; + + private static readonly short[] SpectrumA62Codes = + { + 0x14, 0x0E, 0x08, 0x04, 0x02, 0x3E, 0x3C, 0x38, 0x34, 0x30, 0x2A, 0x24, 0x1A, 0x18, 0x0E, 0x02, + 0x32, 0x36, 0x2C, 0x26, 0x20, 0x16, 0x0C, 0x00, 0x76, 0x74, 0x5E, 0x5C, 0x46, 0x44, 0x2A, 0x28, + 0x00, 0x29, 0x2B, 0x45, 0x47, 0x5D, 0x5F, 0x75, 0x77, 0x01, 0x0D, 0x17, 0x21, 0x27, 0x2D, 0x37, + 0x33, 0x03, 0x0F, 0x19, 0x1B, 0x25, 0x2B, 0x31, 0x35, 0x39, 0x3D, 0x3F, 0x03, 0x05, 0x09, 0x0F + }; + + private static readonly byte[] SpectrumA63Bits = + { + 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, + 0, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5 + }; + + private static readonly short[] SpectrumA63Codes = + { + 0x00, 0x1C, 0x18, 0x14, 0x10, 0x0A, 0x08, 0x02, 0x3E, 0x36, 0x2E, 0x2C, 0x24, 0x1C, 0x0E, 0x08, + 0x1E, 0x1A, 0x0C, 0x7A, 0x6A, 0x68, 0x4C, 0x32, 0x16, 0x14, 0xF2, 0xF0, 0x9E, 0x9C, 0x62, 0x60, + 0x00, 0x61, 0x63, 0x9D, 0x9F, 0xF1, 0xF3, 0x15, 0x17, 0x33, 0x4D, 0x69, 0x6B, 0x7B, 0x0D, 0x1B, + 0x1F, 0x09, 0x0F, 0x1D, 0x25, 0x2D, 0x2F, 0x37, 0x3F, 0x03, 0x09, 0x0B, 0x11, 0x15, 0x19, 0x1D + }; + + private static readonly byte[] SpectrumA64Bits = + { + 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, + 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, + 6, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4 + }; + + private static readonly short[] SpectrumA64Codes = + { + 0x006, 0x002, 0x01C, 0x01A, 0x016, 0x012, 0x00E, 0x00A, 0x002, 0x03E, 0x032, 0x02A, + 0x022, 0x020, 0x010, 0x07A, 0x000, 0x078, 0x060, 0x050, 0x024, 0x006, 0x0C6, 0x0C4, + 0x0A4, 0x04E, 0x00A, 0x008, 0x14E, 0x14C, 0x09A, 0x098, 0x000, 0x099, 0x09B, 0x14D, + 0x14F, 0x009, 0x00B, 0x04F, 0x0A5, 0x0C5, 0x0C7, 0x007, 0x025, 0x051, 0x061, 0x079, + 0x001, 0x07B, 0x011, 0x021, 0x023, 0x02B, 0x033, 0x03F, 0x003, 0x00B, 0x00F, 0x013, + 0x017, 0x01B, 0x01D, 0x003 + }; + + private static readonly byte[] SpectrumA71Bits = + { + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, + 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + }; + + private static readonly short[] SpectrumA71Codes = + { + 0x6C, 0x66, 0x62, 0x5C, 0x56, 0x50, 0x52, 0x4E, 0x48, 0x3E, 0x36, 0x34, 0x2A, 0x26, 0x1E, 0x16, + 0x0E, 0x08, 0x00, 0xF6, 0xF4, 0xEE, 0xEC, 0xE2, 0xE0, 0xDA, 0xD2, 0xD0, 0xBE, 0xBC, 0xB2, 0xB0, + 0x0C, 0x20, 0x1C, 0x16, 0x10, 0x08, 0x02, 0x7E, 0x7C, 0x78, 0x74, 0x72, 0x6E, 0x6A, 0x64, 0x60, + 0x5A, 0x54, 0x4C, 0x4A, 0x46, 0x44, 0x3C, 0x32, 0x30, 0x28, 0x24, 0x1C, 0x14, 0x0C, 0x0A, 0x02, + 0x00, 0x03, 0x0B, 0x0D, 0x15, 0x1D, 0x25, 0x29, 0x31, 0x33, 0x3D, 0x45, 0x47, 0x4B, 0x4D, 0x55, + 0x5B, 0x61, 0x65, 0x6B, 0x6F, 0x73, 0x75, 0x79, 0x7D, 0x7F, 0x03, 0x09, 0x11, 0x17, 0x1D, 0x21, + 0x0D, 0xB1, 0xB3, 0xBD, 0xBF, 0xD1, 0xD3, 0xDB, 0xE1, 0xE3, 0xED, 0xEF, 0xF5, 0xF7, 0x01, 0x09, + 0x0F, 0x17, 0x1F, 0x27, 0x2B, 0x35, 0x37, 0x3F, 0x49, 0x4F, 0x53, 0x51, 0x57, 0x5D, 0x63, 0x67 + }; + + private static readonly byte[] SpectrumA72Bits = + { + 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6 + }; + + private static readonly short[] SpectrumA72Codes = + { + 0x2A, 0x24, 0x1C, 0x18, 0x12, 0x0E, 0x0A, 0x06, 0x02, 0x7E, 0x7C, 0x7A, 0x76, 0x72, 0x70, 0x6A, + 0x68, 0x62, 0x5C, 0x5A, 0x52, 0x4E, 0x46, 0x42, 0x3C, 0x34, 0x2A, 0x28, 0x20, 0x12, 0x10, 0x08, + 0x66, 0x74, 0x6C, 0x64, 0x5E, 0x58, 0x50, 0x44, 0x40, 0x36, 0x2C, 0x22, 0x1A, 0x0A, 0x02, 0x00, + 0xF2, 0xF0, 0xDE, 0xDC, 0xC2, 0xC0, 0xAE, 0xAC, 0x9A, 0x98, 0x7E, 0x7C, 0x5E, 0x5C, 0x32, 0x30, + 0x00, 0x31, 0x33, 0x5D, 0x5F, 0x7D, 0x7F, 0x99, 0x9B, 0xAD, 0xAF, 0xC1, 0xC3, 0xDD, 0xDF, 0xF1, + 0xF3, 0x01, 0x03, 0x0B, 0x1B, 0x23, 0x2D, 0x37, 0x41, 0x45, 0x51, 0x59, 0x5F, 0x65, 0x6D, 0x75, + 0x67, 0x09, 0x11, 0x13, 0x21, 0x29, 0x2B, 0x35, 0x3D, 0x43, 0x47, 0x4F, 0x53, 0x5B, 0x5D, 0x63, + 0x69, 0x6B, 0x71, 0x73, 0x77, 0x7B, 0x7D, 0x7F, 0x03, 0x07, 0x0B, 0x0F, 0x13, 0x19, 0x1D, 0x25 + }; + + private static readonly byte[] SpectrumA73Bits = + { + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 + }; + + private static readonly short[] SpectrumA73Codes = + { + 0x003, 0x03E, 0x038, 0x034, 0x030, 0x02C, 0x028, 0x024, 0x020, 0x01C, 0x016, 0x014, + 0x00E, 0x00A, 0x004, 0x000, 0x07A, 0x076, 0x06E, 0x06C, 0x064, 0x05E, 0x056, 0x04E, + 0x04C, 0x044, 0x036, 0x030, 0x022, 0x018, 0x012, 0x004, 0x03C, 0x03E, 0x032, 0x024, + 0x020, 0x010, 0x0F2, 0x0F0, 0x0E8, 0x0CE, 0x0BA, 0x0B8, 0x0A8, 0x08C, 0x06A, 0x04E, + 0x04C, 0x034, 0x00E, 0x00C, 0x1D6, 0x1D4, 0x19A, 0x198, 0x156, 0x154, 0x11E, 0x11C, + 0x0D2, 0x0D0, 0x06E, 0x06C, 0x000, 0x06D, 0x06F, 0x0D1, 0x0D3, 0x11D, 0x11F, 0x155, + 0x157, 0x199, 0x19B, 0x1D5, 0x1D7, 0x00D, 0x00F, 0x035, 0x04D, 0x04F, 0x06B, 0x08D, + 0x0A9, 0x0B9, 0x0BB, 0x0CF, 0x0E9, 0x0F1, 0x0F3, 0x011, 0x021, 0x025, 0x033, 0x03F, + 0x03D, 0x005, 0x013, 0x019, 0x023, 0x031, 0x037, 0x045, 0x04D, 0x04F, 0x057, 0x05F, + 0x065, 0x06D, 0x06F, 0x077, 0x07B, 0x001, 0x005, 0x00B, 0x00F, 0x015, 0x017, 0x01D, + 0x021, 0x025, 0x029, 0x02D, 0x031, 0x035, 0x039, 0x03F + }; + + private static readonly byte[] SpectrumA74Bits = + { + 05, 05, 05, 05, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, + 06, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, 08, 08, + 07, 08, 08, 08, 08, 08, 08, 08, 08, 08, 08, 09, 09, 09, 09, 09, + 09, 09, 09, 09, 09, 09, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 00, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 09, 09, 09, 09, 09, + 09, 09, 09, 09, 09, 09, 08, 08, 08, 08, 08, 08, 08, 08, 08, 08, + 07, 08, 08, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, + 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 05, 05, 05 + }; + + private static readonly short[] SpectrumA74Codes = + { + 0x00D, 0x00A, 0x004, 0x000, 0x03A, 0x036, 0x032, 0x030, 0x02C, 0x028, 0x026, 0x022, + 0x01E, 0x018, 0x012, 0x00E, 0x006, 0x07E, 0x07A, 0x070, 0x06A, 0x05E, 0x056, 0x054, + 0x048, 0x040, 0x038, 0x022, 0x01A, 0x00A, 0x0F8, 0x0E6, 0x008, 0x0FA, 0x0F0, 0x0D2, + 0x0BA, 0x0B8, 0x094, 0x084, 0x074, 0x042, 0x032, 0x1E6, 0x1CA, 0x1C8, 0x1A2, 0x12E, + 0x10E, 0x10C, 0x0EC, 0x082, 0x062, 0x060, 0x3CA, 0x3C8, 0x342, 0x340, 0x25A, 0x258, + 0x1DE, 0x1DC, 0x102, 0x100, 0x000, 0x101, 0x103, 0x1DD, 0x1DF, 0x259, 0x25B, 0x341, + 0x343, 0x3C9, 0x3CB, 0x061, 0x063, 0x083, 0x0ED, 0x10D, 0x10F, 0x12F, 0x1A3, 0x1C9, + 0x1CB, 0x1E7, 0x033, 0x043, 0x075, 0x085, 0x095, 0x0B9, 0x0BB, 0x0D3, 0x0F1, 0x0FB, + 0x009, 0x0E7, 0x0F9, 0x00B, 0x01B, 0x023, 0x039, 0x041, 0x049, 0x055, 0x057, 0x05F, + 0x06B, 0x071, 0x07B, 0x07F, 0x007, 0x00F, 0x013, 0x019, 0x01F, 0x023, 0x027, 0x029, + 0x02D, 0x031, 0x033, 0x037, 0x03B, 0x001, 0x005, 0x00B + }; + + private static readonly byte[] SpectrumB22Bits = + { + 00, 04, 00, 04, 04, 05, 00, 05, 00, 00, 00, 00, 04, 05, 00, 05, + 04, 07, 00, 06, 06, 09, 00, 07, 00, 00, 00, 00, 06, 09, 00, 07, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 04, 06, 00, 07, 06, 07, 00, 09, 00, 00, 00, 00, 06, 07, 00, 09, + 04, 08, 00, 08, 08, 10, 00, 10, 00, 00, 00, 00, 06, 09, 00, 09, + 05, 10, 00, 09, 09, 10, 00, 10, 00, 00, 00, 00, 07, 10, 00, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 06, 09, 00, 10, 09, 10, 00, 10, 00, 00, 00, 00, 07, 10, 00, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 04, 08, 00, 08, 06, 09, 00, 09, 00, 00, 00, 00, 08, 10, 00, 10, + 06, 10, 00, 09, 07, 10, 00, 10, 00, 00, 00, 00, 09, 10, 00, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 05, 09, 00, 10, 07, 10, 00, 10, 00, 00, 00, 00, 09, 10, 00, 10 + }; + + private static readonly short[] SpectrumB22Codes = + { + 0x000, 0x00E, 0x000, 0x00F, 0x008, 0x006, 0x000, 0x00B, 0x000, 0x000, 0x000, 0x000, + 0x009, 0x00A, 0x000, 0x007, 0x006, 0x00A, 0x000, 0x029, 0x006, 0x158, 0x000, 0x023, + 0x000, 0x000, 0x000, 0x000, 0x013, 0x174, 0x000, 0x021, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x007, 0x028, 0x000, 0x00B, 0x012, 0x020, 0x000, 0x175, 0x000, 0x000, 0x000, 0x000, + 0x007, 0x022, 0x000, 0x159, 0x00C, 0x0BC, 0x000, 0x0BF, 0x022, 0x2B8, 0x000, 0x2BB, + 0x000, 0x000, 0x000, 0x000, 0x00B, 0x170, 0x000, 0x15B, 0x000, 0x04E, 0x000, 0x15F, + 0x042, 0x04A, 0x000, 0x041, 0x000, 0x000, 0x000, 0x000, 0x055, 0x044, 0x000, 0x04D, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x02D, 0x172, 0x000, 0x2ED, 0x040, 0x042, 0x000, 0x047, + 0x000, 0x000, 0x000, 0x000, 0x013, 0x2EE, 0x000, 0x049, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x00D, 0x0BE, 0x000, 0x0BD, 0x00A, 0x15A, 0x000, 0x171, 0x000, 0x000, 0x000, 0x000, + 0x023, 0x2BA, 0x000, 0x2B9, 0x02C, 0x2EC, 0x000, 0x173, 0x012, 0x048, 0x000, 0x2EF, + 0x000, 0x000, 0x000, 0x000, 0x041, 0x046, 0x000, 0x043, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x15E, 0x000, 0x04F, 0x054, 0x04C, 0x000, 0x045, 0x000, 0x000, 0x000, 0x000, + 0x043, 0x040, 0x000, 0x04B + }; + + private static readonly byte[] SpectrumB23Bits = + { + 02, 04, 00, 04, 04, 06, 00, 06, 00, 00, 00, 00, 04, 06, 00, 06, + 04, 09, 00, 07, 07, 09, 00, 08, 00, 00, 00, 00, 07, 09, 00, 08, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 04, 07, 00, 09, 07, 08, 00, 09, 00, 00, 00, 00, 07, 08, 00, 09, + 04, 08, 00, 08, 09, 10, 00, 10, 00, 00, 00, 00, 07, 10, 00, 10, + 07, 10, 00, 10, 10, 10, 00, 10, 00, 00, 00, 00, 09, 10, 00, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 07, 10, 00, 10, 10, 10, 00, 10, 00, 00, 00, 00, 08, 10, 00, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 04, 08, 00, 08, 07, 10, 00, 10, 00, 00, 00, 00, 09, 10, 00, 10, + 07, 10, 00, 10, 08, 10, 00, 10, 00, 00, 00, 00, 10, 10, 00, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 07, 10, 00, 10, 09, 10, 00, 10, 00, 00, 00, 00, 10, 10, 00, 10 + }; + + private static readonly short[] SpectrumB23Codes = + { + 0x003, 0x008, 0x000, 0x009, 0x002, 0x018, 0x000, 0x01B, 0x000, 0x000, 0x000, 0x000, + 0x003, 0x01A, 0x000, 0x019, 0x000, 0x17C, 0x000, 0x055, 0x056, 0x0E8, 0x000, 0x07D, + 0x000, 0x000, 0x000, 0x000, 0x059, 0x0F6, 0x000, 0x07F, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x054, 0x000, 0x17D, 0x058, 0x07E, 0x000, 0x0F7, 0x000, 0x000, 0x000, 0x000, + 0x057, 0x07C, 0x000, 0x0E9, 0x004, 0x0A2, 0x000, 0x0A1, 0x17A, 0x1DA, 0x000, 0x1D9, + 0x000, 0x000, 0x000, 0x000, 0x053, 0x1E8, 0x000, 0x2F3, 0x05C, 0x1D6, 0x000, 0x1E7, + 0x1EA, 0x1E2, 0x000, 0x1CF, 0x000, 0x000, 0x000, 0x000, 0x17F, 0x1CA, 0x000, 0x1DD, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x05B, 0x2F0, 0x000, 0x1DF, 0x1E4, 0x1CC, 0x000, 0x1D5, + 0x000, 0x000, 0x000, 0x000, 0x071, 0x1E0, 0x000, 0x1C9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x005, 0x0A0, 0x000, 0x0A3, 0x052, 0x2F2, 0x000, 0x1E9, 0x000, 0x000, 0x000, 0x000, + 0x17B, 0x1D8, 0x000, 0x1DB, 0x05A, 0x1DE, 0x000, 0x2F1, 0x070, 0x1C8, 0x000, 0x1E1, + 0x000, 0x000, 0x000, 0x000, 0x1E5, 0x1D4, 0x000, 0x1CD, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x05D, 0x1E6, 0x000, 0x1D7, 0x17E, 0x1DC, 0x000, 0x1CB, 0x000, 0x000, 0x000, 0x000, + 0x1EB, 0x1CE, 0x000, 0x1E3 + }; + + private static readonly byte[] SpectrumB24Bits = + { + 01, 04, 00, 04, 05, 07, 00, 07, 00, 00, 00, 00, 05, 07, 00, 07, + 05, 09, 00, 07, 08, 10, 00, 09, 00, 00, 00, 00, 07, 10, 00, 09, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 05, 07, 00, 09, 07, 09, 00, 10, 00, 00, 00, 00, 08, 09, 00, 10, + 05, 09, 00, 08, 09, 10, 00, 10, 00, 00, 00, 00, 07, 10, 00, 10, + 07, 10, 00, 10, 10, 10, 00, 10, 00, 00, 00, 00, 10, 10, 00, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 07, 10, 00, 10, 10, 10, 00, 10, 00, 00, 00, 00, 10, 10, 00, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 05, 08, 00, 09, 07, 10, 00, 10, 00, 00, 00, 00, 09, 10, 00, 10, + 07, 10, 00, 10, 10, 10, 00, 10, 00, 00, 00, 00, 10, 10, 00, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 07, 10, 00, 10, 10, 10, 00, 10, 00, 00, 00, 00, 10, 10, 00, 10 + }; + + private static readonly short[] SpectrumB24Codes = + { + 0x001, 0x000, 0x000, 0x001, 0x00A, 0x01C, 0x000, 0x033, 0x000, 0x000, 0x000, 0x000, + 0x00B, 0x032, 0x000, 0x01D, 0x008, 0x0D8, 0x000, 0x031, 0x06E, 0x0FA, 0x000, 0x0D7, + 0x000, 0x000, 0x000, 0x000, 0x011, 0x0F4, 0x000, 0x0D5, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x009, 0x030, 0x000, 0x0D9, 0x010, 0x0D4, 0x000, 0x0F5, 0x000, 0x000, 0x000, 0x000, + 0x06F, 0x0D6, 0x000, 0x0FB, 0x00E, 0x0DA, 0x000, 0x025, 0x0D2, 0x0D4, 0x000, 0x0DB, + 0x000, 0x000, 0x000, 0x000, 0x017, 0x0FE, 0x000, 0x0FD, 0x014, 0x0DC, 0x000, 0x0F9, + 0x0F2, 0x0D6, 0x000, 0x09B, 0x000, 0x000, 0x000, 0x000, 0x1A3, 0x09C, 0x000, 0x0D3, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x019, 0x0F6, 0x000, 0x0D9, 0x0F0, 0x09E, 0x000, 0x0D1, + 0x000, 0x000, 0x000, 0x000, 0x1A1, 0x0DE, 0x000, 0x099, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x00F, 0x024, 0x000, 0x0DB, 0x016, 0x0FC, 0x000, 0x0FF, 0x000, 0x000, 0x000, 0x000, + 0x0D3, 0x0DA, 0x000, 0x0D5, 0x018, 0x0D8, 0x000, 0x0F7, 0x1A0, 0x098, 0x000, 0x0DF, + 0x000, 0x000, 0x000, 0x000, 0x0F1, 0x0D0, 0x000, 0x09F, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x015, 0x0F8, 0x000, 0x0DD, 0x1A2, 0x0D2, 0x000, 0x09D, 0x000, 0x000, 0x000, 0x000, + 0x0F3, 0x09A, 0x000, 0x0D7 + }; + + private static readonly byte[] SpectrumB32Bits = + { + 2, 4, 5, 6, 0, 6, 5, 4, 5, 6, 6, 7, 0, 6, 5, 6, + 5, 6, 7, 7, 0, 8, 7, 6, 6, 7, 8, 9, 0, 9, 8, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 0, 9, 8, 7, + 5, 6, 7, 8, 0, 7, 7, 6, 5, 6, 5, 6, 0, 7, 6, 6 + }; + + private static readonly short[] SpectrumB32Codes = + { + 0x001, 0x002, 0x01E, 0x02A, 0x000, 0x02B, 0x01F, 0x003, 0x016, 0x020, 0x03A, 0x064, + 0x000, 0x005, 0x001, 0x023, 0x01A, 0x026, 0x070, 0x00C, 0x000, 0x0CF, 0x073, 0x031, + 0x024, 0x00E, 0x0CC, 0x146, 0x000, 0x145, 0x0A1, 0x053, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x025, 0x052, 0x0A0, 0x144, 0x000, 0x147, 0x0CD, 0x00F, + 0x01B, 0x030, 0x072, 0x0CE, 0x000, 0x00D, 0x071, 0x027, 0x017, 0x022, 0x000, 0x004, + 0x000, 0x065, 0x03B, 0x021 + }; + + private static readonly byte[] SpectrumB33Bits = + { + 02, 04, 05, 07, 00, 07, 05, 04, 04, 05, 06, 08, 00, 07, 06, 05, + 05, 06, 07, 09, 00, 08, 07, 06, 07, 08, 09, 10, 00, 10, 09, 08, + 00, 00, 00, 00, 00, 00, 00, 00, 07, 08, 09, 10, 00, 10, 09, 08, + 05, 06, 07, 08, 00, 09, 07, 06, 04, 05, 06, 07, 00, 08, 06, 05 + }; + + private static readonly short[] SpectrumB33Codes = + { + 0x003, 0x008, 0x014, 0x05E, 0x000, 0x05F, 0x015, 0x009, 0x004, 0x002, 0x01C, 0x0BA, + 0x000, 0x011, 0x01F, 0x001, 0x00C, 0x00C, 0x014, 0x166, 0x000, 0x02D, 0x013, 0x00F, + 0x05A, 0x0B0, 0x05E, 0x0B8, 0x000, 0x0BB, 0x165, 0x0B9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x05B, 0x0B8, 0x164, 0x0BA, 0x000, 0x0B9, 0x05F, 0x0B1, + 0x00D, 0x00E, 0x012, 0x02C, 0x000, 0x167, 0x015, 0x00D, 0x005, 0x000, 0x01E, 0x010, + 0x000, 0x0BB, 0x01D, 0x003 + }; + + private static readonly byte[] SpectrumB34Bits = + { + 01, 04, 06, 08, 00, 08, 06, 04, 04, 06, 07, 09, 00, 08, 07, 06, + 06, 07, 08, 10, 00, 10, 08, 07, 08, 09, 10, 10, 00, 10, 10, 09, + 00, 00, 00, 00, 00, 00, 00, 00, 08, 09, 10, 10, 00, 10, 10, 09, + 06, 07, 08, 10, 00, 10, 08, 07, 04, 06, 07, 08, 00, 09, 07, 06 + }; + + private static readonly short[] SpectrumB34Codes = + { + 0x000, 0x00A, 0x038, 0x0EE, 0x000, 0x0EF, 0x039, 0x00B, 0x008, 0x03C, 0x06E, 0x1D8, + 0x000, 0x0C1, 0x075, 0x03F, 0x032, 0x068, 0x0C4, 0x358, 0x000, 0x30F, 0x0C7, 0x06D, + 0x0D4, 0x1AE, 0x30C, 0x308, 0x000, 0x30B, 0x35B, 0x1DB, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x0D5, 0x1DA, 0x35A, 0x30A, 0x000, 0x309, 0x30D, 0x1AF, + 0x033, 0x06C, 0x0C6, 0x30E, 0x000, 0x359, 0x0C5, 0x069, 0x009, 0x03E, 0x074, 0x0C0, + 0x000, 0x1D9, 0x06F, 0x03D + }; + + private static readonly byte[] SpectrumB42Bits = + { + 04, 05, 06, 08, 06, 07, 08, 08, 00, 08, 08, 07, 06, 08, 06, 05, + 05, 06, 07, 08, 07, 07, 08, 09, 00, 08, 08, 07, 07, 08, 07, 06, + 07, 07, 08, 09, 07, 08, 09, 09, 00, 09, 09, 08, 07, 09, 08, 07, + 08, 09, 09, 10, 08, 08, 09, 10, 00, 10, 09, 08, 08, 10, 09, 08, + 06, 07, 08, 08, 09, 09, 10, 10, 00, 10, 10, 09, 09, 08, 08, 07, + 07, 07, 08, 09, 09, 10, 10, 10, 00, 10, 10, 10, 09, 09, 08, 07, + 08, 08, 09, 09, 10, 10, 10, 10, 00, 10, 10, 10, 10, 09, 09, 08, + 08, 09, 09, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 09, 09, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 08, 09, 09, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 09, 09, + 08, 08, 09, 09, 10, 10, 10, 10, 00, 10, 10, 10, 10, 09, 09, 08, + 07, 07, 08, 09, 09, 10, 10, 10, 00, 10, 10, 10, 09, 09, 08, 07, + 06, 07, 08, 08, 09, 09, 10, 10, 00, 10, 10, 09, 09, 08, 08, 07, + 08, 08, 09, 10, 08, 08, 09, 10, 00, 10, 09, 08, 08, 10, 09, 09, + 07, 07, 08, 09, 07, 08, 09, 09, 00, 09, 09, 08, 07, 09, 08, 07, + 05, 06, 07, 08, 07, 07, 08, 08, 00, 09, 08, 07, 07, 08, 07, 06 + }; + + private static readonly short[] SpectrumB42Codes = + { + 0x00E, 0x018, 0x010, 0x0F0, 0x024, 0x05A, 0x0F6, 0x078, 0x000, 0x079, 0x0F7, 0x05B, + 0x025, 0x0F1, 0x011, 0x019, 0x00C, 0x014, 0x01C, 0x036, 0x05C, 0x012, 0x09E, 0x1E4, + 0x000, 0x00B, 0x0A9, 0x03B, 0x05F, 0x071, 0x019, 0x017, 0x06E, 0x000, 0x03E, 0x114, + 0x002, 0x0B0, 0x1AA, 0x07A, 0x000, 0x099, 0x1E7, 0x0B3, 0x00B, 0x131, 0x07F, 0x00D, + 0x0D8, 0x1FE, 0x112, 0x22E, 0x086, 0x010, 0x134, 0x35C, 0x000, 0x35F, 0x133, 0x013, + 0x081, 0x22D, 0x119, 0x07B, 0x00A, 0x050, 0x0F8, 0x04E, 0x1B4, 0x154, 0x3EC, 0x0D2, + 0x000, 0x0D7, 0x3D7, 0x137, 0x1FD, 0x073, 0x0FD, 0x057, 0x052, 0x010, 0x08E, 0x1E8, + 0x11A, 0x3EE, 0x0F2, 0x03C, 0x000, 0x03F, 0x0F1, 0x3D5, 0x111, 0x1F5, 0x09D, 0x025, + 0x0D2, 0x082, 0x1A0, 0x0F8, 0x36E, 0x0D4, 0x072, 0x03A, 0x000, 0x027, 0x071, 0x07D, + 0x36D, 0x0FB, 0x1AD, 0x085, 0x00C, 0x1A8, 0x03C, 0x346, 0x0D0, 0x076, 0x024, 0x020, + 0x000, 0x023, 0x039, 0x075, 0x07F, 0x345, 0x09B, 0x157, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x00D, 0x156, 0x09A, 0x344, 0x07E, 0x074, 0x038, 0x022, 0x000, 0x021, 0x025, 0x077, + 0x0D1, 0x347, 0x03D, 0x1A9, 0x0D3, 0x084, 0x1AC, 0x0FA, 0x36C, 0x07C, 0x070, 0x026, + 0x000, 0x03B, 0x073, 0x0D5, 0x36F, 0x0F9, 0x1A1, 0x083, 0x053, 0x024, 0x09C, 0x1F4, + 0x110, 0x3D4, 0x0F0, 0x03E, 0x000, 0x03D, 0x0F3, 0x3EF, 0x11B, 0x1E9, 0x08F, 0x011, + 0x00B, 0x056, 0x0FC, 0x072, 0x1FC, 0x136, 0x3D6, 0x0D6, 0x000, 0x0D3, 0x3ED, 0x155, + 0x1B5, 0x04F, 0x0F9, 0x051, 0x0D9, 0x07A, 0x118, 0x22C, 0x080, 0x012, 0x132, 0x35E, + 0x000, 0x35D, 0x135, 0x011, 0x087, 0x22F, 0x113, 0x1FF, 0x06F, 0x00C, 0x07E, 0x130, + 0x00A, 0x0B2, 0x1E6, 0x098, 0x000, 0x07B, 0x1AB, 0x0B1, 0x003, 0x115, 0x03F, 0x001, + 0x00D, 0x016, 0x018, 0x070, 0x05E, 0x03A, 0x0A8, 0x00A, 0x000, 0x1E5, 0x09F, 0x013, + 0x05D, 0x037, 0x01D, 0x015 + }; + + private static readonly byte[] SpectrumB43Bits = + { + 02, 05, 06, 07, 07, 08, 08, 09, 00, 09, 08, 08, 07, 07, 06, 05, + 05, 06, 07, 08, 07, 08, 09, 10, 00, 10, 09, 08, 07, 08, 07, 06, + 06, 07, 08, 09, 08, 09, 10, 10, 00, 10, 10, 09, 08, 09, 08, 07, + 07, 08, 09, 10, 09, 09, 10, 10, 00, 10, 10, 10, 09, 10, 09, 08, + 07, 08, 08, 09, 10, 10, 10, 10, 00, 10, 10, 10, 10, 09, 08, 07, + 08, 08, 09, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 09, 08, + 09, 09, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 09, + 10, 10, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 10, 10, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 10, + 09, 09, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 09, + 08, 08, 09, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 09, 08, + 07, 07, 08, 09, 10, 10, 10, 10, 00, 10, 10, 10, 10, 09, 08, 08, + 07, 08, 09, 10, 09, 10, 10, 10, 00, 10, 10, 09, 09, 10, 09, 08, + 06, 07, 08, 09, 08, 09, 10, 10, 00, 10, 10, 09, 08, 09, 08, 07, + 05, 06, 07, 08, 07, 08, 09, 10, 00, 10, 09, 08, 07, 08, 07, 06 + }; + + private static readonly short[] SpectrumB43Codes = + { + 0x001, 0x01E, 0x022, 0x018, 0x064, 0x0EC, 0x008, 0x100, 0x000, 0x101, 0x009, 0x0ED, + 0x065, 0x019, 0x023, 0x01F, 0x01A, 0x030, 0x056, 0x09A, 0x00A, 0x090, 0x12C, 0x0A6, + 0x000, 0x0A9, 0x12F, 0x093, 0x00F, 0x09F, 0x059, 0x039, 0x00E, 0x054, 0x0BC, 0x19E, + 0x082, 0x176, 0x0AC, 0x088, 0x000, 0x08B, 0x0AF, 0x19D, 0x095, 0x1D1, 0x0BF, 0x051, + 0x002, 0x098, 0x1D4, 0x0B8, 0x170, 0x046, 0x090, 0x060, 0x000, 0x067, 0x095, 0x0BD, + 0x173, 0x0B5, 0x1D3, 0x09D, 0x052, 0x0EE, 0x034, 0x174, 0x0BA, 0x09C, 0x080, 0x044, + 0x000, 0x047, 0x06D, 0x099, 0x0BF, 0x16F, 0x085, 0x001, 0x0CC, 0x036, 0x16C, 0x0B0, + 0x09A, 0x084, 0x04E, 0x03E, 0x000, 0x037, 0x04B, 0x06B, 0x0A1, 0x0B3, 0x16B, 0x087, + 0x1D6, 0x102, 0x0A4, 0x092, 0x068, 0x04C, 0x034, 0x030, 0x000, 0x02D, 0x03D, 0x049, + 0x083, 0x097, 0x0AB, 0x169, 0x0B6, 0x09E, 0x06E, 0x064, 0x040, 0x038, 0x02E, 0x02A, + 0x000, 0x029, 0x033, 0x03B, 0x043, 0x063, 0x087, 0x0A3, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x0B7, 0x0A2, 0x086, 0x062, 0x042, 0x03A, 0x032, 0x028, 0x000, 0x02B, 0x02F, 0x039, + 0x041, 0x065, 0x06F, 0x09F, 0x1D7, 0x168, 0x0AA, 0x096, 0x082, 0x048, 0x03C, 0x02C, + 0x000, 0x031, 0x035, 0x04D, 0x069, 0x093, 0x0A5, 0x103, 0x0CD, 0x086, 0x16A, 0x0B2, + 0x0A0, 0x06A, 0x04A, 0x036, 0x000, 0x03F, 0x04F, 0x085, 0x09B, 0x0B1, 0x16D, 0x037, + 0x053, 0x000, 0x084, 0x16E, 0x0BE, 0x098, 0x06C, 0x046, 0x000, 0x045, 0x081, 0x09D, + 0x0BB, 0x175, 0x035, 0x0EF, 0x003, 0x09C, 0x1D2, 0x0B4, 0x172, 0x0BC, 0x094, 0x066, + 0x000, 0x061, 0x091, 0x047, 0x171, 0x0B9, 0x1D5, 0x099, 0x00F, 0x050, 0x0BE, 0x1D0, + 0x094, 0x19C, 0x0AE, 0x08A, 0x000, 0x089, 0x0AD, 0x177, 0x083, 0x19F, 0x0BD, 0x055, + 0x01B, 0x038, 0x058, 0x09E, 0x00E, 0x092, 0x12E, 0x0A8, 0x000, 0x0A7, 0x12D, 0x091, + 0x00B, 0x09B, 0x057, 0x031 + }; + + private static readonly byte[] SpectrumB44Bits = + { + 02, 04, 06, 07, 07, 08, 10, 10, 00, 10, 10, 08, 07, 07, 06, 04, + 05, 05, 07, 08, 08, 10, 10, 10, 00, 10, 10, 10, 08, 08, 07, 05, + 06, 07, 08, 09, 09, 10, 10, 10, 00, 10, 10, 10, 10, 09, 08, 07, + 08, 08, 09, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 08, + 08, 08, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 08, + 09, 10, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 10, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 10, 10, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 10, + 09, 10, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 10, + 08, 08, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 10, 08, + 08, 08, 10, 10, 10, 10, 10, 10, 00, 10, 10, 10, 10, 10, 09, 08, + 06, 07, 08, 09, 10, 10, 10, 10, 00, 10, 10, 10, 09, 09, 08, 07, + 05, 05, 07, 08, 08, 10, 10, 10, 00, 10, 10, 10, 08, 08, 07, 05 + }; + + private static readonly short[] SpectrumB44Codes = + { + 0x002, 0x002, 0x030, 0x000, 0x002, 0x00C, 0x1D2, 0x1AE, 0x000, 0x1AF, 0x1D3, 0x00D, + 0x003, 0x001, 0x031, 0x003, 0x01E, 0x002, 0x070, 0x0C8, 0x07E, 0x1E8, 0x1C0, 0x176, + 0x000, 0x17F, 0x1C3, 0x1EB, 0x0CF, 0x0D3, 0x073, 0x009, 0x018, 0x06A, 0x0EC, 0x1DE, + 0x1A2, 0x1CA, 0x1AA, 0x164, 0x000, 0x16D, 0x1AD, 0x1D1, 0x1EF, 0x1DD, 0x0EB, 0x06D, + 0x0E8, 0x0CA, 0x1BE, 0x1CE, 0x1DA, 0x1B6, 0x170, 0x154, 0x000, 0x153, 0x173, 0x1B1, + 0x1D7, 0x1D5, 0x343, 0x0CD, 0x0DC, 0x078, 0x340, 0x1CC, 0x1BA, 0x1A8, 0x156, 0x148, + 0x000, 0x145, 0x15F, 0x1A1, 0x1BD, 0x1D9, 0x1ED, 0x07D, 0x1BC, 0x1DC, 0x1C4, 0x1B2, + 0x17C, 0x15A, 0x14A, 0x03A, 0x000, 0x039, 0x147, 0x16B, 0x17B, 0x1B5, 0x1C9, 0x1DF, + 0x1C6, 0x1B8, 0x1A2, 0x168, 0x160, 0x14C, 0x02E, 0x024, 0x000, 0x027, 0x03D, 0x151, + 0x15D, 0x16F, 0x1A7, 0x1BF, 0x1A4, 0x174, 0x162, 0x14E, 0x140, 0x02C, 0x02A, 0x022, + 0x000, 0x021, 0x029, 0x03F, 0x143, 0x159, 0x167, 0x179, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x1A5, 0x178, 0x166, 0x158, 0x142, 0x03E, 0x028, 0x020, 0x000, 0x023, 0x02B, 0x02D, + 0x141, 0x14F, 0x163, 0x175, 0x1C7, 0x1BE, 0x1A6, 0x16E, 0x15C, 0x150, 0x03C, 0x026, + 0x000, 0x025, 0x02F, 0x14D, 0x161, 0x169, 0x1A3, 0x1B9, 0x1BD, 0x1DE, 0x1C8, 0x1B4, + 0x17A, 0x16A, 0x146, 0x038, 0x000, 0x03B, 0x14B, 0x15B, 0x17D, 0x1B3, 0x1C5, 0x1DD, + 0x0DD, 0x07C, 0x1EC, 0x1D8, 0x1BC, 0x1A0, 0x15E, 0x144, 0x000, 0x149, 0x157, 0x1A9, + 0x1BB, 0x1CD, 0x341, 0x079, 0x0E9, 0x0CC, 0x342, 0x1D4, 0x1D6, 0x1B0, 0x172, 0x152, + 0x000, 0x155, 0x171, 0x1B7, 0x1DB, 0x1CF, 0x1BF, 0x0CB, 0x019, 0x06C, 0x0EA, 0x1DC, + 0x1EE, 0x1D0, 0x1AC, 0x16C, 0x000, 0x165, 0x1AB, 0x1CB, 0x1A3, 0x1DF, 0x0ED, 0x06B, + 0x01F, 0x008, 0x072, 0x0D2, 0x0CE, 0x1EA, 0x1C2, 0x17E, 0x000, 0x177, 0x1C1, 0x1E9, + 0x07F, 0x0C9, 0x071, 0x003 + }; + + private static readonly byte[] SpectrumB52Bits = + { + 3, 4, 4, 4, 5, 5, 6, 6, 5, 5, 5, 6, 6, 6, 7, 7, + 0, 7, 7, 6, 6, 6, 5, 5, 5, 6, 6, 5, 5, 4, 4, 4 + }; + + private static readonly short[] SpectrumB52Codes = + { + 0x06, 0x0E, 0x06, 0x00, 0x0A, 0x04, 0x2C, 0x12, 0x14, 0x10, 0x06, 0x2E, 0x24, 0x10, 0x4E, 0x4C, + 0x00, 0x4D, 0x4F, 0x11, 0x25, 0x2F, 0x07, 0x11, 0x15, 0x13, 0x2D, 0x05, 0x0B, 0x01, 0x07, 0x0F + }; + + private static readonly byte[] SpectrumB53Bits = + { + 2, 3, 4, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 8, 8, + 0, 8, 8, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 4, 3 + }; + + private static readonly short[] SpectrumB53Codes = + { + 0x02, 0x00, 0x06, 0x1C, 0x18, 0x3E, 0x16, 0x10, 0x3C, 0x36, 0x14, 0x6A, 0x26, 0x24, 0xD2, 0xD0, + 0x00, 0xD1, 0xD3, 0x25, 0x27, 0x6B, 0x15, 0x37, 0x3D, 0x11, 0x17, 0x3F, 0x19, 0x1D, 0x07, 0x01 + }; + + private static readonly byte[] SpectrumB54Bits = + { + 2, 3, 4, 4, 5, 6, 6, 7, 6, 6, 7, 8, 8, 8, 9, 9, + 0, 9, 9, 8, 8, 8, 7, 6, 6, 7, 6, 6, 5, 4, 4, 3 + }; + + private static readonly short[] SpectrumB54Codes = + { + 0x003, 0x002, 0x008, 0x000, 0x014, 0x02E, 0x00E, 0x05A, 0x00A, 0x008, 0x01A, 0x0B2, + 0x032, 0x030, 0x162, 0x160, 0x000, 0x161, 0x163, 0x031, 0x033, 0x0B3, 0x01B, 0x009, + 0x00B, 0x05B, 0x00F, 0x02F, 0x015, 0x001, 0x009, 0x003 + }; + + private static readonly byte[] SpectrumB62Bits = + { + 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 0, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4 + }; + + private static readonly short[] SpectrumB62Codes = + { + 0x0D, 0x06, 0x1C, 0x14, 0x0A, 0x04, 0x3E, 0x2E, 0x22, 0x0E, 0x06, 0x00, 0x5A, 0x4E, 0x40, 0x20, + 0x30, 0x32, 0x24, 0x12, 0x0C, 0x02, 0x78, 0x58, 0x42, 0x22, 0x0A, 0x08, 0xF6, 0xF4, 0x9A, 0x98, + 0x00, 0x99, 0x9B, 0xF5, 0xF7, 0x09, 0x0B, 0x23, 0x43, 0x59, 0x79, 0x03, 0x0D, 0x13, 0x25, 0x33, + 0x31, 0x21, 0x41, 0x4F, 0x5B, 0x01, 0x07, 0x0F, 0x23, 0x2F, 0x3F, 0x05, 0x0B, 0x15, 0x1D, 0x07 + }; + + private static readonly byte[] SpectrumB63Bits = + { + 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, + 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, + 6, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4 + }; + + private static readonly short[] SpectrumB63Codes = + { + 0x006, 0x00E, 0x004, 0x014, 0x010, 0x006, 0x000, 0x026, 0x01C, 0x018, 0x004, 0x05C, + 0x04A, 0x03C, 0x016, 0x0BC, 0x006, 0x008, 0x058, 0x03E, 0x036, 0x014, 0x0B6, 0x0B4, + 0x090, 0x068, 0x17E, 0x17C, 0x126, 0x124, 0x0D6, 0x0D4, 0x000, 0x0D5, 0x0D7, 0x125, + 0x127, 0x17D, 0x17F, 0x069, 0x091, 0x0B5, 0x0B7, 0x015, 0x037, 0x03F, 0x059, 0x009, + 0x007, 0x0BD, 0x017, 0x03D, 0x04B, 0x05D, 0x005, 0x019, 0x01D, 0x027, 0x001, 0x007, + 0x011, 0x015, 0x005, 0x00F + }; + + private static readonly byte[] SpectrumB64Bits = + { + 03, 03, 04, 05, 05, 05, 06, 06, 06, 06, 07, 07, 07, 07, 07, 08, + 07, 07, 07, 08, 08, 08, 09, 09, 09, 09, 09, 09, 10, 10, 10, 10, + 00, 10, 10, 10, 10, 09, 09, 09, 09, 09, 09, 08, 08, 08, 07, 07, + 07, 08, 07, 07, 07, 07, 07, 06, 06, 06, 06, 05, 05, 05, 04, 03 + }; + + private static readonly short[] SpectrumB64Codes = + { + 0x007, 0x000, 0x008, 0x01A, 0x014, 0x00C, 0x032, 0x02E, 0x01E, 0x014, 0x062, 0x05A, + 0x03A, 0x026, 0x020, 0x0B2, 0x038, 0x02C, 0x022, 0x0C0, 0x05E, 0x04A, 0x186, 0x184, + 0x160, 0x0BA, 0x092, 0x090, 0x2C6, 0x2C4, 0x172, 0x170, 0x000, 0x171, 0x173, 0x2C5, + 0x2C7, 0x091, 0x093, 0x0BB, 0x161, 0x185, 0x187, 0x04B, 0x05F, 0x0C1, 0x023, 0x02D, + 0x039, 0x0B3, 0x021, 0x027, 0x03B, 0x05B, 0x063, 0x015, 0x01F, 0x02F, 0x033, 0x00D, + 0x015, 0x01B, 0x009, 0x001 + }; + + private static readonly byte[] SpectrumB72Bits = + { + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5 + }; + + private static readonly short[] SpectrumB72Codes = + { + 0x01E, 0x016, 0x00C, 0x000, 0x038, 0x032, 0x028, 0x022, 0x01C, 0x012, 0x00E, 0x006, + 0x076, 0x06C, 0x060, 0x04E, 0x03E, 0x02A, 0x022, 0x01A, 0x012, 0x00A, 0x0FC, 0x0DC, + 0x0C6, 0x0A8, 0x094, 0x086, 0x058, 0x042, 0x040, 0x02A, 0x068, 0x07C, 0x06A, 0x056, + 0x048, 0x040, 0x02E, 0x028, 0x016, 0x010, 0x008, 0x0EA, 0x0DE, 0x0AA, 0x09A, 0x096, + 0x07A, 0x078, 0x05A, 0x032, 0x030, 0x028, 0x1FE, 0x1FC, 0x1D2, 0x1D0, 0x18A, 0x188, + 0x132, 0x130, 0x10A, 0x108, 0x000, 0x109, 0x10B, 0x131, 0x133, 0x189, 0x18B, 0x1D1, + 0x1D3, 0x1FD, 0x1FF, 0x029, 0x031, 0x033, 0x05B, 0x079, 0x07B, 0x097, 0x09B, 0x0AB, + 0x0DF, 0x0EB, 0x009, 0x011, 0x017, 0x029, 0x02F, 0x041, 0x049, 0x057, 0x06B, 0x07D, + 0x069, 0x02B, 0x041, 0x043, 0x059, 0x087, 0x095, 0x0A9, 0x0C7, 0x0DD, 0x0FD, 0x00B, + 0x013, 0x01B, 0x023, 0x02B, 0x03F, 0x04F, 0x061, 0x06D, 0x077, 0x007, 0x00F, 0x013, + 0x01D, 0x023, 0x029, 0x033, 0x039, 0x001, 0x00D, 0x017 + }; + + private static readonly byte[] SpectrumB73Bits = + { + 03, 04, 05, 05, 05, 06, 06, 06, 06, 06, 06, 07, 07, 07, 07, 07, + 07, 07, 07, 07, 08, 08, 08, 08, 08, 08, 08, 08, 08, 08, 09, 09, + 08, 07, 08, 08, 08, 08, 08, 08, 08, 08, 09, 09, 09, 09, 09, 09, + 09, 09, 09, 09, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 00, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 09, 09, 09, + 09, 09, 09, 09, 09, 09, 09, 08, 08, 08, 08, 08, 08, 08, 08, 07, + 08, 09, 09, 08, 08, 08, 08, 08, 08, 08, 08, 08, 08, 07, 07, 07, + 07, 07, 07, 07, 07, 07, 06, 06, 06, 06, 06, 06, 05, 05, 05, 04 + }; + + private static readonly short[] SpectrumB73Codes = + { + 0x000, 0x006, 0x018, 0x010, 0x004, 0x03A, 0x034, 0x02A, 0x026, 0x014, 0x010, 0x07E, + 0x072, 0x06E, 0x05C, 0x052, 0x04A, 0x02C, 0x024, 0x018, 0x0F4, 0x0E0, 0x0DA, 0x0B6, + 0x0B2, 0x0A0, 0x05E, 0x04E, 0x038, 0x034, 0x1E6, 0x1B2, 0x0FA, 0x01E, 0x0F8, 0x0F0, + 0x0BE, 0x0B4, 0x0A2, 0x090, 0x04C, 0x03A, 0x1EE, 0x1E4, 0x1C6, 0x1B0, 0x178, 0x162, + 0x126, 0x124, 0x0B8, 0x06C, 0x3DA, 0x3D8, 0x38A, 0x388, 0x2F6, 0x2F4, 0x2C2, 0x2C0, + 0x176, 0x174, 0x0DC, 0x0DE, 0x000, 0x0DF, 0x0DD, 0x175, 0x177, 0x2C1, 0x2C3, 0x2F5, + 0x2F7, 0x389, 0x38B, 0x3D9, 0x3DB, 0x06D, 0x0B9, 0x125, 0x127, 0x163, 0x179, 0x1B1, + 0x1C7, 0x1E5, 0x1EF, 0x03B, 0x04D, 0x091, 0x0A3, 0x0B5, 0x0BF, 0x0F1, 0x0F9, 0x01F, + 0x0FB, 0x1B3, 0x1E7, 0x035, 0x039, 0x04F, 0x05F, 0x0A1, 0x0B3, 0x0B7, 0x0DB, 0x0E1, + 0x0F5, 0x019, 0x025, 0x02D, 0x04B, 0x053, 0x05D, 0x06F, 0x073, 0x07F, 0x011, 0x015, + 0x027, 0x02B, 0x035, 0x03B, 0x005, 0x011, 0x019, 0x007 + }; + + private static readonly byte[] SpectrumB74Bits = + { + 03, 04, 05, 05, 05, 05, 06, 06, 06, 06, 06, 06, 07, 07, 07, 07, + 07, 07, 07, 07, 08, 08, 08, 08, 08, 08, 08, 08, 08, 09, 09, 09, + 08, 08, 08, 08, 08, 09, 09, 09, 09, 09, 09, 09, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 00, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 09, 09, 09, 09, 09, 09, 09, 08, 08, 08, 08, + 08, 09, 09, 09, 08, 08, 08, 08, 08, 08, 08, 08, 08, 07, 07, 07, + 07, 07, 07, 07, 07, 06, 06, 06, 06, 06, 06, 05, 05, 05, 05, 04 + }; + + private static readonly short[] SpectrumB74Codes = + { + 0x001, 0x008, 0x01E, 0x018, 0x00C, 0x002, 0x03A, 0x034, 0x02C, 0x01E, 0x016, 0x012, + 0x072, 0x06E, 0x05E, 0x056, 0x050, 0x038, 0x022, 0x004, 0x0E2, 0x0DA, 0x0BA, 0x0A8, + 0x076, 0x054, 0x050, 0x002, 0x000, 0x1C0, 0x1B0, 0x156, 0x0A4, 0x0A6, 0x074, 0x052, + 0x004, 0x1C2, 0x1B2, 0x170, 0x154, 0x0AE, 0x0AC, 0x086, 0x2E6, 0x2E4, 0x10A, 0x108, + 0x106, 0x104, 0x102, 0x100, 0x03E, 0x03A, 0x03C, 0x038, 0x036, 0x034, 0x032, 0x030, + 0x01E, 0x01A, 0x01C, 0x018, 0x000, 0x019, 0x01D, 0x01B, 0x01F, 0x031, 0x033, 0x035, + 0x037, 0x039, 0x03D, 0x03B, 0x03F, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x2E5, + 0x2E7, 0x087, 0x0AD, 0x0AF, 0x155, 0x171, 0x1B3, 0x1C3, 0x005, 0x053, 0x075, 0x0A7, + 0x0A5, 0x157, 0x1B1, 0x1C1, 0x001, 0x003, 0x051, 0x055, 0x077, 0x0A9, 0x0BB, 0x0DB, + 0x0E3, 0x005, 0x023, 0x039, 0x051, 0x057, 0x05F, 0x06F, 0x073, 0x013, 0x017, 0x01F, + 0x02D, 0x035, 0x03B, 0x003, 0x00D, 0x019, 0x01F, 0x009 + }; + + public static readonly byte[][] HuffmanScaleFactorsABits = + { + null, + ScaleFactorsA1Bits, ScaleFactorsA2Bits, ScaleFactorsA3Bits, + ScaleFactorsA4Bits, ScaleFactorsA5Bits, ScaleFactorsA6Bits + }; + + public static readonly short[][] HuffmanScaleFactorsACodes = + { + null, + ScaleFactorsA1Codes, ScaleFactorsA2Codes, ScaleFactorsA3Codes, + ScaleFactorsA4Codes, ScaleFactorsA5Codes, ScaleFactorsA6Codes + }; + + public static readonly byte[][] HuffmanScaleFactorsBBits = + { + null, null, + ScaleFactorsB2Bits, ScaleFactorsB3Bits, ScaleFactorsB4Bits, ScaleFactorsB5Bits + }; + + public static readonly short[][] HuffmanScaleFactorsBCodes = + { + null, null, + ScaleFactorsB2Codes, ScaleFactorsB3Codes, ScaleFactorsB4Codes, ScaleFactorsB5Codes + }; + + public static readonly byte[] HuffmanScaleFactorsGroupSizes = { 0, 0, 0, 0, 0, 0, 0 }; + + public static readonly byte[][][] HuffmanSpectrumABits = + { + null, + null, + new[] {SpectrumA21Bits, SpectrumA22Bits, SpectrumA23Bits, SpectrumA24Bits}, + new[] {SpectrumA31Bits, SpectrumA32Bits, SpectrumA33Bits, SpectrumA34Bits}, + new[] {SpectrumA41Bits, SpectrumA42Bits, SpectrumA43Bits, SpectrumA44Bits}, + new[] {SpectrumA51Bits, SpectrumA52Bits, SpectrumA53Bits, SpectrumA54Bits}, + new[] {SpectrumA61Bits, SpectrumA62Bits, SpectrumA63Bits, SpectrumA64Bits}, + new[] {SpectrumA71Bits, SpectrumA72Bits, SpectrumA73Bits, SpectrumA74Bits} + }; + + public static readonly short[][][] HuffmanSpectrumACodes = + { + null, + null, + new[] {SpectrumA21Codes, SpectrumA22Codes, SpectrumA23Codes, SpectrumA24Codes}, + new[] {SpectrumA31Codes, SpectrumA32Codes, SpectrumA33Codes, SpectrumA34Codes}, + new[] {SpectrumA41Codes, SpectrumA42Codes, SpectrumA43Codes, SpectrumA44Codes}, + new[] {SpectrumA51Codes, SpectrumA52Codes, SpectrumA53Codes, SpectrumA54Codes}, + new[] {SpectrumA61Codes, SpectrumA62Codes, SpectrumA63Codes, SpectrumA64Codes}, + new[] {SpectrumA71Codes, SpectrumA72Codes, SpectrumA73Codes, SpectrumA74Codes} + }; + + public static readonly byte[][] HuffmanSpectrumAGroupSizes = + { + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {1, 2, 2, 2}, + new byte[] {1, 1, 1, 1}, + new byte[] {1, 1, 1, 1}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0} + }; + + public static readonly byte[][][] HuffmanSpectrumBBits = + { + null, + null, + new[] {null, SpectrumB22Bits, SpectrumB23Bits, SpectrumB24Bits}, + new[] {null, SpectrumB32Bits, SpectrumB33Bits, SpectrumB34Bits}, + new[] {null, SpectrumB42Bits, SpectrumB43Bits, SpectrumB44Bits}, + new[] {null, SpectrumB52Bits, SpectrumB53Bits, SpectrumB54Bits}, + new[] {null, SpectrumB62Bits, SpectrumB63Bits, SpectrumB64Bits}, + new[] {null, SpectrumB72Bits, SpectrumB73Bits, SpectrumB74Bits} + }; + + public static readonly short[][][] HuffmanSpectrumBCodes = + { + null, + null, + new[] {null, SpectrumB22Codes, SpectrumB23Codes, SpectrumB24Codes}, + new[] {null, SpectrumB32Codes, SpectrumB33Codes, SpectrumB34Codes}, + new[] {null, SpectrumB42Codes, SpectrumB43Codes, SpectrumB44Codes}, + new[] {null, SpectrumB52Codes, SpectrumB53Codes, SpectrumB54Codes}, + new[] {null, SpectrumB62Codes, SpectrumB63Codes, SpectrumB64Codes}, + new[] {null, SpectrumB72Codes, SpectrumB73Codes, SpectrumB74Codes} + }; + + public static readonly byte[][] HuffmanSpectrumBGroupSizes = + { + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 2, 2, 2}, + new byte[] {0, 1, 1, 1}, + new byte[] {0, 1, 1, 1}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0}, + new byte[] {0, 0, 0, 0} + }; + } +} \ No newline at end of file diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/LibAtrac9.csproj b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/LibAtrac9.csproj new file mode 100644 index 000000000..39fc3c8d4 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/LibAtrac9.csproj @@ -0,0 +1,8 @@ + + + + netstandard1.0 + true + + + diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Quantization.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Quantization.cs new file mode 100644 index 000000000..beb3d7d82 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Quantization.cs @@ -0,0 +1,57 @@ +using System; + +namespace LibAtrac9 +{ + internal static class Quantization + { + public static void DequantizeSpectra(Block block) + { + foreach (Channel channel in block.Channels) + { + Array.Clear(channel.Spectra, 0, channel.Spectra.Length); + + for (int i = 0; i < channel.CodedQuantUnits; i++) + { + DequantizeQuantUnit(channel, i); + } + } + } + + private static void DequantizeQuantUnit(Channel channel, int band) + { + int subBandIndex = Tables.QuantUnitToCoeffIndex[band]; + int subBandCount = Tables.QuantUnitToCoeffCount[band]; + double stepSize = Tables.QuantizerStepSize[channel.Precisions[band]]; + double stepSizeFine = Tables.QuantizerFineStepSize[channel.PrecisionsFine[band]]; + + for (int sb = 0; sb < subBandCount; sb++) + { + double coarse = channel.QuantizedSpectra[subBandIndex + sb] * stepSize; + double fine = channel.QuantizedSpectraFine[subBandIndex + sb] * stepSizeFine; + channel.Spectra[subBandIndex + sb] = coarse + fine; + } + } + + public static void ScaleSpectrum(Block block) + { + foreach (Channel channel in block.Channels) + { + ScaleSpectrum(channel); + } + } + + private static void ScaleSpectrum(Channel channel) + { + int quantUnitCount = channel.Block.QuantizationUnitCount; + double[] spectra = channel.Spectra; + + for (int i = 0; i < quantUnitCount; i++) + { + for (int sb = Tables.QuantUnitToCoeffIndex[i]; sb < Tables.QuantUnitToCoeffIndex[i + 1]; sb++) + { + spectra[sb] *= Tables.SpectrumScale[channel.ScaleFactors[i]]; + } + } + } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/ScaleFactors.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/ScaleFactors.cs new file mode 100644 index 000000000..55634a993 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/ScaleFactors.cs @@ -0,0 +1,171 @@ +using System; +using System.IO; +using LibAtrac9.Utilities; + +namespace LibAtrac9 +{ + internal static class ScaleFactors + { + public static void Read(BitReader reader, Channel channel) + { + Array.Clear(channel.ScaleFactors, 0, channel.ScaleFactors.Length); + + channel.ScaleFactorCodingMode = reader.ReadInt(2); + if (channel.ChannelIndex == 0) + { + switch (channel.ScaleFactorCodingMode) + { + case 0: + ReadVlcDeltaOffset(reader, channel); + break; + case 1: + ReadClcOffset(reader, channel); + break; + case 2: + if (channel.Block.FirstInSuperframe) throw new InvalidDataException(); + ReadVlcDistanceToBaseline(reader, channel, channel.ScaleFactorsPrev, channel.Block.QuantizationUnitsPrev); + break; + case 3: + if (channel.Block.FirstInSuperframe) throw new InvalidDataException(); + ReadVlcDeltaOffsetWithBaseline(reader, channel, channel.ScaleFactorsPrev, channel.Block.QuantizationUnitsPrev); + break; + } + } + else + { + switch (channel.ScaleFactorCodingMode) + { + case 0: + ReadVlcDeltaOffset(reader, channel); + break; + case 1: + ReadVlcDistanceToBaseline(reader, channel, channel.Block.Channels[0].ScaleFactors, channel.Block.ExtensionUnit); + break; + case 2: + ReadVlcDeltaOffsetWithBaseline(reader, channel, channel.Block.Channels[0].ScaleFactors, channel.Block.ExtensionUnit); + break; + case 3: + if (channel.Block.FirstInSuperframe) throw new InvalidDataException(); + ReadVlcDistanceToBaseline(reader, channel, channel.ScaleFactorsPrev, channel.Block.QuantizationUnitsPrev); + break; + } + } + + for (int i = 0; i < channel.Block.ExtensionUnit; i++) + { + if (channel.ScaleFactors[i] < 0 || channel.ScaleFactors[i] > 31) + { + throw new InvalidDataException("Scale factor values are out of range."); + } + } + + Array.Copy(channel.ScaleFactors, channel.ScaleFactorsPrev, channel.ScaleFactors.Length); + } + + private static void ReadClcOffset(BitReader reader, Channel channel) + { + const int maxBits = 5; + int[] sf = channel.ScaleFactors; + int bitLength = reader.ReadInt(2) + 2; + int baseValue = bitLength < maxBits ? reader.ReadInt(maxBits) : 0; + + for (int i = 0; i < channel.Block.ExtensionUnit; i++) + { + sf[i] = reader.ReadInt(bitLength) + baseValue; + } + } + + private static void ReadVlcDeltaOffset(BitReader reader, Channel channel) + { + int weightIndex = reader.ReadInt(3); + byte[] weights = ScaleFactorWeights[weightIndex]; + + int[] sf = channel.ScaleFactors; + int baseValue = reader.ReadInt(5); + int bitLength = reader.ReadInt(2) + 3; + HuffmanCodebook codebook = Tables.HuffmanScaleFactorsUnsigned[bitLength]; + + sf[0] = reader.ReadInt(bitLength); + + for (int i = 1; i < channel.Block.ExtensionUnit; i++) + { + int delta = Unpack.ReadHuffmanValue(codebook, reader); + sf[i] = (sf[i - 1] + delta) & (codebook.ValueMax - 1); + } + + for (int i = 0; i < channel.Block.ExtensionUnit; i++) + { + sf[i] += baseValue - weights[i]; + } + } + + private static void ReadVlcDistanceToBaseline(BitReader reader, Channel channel, int[] baseline, int baselineLength) + { + int[] sf = channel.ScaleFactors; + int bitLength = reader.ReadInt(2) + 2; + HuffmanCodebook codebook = Tables.HuffmanScaleFactorsSigned[bitLength]; + int unitCount = Math.Min(channel.Block.ExtensionUnit, baselineLength); + + for (int i = 0; i < unitCount; i++) + { + int distance = Unpack.ReadHuffmanValue(codebook, reader, true); + sf[i] = (baseline[i] + distance) & 31; + } + + for (int i = unitCount; i < channel.Block.ExtensionUnit; i++) + { + sf[i] = reader.ReadInt(5); + } + } + + private static void ReadVlcDeltaOffsetWithBaseline(BitReader reader, Channel channel, int[] baseline, int baselineLength) + { + int[] sf = channel.ScaleFactors; + int baseValue = reader.ReadOffsetBinary(5, BitReader.OffsetBias.Negative); + int bitLength = reader.ReadInt(2) + 1; + HuffmanCodebook codebook = Tables.HuffmanScaleFactorsUnsigned[bitLength]; + int unitCount = Math.Min(channel.Block.ExtensionUnit, baselineLength); + + sf[0] = reader.ReadInt(bitLength); + + for (int i = 1; i < unitCount; i++) + { + int delta = Unpack.ReadHuffmanValue(codebook, reader); + sf[i] = (sf[i - 1] + delta) & (codebook.ValueMax - 1); + } + + for (int i = 0; i < unitCount; i++) + { + sf[i] += baseValue + baseline[i]; + } + + for (int i = unitCount; i < channel.Block.ExtensionUnit; i++) + { + sf[i] = reader.ReadInt(5); + } + } + + public static readonly byte[][] ScaleFactorWeights = + { + new byte[] { + 0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 10, 12, 12, 12 + }, new byte[] { + 3, 2, 2, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 5, 7, 10, 10, 10 + }, new byte[] { + 0, 2, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 9, 12, 12, 12 + }, new byte[] { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 8, 8, 10, 11, 11, 12, 13, 13, 13, 13 + }, new byte[] { + 0, 2, 2, 3, 3, 4, 4, 5, 4, 5, 5, 5, 5, 6, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 14 + }, new byte[] { + 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 7, 9, 11, 11, 11 + }, new byte[] { + 0, 5, 8, 10, 11, 11, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, + 12, 13, 15, 15, 15 + }, new byte[] { + 0, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, + 15, 15, 15 + } + }; + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Stereo.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Stereo.cs new file mode 100644 index 000000000..a7ebdaf67 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Stereo.cs @@ -0,0 +1,33 @@ +namespace LibAtrac9 +{ + internal static class Stereo + { + public static void ApplyIntensityStereo(Block block) + { + if (block.BlockType != BlockType.Stereo) return; + + int totalUnits = block.QuantizationUnitCount; + int stereoUnits = block.StereoQuantizationUnit; + if (stereoUnits >= totalUnits) return; + + Channel source = block.PrimaryChannel; + Channel dest = block.SecondaryChannel; + + for (int i = stereoUnits; i < totalUnits; i++) + { + int sign = block.JointStereoSigns[i]; + for (int sb = Tables.QuantUnitToCoeffIndex[i]; sb < Tables.QuantUnitToCoeffIndex[i + 1]; sb++) + { + if (sign > 0) + { + dest.Spectra[sb] = -source.Spectra[sb]; + } + else + { + dest.Spectra[sb] = source.Spectra[sb]; + } + } + } + } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Tables.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Tables.cs new file mode 100644 index 000000000..150759c02 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Tables.cs @@ -0,0 +1,115 @@ +using System; +using static LibAtrac9.HuffmanCodebooks; + +namespace LibAtrac9 +{ + internal static class Tables + { + public static int MaxHuffPrecision(bool highSampleRate) => highSampleRate ? 1 : 7; + public static int MinBandCount(bool highSampleRate) => highSampleRate ? 1 : 3; + public static int MaxExtensionBand(bool highSampleRate) => highSampleRate ? 16 : 18; + + public static readonly int[] SampleRates = + { + 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, + 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 + }; + + public static readonly byte[] SamplingRateIndexToFrameSamplesPower = { 6, 6, 7, 7, 7, 8, 8, 8, 6, 6, 7, 7, 7, 8, 8, 8 }; + + // From sampling rate index + public static readonly byte[] MaxBandCount = { 8, 8, 12, 12, 12, 18, 18, 18, 8, 8, 12, 12, 12, 16, 16, 16 }; + public static readonly byte[] BandToQuantUnitCount = { 0, 4, 8, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 28, 30 }; + + public static readonly byte[] QuantUnitToCoeffCount = + { + 02, 02, 02, 02, 02, 02, 02, 02, 04, 04, 04, 04, 08, 08, 08, + 08, 08, 08, 08, 08, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + }; + + public static readonly short[] QuantUnitToCoeffIndex = + { + 0, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, + 64, 72, 80, 88, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256 + }; + + public static readonly byte[] QuantUnitToCodebookIndex = + { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 + }; + + public static readonly ChannelConfig[] ChannelConfig = + { + new ChannelConfig(BlockType.Mono), + new ChannelConfig(BlockType.Mono, BlockType.Mono), + new ChannelConfig(BlockType.Stereo), + new ChannelConfig(BlockType.Stereo, BlockType.Mono, BlockType.LFE, BlockType.Stereo), + new ChannelConfig(BlockType.Stereo, BlockType.Mono, BlockType.LFE, BlockType.Stereo, BlockType.Stereo), + new ChannelConfig(BlockType.Stereo, BlockType.Stereo) + }; + + public static readonly HuffmanCodebook[] HuffmanScaleFactorsUnsigned = + GenerateHuffmanCodebooks(HuffmanScaleFactorsACodes, HuffmanScaleFactorsABits, HuffmanScaleFactorsGroupSizes); + + public static readonly HuffmanCodebook[] HuffmanScaleFactorsSigned = + GenerateHuffmanCodebooks(HuffmanScaleFactorsBCodes, HuffmanScaleFactorsBBits, HuffmanScaleFactorsGroupSizes); + + public static readonly HuffmanCodebook[][][] HuffmanSpectrum = + { + GenerateHuffmanCodebooks(HuffmanSpectrumACodes, HuffmanSpectrumABits, HuffmanSpectrumAGroupSizes), + GenerateHuffmanCodebooks(HuffmanSpectrumBCodes, HuffmanSpectrumBBits, HuffmanSpectrumBGroupSizes) + }; + + public static readonly double[][] ImdctWindow = { GenerateImdctWindow(6), GenerateImdctWindow(7), GenerateImdctWindow(8) }; + + public static readonly double[] SpectrumScale = Generate(32, SpectrumScaleFunction); + public static readonly double[] QuantizerStepSize = Generate(16, QuantizerStepSizeFunction); + public static readonly double[] QuantizerFineStepSize = Generate(16, QuantizerFineStepSizeFunction); + + public static readonly byte[][] GradientCurves = BitAllocation.GenerateGradientCurves(); + + private static double QuantizerStepSizeFunction(int x) => 2.0 / ((1 << (x + 1)) - 1); + private static double QuantizerFineStepSizeFunction(int x) => QuantizerStepSizeFunction(x) / ushort.MaxValue; + private static double SpectrumScaleFunction(int x) => Math.Pow(2, x - 15); + + private static double[] GenerateImdctWindow(int frameSizePower) + { + int frameSize = 1 << frameSizePower; + var output = new double[frameSize]; + + double[] a1 = GenerateMdctWindow(frameSizePower); + + for (int i = 0; i < frameSize; i++) + { + output[i] = a1[i] / (a1[frameSize - 1 - i] * a1[frameSize - 1 - i] + a1[i] * a1[i]); + } + return output; + } + + private static double[] GenerateMdctWindow(int frameSizePower) + { + int frameSize = 1 << frameSizePower; + var output = new double[frameSize]; + + for (int i = 0; i < frameSize; i++) + { + output[i] = (Math.Sin(((i + 0.5) / frameSize - 0.5) * Math.PI) + 1.0) * 0.5; + } + + return output; + } + + private static T[] Generate(int count, Func elementGenerator) + { + var table = new T[count]; + for (int i = 0; i < count; i++) + { + table[i] = elementGenerator(i); + } + return table; + } + + + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Unpack.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Unpack.cs new file mode 100644 index 000000000..29c25fe0c --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Unpack.cs @@ -0,0 +1,425 @@ +using System; +using System.IO; +using LibAtrac9.Utilities; + +namespace LibAtrac9 +{ + internal static class Unpack + { + public static void UnpackFrame(BitReader reader, Frame frame) + { + foreach (Block block in frame.Blocks) + { + UnpackBlock(reader, block); + } + } + + private static void UnpackBlock(BitReader reader, Block block) + { + ReadBlockHeader(reader, block); + + if (block.BlockType == BlockType.LFE) + { + UnpackLfeBlock(reader, block); + } + else + { + UnpackStandardBlock(reader, block); + } + + reader.AlignPosition(8); + } + + private static void ReadBlockHeader(BitReader reader, Block block) + { + bool firstInSuperframe = block.Frame.FrameIndex == 0; + block.FirstInSuperframe = !reader.ReadBool(); + block.ReuseBandParams = reader.ReadBool(); + + if (block.FirstInSuperframe != firstInSuperframe) + { + throw new InvalidDataException(); + } + + if (firstInSuperframe && block.ReuseBandParams && block.BlockType != BlockType.LFE) + { + throw new InvalidDataException(); + } + } + + private static void UnpackStandardBlock(BitReader reader, Block block) + { + Channel[] channels = block.Channels; + + if (!block.ReuseBandParams) + { + ReadBandParams(reader, block); + } + + ReadGradientParams(reader, block); + BitAllocation.CreateGradient(block); + ReadStereoParams(reader, block); + ReadExtensionParams(reader, block); + + foreach (Channel channel in channels) + { + channel.UpdateCodedUnits(); + + ScaleFactors.Read(reader, channel); + BitAllocation.CalculateMask(channel); + BitAllocation.CalculatePrecisions(channel); + CalculateSpectrumCodebookIndex(channel); + + ReadSpectra(reader, channel); + ReadSpectraFine(reader, channel); + } + + block.QuantizationUnitsPrev = block.BandExtensionEnabled ? block.ExtensionUnit : block.QuantizationUnitCount; + } + + private static void ReadBandParams(BitReader reader, Block block) + { + int minBandCount = Tables.MinBandCount(block.Config.HighSampleRate); + int maxExtensionBand = Tables.MaxExtensionBand(block.Config.HighSampleRate); + block.BandCount = reader.ReadInt(4); + block.BandCount += minBandCount; + block.QuantizationUnitCount = Tables.BandToQuantUnitCount[block.BandCount]; + if (block.BandCount < minBandCount || block.BandCount > + Tables.MaxBandCount[block.Config.SampleRateIndex]) + { + return; + } + + if (block.BlockType == BlockType.Stereo) + { + block.StereoBand = reader.ReadInt(4); + block.StereoBand += minBandCount; + block.StereoQuantizationUnit = Tables.BandToQuantUnitCount[block.StereoBand]; + } + else + { + block.StereoBand = block.BandCount; + } + + block.BandExtensionEnabled = reader.ReadBool(); + if (block.BandExtensionEnabled) + { + block.ExtensionBand = reader.ReadInt(4); + block.ExtensionBand += minBandCount; + + if (block.ExtensionBand < block.BandCount || block.ExtensionBand > maxExtensionBand) + { + throw new InvalidDataException(); + } + + block.ExtensionUnit = Tables.BandToQuantUnitCount[block.ExtensionBand]; + } + else + { + block.ExtensionBand = block.BandCount; + block.ExtensionUnit = block.QuantizationUnitCount; + } + } + + private static void ReadGradientParams(BitReader reader, Block block) + { + block.GradientMode = reader.ReadInt(2); + if (block.GradientMode > 0) + { + block.GradientEndUnit = 31; + block.GradientEndValue = 31; + block.GradientStartUnit = reader.ReadInt(5); + block.GradientStartValue = reader.ReadInt(5); + } + else + { + block.GradientStartUnit = reader.ReadInt(6); + block.GradientEndUnit = reader.ReadInt(6) + 1; + block.GradientStartValue = reader.ReadInt(5); + block.GradientEndValue = reader.ReadInt(5); + } + block.GradientBoundary = reader.ReadInt(4); + + if (block.GradientBoundary > block.QuantizationUnitCount) + { + throw new InvalidDataException(); + } + if (block.GradientStartUnit < 1 || block.GradientStartUnit >= 48) + { + throw new InvalidDataException(); + } + if (block.GradientEndUnit < 1 || block.GradientEndUnit >= 48) + { + throw new InvalidDataException(); + } + if (block.GradientStartUnit > block.GradientEndUnit) + { + throw new InvalidDataException(); + } + if (block.GradientStartValue < 0 || block.GradientStartValue >= 32) + { + throw new InvalidDataException(); + } + if (block.GradientEndValue < 0 || block.GradientEndValue >= 32) + { + throw new InvalidDataException(); + } + } + + private static void ReadStereoParams(BitReader reader, Block block) + { + if (block.BlockType != BlockType.Stereo) return; + + block.PrimaryChannelIndex = reader.ReadInt(1); + block.HasJointStereoSigns = reader.ReadBool(); + if (block.HasJointStereoSigns) + { + for (int i = block.StereoQuantizationUnit; i < block.QuantizationUnitCount; i++) + { + block.JointStereoSigns[i] = reader.ReadInt(1); + } + } + else + { + Array.Clear(block.JointStereoSigns, 0, block.JointStereoSigns.Length); + } + } + + private static void ReadExtensionParams(BitReader reader, Block block) + { + // ReSharper disable once RedundantAssignment + int bexBand = 0; + if (block.BandExtensionEnabled) + { + BandExtension.GetBexBandInfo(out bexBand, out _, out _, block.QuantizationUnitCount); + if (block.BlockType == BlockType.Stereo) + { + ReadHeader(block.Channels[1]); + } + else + { + reader.Position += 1; + } + } + block.HasExtensionData = reader.ReadBool(); + + if (!block.HasExtensionData) return; + if (!block.BandExtensionEnabled) + { + block.BexMode = reader.ReadInt(2); + block.BexDataLength = reader.ReadInt(5); + reader.Position += block.BexDataLength; + return; + } + + ReadHeader(block.Channels[0]); + + block.BexDataLength = reader.ReadInt(5); + if (block.BexDataLength <= 0) return; + int bexDataEnd = reader.Position + block.BexDataLength; + + ReadData(block.Channels[0]); + + if (block.BlockType == BlockType.Stereo) + { + ReadData(block.Channels[1]); + } + + // Make sure we didn't read too many bits + if (reader.Position > bexDataEnd) + { + throw new InvalidDataException(); + } + + void ReadHeader(Channel channel) + { + int bexMode = reader.ReadInt(2); + channel.BexMode = bexBand > 2 ? bexMode : 4; + channel.BexValueCount = BandExtension.BexEncodedValueCounts[channel.BexMode][bexBand]; + } + + void ReadData(Channel channel) + { + for (int i = 0; i < channel.BexValueCount; i++) + { + int dataLength = BandExtension.BexDataLengths[channel.BexMode][bexBand][i]; + channel.BexValues[i] = reader.ReadInt(dataLength); + } + } + } + + private static void CalculateSpectrumCodebookIndex(Channel channel) + { + Array.Clear(channel.CodebookSet, 0, channel.CodebookSet.Length); + int quantUnits = channel.CodedQuantUnits; + int[] sf = channel.ScaleFactors; + + if (quantUnits <= 1) return; + if (channel.Config.HighSampleRate) return; + + // Temporarily setting this value allows for simpler code by + // making the last value a non-special case. + int originalScaleTmp = sf[quantUnits]; + sf[quantUnits] = sf[quantUnits - 1]; + + int avg = 0; + if (quantUnits > 12) + { + for (int i = 0; i < 12; i++) + { + avg += sf[i]; + } + avg = (avg + 6) / 12; + } + + for (int i = 8; i < quantUnits; i++) + { + int prevSf = sf[i - 1]; + int nextSf = sf[i + 1]; + int minSf = Math.Min(prevSf, nextSf); + if (sf[i] - minSf >= 3 || sf[i] - prevSf + sf[i] - nextSf >= 3) + { + channel.CodebookSet[i] = 1; + } + } + + for (int i = 12; i < quantUnits; i++) + { + if (channel.CodebookSet[i] == 0) + { + int minSf = Math.Min(sf[i - 1], sf[i + 1]); + if (sf[i] - minSf >= 2 && sf[i] >= avg - (Tables.QuantUnitToCoeffCount[i] == 16 ? 1 : 0)) + { + channel.CodebookSet[i] = 1; + } + } + } + + sf[quantUnits] = originalScaleTmp; + } + + private static void ReadSpectra(BitReader reader, Channel channel) + { + int[] values = channel.SpectraValuesBuffer; + Array.Clear(channel.QuantizedSpectra, 0, channel.QuantizedSpectra.Length); + int maxHuffPrecision = Tables.MaxHuffPrecision(channel.Config.HighSampleRate); + + for (int i = 0; i < channel.CodedQuantUnits; i++) + { + int subbandCount = Tables.QuantUnitToCoeffCount[i]; + int precision = channel.Precisions[i] + 1; + if (precision <= maxHuffPrecision) + { + HuffmanCodebook huff = Tables.HuffmanSpectrum[channel.CodebookSet[i]][precision][Tables.QuantUnitToCodebookIndex[i]]; + int groupCount = subbandCount >> huff.ValueCountPower; + for (int j = 0; j < groupCount; j++) + { + values[j] = ReadHuffmanValue(huff, reader); + } + + DecodeHuffmanValues(channel.QuantizedSpectra, Tables.QuantUnitToCoeffIndex[i], subbandCount, huff, values); + } + else + { + int subbandIndex = Tables.QuantUnitToCoeffIndex[i]; + for (int j = subbandIndex; j < Tables.QuantUnitToCoeffIndex[i + 1]; j++) + { + channel.QuantizedSpectra[j] = reader.ReadSignedInt(precision); + } + } + } + } + + private static void ReadSpectraFine(BitReader reader, Channel channel) + { + Array.Clear(channel.QuantizedSpectraFine, 0, channel.QuantizedSpectraFine.Length); + + for (int i = 0; i < channel.CodedQuantUnits; i++) + { + if (channel.PrecisionsFine[i] > 0) + { + int overflowBits = channel.PrecisionsFine[i] + 1; + int startSubband = Tables.QuantUnitToCoeffIndex[i]; + int endSubband = Tables.QuantUnitToCoeffIndex[i + 1]; + + for (int j = startSubband; j < endSubband; j++) + { + channel.QuantizedSpectraFine[j] = reader.ReadSignedInt(overflowBits); + } + } + } + } + + private static void DecodeHuffmanValues(int[] spectrum, int index, int bandCount, HuffmanCodebook huff, int[] values) + { + int valueCount = bandCount >> huff.ValueCountPower; + int mask = (1 << huff.ValueBits) - 1; + + for (int i = 0; i < valueCount; i++) + { + int value = values[i]; + for (int j = 0; j < huff.ValueCount; j++) + { + spectrum[index++] = Bit.SignExtend32(value & mask, huff.ValueBits); + value >>= huff.ValueBits; + } + } + } + + public static int ReadHuffmanValue(HuffmanCodebook huff, BitReader reader, bool signed = false) + { + int code = reader.PeekInt(huff.MaxBitSize); + byte value = huff.Lookup[code]; + int bits = huff.Bits[value]; + reader.Position += bits; + return signed ? Bit.SignExtend32(value, huff.ValueBits) : value; + } + + private static void UnpackLfeBlock(BitReader reader, Block block) + { + Channel channel = block.Channels[0]; + block.QuantizationUnitCount = 2; + + DecodeLfeScaleFactors(reader, channel); + CalculateLfePrecision(channel); + channel.CodedQuantUnits = block.QuantizationUnitCount; + ReadLfeSpectra(reader, channel); + } + + private static void DecodeLfeScaleFactors(BitReader reader, Channel channel) + { + Array.Clear(channel.ScaleFactors, 0, channel.ScaleFactors.Length); + for (int i = 0; i < channel.Block.QuantizationUnitCount; i++) + { + channel.ScaleFactors[i] = reader.ReadInt(5); + } + } + + private static void CalculateLfePrecision(Channel channel) + { + Block block = channel.Block; + int precision = block.ReuseBandParams ? 8 : 4; + for (int i = 0; i < block.QuantizationUnitCount; i++) + { + channel.Precisions[i] = precision; + channel.PrecisionsFine[i] = 0; + } + } + + private static void ReadLfeSpectra(BitReader reader, Channel channel) + { + Array.Clear(channel.QuantizedSpectra, 0, channel.QuantizedSpectra.Length); + + for (int i = 0; i < channel.CodedQuantUnits; i++) + { + if (channel.Precisions[i] <= 0) continue; + + int precision = channel.Precisions[i] + 1; + for (int j = Tables.QuantUnitToCoeffIndex[i]; j < Tables.QuantUnitToCoeffIndex[i + 1]; j++) + { + channel.QuantizedSpectra[j] = reader.ReadSignedInt(precision); + } + } + } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Bit.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Bit.cs new file mode 100644 index 000000000..f8ff07946 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Bit.cs @@ -0,0 +1,22 @@ +namespace LibAtrac9.Utilities +{ + internal static class Bit + { + private static uint BitReverse32(uint value) + { + value = ((value & 0xaaaaaaaa) >> 1) | ((value & 0x55555555) << 1); + value = ((value & 0xcccccccc) >> 2) | ((value & 0x33333333) << 2); + value = ((value & 0xf0f0f0f0) >> 4) | ((value & 0x0f0f0f0f) << 4); + value = ((value & 0xff00ff00) >> 8) | ((value & 0x00ff00ff) << 8); + return (value >> 16) | (value << 16); + } + private static uint BitReverse32(uint value, int bitCount) => BitReverse32(value) >> (32 - bitCount); + public static int BitReverse32(int value, int bitCount) => (int) BitReverse32((uint) value, bitCount); + + public static int SignExtend32(int value, int bits) + { + int shift = 8 * sizeof(int) - bits; + return (value << shift) >> shift; + } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/BitReader.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/BitReader.cs new file mode 100644 index 000000000..b89d9d765 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/BitReader.cs @@ -0,0 +1,132 @@ +using System; +using System.Diagnostics; + +namespace LibAtrac9.Utilities +{ + internal class BitReader + { + private byte[] Buffer { get; set; } + private int LengthBits { get; set; } + public int Position { get; set; } + private int Remaining => LengthBits - Position; + + public BitReader(byte[] buffer) => SetBuffer(buffer); + + public void SetBuffer(byte[] buffer) + { + Buffer = buffer; + LengthBits = Buffer?.Length * 8 ?? 0; + Position = 0; + } + + public int ReadInt(int bitCount) + { + int value = PeekInt(bitCount); + Position += bitCount; + return value; + } + + public int ReadSignedInt(int bitCount) + { + int value = PeekInt(bitCount); + Position += bitCount; + return Bit.SignExtend32(value, bitCount); + } + + public bool ReadBool() => ReadInt(1) == 1; + + public int ReadOffsetBinary(int bitCount, OffsetBias bias) + { + int offset = (1 << (bitCount - 1)) - (int)bias; + int value = PeekInt(bitCount) - offset; + Position += bitCount; + return value; + } + + public void AlignPosition(int multiple) + { + Position = Helpers.GetNextMultiple(Position, multiple); + } + + public int PeekInt(int bitCount) + { + Debug.Assert(bitCount >= 0 && bitCount <= 32); + + if (bitCount > Remaining) + { + if (Position >= LengthBits) return 0; + + int extraBits = bitCount - Remaining; + return PeekIntFallback(Remaining) << extraBits; + } + + int byteIndex = Position / 8; + int bitIndex = Position % 8; + + if (bitCount <= 9 && Remaining >= 16) + { + int value = Buffer[byteIndex] << 8 | Buffer[byteIndex + 1]; + value &= 0xFFFF >> bitIndex; + value >>= 16 - bitCount - bitIndex; + return value; + } + + if (bitCount <= 17 && Remaining >= 24) + { + int value = Buffer[byteIndex] << 16 | Buffer[byteIndex + 1] << 8 | Buffer[byteIndex + 2]; + value &= 0xFFFFFF >> bitIndex; + value >>= 24 - bitCount - bitIndex; + return value; + } + + if (bitCount <= 25 && Remaining >= 32) + { + int value = Buffer[byteIndex] << 24 | Buffer[byteIndex + 1] << 16 | Buffer[byteIndex + 2] << 8 | Buffer[byteIndex + 3]; + value &= (int)(0xFFFFFFFF >> bitIndex); + value >>= 32 - bitCount - bitIndex; + return value; + } + return PeekIntFallback(bitCount); + } + + private int PeekIntFallback(int bitCount) + { + int value = 0; + int byteIndex = Position / 8; + int bitIndex = Position % 8; + + while (bitCount > 0) + { + if (bitIndex >= 8) + { + bitIndex = 0; + byteIndex++; + } + + int bitsToRead = Math.Min(bitCount, 8 - bitIndex); + int mask = 0xFF >> bitIndex; + int currentByte = (mask & Buffer[byteIndex]) >> (8 - bitIndex - bitsToRead); + + value = (value << bitsToRead) | currentByte; + bitIndex += bitsToRead; + bitCount -= bitsToRead; + } + return value; + } + + /// + /// Specifies the bias of an offset binary value. A positive bias can represent one more + /// positive value than negative value, and a negative bias can represent one more + /// negative value than positive value. + /// + /// Example: + /// A 4-bit offset binary value with a positive bias can store + /// the values 8 through -7 inclusive. + /// A 4-bit offset binary value with a positive bias can store + /// the values 7 through -8 inclusive. + public enum OffsetBias + { + Negative = 0 + } + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Helpers.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Helpers.cs new file mode 100644 index 000000000..24f615ace --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Helpers.cs @@ -0,0 +1,50 @@ +using System.Runtime.CompilerServices; + +namespace LibAtrac9.Utilities +{ + internal static class Helpers + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short Clamp16(int value) + { + if (value > short.MaxValue) + return short.MaxValue; + if (value < short.MinValue) + return short.MinValue; + return (short)value; + } + + public static int GetNextMultiple(int value, int multiple) + { + if (multiple <= 0) + return value; + + if (value % multiple == 0) + return value; + + return value + multiple - value % multiple; + } + + /// + /// Returns the floor of the base 2 logarithm of a specified number. + /// + /// The number whose logarithm is to be found. + /// The floor of the base 2 logarithm of . + public static int Log2(int value) + { + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + + return MultiplyDeBruijnBitPosition[(uint)(value * 0x07C4ACDDU) >> 27]; + } + + private static readonly int[] MultiplyDeBruijnBitPosition = + { + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 + }; + } +} diff --git a/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Mdct.cs b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Mdct.cs new file mode 100644 index 000000000..dfc4c1b41 --- /dev/null +++ b/Frameworks/libatrac9/libatrac9/LibAtrac9/CSharp/LibAtrac9/Utilities/Mdct.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; + +namespace LibAtrac9.Utilities +{ + internal class Mdct + { + private int MdctBits { get; } + private int MdctSize { get; } + private double Scale { get; } + + private static readonly object TableLock = new object(); + private static int _tableBits = -1; + private static readonly List SinTables = new List(); + private static readonly List CosTables = new List(); + private static readonly List ShuffleTables = new List(); + + private readonly double[] _imdctPrevious; + private readonly double[] _imdctWindow; + + private readonly double[] _scratchMdct; + private readonly double[] _scratchDct; + + public Mdct(int mdctBits, double[] window, double scale = 1) + { + SetTables(mdctBits); + + MdctBits = mdctBits; + MdctSize = 1 << mdctBits; + Scale = scale; + + if (window.Length < MdctSize) + { + throw new ArgumentException("Window must be as long as the MDCT size.", nameof(window)); + } + + _imdctPrevious = new double[MdctSize]; + _scratchMdct = new double[MdctSize]; + _scratchDct = new double[MdctSize]; + _imdctWindow = window; + } + + private static void SetTables(int maxBits) + { + lock (TableLock) + { + if (maxBits > _tableBits) + { + for (int i = _tableBits + 1; i <= maxBits; i++) + { + GenerateTrigTables(i, out double[] sin, out double[] cos); + SinTables.Add(sin); + CosTables.Add(cos); + ShuffleTables.Add(GenerateShuffleTable(i)); + } + _tableBits = maxBits; + } + } + } + + public void RunImdct(double[] input, double[] output) + { + if (input.Length < MdctSize) + { + throw new ArgumentException("Input must be as long as the MDCT size.", nameof(input)); + } + + if (output.Length < MdctSize) + { + throw new ArgumentException("Output must be as long as the MDCT size.", nameof(output)); + } + + int size = MdctSize; + int half = size / 2; + double[] dctOut = _scratchMdct; + + Dct4(input, dctOut); + + for (int i = 0; i < half; i++) + { + output[i] = _imdctWindow[i] * dctOut[i + half] + _imdctPrevious[i]; + output[i + half] = _imdctWindow[i + half] * -dctOut[size - 1 - i] - _imdctPrevious[i + half]; + _imdctPrevious[i] = _imdctWindow[size - 1 - i] * -dctOut[half - i - 1]; + _imdctPrevious[i + half] = _imdctWindow[half - i - 1] * dctOut[i]; + } + } + + /// + /// Does a Type-4 DCT. + /// + /// The input array containing the time or frequency-domain samples + /// The output array that will contain the transformed time or frequency-domain samples + private void Dct4(double[] input, double[] output) + { + int[] shuffleTable = ShuffleTables[MdctBits]; + double[] sinTable = SinTables[MdctBits]; + double[] cosTable = CosTables[MdctBits]; + double[] dctTemp = _scratchDct; + + int size = MdctSize; + int lastIndex = size - 1; + int halfSize = size / 2; + + for (int i = 0; i < halfSize; i++) + { + int i2 = i * 2; + double a = input[i2]; + double b = input[lastIndex - i2]; + double sin = sinTable[i]; + double cos = cosTable[i]; + dctTemp[i2] = a * cos + b * sin; + dctTemp[i2 + 1] = a * sin - b * cos; + } + int stageCount = MdctBits - 1; + + for (int stage = 0; stage < stageCount; stage++) + { + int blockCount = 1 << stage; + int blockSizeBits = stageCount - stage; + int blockHalfSizeBits = blockSizeBits - 1; + int blockSize = 1 << blockSizeBits; + int blockHalfSize = 1 << blockHalfSizeBits; + sinTable = SinTables[blockHalfSizeBits]; + cosTable = CosTables[blockHalfSizeBits]; + + for (int block = 0; block < blockCount; block++) + { + for (int i = 0; i < blockHalfSize; i++) + { + int frontPos = (block * blockSize + i) * 2; + int backPos = frontPos + blockSize; + double a = dctTemp[frontPos] - dctTemp[backPos]; + double b = dctTemp[frontPos + 1] - dctTemp[backPos + 1]; + double sin = sinTable[i]; + double cos = cosTable[i]; + dctTemp[frontPos] += dctTemp[backPos]; + dctTemp[frontPos + 1] += dctTemp[backPos + 1]; + dctTemp[backPos] = a * cos + b * sin; + dctTemp[backPos + 1] = a * sin - b * cos; + } + } + } + + for (int i = 0; i < MdctSize; i++) + { + output[i] = dctTemp[shuffleTable[i]] * Scale; + } + } + + internal static void GenerateTrigTables(int sizeBits, out double[] sin, out double[] cos) + { + int size = 1 << sizeBits; + sin = new double[size]; + cos = new double[size]; + + for (int i = 0; i < size; i++) + { + double value = Math.PI * (4 * i + 1) / (4 * size); + sin[i] = Math.Sin(value); + cos[i] = Math.Cos(value); + } + } + + internal static int[] GenerateShuffleTable(int sizeBits) + { + int size = 1 << sizeBits; + var table = new int[size]; + + for (int i = 0; i < size; i++) + { + table[i] = Bit.BitReverse32(i ^ (i / 2), sizeBits); + } + + return table; + } + } +} diff --git a/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj index 8796b0c67..96cbb0acc 100644 --- a/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj @@ -12,6 +12,11 @@ 8301659B1F256BD000CA0941 /* ea_schl_fixed.c in Sources */ = {isa = PBXBuildFile; fileRef = 830165981F256BD000CA0941 /* ea_schl_fixed.c */; }; 8301659C1F256BD000CA0941 /* nds_strm_ffta2.c in Sources */ = {isa = PBXBuildFile; fileRef = 830165991F256BD000CA0941 /* nds_strm_ffta2.c */; }; 830165A21F256BF400CA0941 /* hwas_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 830165A11F256BF400CA0941 /* hwas_blocked.c */; }; + 830EBE102004655D0023AA10 /* atrac9_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBE0F2004655D0023AA10 /* atrac9_decoder.c */; }; + 830EBE132004656E0023AA10 /* xnb.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBE112004656E0023AA10 /* xnb.c */; }; + 830EBE142004656E0023AA10 /* ktss.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBE122004656E0023AA10 /* ktss.c */; }; + 830EBE19200465B00023AA10 /* libatrac9.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 830EBD9720045F1B0023AA10 /* libatrac9.framework */; }; + 830EBE1A200465C00023AA10 /* libatrac9.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 830EBD9720045F1B0023AA10 /* libatrac9.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 8313E3E61902020400B4B6F1 /* mpg123.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8313E3431901FBDD00B4B6F1 /* mpg123.framework */; }; 8313E3E71902021800B4B6F1 /* mpg123.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8313E3431901FBDD00B4B6F1 /* mpg123.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 831BA6181EAC61A500CF89B0 /* adx.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA60E1EAC61A500CF89B0 /* adx.c */; }; @@ -444,6 +449,27 @@ /* End PBXBuildRule section */ /* Begin PBXContainerItemProxy section */ + 830EBD9620045F1B0023AA10 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 830EBD9220045F190023AA10 /* libatrac9.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 830EBD8720045F190023AA10; + remoteInfo = libatrac9; + }; + 830EBE152004659B0023AA10 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 830EBD9220045F190023AA10 /* libatrac9.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 830EBD8620045F190023AA10; + remoteInfo = libatrac9; + }; + 830EBE17200465A30023AA10 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83F412871E932F9A002E37D0 /* Vorbis.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 730F23A1091827B100AB638C; + remoteInfo = Vorbis; + }; 8313E3421901FBDD00B4B6F1 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 8313E33D1901FBDC00B4B6F1 /* mpg123.xcodeproj */; @@ -523,6 +549,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 830EBE1A200465C00023AA10 /* libatrac9.framework in CopyFiles */, 832C70BF1E9335E400BD7B4E /* Vorbis.framework in CopyFiles */, 83D7318A1A749D2200CA1366 /* g719.framework in CopyFiles */, 83D731111A7394D300CA1366 /* g7221.framework in CopyFiles */, @@ -538,6 +565,10 @@ 830165981F256BD000CA0941 /* ea_schl_fixed.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_schl_fixed.c; sourceTree = ""; }; 830165991F256BD000CA0941 /* nds_strm_ffta2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_strm_ffta2.c; sourceTree = ""; }; 830165A11F256BF400CA0941 /* hwas_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hwas_blocked.c; sourceTree = ""; }; + 830EBD9220045F190023AA10 /* libatrac9.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libatrac9.xcodeproj; path = ../libatrac9/libatrac9.xcodeproj; sourceTree = ""; }; + 830EBE0F2004655D0023AA10 /* atrac9_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = atrac9_decoder.c; sourceTree = ""; }; + 830EBE112004656E0023AA10 /* xnb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xnb.c; sourceTree = ""; }; + 830EBE122004656E0023AA10 /* ktss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ktss.c; sourceTree = ""; }; 8313E33D1901FBDC00B4B6F1 /* mpg123.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = mpg123.xcodeproj; path = ../mpg123/mpg123.xcodeproj; sourceTree = ""; }; 831BA60E1EAC61A500CF89B0 /* adx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adx.c; sourceTree = ""; }; 831BA60F1EAC61A500CF89B0 /* ogl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogl.c; sourceTree = ""; }; @@ -960,6 +991,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 830EBE19200465B00023AA10 /* libatrac9.framework in Frameworks */, 838BDB7F1D3B1FD10022CA6F /* Cocoa.framework in Frameworks */, 838BDB7D1D3B1FCC0022CA6F /* CoreVideo.framework in Frameworks */, 838BDB7B1D3B1FC20022CA6F /* CoreMedia.framework in Frameworks */, @@ -984,6 +1016,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 830EBD9320045F190023AA10 /* Products */ = { + isa = PBXGroup; + children = ( + 830EBD9720045F1B0023AA10 /* libatrac9.framework */, + ); + name = Products; + sourceTree = ""; + }; 8313E33E1901FBDC00B4B6F1 /* Products */ = { isa = PBXGroup; children = ( @@ -1040,6 +1080,7 @@ 836F6B3E18BDB8880095E648 /* Other Frameworks */ = { isa = PBXGroup; children = ( + 830EBD9220045F190023AA10 /* libatrac9.xcodeproj */, 838BDB611D3AF08C0022CA6F /* libavcodec.a */, 838BDB621D3AF08C0022CA6F /* libavformat.a */, 838BDB631D3AF08C0022CA6F /* libavutil.a */, @@ -1093,6 +1134,7 @@ 836F6DDF18BDC2180095E648 /* coding */ = { isa = PBXGroup; children = ( + 830EBE0F2004655D0023AA10 /* atrac9_decoder.c */, 8349A8DE1FE6251F00E26435 /* ea_mt_decoder.c */, 8349A8DD1FE6251F00E26435 /* ffmpeg_decoder_utils_bgw_atrac3.c */, 8349A8DC1FE6251E00E26435 /* vorbis_custom_utils_vid1.c */, @@ -1204,6 +1246,8 @@ 836F6E2718BDC2180095E648 /* meta */ = { isa = PBXGroup; children = ( + 830EBE122004656E0023AA10 /* ktss.c */, + 830EBE112004656E0023AA10 /* xnb.c */, 8349A9041FE6258100E26435 /* aax_streamfile.h */, 8349A9021FE6258100E26435 /* adx_keys.h */, 8349A9001FE6258000E26435 /* afc.c */, @@ -1576,6 +1620,8 @@ 48C265101A5D424500A0A3D6 /* PBXBuildRule */, ); dependencies = ( + 830EBE18200465A30023AA10 /* PBXTargetDependency */, + 830EBE162004659B0023AA10 /* PBXTargetDependency */, 83D731881A749D0D00CA1366 /* PBXTargetDependency */, 83D7310F1A7394B500CA1366 /* PBXTargetDependency */, 8313E3E91902021F00B4B6F1 /* PBXTargetDependency */, @@ -1619,6 +1665,10 @@ ProductGroup = 83D730E61A738EB200CA1366 /* Products */; ProjectRef = 83D730E51A738EB200CA1366 /* g7221.xcodeproj */; }, + { + ProductGroup = 830EBD9320045F190023AA10 /* Products */; + ProjectRef = 830EBD9220045F190023AA10 /* libatrac9.xcodeproj */; + }, { ProductGroup = 8313E33E1901FBDC00B4B6F1 /* Products */; ProjectRef = 8313E33D1901FBDC00B4B6F1 /* mpg123.xcodeproj */; @@ -1636,6 +1686,13 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ + 830EBD9720045F1B0023AA10 /* libatrac9.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = libatrac9.framework; + remoteRef = 830EBD9620045F1B0023AA10 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 8313E3431901FBDD00B4B6F1 /* mpg123.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; @@ -1781,6 +1838,7 @@ 8349A91F1FE6258200E26435 /* naac.c in Sources */, 836F6FD218BDC2190095E648 /* ps2_bmdx.c in Sources */, 836F703C18BDC2190095E648 /* wii_bns.c in Sources */, + 830EBE132004656E0023AA10 /* xnb.c in Sources */, 835027131ED119E000C25929 /* mta2_decoder.c in Sources */, 836F6FA718BDC2190095E648 /* nds_strm.c in Sources */, 8349A91A1FE6258200E26435 /* vxn.c in Sources */, @@ -1817,8 +1875,10 @@ 836F701118BDC2190095E648 /* ps3_cps.c in Sources */, 836F701418BDC2190095E648 /* ps3_msf.c in Sources */, 836F6F6518BDC2190095E648 /* 2dx9.c in Sources */, + 830EBE102004655D0023AA10 /* atrac9_decoder.c in Sources */, 836F700818BDC2190095E648 /* ps2_vms.c in Sources */, 836F702418BDC2190095E648 /* rwsd.c in Sources */, + 830EBE142004656E0023AA10 /* ktss.c in Sources */, 836F6F5618BDC2190095E648 /* scd_int_layout.c in Sources */, 836F6F6618BDC2190095E648 /* aax.c in Sources */, 836F6FD618BDC2190095E648 /* ps2_exst.c in Sources */, @@ -2084,6 +2144,16 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 830EBE162004659B0023AA10 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = libatrac9; + targetProxy = 830EBE152004659B0023AA10 /* PBXContainerItemProxy */; + }; + 830EBE18200465A30023AA10 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Vorbis; + targetProxy = 830EBE17200465A30023AA10 /* PBXContainerItemProxy */; + }; 8313E3E91902021F00B4B6F1 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = mpg123; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/at3_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/at3_decoder.c index a8b444ecb..57f56ef9b 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/at3_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/at3_decoder.c @@ -4,6 +4,20 @@ #ifdef VGM_USE_MAIATRAC3PLUS #include "maiatrac3plus.h" +maiatrac3plus_codec_data *init_at3plus() { + + maiatrac3plus_codec_data *data = malloc(sizeof(maiatrac3plus_codec_data)); + data->buffer = 0; + data->samples_discard = 0; + data->handle = Atrac3plusDecoder_openContext(); + if (!data->handle) goto fail; + + return data; + +fail: + return NULL; +} + void decode_at3plus(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) { VGMSTREAMCHANNEL *ch = &vgmstream->ch[0]; maiatrac3plus_codec_data *data = vgmstream->codec_data; @@ -25,8 +39,7 @@ void decode_at3plus(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, data->samples_discard = 0; } - for (i = 0; i < samples_to_do; i++) - { + for (i = 0; i < samples_to_do; i++) { outbuf[i*channelspacing] = data->buffer[(first_sample+i)*data->channels+channel]; } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/atrac9_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/atrac9_decoder.c new file mode 100644 index 000000000..eb0b61166 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/coding/atrac9_decoder.c @@ -0,0 +1,219 @@ +#include "coding.h" + +#ifdef VGM_USE_ATRAC9 +#include + + +atrac9_codec_data *init_atrac9(atrac9_config *cfg) { + int status; + uint8_t config_data[4]; + Atrac9CodecInfo info = {0}; + atrac9_codec_data *data = NULL; + + data = calloc(1, sizeof(atrac9_codec_data)); + + data->handle = Atrac9GetHandle(); + if (!data->handle) goto fail; + + put_32bitBE(config_data, cfg->config_data); + status = Atrac9InitDecoder(data->handle, config_data); + if (status < 0) goto fail; + + status = Atrac9GetCodecInfo(data->handle, &info); + if (status < 0) goto fail; + //;VGM_LOG("ATRAC9: config=%x, sf-size=%x, sub-frames=%i x %i samples\n", cfg->config_data, info.superframeSize, info.framesInSuperframe, info.frameSamples); + + if (cfg->channels && cfg->channels != info.channels) { + VGM_LOG("ATRAC9: channels in header %i vs config %i don't match\n", cfg->channels, info.channels); + goto fail; /* unknown multichannel layout */ + } + + + /* must hold at least one superframe and its samples */ + data->data_buffer_size = info.superframeSize; + data->data_buffer = calloc(sizeof(uint8_t), data->data_buffer_size); + data->sample_buffer = calloc(sizeof(sample), info.channels * info.frameSamples * info.framesInSuperframe); + + data->samples_to_discard = cfg->encoder_delay; + + memcpy(&data->config, cfg, sizeof(atrac9_config)); + + return data; + +fail: + return NULL; +} + +void decode_atrac9(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels) { + VGMSTREAMCHANNEL *stream = &vgmstream->ch[0]; + atrac9_codec_data * data = vgmstream->codec_data; + int samples_done = 0; + + + while (samples_done < samples_to_do) { + + if (data->samples_filled) { /* consume samples */ + 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; + } + 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_used*channels, + samples_to_get*channels * sizeof(sample)); + + samples_done += samples_to_get; + } + + /* mark consumed samples */ + data->samples_used += samples_to_get; + data->samples_filled -= samples_to_get; + } + else { /* decode data */ + int iframe, status; + int bytes_used = 0; + uint8_t *buffer = data->data_buffer; + size_t bytes; + Atrac9CodecInfo info = {0}; + + data->samples_used = 0; + + /* ATRAC9 is made of decodable superframes with several sub-frames. AT9 config data gives + * superframe size, number of frames and samples (~100-200 bytes and ~256/1024 samples). */ + status = Atrac9GetCodecInfo(data->handle, &info); + if (status < 0) goto decode_fail; + + + /* preadjust */ //todo improve + switch(data->config.type) { + case ATRAC9_XVAG: + /* PS4 (ex. The Last of Us) has a RIFF AT9 (can be ignored) instead of the first superframe. + * As subsongs do too, needs to be skipped here instead of adjusting start_offset */ + if (stream->offset == stream->channel_start_offset) { + if (read_32bitBE(stream->offset, stream->streamfile) == 0x00000000 /* padding before RIFF */ + && read_32bitBE(stream->offset + info.superframeSize - 0x08,stream->streamfile) == 0x64617461) { /* RIFF's "data" */ + stream->offset += info.superframeSize; + } + } + break; + default: + break; + } + + /* read one raw block (superframe) and advance offsets */ + bytes = read_streamfile(data->data_buffer,stream->offset, info.superframeSize,stream->streamfile); + if (bytes != data->data_buffer_size) { + VGM_LOG("ATRAC9: read %x vs expected %x bytes at %lx\n", bytes, info.superframeSize, stream->offset); + goto decode_fail; + } + + stream->offset += bytes; + + /* postadjust */ //todo improve + switch(data->config.type) { + case ATRAC9_XVAG: /* skip other subsong blocks in XVAG */ + if (data->config.interleave_skip && ((stream->offset - stream->channel_start_offset) % data->config.interleave_skip == 0)) { + stream->offset += data->config.interleave_skip * (data->config.subsong_skip - 1); + } + break; + default: + break; + } + + + /* decode all frames in the superframe block */ + for (iframe = 0; iframe < info.framesInSuperframe; iframe++) { + status = Atrac9Decode(data->handle, buffer, data->sample_buffer + data->samples_filled*channels, &bytes_used); + if (status < 0) goto decode_fail; + + buffer += bytes_used; + data->samples_filled += info.frameSamples; + } + } + } + + return; + +decode_fail: + /* on error just put some 0 samples */ + VGM_LOG("ATRAC9: decode fail at %lx, missing %i samples\n", stream->offset, (samples_to_do - samples_done)); + memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample) * channels); +} + +void reset_atrac9(VGMSTREAM *vgmstream) { + atrac9_codec_data *data = vgmstream->codec_data; + + if (!data->handle) + goto fail; + +#if 0 + /* reopen/flush, not needed as superframes decode separatedly and there is no carried state */ + { + int status; + uint8_t config_data[4]; + + Atrac9ReleaseHandle(data->handle); + data->handle = Atrac9GetHandle(); + if (!data->handle) goto fail; + + put_32bitBE(config_data, data->config.config_data); + status = Atrac9InitDecoder(data->handle, config_data); + if (status < 0) goto fail; + } +#endif + + data->samples_used = 0; + data->samples_filled = 0; + data->samples_to_discard = 0; + + return; + +fail: + return; /* decode calls should fail... */ +} + +void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample) { + atrac9_codec_data *data = vgmstream->codec_data; + + reset_atrac9(vgmstream); + + data->samples_to_discard = num_sample; + data->samples_to_discard += data->config.encoder_delay; + + /* 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_atrac9(atrac9_codec_data *data) { + if (!data) + return; + + if (data->handle) Atrac9ReleaseHandle(data->handle); + free(data->data_buffer); + free(data->sample_buffer); + free(data); +} + + +size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data) { + Atrac9CodecInfo info = {0}; + int status; + + status = Atrac9GetCodecInfo(data->handle, &info); + if (status < 0) goto fail; + + return bytes / info.superframeSize * (info.frameSamples * info.framesInSuperframe); + +fail: + return 0; +} +#endif diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding.h b/Frameworks/vgmstream/vgmstream/src/coding/coding.h index 6e36600b9..dbca81d47 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding.h @@ -65,6 +65,7 @@ void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian); size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample); @@ -79,7 +80,6 @@ size_t ps_bytes_to_samples(size_t bytes, int channels); /* xa_decoder */ void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); -void xa_init_get_high_nibble(VGMSTREAM * vgmstream); size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked); /* ea_xa_decoder */ @@ -157,7 +157,7 @@ void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample); void free_ogg_vorbis(ogg_vorbis_codec_data *data); /* vorbis_custom_decoder */ -vorbis_custom_codec_data * init_vorbis_custom_codec_data(STREAMFILE *streamfile, off_t start_offset, vorbis_custom_t type, vorbis_custom_config * config); +vorbis_custom_codec_data *init_vorbis_custom(STREAMFILE *streamfile, off_t start_offset, vorbis_custom_t type, vorbis_custom_config * config); void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels); void reset_vorbis_custom(VGMSTREAM *vgmstream); void seek_vorbis_custom(VGMSTREAM *vgmstream, int32_t num_sample); @@ -166,11 +166,9 @@ void free_vorbis_custom(vorbis_custom_codec_data *data); #ifdef VGM_USE_MPEG /* mpeg_decoder */ -mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels); -mpeg_codec_data *init_mpeg_custom_codec_data(STREAMFILE *streamFile, off_t start_offset, coding_t *coding_type, int channels, mpeg_custom_t custom_type, mpeg_custom_config *config); - +mpeg_codec_data *init_mpeg(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels); +mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, coding_t *coding_type, int channels, mpeg_custom_t custom_type, mpeg_custom_config *config); void decode_mpeg(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels); -void decode_fake_mpeg2_l2(VGMSTREAMCHANNEL * stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do); void reset_mpeg(VGMSTREAM *vgmstream); void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample); void free_mpeg(mpeg_codec_data *data); @@ -204,18 +202,29 @@ void free_mp4_aac(mp4_aac_codec_data * data); #endif #ifdef VGM_USE_MAIATRAC3PLUS -/* at3_decoder */ +/* at3plus_decoder */ +maiatrac3plus_codec_data *init_at3plus(); void decode_at3plus(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel); void reset_at3plus(VGMSTREAM *vgmstream); void seek_at3plus(VGMSTREAM *vgmstream, int32_t num_sample); void free_at3plus(maiatrac3plus_codec_data *data); #endif +#ifdef VGM_USE_ATRAC9 +/* atrac9_decoder */ +atrac9_codec_data *init_atrac9(atrac9_config *cfg); +void decode_atrac9(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels); +void reset_atrac9(VGMSTREAM *vgmstream); +void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample); +void free_atrac9(atrac9_codec_data *data); +size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data); +#endif + #ifdef VGM_USE_FFMPEG /* ffmpeg_decoder */ -ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size); -ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size); -ffmpeg_codec_data * init_ffmpeg_config(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size, ffmpeg_custom_config * config); +ffmpeg_codec_data *init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size); +ffmpeg_codec_data *init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size); +ffmpeg_codec_data *init_ffmpeg_config(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size, ffmpeg_custom_config * config); void decode_ffmpeg(VGMSTREAM *stream, sample * outbuf, int32_t samples_to_do, int channels); void reset_ffmpeg(VGMSTREAM *vgmstream); diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_ea_xma.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_ea_xma.c index fd56320ce..c4dc0b625 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_ea_xma.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_ea_xma.c @@ -119,8 +119,8 @@ int ffmpeg_custom_read_eaxma(ffmpeg_codec_data *data, uint8_t *buf, int buf_size virtual_base += data_size; } - /* exit on last block just in case, though should reach file size */ - if (block_size & 0x80000000) + /* exit on last block just in case, though should reach real_size */ + if ((block_size & 0x80000000) || (block_size & 0x45000000)) break; } @@ -199,10 +199,9 @@ size_t ffmpeg_get_eaxma_virtual_size(int channels, off_t real_offset, size_t rea /* 0x04(4): decoded samples */ off_t packets_offset = real_offset + 0x08; - if ((block_size & 0xFF000000) && !(block_size & 0x80000000)) { - VGM_LOG("EA-XMA: unknown flag found at %lx\n", (off_t)real_offset); - goto fail; - } + /* At 0x00(1): block flag + * - in SNS: 0x00=normal block, 0x80=last block (not mandatory) + * - in SPS: 0x48=header, 0x44=normal block, 0x45=last block (empty) */ max_packets = get_block_max_packets(num_streams, packets_offset, streamFile); if (max_packets == 0) goto fail; @@ -213,7 +212,7 @@ size_t ffmpeg_get_eaxma_virtual_size(int channels, off_t real_offset, size_t rea real_offset += (block_size & 0x00FFFFFF); /* exit on last block just in case, though should reach real_size */ - if (block_size & 0x80000000) + if ((block_size & 0x80000000) || (block_size & 0x45000000)) break; } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c index c8f56ef1d..6cc343e7b 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c @@ -787,12 +787,13 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels) { /* MS IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */ - return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels; + return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels + + ((bytes % block_align) ? ((bytes % block_align) - 4 * channels) * 2 / channels : 0); } size_t ima_bytes_to_samples(size_t bytes, int channels) { /* 2 samples per byte (2 nibbles) in stereo or mono config */ - return bytes / channels * 2; + return bytes * 2 / channels; } size_t ubi_ima_bytes_to_samples(size_t bytes, int channels, STREAMFILE *streamFile, off_t offset) { diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c index 6b8cb7e7b..1c1385acc 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c @@ -21,7 +21,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data /* Inits regular MPEG */ -mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels) { +mpeg_codec_data *init_mpeg(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels) { mpeg_codec_data *data = NULL; /* init codec */ @@ -116,7 +116,7 @@ fail: /* Init custom MPEG, with given type and config */ -mpeg_codec_data *init_mpeg_custom_codec_data(STREAMFILE *streamFile, off_t start_offset, coding_t *coding_type, int channels, mpeg_custom_t type, mpeg_custom_config *config) { +mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, coding_t *coding_type, int channels, mpeg_custom_t type, mpeg_custom_config *config) { mpeg_codec_data *data = NULL; int i, ok; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c index 3a8e813a1..3e016f949 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c @@ -87,69 +87,83 @@ void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int chan } } -/* decodes u-law (ITU G.711 non-linear PCM), from g711.c */ -void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - int i; - int32_t sample_count; - int sign, segment, quantization, sample; +static int expand_ulaw(uint8_t ulawbyte) { + int sign, segment, quantization, new_sample; const int bias = 0x84; + ulawbyte = ~ulawbyte; /* stored in complement */ + sign = (ulawbyte & 0x80); + segment = (ulawbyte & 0x70) >> 4; /* exponent */ + quantization = ulawbyte & 0x0F; /* mantissa */ + + new_sample = (quantization << 3) + bias; /* add bias */ + new_sample <<= segment; + new_sample = (sign) ? (bias - new_sample) : (new_sample - bias); /* remove bias */ + +#if 0 // the above follows Sun's implementation, but this works too + { + static int exp_lut[8] = {0,132,396,924,1980,4092,8316,16764}; /* precalcs from bias */ + new_sample = exp_lut[segment] + (quantization << (segment + 3)); + if (sign != 0) new_sample = -new_sample; + } +#endif + + return new_sample; +} + +/* decodes u-law (ITU G.711 non-linear PCM), from g711.c */ +void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_count; for (i=first_sample,sample_count=0; ioffset+i,stream->streamfile); - - ulawbyte = ~ulawbyte; /* stored in complement */ - sign = (ulawbyte & 0x80); - segment = (ulawbyte & 0x70) >> 4; /* exponent */ - quantization = ulawbyte & 0x0F; /* mantissa */ - - sample = (quantization << 3) + bias; /* add bias */ - sample <<= segment; - sample = (sign) ? (bias - sample) : (sample - bias); /* remove bias */ - -#if 0 // the above follows Sun's implementation, but this works too - { - static int exp_lut[8] = {0,132,396,924,1980,4092,8316,16764}; /* precalcs from bias */ - sample = exp_lut[segment] + (quantization << (segment + 3)); - if (sign != 0) sample = -sample; - } -#endif - - outbuf[sample_count] = sample; + outbuf[sample_count] = expand_ulaw(ulawbyte); } } + +void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_count; + + for (i=first_sample,sample_count=0; ioffset+i*channelspacing,stream->streamfile); + outbuf[sample_count] = expand_ulaw(ulawbyte); + } +} + +static int expand_alaw(uint8_t alawbyte) { + int sign, segment, quantization, new_sample; + + alawbyte ^= 0x55; + sign = (alawbyte & 0x80); + segment = (alawbyte & 0x70) >> 4; /* exponent */ + quantization = alawbyte & 0x0F; /* mantissa */ + + new_sample = (quantization << 4); + switch (segment) { + case 0: + new_sample += 8; + break; + case 1: + new_sample += 0x108; + break; + default: + new_sample += 0x108; + new_sample <<= segment - 1; + break; + } + new_sample = (sign) ? new_sample : -new_sample; + + return new_sample; +} + /* decodes a-law (ITU G.711 non-linear PCM), from g711.c */ void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - int i; - int32_t sample_count; - int sign, segment, quantization, sample; - + int i, sample_count; for (i=first_sample,sample_count=0; ioffset+i,stream->streamfile); - - alawbyte ^= 0x55; - sign = (alawbyte & 0x80); - segment = (alawbyte & 0x70) >> 4; /* exponent */ - quantization = alawbyte & 0x0F; /* mantissa */ - - sample = (quantization << 4); - switch (segment) { - case 0: - sample += 8; - break; - case 1: - sample += 0x108; - break; - default: - sample += 0x108; - sample <<= segment - 1; - break; - } - sample = (sign) ? sample : -sample; - - outbuf[sample_count] = sample; + outbuf[sample_count] = expand_alaw(alawbyte);; } } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c index 1cc12ae98..a85250ad5 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c @@ -6,12 +6,25 @@ #define VAG_USE_INTEGER_TABLE 0 /* PS ADPCM table (precalculated divs) */ -static const double VAG_f[5][2] = { +static const double VAG_f[16][2] = { { 0.0 , 0.0 }, { 60.0 / 64.0 , 0.0 }, { 115.0 / 64.0 , -52.0 / 64.0 }, { 98.0 / 64.0 , -55.0 / 64.0 }, - { 122.0 / 64.0 , -60.0 / 64.0 } + { 122.0 / 64.0 , -60.0 / 64.0 }, + /* extended table from PPSSPP (PSP emu), found by tests + * (only seen in inFamous PS3, very rare, possibly "SVAG" or "VAG-HE") */ + { 0.0 , 0.0 }, + { 0.0 , 0.0 }, + { 52.0 / 64.0 , 0.0 }, + { 55.0 / 64.0 , -2.0 / 64.0 }, + { 60.0 / 64.0 ,-125.0 / 64.0 }, + { 0.0 , 0.0 }, + { 0.0 , -91.0 / 64.0 }, + { 0.0 , 0.0 }, + { 2.0 / 64.0 ,-216.0 / 64.0 }, + { 125.0 / 64.0 , -6.0 / 64.0 }, + { 0.0 ,-151.0 / 64.0 }, }; #if VAG_USE_INTEGER_TABLE /* PS ADPCM table */ @@ -20,7 +33,19 @@ static const int8_t VAG_coefs[5][2] = { { 60 , 0 }, { 115 , -52 }, { 98 , -55 }, - { 122 , -60 } + { 122 , -60 }, + /* extended */ + { 0 , 0 }, + { 0 , 0 }, + { 52 , 0 }, + { 55 , -2 }, + { 60 ,-125 }, + { 0 , 0 }, + { 0 , -91 }, + { 0 , 0 }, + { 2 ,-216 }, + { 125 , -6 }, + { 0 ,-151 }, }; #endif diff --git a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_decoder.c index 7c6cdf282..29d20a321 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_decoder.c @@ -19,7 +19,7 @@ static void pcm_convert_float_to_16(vorbis_custom_codec_data * data, sample * ou * * Reference: https://www.xiph.org/vorbis/doc/libvorbis/overview.html */ -vorbis_custom_codec_data * init_vorbis_custom_codec_data(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_t type, vorbis_custom_config * config) { +vorbis_custom_codec_data * init_vorbis_custom(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_t type, vorbis_custom_config * config) { vorbis_custom_codec_data * data = NULL; int ok; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/xa_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/xa_decoder.c index deeada360..96b6568db 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/xa_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/xa_decoder.c @@ -20,10 +20,6 @@ static int CLAMP(int value, int Minim, int Maxim) return value; } -void xa_init_get_high_nibble(VGMSTREAM *vgmstream) { - vgmstream->xa_get_high_nibble=1; -} - void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]); diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index f3572d48d..975a3c543 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -42,6 +42,7 @@ static const char* extension_list[] = { "ass", "ast", "at3", + "at9", "aud", "aus", "awc", @@ -106,7 +107,7 @@ static const char* extension_list[] = { "emff", "enth", "exa", - "ezw", + "ezw", "fag", "ffw", @@ -156,6 +157,8 @@ static const char* extension_list[] = { "khv", "kovs", "kraw", + "ktss", + "kvs", "laac", //fake extension, for AAC (tri-Ace/FFmpeg) "lac3", //fake extension, for AC3 @@ -181,7 +184,7 @@ static const char* extension_list[] = { "mic", "mihb", "mnstr", - "mogg", + "mogg", //"mp4", //common //"mpc", //FFmpeg, not parsed (musepack) //common "mpdsp", @@ -423,6 +426,7 @@ static const coding_info coding_info_list[] = { {coding_PCM8_U_int, "8-bit unsigned PCM with 1 byte interleave (block)"}, {coding_PCM8_SB_int, "8-bit PCM with sign bit, 1 byte interleave (block)"}, {coding_ULAW, "8-bit u-Law"}, + {coding_ULAW_int, "8-bit u-Law with 1 byte interleave (block)"}, {coding_ALAW, "8-bit a-Law"}, {coding_PCMFLOAT, "32-bit float PCM"}, @@ -521,6 +525,9 @@ static const coding_info coding_info_list[] = { #ifdef VGM_USE_MAIATRAC3PLUS {coding_AT3plus, "ATRAC3plus"}, #endif +#ifdef VGM_USE_ATRAC9 + {coding_ATRAC9, "ATRAC9"}, +#endif #ifdef VGM_USE_FFMPEG {coding_FFmpeg, "FFmpeg"}, #endif @@ -879,6 +886,7 @@ static const meta_info meta_info_list[] = { {meta_CSTM, "Nintendo 3DS CSTM Header"}, {meta_FSTM, "Nintendo Wii U FSTM Header"}, {meta_KT_WIIBGM, "Koei Tecmo WiiBGM Header"}, + {meta_KTSS, "Koei Tecmo Switch Sound Header"}, {meta_3DS_IDSP, "Nintendo IDSP Header"}, {meta_WIIU_BTSND, "Nintendo Wii U Menu Boot Sound"}, {meta_MCA, "Capcom MCA header"}, @@ -900,6 +908,7 @@ static const meta_info meta_info_list[] = { {meta_GTD, "GTD/GHS header"}, {meta_TA_AAC_X360, "tri-Ace AAC (X360) header"}, {meta_TA_AAC_PS3, "tri-Ace AAC (PS3) header"}, + {meta_TA_AAC_VORBIS, "tri-Ace AAC (Mobile Vorbis) header"}, {meta_PS3_MTA2, "Konami MTA2 header"}, {meta_NGC_ULW, "Criterion ULW raw header"}, {meta_PC_XA30, "Reflections XA30 PC header"}, @@ -923,8 +932,7 @@ static const meta_info meta_info_list[] = { {meta_EA_SPS, "Electronic Arts SPS header"}, {meta_NGC_VID1, "Neversoft VID1 header"}, {meta_PC_FLX, "Ultima IX .FLX header"}, - {meta_MOGG, "Harmonix Music Systems MOGG Vorbis "}, - + {meta_MOGG, "Harmonix Music Systems MOGG Vorbis"}, #ifdef VGM_USE_VORBIS {meta_OGG_VORBIS, "Ogg Vorbis"}, diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_1snh.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_1snh.c index bcb8e673e..b9d921b8b 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_1snh.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_1snh.c @@ -4,36 +4,41 @@ /* set up for the block at the given offset */ void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream) { - int i; STREAMFILE* streamFile = vgmstream->ch[0].streamfile; - uint32_t id; - size_t file_size, block_size = 0, block_header = 0; + int i; + size_t block_size = 0, block_header = 0; int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE; + size_t file_size = get_streamfile_size(streamFile); - /* find target block ID and skip the rest */ - file_size = get_streamfile_size(streamFile); while (block_offset < file_size) { - id = read_32bitBE(block_offset+0x00,streamFile); - block_size = read_32bit(block_offset+0x04,streamFile); /* includes id/size */ - block_header = 0x0; + uint32_t id = read_32bitBE(block_offset+0x00,streamFile); - if (id == 0x31534E68) { /* "1SNh" header block found */ - block_header = read_32bitBE(block_offset+0x08, streamFile) == 0x45414353 ? 0x28 : 0x2c; /* "EACS" */ - if (block_header < block_size) /* sometimes has data */ - break; + block_size = read_32bitLE(block_offset+0x04,streamFile); + if (block_size > 0x00F00000) /* BE in SAT, but one file may have both BE and LE chunks */ + block_size = read_32bitBE(block_offset+0x04,streamFile); + + block_header = 0; + + if (id == 0x31534E68 || id == 0x53454144) { /* "1SNh" "SEAD" audio header */ + int is_sead = (id == 0x53454144); + int is_eacs = read_32bitBE(block_offset+0x08, streamFile) == 0x45414353; + + block_header = is_eacs ? 0x28 : (is_sead ? 0x14 : 0x2c); + if (block_header >= block_size) /* sometimes has audio data after header */ + block_header = 0; } - - if (id == 0x31534E64) { /* "1SNd" data block found */ + else if (id == 0x31534E64 || id == 0x534E4443) { /* "1SNd" "SNDC" audio data */ block_header = 0x08; + } + else if (id == 0x00000000) { break; } - if (id == 0x00000000 || id == 0xFFFFFFFF) { /* EOF: possible? */ + if (block_header) { break; } - /* any other blocks "1SNl" "1SNe" etc */ //todo parse movie blocks block_offset += block_size; } @@ -45,6 +50,7 @@ void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream) { /* set new channel offsets and block sizes */ switch(vgmstream->coding_type) { case coding_PCM8_int: + case coding_ULAW_int: vgmstream->current_block_size /= vgmstream->channels; for (i=0;ichannels;i++) { vgmstream->ch[i].offset = block_offset + block_header + i; @@ -66,13 +72,24 @@ void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream) { break; case coding_DVI_IMA: - vgmstream->current_block_size -= 0x14; - for(i = 0; i < vgmstream->channels; i++) { - off_t adpcm_offset = block_offset + block_header + 0x04; - vgmstream->ch[i].adpcm_step_index = read_32bit(adpcm_offset + i*0x04, streamFile); - vgmstream->ch[i].adpcm_history1_32 = read_32bit(adpcm_offset + 0x04*vgmstream->channels + i*0x04, streamFile); - // todo some demuxed vids don't have ADPCM hist? not sure how to correctly detect - vgmstream->ch[i].offset = block_offset + block_header + 0x14; + if (vgmstream->codec_version == 1) { /* ADPCM hist */ + vgmstream->current_block_samples = read_32bit(block_offset + block_header, streamFile); + vgmstream->current_block_size = 0; // - (0x04 + 0x08*vgmstream->channels); /* should be equivalent */ + + for(i = 0; i < vgmstream->channels; i++) { + off_t adpcm_offset = block_offset + block_header + 0x04; + vgmstream->ch[i].adpcm_step_index = read_32bit(adpcm_offset + i*0x04 + 0x00*vgmstream->channels, streamFile); + vgmstream->ch[i].adpcm_history1_32 = read_32bit(adpcm_offset + i*0x04 + 0x04*vgmstream->channels, streamFile); + vgmstream->ch[i].offset = adpcm_offset + 0x08*vgmstream->channels; + } + + VGM_ASSERT(vgmstream->current_block_samples != (block_size - block_header - 0x04 - 0x08*vgmstream->channels) * 2 / vgmstream->channels, + "EA 1SHN blocked: different expected vs block num samples at %lx\n", block_offset); + } + else { + for(i = 0; i < vgmstream->channels; i++) { + vgmstream->ch[i].offset = block_offset + block_header; + } } break; diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c index 39c8f2648..5e222339c 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c @@ -4,66 +4,58 @@ /* set up for the block at the given offset */ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { + STREAMFILE* streamFile = vgmstream->ch[0].streamfile; int i; int new_schl = 0; - STREAMFILE* streamFile = vgmstream->ch[0].streamfile; - uint32_t id; - size_t file_size, block_size = 0, block_samples; + size_t block_size = 0, block_samples = 0; int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE; - //int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE; + size_t file_size = get_streamfile_size(streamFile); - /* find target block ID and skip the rest */ - file_size = get_streamfile_size(streamFile); while (block_offset < file_size) { - id = read_32bitBE(block_offset+0x00,streamFile); + uint32_t id = read_32bitBE(block_offset+0x00,streamFile); block_size = read_32bitLE(block_offset+0x04,streamFile); - if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */ + if (block_size > 0x00F00000) /* size is always LE, except in early SAT/MAC */ block_size = read_32bitBE(block_offset+0x04,streamFile); - /* SCxx blocks have size in the header, but others may not. To simplify we just try to find - * a SCDl (main data) every 0x04. EA sometimes concats many small files, so after a SCEl (end block) - * there may be a new SCHl + SCDl too, so this pretends they are a single stream. */ - if (id == 0x5343446C) { /* "SCDl" data block found */ + block_samples = 0; - /* use num_samples from header if possible; don't calc as data may have padding (ex. PCM8) or not possible (ex. MP3) */ + if (id == 0x5343446C || id == 0x5344454E) { /* "SCDl" "SDEN" audio data */ switch(vgmstream->coding_type) { case coding_PSX: block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels); break; - default: block_samples = read_32bit(block_offset+0x08,streamFile); break; } - - /* guard against false positives (happens in "pIQT" blocks) */ - if (block_size > 0xFFFF || block_samples > 0xFFFF) { /* observed max is ~0xf00 but who knows */ - block_offset += 0x04; - continue; - } - - break; } - else { - /* movie "pIQT" may be bigger than what block_size says, but seems to help */ - if (id == 0x5343486C || id == 0x5343436C || id == 0x53434C6C || id == 0x70495154) { /* "SCHl" "SCCl" "SCLl" "SCEl" "pIQT" */ - block_offset += block_size; - } else { - block_offset += 0x04; + else { /* any other chunk, audio ("SCHl" "SCCl" "SCLl" "SCEl" etc), or video ("pQGT" "pIQT "MADk" etc) */ + /* padding between "SCEl" and next "SCHl" (when subfiles exist) */ + if (id == 0x00000000) { + block_size = 0x04; } - if (id == 0x5343456C) { /* "SCEl" end block found */ - block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* 32b-aligned, important */ - /* Usually there is padding between SCEl and SCHl too (aligned to 0x80) */ - } - - if (id == 0x5343486C) { /* "SCHl", new subfile */ + if (id == 0x5343486C || id == 0x5348454E) { /* "SCHl" "SHEN" end block */ new_schl = 1; } + } - continue; + /* guard against errors (happens in bad rips/endianness, observed max is vid ~0x20000) */ + if (block_size == 0x00 || block_size > 0xFFFFF || block_samples > 0xFFFF) { + block_size = 0x04; + block_samples = 0; + } + + + if (block_samples) /* audio found */ + break; + block_offset += block_size; + + /* "SCEl" are aligned to 0x80 usually, but causes problems if not 32b-aligned (ex. Need for Speed 2 PC) */ + if ((id == 0x5343456C || id == 0x5345454E) && block_offset % 0x04) { + block_offset += 0x04 - (block_offset % 0x04); } } diff --git a/Frameworks/vgmstream/vgmstream/src/layout/xa_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/xa_blocked.c index b8bdd4f1c..bd208fd28 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/xa_blocked.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/xa_blocked.c @@ -8,13 +8,13 @@ void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream) { int8_t currentChannel=0; int8_t subAudio=0; - xa_init_get_high_nibble(vgmstream); + vgmstream->xa_get_high_nibble = 1; /* reset nibble order */ /* don't change this variable in the init process */ if (vgmstream->samples_into_block != 0) vgmstream->xa_sector_length += 0x80; - /* XA mode2/form2 sector + /* XA mode2/form2 sector, size 0x930 * 0x00: sync word * 0x0c: header = minute, second, sector, mode (always 0x02) * 0x10: subheader = file, channel (marker), submode flags, xa header @@ -23,9 +23,10 @@ void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream) { * 0x918: unused * 0x92c: EDC/checksum or null * 0x930: end + * (in non-blocked ISO 2048 mode1/data chunks are 0x800) */ - /* submode flags (typical audio value = 0x64) + /* submode flag bits (typical audio value = 0x64) * - 7: end of file * - 6: real time mode * - 5: sector form (0=form1, 1=form2) diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ahx.c b/Frameworks/vgmstream/vgmstream/src/meta/ahx.c index a1e2ac250..516773e02 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ahx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ahx.c @@ -64,7 +64,7 @@ VGMSTREAM * init_vgmstream_ahx(STREAMFILE *streamFile) { } vgmstream->layout_type = layout_none; - vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, start_offset, &vgmstream->coding_type, channel_count, MPEG_AHX, &cfg); + vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, channel_count, MPEG_AHX, &cfg); if (!vgmstream->codec_data) goto fail; #else goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/awc.c b/Frameworks/vgmstream/vgmstream/src/meta/awc.c index 4d3bf847d..ab2a605bd 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/awc.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/awc.c @@ -74,7 +74,7 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) { cfg.chunk_size = awc.block_chunk; cfg.big_endian = awc.big_endian; - vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, awc.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_AWC, &cfg); + vgmstream->codec_data = init_mpeg_custom(streamFile, awc.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_AWC, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_none; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_1snh.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_1snh.c index bce32875f..d4b7317c3 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_1snh.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_1snh.c @@ -3,7 +3,7 @@ #include "../layout/layout.h" #define EA_CODEC_PCM 0x00 -//#define EA_CODEC_??? 0x01 //used in SAT videos +#define EA_CODEC_ULAW 0x01 #define EA_CODEC_IMA 0x02 #define EA_CODEC_PSX 0xFF //fake value @@ -20,10 +20,13 @@ typedef struct { int big_endian; int loop_flag; + int is_sead; + int codec_version; } ea_header; static int parse_header(STREAMFILE* streamFile, ea_header* ea, off_t begin_offset); -static void set_ea_1snh_psx_samples(STREAMFILE* streamFile, off_t start_offset, ea_header* ea); +static void set_ea_1snh_num_samples(STREAMFILE* streamFile, off_t start_offset, ea_header* ea); +static int get_ea_1snh_ima_version(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea); /* EA 1SNh - from early EA games (~1996, ex. Need for Speed) */ VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE *streamFile) { @@ -37,9 +40,15 @@ VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE *streamFile) { goto fail; /* check header (first block) */ - if (read_32bitBE(0,streamFile)!=0x31534E68) /* "1SNh" */ + if (read_32bitBE(0x00,streamFile) != 0x31534E68 && /* "1SNh" */ + read_32bitBE(0x00,streamFile) != 0x53454144) /* "SEAD" */ goto fail; + /* stream is divided into blocks/chunks: 1SNh=audio header, 1SNd=data xN, 1SNl=loop end, 1SNe=end. + * Video uses various blocks (kVGT/fVGT/etc) and sometimes alt audio blocks (SEAD/SNDC/SEND). */ + + ea.is_sead = read_32bitBE(0x00,streamFile) == 0x53454144; + /* use block size as endian marker (Saturn = BE) */ ea.big_endian = !(read_32bitLE(0x04,streamFile) < 0x0000FFFF); @@ -63,16 +72,22 @@ VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE *streamFile) { vgmstream->meta_type = meta_EA_1SNH; switch (ea.codec) { - case EA_CODEC_PCM: + case EA_CODEC_PCM: /* Need for Speed (PC) */ vgmstream->coding_type = ea.bits==1 ? coding_PCM8_int : coding_PCM16_int; break; - case EA_CODEC_IMA: - if (ea.bits!=2) goto fail; - vgmstream->coding_type = coding_DVI_IMA; /* stereo/mono, high nibble first */ + case EA_CODEC_ULAW: /* Crusader: No Remorse movies (SAT), FIFA 96 movies (SAT) */ + if (ea.bits && ea.bits!=2) goto fail; /* only set in EACS */ + vgmstream->coding_type = coding_ULAW_int; break; - case EA_CODEC_PSX: + case EA_CODEC_IMA: /* Need for Speed II (PC) */ + if (ea.bits && ea.bits!=2) goto fail; /* only in EACS */ + vgmstream->coding_type = coding_DVI_IMA; /* stereo/mono, high nibble first */ + vgmstream->codec_version = ea.codec_version; + break; + + case EA_CODEC_PSX: /* Need for Speed (PS) */ vgmstream->coding_type = coding_PSX; break; @@ -98,7 +113,7 @@ static int parse_header(STREAMFILE* streamFile, ea_header* ea, off_t offset) { int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE; if (read_32bitBE(offset+0x00, streamFile) == 0x45414353) { /* "EACS" */ - /* PC/SAT EACS subheader */ + /* EACS subheader (PC, SAT) */ ea->sample_rate = read_32bit(offset+0x04, streamFile); ea->bits = read_8bit(offset+0x08, streamFile); ea->channels = read_8bit(offset+0x09, streamFile); @@ -109,15 +124,32 @@ static int parse_header(STREAMFILE* streamFile, ea_header* ea, off_t offset) { ea->loop_end = read_32bit(offset+0x14, streamFile) + ea->loop_start; /* loop length */ /* 0x18: data start? (0x00), 0x1c: pan/volume/etc? (0x7F), rest can be padding/garbage */ VGM_ASSERT(ea->type != 0, "EA EACS: unknown type\n"); /* block type? */ + + if (ea->codec == EA_CODEC_IMA) + ea->codec_version = get_ea_1snh_ima_version(streamFile, 0x00, ea); + } + else if (ea->is_sead) { + /* alt subheader (found in some PC videos) */ + ea->sample_rate = read_32bit(offset+0x00, streamFile); + ea->channels = read_32bit(offset+0x04, streamFile); + ea->codec = read_32bit(offset+0x08, streamFile); + + if (ea->codec == EA_CODEC_IMA) + ea->codec_version = get_ea_1snh_ima_version(streamFile, 0x00, ea); + + set_ea_1snh_num_samples(streamFile, 0x00, ea); + if (ea->loop_start_offset) /* offset found, now find actual start sample */ + set_ea_1snh_num_samples(streamFile, 0x00, ea); } else { - /* PS subheader */ + /* alt subheader (PS) */ ea->sample_rate = read_32bit(offset+0x00, streamFile); ea->channels = read_8bit(offset+0x18, streamFile); ea->codec = EA_CODEC_PSX; - set_ea_1snh_psx_samples(streamFile, 0x00, ea); - if (ea->loop_start_offset)/* found offset, now find sample start */ - set_ea_1snh_psx_samples(streamFile, 0x00, ea); + + set_ea_1snh_num_samples(streamFile, 0x00, ea); + if (ea->loop_start_offset) /* offset found, now find actual start sample */ + set_ea_1snh_num_samples(streamFile, 0x00, ea); } ea->loop_flag = (ea->loop_end > 0); @@ -126,42 +158,61 @@ static int parse_header(STREAMFILE* streamFile, ea_header* ea, off_t offset) { } /* get total samples by parsing block headers, needed when EACS isn't present */ -static void set_ea_1snh_psx_samples(STREAMFILE* streamFile, off_t start_offset, ea_header* ea) { +static void set_ea_1snh_num_samples(STREAMFILE* streamFile, off_t start_offset, ea_header* ea) { int num_samples = 0, loop_start = 0, loop_end = 0, loop_start_offset = 0; off_t block_offset = start_offset; - size_t file_size = get_streamfile_size(streamFile); + size_t block_size, block_header, block_samples; int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE; + size_t file_size = get_streamfile_size(streamFile); + while (block_offset < file_size) { uint32_t id = read_32bitBE(block_offset+0x00,streamFile); - size_t block_size = read_32bit(block_offset+0x04,streamFile); /* includes id/size */ + block_size = read_32bit(block_offset+0x04,streamFile); + block_header = 0; + block_samples = 0; - if (id == 0x31534E68) { /* "1SNh" header block found */ - size_t block_header = read_32bitBE(block_offset+0x08, streamFile) == 0x45414353 ? 0x28 : 0x2c; /* "EACS" */ - if (block_header < block_size) /* sometimes has data */ - num_samples += ps_bytes_to_samples(block_size - block_header, ea->channels); + if (id == 0x31534E68 || id == 0x53454144) { /* "1SNh" "SEAD" audio header */ + int is_sead = (id == 0x53454144); + int is_eacs = read_32bitBE(block_offset+0x08, streamFile) == 0x45414353; + + block_header = is_eacs ? 0x28 : (is_sead ? 0x14 : 0x2c); + if (block_header >= block_size) /* sometimes has audio data after header */ + block_header = 0; } - - if (id == 0x31534E64) { /* "1SNd" data block found */ - num_samples += ps_bytes_to_samples(block_size - 0x08, ea->channels); + else if (id == 0x31534E64 || id == 0x534E4443) { /* "1SNd" "SNDC" audio data */ + block_header = 0x08; } - - if (id == 0x31534E6C) { /* "1SNl" loop point found */ + else if (id == 0x00000000) { + break; + } + else if (id == 0x31534E6C) { /* "1SNl" loop point found */ loop_start_offset = read_32bit(block_offset+0x08,streamFile); loop_end = num_samples; } - if (id == 0x00000000 || id == 0xFFFFFFFF) { /* EOF: possible? */ - break; + if (block_header) { + switch(ea->codec) { + case EA_CODEC_PSX: + block_samples = ps_bytes_to_samples(block_size - block_header, ea->channels); + break; + case EA_CODEC_IMA: + if (ea->codec_version == 1) + block_samples = read_32bit(block_offset + block_header, streamFile); + else + block_samples = ima_bytes_to_samples(block_size - block_header, ea->channels); + break; + } } - /* if there is a loop start offset this was called again just to find it */ + + /* if there is a loop start offset set, this was called again just to find it */ if (ea->loop_start_offset && ea->loop_start_offset == block_offset) { ea->loop_start = num_samples; return; } - /* any other blocks "1SNl" "1SNe" etc */ //todo parse movie blocks + num_samples += block_samples; block_offset += block_size; } @@ -171,3 +222,31 @@ static void set_ea_1snh_psx_samples(STREAMFILE* streamFile, off_t start_offset, ea->loop_end = loop_end; ea->loop_start_offset = loop_start_offset; } + +/* find codec version used, with or without ADPCM hist per block */ +static int get_ea_1snh_ima_version(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea) { + off_t block_offset = start_offset; + size_t file_size = get_streamfile_size(streamFile); + int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE; + + while (block_offset < file_size) { + uint32_t id = read_32bitBE(block_offset+0x00,streamFile); + + size_t block_size = read_32bitLE(block_offset+0x04,streamFile); + if (block_size > 0x00F00000) /* BE in SAT, but one file may have both BE and LE chunks */ + block_size = read_32bitBE(block_offset+0x04,streamFile); + + if (id == 0x31534E64 || id == 0x534E4443) { /* "1SNd" "SNDC" audio data */ + size_t ima_samples = read_32bit(block_offset + 0x08, streamFile); + size_t expected_samples = (block_size - 0x08 - 0x04 - 0x08*ea->channels) * 2 / ea->channels; + + if (ima_samples == expected_samples) { + return 1; /* has ADPCM hist (hopefully) */ + } + } + + block_offset += block_size; + } + + return 0; /* no ADPCM hist */ +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c index 03eb0ebda..534350afe 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c @@ -214,18 +214,36 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST mpeg_custom_t type = (codec == 0x05 ? MPEG_EAL31b : (codec == 0x06) ? MPEG_EAL32P : MPEG_EAL32S); /* layout is still blocks, but should work fine with the custom mpeg decoder */ - vgmstream->codec_data = init_mpeg_custom_codec_data(streamData, mpeg_start_offset, &vgmstream->coding_type, vgmstream->channels, type, &cfg); + vgmstream->codec_data = init_mpeg_custom(streamData, mpeg_start_offset, &vgmstream->coding_type, vgmstream->channels, type, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_blocked_ea_sns; break; } #endif + +#if 0 //todo unknown variation +#ifdef VGM_USE_ATRAC9 + case 0x0a: { /* EATrax */ + atrac9_config cfg = {0}; + + cfg.channels = vgmstream->channels; + cfg.config_data = read_32bitBE(header_offset + 0x08,streamHead); + /* 0x0c: data size without blocks?, 0x10: frame size? (same as config data?) */ + + vgmstream->codec_data = init_atrac9(&cfg); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_ATRAC9; + vgmstream->layout_type = layout_blocked_ea_sns; + break; + } +#endif +#endif + case 0x00: /* "NONE" (internal 'codec not set' flag) */ case 0x01: /* not used/reserved? Gca0/MP30/P6L0/P2B0/P2L0/P8S0/P8U0/PFN0? */ case 0x08: /* ? */ case 0x09: /* EASpeex (libspeex variant, base versions vary: 1.0.5, 1.2beta3) */ - case 0x0a: /* EATrax (ATRAC9 variant, has deflated fillers a la EA-XMA) */ case 0x0b: /* ? */ case 0x0c: /* EAOpus (inside each SNS/SPS block is 16b frame size + standard? Opus packet) */ case 0x0d: /* ? */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c index 5c409da92..e8cfa8a9a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c @@ -28,7 +28,7 @@ #define EA_CODEC1_NONE -1 #define EA_CODEC1_PCM 0x00 #define EA_CODEC1_VAG 0x01 // unsure -#define EA_CODEC1_EAXA 0x07 // Need for Speed 2 PC, Fifa 98 SAT +#define EA_CODEC1_EAXA 0x07 // Need for Speed 2 PC, FIFA 98 SAT #define EA_CODEC1_MT10 0x09 //#define EA_CODEC1_N64 ? @@ -91,12 +91,14 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) { goto fail; /* check header */ - /* EA's stream files are made of blocks called "chunks" (SCxx, presumably Sound Chunk xx) - * typically: SCHl=header, SCCl=count of SCDl, SCDl=data xN, SCLl=loop end, SCEl=stream end. - * The number/size of blocks is affected by: block rate setting, sample rate, channels, CPU location (SPU/main/DSP/others), etc */ - if (read_32bitBE(0x00,streamFile) != 0x5343486C) /* "SCHl" */ + if (read_32bitBE(0x00,streamFile) != 0x5343486C && /* "SCHl" */ + read_32bitBE(0x00,streamFile) != 0x5348454E) /* "SHEN" */ goto fail; + /* stream is divided into blocks/chunks: SCHl=audio header, SCCl=count of SCDl, SCDl=data xN, SCLl=loop end, SCEl=end. + * Video uses various blocks (MVhd/MV0K/etc) and sometimes alt audio blocks (SHEN/SDEN/SEEN). + * The number/size is affected by: block rate setting, sample rate, channels, CPU location (SPU/main/DSP/others), etc */ + header_size = read_32bitLE(0x04,streamFile); if (header_size > 0x00F00000) /* size is always LE, except in early SS/MAC */ header_size = read_32bitBE(0x04,streamFile); @@ -318,7 +320,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_ if (!mpeg_start_offset) goto fail; /* layout is still blocks, but should work fine with the custom mpeg decoder */ - vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, mpeg_start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_EA, &cfg); + vgmstream->codec_data = init_mpeg_custom(streamFile, mpeg_start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_EA, &cfg); if (!vgmstream->codec_data) goto fail; break; } @@ -331,7 +333,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_ if (!mpeg_start_offset) goto fail; /* layout is still blocks, but should work fine with the custom mpeg decoder */ - vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, mpeg_start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_EAL31, &cfg); + vgmstream->codec_data = init_mpeg_custom(streamFile, mpeg_start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_EAL31, &cfg); if (!vgmstream->codec_data) goto fail; break; } @@ -451,7 +453,7 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be memset(ea,0,sizeof(ea_header)); /* null defaults as 0 can be valid */ - ea->version = EA_VERSION_NONE; + ea->version = EA_VERSION_NONE; ea->codec1 = EA_CODEC1_NONE; ea->codec2 = EA_CODEC2_NONE; @@ -747,70 +749,73 @@ fail: return 0; } -/* get total samples by parsing block headers, needed when multiple files are stitched together */ -/* Some EA files (.mus, .eam, .sng, etc) concat many small subfiles, used as mapped - * music (.map/lin). We get total possible samples (counting all subfiles) and pretend - * they are a single stream. Subfiles always share header, except num_samples. */ +/* Get total samples by parsing block headers, needed when multiple files are stitched together. + * Some EA files (.mus/eam/sng/etc) concat many small subfiles, used for interactive/mapped + * music (.map/lin). Subfiles always share header, except num_samples. */ static int get_ea_stream_total_samples(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea) { int num_samples = 0; - size_t file_size = get_streamfile_size(streamFile); + int new_schl = 0; off_t block_offset = start_offset; + size_t block_size, block_samples; int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE; + size_t file_size = get_streamfile_size(streamFile); + while (block_offset < file_size) { - uint32_t id, block_size, block_samples; - - id = read_32bitBE(block_offset+0x00,streamFile); + uint32_t id = read_32bitBE(block_offset+0x00,streamFile); block_size = read_32bitLE(block_offset+0x04,streamFile); - if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */ + if (block_size > 0x00F00000) /* size is always LE, except in early SAT/MAC */ block_size = read_32bitBE(block_offset+0x04,streamFile); - /* SCxx blocks have size in the header, but others may not. To simplify we just try to - * find a SCDl (main data) every 0x04. EA sometimes concats many small files, so after a SCEl (end block) - * there may be a new SCHl + SCDl too, so this pretends they are a single stream. */ - if (id == 0x5343446C) { /* "SCDl" data block found */ + block_samples = 0; - /* use num_samples from header if possible */ + if (id == 0x5343446C || id == 0x5344454E) { /* "SCDl" "SDEN" audio data */ switch (ea->codec2) { - case EA_CODEC2_VAG: /* PS-ADPCM */ + case EA_CODEC2_VAG: block_samples = ps_bytes_to_samples(block_size-0x10, ea->channels); break; - default: block_samples = read_32bit(block_offset+0x08,streamFile); break; } - - /* guard against false positives (happens in "pIQT" blocks) */ - if (block_size > 0xFFFF || block_samples > 0xFFFF) { /* observed max is ~0xf00 but who knows */ - block_offset += 0x04; - continue; - } - - num_samples += block_samples; - - block_offset += block_size; /* size includes header */ } - else { - /* movie "pIQT" may be bigger than what block_size says, but seems to help */ - if (id == 0x5343486C || id == 0x5343436C || id == 0x53434C6C || id == 0x70495154) { /* "SCHl" "SCCl" "SCLl" "SCEl" "pIQT" */ - block_offset += block_size; - } else { - block_offset += 0x04; + else { /* any other chunk, audio ("SCHl" "SCCl" "SCLl" "SCEl" etc), or video ("pQGT" "pIQT "MADk" "MPCh" etc) */ + /* padding between "SCEl" and next "SCHl" (when subfiles exist) */ + if (id == 0x00000000) { + block_size = 0x04; } - if (id == 0x5343456C) { /* "SCEl" end block found */ - /* Usually there is padding between SCEl and SCHl (aligned to 0x80) */ - block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* also 32b-aligned, important */ + if (id == 0x5343486C || id == 0x5348454E) { /* "SCHl" "SHEN" end block */ + new_schl = 1; } + } - block_offset += 0x04; - continue; + /* guard against errors (happens in bad rips/endianness, observed max is vid ~0x20000) */ + if (block_size == 0x00 || block_size > 0xFFFFF || block_samples > 0xFFFF) { + VGM_LOG("EA SCHl: bad block size %x at %lx\n", block_size, block_offset); + block_size = 0x04; + block_samples = 0; + } + + num_samples += block_samples; + block_offset += block_size; + + /* "SCEl" are aligned to 0x80 usually, but causes problems if not 32b-aligned (ex. Need for Speed 2 PC) */ + if ((id == 0x5343456C || id == 0x5345454E) && block_offset % 0x04) { + VGM_LOG_ONCE("EA SCHl: mis-aligned end offset found\n"); + block_offset += 0x04 - (block_offset % 0x04); } } - return num_samples; + /* only use calculated samples with multiple subfiles (rarely header samples may be less due to padding) */ + if (new_schl) { + ;VGM_LOG("EA SCHl: multiple SCHl found\n"); + return num_samples; + } + else { + return 0; + } } /* find data start offset inside the first SCDl; not very elegant but oh well */ @@ -825,7 +830,7 @@ static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* streamFile, off_t start id = read_32bitBE(block_offset+0x00,streamFile); block_size = read_32bitLE(block_offset+0x04,streamFile); - if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */ + if (block_size > 0x00F00000) /* size is always LE, except in early SAT/MAC */ block_size = read_32bitBE(block_offset+0x04,streamFile); if (id == 0x5343446C) { /* "SCDl" data block found */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb.c index 388cad2e7..5b0e12e7e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb.c @@ -296,7 +296,7 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) { //VGM_ASSERT(fsbh.mode & FSOUND_MPEG_LAYER2, "FSB FSOUND_MPEG_LAYER2 found\n");/* not always set anyway */ VGM_ASSERT(fsbh.mode & FSOUND_IGNORETAGS, "FSB FSOUND_IGNORETAGS found\n"); - vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg); + vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_none; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c index c648db712..a29fa70e2 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c @@ -6,37 +6,42 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t StartOffset = 0, NameOffset = 0; - off_t SampleHeaderStart = 0, DSPInfoStart = 0; - size_t SampleHeaderLength, NameTableLength, SampleDataLength, BaseHeaderLength, StreamSize = 0; + off_t SampleHeaderStart = 0, ExtraInfoStart = 0; + size_t SampleHeaderLength, NameTableLength, SampleDataLength, BaseHeaderLength, StreamSize = 0, ExtraInfoSize = 0; uint32_t NumSamples = 0, LoopStart = 0, LoopEnd = 0; - int LoopFlag = 0, ChannelCount = 0, SampleRate = 0, CodingID; + int LoopFlag = 0, ChannelCount = 0, Version, SampleRate = 0, CodingID; int TotalStreams, TargetStream = streamFile->stream_index; - uint32_t VorbisSetupId = 0; int i; /* check extension, case insensitive */ - if (!check_extensions(streamFile,"fsb")) goto fail; + if (!check_extensions(streamFile,"fsb")) + goto fail; - if (read_32bitBE(0x00,streamFile) != 0x46534235) goto fail; /* "FSB5" */ + if (read_32bitBE(0x00,streamFile) != 0x46534235) /* "FSB5" */ + goto fail; - //v0 has extra flags at 0x1c and BaseHeaderLength = 0x40? - if (read_32bitLE(0x04,streamFile) != 0x01) goto fail; /* Version ID */ + /* 0x00 is rare (seen in Tales from Space Vita) */ + Version = read_32bitLE(0x04,streamFile); + if (Version != 0x00 && Version != 0x01) goto fail; TotalStreams = read_32bitLE(0x08,streamFile); SampleHeaderLength = read_32bitLE(0x0C,streamFile); NameTableLength = read_32bitLE(0x10,streamFile); SampleDataLength = read_32bitLE(0x14,streamFile); CodingID = read_32bitLE(0x18,streamFile); - /* 0x1c (8): zero, 0x24 (16): hash, 0x34 (8): unk */ - BaseHeaderLength = 0x3C; + /* type 0x01 - 0x1c(8): zero, 0x24(16): hash, 0x34(8): unk + * type 0x00 has an extra field (always 0?) at 0x1c */ + BaseHeaderLength = (Version==0x00) ? 0x40 : 0x3C; - SampleHeaderStart = BaseHeaderLength; + if ((SampleHeaderLength + NameTableLength + SampleDataLength + BaseHeaderLength) != get_streamfile_size(streamFile)) + goto fail; - if ((SampleHeaderLength + NameTableLength + SampleDataLength + 0x3C) != get_streamfile_size(streamFile)) goto fail; if (TargetStream == 0) TargetStream = 1; /* default to 1 */ if (TargetStream > TotalStreams || TotalStreams <= 0) goto fail; + SampleHeaderStart = BaseHeaderLength; + /* find target stream header and data offset, and read all needed values for later use * (reads one by one as the size of a single stream header is variable) */ for (i = 1; i <= TotalStreams; i++) { @@ -113,18 +118,23 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { break; case 0x04: /* free comment, or maybe SFX info */ break; + //case 0x05: /* Unknown (32b) */ + // /* found in Tearaway Vita, value 0, first stream only */ + // break; case 0x06: /* XMA seek table */ /* no need for it */ break; - case 0x07: /* DSP Info (Coeffs) */ - DSPInfoStart = ExtraFlagStart + 0x04; + case 0x07: /* DSP coeffs */ + ExtraInfoStart = ExtraFlagStart + 0x04; break; - case 0x09: /* ATRAC9 data */ + case 0x09: /* ATRAC9 config */ + ExtraInfoStart = ExtraFlagStart + 0x04; + ExtraInfoSize = ExtraFlagSize; break; case 0x0a: /* XWMA data */ break; - case 0x0b: /* Vorbis data */ - VorbisSetupId = (uint32_t)read_32bitLE(ExtraFlagStart+0x04,streamFile); /* crc32? */ + case 0x0b: /* Vorbis setup ID and seek table */ + ExtraInfoStart = ExtraFlagStart + 0x04; /* seek table format: * 0x08: table_size (total_entries = seek_table_size / (4+4)), not counting this value; can be 0 * 0x0C: sample number (only some samples are saved in the table) @@ -132,7 +142,8 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { * (xN entries) */ break; - //case 0x0d: /* Unknown value (32b), found in some XMA2 and Vorbis */ + //case 0x0d: /* Unknown (32b) */ + // /* found in some XMA2 and Vorbis */ // break; default: VGM_LOG("FSB5: unknown extra flag 0x%x at 0x%04x (size 0x%x)\n", ExtraFlagType, ExtraFlagStart, ExtraFlagSize); @@ -221,7 +232,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = 0x02; - dsp_read_coefs_be(vgmstream,streamFile,DSPInfoStart,0x2E); + dsp_read_coefs_be(vgmstream,streamFile,ExtraInfoStart,0x2E); break; case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM */ @@ -263,7 +274,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */ - vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, StartOffset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg); + vgmstream->codec_data = init_mpeg_custom(streamFile, StartOffset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_none; break; @@ -272,8 +283,36 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { case 0x0C: /* FMOD_SOUND_FORMAT_CELT */ goto fail; - case 0x0D: /* FMOD_SOUND_FORMAT_AT9 */ - goto fail; +#ifdef VGM_USE_ATRAC9 + case 0x0D: {/* FMOD_SOUND_FORMAT_AT9 */ + atrac9_config cfg = {0}; + + cfg.channels = vgmstream->channels; + switch(ExtraInfoSize) { + case 0x04: /* Little Big Planet 2ch (Vita), Guacamelee (Vita) */ + cfg.config_data = read_32bitBE(ExtraInfoStart,streamFile); + break; + case 0x08: /* Day of the Tentacle Remastered (Vita) */ + /* 0x00: superframe size (also in config_data) */ + cfg.config_data = read_32bitBE(ExtraInfoStart+0x04,streamFile); + break; + //case 0x0c: /* Little Big Planet 6ch (Vita) */ + // //todo: this is just 0x04 x3, in case of 4ch would be 0x08 --must improve detection + // //each stream has its own config_data (but seem to be the same), interleaves 1 super frame per stream + // break; + default: + VGM_LOG("FSB5: unknown extra info size 0x%x\n", ExtraInfoSize); + goto fail; + } + //cfg.encoder_delay = 0x100; //todo not used? num_samples seems to count all data + + vgmstream->codec_data = init_atrac9(&cfg); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_ATRAC9; + vgmstream->layout_type = layout_none; + break; + } +#endif case 0x0E: /* FMOD_SOUND_FORMAT_XWMA */ goto fail; @@ -284,11 +323,11 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { cfg.channels = vgmstream->channels; cfg.sample_rate = vgmstream->sample_rate; - cfg.setup_id = VorbisSetupId; + cfg.setup_id = read_32bitLE(ExtraInfoStart,streamFile); vgmstream->layout_type = layout_none; vgmstream->coding_type = coding_VORBIS_custom; - vgmstream->codec_data = init_vorbis_custom_codec_data(streamFile, StartOffset, VORBIS_FSB, &cfg); + vgmstream->codec_data = init_vorbis_custom(streamFile, StartOffset, VORBIS_FSB, &cfg); if (!vgmstream->codec_data) goto fail; break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/genh.c b/Frameworks/vgmstream/vgmstream/src/meta/genh.c index f42d442e7..d0a451da8 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/genh.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/genh.c @@ -239,7 +239,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { #ifdef VGM_USE_MPEG case coding_MPEG_layer3: vgmstream->layout_type = layout_none; - vgmstream->codec_data = init_mpeg_codec_data(streamFile, genh.start_offset, &coding, vgmstream->channels); + vgmstream->codec_data = init_mpeg(streamFile, genh.start_offset, &coding, vgmstream->channels); if (!vgmstream->codec_data) goto fail; break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/gtd.c b/Frameworks/vgmstream/vgmstream/src/meta/gtd.c index de7c5e13d..c334ad5cd 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/gtd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/gtd.c @@ -1,7 +1,7 @@ #include "meta.h" #include "../coding/coding.h" -typedef enum { XMA2 } gtd_codec; +typedef enum { XMA2, ATRAC9 } gtd_codec; /* GTD - found in Knights Contract (X360, PS3), Valhalla Knights 3 (PSV) */ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile) { @@ -10,6 +10,7 @@ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile) { size_t data_size, chunk_size; int loop_flag, channel_count, sample_rate; int num_samples, loop_start_sample, loop_end_sample; + uint32_t at9_config_data; gtd_codec codec; @@ -34,30 +35,41 @@ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile) { data_size = read_32bitBE(0x5c,streamFile); /* 0x34(18): null, 0x54(4): seek table offset, 0x58(4): seek table size, 0x5c(8): null, 0x64: seek table */ - stpr_offset = read_32bitBE(chunk_offset+0x54,streamFile) + read_32bitBE(chunk_offset+0x58,streamFile);; + stpr_offset = read_32bitBE(chunk_offset+0x54,streamFile) + read_32bitBE(chunk_offset+0x58,streamFile); if (read_32bitBE(stpr_offset,streamFile) == 0x53545052) { /* "STPR" */ name_offset = stpr_offset + 0xB8; /* there are offsets fields but seems to work */ } codec = XMA2; } + else if (0x34 + read_32bitLE(0x30,streamFile) + read_32bitLE(0x0c,streamFile) == get_streamfile_size(streamFile)) { /* ATRAC9 */ + + data_size = read_32bitLE(0x0c,streamFile); + start_offset = 0x34 + read_32bitLE(0x30,streamFile); + channel_count = read_32bitLE(0x10,streamFile); + sample_rate = read_32bitLE(0x14,streamFile); + at9_config_data = read_32bitBE(0x28,streamFile); + /* 0x18-0x28: fixed/unknown values */ + + stpr_offset = 0x2c; + if (read_32bitBE(stpr_offset,streamFile) == 0x53545052) { /* "STPR" */ + name_offset = stpr_offset + 0xE8; /* there are offsets fields but seems to work */ + } + + codec = ATRAC9; + } else { - /* there are PSV (LE, ATRAC9 data) and PS3 (MSF inside?) variations, somewhat-but-not-quite similar */ - - /* for PSV: */ - /* 0x0c: data_size, 0x10: channles, 0x14: sample rate, 0x18-0x2c: fixed and unknown values */ - /* 0x2c: STPR chunk, with name_offset at + 0xE8 */ - + /* apparently there is a PS3 variation (MSF inside?) */ goto fail; } + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = num_samples; vgmstream->loop_start_sample = loop_start_sample; vgmstream->loop_end_sample = loop_end_sample; vgmstream->meta_type = meta_GTD; @@ -77,9 +89,29 @@ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile) { if ( !vgmstream->codec_data ) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; + + vgmstream->num_samples = num_samples; break; } #endif +#ifdef VGM_USE_ATRAC9 + case ATRAC9: { + atrac9_config cfg = {0}; + + cfg.channels = vgmstream->channels; + cfg.config_data = at9_config_data; + + vgmstream->codec_data = init_atrac9(&cfg); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_ATRAC9; + vgmstream->layout_type = layout_none; + + vgmstream->num_samples = atrac9_bytes_to_samples(data_size, vgmstream->codec_data); + break; + } + +#endif + default: goto fail; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index 31af3f247..d83949070 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -147,7 +147,81 @@ static const hcakey_info hcakey_list[] = { // Kirara Fantasia (Android/iOS) {51408295487268137}, // 00B6A3928706E529 + // A3! (iOS/Android) + {914306251}, // 00000000367F34CB + + // Weekly Shonen Jump: Ore Collection! (iOS/Android) + {11708691}, // 0000000000B2A913 + + // Monster Gear Versus (iOS/Android) + {0xB1E30F346415B475}, // B1E30F346415B475 + + // Yumeiro Cast (iOS/Android) + {14418}, // 0000000000003852 + + // Ikki Tousen: Straight Striker (iOS/Android) + {1000}, // 00000000000003E8 + + // Zero kara Hajimeru Mahou no Sho (iOS/Android) + {0xD2E836E662F20000}, // D2E836E662F20000 + + // Soul Reverse Zero (iOS/Android) + {2873513618}, // 00000000AB465692 + + // Jojo's Bizarre Adventure: Diamond Records (iOS/Android) [additional data] + {0x820212864CAB35DE}, // 820212864CAB35DE + + // HUNTER x HUNTER: World Hunt (iOS/Android) + {71777214294589695}, // 00FF00FF00FF00FF + + // \Comepri/ Comedy Prince (iOS/Android) + {201537197868}, // 0000002EEC8D972C + + // Puzzle of Empires (iOS/Android) + {13687846}, // 0000000000D0DC26 + + // Aozora Under Girls! (iOS/Android) + {4988006236073}, // 000004895C56FFA9 + + // Castle & Dragon (iOS/Android) + {20140528}, // 00000000013351F0 + + // Uta no Prince sama Shining Live (iOS/Android) + {2122831366}, // 000000007E87D606 + + // Sevens Story (iOS/Android) + {629427372852}, // 000000928CCB8334 + + // MinGol: Everybody's Golf (iOS/Android) + {1430028151061218}, // 0005149A5FF67AE2 + + // AKB48 Group Tsui ni Koushiki Otoge demashita. (iOS/Android) + {831021912315111419}, // 0B886206BC1BA7FB + + // Sen no Kaizoku (iOS/Android) + {81368371967}, // 00000012F1EED2FF + + // I Chu (iOS/Android) + {13456}, // 0000000000003490 + + // Shinobi Nightmare (iOS/Android) + {369481198260487572}, // 0520A93135808594 + + // Bungo Stray Dogs: Mayoi Inu Kaikitan (iOS/Android) + {1655728931134731873}, // 16FA54B0C09F7661 + + // Super Sentai Legend Wars (iOS/Android) + {4017992759667450}, // 000E4657D7266AFA + + // Metal Saga: The Ark of Wastes (iOS/Android) + {100097101118097115}, // 01639DC87B30C6DB + + // Taga Tame no Alchemist (iOS/Android) + {5047159794308}, // 00000497222AAA84 + + // Shin Tennis no Ouji-sama: Rising Beat (iOS/Android) + {4902201417679}, // 0000047561F95FCF + }; - #endif/*_HCA_KEYS_H_*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ktss.c b/Frameworks/vgmstream/vgmstream/src/meta/ktss.c new file mode 100644 index 000000000..632285945 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/ktss.c @@ -0,0 +1,49 @@ +#include "meta.h" +#include "../util.h" +#include "../stack_alloc.h" +#include "../coding/coding.h" + +VGMSTREAM * init_vgmstream_ktss(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + int loop_flag, channel_count; + int32_t loop_length; + off_t start_offset; + + if (!check_extensions(streamFile, "ktss")) + goto fail; + + if (read_32bitBE(0, streamFile) != 0x4B545353) /* "KTSS" */ + goto fail; + + loop_length = read_32bitLE(0x38, streamFile); + loop_flag = loop_length > 0; + channel_count = read_8bit(0x29, streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count, loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = read_32bitLE(0x30, streamFile); + vgmstream->sample_rate = (uint16_t)read_16bitLE(0x2c, streamFile); + vgmstream->loop_start_sample = read_32bitLE(0x34, streamFile); + vgmstream->loop_end_sample = vgmstream->loop_start_sample + loop_length; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->meta_type = meta_KTSS; + + vgmstream->interleave_block_size = 0x8; + + dsp_read_coefs_le(vgmstream, streamFile, 0x40, 0x2e); + start_offset = read_32bitLE(0x24, streamFile) + 0x20; + + if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index bc0ba6b03..cd7a78c7a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -152,7 +152,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_rifx(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_xnbm(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_xnb(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_pos(STREAMFILE * streamFile); @@ -602,6 +602,7 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_kt_g1l(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_kt_wiibgm(STREAMFILE* streamFile); +VGMSTREAM * init_vgmstream_ktss(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_mca(STREAMFILE* streamFile); @@ -642,6 +643,7 @@ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ta_aac_x360(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ta_aac_ps3(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_ta_aac_mobile(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ps3_mta2(STREAMFILE *streamFile); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ngc_vid1.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_vid1.c index ec2576423..6e4120eb5 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_vid1.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ngc_vid1.c @@ -57,7 +57,7 @@ VGMSTREAM * init_vgmstream_ngc_vid1(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; vgmstream->coding_type = coding_VORBIS_custom; - vgmstream->codec_data = init_vorbis_custom_codec_data(streamFile, header_offset + 0x20, VORBIS_VID1, &cfg); + vgmstream->codec_data = init_vorbis_custom(streamFile, header_offset + 0x20, VORBIS_VID1, &cfg); if (!vgmstream->codec_data) goto fail; } #else diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis_file.c b/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis_file.c index fe3a9ba16..02aaade46 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis_file.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis_file.c @@ -189,7 +189,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { strcasecmp("ogg",filename_extension(filename))) { if (!strcasecmp("um3",filename_extension(filename))) { um3_ogg = 1; - } else if (!strcasecmp("kovs",filename_extension(filename))) { + } else if (check_extensions(streamFile,"kvs,kovs")) { /* .kvs: Atelier Sophie, kovs: header id only? */ kovs_ogg = 1; } else { goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ogl.c b/Frameworks/vgmstream/vgmstream/src/meta/ogl.c index 2f655b09f..66587b82c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ogl.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ogl.c @@ -46,7 +46,7 @@ VGMSTREAM * init_vgmstream_ogl(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; vgmstream->coding_type = coding_VORBIS_custom; - vgmstream->codec_data = init_vorbis_custom_codec_data(streamFile, 0x14, VORBIS_OGL, &cfg); + vgmstream->codec_data = init_vorbis_custom(streamFile, 0x14, VORBIS_OGL, &cfg); if (!vgmstream->codec_data) goto fail; start_offset = cfg.data_start_offset; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/p3d.c b/Frameworks/vgmstream/vgmstream/src/meta/p3d.c index 752e60148..7e5350a79 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/p3d.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/p3d.c @@ -151,7 +151,7 @@ VGMSTREAM * init_vgmstream_p3d(STREAMFILE *streamFile) { cfg.data_size = data_size; /* block_size * 3 = frame size (0x60*3=0x120 or 0x40*3=0xC0) but doesn't seem to have any significance) */ - vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_P3D, &cfg); + vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_P3D, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_none; break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps3_msf.c b/Frameworks/vgmstream/vgmstream/src/meta/ps3_msf.c index 2d3e4e72d..fc4e3cdba 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps3_msf.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps3_msf.c @@ -173,7 +173,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) { mpeg_codec_data *mpeg_data = NULL; coding_t ct; - mpeg_data = init_mpeg_codec_data(streamFile, start_offset, &ct, vgmstream->channels); + mpeg_data = init_mpeg(streamFile, start_offset, &ct, vgmstream->channels); if (!mpeg_data) goto fail; vgmstream->codec_data = mpeg_data; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff.c b/Frameworks/vgmstream/vgmstream/src/meta/riff.c index c7c4265b3..31412d5ec 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/riff.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff.c @@ -4,10 +4,10 @@ #include "../util.h" #include -/* Resource Interchange File Format */ +/* RIFF - Resource Interchange File Format, standard container used in many games */ /* return milliseconds */ -static long parse_marker(unsigned char * marker) { +static long parse_adtl_marker(unsigned char * marker) { long hh,mm,ss,ms; if (memcmp("Marker ",marker,7)) return -1; @@ -21,7 +21,6 @@ static long parse_marker(unsigned char * marker) { static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *streamFile, long *loop_start, long *loop_end, int *loop_flag) { int loop_start_found = 0; int loop_end_found = 0; - off_t current_chunk = adtl_offset+4; while (current_chunk < adtl_offset+adtl_length) { @@ -31,39 +30,31 @@ static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *stream if (current_chunk+8+chunk_size > adtl_offset+adtl_length) return; switch(chunk_type) { - case 0x6c61626c: /* labl */ - { - unsigned char *labelcontent; - labelcontent = malloc(chunk_size-4); - if (!labelcontent) return; - if (read_streamfile(labelcontent,current_chunk+0xc, - chunk_size-4,streamFile)!=chunk_size-4) { - free(labelcontent); - return; - } - - switch (read_32bitLE(current_chunk+8,streamFile)) { - case 1: - if (!loop_start_found && - (*loop_start = parse_marker(labelcontent))>=0) - { - loop_start_found = 1; - } - break; - case 2: - if (!loop_end_found && - (*loop_end = parse_marker(labelcontent))>=0) - { - loop_end_found = 1; - } - break; - default: - break; - } - + case 0x6c61626c: { /* labl */ + unsigned char *labelcontent; + labelcontent = malloc(chunk_size-4); + if (!labelcontent) return; + if (read_streamfile(labelcontent,current_chunk+0xc, chunk_size-4,streamFile)!=chunk_size-4) { free(labelcontent); + return; } + + switch (read_32bitLE(current_chunk+8,streamFile)) { + case 1: + if (!loop_start_found && (*loop_start = parse_adtl_marker(labelcontent))>=0) + loop_start_found = 1; + break; + case 2: + if (!loop_end_found && (*loop_end = parse_adtl_marker(labelcontent))>=0) + loop_end_found = 1; + break; + default: + break; + } + + free(labelcontent); break; + } default: break; } @@ -71,7 +62,8 @@ static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *stream current_chunk += 8 + chunk_size; } - if (loop_start_found && loop_end_found) *loop_flag = 1; + if (loop_start_found && loop_end_found) + *loop_flag = 1; /* labels don't seem to be consistently ordered */ if (*loop_start > *loop_end) { @@ -81,29 +73,21 @@ static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *stream } } -struct riff_fmt_chunk { +typedef struct { off_t offset; off_t size; int sample_rate; int channel_count; uint32_t block_size; + int coding_type; int interleave; -}; - -static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk, struct riff_fmt_chunk * fmt, int sns, int mwv) { +} riff_fmt_chunk; +static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk, riff_fmt_chunk * fmt, int sns, int mwv) { int codec, bps; - int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; - int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; - - if (big_endian) { - read_32bit = read_32bitBE; - read_16bit = read_16bitBE; - } else { - read_32bit = read_32bitLE; - read_16bit = read_16bitLE; - } + int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE; + int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE; fmt->offset = current_chunk; fmt->size = read_32bit(current_chunk+0x4,streamFile); @@ -111,6 +95,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk fmt->sample_rate = read_32bit(current_chunk+0x0c,streamFile); fmt->channel_count = read_16bit(current_chunk+0x0a,streamFile); fmt->block_size = read_16bit(current_chunk+0x14,streamFile); + fmt->interleave = 0; bps = read_16bit(current_chunk+0x16,streamFile); codec = (uint16_t)read_16bit(current_chunk+0x8,streamFile); @@ -119,11 +104,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk case 0x01: /* PCM */ switch (bps) { case 16: - if (big_endian) { - fmt->coding_type = coding_PCM16BE; - } else { - fmt->coding_type = coding_PCM16LE; - } + fmt->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE; fmt->interleave = 2; break; case 8: @@ -136,24 +117,18 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk break; case 0x02: /* MS ADPCM */ - if (bps != 4) /* ensure 4bps */ - goto fail; + if (bps != 4) goto fail; fmt->coding_type = coding_MSADPCM; - fmt->interleave = 0; break; case 0x11: /* MS IMA ADPCM */ - if (bps != 4) /* ensure 4bps */ - goto fail; + if (bps != 4) goto fail; fmt->coding_type = coding_MS_IMA; - fmt->interleave = 0; break; - case 0x69: /* MS IMA ADPCM - Rayman Raving Rabbids 2 (PC) */ - if (bps != 4) /* ensure 4bps */ - goto fail; + case 0x69: /* MS IMA ADPCM (XBOX) - Rayman Raving Rabbids 2 (PC) */ + if (bps != 4) goto fail; fmt->coding_type = coding_MS_IMA; - fmt->interleave = 0; break; case 0x007A: /* MS IMA ADPCM (LA Rush, Psi Ops PC) */ @@ -167,7 +142,6 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk goto fail; //fmt->coding_type = coding_MS_IMA_3BIT; else goto fail; - fmt->interleave = 0; break; case 0x0555: /* Level-5 0x555 ADPCM */ @@ -179,34 +153,51 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk case 0x5050: /* Ubisoft .sns uses this for DSP */ if (!sns) goto fail; fmt->coding_type = coding_NGC_DSP; - fmt->interleave = 8; + fmt->interleave = 0x08; break; + case 0x270: /* ATRAC3 */ #ifdef VGM_USE_FFMPEG - case 0x270: /* ATRAC3 */ -#if defined(VGM_USE_FFMPEG) && !defined(VGM_USE_MAIATRAC3PLUS) - case 0xFFFE: /* WAVEFORMATEXTENSIBLE / ATRAC3plus */ -#endif /* defined */ - fmt->coding_type = coding_FFmpeg; - fmt->interleave = 0; - break; -#endif /* VGM_USE_FFMPEG */ - -#ifdef VGM_USE_MAIATRAC3PLUS - case 0xFFFE: /* WAVEFORMATEXTENSIBLE / ATRAC3plus */ - if (read_32bit(current_chunk+0x20,streamFile) == 0xE923AABF && - read_16bit(current_chunk+0x24,streamFile) == (int16_t)0xCB58 && - read_16bit(current_chunk+0x26,streamFile) == 0x4471 && - read_32bitLE(current_chunk+0x28,streamFile) == 0xFAFF19A1 && - read_32bitLE(current_chunk+0x2C,streamFile) == 0x62CEE401) { - uint16_t bztmp = read_16bit(current_chunk+0x32,streamFile); - bztmp = (bztmp >> 8) | (bztmp << 8); - fmt->coding_type = coding_AT3plus; - fmt->block_size = (bztmp & 0x3FF) * 8 + 8; - fmt->interleave = 0; - } - break; + fmt->coding_type = coding_FFmpeg; + break; +#else + goto fail; #endif + + case 0xFFFE: /* WAVEFORMATEXTENSIBLE */ + + /* ATRAC3plus GUID (0xBFAA23E9 58CB7144 A119FFFA 01E4CE62) */ + if (read_32bit(current_chunk+0x20,streamFile) == 0xE923AABF && + read_16bit(current_chunk+0x24,streamFile) == (int16_t)0xCB58 && + read_16bit(current_chunk+0x26,streamFile) == 0x4471 && + read_32bitLE(current_chunk+0x28,streamFile) == 0xFAFF19A1 && + read_32bitLE(current_chunk+0x2C,streamFile) == 0x62CEE401) { +#ifdef VGM_USE_MAIATRAC3PLUS + uint16_t bztmp = read_16bit(current_chunk+0x32,streamFile); + bztmp = (bztmp >> 8) | (bztmp << 8); + fmt->coding_type = coding_AT3plus; + fmt->block_size = (bztmp & 0x3FF) * 8 + 8; //should match fmt->block_size +#elif defined(VGM_USE_FFMPEG) + fmt->coding_type = coding_FFmpeg; +#else + goto fail; +#endif + } + + /* ATRAC9 GUID 47E142D2-36BA-4d8d-88FC-61654F8C836C (D242E147 BA368D4D 88FC6165 4F8C836C) */ + if (read_32bitBE(current_chunk+0x20,streamFile) == 0xD242E147 && + read_32bitBE(current_chunk+0x24,streamFile) == 0xBA368D4D && + read_32bitBE(current_chunk+0x28,streamFile) == 0x88FC6165 && + read_32bitBE(current_chunk+0x2c,streamFile) == 0x4F8C836C) { +#ifdef VGM_USE_ATRAC9 + fmt->coding_type = coding_ATRAC9; +#else + goto fail; +#endif + } + + break; + default: goto fail; } @@ -219,82 +210,61 @@ fail: VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; + riff_fmt_chunk fmt = {0}; - struct riff_fmt_chunk fmt; + size_t file_size, riff_size, data_size = 0; + off_t start_offset = 0; -#ifdef VGM_USE_FFMPEG - ffmpeg_codec_data *ffmpeg_data = NULL; -#endif - - off_t file_size = -1; - int sample_count = 0; int fact_sample_count = -1; int fact_sample_skip = -1; - off_t start_offset = -1; int loop_flag = 0; long loop_start_ms = -1; long loop_end_ms = -1; off_t loop_start_offset = -1; off_t loop_end_offset = -1; - uint32_t riff_size; - uint32_t data_size = 0; int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0; - /* Level-5 mwv */ - int mwv = 0; + int mwv = 0; /* Level-5 .mwv (Dragon Quest VIII, Rogue Galaxy) */ off_t mwv_pflt_offset = -1; off_t mwv_ctrl_offset = -1; + int sns = 0; /* Ubisoft .sns LyN engine (Red Steel 2, Just Dance 3) */ + int at3 = 0; /* Sony ATRAC3 / ATRAC3plus */ + int at9 = 0; /* Sony ATRAC9 */ - /* Ubisoft sns */ - int sns = 0; - - /* Sony atrac3 / 3plus */ - int at3 = 0; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("wav",filename_extension(filename)) - && strcasecmp("lwav",filename_extension(filename)) - && strcasecmp("da",filename_extension(filename)) /* SD Gundam - Over Galaxian, The Great Battle VI (PS) */ - && strcasecmp("cd",filename_extension(filename)) /* Exector (PS) */ -#ifndef VGM_USE_FFMPEG - && strcasecmp("sgb",filename_extension(filename)) /* SGB has proper support with FFmpeg in sgxd */ -#endif - && strcasecmp("med",filename_extension(filename)) - ) - { - if (!strcasecmp("mwv",filename_extension(filename))) { - mwv = 1; - } - else if (!strcasecmp("sns",filename_extension(filename))) { - sns = 1; - } -#if defined(VGM_USE_MAIATRAC3PLUS) || defined(VGM_USE_FFMPEG) - /* .RWS: AT3 found in Climax games (Silent Hill Origins PSP, Oblivion PSP) - * .AUD: EA Replay */ - else if ( check_extensions(streamFile, "at3,rws,aud") ) { - at3 = 1; - } -#endif - else { - goto fail; - } + /* check extension, case insensitive + * .da: The Great Battle VI (PS), .cd: Exector (PS), .med: Psi Ops (PC) */ + if ( check_extensions(streamFile, "wav,lwav,da,cd,med") ) { + ; + } + else if ( check_extensions(streamFile, "mwv") ) { + mwv = 1; + } + else if ( check_extensions(streamFile, "sns") ) { + sns = 1; + } + /* .rws: Climax games (Silent Hill Origins PSP, Oblivion PSP), .aud: EA Replay */ + else if ( check_extensions(streamFile, "at3,rws,aud") ) { + at3 = 1; + } + else if ( check_extensions(streamFile, "at9") ) { + at9 = 1; + } + else { + goto fail; } /* check header */ - if ((uint32_t)read_32bitBE(0,streamFile)!=0x52494646) /* "RIFF" */ + if (read_32bitBE(0x00,streamFile) != 0x52494646) /* "RIFF" */ goto fail; - /* check for WAVE form */ - if ((uint32_t)read_32bitBE(8,streamFile)!=0x57415645) /* "WAVE" */ + if (read_32bitBE(0x08,streamFile) != 0x57415645) /* "WAVE" */ goto fail; - riff_size = read_32bitLE(4,streamFile); + riff_size = read_32bitLE(0x04,streamFile); file_size = get_streamfile_size(streamFile); - /* check for tructated RIFF */ + /* check for truncated RIFF */ if (file_size < riff_size+8) goto fail; /* read through chunks to verify format and find metadata */ @@ -344,42 +314,34 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { } break; case 0x736D706C: /* smpl */ - /* check loop count */ - if (read_32bitLE(current_chunk+0x24, streamFile)==1) - { - /* check loop info */ - if (read_32bitLE(current_chunk+0x2c+4, streamFile)==0) - { + /* check loop count and loop info */ + if (read_32bitLE(current_chunk+0x24, streamFile)==1) { + if (read_32bitLE(current_chunk+0x2c+4, streamFile)==0) { loop_flag = 1; - loop_start_offset = - read_32bitLE(current_chunk+0x2c+8, streamFile); - loop_end_offset = - read_32bitLE(current_chunk+0x2c+0xc,streamFile); + loop_start_offset = read_32bitLE(current_chunk+0x2c+8, streamFile); + loop_end_offset = read_32bitLE(current_chunk+0x2c+0xc,streamFile); } } break; case 0x70666c74: /* pflt */ if (!mwv) break; /* ignore if not in an mwv */ - /* predictor filters */ - mwv_pflt_offset = current_chunk; + + mwv_pflt_offset = current_chunk; /* predictor filters */ break; case 0x6374726c: /* ctrl */ - if (!mwv) break; /* ignore if not in an mwv */ - /* loops! */ - if (read_32bitLE(current_chunk+8, streamFile)) - { - loop_flag = 1; - } + if (!mwv) break; + + loop_flag = read_32bitLE(current_chunk+0x08, streamFile); mwv_ctrl_offset = current_chunk; break; case 0x66616374: /* fact */ if (sns && chunk_size == 0x10) { - fact_sample_count = read_32bitLE(current_chunk+0x8, streamFile); - } else if (at3 && chunk_size == 0x8) { - fact_sample_count = read_32bitLE(current_chunk+0x8, streamFile); - fact_sample_skip = read_32bitLE(current_chunk+0xc, streamFile); - } else if (at3 && chunk_size == 0xc) { - fact_sample_count = read_32bitLE(current_chunk+0x8, streamFile); + fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile); + } else if ((at3 || at9) && chunk_size == 0x08) { + fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile); + fact_sample_skip = read_32bitLE(current_chunk+0x0c, streamFile); + } else if ((at3 || at9) && chunk_size == 0x0c) { + fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile); fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile); } @@ -408,103 +370,136 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { goto fail; + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = fmt.sample_rate; + + /* init, samples */ switch (fmt.coding_type) { case coding_PCM16LE: - sample_count = data_size/2/fmt.channel_count; + vgmstream->num_samples = pcm_bytes_to_samples(data_size, fmt.channel_count, 16); break; case coding_PCM8_U_int: - sample_count = data_size/fmt.channel_count; + vgmstream->num_samples = pcm_bytes_to_samples(data_size, vgmstream->channels, 8); break; case coding_L5_555: - sample_count = data_size/0x12/fmt.channel_count*32; - break; - case coding_MSADPCM: - sample_count = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count); - break; - case coding_MS_IMA: - sample_count = (data_size / fmt.block_size) * (fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count + - ((data_size % fmt.block_size) ? (data_size % fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count : 0); - break; - case coding_NGC_DSP: - //sample_count = data_size / fmt.channel_count / 8 * 14; /* expected from the "fact" chunk */ - break; -#ifdef VGM_USE_FFMPEG - case coding_FFmpeg: - { - ffmpeg_data = init_ffmpeg_offset(streamFile, 0, streamFile->get_size(streamFile) ); - if ( !ffmpeg_data ) goto fail; + vgmstream->num_samples = data_size / 0x12 / fmt.channel_count * 32; - sample_count = ffmpeg_data->totalSamples; /* fact_sample_count */ + /* coefs */ + if (mwv) { + int i, ch; + const int filter_order = 3; + int filter_count = read_32bitLE(mwv_pflt_offset+0x0c, streamFile); + if (filter_count > 0x20) goto fail; - if (at3) { - /* the encoder introduces some garbage (not always silent) samples to skip before the stream */ - /* manually set skip_samples if FFmpeg didn't do it */ - if (ffmpeg_data->skipSamples <= 0) { - ffmpeg_set_skip_samples(ffmpeg_data, fact_sample_skip); - } + if (mwv_pflt_offset == -1 || + read_32bitLE(mwv_pflt_offset+0x08, streamFile) != filter_order || + read_32bitLE(mwv_pflt_offset+0x04, streamFile) < 8 + filter_count * 4 * filter_order) + goto fail; - /* RIFF loop/sample values are absolute (with skip samples), adjust */ - if (loop_flag) { - loop_start_offset -= ffmpeg_data->skipSamples; - loop_end_offset -= ffmpeg_data->skipSamples; + for (ch = 0; ch < fmt.channel_count; ch++) { + for (i = 0; i < filter_count * filter_order; i++) { + int coef = read_32bitLE(mwv_pflt_offset+0x10+i*0x04, streamFile); + vgmstream->ch[ch].adpcm_coef_3by32[i] = coef; } } } + break; + case coding_MSADPCM: + vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count); + break; + case coding_MS_IMA: + vgmstream->num_samples = ms_ima_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count); + break; + case coding_NGC_DSP: + //sample_count = dsp_bytes_to_samples(data_size, fmt.channel_count); /* expected from the "fact" chunk */ + + /* coefs */ + if (sns) { + int i, ch; + static const int16_t coef[16] = { /* common codebook? */ + 0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1, + 0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5 + }; + + for (ch = 0; ch < fmt.channel_count; ch++) { + for (i = 0; i < 16; i++) { + vgmstream->ch[ch].adpcm_coef[i] = coef[i]; + } + } + } + + break; +#ifdef VGM_USE_FFMPEG + case coding_FFmpeg: { + ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_offset(streamFile, 0x00, streamFile->get_size(streamFile)); + if ( !ffmpeg_data ) goto fail; + vgmstream->codec_data = ffmpeg_data; + + vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact_sample_count */ + + if (at3) { + /* the encoder introduces some garbage (not always silent) samples to skip before the stream */ + /* manually set skip_samples if FFmpeg didn't do it */ + if (ffmpeg_data->skipSamples <= 0) { + ffmpeg_set_skip_samples(ffmpeg_data, fact_sample_skip); + } + + /* RIFF loop/sample values are absolute (with skip samples), adjust */ + if (loop_flag) { + loop_start_offset -= ffmpeg_data->skipSamples; + loop_end_offset -= ffmpeg_data->skipSamples; + } + } + break; + } #endif #ifdef VGM_USE_MAIATRAC3PLUS - case coding_AT3plus: - /* rough total samples (block_size may be incorrect if not using joint stereo) */ - sample_count = (data_size / fmt.block_size) * 2048; - /* favor fact_samples if available (skip isn't correctly handled for now) */ - if (fact_sample_count > 0 && fact_sample_count + fact_sample_skip < sample_count) - sample_count = fact_sample_count + fact_sample_skip; + case coding_AT3plus: { + vgmstream->codec_data = init_at3plus(); - break; + /* get rough total samples but favor fact_samples if available (skip isn't correctly handled for now) */ + vgmstream->num_samples = atrac3plus_bytes_to_samples(data_size, fmt.block_size); + if (fact_sample_count > 0 && fact_sample_count + fact_sample_skip < vgmstream->num_samples) + vgmstream->num_samples = fact_sample_count + fact_sample_skip; + break; + } +#endif +#ifdef VGM_USE_ATRAC9 + case coding_ATRAC9: { + atrac9_config cfg = {0}; + + cfg.channels = vgmstream->channels; + cfg.config_data = read_32bitBE(fmt.offset+0x08+0x2c,streamFile); + cfg.encoder_delay = fact_sample_skip; + + vgmstream->codec_data = init_atrac9(&cfg); + if (!vgmstream->codec_data) goto fail; + + vgmstream->num_samples = fact_sample_count; + /* RIFF loop/sample values are absolute (with skip samples), adjust */ + if (loop_flag) { + loop_start_offset -= fact_sample_skip; + loop_end_offset -= fact_sample_skip; + } + + break; + } #endif default: goto fail; } - /* .sns uses fact chunk */ - if (sns) - { + if (sns) { if (-1 == fact_sample_count) goto fail; - sample_count = fact_sample_count; + vgmstream->num_samples = fact_sample_count; } - /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = sample_count; - vgmstream->sample_rate = fmt.sample_rate; - + /* coding, layout, interleave */ vgmstream->coding_type = fmt.coding_type; - - vgmstream->layout_type = layout_none; - if (fmt.channel_count > 1) { - switch (fmt.coding_type) { - case coding_PCM8_U_int: - case coding_MS_IMA: - case coding_MSADPCM: -#ifdef VGM_USE_FFMPEG - case coding_FFmpeg: -#endif -#ifdef VGM_USE_MAIATRAC3PLUS - case coding_AT3plus: -#endif - // use layout_none from above - break; - default: - vgmstream->layout_type = layout_interleave; - break; - } - } - - vgmstream->interleave_block_size = fmt.interleave; switch (fmt.coding_type) { case coding_MSADPCM: case coding_MS_IMA: @@ -512,171 +507,84 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { case coding_FFmpeg: #endif #ifdef VGM_USE_MAIATRAC3PLUS - case coding_AT3plus: + case coding_AT3plus: #endif - // override interleave_block_size with frame size +#ifdef VGM_USE_ATRAC9 + case coding_ATRAC9: +#endif + vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = fmt.block_size; break; default: - // use interleave from above + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = fmt.interleave; break; } -#ifdef VGM_USE_FFMPEG - if (fmt.coding_type == coding_FFmpeg) { - vgmstream->codec_data = ffmpeg_data; - } -#endif - -#ifdef VGM_USE_MAIATRAC3PLUS - if (fmt.coding_type == coding_AT3plus) { - maiatrac3plus_codec_data *data = malloc(sizeof(maiatrac3plus_codec_data)); - data->buffer = 0; - data->samples_discard = 0; - data->handle = Atrac3plusDecoder_openContext(); - vgmstream->codec_data = data; - } -#endif - + /* meta, loops */ + vgmstream->meta_type = meta_RIFF_WAVE; if (loop_flag) { - if (loop_start_ms >= 0) - { - vgmstream->loop_start_sample = - (long long)loop_start_ms*fmt.sample_rate/1000; - vgmstream->loop_end_sample = - (long long)loop_end_ms*fmt.sample_rate/1000; + if (loop_start_ms >= 0) { + vgmstream->loop_start_sample = (long long)loop_start_ms*fmt.sample_rate/1000; + vgmstream->loop_end_sample = (long long)loop_end_ms*fmt.sample_rate/1000; vgmstream->meta_type = meta_RIFF_WAVE_labl; } - else if (loop_start_offset >= 0) - { + else if (loop_start_offset >= 0) { vgmstream->loop_start_sample = loop_start_offset; vgmstream->loop_end_sample = loop_end_offset; vgmstream->meta_type = meta_RIFF_WAVE_smpl; } - else if (mwv && mwv_ctrl_offset != -1) - { - vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, - streamFile); - vgmstream->loop_end_sample = sample_count; + else if (mwv && mwv_ctrl_offset != -1) { + vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, streamFile); + vgmstream->loop_end_sample = vgmstream->num_samples; } } - else - { - vgmstream->meta_type = meta_RIFF_WAVE; - } - - if (mwv) - { - int i, c; - if (fmt.coding_type == coding_L5_555) - { - const int filter_order = 3; - int filter_count = read_32bitLE(mwv_pflt_offset+12, streamFile); - - if (mwv_pflt_offset == -1 || - read_32bitLE(mwv_pflt_offset+8, streamFile) != filter_order || - read_32bitLE(mwv_pflt_offset+4, streamFile) < 8 + filter_count * 4 * filter_order) - goto fail; - if (filter_count > 0x20) goto fail; - for (c = 0; c < fmt.channel_count; c++) - { - for (i = 0; i < filter_count * filter_order; i++) - { - vgmstream->ch[c].adpcm_coef_3by32[i] = read_32bitLE( - mwv_pflt_offset+16+i*4, streamFile - ); - } - } - } + if (mwv) { vgmstream->meta_type = meta_RIFF_WAVE_MWV; } - - if (sns) - { - int c; - /* common codebook? */ - static const int16_t coef[16] = - {0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1, - 0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5}; - - for (c = 0; c < fmt.channel_count; c++) - { - int i; - for (i = 0; i < 16; i++) - { - vgmstream->ch[c].adpcm_coef[i] = coef[i]; - } - } + if (sns) { vgmstream->meta_type = meta_RIFF_WAVE_SNS; } - /* open the file, set up each channel */ - { - int i; - - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, - STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - - for (i=0;ich[i].streamfile = vgmstream->ch[0].streamfile; - vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset = - start_offset+i*fmt.interleave; - } - } + if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) ) + goto fail; return vgmstream; - /* clean up anything we may have opened */ + fail: -#ifdef VGM_USE_FFMPEG - if (ffmpeg_data) { - free_ffmpeg(ffmpeg_data); - if (vgmstream) vgmstream->codec_data = NULL; - } -#endif - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; + riff_fmt_chunk fmt = {0}; - struct riff_fmt_chunk fmt; - - off_t file_size = -1; - int sample_count = 0; - //int fact_sample_count = -1; - off_t start_offset = -1; + size_t file_size, riff_size, data_size = 0; + off_t start_offset = 0; int loop_flag = 0; off_t loop_start_offset = -1; off_t loop_end_offset = -1; - uint32_t riff_size; - uint32_t data_size = 0; - int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0; + int FormatChunkFound = 0, DataChunkFound = 0; + /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("wav",filename_extension(filename)) && - strcasecmp("lwav",filename_extension(filename))) - { + if ( !check_extensions(streamFile, "wav,lwav") ) goto fail; - } /* check header */ - if ((uint32_t)read_32bitBE(0,streamFile)!=0x52494658) /* "RIFX" */ + if (read_32bitBE(0x00,streamFile) != 0x52494658) /* "RIFX" */ goto fail; - /* check for WAVE form */ - if ((uint32_t)read_32bitBE(8,streamFile)!=0x57415645) /* "WAVE" */ + if (read_32bitBE(0x08,streamFile) != 0x57415645) /* "WAVE" */ goto fail; - riff_size = read_32bitBE(4,streamFile); + riff_size = read_32bitBE(0x04,streamFile); file_size = get_streamfile_size(streamFile); - /* check for tructated RIFF */ + /* check for truncated RIFF */ if (file_size < riff_size+8) goto fail; /* read through chunks to verify format and find metadata */ @@ -713,27 +621,15 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) { data_size = chunk_size; break; case 0x736D706C: /* smpl */ - /* check loop count */ - if (read_32bitBE(current_chunk+0x24, streamFile)==1) - { - /* check loop info */ - if (read_32bitBE(current_chunk+0x2c+4, streamFile)==0) - { + /* check loop count and loop info */ + if (read_32bitBE(current_chunk+0x24, streamFile)==1) { + if (read_32bitBE(current_chunk+0x2c+4, streamFile)==0) { loop_flag = 1; - loop_start_offset = - read_32bitBE(current_chunk+0x2c+8, streamFile); - loop_end_offset = - read_32bitBE(current_chunk+0x2c+0xc,streamFile); + loop_start_offset = read_32bitBE(current_chunk+0x2c+8, streamFile); + loop_end_offset = read_32bitBE(current_chunk+0x2c+0xc,streamFile); } } break; - case 0x66616374: /* fact */ - if (chunk_size != 4) break; - //fact_sample_count = read_32bitBE(current_chunk+8, streamFile); - break; - case 0x4A554E4B: /* JUNK */ - JunkFound = 1; - break; default: /* ignorance is bliss */ break; @@ -745,241 +641,50 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) { if (!FormatChunkFound || !DataChunkFound) goto fail; - /* JUNK is an optional Wwise chunk, and Wwise hijacks the MSADPCM/MS_IMA/XBOX IMA ids (how nice). - * To ensure their stuff is parsed in wwise.c we reject their JUNK, which they put almost always. - * As JUNK is legal (if unusual) we only reject those codecs. - * (ex. Cave PC games have PCM16LE + JUNK + smpl created by "Samplitude software") */ - if (JunkFound && (fmt.coding_type==coding_MSADPCM || fmt.coding_type==coding_MS_IMA)) goto fail; + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = fmt.sample_rate; + + /* init, samples */ switch (fmt.coding_type) { case coding_PCM16BE: - sample_count = data_size/2/fmt.channel_count; + vgmstream->num_samples = pcm_bytes_to_samples(data_size, vgmstream->channels, 16); break; case coding_PCM8_U_int: - sample_count = data_size/fmt.channel_count; - break; - case coding_NGC_DSP: - //sample_count = data_size / fmt.channel_count / 8 * 14; /* expected from the "fact" chunk */ + vgmstream->num_samples = pcm_bytes_to_samples(data_size, vgmstream->channels, 8); break; default: goto fail; } - /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = sample_count; - vgmstream->sample_rate = fmt.sample_rate; - + /* coding, layout, interleave */ vgmstream->coding_type = fmt.coding_type; - - vgmstream->layout_type = layout_none; - if (fmt.channel_count > 1) { - switch (fmt.coding_type) { - case coding_PCM8_U_int: - case coding_MS_IMA: - case coding_MSADPCM: - // use layout_none from above - break; - default: - vgmstream->layout_type = layout_interleave; - break; - } - } - - vgmstream->interleave_block_size = fmt.interleave; switch (fmt.coding_type) { - case coding_MSADPCM: - case coding_MS_IMA: - // override interleave_block_size with frame size - vgmstream->interleave_block_size = fmt.block_size; - break; default: - // use interleave from above + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = fmt.interleave; break; } - if (fmt.coding_type == coding_MS_IMA) - vgmstream->interleave_block_size = fmt.block_size; - + /* meta, loops */ + vgmstream->meta_type = meta_RIFX_WAVE; if (loop_flag) { - if (loop_start_offset >= 0) - { + if (loop_start_offset >= 0) { vgmstream->loop_start_sample = loop_start_offset; vgmstream->loop_end_sample = loop_end_offset; vgmstream->meta_type = meta_RIFX_WAVE_smpl; } } - else - { - vgmstream->meta_type = meta_RIFX_WAVE; - } - - /* open the file, set up each channel */ - { - int i; - - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, - STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - - for (i=0;ich[i].streamfile = vgmstream->ch[0].streamfile; - vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset = - start_offset+i*fmt.interleave; - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - -//todo move -/* XNB - Microsoft XNA Game Studio 4.0 format */ -VGMSTREAM * init_vgmstream_xnbm(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int loop_flag = 0, version, flags, num_samples = 0; - size_t xnb_size, data_size; - - struct riff_fmt_chunk fmt; - - - /* check extension, case insensitive */ - if ( !check_extensions(streamFile,"xnb")) - goto fail; - - /* check header */ - if ((read_32bitBE(0,streamFile) & 0xFFFFFF00) != 0x584E4200) /* "XNB" */ - goto fail; - /* 0x04: platform: ‘w’ = Microsoft Windows, ‘m’ = Windows Phone 7, ‘x’ = Xbox 360, 'a' = Android */ - - version = read_8bit(0x04,streamFile); - if (version != 5) goto fail; /* XNA 4.0 only */ - - flags = read_8bit(0x05,streamFile); - if (flags & 0x80) goto fail; /* compressed with XMemCompress, not public */ - //if (flags & 0x01) goto fail; /* XMA flag? */ - - /* "check for truncated XNB" (???) */ - xnb_size = read_32bitLE(0x06,streamFile); - if (get_streamfile_size(streamFile) < xnb_size) goto fail; - - /* XNB contains "type reader" class references to parse "shared resource" data (can be any implemented filetype) */ - { - char reader_name[255+1]; - off_t current_chunk = 0xa; - int reader_string_len; - uint32_t fmt_chunk_size; - const char * type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */ - //const char * type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* just references a companion .wma */ - - /* type reader count, accept only one for now */ - if (read_8bit(current_chunk++, streamFile) != 1) - goto fail; - - reader_string_len = read_8bit(current_chunk++, streamFile); /* doesn't count null */ - if (reader_string_len > 255) goto fail; - - /* check SoundEffect type string */ - if (read_string(reader_name,reader_string_len+1,current_chunk,streamFile) != reader_string_len) - goto fail; - if ( strcmp(reader_name, type_sound) != 0 ) - goto fail; - current_chunk += reader_string_len + 1; - current_chunk += 4; /* reader version */ - - /* shared resource count */ - if (read_8bit(current_chunk++, streamFile) != 1) - goto fail; - - /* shared resource: partial "fmt" chunk */ - fmt_chunk_size = read_32bitLE(current_chunk, streamFile); - current_chunk += 4; - - if (-1 == read_fmt(0, /* big endian == false */ - streamFile, - current_chunk-8, /* read_fmt() expects to skip "fmt "+size */ - &fmt, - 0, /* sns == false */ - 0)) /* mwv == false */ - goto fail; - current_chunk += fmt_chunk_size; - - data_size = read_32bitLE(current_chunk, streamFile); - current_chunk += 4; - - start_offset = current_chunk; - } - - switch (fmt.coding_type) { - case coding_PCM16LE: - num_samples = pcm_bytes_to_samples(data_size, fmt.channel_count, 16); - break; - case coding_PCM8_U_int: - num_samples = pcm_bytes_to_samples(data_size, fmt.channel_count, 8); - break; - case coding_MSADPCM: - num_samples = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count); - break; - case coding_MS_IMA: - num_samples = (data_size / fmt.block_size) * (fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count + - ((data_size % fmt.block_size) ? (data_size % fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count : 0); - break; - default: - VGM_LOG("XNB: unknown codec 0x%x\n", fmt.coding_type); - goto fail; - } - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->num_samples = num_samples; - vgmstream->sample_rate = fmt.sample_rate; - - vgmstream->meta_type = meta_XNB; - vgmstream->coding_type = fmt.coding_type; - - if (fmt.channel_count > 1) { - switch (fmt.coding_type) { - case coding_PCM8_U_int: - case coding_MS_IMA: - case coding_MSADPCM: - vgmstream->layout_type = layout_none; - break; - default: - vgmstream->layout_type = layout_interleave; - break; - } - } - - switch (fmt.coding_type) { - case coding_MSADPCM: - case coding_MS_IMA: - vgmstream->interleave_block_size = fmt.block_size; - break; - default: - vgmstream->interleave_block_size = fmt.interleave; - break; - } if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) ) goto fail; - return vgmstream; fail: close_vgmstream(vgmstream); return NULL; } - diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sk_aud.c b/Frameworks/vgmstream/vgmstream/src/meta/sk_aud.c index ce3bc55fb..6dd60a777 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sk_aud.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sk_aud.c @@ -37,7 +37,7 @@ VGMSTREAM * init_vgmstream_sk_aud(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; vgmstream->coding_type = coding_VORBIS_custom; - vgmstream->codec_data = init_vorbis_custom_codec_data(streamFile, 0x00, VORBIS_SK, &cfg); + vgmstream->codec_data = init_vorbis_custom(streamFile, 0x00, VORBIS_SK, &cfg); if (!vgmstream->codec_data) goto fail; start_offset = cfg.data_start_offset; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c b/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c index faffc0a02..2dfa87052 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c @@ -211,7 +211,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { cfg.interleave = 0x800; /* for multistream [Final Fantasy XIII-2 (PS3)], otherwise ignored */ cfg.data_size = stream_size; - mpeg_data = init_mpeg_custom_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_SCD, &cfg); + mpeg_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_SCD, &cfg); if (!mpeg_data) goto fail; vgmstream->codec_data = mpeg_data; vgmstream->layout_type = layout_none; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sxd.c b/Frameworks/vgmstream/vgmstream/src/meta/sxd.c index 71243ec78..a42ff2876 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sxd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sxd.c @@ -1,16 +1,18 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* SXD - Sony's SDK format? (cousin of SGXD) [Gravity Rush, Freedom Wars, Soul Sacrifice PSV] */ +/* SXD - Sony/SCE's SNDX lib format (cousin of SGXD) [Gravity Rush, Freedom Wars, Soul Sacrifice PSV] */ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; STREAMFILE * streamHeader = NULL; off_t start_offset, chunk_offset, first_offset = 0x60, name_offset = 0; + size_t chunk_size; int is_separate; - int loop_flag, channels, type; + int loop_flag, channels, codec; int sample_rate, num_samples, loop_start_sample, loop_end_sample; + uint32_t at9_config_data = 0; int total_streams, target_stream = streamFile->stream_index; @@ -33,8 +35,7 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) { /* typical chunks: NAME, WAVE and many control chunks (SXDs don't need to contain any sound data) */ - /* WAVE chunk (0 + streams + 4*streams table + streams * variable? + optional padding) */ - if (!find_chunk_le(streamHeader, 0x57415645,first_offset,0, &chunk_offset,NULL)) goto fail; /* "WAVE" */ + if (!find_chunk_le(streamHeader, 0x57415645,first_offset,0, &chunk_offset,&chunk_size)) goto fail; /* "WAVE" */ /* check multi-streams (usually only in SFX containers) */ total_streams = read_32bitLE(chunk_offset+0x04,streamHeader); @@ -43,53 +44,60 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) { /* read stream header */ { - off_t table_offset, header_offset, stream_offset, data_offset; - int i; + off_t table_offset, header_offset, stream_offset; /* get target offset using table of relative offsets within WAVE */ table_offset = chunk_offset + 0x08 + 4*(target_stream-1); header_offset = table_offset + read_32bitLE(table_offset,streamHeader); - type = read_32bitLE(header_offset+0x00,streamHeader); - /* 0x04 (1): unk (HEVAG: 21, ATRAC9: 42 */ - channels = read_8bit (header_offset+0x05,streamHeader); - sample_rate = read_32bitLE(header_offset+0x08,streamHeader); - /* 0x0c (4): unk size? */ - /* 0x10 (4): ? + volume? + pan? (can be 0 for music) */ - num_samples = read_32bitLE(header_offset+0x14,streamHeader); + /* 0x00(4): type/location? (00/01=sxd/RAM?, 02/03=sxd2/stream?) */ + codec = read_8bit (header_offset+0x04,streamHeader); + channels = read_8bit (header_offset+0x05,streamHeader); + sample_rate = read_32bitLE(header_offset+0x08,streamHeader); + /* 0x0c(4): unknown size? (0x4000/0x3999/0x3333/etc, not related to extra data) */ + /* 0x10(4): ? + volume? + pan? (can be 0 for music) */ + num_samples = read_32bitLE(header_offset+0x14,streamHeader); loop_start_sample = read_32bitLE(header_offset+0x18,streamHeader); loop_end_sample = read_32bitLE(header_offset+0x1c,streamHeader); - /* 0x20 (4): data size */ - /* 0x24 (-): extra data, variable size and format dependant - (ATRAC9 can contain truncated part of the data, for preloading I guess) */ + /* 0x20(4): data size */ + stream_offset = read_32bitLE(header_offset+0x24,streamHeader); + + /* Extra data, variable sized and uses some kind of TLVs (HEVAG's is optional and much smaller). + * One tag seems to add a small part of the ATRAC9 data, for RAM preloding I guess. */ + if (codec == 0x42) { + off_t extra_offset = header_offset+0x28; + off_t max_offset = chunk_offset + chunk_size; + + /* manually try to find certain tag, no idea about the actual format + * (most variable in Soul Sacrifice; extra size isn't found in the SXD AFAIK) */ + while (extra_offset < max_offset) { + uint32_t tag = read_32bitBE(extra_offset, streamHeader); + if (tag == 0x0A010000 || tag == 0x0A010600) { + at9_config_data = read_32bitLE(extra_offset+0x04,streamHeader); /* yes, LE */ + break; + } + + extra_offset += 0x04; + } + if (!at9_config_data) + goto fail; + } + loop_flag = loop_start_sample != -1 && loop_end_sample != -1; - /* calc stream offset by reading stream sizes */ - stream_offset = 0; - for (i = 0; i < total_streams; i++) { - off_t subtable_offset, subheader_offset; - if (i == target_stream-1) break; - - subtable_offset = chunk_offset + 0x08 + 4*(i); - subheader_offset = subtable_offset + read_32bitLE(subtable_offset,streamHeader); - stream_offset += read_32bitLE(subheader_offset+0x20,streamHeader); /* data size */ - } - + /* from current offset in sxd, absolute in sxd2 */ if (is_separate) { - data_offset = first_offset; + start_offset = stream_offset; } else { - if (!find_chunk_le(streamHeader, 0x44415441,first_offset,0, &data_offset,NULL)) goto fail; /* "DATA" */ - data_offset += 0x08; + start_offset = header_offset+0x24 + stream_offset; } - - start_offset = data_offset + stream_offset; } /* get stream name (NAME is tied to REQD/cues, and SFX cues repeat WAVEs, but should work ok for streams) */ if (is_separate && find_chunk_le(streamHeader, 0x4E414D45,first_offset,0, &chunk_offset,NULL)) { /* "NAME" */ /* table: relative offset (32b) + hash? (32b) + cue index (32b) */ int i; - int num_entries = read_16bitLE(chunk_offset+0x04,streamHeader); /*can be more than streams */ + int num_entries = read_16bitLE(chunk_offset+0x04,streamHeader); /* can be bigger than streams */ for (i = 0; i < num_entries; i++) { uint32_t index = (uint32_t)read_32bitLE(chunk_offset+0x08 + 0x08 + i*0x0c,streamHeader); if (index+1 == target_stream) { @@ -113,18 +121,30 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) { if (name_offset) read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader); - switch (type) { - case 0x01: /* HEVAG */ + switch (codec) { + case 0x21: /* HEVAG */ vgmstream->coding_type = coding_HEVAG; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x10; break; - case 0x03: /* ATRAC9 */ - goto fail; +#ifdef VGM_USE_ATRAC9 + case 0x42: { /* ATRAC9 */ + atrac9_config cfg = {0}; + + cfg.channels = vgmstream->channels; + cfg.config_data = at9_config_data; + + vgmstream->codec_data = init_atrac9(&cfg); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_ATRAC9; + vgmstream->layout_type = layout_none; + break; + } +#endif default: - VGM_LOG("SXD: unknown codec %i", type); + VGM_LOG("SXD: unknown codec 0x%x", codec); goto fail; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ta_aac.c b/Frameworks/vgmstream/vgmstream/src/meta/ta_aac.c index 136ef057f..f7984bd9b 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ta_aac.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ta_aac.c @@ -208,3 +208,50 @@ fail: close_vgmstream(vgmstream); return NULL; } + +/* Android/iOS Variants (Star Ocean Anamnesis (APK v1.9.2), Heaven x Inferno (iOS)) */ +VGMSTREAM * init_vgmstream_ta_aac_mobile(STREAMFILE *streamFile) { +#ifdef VGM_USE_VORBIS + off_t start_offset; + char filename[PATH_LIMIT]; + int8_t codec_id; + + streamFile->get_name(streamFile, filename, sizeof(filename)); + /* check extension, case insensitive */ + /* .aac: expected, .laac/ace: for players to avoid hijacking MP4/AAC */ + if (!check_extensions(streamFile, "aac,laac,ace")) + goto fail; + + if (read_32bitLE(0x00, streamFile) != 0x41414320) /* "AAC " */ + goto fail; + + if (read_32bitLE(0xf0, streamFile) != 0x57415645) /* "WAVE" */ + goto fail; + + codec_id = read_8bit(0x104, streamFile); + if (codec_id == 0xe) /* Vorbis */ + { + vgm_vorbis_info_t inf; + VGMSTREAM * result = NULL; + + memset(&inf, 0, sizeof(inf)); + inf.layout_type = layout_ogg_vorbis; + inf.meta_type = meta_TA_AAC_VORBIS; + inf.loop_start = read_32bitLE(0x140, streamFile); + inf.loop_end = read_32bitLE(0x144, streamFile); + inf.loop_flag = inf.loop_end > inf.loop_start; + inf.loop_end_found = inf.loop_flag; + + start_offset = read_32bitLE(0x120, streamFile); + result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf); + + if (result != NULL) { + return result; + } + } + +fail: + /* clean up anything we may have opened */ +#endif + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txth.c b/Frameworks/vgmstream/vgmstream/src/meta/txth.c index 7d6dd602a..ee5ddcfd2 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/txth.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/txth.c @@ -253,7 +253,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { #ifdef VGM_USE_MPEG case coding_MPEG_layer3: vgmstream->layout_type = layout_none; - vgmstream->codec_data = init_mpeg_codec_data(streamFile, txth.start_offset, &coding, vgmstream->channels); + vgmstream->codec_data = init_mpeg(streamFile, txth.start_offset, &coding, vgmstream->channels); if (!vgmstream->codec_data) goto fail; break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_raki.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_raki.c index 118998f1c..486ace356 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_raki.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_raki.c @@ -7,7 +7,7 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset, off, fmt_offset; size_t header_size, data_size; - int little_endian; + int big_endian; int loop_flag, channel_count, block_align, bits_per_sample; uint32_t platform, type; @@ -28,25 +28,33 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) { else goto fail; - /* endianness is given with the platform field, but this is more versatile */ - little_endian = read_32bitBE(off+0x10,streamFile) > 0x00ffffff; - if (little_endian) { - read_32bit = read_32bitLE; - read_16bit = read_16bitLE; - } else { - read_32bit = read_32bitBE; - read_16bit = read_16bitBE; - } - /* 0x04: version? (0x00, 0x07, 0x0a, etc); */ platform = read_32bitBE(off+0x08,streamFile); /* string */ type = read_32bitBE(off+0x0c,streamFile); /* string */ + + switch(platform) { + case 0x57696920: /* "Wii " */ + case 0x43616665: /* "Cafe" */ + case 0x50533320: /* "PS3 " */ + case 0x58333630: /* "X360" */ + big_endian = 1; + read_32bit = read_32bitBE; + read_16bit = read_16bitBE; + break; + default: + big_endian = 0; + read_32bit = read_32bitLE; + read_16bit = read_16bitLE; + break; + } + header_size = read_32bit(off+0x10,streamFile); start_offset = read_32bit(off+0x14,streamFile); /* 0x18: number of chunks */ /* 0x1c: unk */ - /* The first chunk is always "fmt" and points to a RIFF "fmt" chunk (even for WiiU or PS3) */ + /* the format has a chunk offset table, and the first one always "fmt" and points + * to a RIFF "fmt" chunk (even for WiiU or PS3) */ if (read_32bitBE(off+0x20,streamFile) != 0x666D7420) goto fail; /*"fmt "*/ fmt_offset = read_32bit(off+0x24,streamFile); //fmt_size = read_32bit(off+0x28,streamFile); @@ -74,7 +82,7 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) { /* chunks: "data" */ vgmstream->coding_type = coding_PCM16LE; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = block_align; /* usually 0x04 */ + vgmstream->interleave_block_size = 0x2; vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, bits_per_sample); break; @@ -114,7 +122,7 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) { { /* get coef offsets; could check "dspL" and "dspR" chunks after "fmt " better but whatevs (only "dspL" if mono) */ off_t dsp_coefs = read_32bitBE(off+0x30,streamFile); /* after "dspL"; spacing is consistent but could vary */ - dsp_read_coefs(vgmstream,streamFile, dsp_coefs+0x1c, 0x60, !little_endian); + dsp_read_coefs(vgmstream,streamFile, dsp_coefs+0x1c, 0x60, big_endian); /* dsp_coefs + 0x00-0x1c: ? (special coefs or adpcm history?) */ } @@ -123,8 +131,8 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) { #ifdef VGM_USE_MPEG case 0x505333206D703320: { /* "PS3 mp3 " */ - /* chunks: "MARK" optional seek table), "STRG" (optional description), "Msf " ("data" equivalent) */ - vgmstream->codec_data = init_mpeg_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels); + /* chunks: "MARK" (optional seek table), "STRG" (optional description), "Msf " ("data" equivalent) */ + vgmstream->codec_data = init_mpeg(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_none; @@ -153,9 +161,25 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) { } #endif - case 0x5649544161743920: /*"VITAat9 "*/ +#ifdef VGM_USE_ATRAC9 + case 0x5649544161743920: { /*"VITAat9 "*/ /* chunks: "fact" (equivalent to a RIFF "fact", num_samples + skip_samples), "data" */ - goto fail; + atrac9_config cfg = {0}; + + cfg.channels = vgmstream->channels; + cfg.config_data = read_32bitBE(fmt_offset+0x2c,streamFile); + cfg.encoder_delay = read_32bit(fmt_offset+0x3c,streamFile); + + vgmstream->codec_data = init_atrac9(&cfg); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_ATRAC9; + vgmstream->layout_type = layout_none; + + /* could get the "fact" offset but seems it always follows "fmt " */ + vgmstream->num_samples = read_32bit(fmt_offset+0x34,streamFile); + break; + } +#endif default: VGM_LOG("RAKI: unknown platform %x and type %x\n", platform, type); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c index b871da8ab..e4619791a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c @@ -285,7 +285,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { } } - vgmstream->codec_data = init_vorbis_custom_codec_data(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg); + vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg); if (!vgmstream->codec_data) goto fail; } else { @@ -330,11 +330,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { } /* try with the selected codebooks */ - vgmstream->codec_data = init_vorbis_custom_codec_data(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg); + vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg); if (!vgmstream->codec_data) { /* codebooks failed: try again with the other type */ cfg.setup_type = is_wem ? EXTERNAL_CODEBOOKS : AOTUV603_CODEBOOKS; - vgmstream->codec_data = init_vorbis_custom_codec_data(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg); + vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg); if (!vgmstream->codec_data) goto fail; } } @@ -528,9 +528,24 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { vgmstream->num_samples = ps_bytes_to_samples(ww.data_size, ww.channels); break; - case ATRAC9: /* PSV/PS4 */ - VGM_LOG("WWISE: ATRAC9 found (unsupported)\n"); - goto fail; +#ifdef VGM_USE_ATRAC9 + case ATRAC9: { /* PSV/PS4 */ + atrac9_config cfg = {0}; + if (ww.extra_size != 0x12) goto fail; + + cfg.channels = vgmstream->channels; + cfg.config_data = read_32bitBE(ww.fmt_offset+0x18,streamFile); + cfg.encoder_delay = read_32bit(ww.fmt_offset+0x20,streamFile); + + vgmstream->codec_data = init_atrac9(&cfg); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_ATRAC9; + vgmstream->layout_type = layout_none; + + vgmstream->num_samples = read_32bit(ww.fmt_offset+0x1c,streamFile); + break; + } +#endif default: goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xnb.c b/Frameworks/vgmstream/vgmstream/src/meta/xnb.c new file mode 100644 index 000000000..c0034a71e --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/xnb.c @@ -0,0 +1,123 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* XNB - Microsoft XNA Game Studio 4.0 format */ +VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag = 0, channel_count; + int flags, codec, sample_rate, block_size, bps; + size_t xnb_size, data_size; + + + /* check extension, case insensitive */ + if ( !check_extensions(streamFile,"xnb")) + goto fail; + + /* check header */ + if ((read_32bitBE(0,streamFile) & 0xFFFFFF00) != 0x584E4200) /* "XNB" */ + goto fail; + /* 0x04: platform: ‘w’ = Microsoft Windows, ‘m’ = Windows Phone 7, ‘x’ = Xbox 360, 'a' = Android */ + + if (read_8bit(0x04,streamFile) != 0x05) /* XNA 4.0 version only */ + goto fail; + + flags = read_8bit(0x05,streamFile); + if (flags & 0x80) goto fail; /* compressed with XMemCompress */ + //if (flags & 0x01) goto fail; /* XMA/big endian flag? */ + + /* "check for truncated XNB" (???) */ + xnb_size = read_32bitLE(0x06,streamFile); + if (get_streamfile_size(streamFile) < xnb_size) goto fail; + + /* XNB contains "type reader" class references to parse "shared resource" data (can be any implemented filetype) */ + { + char reader_name[255+1]; + off_t current_chunk = 0xa; + int reader_string_len; + uint32_t fmt_chunk_size; + const char * type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */ + //const char * type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* just references a companion .wma */ + + /* type reader count, accept only one for now */ + if (read_8bit(current_chunk++, streamFile) != 1) + goto fail; + + reader_string_len = read_8bit(current_chunk++, streamFile); /* doesn't count null */ + if (reader_string_len > 255) goto fail; + + /* check SoundEffect type string */ + if (read_string(reader_name,reader_string_len+1,current_chunk,streamFile) != reader_string_len) + goto fail; + if ( strcmp(reader_name, type_sound) != 0 ) + goto fail; + current_chunk += reader_string_len + 1; + current_chunk += 4; /* reader version */ + + /* shared resource count */ + if (read_8bit(current_chunk++, streamFile) != 1) + goto fail; + + /* shared resource: partial "fmt" chunk */ + fmt_chunk_size = read_32bitLE(current_chunk, streamFile); + current_chunk += 4; + + { + codec = read_16bitLE(current_chunk+0x00, streamFile); + channel_count = read_16bitLE(current_chunk+0x02, streamFile); + sample_rate = read_32bitLE(current_chunk+0x04, streamFile); + block_size = read_16bitLE(current_chunk+0x0c, streamFile); + bps = read_16bitLE(current_chunk+0x0e, streamFile); + } + + current_chunk += fmt_chunk_size; + + data_size = read_32bitLE(current_chunk, streamFile); + current_chunk += 4; + + start_offset = current_chunk; + } + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = sample_rate; + vgmstream->meta_type = meta_XNB; + + switch (codec) { + case 0x01: + vgmstream->coding_type = bps == 8 ? coding_PCM8_U_int : coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = block_size / channel_count; + vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, bps); + break; + + case 0x02: + vgmstream->coding_type = coding_MSADPCM; + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = block_size; + vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, block_size, channel_count); + break; + + case 0x11: + vgmstream->coding_type = coding_MS_IMA; + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = block_size; + vgmstream->num_samples = ms_ima_bytes_to_samples(data_size, block_size, channel_count); + break; + + default: + VGM_LOG("XNB: unknown codec 0x%x\n", codec); + goto fail; + } + + if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) ) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xvag.c b/Frameworks/vgmstream/vgmstream/src/meta/xvag.c index c187aebfc..0a84c1e81 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xvag.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xvag.c @@ -4,50 +4,71 @@ static int ps_adpcm_find_loop_offsets(STREAMFILE *streamFile, int channel_count, off_t start_offset, off_t * loop_start, off_t * loop_end); -/* XVAG - Sony's (second party?) format (God of War III, Ratchet & Clank Future, The Last of Us, Uncharted) */ +/* XVAG - Sony's Scream Tool/Stream Creator format (God of War III, Ratchet & Clank Future, The Last of Us, Uncharted) */ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; int loop_flag = 0, channel_count, codec; + int big_endian; + int sample_rate, num_samples, multiplier, multistreams = 0; + int total_subsongs = 0, target_subsong = streamFile->stream_index; off_t start_offset, loop_start, loop_end, chunk_offset; off_t first_offset = 0x20; - int little_endian; - int sample_rate, num_samples, multiplier; + size_t chunk_size; /* check extension, case insensitive */ - if (!check_extensions(streamFile,"xvag")) goto fail; + if (!check_extensions(streamFile,"xvag")) + goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x58564147) /* "XVAG" */ goto fail; - little_endian = read_8bit(0x07,streamFile)==0; /* empty start_offset > little endian */ - if (little_endian) { - read_32bit = read_32bitLE; - } else { + /* endian flag (XVAGs of the same game can use BE or LE, usually when reusing from other platforms) */ + big_endian = read_8bit(0x08,streamFile) & 0x01; + if (big_endian) { read_32bit = read_32bitBE; + } else { + read_32bit = read_32bitLE; } start_offset = read_32bit(0x04,streamFile); - /* 0x08: flags? (&0x01=big endian?) 0x0a: version (chunk sizes vary) */ + /* 0x08: flags? (&0x01=big endian, 0x02=?, 0x06=full RIFF AT9?) + * 0x09: flags2? (0x00/0x01/0x04, speaker mode?) + * 0x0a: always 0? + * 0x0b: version-flag? (0x5f/0x60/0x61, last has extra data) */ - /* "fmat": base format */ - if (!find_chunk(streamFile, 0x666D6174,first_offset,0, &chunk_offset,NULL, !little_endian, 1)) goto fail; /*"fmat"*/ + /* "fmat": base format (always first) */ + if (!find_chunk(streamFile, 0x666D6174,first_offset,0, &chunk_offset,&chunk_size, big_endian, 1)) /*"fmat"*/ + goto fail; channel_count = read_32bit(chunk_offset+0x00,streamFile); codec = read_32bit(chunk_offset+0x04,streamFile); num_samples = read_32bit(chunk_offset+0x08,streamFile); - /* 0x0c: samples again? */ - multiplier = read_32bit(chunk_offset+0x10,streamFile); + /* 0x0c: samples again? playable section? */ + VGM_ASSERT(num_samples != read_32bit(chunk_offset+0x0c,streamFile), "XVAG: num_samples values don't match\n"); + + multiplier = read_32bit(chunk_offset+0x10,streamFile); /* 'interleave factor' */ sample_rate = read_32bit(chunk_offset+0x14,streamFile); /* 0x18: datasize */ + /* extra data, seen in MPEG/ATRAC9 */ + if (chunk_size > 0x1c) { + total_subsongs = read_32bit(chunk_offset+0x1c,streamFile); /* number of interleaved layers */ + multistreams = read_32bit(chunk_offset+0x20,streamFile); /* number of bitstreams per layer (for multistream Nch MPEG/ATRAC9) */ + } + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + + /* other chunks: */ /* "cpan": pan/volume per channel */ + /* "cues": cue/labels (rare) */ /* "0000": end chunk before start_offset */ - //if ((uint16_t)read_16bitBE(start_offset,streamFile)==0xFFFB) codec = 0x08; - if (codec == 0x06) { /* todo not sure if there are any looping XVAGs */ + /* some XVAG seem to do full loops, this should detect them as looping */ + //todo remove, looping seems external and specified in Scream Tool's bank formats + if (codec == 0x06) { loop_flag = ps_adpcm_find_loop_offsets(streamFile, channel_count, start_offset, &loop_start, &loop_end); } @@ -57,52 +78,85 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { vgmstream->sample_rate = sample_rate; vgmstream->num_samples = num_samples; + vgmstream->num_streams = total_subsongs; vgmstream->meta_type = meta_XVAG; switch (codec) { - case 0x06: /* PS ADPCM: God of War III, Uncharted 1/2, Ratchet and Clank Future */ - case 0x07: { /* Bizarro 6ch PS ADPCM: infamous 1 (todo won't play properly; algo tweak + bigger predictor table?) */ + //case 0x??: /* PCM? */ + case 0x06: /* VAG (PS ADPCM): God of War III (PS3), Uncharted 1/2 (PS3), Ratchet and Clank Future (PS3) */ + case 0x07: /* SVAG? (PS ADPCM with extended table): inFamous 1 (PS3) */ + if (total_subsongs > 1 || multistreams > 1) goto fail; + if (multiplier > 1) goto fail; + vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x10;//* multiplier? (doesn't seem necessary, always 1); + vgmstream->interleave_block_size = 0x10; vgmstream->coding_type = coding_PSX; if (loop_flag) { - if (loop_start!=0) { - vgmstream->loop_start_sample = ((((loop_start/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*28)/channel_count; - if(loop_start%vgmstream->interleave_block_size) - vgmstream->loop_start_sample += (((loop_start%vgmstream->interleave_block_size)-1)/16*14*channel_count); - } - vgmstream->loop_end_sample = ((((loop_end/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*28)/channel_count; - if (loop_end%vgmstream->interleave_block_size) - vgmstream->loop_end_sample += (((loop_end%vgmstream->interleave_block_size)-1)/16*14*channel_count); + vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, vgmstream->channels); + vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, vgmstream->channels); } - break; - } #ifdef VGM_USE_MPEG - case 0x08: { /* MPEG: The Last of Us, Uncharted 3, Medieval Moves */ + case 0x08: { /* MPEG: The Last of Us (PS3), Uncharted 3 (PS3), Medieval Moves (PS3) */ mpeg_custom_config cfg = {0}; + if (total_subsongs > 1 || (multistreams > 1 && multistreams == vgmstream->channels)) goto fail; + /* "mpin": mpeg info */ /* 0x00/04: mpeg version/layer? other: unknown or repeats of "fmat" */ - if (!find_chunk(streamFile, 0x6D70696E,first_offset,0, &chunk_offset,NULL, !little_endian, 1)) - goto fail; /*"mpin"*/ + if (!find_chunk(streamFile, 0x6D70696E,first_offset,0, &chunk_offset,NULL, big_endian, 1)) /*"mpin"*/ + goto fail; cfg.chunk_size = read_32bit(chunk_offset+0x1c,streamFile); /* fixed frame size */ cfg.interleave = cfg.chunk_size * multiplier; - vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_XVAG, &cfg); + vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_XVAG, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_none; break; } #endif - case 0x09: { /* ATRAC9: Sly Cooper and the Thievius Raccoonus */ +#ifdef VGM_USE_ATRAC9 + case 0x09: { /* ATRAC9: Sly Cooper and the Thievius Raccoonus (Vita), The Last of Us Remastered (PS4) */ + atrac9_config cfg = {0}; + /* "a9in": ATRAC9 info */ - goto fail; + /* 0x00: block align, 0x04: samples per block, 0x0c: fact num_samples (no change), 0x10: encoder delay1 */ + if (!find_chunk(streamFile, 0x6139696E,first_offset,0, &chunk_offset,NULL, big_endian, 1)) /*"a9in"*/ + goto fail; + + cfg.type = ATRAC9_XVAG; + cfg.channels = vgmstream->channels; + cfg.config_data = read_32bitBE(chunk_offset+0x08,streamFile); + cfg.encoder_delay = read_32bit(chunk_offset+0x14,streamFile); + + if (total_subsongs > 1 && multistreams > 1) { + goto fail; /* not known */ + } + else if (total_subsongs > 1) { + /* interleaves 'multiplier' superframes per subsong (all share config_data) */ + cfg.interleave_skip = read_32bit(chunk_offset+0x00,streamFile) * multiplier; + cfg.subsong_skip = total_subsongs; + /* start in subsong's first superframe */ + start_offset += (target_subsong-1) * cfg.interleave_skip * (cfg.subsong_skip-1); + } + else if (multistreams > 1) { + /* Vita multichannel (flower) interleaves streams like MPEG + * PS4 (The Last of Us) uses ATRAC9's multichannel directly instead (multistreams==1) */ + goto fail;//todo add + } + //if (multistreams == vgmstream->channels) goto fail; + + vgmstream->codec_data = init_atrac9(&cfg); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_ATRAC9; + vgmstream->layout_type = layout_none; + break; } +#endif default: goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index c3001d215..68f8290e3 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -17,10 +17,10 @@ static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *strea VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_adx, init_vgmstream_brstm, - init_vgmstream_bfwav, - init_vgmstream_bfstm, - init_vgmstream_mca, - init_vgmstream_btsnd, + init_vgmstream_bfwav, + init_vgmstream_bfstm, + init_vgmstream_mca, + init_vgmstream_btsnd, init_vgmstream_nds_strm, init_vgmstream_agsc, init_vgmstream_ngc_adpdtk, @@ -31,7 +31,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_rs03, init_vgmstream_ngc_dsp_std, init_vgmstream_ngc_mdsp_std, - init_vgmstream_ngc_dsp_csmp, + init_vgmstream_ngc_dsp_csmp, init_vgmstream_cstr, init_vgmstream_gcsw, init_vgmstream_ps2_ads, @@ -67,10 +67,10 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_sfl, #endif #if 0 - init_vgmstream_mp4_aac, + init_vgmstream_mp4_aac, #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) - init_vgmstream_akb, + init_vgmstream_akb, #endif init_vgmstream_sadb, init_vgmstream_ps2_bmdx, @@ -117,7 +117,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ps2_dxh, init_vgmstream_ps2_psh, init_vgmstream_scd_pcm, - init_vgmstream_ps2_pcm, + init_vgmstream_ps2_pcm, init_vgmstream_ps2_rkv, init_vgmstream_ps2_psw, init_vgmstream_ps2_vas, @@ -162,13 +162,13 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_rsd2vag, init_vgmstream_rsd2pcmb, init_vgmstream_rsd2xadp, - init_vgmstream_rsd3vag, - init_vgmstream_rsd3gadp, + init_vgmstream_rsd3vag, + init_vgmstream_rsd3gadp, init_vgmstream_rsd3pcm, - init_vgmstream_rsd3pcmb, + init_vgmstream_rsd3pcmb, init_vgmstream_rsd4pcmb, init_vgmstream_rsd4pcm, - init_vgmstream_rsd4radp, + init_vgmstream_rsd4radp, init_vgmstream_rsd4vag, init_vgmstream_rsd6vag, init_vgmstream_rsd6wadp, @@ -222,19 +222,19 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ps2_sps, init_vgmstream_ps2_xa2_rrp, init_vgmstream_nds_hwas, - init_vgmstream_ngc_lps, + init_vgmstream_ngc_lps, init_vgmstream_ps2_snd, init_vgmstream_naomi_adpcm, - init_vgmstream_sd9, - init_vgmstream_2dx9, - init_vgmstream_dsp_ygo, + init_vgmstream_sd9, + init_vgmstream_2dx9, + init_vgmstream_dsp_ygo, init_vgmstream_ps2_vgv, init_vgmstream_ngc_gcub, init_vgmstream_maxis_xa, init_vgmstream_ngc_sck_dsp, init_vgmstream_apple_caff, - init_vgmstream_pc_mxst, - init_vgmstream_sab, + init_vgmstream_pc_mxst, + init_vgmstream_sab, init_vgmstream_exakt_sc, init_vgmstream_wii_bns, init_vgmstream_wii_was, @@ -244,8 +244,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_stx, init_vgmstream_myspd, init_vgmstream_his, - init_vgmstream_ps2_ast, - init_vgmstream_dmsg, + init_vgmstream_ps2_ast, + init_vgmstream_dmsg, init_vgmstream_ngc_dsp_aaap, init_vgmstream_ngc_dsp_konami, init_vgmstream_ps2_ster, @@ -261,8 +261,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ngc_bo2, init_vgmstream_dsp_ddsp, init_vgmstream_p3d, - init_vgmstream_ps2_tk1, - init_vgmstream_ps2_adsc, + init_vgmstream_ps2_tk1, + init_vgmstream_ps2_adsc, init_vgmstream_ngc_dsp_mpds, init_vgmstream_dsp_str_ig, init_vgmstream_psx_mgav, @@ -274,57 +274,58 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_dsp_xiii, init_vgmstream_dsp_cabelas, init_vgmstream_ps2_adm, - init_vgmstream_ps2_lpcm, + init_vgmstream_ps2_lpcm, init_vgmstream_dsp_bdsp, - init_vgmstream_ps2_vms, - init_vgmstream_xau, + init_vgmstream_ps2_vms, + init_vgmstream_xau, init_vgmstream_bar, init_vgmstream_ffw, init_vgmstream_dsp_dspw, init_vgmstream_ps2_jstm, init_vgmstream_xvag, - init_vgmstream_ps3_cps, + init_vgmstream_ps3_cps, init_vgmstream_sqex_scd, init_vgmstream_ngc_nst_dsp, init_vgmstream_baf, init_vgmstream_ps3_msf, - init_vgmstream_nub_vag, - init_vgmstream_ps3_past, + init_vgmstream_nub_vag, + init_vgmstream_ps3_past, init_vgmstream_sgxd, - init_vgmstream_ngca, - init_vgmstream_wii_ras, - init_vgmstream_ps2_spm, - init_vgmstream_x360_tra, - init_vgmstream_ps2_iab, - init_vgmstream_ps2_strlr, + init_vgmstream_ngca, + init_vgmstream_wii_ras, + init_vgmstream_ps2_spm, + init_vgmstream_x360_tra, + init_vgmstream_ps2_iab, + init_vgmstream_ps2_strlr, init_vgmstream_lsf_n1nj4n, - init_vgmstream_vawx, + init_vgmstream_vawx, init_vgmstream_pc_snds, - init_vgmstream_ps2_wmus, - init_vgmstream_hyperscan_kvag, - init_vgmstream_ios_psnd, - init_vgmstream_pc_adp_bos, - init_vgmstream_pc_adp_otns, + init_vgmstream_ps2_wmus, + init_vgmstream_hyperscan_kvag, + init_vgmstream_ios_psnd, + init_vgmstream_pc_adp_bos, + init_vgmstream_pc_adp_otns, init_vgmstream_eb_sfx, init_vgmstream_eb_sf0, - init_vgmstream_ps3_klbs, + init_vgmstream_ps3_klbs, init_vgmstream_ps2_mtaf, - init_vgmstream_tun, - init_vgmstream_wpd, - init_vgmstream_mn_str, - init_vgmstream_mss, - init_vgmstream_ps2_hsf, - init_vgmstream_ps3_ivag, - init_vgmstream_ps2_2pfs, - init_vgmstream_xnbm, - init_vgmstream_rsd6oogv, - init_vgmstream_ubi_ckd, - init_vgmstream_ps2_vbk, - init_vgmstream_otm, - init_vgmstream_bcstm, - init_vgmstream_3ds_idsp, + init_vgmstream_tun, + init_vgmstream_wpd, + init_vgmstream_mn_str, + init_vgmstream_mss, + init_vgmstream_ps2_hsf, + init_vgmstream_ps3_ivag, + init_vgmstream_ps2_2pfs, + init_vgmstream_xnb, + init_vgmstream_rsd6oogv, + init_vgmstream_ubi_ckd, + init_vgmstream_ps2_vbk, + init_vgmstream_otm, + init_vgmstream_bcstm, + init_vgmstream_3ds_idsp, init_vgmstream_kt_g1l, init_vgmstream_kt_wiibgm, + init_vgmstream_ktss, init_vgmstream_hca, init_vgmstream_ps2_svag_snk, init_vgmstream_ps2_vds_vdm, @@ -349,6 +350,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_rsd6xma, init_vgmstream_ta_aac_x360, init_vgmstream_ta_aac_ps3, + init_vgmstream_ta_aac_mobile, init_vgmstream_ps3_mta2, init_vgmstream_ngc_ulw, init_vgmstream_pc_xa30, @@ -370,7 +372,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ea_sps, init_vgmstream_ngc_vid1, init_vgmstream_flx, - init_vgmstream_mogg, + init_vgmstream_mogg, init_vgmstream_txth, /* should go at the end (lower priority) */ #ifdef VGM_USE_FFMPEG @@ -512,9 +514,9 @@ void reset_vgmstream(VGMSTREAM * vgmstream) { } #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) - if (vgmstream->coding_type==coding_MP4_AAC) { - reset_mp4_aac(vgmstream); - } + if (vgmstream->coding_type==coding_MP4_AAC) { + reset_mp4_aac(vgmstream); + } #endif #ifdef VGM_USE_MPEG @@ -541,11 +543,17 @@ void reset_vgmstream(VGMSTREAM * vgmstream) { #endif #ifdef VGM_USE_MAIATRAC3PLUS - if (vgmstream->coding_type==coding_AT3plus) { - reset_at3plus(vgmstream); - } + if (vgmstream->coding_type==coding_AT3plus) { + reset_at3plus(vgmstream); + } #endif - + +#ifdef VGM_USE_ATRAC9 + if (vgmstream->coding_type==coding_ATRAC9) { + reset_atrac9(vgmstream); + } +#endif + #ifdef VGM_USE_FFMPEG if (vgmstream->coding_type==coding_FFmpeg) { reset_ffmpeg(vgmstream); @@ -701,10 +709,10 @@ void close_vgmstream(VGMSTREAM * vgmstream) { #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) - if (vgmstream->coding_type==coding_MP4_AAC) { - free_mp4_aac(vgmstream->codec_data); + if (vgmstream->coding_type==coding_MP4_AAC) { + free_mp4_aac(vgmstream->codec_data); vgmstream->codec_data = NULL; - } + } #endif #ifdef VGM_USE_MPEG @@ -734,10 +742,17 @@ void close_vgmstream(VGMSTREAM * vgmstream) { #endif #ifdef VGM_USE_MAIATRAC3PLUS - if (vgmstream->coding_type == coding_AT3plus) { - free_at3plus(vgmstream->codec_data); + if (vgmstream->coding_type == coding_AT3plus) { + free_at3plus(vgmstream->codec_data); vgmstream->codec_data = NULL; - } + } +#endif + +#ifdef VGM_USE_ATRAC9 + if (vgmstream->coding_type == coding_ATRAC9) { + free_atrac9(vgmstream->codec_data); + vgmstream->codec_data = NULL; + } #endif if (vgmstream->coding_type==coding_ACM) { @@ -926,7 +941,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_none: render_vgmstream_nolayout(buffer,sample_count,vgmstream); break; - case layout_mxch_blocked: + case layout_mxch_blocked: case layout_ast_blocked: case layout_halpst_blocked: case layout_xa_blocked: @@ -949,8 +964,8 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_psx_mgav_blocked: case layout_ps2_adm_blocked: case layout_dsp_bdsp_blocked: - case layout_tra_blocked: - case layout_ps2_iab_blocked: + case layout_tra_blocked: + case layout_ps2_iab_blocked: case layout_ps2_strlr_blocked: case layout_rws_blocked: case layout_hwas_blocked: @@ -986,7 +1001,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_CRI_ADX_exp: case coding_CRI_ADX_enc_8: case coding_CRI_ADX_enc_9: - return (vgmstream->interleave_block_size - 2) * 2; + return (vgmstream->interleave_block_size - 2) * 2; case coding_L5_555: return 32; case coding_NGC_DSP: @@ -1002,6 +1017,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_PCM8_SB_int: case coding_PCM8_U_int: case coding_ULAW: + case coding_ULAW_int: case coding_ALAW: case coding_PCMFLOAT: return 1; @@ -1056,14 +1072,14 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_PSX_cfg: return (vgmstream->interleave_block_size - 1) * 2; /* decodes 1 byte into 2 bytes */ case coding_XBOX: - case coding_XBOX_int: + case coding_XBOX_int: case coding_FSB_IMA: return 64; case coding_EA_XA: case coding_EA_XA_int: case coding_EA_XA_V2: case coding_MAXIS_XA: - return 28; + return 28; case coding_EA_XAS: return 128; case coding_WS: @@ -1099,7 +1115,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { { ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data; if (data) { - /* must know the full block size for edge loops */ + /* must know the full block size for edge loops */ return data->sampleBufferBlock; } return 0; @@ -1119,12 +1135,16 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_CRI_HCA: return clHCA_samplesPerBlock; #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) - case coding_MP4_AAC: - return ((mp4_aac_codec_data*)vgmstream->codec_data)->samples_per_frame; + case coding_MP4_AAC: + return ((mp4_aac_codec_data*)vgmstream->codec_data)->samples_per_frame; #endif #ifdef VGM_USE_MAIATRAC3PLUS - case coding_AT3plus: - return 2048 - ((maiatrac3plus_codec_data*)vgmstream->codec_data)->samples_discard; + case coding_AT3plus: + return 2048 - ((maiatrac3plus_codec_data*)vgmstream->codec_data)->samples_discard; +#endif +#ifdef VGM_USE_ATRAC9 + case coding_ATRAC9: + return 0; /* varies with config data, usually 256 or 1024 */ #endif default: return 0; @@ -1157,6 +1177,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_PCM8_SB_int: case coding_PCM8_U_int: case coding_ULAW: + case coding_ULAW_int: case coding_ALAW: return 1; case coding_PCMFLOAT: @@ -1204,7 +1225,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_XA: return 14*vgmstream->channels; case coding_XBOX: - case coding_XBOX_int: + case coding_XBOX_int: case coding_FSB_IMA: return 36; case coding_EA_XA: @@ -1239,7 +1260,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_G719: #endif #ifdef VGM_USE_MAIATRAC3PLUS - case coding_AT3plus: + case coding_AT3plus: #endif #ifdef VGM_USE_FFMPEG case coding_FFmpeg: @@ -1253,6 +1274,10 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { return 0x04; case coding_EA_MT: return 0; /* variable (frames of bit counts or PCM frames) */ +#ifdef VGM_USE_ATRAC9 + case coding_ATRAC9: + return 0; /* varies with config data, usually 0x100-200 */ +#endif default: return 0; } @@ -1405,6 +1430,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; + case coding_ULAW_int: + for (chan=0;chanchannels;chan++) { + decode_ulaw_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; case coding_ALAW: for (chan=0;chanchannels;chan++) { decode_alaw(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, @@ -1595,11 +1627,11 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to break; #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) - case coding_MP4_AAC: - decode_mp4_aac(vgmstream->codec_data, - buffer+samples_written*vgmstream->channels,samples_to_do, - vgmstream->channels); - break; + case coding_MP4_AAC: + decode_mp4_aac(vgmstream->codec_data, + buffer+samples_written*vgmstream->channels,samples_to_do, + vgmstream->channels); + break; #endif case coding_SDX2: for (chan=0;chanchannels;chan++) { @@ -1752,15 +1784,23 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to break; #endif #ifdef VGM_USE_MAIATRAC3PLUS - case coding_AT3plus: - for (chan=0;chanchannels;chan++) { - decode_at3plus(vgmstream, - buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels, - samples_to_do, - chan); - } - break; + case coding_AT3plus: + for (chan=0;chanchannels;chan++) { + decode_at3plus(vgmstream, + buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels, + samples_to_do, + chan); + } + break; +#endif +#ifdef VGM_USE_ATRAC9 + case coding_ATRAC9: + decode_atrac9(vgmstream, + buffer+samples_written*vgmstream->channels, + samples_to_do, + vgmstream->channels); + break; #endif case coding_ACM: /* handled in its own layout, here to quiet compiler */ @@ -1964,6 +2004,12 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) { } #endif +#ifdef VGM_USE_ATRAC9 + if (vgmstream->coding_type==coding_ATRAC9) { + seek_atrac9(vgmstream, vgmstream->loop_sample); + } +#endif + #ifdef VGM_USE_MPEG if (vgmstream->coding_type==coding_MPEG_custom || vgmstream->coding_type==coding_MPEG_ealayer3 || diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index 41b00f519..3cbe097b3 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -22,13 +22,14 @@ enum { STREAM_NAME_SIZE = 255 }; /* reasonable max */ #define VGM_USE_MPEG #endif -/* disabled by default, defined on compile-time for builds that support it*/ +/* disabled by default, defined on compile-time for builds that support it */ #define VGM_USE_G7221 #define VGM_USE_G719 //#define VGM_USE_MP4V2 //#define VGM_USE_FDKAAC //#define VGM_USE_MAIATRAC3PLUS #define VGM_USE_FFMPEG +#define VGM_USE_ATRAC9 #ifdef VGM_USE_VORBIS #ifdef __APPLE__ @@ -44,6 +45,7 @@ enum { STREAM_NAME_SIZE = 255 }; /* reasonable max */ #ifdef VGM_USE_G7221 #include #endif + #ifdef VGM_USE_G719 #include #endif @@ -88,12 +90,13 @@ typedef enum { coding_PCM16_int, /* 16-bit PCM with sample-level interleave (for blocks) */ coding_PCM8, /* 8-bit PCM */ - coding_PCM8_int, /* 8-Bit PCM with sample-level interleave (for blocks) */ + coding_PCM8_int, /* 8-bit PCM with sample-level interleave (for blocks) */ coding_PCM8_U, /* 8-bit PCM, unsigned (0x80 = 0) */ coding_PCM8_U_int, /* 8-bit PCM, unsigned (0x80 = 0) with sample-level interleave (for blocks) */ coding_PCM8_SB_int, /* 8-bit PCM, sign bit (others are 2's complement) with sample-level interleave (for blocks) */ coding_ULAW, /* 8-bit u-Law (non-linear PCM) */ + coding_ULAW_int, /* 8-bit u-Law (non-linear PCM) with sample-level interleave (for blocks) */ coding_ALAW, /* 8-bit a-Law (non-linear PCM) */ coding_PCMFLOAT, /* 32 bit float PCM */ @@ -113,7 +116,7 @@ typedef enum { coding_G721, /* CCITT G.721 */ coding_XA, /* CD-ROM XA */ - coding_PSX, /* Sony PS ADPCM (VAG) */ + coding_PSX, /* Sony PS ADPCM (VAG) */ coding_PSX_badflags, /* Sony PS ADPCM with custom flag byte */ coding_PSX_bmdx, /* Sony PS ADPCM with BMDX encryption */ coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (FF XI, SGXD type 5, Bizarre Creations) */ @@ -128,7 +131,7 @@ typedef enum { coding_IMA, /* IMA ADPCM (stereo or mono, low nibble first) */ coding_IMA_int, /* IMA ADPCM (mono/interleave, low nibble first) */ coding_DVI_IMA, /* DVI IMA ADPCM (stereo or mono, high nibble first) */ - coding_DVI_IMA_int, /* DVI IMA ADPCM (mono/interleave, high nibble first) */ + coding_DVI_IMA_int, /* DVI IMA ADPCM (mono/interleave, high nibble first) */ coding_3DS_IMA, /* 3DS IMA ADPCM */ coding_MS_IMA, /* Microsoft IMA ADPCM */ coding_XBOX, /* XBOX IMA ADPCM */ @@ -197,11 +200,15 @@ typedef enum { #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) - coding_MP4_AAC, /* AAC (MDCT-based) */ + coding_MP4_AAC, /* AAC (MDCT-based) */ #endif #ifdef VGM_USE_MAIATRAC3PLUS - coding_AT3plus, /* Sony ATRAC3plus (MDCT-based) */ + coding_AT3plus, /* Sony ATRAC3plus (MDCT-based) */ +#endif + +#ifdef VGM_USE_ATRAC9 + coding_ATRAC9, /* Sony ATRAC9 (MDCT-based) */ #endif #ifdef VGM_USE_FFMPEG @@ -257,7 +264,7 @@ typedef enum { layout_mus_acm, /* mus has multi-files to deal with */ layout_aix, /* CRI AIX's wheels within wheels */ layout_aax, /* CRI AAX's wheels within databases */ - layout_scd_int, /* deinterleave done by the SCDINTSTREAMFILE */ + layout_scd_int, /* deinterleave done by the SCDINTSTREAMFILE */ #ifdef VGM_USE_VORBIS layout_ogg_vorbis, /* ogg vorbis file */ @@ -278,14 +285,14 @@ typedef enum { meta_DSP_JETTERS, /* Bomberman Jetters .dsp */ meta_DSP_MSS, /* ? */ meta_DSP_GCM, /* ? */ - meta_DSP_STR, /* Conan .str files */ + meta_DSP_STR, /* Conan .str files */ meta_DSP_SADB, /* .sad */ meta_DSP_WSI, /* .wsi */ - meta_DSP_WII_IDSP, /* .gcm with IDSP header */ + meta_DSP_WII_IDSP, /* .gcm with IDSP header */ meta_DSP_WII_MUS, /* .mus */ - meta_DSP_WII_WSD, /* Phantom Brave (WII) */ - meta_WII_NDP, /* Vertigo (Wii) */ - meta_DSP_YGO, /* Konami: Yu-Gi-Oh! The Falsebound Kingdom (NGC), Hikaru no Go 3 (NGC) */ + meta_DSP_WII_WSD, /* Phantom Brave (WII) */ + meta_WII_NDP, /* Vertigo (Wii) */ + meta_DSP_YGO, /* Konami: Yu-Gi-Oh! The Falsebound Kingdom (NGC), Hikaru no Go 3 (NGC) */ /* Nintendo */ meta_STRM, /* Nintendo STRM */ @@ -296,15 +303,15 @@ typedef enum { meta_RWAR, /* single-stream RWAR */ meta_RWAV, /* contents of RWAR */ meta_CWAV, /* contents of CWAR */ - meta_FWAV, /* contents of FWAR */ + meta_FWAV, /* contents of FWAR */ meta_RSTM_SPM, /* RSTM with 44->22khz hack */ meta_THP, /* THP movie files */ meta_RSTM_shrunken, /* Atlus' mutant shortened RSTM */ - meta_NDS_SWAV, /* Asphalt Urban GT 1 & 2 */ - meta_NDS_RRDS, /* Ridge Racer DS */ + meta_NDS_SWAV, /* Asphalt Urban GT 1 & 2 */ + meta_NDS_RRDS, /* Ridge Racer DS */ meta_WII_BNS, /* Wii BNS Banner Sound (similar to RSTM) */ meta_STX, /* Pikmin .stx */ - meta_WIIU_BTSND, /* Wii U Boot Sound */ + meta_WIIU_BTSND, /* Wii U Boot Sound */ meta_ADX_03, /* CRI ADX "type 03" */ meta_ADX_04, /* CRI ADX "type 04" */ @@ -317,157 +324,157 @@ typedef enum { meta_RSF, /* Retro Studios RSF (Metroid Prime .rsf) [no header_id] */ meta_HALPST, /* HAL Labs HALPST */ meta_GCSW, /* GCSW (PCM) */ - meta_CFN, /* Namco CAF Audio File */ + meta_CFN, /* Namco CAF Audio File */ meta_MYSPD, /* U-Sing .myspd */ meta_HIS, /* Her Ineractive .his */ meta_BNSF, /* Bandai Namco Sound Format */ meta_PSX_XA, /* CD-ROM XA */ - meta_PS2_SShd, /* .ADS with SShd header */ - meta_PS2_NPSF, /* Namco Production Sound File */ + meta_PS2_SShd, /* .ADS with SShd header */ + meta_PS2_NPSF, /* Namco Production Sound File */ meta_PS2_RXWS, /* Sony games (Genji, Okage Shadow King, Arc The Lad Twilight of Spirits) */ - meta_PS2_RAW, /* RAW Interleaved Format */ - meta_PS2_EXST, /* Shadow of Colossus EXST */ - meta_PS2_SVAG, /* Konami SVAG */ - meta_PS2_MIB, /* MIB File */ - meta_PS2_MIB_MIH, /* MIB File + MIH Header*/ - meta_PS2_MIC, /* KOEI MIC File */ - meta_PS2_VAGi, /* VAGi Interleaved File */ - meta_PS2_VAGp, /* VAGp Mono File */ - meta_PS2_VAGm, /* VAGp Mono File */ - meta_PS2_pGAV, /* VAGp with Little Endian Header */ + meta_PS2_RAW, /* RAW Interleaved Format */ + meta_PS2_EXST, /* Shadow of Colossus EXST */ + meta_PS2_SVAG, /* Konami SVAG */ + meta_PS2_MIB, /* MIB File */ + meta_PS2_MIB_MIH, /* MIB File + MIH Header*/ + meta_PS2_MIC, /* KOEI MIC File */ + meta_PS2_VAGi, /* VAGi Interleaved File */ + meta_PS2_VAGp, /* VAGp Mono File */ + meta_PS2_VAGm, /* VAGp Mono File */ + meta_PS2_pGAV, /* VAGp with Little Endian Header */ meta_PSX_GMS, /* GMS File (used in PS1 & PS2) [no header_id] */ - meta_PS2_STR, /* Pacman STR+STH files */ - meta_PS2_ILD, /* ILD File */ - meta_PS2_PNB, /* PsychoNauts Bgm File */ - meta_PS2_VAGs, /* VAG Stereo from Kingdom Hearts */ - meta_PS2_VPK, /* VPK Audio File */ + meta_PS2_STR, /* Pacman STR+STH files */ + meta_PS2_ILD, /* ILD File */ + meta_PS2_PNB, /* PsychoNauts Bgm File */ + meta_PS2_VAGs, /* VAG Stereo from Kingdom Hearts */ + meta_PS2_VPK, /* VPK Audio File */ meta_PS2_BMDX, /* Beatmania thing */ meta_PS2_IVB, /* Langrisser 3 IVB */ meta_PS2_SND, /* some Might & Magics SSND header */ meta_PS2_SVS, /* Square SVS */ - meta_XSS, /* Dino Crisis 3 */ - meta_SL3, /* Test Drive Unlimited */ - meta_HGC1, /* Knights of the Temple 2 */ - meta_AUS, /* Various Capcom games */ - meta_RWS, /* RenderWare games (only when using RW Audio middleware) */ + meta_XSS, /* Dino Crisis 3 */ + meta_SL3, /* Test Drive Unlimited */ + meta_HGC1, /* Knights of the Temple 2 */ + meta_AUS, /* Various Capcom games */ + meta_RWS, /* RenderWare games (only when using RW Audio middleware) */ meta_FSB1, /* FMOD Sample Bank, version 1 */ meta_FSB2, /* FMOD Sample Bank, version 2 */ meta_FSB3, /* FMOD Sample Bank, version 3.0/3.1 */ meta_FSB4, /* FMOD Sample Bank, version 4 */ meta_FSB5, /* FMOD Sample Bank, version 5 */ - meta_RWX, /* Air Force Delta Storm (XBOX) */ - meta_XWB, /* Microsoft XACT framework (Xbox, X360, Windows) */ + meta_RWX, /* Air Force Delta Storm (XBOX) */ + meta_XWB, /* Microsoft XACT framework (Xbox, X360, Windows) */ meta_PS2_XA30, /* Driver - Parallel Lines (PS2) */ - meta_MUSC, /* Krome PS2 games */ - meta_MUSX_V004, /* Spyro Games, possibly more */ - meta_MUSX_V005, /* Spyro Games, possibly more */ - meta_MUSX_V006, /* Spyro Games, possibly more */ - meta_MUSX_V010, /* Spyro Games, possibly more */ - meta_MUSX_V201, /* Sphinx and the cursed Mummy */ - meta_LEG, /* Legaia 2 [no header_id] */ - meta_FILP, /* Resident Evil - Dead Aim */ - meta_IKM, /* Zwei! */ - meta_SFS, /* Baroque */ - meta_BG00, /* Ibara, Mushihimesama */ - meta_PS2_RSTM, /* Midnight Club 3 */ - meta_PS2_KCES, /* Dance Dance Revolution */ - meta_PS2_DXH, /* Tokobot Plus - Myteries of the Karakuri */ - meta_PS2_PSH, /* Dawn of Mana - Seiken Densetsu 4 */ - meta_SCD_PCM, /* Lunar - Eternal Blue */ - meta_PS2_PCM, /* Konami KCEJ East: Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses, 7 Blades */ - meta_PS2_RKV, /* Legacy of Kain - Blood Omen 2 */ - meta_PS2_PSW, /* Rayman Raving Rabbids */ - meta_PS2_VAS, /* Pro Baseball Spirits 5 */ - meta_PS2_TEC, /* TECMO badflagged stream */ - meta_PS2_ENTH, /* Enthusia */ - meta_SDT, /* Baldur's Gate - Dark Alliance */ - meta_NGC_TYDSP, /* Ty - The Tasmanian Tiger */ - meta_NGC_SWD, /* Conflict - Desert Storm 1 & 2 */ + meta_MUSC, /* Krome PS2 games */ + meta_MUSX_V004, /* Spyro Games, possibly more */ + meta_MUSX_V005, /* Spyro Games, possibly more */ + meta_MUSX_V006, /* Spyro Games, possibly more */ + meta_MUSX_V010, /* Spyro Games, possibly more */ + meta_MUSX_V201, /* Sphinx and the cursed Mummy */ + meta_LEG, /* Legaia 2 [no header_id] */ + meta_FILP, /* Resident Evil - Dead Aim */ + meta_IKM, /* Zwei! */ + meta_SFS, /* Baroque */ + meta_BG00, /* Ibara, Mushihimesama */ + meta_PS2_RSTM, /* Midnight Club 3 */ + meta_PS2_KCES, /* Dance Dance Revolution */ + meta_PS2_DXH, /* Tokobot Plus - Myteries of the Karakuri */ + meta_PS2_PSH, /* Dawn of Mana - Seiken Densetsu 4 */ + meta_SCD_PCM, /* Lunar - Eternal Blue */ + meta_PS2_PCM, /* Konami KCEJ East: Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses, 7 Blades */ + meta_PS2_RKV, /* Legacy of Kain - Blood Omen 2 */ + meta_PS2_PSW, /* Rayman Raving Rabbids */ + meta_PS2_VAS, /* Pro Baseball Spirits 5 */ + meta_PS2_TEC, /* TECMO badflagged stream */ + meta_PS2_ENTH, /* Enthusia */ + meta_SDT, /* Baldur's Gate - Dark Alliance */ + meta_NGC_TYDSP, /* Ty - The Tasmanian Tiger */ + meta_NGC_SWD, /* Conflict - Desert Storm 1 & 2 */ meta_CAPDSP, /* Capcom DSP Header [no header_id] */ - meta_DC_STR, /* SEGA Stream Asset Builder */ - meta_DC_STR_V2, /* variant of SEGA Stream Asset Builder */ - meta_NGC_BH2PCM, /* Bio Hazard 2 */ - meta_SAT_SAP, /* Bubble Symphony */ - meta_DC_IDVI, /* Eldorado Gate */ - meta_KRAW, /* Geometry Wars - Galaxies */ - meta_PS2_OMU, /* PS2 Int file with Header */ - meta_PS2_XA2, /* XG3 Extreme-G Racing */ - meta_IDSP, /* Chronicles of Narnia, Soul Calibur Legends, Mario Strikers Charged */ - meta_SPT_SPD, /* Various (SPT+SPT DSP) */ - meta_ISH_ISD, /* Various (ISH+ISD DSP) */ - meta_GSP_GSB, /* Tecmo games (Super Swing Golf 1 & 2, Quamtum Theory) */ - meta_YDSP, /* WWE Day of Reckoning */ + meta_DC_STR, /* SEGA Stream Asset Builder */ + meta_DC_STR_V2, /* variant of SEGA Stream Asset Builder */ + meta_NGC_BH2PCM, /* Bio Hazard 2 */ + meta_SAT_SAP, /* Bubble Symphony */ + meta_DC_IDVI, /* Eldorado Gate */ + meta_KRAW, /* Geometry Wars - Galaxies */ + meta_PS2_OMU, /* PS2 Int file with Header */ + meta_PS2_XA2, /* XG3 Extreme-G Racing */ + meta_IDSP, /* Chronicles of Narnia, Soul Calibur Legends, Mario Strikers Charged */ + meta_SPT_SPD, /* Various (SPT+SPT DSP) */ + meta_ISH_ISD, /* Various (ISH+ISD DSP) */ + meta_GSP_GSB, /* Tecmo games (Super Swing Golf 1 & 2, Quamtum Theory) */ + meta_YDSP, /* WWE Day of Reckoning */ meta_FFCC_STR, /* Final Fantasy: Crystal Chronicles */ - meta_WAA_WAC_WAD_WAM, /* Beyond Good & Evil */ - meta_GCA, /* Metal Slug Anthology */ - meta_MSVP, /* Popcap Hits */ - meta_NGC_SSM, /* Golden Gashbell Full Power */ - meta_PS2_JOE, /* Wall-E / Pixar games */ + meta_WAA_WAC_WAD_WAM, /* Beyond Good & Evil */ + meta_GCA, /* Metal Slug Anthology */ + meta_MSVP, /* Popcap Hits */ + meta_NGC_SSM, /* Golden Gashbell Full Power */ + meta_PS2_JOE, /* Wall-E / Pixar games */ - meta_NGC_YMF, /* WWE WrestleMania X8 */ + meta_NGC_YMF, /* WWE WrestleMania X8 */ meta_SADL, /* .sad */ meta_PS2_CCC, /* Tokyo Xtreme Racer DRIFT 2 */ meta_PSX_FAG, /* Jackie Chan - Stuntmaster */ meta_PS2_MIHB, /* Merged MIH+MIB */ meta_NGC_PDT, /* Mario Party 6 */ - meta_DC_ASD, /* Miss Moonligh */ - meta_NAOMI_SPSD, /* Guilty Gear X */ + meta_DC_ASD, /* Miss Moonligh */ + meta_NAOMI_SPSD, /* Guilty Gear X */ - meta_RSD2VAG, /* RSD2VAG */ - meta_RSD2PCMB, /* RSD2PCMB */ - meta_RSD2XADP, /* RSD2XADP */ - meta_RSD3VAG, /* RSD3VAG */ - meta_RSD3GADP, /* RSD3GADP */ - meta_RSD3PCM, /* RSD3PCM */ - meta_RSD3PCMB, /* RSD3PCMB */ - meta_RSD4PCMB, /* RSD4PCMB */ - meta_RSD4PCM, /* RSD4PCM */ - meta_RSD4RADP, /* RSD4RADP */ - meta_RSD4VAG, /* RSD4VAG */ - meta_RSD6VAG, /* RSD6VAG */ - meta_RSD6WADP, /* RSD6WADP */ - meta_RSD6XADP, /* RSD6XADP */ - meta_RSD6RADP, /* RSD6RADP */ - meta_RSD6OOGV, /* RSD6OOGV */ + meta_RSD2VAG, /* RSD2VAG */ + meta_RSD2PCMB, /* RSD2PCMB */ + meta_RSD2XADP, /* RSD2XADP */ + meta_RSD3VAG, /* RSD3VAG */ + meta_RSD3GADP, /* RSD3GADP */ + meta_RSD3PCM, /* RSD3PCM */ + meta_RSD3PCMB, /* RSD3PCMB */ + meta_RSD4PCMB, /* RSD4PCMB */ + meta_RSD4PCM, /* RSD4PCM */ + meta_RSD4RADP, /* RSD4RADP */ + meta_RSD4VAG, /* RSD4VAG */ + meta_RSD6VAG, /* RSD6VAG */ + meta_RSD6WADP, /* RSD6WADP */ + meta_RSD6XADP, /* RSD6XADP */ + meta_RSD6RADP, /* RSD6RADP */ + meta_RSD6OOGV, /* RSD6OOGV */ meta_RSD6XMA, /* RSD6XMA */ - meta_PS2_ASS, /* ASS */ - meta_PS2_SEG, /* Eragon */ + meta_PS2_ASS, /* ASS */ + meta_PS2_SEG, /* Eragon */ meta_XBOX_SEG, /* Eragon */ - meta_NDS_STRM_FFTA2, /* Final Fantasy Tactics A2 */ - meta_STR_ASR, /* Donkey Kong Jet Race */ - meta_ZWDSP, /* Zack and Wiki */ - meta_VGS, /* Guitar Hero Encore - Rocks the 80s */ - meta_DC_DCSW_DCS, /* Evil Twin - Cypriens Chronicles (DC) */ - meta_WII_SMP, /* Mushroom Men - The Spore Wars */ + meta_NDS_STRM_FFTA2, /* Final Fantasy Tactics A2 */ + meta_STR_ASR, /* Donkey Kong Jet Race */ + meta_ZWDSP, /* Zack and Wiki */ + meta_VGS, /* Guitar Hero Encore - Rocks the 80s */ + meta_DC_DCSW_DCS, /* Evil Twin - Cypriens Chronicles (DC) */ + meta_WII_SMP, /* Mushroom Men - The Spore Wars */ meta_WII_SNG, /* Excite Trucks */ - meta_EMFF_PS2, /* Eidos Music File Format for PS2*/ - meta_EMFF_NGC, /* Eidos Music File Format for NGC/WII */ - meta_SAT_BAKA, /* Crypt Killer */ + meta_EMFF_PS2, /* Eidos Music File Format for PS2*/ + meta_EMFF_NGC, /* Eidos Music File Format for NGC/WII */ + meta_SAT_BAKA, /* Crypt Killer */ meta_PS2_VSF, /* Musashi: Samurai Legend */ - meta_PS2_VSF_TTA, /* Tiny Toon Adventures: Defenders of the Universe */ - meta_ADS, /* Gauntlet Dark Legends (GC) */ - meta_PS2_SPS, /* Ape Escape 2 */ + meta_PS2_VSF_TTA, /* Tiny Toon Adventures: Defenders of the Universe */ + meta_ADS, /* Gauntlet Dark Legends (GC) */ + meta_PS2_SPS, /* Ape Escape 2 */ meta_PS2_XA2_RRP, /* RC Revenge Pro */ meta_NGC_DSP_KONAMI, /* Konami DSP header, found in various games */ - meta_UBI_CKD, /* Ubisoft CKD RIFF header (Rayman Origins Wii) */ + meta_UBI_CKD, /* Ubisoft CKD RIFF header (Rayman Origins Wii) */ - meta_XBOX_WAVM, /* XBOX WAVM File */ - meta_XBOX_RIFF, /* XBOX RIFF/WAVE File */ - meta_XBOX_WVS, /* XBOX WVS */ - meta_NGC_WVS, /* Metal Arms - Glitch in the System */ - meta_XBOX_MATX, /* XBOX MATX */ - meta_XBOX_XMU, /* XBOX XMU */ - meta_XBOX_XVAS, /* XBOX VAS */ + meta_XBOX_WAVM, /* XBOX WAVM File */ + meta_XBOX_RIFF, /* XBOX RIFF/WAVE File */ + meta_XBOX_WVS, /* XBOX WVS */ + meta_NGC_WVS, /* Metal Arms - Glitch in the System */ + meta_XBOX_MATX, /* XBOX MATX */ + meta_XBOX_XMU, /* XBOX XMU */ + meta_XBOX_XVAS, /* XBOX VAS */ meta_EA_SCHL, /* Electronic Arts SCHl with variable header */ meta_EA_SCHL_fixed, /* Electronic Arts SCHl with fixed header */ meta_EA_BNK, /* Electronic Arts BNK */ meta_EA_1SNH, /* Electronic Arts 1SNh/EACS */ - meta_RAW, /* RAW PCM file */ + meta_RAW, /* RAW PCM file */ meta_GENH, /* generic header */ @@ -486,7 +493,7 @@ typedef enum { meta_RIFX_WAVE_smpl, /* RIFX w/ loop data in smpl chunk */ meta_XNB, /* XNA Game Studio 4.0 */ meta_PC_MXST, /* Lego Island MxSt */ - meta_SAB, /* Worms 4 Mayhem SAB+SOB file */ + meta_SAB, /* Worms 4 Mayhem SAB+SOB file */ meta_NWA, /* Visual Art's NWA */ meta_NWA_NWAINFOINI, /* Visual Art's NWA w/ NWAINFO.INI for looping */ meta_NWA_GAMEEXEINI, /* Visual Art's NWA w/ Gameexe.ini for looping */ @@ -495,24 +502,24 @@ typedef enum { meta_ACM, /* InterPlay ACM header */ meta_MUS_ACM, /* MUS playlist of InterPlay ACM files */ meta_DEC, /* Falcom PC games (Xanadu Next, Gurumin) */ - meta_VS, /* Men in Black .vs */ + meta_VS, /* Men in Black .vs */ meta_FFXI_BGW, /* FFXI (PC) BGW */ meta_FFXI_SPW, /* FFXI (PC) SPW */ - meta_STS_WII, /* Shikigami No Shiro 3 STS Audio File */ - meta_PS2_P2BT, /* Pop'n'Music 7 Audio File */ - meta_PS2_GBTS, /* Pop'n'Music 9 Audio File */ + meta_STS_WII, /* Shikigami No Shiro 3 STS Audio File */ + meta_PS2_P2BT, /* Pop'n'Music 7 Audio File */ + meta_PS2_GBTS, /* Pop'n'Music 9 Audio File */ meta_NGC_DSP_IADP, /* Gamecube Interleave DSP */ - meta_PS2_TK5, /* Tekken 5 Stream Files */ - meta_WII_STR, /* House of The Dead Overkill STR+STH */ - meta_PS2_MCG, /* Gunvari MCG Files (was name .GCM on disk) */ + meta_PS2_TK5, /* Tekken 5 Stream Files */ + meta_WII_STR, /* House of The Dead Overkill STR+STH */ + meta_PS2_MCG, /* Gunvari MCG Files (was name .GCM on disk) */ meta_ZSD, /* Dragon Booster ZSD */ meta_RedSpark, /* "RedSpark" RSD (MadWorld) */ - meta_PC_IVAUD, /* .ivaud GTA IV */ - meta_NDS_HWAS, /* Spider-Man 3, Tony Hawk's Downhill Jam, possibly more... */ - meta_NGC_LPS, /* Rave Master (Groove Adventure Rave)(GC) */ - meta_NAOMI_ADPCM, /* NAOMI/NAOMI2 ARcade games */ - meta_SD9, /* beatmaniaIIDX16 - EMPRESS (Arcade) */ - meta_2DX9, /* beatmaniaIIDX16 - EMPRESS (Arcade) */ + meta_PC_IVAUD, /* .ivaud GTA IV */ + meta_NDS_HWAS, /* Spider-Man 3, Tony Hawk's Downhill Jam, possibly more... */ + meta_NGC_LPS, /* Rave Master (Groove Adventure Rave)(GC) */ + meta_NAOMI_ADPCM, /* NAOMI/NAOMI2 ARcade games */ + meta_SD9, /* beatmaniaIIDX16 - EMPRESS (Arcade) */ + meta_2DX9, /* beatmaniaIIDX16 - EMPRESS (Arcade) */ meta_PS2_VGV, /* Rune: Viking Warlord */ meta_NGC_GCUB, /* Sega Soccer Slam */ meta_MAXIS_XA, /* Sim City 3000 (PC) */ @@ -523,9 +530,9 @@ typedef enum { meta_PONA_3DO, /* Policenauts (3DO) */ meta_PONA_PSX, /* Policenauts (PSX) */ meta_XBOX_HLWAV, /* Half Life 2 (XBOX) */ - meta_PS2_AST, /* Some KOEI game (PS2) */ - meta_DMSG, /* Nightcaster II - Equinox (XBOX) */ - meta_NGC_DSP_AAAP, /* Turok: Evolution (NGC), Vexx (NGC) */ + meta_PS2_AST, /* Some KOEI game (PS2) */ + meta_DMSG, /* Nightcaster II - Equinox (XBOX) */ + meta_NGC_DSP_AAAP, /* Turok: Evolution (NGC), Vexx (NGC) */ meta_PS2_STER, /* Juuni Kokuki: Kakukaku Taru Ou Michi Beni Midori no Uka */ meta_PS2_WB, /* Shooting Love. ~TRIZEAL~ */ meta_S14, /* raw Siren 14, 24kbit mono */ @@ -537,7 +544,7 @@ typedef enum { meta_PS2_KHV, /* Kingdom Hearts 2 VAG streams */ meta_PC_SMP, /* Ghostbusters PC .smp */ meta_P3D, /* Prototype P3D */ - meta_PS2_TK1, /* Tekken (NamCollection) */ + meta_PS2_TK1, /* Tekken (NamCollection) */ meta_PS2_ADSC, /* Kenka Bancho 2: Full Throttle */ meta_NGC_BO2, /* Blood Omen 2 (NGC) */ meta_DSP_DDSP, /* Various (2 dsp files stuck together */ @@ -550,10 +557,10 @@ typedef enum { meta_DSP_XIII, /* XIII, possibly more (Ubisoft header???) */ meta_DSP_CABELAS, /* Cabelas games */ meta_PS2_ADM, /* Dragon Quest 5 */ - meta_PS2_LPCM, /* Ah! My Goddess */ + meta_PS2_LPCM, /* Ah! My Goddess */ meta_DSP_BDSP, /* Ah! My Goddess */ - meta_PS2_VMS, /* Autobahn Raser - Police Madness */ - meta_XAU, /* XPEC Entertainment (Beat Down (PS2 Xbox), Spectral Force Chronicle (PS2)) */ + meta_PS2_VMS, /* Autobahn Raser - Police Madness */ + meta_XAU, /* XPEC Entertainment (Beat Down (PS2 Xbox), Spectral Force Chronicle (PS2)) */ meta_GH3_BAR, /* Guitar Hero III Mobile .bar */ meta_FFW, /* Freedom Fighters [NGC] */ meta_DSP_DSPW, /* Sengoku Basara 3 [WII] */ @@ -561,46 +568,47 @@ typedef enum { meta_SQEX_SCD, /* Square-Enix SCD */ meta_NGC_NST_DSP, /* Animaniacs [NGC] */ meta_BAF, /* Bizarre Creations (Blur, James Bond) */ - meta_XVAG, /* Ratchet & Clank Future: Quest for Booty (PS3) */ - meta_PS3_CPS, /* Eternal Sonata (PS3) */ + meta_XVAG, /* Ratchet & Clank Future: Quest for Booty (PS3) */ + meta_PS3_CPS, /* Eternal Sonata (PS3) */ meta_PS3_MSF, /* MSF header */ - meta_NUB_VAG, /* Namco VAG from NUB archives */ - meta_PS3_PAST, /* Bakugan Battle Brawlers (PS3) */ + meta_NUB_VAG, /* Namco VAG from NUB archives */ + meta_PS3_PAST, /* Bakugan Battle Brawlers (PS3) */ meta_SGXD, /* Sony: Folklore, Genji, Tokyo Jungle (PS3), Brave Story, Kurohyo (PSP) */ - meta_NGCA, /* GoldenEye 007 (Wii) */ - meta_WII_RAS, /* Donkey Kong Country Returns (Wii) */ - meta_PS2_SPM, /* Lethal Skies Elite Pilot: Team SW */ - meta_X360_TRA, /* Def Jam Rapstar */ - meta_PS2_VGS, /* Princess Soft PS2 games */ - meta_PS2_IAB, /* Ueki no Housoku - Taosu ze Robert Juudan!! (PS2) */ - meta_PS2_STRLR, /* The Bouncer */ + meta_NGCA, /* GoldenEye 007 (Wii) */ + meta_WII_RAS, /* Donkey Kong Country Returns (Wii) */ + meta_PS2_SPM, /* Lethal Skies Elite Pilot: Team SW */ + meta_X360_TRA, /* Def Jam Rapstar */ + meta_PS2_VGS, /* Princess Soft PS2 games */ + meta_PS2_IAB, /* Ueki no Housoku - Taosu ze Robert Juudan!! (PS2) */ + meta_PS2_STRLR, /* The Bouncer */ meta_LSF_N1NJ4N, /* .lsf n1nj4n Fastlane Street Racing (iPhone) */ meta_VAWX, /* feelplus: No More Heroes Heroes Paradise, Moon Diver */ - meta_PC_SNDS, // Incredibles PC .snds - meta_PS2_WMUS, // The Warriors (PS2) - meta_HYPERSCAN_KVAG, // Hyperscan KVAG/BVG - meta_IOS_PSND, // Crash Bandicoot Nitro Kart 2 (iOS) - meta_BOS_ADP, // ADP! (Balls of Steel, PC) - meta_OTNS_ADP, // Omikron: The Nomad Soul .adp (PC/DC) - meta_EB_SFX, // Excitebots .sfx - meta_EB_SF0, // Excitebots .sf0 - meta_PS3_KLBS, // L@VE ONCE (PS3) - meta_PS2_MTAF, // Metal Gear Solid 3 MTAF - meta_PS2_VAG1, // Metal Gear Solid 3 VAG1 - meta_PS2_VAG2, // Metal Gear Solid 3 VAG2 - meta_TUN, // LEGO Racers (PC) - meta_WPD, // Shuffle! (PC) - meta_MN_STR, // Mini Ninjas (PC/PS3/WII) - meta_MSS, // Guerilla: ShellShock Nam '67 (PS2/Xbox), Killzone (PS2) - meta_PS2_HSF, // Lowrider (PS2) - meta_PS3_IVAG, // Interleaved VAG files (PS3) - meta_PS2_2PFS, // Konami: Mahoromatic: Moetto - KiraKira Maid-San, GANTZ (PS2) - meta_PS2_VBK, // Disney's Stitch - Experiment 626 - meta_OTM, // Otomedius (Arcade) - meta_CSTM, // Nintendo 3DS CSTM (Century Stream) - meta_FSTM, // Nintendo Wii U FSTM (caFe? Stream) - meta_3DS_IDSP, // Nintendo 3DS/Wii U IDSP - meta_KT_WIIBGM, // Koei Tecmo WiiBGM + meta_PC_SNDS, /* Incredibles PC .snds */ + meta_PS2_WMUS, /* The Warriors (PS2) */ + meta_HYPERSCAN_KVAG, /* Hyperscan KVAG/BVG */ + meta_IOS_PSND, /* Crash Bandicoot Nitro Kart 2 (iOS) */ + meta_BOS_ADP, /* ADP! (Balls of Steel, PC) */ + meta_OTNS_ADP, /* Omikron: The Nomad Soul .adp (PC/DC) */ + meta_EB_SFX, /* Excitebots .sfx */ + meta_EB_SF0, /* Excitebots .sf0 */ + meta_PS3_KLBS, /* L@VE ONCE (PS3) */ + meta_PS2_MTAF, /* Metal Gear Solid 3 MTAF */ + meta_PS2_VAG1, /* Metal Gear Solid 3 VAG1 */ + meta_PS2_VAG2, /* Metal Gear Solid 3 VAG2 */ + meta_TUN, /* LEGO Racers (PC) */ + meta_WPD, /* Shuffle! (PC) */ + meta_MN_STR, /* Mini Ninjas (PC/PS3/WII) */ + meta_MSS, /* Guerilla: ShellShock Nam '67 (PS2/Xbox), Killzone (PS2) */ + meta_PS2_HSF, /* Lowrider (PS2) */ + meta_PS3_IVAG, /* Interleaved VAG files (PS3) */ + meta_PS2_2PFS, /* Konami: Mahoromatic: Moetto - KiraKira Maid-San, GANTZ (PS2) */ + meta_PS2_VBK, /* Disney's Stitch - Experiment 626 */ + meta_OTM, /* Otomedius (Arcade) */ + meta_CSTM, /* Nintendo 3DS CSTM (Century Stream) */ + meta_FSTM, /* Nintendo Wii U FSTM (caFe? Stream) */ + meta_3DS_IDSP, /* Nintendo 3DS/Wii U IDSP */ + meta_KT_WIIBGM, /* Koei Tecmo WiiBGM */ + meta_KTSS, /* Koei Tecmo Switch Sound */ meta_MCA, /* Capcom MCA "MADP" */ meta_XB3D_ADX, /* Xenoblade Chronicles 3D ADX */ meta_HCA, /* CRI HCA */ @@ -618,8 +626,9 @@ typedef enum { meta_OGL, /* Shin'en Wii/WiiU (Jett Rocket (Wii), FAST Racing NEO (WiiU)) */ meta_MC3, /* Paradigm games (T3 PS2, MX Rider PS2, MI: Operation Surma PS2) */ meta_GTD, /* Knights Contract (X360/PS3), Valhalla Knights 3 (PSV) */ - meta_TA_AAC_X360, /* tri-ace AAC (Star Ocean 4, End of Eternity, Infinite Undiscovery) */ - meta_TA_AAC_PS3, /* tri-ace AAC (Star Ocean International, Resonance of Fate) */ + meta_TA_AAC_X360, /* tri-Ace AAC (Star Ocean 4, End of Eternity, Infinite Undiscovery) */ + meta_TA_AAC_PS3, /* tri-Ace AAC (Star Ocean International, Resonance of Fate) */ + meta_TA_AAC_VORBIS, /* tri-Ace AAC (Star Ocean Anamnesis, Heaven x Inferno) */ meta_PS3_MTA2, /* Metal Gear Solid 4 MTA2 */ meta_NGC_ULW, /* Burnout 1 (GC only) */ meta_PC_XA30, /* Driver - Parallel Lines (PC) */ @@ -642,7 +651,7 @@ typedef enum { meta_EA_SPS, /* Electronic Arts SPS (Burnout Crash) */ meta_NGC_VID1, /* Neversoft .ogg (Gun GC) */ meta_PC_FLX, /* Ultima IX PC */ - meta_MOGG, /* Harmonix Music Systems MOGG Vorbis */ + meta_MOGG, /* Harmonix Music Systems MOGG Vorbis */ #ifdef VGM_USE_VORBIS meta_OGG_VORBIS, /* Ogg Vorbis */ @@ -693,8 +702,8 @@ typedef struct { int32_t adpcm_history4_32; }; - double adpcm_history1_double; - double adpcm_history2_double; + double adpcm_history1_double; + double adpcm_history2_double; int adpcm_step_index; /* for IMA */ int adpcm_scale; /* for MS ADPCM */ @@ -771,8 +780,8 @@ typedef struct { int codec_endian; /* little/big endian marker; name is left vague but usually means big endian */ int codec_version; /* flag for codecs with minor variations */ - uint8_t xa_channel; /* XA ADPCM: selected channel */ - int32_t xa_sector_length; /* XA ADPCM: XA block */ + uint8_t xa_channel; /* XA ADPCM: selected channel */ + int32_t xa_sector_length; /* XA ADPCM: XA block */ uint8_t xa_headerless; /* XA ADPCM: headerless XA */ int8_t xa_get_high_nibble; /* XA ADPCM: mono/stereo nibble selection (XA state could be simplified) */ @@ -780,7 +789,7 @@ typedef struct { void * start_vgmstream; /* a copy of the VGMSTREAM as it was at the beginning of the stream (for AAX/AIX/SCD) */ - /* Data the codec needs for the whole stream. This is for codecs too + /* Data the codec needs for the whole stream. This is for codecs too * different from vgmstream's structure to be reasonably shoehorned into * using the ch structures. * Note also that support must be added for resetting, looping and @@ -930,7 +939,6 @@ typedef struct { size_t current_size_target; /* max data, until something happens */ size_t decode_to_discard; /* discard from this stream only (for EALayer3 or AWC) */ - } mpeg_custom_stream; typedef struct { @@ -980,13 +988,50 @@ typedef struct { #ifdef VGM_USE_MAIATRAC3PLUS typedef struct { - sample *buffer; - int channels; - int samples_discard; - void *handle; + sample *buffer; + int channels; + int samples_discard; + void *handle; } maiatrac3plus_codec_data; #endif +#ifdef VGM_USE_ATRAC9 + +/* custom ATRAC9 modes */ +typedef enum { + ATRAC9_DEFAULT = 0, /* ATRAC9 standard */ + ATRAC9_XVAG, /* Sony XVAG: interleaved subsongs, Vita multichannel interleaves 2ch xN superframes */ + //ATRAC9_FSB, /* FMOD FSB: Vita multichannel interleaves 2ch xN superframes */ + //ATRAC9_EATRAX, /* EA EATrax: buffered ATRAC9 in SPS blocks (superframes can be split between blocks) */ +} atrac9_custom_t; + +typedef struct { + atrac9_custom_t type; + + int channels; /* to detect weird multichannel */ + uint32_t config_data; /* ATRAC9 config header */ + int encoder_delay; /* initial samples to discard */ + + size_t interleave_skip; /* XVAG */ + size_t subsong_skip; /* XVAG */ +} atrac9_config; + +typedef struct { + uint8_t *data_buffer; + size_t data_buffer_size; + + sample *sample_buffer; + size_t samples_filled; /* number of samples in the buffer */ + size_t samples_used; /* number of samples extracted from the buffer */ + + int samples_to_discard; + + atrac9_config config; + + void *handle; /* decoder handle */ +} atrac9_codec_data; +#endif + /* with one file this is also used for just ACM */ typedef struct { int file_count; @@ -1138,22 +1183,22 @@ typedef struct { #ifdef VGM_USE_MP4V2 typedef struct { - STREAMFILE *streamfile; - uint64_t start; - uint64_t offset; - uint64_t size; + STREAMFILE *streamfile; + uint64_t start; + uint64_t offset; + uint64_t size; } mp4_streamfile; #ifdef VGM_USE_FDKAAC typedef struct { - mp4_streamfile if_file; - MP4FileHandle h_mp4file; - MP4TrackId track_id; - unsigned long sampleId, numSamples; - UINT codec_init_data_size; - HANDLE_AACDECODER h_aacdecoder; - unsigned int sample_ptr, samples_per_frame, samples_discard; - INT_PCM sample_buffer[( (6) * (2048)*4 )]; + mp4_streamfile if_file; + MP4FileHandle h_mp4file; + MP4TrackId track_id; + unsigned long sampleId, numSamples; + UINT codec_init_data_size; + HANDLE_AACDECODER h_aacdecoder; + unsigned int sample_ptr, samples_per_frame, samples_discard; + INT_PCM sample_buffer[( (6) * (2048)*4 )]; } mp4_aac_codec_data; #endif #endif