From 2a4d3b82634c95b61b852c5fc348e78dc926c6ba Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Wed, 28 Oct 2026 18:00:05 +0900 Subject: [PATCH] compat.dr_libs 2026.03.03: dr_wav, dr_flac and dr_mp3 (MIT-0 OR Unlicense) dr_libs is three single-file audio libraries in C with no dependencies: dr_wav (WAV/RIFF, RIFX, RF64, Wave64 and AIFF reading, and writing), dr_flac (FLAC, native and Ogg) and dr_mp3 (MPEG Layer III). Upstream tags each header on its own and no tag names the three together, so this pins the commit archive of wav-0.14.5 (fa931f3, 2026-03-03), whose dr_flac.h and dr_mp3.h are byte-identical to flac-0.13.3 and mp3-0.7.3: the newest commit at which all three are tagged releases. The version is that commit's date, as compat.nanosvg's is. One generated implementation TU defines DR_WAV_IMPLEMENTATION, DR_FLAC_IMPLEMENTATION and DR_MP3_IMPLEMENTATION, a static library; consumers include , , and link. Upstream's default configuration: the stdio and conversion APIs on, SIMD chosen by the compiler's predefined macros. miniaudio's embedded copies are renamed (ma_dr_*), so the two link into one program. GLOBAL is the GitHub commit archive, CN the gitcode mcpp-res mirror, byte-identical. The member tests/examples/dr_libs runs on all three platforms: the three versions, WAV round trips (RIFF and Wave64 PCM16 read as s16 and f32, IEEE float bit-exact, every mu-law code against drwav_mulaw_to_s16), a FLAC stream decoded sample-exact against the signal whose MD5 its STREAMINFO carries, with a seek, and an MP3 decoded to its LAME tag's gapless length with 440 Hz dominant. --- CHANGELOG.md | 10 + mcpp.toml | 1 + pkgs/c/compat.dr_libs.lua | 120 ++++++ tests/examples/dr_libs/mcpp.toml | 11 + tests/examples/dr_libs/tests/dr_libs.cpp | 515 +++++++++++++++++++++++ 5 files changed, 657 insertions(+) create mode 100644 pkgs/c/compat.dr_libs.lua create mode 100644 tests/examples/dr_libs/mcpp.toml create mode 100644 tests/examples/dr_libs/tests/dr_libs.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 81a5b50c..2738ab7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,16 @@ ### Added +- **compat.dr_libs 2026.03.03(新包)。** dr_libs:单文件的 WAV/AIFF、FLAC 与 MP3 解码器(以及 WAV 编码器),C 实现, + 无依赖,许可为 MIT-0 或 Unlicense 二选一。上游按头文件分别打标签(`wav-*`、`flac-*`、`mp3-*`),没有同时覆盖三者的标签; + 本包固定 `wav-0.14.5` 的提交 `fa931f3`(2026-03-03)的归档,其中 `dr_flac.h`、`dr_mp3.h` 与 `flac-0.13.3`、`mp3-0.7.3` + 标签逐字节相同,即 dr_wav 0.14.5、dr_flac 0.13.3、dr_mp3 0.7.3 三者均为已发布版本的最新提交;版本号取提交日期(同 + compat.nanosvg)。一个生成的实现编译单元同时定义 `DR_WAV_IMPLEMENTATION`、`DR_FLAC_IMPLEMENTATION`、 + `DR_MP3_IMPLEMENTATION`,构建为一个静态库;使用者 `#include `(``、``)并链接,不要再定义 + 这些宏。上游默认配置(stdio 与转换接口保留,SIMD 由编译器预定义宏决定)。miniaudio 内嵌的是改名的副本(`ma_dr_*`), + 两者可在同一程序中共存。GLOBAL 为 GitHub 提交归档,CN 为 GitCode `mcpp-res/dr_libs` 镜像,sha256 一致。新增测试成员 + `tests/examples/dr_libs`(三平台):WAV(RIFF、Wave64、IEEE float、mu-law)往返、FLAC 按 STREAMINFO 的 MD5 逐样本无损解码与 + 定位、MP3 按 LAME 标签的无缝长度解码。 - **mcpplibs.mwrap.opus 1.6.1(新包)。** opus-m:以 C++23 模块(`import mcpplibs.mwrap.opus;`)使用 compat.opus 1.6.1、 compat.opusfile 0.12 与 compat.ogg 1.3.6。`mcpplibs.mwrap.opus` 导出 libopus 的 13 个类型与 87 个函数,并重新导出 `.file`(opusfile:10 个类型、54 个函数;不导出未构建的 libopusurl 的 9 个声明)、`.ogg`(libogg:12 个类型、71 个函数) diff --git a/mcpp.toml b/mcpp.toml index ecab4106..97d12a85 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -73,6 +73,7 @@ members = [ "tests/examples/cuda-driver", "tests/examples/curl", "tests/examples/doctest", + "tests/examples/dr_libs", "tests/examples/eigen", "tests/examples/eui-neo", "tests/examples/eui-neo-app-main", diff --git a/pkgs/c/compat.dr_libs.lua b/pkgs/c/compat.dr_libs.lua new file mode 100644 index 00000000..faf66f9d --- /dev/null +++ b/pkgs/c/compat.dr_libs.lua @@ -0,0 +1,120 @@ +-- compat.dr_libs — dr_wav, dr_flac and dr_mp3: single-file audio decoders +-- (and a WAV encoder) in C, no dependencies, MIT-0 OR Unlicense. +-- +-- dr_wav.h 0.14.5 WAV / RIFF, RIFX, RF64, Sony Wave64 and AIFF: PCM, +-- IEEE float, A-law, mu-law, MS and IMA ADPCM; reading, +-- writing, metadata chunks (smpl, cue, acid, bext, ...). +-- dr_flac.h 0.13.3 FLAC (native and Ogg-encapsulated) decoding. +-- dr_mp3.h 0.7.3 MPEG-1/2 Layer III decoding (built on minimp3). +-- +-- SHAPE: three single-file libraries in the stb tradition, as compat.nanosvg +-- packages two: each header holds the declarations and, behind +-- DR_WAV_IMPLEMENTATION / DR_FLAC_IMPLEMENTATION / DR_MP3_IMPLEMENTATION, the +-- implementation. Upstream ships no implementation .c, so this package +-- generates one TU that instantiates all three, once, into one static library. +-- A consumer writes `#include ` (``, ``) and +-- links -- the spelling upstream's own documentation uses. +-- +-- CONSEQUENCE FOR CONSUMERS: do NOT also define DR_WAV_IMPLEMENTATION, +-- DR_FLAC_IMPLEMENTATION or DR_MP3_IMPLEMENTATION (or their DRWAV_ / DRFLAC_ / +-- DRMP3_ spellings). The implementations are already compiled into this +-- package's lib; defining one again duplicates its symbols, a LINK error that +-- surfaces late. +-- +-- miniaudio embeds its own copies of the three, renamed (ma_dr_wav_*, +-- ma_dr_flac_*, ma_dr_mp3_*), so compat.miniaudio and compat.dr_libs link +-- into one program without a symbol in common. +-- +-- VERSIONING: upstream tags each header on its own (wav-*, flac-*, mp3-*) in +-- one repository, and no tag names the three together. This pins the commit +-- archive of wav-0.14.5, fa931f3285ced10ace628f7f1ac951e1951e7ea6 +-- (2026-03-03), whose dr_flac.h and dr_mp3.h are byte-identical to the +-- flac-0.13.3 and mp3-0.7.3 tags: the newest commit at which all three headers +-- are tagged releases (later commits carry untagged dr_wav/dr_mp3 changes). +-- Following compat.nanosvg and compat.khrplatform, the version is the commit's +-- DATE, 2026.03.03. No extensions.autoupdate: there is no single tag series to +-- follow; a bump re-checks the three headers' tags by hand. +-- +-- CONFIGURATION: upstream's defaults, nothing defined. The stdio APIs stay on +-- (drwav_init_file, drflac_open_file, drmp3_init_file and their _w wide-path +-- forms: _wfopen_s / _wfopen on Windows, wcsrtombs + fopen elsewhere), as do +-- the conversion APIs (drwav_s16_to_f32 ...). SIMD is chosen by each header +-- at compile time from the compiler's own predefined macros (SSE2 / SSE4.1 +-- when the target enables them, NEON on arm64); there is no runtime dispatch +-- to configure. +-- +-- kind = "lib": a static library. DRWAV_API / DRFLAC_API / DRMP3_API are +-- `extern` unless DRWAV_DLL / DRFLAC_DLL / DRMP3_DLL is defined, and neither +-- side defines it, so the consumer's declarations match on every platform. +package = { + spec = "1", + namespace = "compat", + name = "dr_libs", + description = "dr_libs (2026.03.03: dr_wav 0.14.5, dr_flac 0.13.3, dr_mp3 0.7.3) — single-file WAV/AIFF, FLAC and MP3 decoders and a WAV encoder in C, no dependencies", + licenses = {"MIT-0", "Unlicense"}, + repo = "https://github.com/mackron/dr_libs", + type = "package", + + -- One source archive for every platform: portable C whose platform + -- choices are made by the compiler's own predefined macros. + xpm = { + linux = { + ["2026.03.03"] = { + url = { + GLOBAL = "https://github.com/mackron/dr_libs/archive/fa931f3285ced10ace628f7f1ac951e1951e7ea6.tar.gz", + CN = "https://gitcode.com/mcpp-res/dr_libs/releases/download/2026.03.03/dr_libs-2026.03.03.tar.gz", + }, + sha256 = "b56be5930399b9ea81591a837e0c9ee959a5d57e90dac96e0af37dde1fa0bb7e", + }, + }, + macosx = { + ["2026.03.03"] = { + url = { + GLOBAL = "https://github.com/mackron/dr_libs/archive/fa931f3285ced10ace628f7f1ac951e1951e7ea6.tar.gz", + CN = "https://gitcode.com/mcpp-res/dr_libs/releases/download/2026.03.03/dr_libs-2026.03.03.tar.gz", + }, + sha256 = "b56be5930399b9ea81591a837e0c9ee959a5d57e90dac96e0af37dde1fa0bb7e", + }, + }, + windows = { + ["2026.03.03"] = { + url = { + GLOBAL = "https://github.com/mackron/dr_libs/archive/fa931f3285ced10ace628f7f1ac951e1951e7ea6.tar.gz", + CN = "https://gitcode.com/mcpp-res/dr_libs/releases/download/2026.03.03/dr_libs-2026.03.03.tar.gz", + }, + sha256 = "b56be5930399b9ea81591a837e0c9ee959a5d57e90dac96e0af37dde1fa0bb7e", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + -- Upstream's spelling: ``, ``, ``. + -- The headers carry their own extern "C" under __cplusplus. + include_dirs = { "*" }, + -- Upstream ships no implementation TU, so supply one: the three + -- single-file libraries instantiated here, once, for the package. + generated_files = { + ["mcpp_generated/dr_libs_impl.c"] = [==[ +#define DR_WAV_IMPLEMENTATION +#include + +#define DR_FLAC_IMPLEMENTATION +#include + +#define DR_MP3_IMPLEMENTATION +#include +]==], + }, + sources = { "mcpp_generated/dr_libs_impl.c" }, + -- Linked into shared objects by its consumers: position independent. + linux = { cflags = { "-fPIC" } }, + macosx = { cflags = { "-fPIC" } }, + -- No -fPIC on Windows: PE/COFF has no such distinction, and clang + -- rejects it for the MSVC target. + targets = { dr_libs = { kind = "lib" } }, + deps = {}, + }, +} diff --git a/tests/examples/dr_libs/mcpp.toml b/tests/examples/dr_libs/mcpp.toml new file mode 100644 index 00000000..58b1a84e --- /dev/null +++ b/tests/examples/dr_libs/mcpp.toml @@ -0,0 +1,11 @@ +# compat.dr_libs — dr_wav, dr_flac and dr_mp3 from one generated implementation +# TU: a WAV round trip, a FLAC stream decoded sample-exact against its own MD5, +# an MP3 decoded to its LAME-tagged length, on every platform the descriptor +# declares. +[package] +name = "dr_libs-tests" +version = "0.1.0" +standard = "c++23" + +[dependencies] +compat.dr_libs = "2026.03.03" diff --git a/tests/examples/dr_libs/tests/dr_libs.cpp b/tests/examples/dr_libs/tests/dr_libs.cpp new file mode 100644 index 00000000..d24eaca0 --- /dev/null +++ b/tests/examples/dr_libs/tests/dr_libs.cpp @@ -0,0 +1,515 @@ +// compat.dr_libs — dr_wav, dr_flac and dr_mp3, each through its own decoder. +// +// WHAT THIS ASSERTS AND WHY +// +// The package is one generated TU that defines the three *_IMPLEMENTATION +// macros; a build that dropped one would not link. Every check asks a decoder +// a question whose answer is fixed by the data, not by the decoder: +// +// the versions drwav/drflac/drmp3_version_string, the linked code's +// own strings: 0.14.5, 0.13.3, 0.7.3 (the pinned commit) +// WAV round trip PCM16 stereo written with drwav_init_memory_write, +// read back sample-exact, as s16 and as f32 (s / 32768), +// and the same samples through a Sony Wave64 container +// IEEE float WAV f32 written and read back bit-exact +// mu-law WAV the decoder's table equals drwav_mulaw_to_s16 +// FLAC 2048 stereo frames (fixed-predictor/LPC subframes, +// Rice residuals, stereo decorrelation, 4 frames) +// decoded sample-exact against the integer signal the +// fixture was encoded from, whose MD5 is the one in its +// STREAMINFO; the vendor string from VORBIS_COMMENT; +// a seek into the third frame +// MP3 a 440 Hz sine, 22050 Hz mono, 32 kb/s with a LAME +// tag: the gapless length is the encoded 4410 samples, +// and 440 Hz dominates the decoded signal +// +// The fixtures are below as bytes. Both were made for this test from signals +// defined here (FLAC: ffmpeg's native encoder, -compression_level 8 +// -frame_size 512 -bitexact, PADDING dropped; MP3: ffmpeg + LAME, -b:a 32k +// -bitexact, no ID3), so they carry no third-party content. + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace { + +// tone.flac: 3097 bytes +const unsigned char kToneFlac[] = { + 0x66, 0x4c, 0x61, 0x43, 0x00, 0x00, 0x00, 0x22, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0xf0, 0x00, + 0x02, 0xfb, 0x0a, 0xc4, 0x42, 0xf0, 0x00, 0x00, 0x08, 0x00, 0x29, 0x02, 0x2c, 0x35, 0x13, 0xe9, + 0xa6, 0xfe, 0xa7, 0x6a, 0x96, 0x0f, 0xd2, 0x14, 0x70, 0xc2, 0x84, 0x00, 0x00, 0x0e, 0x06, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x6d, 0x70, 0x65, 0x67, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x99, 0xa8, + 0x00, 0xa9, 0x46, 0xe0, 0xc2, 0xe1, 0x0a, 0xe1, 0x50, 0xe1, 0x91, 0xe6, 0xb9, 0xd9, 0xde, 0xef, + 0xcc, 0xb8, 0x1b, 0xf8, 0x06, 0x55, 0xf0, 0x9e, 0xdf, 0x42, 0x02, 0xc6, 0x25, 0x6c, 0x6b, 0xc7, + 0x1b, 0x31, 0xa8, 0x86, 0xa0, 0xde, 0xea, 0x99, 0x2d, 0x45, 0x1f, 0x97, 0x2a, 0x2f, 0x11, 0x7a, + 0x84, 0xd5, 0x27, 0xbe, 0x8c, 0x3f, 0x1c, 0x5a, 0x8f, 0x50, 0x84, 0x92, 0xa5, 0x13, 0x8a, 0xf2, + 0x0f, 0x45, 0x33, 0x50, 0x5e, 0x0c, 0x1e, 0x21, 0x71, 0x62, 0x0d, 0x23, 0x0b, 0xe2, 0x1a, 0xe9, + 0xcf, 0x82, 0x27, 0xf0, 0x8c, 0x6a, 0xa3, 0x5d, 0xec, 0x28, 0xf4, 0x14, 0x24, 0x75, 0xef, 0x55, + 0x1d, 0xea, 0xfd, 0x23, 0x2c, 0x89, 0x8f, 0x76, 0x14, 0x81, 0xae, 0x3b, 0x16, 0x47, 0xe1, 0x48, + 0x34, 0xe4, 0x4e, 0x08, 0x1e, 0x21, 0x4c, 0xd7, 0x3c, 0xc6, 0x5a, 0x29, 0x52, 0xa3, 0x2a, 0x6c, + 0xc7, 0x1e, 0x29, 0x85, 0x86, 0x59, 0xa0, 0xcf, 0xa5, 0x29, 0x52, 0xe9, 0xe1, 0x5f, 0x4c, 0xee, + 0x00, 0x00, 0x2c, 0xd2, 0x0a, 0xd3, 0x09, 0x51, 0xdb, 0xea, 0x0a, 0x26, 0xb8, 0x61, 0x66, 0x4b, + 0x31, 0x0f, 0x10, 0x43, 0x45, 0x1a, 0x14, 0xda, 0x61, 0x0d, 0x33, 0x15, 0x28, 0x54, 0xd0, 0x8a, + 0x69, 0x0c, 0x4c, 0x00, 0x01, 0x2b, 0x31, 0x67, 0x3c, 0x43, 0x79, 0x05, 0x6e, 0xbb, 0x3e, 0x38, + 0xe4, 0xc3, 0x10, 0x58, 0x81, 0x61, 0x84, 0xaa, 0xae, 0xdc, 0xa9, 0x41, 0xa3, 0x2c, 0x49, 0x84, + 0x34, 0xc4, 0xcb, 0x30, 0x68, 0x47, 0x0b, 0x08, 0xb6, 0xe6, 0x64, 0x95, 0xe4, 0xa8, 0x40, 0xf2, + 0xad, 0x89, 0x61, 0xa8, 0x28, 0x68, 0xe2, 0xec, 0x41, 0xa8, 0xec, 0x5f, 0xd4, 0x2b, 0x52, 0x30, + 0x6f, 0x54, 0x6b, 0x06, 0x84, 0x26, 0x57, 0xd3, 0x7d, 0x64, 0xba, 0x3e, 0x74, 0xa1, 0x26, 0x17, + 0x55, 0x78, 0x24, 0x82, 0x7b, 0x93, 0x1f, 0x6c, 0x1a, 0x72, 0x64, 0x99, 0x28, 0x49, 0xde, 0x6d, + 0xb1, 0x31, 0x8d, 0x4a, 0x2c, 0x00, 0x01, 0xc1, 0x0b, 0x35, 0x15, 0x8f, 0x56, 0xec, 0xec, 0xc6, + 0x34, 0x87, 0xfd, 0x47, 0x27, 0xd8, 0x69, 0x4d, 0xb5, 0x5d, 0x3f, 0xbf, 0x6c, 0x70, 0x7b, 0xb6, + 0x26, 0x6d, 0x82, 0xec, 0x20, 0xd7, 0x91, 0x97, 0xad, 0x55, 0xf9, 0x44, 0xc6, 0xa1, 0x2e, 0x3e, + 0x8a, 0x13, 0x8a, 0x9c, 0x6a, 0x48, 0x7f, 0xb2, 0x2e, 0x1f, 0x67, 0x0b, 0x42, 0x89, 0xe9, 0x9d, + 0x88, 0xaa, 0x48, 0x00, 0x0e, 0xa6, 0x26, 0x19, 0x73, 0xc5, 0x88, 0x46, 0xff, 0xfe, 0x80, 0x04, + 0xc0, 0x03, 0xa0, 0x03, 0x2e, 0x6b, 0x54, 0x7e, 0x25, 0xdf, 0x45, 0xfe, 0x36, 0x80, 0x9c, 0x32, + 0x5a, 0xa9, 0x15, 0xa6, 0x98, 0x8c, 0xd9, 0x60, 0xc0, 0xab, 0x16, 0x54, 0xd6, 0x7a, 0x70, 0x65, + 0x88, 0x43, 0xc8, 0x55, 0x51, 0x06, 0x76, 0xb5, 0xe2, 0xc2, 0xcd, 0xc2, 0xcd, 0xa8, 0x38, 0x13, + 0x24, 0x97, 0xd2, 0xda, 0x6a, 0x40, 0xe2, 0x2b, 0xea, 0xc8, 0x49, 0xc1, 0x14, 0x9c, 0x8c, 0x11, + 0x38, 0x9c, 0x30, 0x83, 0xf0, 0x16, 0x7e, 0x07, 0x11, 0x86, 0x20, 0x99, 0x24, 0xde, 0x5a, 0xee, + 0x94, 0xcf, 0x9d, 0x12, 0x7c, 0xf5, 0xd5, 0x91, 0x2d, 0xad, 0x0e, 0x67, 0xe7, 0x84, 0xc2, 0x04, + 0x5e, 0x40, 0x5c, 0xf3, 0x4d, 0xb4, 0xd8, 0xc1, 0x14, 0xab, 0x42, 0x9f, 0xfa, 0xc4, 0x95, 0xf6, + 0xb3, 0x69, 0x90, 0x2a, 0x35, 0xfe, 0x7d, 0x03, 0x44, 0x64, 0x92, 0xca, 0xea, 0xcf, 0x1d, 0x20, + 0xd7, 0x1b, 0xc1, 0xa7, 0xc8, 0x48, 0xc8, 0x20, 0x4e, 0x16, 0x51, 0xab, 0xb0, 0x8f, 0x22, 0xd2, + 0xeb, 0x7b, 0x3e, 0xb4, 0x10, 0xd8, 0xa3, 0xf1, 0x09, 0x15, 0x6b, 0xf6, 0x69, 0x91, 0xc2, 0x2a, + 0x45, 0x20, 0x00, 0x00, 0x44, 0x3e, 0x9a, 0x1f, 0x76, 0x37, 0x3d, 0x57, 0x7d, 0x12, 0xe3, 0x44, + 0x6b, 0x9c, 0x67, 0x19, 0xd2, 0x3d, 0x60, 0x9d, 0x99, 0x42, 0x42, 0x66, 0x91, 0x75, 0x1c, 0x51, + 0x47, 0xcb, 0xc0, 0xa1, 0xb4, 0x71, 0x75, 0xd3, 0x80, 0x00, 0x05, 0x05, 0xb4, 0x50, 0x55, 0xab, + 0xb3, 0xa5, 0x53, 0x31, 0x11, 0x1a, 0x27, 0x24, 0x09, 0xf5, 0xed, 0x0e, 0xda, 0xd4, 0x66, 0xcb, + 0xaf, 0x85, 0xbb, 0xd2, 0xed, 0x55, 0x18, 0x6f, 0x7d, 0x53, 0x64, 0xcb, 0x15, 0xfc, 0xed, 0x03, + 0x36, 0xc6, 0x5b, 0xaf, 0x75, 0xe2, 0xaa, 0x90, 0x55, 0xd2, 0x02, 0x35, 0x58, 0x8a, 0x83, 0xa5, + 0xb2, 0xfc, 0xf8, 0x45, 0x81, 0x31, 0x61, 0x5c, 0xa3, 0x2a, 0x75, 0x17, 0x8d, 0xd1, 0x98, 0x56, + 0x6a, 0xc8, 0x89, 0x21, 0x37, 0x08, 0xf4, 0x90, 0xef, 0x13, 0x78, 0x5f, 0x93, 0x3a, 0xc7, 0x55, + 0x57, 0x88, 0x90, 0x15, 0x49, 0xfc, 0xc7, 0x35, 0x37, 0xa3, 0x43, 0xb0, 0xac, 0x0a, 0xca, 0xa7, + 0x4a, 0x4d, 0xd7, 0x56, 0x98, 0x4c, 0x41, 0x1e, 0x8c, 0x8a, 0x13, 0x00, 0x00, 0x05, 0x9a, 0x05, + 0xa0, 0x7c, 0x4a, 0xe2, 0xaf, 0x6f, 0x9f, 0x89, 0x08, 0xaf, 0x24, 0x54, 0xab, 0xc2, 0x6c, 0x25, + 0x1f, 0xea, 0x54, 0x62, 0x91, 0x22, 0xc2, 0x95, 0xe9, 0x0e, 0x67, 0xd0, 0xcc, 0x92, 0x2d, 0x74, + 0x4a, 0x71, 0xd2, 0x57, 0xb3, 0x44, 0x8a, 0xb4, 0x3c, 0x26, 0x48, 0x89, 0xc1, 0x61, 0x30, 0xa2, + 0xe5, 0x13, 0x29, 0x28, 0x1c, 0x82, 0xda, 0x81, 0x6d, 0x44, 0xc1, 0x10, 0x61, 0xd5, 0x34, 0xe1, + 0x48, 0xac, 0x40, 0x88, 0x2c, 0x22, 0x10, 0x80, 0xe5, 0xd8, 0xc0, 0x00, 0x19, 0x09, 0xa2, 0x52, + 0xeb, 0x12, 0xa6, 0x0a, 0x4c, 0x6c, 0x12, 0xff, 0xf8, 0x99, 0xa8, 0x01, 0xae, 0x46, 0xf3, 0xc2, + 0xf4, 0x08, 0xf4, 0x4f, 0xf4, 0x93, 0xe6, 0xb5, 0x8b, 0xe3, 0x59, 0xed, 0x2b, 0xeb, 0xb8, 0x06, + 0xa6, 0xb2, 0x16, 0xc4, 0xda, 0xb7, 0x4a, 0xd6, 0xe3, 0x8f, 0x10, 0xd2, 0x0b, 0x67, 0x34, 0x8a, + 0x5f, 0x15, 0x79, 0xb4, 0x85, 0x91, 0x84, 0x26, 0x88, 0xf8, 0xee, 0x76, 0x79, 0x1a, 0xaa, 0x77, + 0x24, 0x73, 0x78, 0x8a, 0x65, 0x4e, 0x18, 0x47, 0xb1, 0x90, 0xea, 0x32, 0xa8, 0xeb, 0x21, 0xc8, + 0xae, 0x32, 0x0c, 0x00, 0x00, 0x3c, 0x1b, 0xee, 0xe4, 0x31, 0xe3, 0xbd, 0xd0, 0x22, 0xca, 0x79, + 0xc4, 0x42, 0x33, 0xcc, 0xc5, 0x23, 0x30, 0x42, 0xd0, 0xa8, 0x11, 0x9a, 0x88, 0x15, 0x19, 0xe6, + 0x5a, 0x0c, 0xa9, 0x3a, 0xef, 0x07, 0x25, 0xd1, 0x67, 0x53, 0xbe, 0xc7, 0x7f, 0x21, 0x91, 0x98, + 0xae, 0x65, 0xc1, 0x0c, 0xf5, 0x0a, 0x3c, 0x42, 0x34, 0xa3, 0x44, 0x11, 0xe8, 0x38, 0x92, 0x21, + 0x18, 0x20, 0x49, 0xd8, 0xc9, 0xe3, 0x30, 0xb3, 0xac, 0x52, 0x71, 0x54, 0xac, 0xb1, 0x4d, 0xb2, + 0x95, 0x97, 0x01, 0xc2, 0x70, 0x57, 0xf6, 0x4d, 0x15, 0xee, 0x38, 0x5b, 0x8c, 0x82, 0x4e, 0xeb, + 0x31, 0x96, 0xd6, 0x00, 0x03, 0x41, 0xfb, 0x09, 0x0c, 0x26, 0xa3, 0x51, 0xe8, 0x8f, 0xcb, 0x52, + 0xd0, 0xd2, 0x3f, 0xee, 0x62, 0x63, 0x14, 0x7c, 0x7f, 0x2d, 0x10, 0x49, 0x06, 0xe3, 0x55, 0x05, + 0xa7, 0xae, 0x80, 0x00, 0x03, 0x02, 0xa7, 0x4c, 0x6c, 0xe4, 0x71, 0xe4, 0x70, 0x48, 0xaa, 0x26, + 0x51, 0xb2, 0xb5, 0x76, 0x1b, 0x62, 0x9a, 0xf2, 0x8b, 0xcc, 0x86, 0x1f, 0x12, 0xab, 0xaf, 0x45, + 0xc0, 0x91, 0xc5, 0x95, 0xf2, 0xd8, 0xed, 0x52, 0x0f, 0x10, 0x7e, 0x21, 0x2a, 0xbf, 0xac, 0x2c, + 0x56, 0x8b, 0x11, 0x04, 0xa2, 0x2b, 0x84, 0x9c, 0xb1, 0x06, 0xda, 0x97, 0x94, 0x85, 0xe7, 0x7c, + 0xd3, 0x0d, 0x38, 0x9a, 0xd3, 0x3e, 0xd4, 0xfe, 0xc5, 0x90, 0x4b, 0x18, 0x7b, 0x14, 0xd8, 0xe9, + 0xd8, 0x2b, 0x05, 0xe2, 0xb1, 0xe4, 0x47, 0xb2, 0x1a, 0x42, 0x58, 0x2c, 0xce, 0x5a, 0x10, 0x9b, + 0x28, 0xf2, 0x21, 0xb8, 0x47, 0xa1, 0x34, 0x20, 0x4a, 0x9e, 0xa6, 0x5e, 0x61, 0x6c, 0xf6, 0x43, + 0x54, 0x51, 0xf0, 0xeb, 0xce, 0x24, 0x60, 0x96, 0x2c, 0xa5, 0x5a, 0xeb, 0x3c, 0xa8, 0x51, 0xbc, + 0x80, 0x95, 0xc9, 0xc1, 0xa3, 0x92, 0x85, 0x3e, 0x2b, 0x96, 0xeb, 0xd6, 0x71, 0xe6, 0x7c, 0x23, + 0x08, 0x00, 0x84, 0x02, 0x82, 0x02, 0xc1, 0x01, 0x9f, 0x35, 0xd9, 0xfe, 0xbb, 0xee, 0xcd, 0x20, + 0xa5, 0xc0, 0x44, 0xa8, 0xe3, 0x22, 0xc2, 0x20, 0x80, 0x89, 0xab, 0xca, 0xa6, 0xb7, 0x46, 0xbe, + 0x91, 0x02, 0x6e, 0x58, 0x81, 0x12, 0x1d, 0x14, 0x5d, 0x87, 0xda, 0x38, 0x22, 0x39, 0xf8, 0x71, + 0xcf, 0x6f, 0x67, 0x8e, 0x8d, 0x41, 0xf0, 0x59, 0xd2, 0xe3, 0xd6, 0x86, 0x0a, 0x87, 0x19, 0x4a, + 0x22, 0x05, 0x58, 0x70, 0xf8, 0xe2, 0x26, 0x19, 0x12, 0x2b, 0x60, 0x81, 0x17, 0x9d, 0x79, 0xeb, + 0xd7, 0x0a, 0x38, 0xaa, 0x4e, 0x7c, 0x00, 0x00, 0x44, 0xfa, 0x07, 0x1d, 0x31, 0x67, 0x60, 0x3c, + 0xab, 0x63, 0x04, 0xe6, 0x92, 0xee, 0x35, 0x79, 0xc6, 0x19, 0x10, 0xca, 0xf8, 0xc7, 0x49, 0x7e, + 0xb8, 0xcb, 0xce, 0x94, 0xec, 0x21, 0x08, 0x3e, 0x2c, 0x57, 0x42, 0x83, 0xad, 0x11, 0x7b, 0x47, + 0x4d, 0x32, 0xd4, 0x04, 0xc5, 0x0b, 0xbd, 0x7b, 0x13, 0x29, 0x05, 0x65, 0x42, 0xa4, 0x27, 0x47, + 0xf8, 0x58, 0x57, 0x2b, 0x65, 0x1f, 0x4a, 0x5d, 0xcb, 0xcf, 0xd5, 0x1b, 0x2c, 0x32, 0x93, 0x09, + 0xef, 0xf0, 0xf5, 0x5d, 0xc6, 0xb6, 0x5c, 0x82, 0x37, 0xca, 0x76, 0x8e, 0xba, 0xca, 0xe6, 0x9f, + 0xd1, 0xf7, 0x17, 0xeb, 0x42, 0x36, 0x5d, 0xa3, 0xfe, 0xcf, 0x7c, 0x75, 0x25, 0xf8, 0x46, 0x50, + 0x23, 0x86, 0x63, 0xa7, 0x57, 0x2c, 0x00, 0x34, 0xc3, 0x13, 0x1b, 0xe5, 0x8b, 0xa9, 0x53, 0x3a, + 0x49, 0x53, 0xa7, 0x84, 0x68, 0xe0, 0x8a, 0x1b, 0xf9, 0x93, 0x4d, 0xf0, 0xcd, 0xa7, 0xba, 0x27, + 0x01, 0xb1, 0x4b, 0xbe, 0xda, 0x9c, 0x08, 0x96, 0x6e, 0x8c, 0xb0, 0x6f, 0x45, 0x40, 0x00, 0x00, + 0xa2, 0x85, 0x68, 0xf8, 0xa0, 0x8a, 0x13, 0x7f, 0x88, 0x0a, 0xac, 0xb9, 0x86, 0x70, 0x64, 0x51, + 0xb5, 0x65, 0x24, 0x93, 0x45, 0xaf, 0xa2, 0x59, 0x57, 0x74, 0x50, 0x99, 0x41, 0xf3, 0x5b, 0xb1, + 0x73, 0x88, 0xf9, 0x7c, 0x4d, 0x65, 0xf9, 0x78, 0x65, 0x2e, 0x23, 0x96, 0x3a, 0xb7, 0x4a, 0x85, + 0x32, 0x8b, 0x3e, 0x72, 0xf8, 0xfd, 0xb5, 0xd7, 0x9b, 0x18, 0x3a, 0x84, 0x39, 0x5d, 0x7d, 0x4d, + 0x20, 0xad, 0x20, 0x51, 0x35, 0x43, 0xc3, 0xe7, 0xa7, 0x1e, 0x53, 0x30, 0x14, 0x11, 0x30, 0xbe, + 0x04, 0x2c, 0x65, 0xa7, 0x88, 0xa9, 0xa6, 0x2f, 0x96, 0x8b, 0x3f, 0x92, 0x5b, 0x39, 0xc3, 0x63, + 0x4d, 0x92, 0xc7, 0x8c, 0x9c, 0xd3, 0xcb, 0xac, 0xa6, 0x5c, 0xcc, 0x84, 0xb2, 0xc3, 0xa4, 0x98, + 0xfb, 0x94, 0xd4, 0x16, 0x21, 0xd5, 0x24, 0xc2, 0x09, 0x8b, 0x37, 0xa1, 0x0b, 0x55, 0x22, 0xd8, + 0x8c, 0x24, 0x25, 0xf7, 0x2c, 0x24, 0x54, 0xc7, 0x2c, 0xe4, 0x5e, 0xc8, 0x40, 0x9c, 0x8c, 0x34, + 0xe2, 0x82, 0x23, 0xd4, 0x14, 0x32, 0x00, 0x00, 0x00, 0x00, 0x98, 0x17, 0x02, 0xd2, 0x83, 0x5b, + 0xd5, 0xac, 0xe2, 0xe0, 0x80, 0x55, 0xa5, 0x35, 0x12, 0x4f, 0x94, 0xe6, 0xc0, 0xde, 0xbe, 0xff, + 0xf8, 0x99, 0x18, 0x02, 0xe8, 0x46, 0x17, 0xc6, 0x17, 0x70, 0x17, 0x1b, 0x16, 0xd1, 0xe6, 0xb2, + 0x08, 0xf5, 0x1f, 0xd1, 0xb3, 0xf7, 0xc8, 0x67, 0xe7, 0x1e, 0x19, 0xcb, 0xfc, 0x41, 0x94, 0x21, + 0xe8, 0x24, 0xea, 0x75, 0xd3, 0x48, 0xb1, 0x84, 0xb8, 0xc1, 0x68, 0x21, 0x6a, 0x51, 0x16, 0x3c, + 0x3b, 0xe5, 0x02, 0xc2, 0x1b, 0x06, 0x30, 0x68, 0x83, 0xf8, 0x10, 0xd0, 0xd0, 0xcc, 0x2f, 0x15, + 0x14, 0x6b, 0xa1, 0x8f, 0x2e, 0xcc, 0x30, 0x5f, 0x8e, 0x5b, 0xfb, 0x3a, 0x1e, 0x56, 0xad, 0xaa, + 0xeb, 0xe7, 0xd9, 0x9a, 0x6e, 0x14, 0xf5, 0xc7, 0x7a, 0x86, 0x95, 0x78, 0x5b, 0x0f, 0x14, 0x7c, + 0xe3, 0xca, 0x12, 0xc1, 0xac, 0xbd, 0x65, 0x87, 0xb1, 0xcd, 0x45, 0xdc, 0xbf, 0xf2, 0xe9, 0x0a, + 0x91, 0xd5, 0x17, 0x94, 0xb9, 0xf3, 0x6f, 0x4e, 0xa4, 0x7d, 0xff, 0x75, 0x3c, 0x27, 0x3c, 0x13, + 0x82, 0xca, 0xb7, 0xae, 0xa4, 0x7d, 0xe7, 0x57, 0xc7, 0x91, 0x45, 0x76, 0x8c, 0x80, 0x00, 0x06, + 0x80, 0x16, 0xa9, 0x55, 0xa1, 0x79, 0xa3, 0xa7, 0x68, 0xf1, 0x5b, 0x1e, 0xcc, 0x38, 0xfa, 0x7e, + 0xde, 0x53, 0xe3, 0x4c, 0x16, 0xe9, 0xdf, 0x16, 0x10, 0xd7, 0x9c, 0xb6, 0x7f, 0xe1, 0xe2, 0x82, + 0x4e, 0xda, 0xda, 0x56, 0xca, 0xd9, 0x73, 0xb6, 0x52, 0x67, 0x69, 0xe8, 0x3a, 0x9b, 0x3b, 0x24, + 0x78, 0xaf, 0x33, 0x70, 0xc6, 0xd5, 0x51, 0xa1, 0x44, 0x88, 0x3c, 0xaa, 0xa7, 0x9d, 0x8b, 0x77, + 0x90, 0xa0, 0x91, 0x44, 0x5a, 0x7c, 0x76, 0x3d, 0xc9, 0x38, 0xa1, 0xa8, 0x66, 0x94, 0x45, 0xdd, + 0x94, 0x90, 0x89, 0x12, 0x18, 0xd5, 0x61, 0x19, 0x57, 0x60, 0xcd, 0x3c, 0x30, 0x94, 0xc2, 0xc9, + 0x33, 0x85, 0x31, 0xa8, 0x29, 0xb6, 0x13, 0x28, 0xcf, 0x0e, 0x27, 0x1f, 0x10, 0xea, 0x5a, 0x8f, + 0x5e, 0xe3, 0x0b, 0xac, 0xa5, 0x7d, 0x36, 0x98, 0x65, 0x6c, 0x49, 0xe4, 0x58, 0xc7, 0xa8, 0xb5, + 0x75, 0xc7, 0x13, 0x72, 0x0b, 0x50, 0x00, 0x00, 0x4c, 0x02, 0x3a, 0xc2, 0xa8, 0x28, 0x7a, 0xec, + 0x3b, 0x93, 0xe1, 0xd7, 0xa5, 0x31, 0x7c, 0x15, 0xab, 0x18, 0x69, 0x4e, 0x64, 0xad, 0x1d, 0xc1, + 0x9a, 0x4a, 0x0c, 0xf6, 0x1a, 0x19, 0x51, 0x2f, 0x61, 0x58, 0x82, 0x46, 0x2d, 0x6a, 0x23, 0x42, + 0x81, 0x26, 0x1d, 0xe1, 0x60, 0xab, 0x3c, 0x8e, 0x08, 0x1a, 0x72, 0x62, 0xea, 0xad, 0x62, 0xb8, + 0x95, 0x30, 0xb4, 0x87, 0x0d, 0x47, 0x31, 0x30, 0xd6, 0x08, 0x1f, 0x6a, 0xe8, 0x57, 0xac, 0xb0, + 0xc3, 0x48, 0x83, 0x54, 0xd3, 0x85, 0xb9, 0x26, 0x1b, 0x6a, 0x26, 0xba, 0xf9, 0x27, 0x06, 0xea, + 0xbb, 0xfb, 0xf0, 0x7a, 0x37, 0x35, 0xf7, 0x37, 0xdf, 0x3a, 0x07, 0x3b, 0xdf, 0x35, 0xb0, 0x97, + 0x3b, 0xae, 0xbc, 0x80, 0x13, 0x43, 0x32, 0x25, 0xef, 0x0c, 0x1e, 0xa7, 0x8c, 0x7d, 0x51, 0x31, + 0xe1, 0x45, 0xbc, 0x85, 0xc6, 0xe2, 0x0c, 0x05, 0x88, 0x27, 0x8a, 0x26, 0x93, 0x07, 0x07, 0x84, + 0x34, 0xc0, 0xf1, 0x0a, 0x6d, 0x4d, 0xe1, 0x9e, 0xf8, 0x1c, 0x25, 0xdd, 0xe7, 0xb1, 0x42, 0x0d, + 0x2f, 0xce, 0x49, 0x16, 0xe4, 0xb6, 0x0a, 0x4b, 0x31, 0x85, 0xba, 0xf6, 0x4e, 0xb3, 0xc1, 0x82, + 0x50, 0x51, 0xe4, 0x71, 0x21, 0x45, 0xd8, 0x50, 0x49, 0x58, 0xeb, 0xc2, 0xdc, 0x10, 0x4c, 0x79, + 0x07, 0x09, 0x82, 0x8e, 0x25, 0x61, 0x82, 0x42, 0x0b, 0x2b, 0xbe, 0x0d, 0x4a, 0x46, 0xa4, 0x10, + 0x7f, 0x41, 0x9a, 0x52, 0x25, 0xe2, 0x90, 0x68, 0x20, 0x69, 0x82, 0x20, 0xf2, 0xba, 0x0a, 0x14, + 0x6a, 0xaa, 0x8a, 0x42, 0x56, 0x07, 0x37, 0x31, 0x1a, 0x21, 0x68, 0x0c, 0x2f, 0x38, 0x20, 0x4a, + 0x0a, 0x74, 0xb2, 0x8e, 0x27, 0x14, 0x51, 0xc8, 0xca, 0x06, 0x8a, 0x9a, 0xcd, 0x79, 0x87, 0x29, + 0x3d, 0x94, 0xe9, 0x2b, 0x57, 0x48, 0x36, 0x43, 0x9a, 0xb3, 0x99, 0xd9, 0x2b, 0x92, 0xce, 0xc9, + 0x70, 0x00, 0x01, 0x57, 0x5d, 0x51, 0x4c, 0x26, 0xb2, 0xe7, 0x13, 0x82, 0x96, 0xea, 0x8b, 0x66, + 0x68, 0x88, 0x3b, 0xcd, 0x61, 0xac, 0xde, 0x28, 0x82, 0x29, 0x69, 0x47, 0xd6, 0x49, 0x74, 0x39, + 0x18, 0x2a, 0x79, 0x98, 0x9c, 0x47, 0x6e, 0x36, 0xa7, 0x25, 0x3f, 0xad, 0x9e, 0x4f, 0x8a, 0x77, + 0xeb, 0x56, 0x92, 0xa2, 0xaf, 0x6d, 0x84, 0x72, 0xf3, 0xa6, 0xbf, 0x45, 0xc9, 0x33, 0x04, 0x9a, + 0x7e, 0x7c, 0xc6, 0x71, 0xe3, 0x3d, 0xda, 0xe5, 0x92, 0x31, 0x46, 0x90, 0xbd, 0x52, 0x42, 0x0d, + 0x49, 0xd4, 0x79, 0xdb, 0xba, 0x8f, 0xd1, 0x18, 0x0b, 0x15, 0xd1, 0x05, 0xa0, 0x81, 0xe7, 0x20, + 0xb9, 0x28, 0x4a, 0x10, 0xf9, 0x51, 0x06, 0x92, 0x1c, 0x1a, 0x39, 0x2d, 0xf5, 0x35, 0x53, 0x64, + 0x18, 0xf1, 0x09, 0x1e, 0x10, 0xbd, 0xd7, 0x25, 0x72, 0x93, 0x20, 0x5b, 0x0d, 0x47, 0x1c, 0x0f, + 0x54, 0x76, 0xc0, 0x58, 0xe1, 0x2c, 0x25, 0x8d, 0x88, 0x42, 0xc2, 0x5c, 0x20, 0x4b, 0xea, 0xd5, + 0x04, 0xfe, 0xda, 0x38, 0x4e, 0x09, 0x3a, 0x1a, 0x5f, 0x8e, 0x04, 0xb1, 0x33, 0xe6, 0xd0, 0x47, + 0x30, 0xcf, 0xf9, 0x06, 0xea, 0xe1, 0xf2, 0x06, 0x48, 0x15, 0x8d, 0xda, 0x65, 0xbd, 0x57, 0x0d, + 0xd8, 0x00, 0x0c, 0x01, 0xe2, 0x70, 0x8c, 0x12, 0x45, 0xb2, 0x0f, 0xe3, 0x8d, 0x90, 0x2a, 0x49, + 0xde, 0x45, 0x3e, 0xb8, 0x8a, 0x93, 0x26, 0xe5, 0x1f, 0xe6, 0xca, 0x1f, 0x60, 0x84, 0x7f, 0xff, + 0xf8, 0x99, 0xa8, 0x03, 0xa0, 0x46, 0xef, 0x39, 0xef, 0x33, 0xef, 0x34, 0xef, 0x28, 0xe6, 0x20, + 0x15, 0xdf, 0x5a, 0x00, 0xec, 0x00, 0x10, 0x07, 0xa2, 0x8d, 0x44, 0xe9, 0x22, 0x0d, 0x1c, 0x0b, + 0x0a, 0x2e, 0x79, 0xb5, 0xdc, 0xfb, 0x61, 0x3e, 0x30, 0xfb, 0xa4, 0x5b, 0xea, 0xdd, 0xb6, 0x95, + 0x8a, 0x2d, 0x1e, 0x58, 0xe3, 0x73, 0x1b, 0xdb, 0x89, 0xc4, 0xb3, 0xe5, 0xf4, 0x50, 0x90, 0x00, + 0x00, 0x08, 0x17, 0x6a, 0x8f, 0x45, 0xe2, 0xcc, 0xda, 0x4c, 0xa2, 0xd4, 0x59, 0x85, 0x9c, 0xf5, + 0x29, 0x70, 0x61, 0xa4, 0x52, 0x74, 0x56, 0xa4, 0x8b, 0x72, 0xca, 0x16, 0x73, 0x1e, 0xc8, 0x3c, + 0x0a, 0x09, 0x51, 0x05, 0xa8, 0xa5, 0xe7, 0x47, 0x2f, 0xb2, 0x08, 0x79, 0x11, 0x13, 0x4c, 0x25, + 0x8a, 0x8c, 0xfb, 0x39, 0xaa, 0xa4, 0x34, 0x56, 0xab, 0x1e, 0x81, 0x13, 0x15, 0x86, 0x36, 0x14, + 0x71, 0x6c, 0x87, 0x16, 0x0c, 0x05, 0x83, 0x9a, 0xc5, 0xb1, 0x50, 0x50, 0xf1, 0x58, 0xe7, 0x8c, + 0xb1, 0x20, 0x8f, 0xa7, 0x7a, 0xbb, 0x96, 0xcc, 0xe4, 0x22, 0x7d, 0x46, 0x12, 0x1c, 0x4b, 0xac, + 0x8a, 0xd0, 0x00, 0xbf, 0x52, 0x25, 0x0d, 0x73, 0x9c, 0x16, 0x0c, 0x5b, 0x16, 0xe4, 0x5f, 0x3c, + 0x31, 0x32, 0x46, 0x91, 0x91, 0x89, 0x21, 0x52, 0xcf, 0xc6, 0x5e, 0x9c, 0xcb, 0x89, 0x77, 0x99, + 0x71, 0x00, 0x00, 0x34, 0x24, 0xa4, 0x24, 0xc4, 0xa9, 0x38, 0xcb, 0x69, 0x48, 0x50, 0xb1, 0xc4, + 0x8a, 0x7e, 0xb0, 0xc1, 0x70, 0x74, 0xe7, 0x98, 0x2c, 0x72, 0xc4, 0x0b, 0x22, 0xf1, 0x0a, 0x12, + 0x21, 0xb8, 0x57, 0xac, 0x8c, 0xaf, 0xc5, 0xe1, 0x42, 0x4a, 0xb4, 0xe6, 0x29, 0x3a, 0xcf, 0xc4, + 0x90, 0xdc, 0x93, 0x07, 0x84, 0x05, 0x86, 0x12, 0x91, 0x43, 0x42, 0x0b, 0x71, 0xf8, 0x46, 0xe7, + 0x90, 0xde, 0x92, 0x4a, 0xbe, 0xf2, 0x13, 0x10, 0xb4, 0x7e, 0x10, 0x16, 0x23, 0xf2, 0xe8, 0xdc, + 0x73, 0xf5, 0xc9, 0x84, 0xd5, 0x55, 0x12, 0xb3, 0xb6, 0x89, 0xb6, 0x61, 0x74, 0xe2, 0x5c, 0x6c, + 0x4a, 0x30, 0xb6, 0x26, 0x50, 0xdf, 0x55, 0x42, 0xff, 0xbe, 0x3c, 0xe2, 0xda, 0xa3, 0xfa, 0xd8, + 0xb2, 0x55, 0x2b, 0xd8, 0xc2, 0xf3, 0xd8, 0x2e, 0x98, 0xb4, 0x90, 0x3d, 0x9a, 0xb6, 0x1f, 0xe5, + 0x17, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x88, 0xea, 0x1e, 0x0a, 0x0f, 0x18, 0x79, 0x06, 0x91, 0x7f, + 0x61, 0x41, 0x34, 0x40, 0x92, 0xb3, 0xeb, 0xbe, 0xad, 0xdf, 0xfc, 0xb3, 0x97, 0x74, 0xe2, 0x4c, + 0x16, 0x30, 0x98, 0x55, 0xda, 0x30, 0x2b, 0xfc, 0x14, 0xea, 0x09, 0xda, 0x04, 0xab, 0xf3, 0x5b, + 0x78, 0xf0, 0x5d, 0xf3, 0x2b, 0xfc, 0x4c, 0x04, 0x5e, 0x5a, 0x66, 0x9a, 0xb3, 0x6d, 0x5d, 0x3b, + 0xa5, 0x74, 0x58, 0x2b, 0xcb, 0x04, 0x44, 0xba, 0xea, 0x1b, 0x57, 0x31, 0x81, 0x76, 0x91, 0x76, + 0x4f, 0xd1, 0x94, 0x0d, 0xb3, 0xce, 0xc1, 0x95, 0xea, 0x5c, 0xa0, 0x9a, 0xa7, 0x56, 0x5d, 0x55, + 0xd3, 0xda, 0xf8, 0x44, 0x2e, 0x00, 0x00, 0x28, 0x05, 0x3f, 0x91, 0x1e, 0x3e, 0xf1, 0x15, 0x76, + 0xef, 0xb4, 0x67, 0x03, 0x7d, 0x42, 0x6d, 0x88, 0x9a, 0x2f, 0x22, 0x3e, 0xb9, 0x75, 0xd8, 0xeb, + 0x3d, 0x6f, 0x04, 0x79, 0xfe, 0x1f, 0xde, 0x6b, 0x17, 0x67, 0x3b, 0x89, 0x98, 0x26, 0xef, 0x93, + 0x5e, 0x9c, 0x0a, 0xa8, 0x99, 0xa0, 0x8d, 0xe4, 0xab, 0x6e, 0x22, 0x26, 0x94, 0xdf, 0xc3, 0xf8, + 0xd3, 0xbd, 0x88, 0x88, 0x92, 0xa6, 0x7f, 0xe2, 0x67, 0x0f, 0xb2, 0xc3, 0xac, 0x94, 0x3f, 0x48, + 0xe6, 0x83, 0xad, 0x4d, 0x33, 0x22, 0x47, 0xf4, 0x9a, 0x37, 0xb2, 0xf4, 0x57, 0x6a, 0x2a, 0xbd, + 0x89, 0xa0, 0xaa, 0x84, 0xd7, 0x30, 0x45, 0x1e, 0xbe, 0x42, 0x26, 0xc9, 0x26, 0x5d, 0x0f, 0xdd, + 0x81, 0x92, 0xc2, 0xed, 0x2a, 0x67, 0xdd, 0x28, 0x54, 0x00, 0x01, 0x0f, 0x20, 0xf7, 0x11, 0xa7, + 0xe9, 0x6c, 0xdf, 0xca, 0x7b, 0x37, 0xf4, 0x61, 0x87, 0x0c, 0xac, 0x42, 0x4c, 0x98, 0xc9, 0x6f, + 0xf0, 0x81, 0x53, 0xd3, 0xd1, 0xe7, 0x74, 0x62, 0x79, 0x30, 0x62, 0xfb, 0x58, 0x71, 0x50, 0x00, + 0x03, 0x63, 0xeb, 0x9e, 0x65, 0x8f, 0x3a, 0xc1, 0x8e, 0xb5, 0xde, 0x6a, 0xe8, 0x5c, 0xd5, 0x20, + 0x89, 0x88, 0x26, 0x72, 0xd3, 0xba, 0x44, 0x9f, 0x29, 0x85, 0x48, 0x2e, 0xa1, 0x0c, 0x13, 0x99, + 0x8a, 0x73, 0xa8, 0x10, 0xfb, 0x99, 0xd3, 0x24, 0x35, 0x92, 0x4a, 0xfb, 0x2f, 0x6f, 0x93, 0xa1, + 0xad, 0xac, 0x22, 0x60, 0x48, 0x36, 0x30, 0xab, 0xdb, 0x43, 0xe4, 0x2d, 0x0f, 0xd2, 0x87, 0x3b, + 0x89, 0xdf, 0x4e, 0x32, 0x53, 0xb7, 0x79, 0xb3, 0xc6, 0xde, 0x73, 0x3b, 0xe5, 0x9d, 0x1e, 0xfd, + 0xe4, 0xc3, 0x28, 0x40, 0xc3, 0xfa, 0x94, 0x5c, 0x2a, 0x7a, 0x59, 0xfb, 0x85, 0xc5, 0xa0, 0xf9, + 0x05, 0xd2, 0x41, 0x5e, 0x47, 0xd8, 0x48, 0x54, 0x42, 0xf1, 0x41, 0x79, 0x1a, 0x55, 0x2d, 0xc7, + 0x54, 0x2e, 0x38, 0x9d, 0xe7, 0x43, 0x99, 0x6f, 0x92, 0xd5, 0x7a, 0x93, 0x82, 0x22, 0x44, 0xd2, + 0x8d, 0x35, 0xb2, 0x02, 0xa7, 0xb0, 0xfd, 0x48, 0x57, 0xf5, 0x20, 0xd9, 0x2d, 0xc2, 0xf4, 0xc2, + 0xef, 0x77, 0x82, 0x88, 0x18, 0x1b, 0x2d, 0x2c, 0x22, 0xd2, 0xf0, 0x53, 0xe2, 0x04, 0xe1, 0x36, + 0xa2, 0xa1, 0xf0, 0xc1, 0x97, 0x45, 0x94, 0x46, 0xff, 0x7a, 0x11, 0xb2, 0x89, 0xea, 0x4a, 0x3a, + 0x59, 0x98, 0x08, 0x1b, 0x30, 0x4d, 0x60, 0x58, 0x0b, +}; + +// tone.mp3: 1227 bytes +const unsigned char kToneMp3[] = { + 0xff, 0xf3, 0x70, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x66, + 0x6f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x04, 0xcb, 0x00, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xea, 0xea, 0xea, + 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x76, 0x66, 0x20, 0x6c, 0x61, 0x6d, 0x65, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x03, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0xcb, 0xfc, 0xd1, 0x18, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf3, 0x40, 0xc4, 0x00, 0x14, 0x10, 0x82, 0x8c, 0x1f, + 0x58, 0x18, 0x00, 0x31, 0xb6, 0xdc, 0x81, 0x53, 0xaa, 0x75, 0x4e, 0x98, 0xea, 0x0e, 0xb1, 0xe0, + 0x77, 0x41, 0x76, 0x17, 0x7c, 0x02, 0x33, 0x4a, 0xcd, 0xf1, 0x37, 0xb4, 0xd2, 0x52, 0xd7, 0xae, + 0xb7, 0x7e, 0x1c, 0x8c, 0x46, 0x23, 0x11, 0x88, 0xc4, 0xb2, 0x93, 0x07, 0x77, 0x03, 0x16, 0x0f, + 0x87, 0xd4, 0x08, 0x02, 0x0e, 0xc1, 0xff, 0x0c, 0x4a, 0x7b, 0xf9, 0x4f, 0x0f, 0xf2, 0x8e, 0xe1, + 0xfe, 0x53, 0xcf, 0xf4, 0x7b, 0xfa, 0x3f, 0x83, 0xe0, 0x40, 0x40, 0x31, 0x20, 0x0f, 0x87, 0xf2, + 0x87, 0x3b, 0xfa, 0x15, 0x0c, 0x00, 0x04, 0x90, 0x61, 0x04, 0x03, 0x00, 0x00, 0x52, 0xff, 0xf3, + 0x42, 0xc4, 0x0a, 0x17, 0x19, 0x16, 0xa1, 0x77, 0x9b, 0x50, 0x00, 0xa4, 0x1e, 0xd3, 0x19, 0xc9, + 0x90, 0x98, 0xc8, 0xc0, 0x02, 0x95, 0xfc, 0x32, 0xe1, 0x64, 0x60, 0x31, 0x4c, 0xe0, 0x16, 0x50, + 0x04, 0x00, 0x6b, 0xa9, 0xa0, 0x19, 0x48, 0x14, 0x32, 0x04, 0xa0, 0x32, 0x05, 0x1f, 0xc4, 0x10, + 0x37, 0x03, 0x77, 0xe3, 0x11, 0x12, 0x22, 0x48, 0xbf, 0xc5, 0xa1, 0x14, 0x42, 0x3d, 0x1e, 0xff, + 0xe4, 0x43, 0xe1, 0xf1, 0x08, 0xf4, 0x7a, 0x7b, 0xf2, 0xc1, 0x50, 0x54, 0x44, 0x15, 0xff, 0x82, + 0xa2, 0x20, 0xa8, 0x2a, 0x22, 0x3c, 0x77, 0xff, 0xca, 0x88, 0x82, 0xa1, 0xa2, 0xca, 0x96, 0xa8, + 0xe9, 0x80, 0x0c, 0x00, 0x28, 0x20, 0x00, 0xff, 0xf3, 0x40, 0xc4, 0x09, 0x15, 0xb8, 0x5a, 0x20, + 0x01, 0xdf, 0x00, 0x00, 0x31, 0x00, 0x09, 0x06, 0x06, 0x08, 0x1b, 0x46, 0x06, 0xd8, 0x8e, 0x86, + 0x0d, 0x58, 0x6c, 0xc6, 0x1c, 0x48, 0x2c, 0xc6, 0x15, 0x48, 0xd0, 0xc6, 0x4b, 0x38, 0xff, 0xc7, + 0xa6, 0x5a, 0x73, 0x66, 0x4e, 0x20, 0xee, 0x61, 0x03, 0x3e, 0x18, 0x10, 0xe0, 0x37, 0x18, 0x1e, + 0x20, 0x8b, 0x18, 0x11, 0xa0, 0x13, 0x98, 0x0b, 0xc0, 0x26, 0x98, 0x05, 0x60, 0x18, 0x18, 0x00, + 0x20, 0x09, 0x82, 0x80, 0x2d, 0x9d, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x1f, 0xfd, 0xbf, 0xff, 0xff, + 0xea, 0xdd, 0xcd, 0xa5, 0x91, 0x22, 0x08, 0x63, 0x03, 0x08, 0x4f, 0xd0, 0x20, 0x03, 0x26, 0xff, + 0xf3, 0x42, 0xc4, 0x0d, 0x0f, 0x00, 0x56, 0x1c, 0x00, 0x7f, 0xf8, 0x24, 0x00, 0x08, 0x01, 0x06, + 0x00, 0xe8, 0x02, 0x06, 0x03, 0x90, 0x0b, 0x27, 0xde, 0xa2, 0x64, 0x87, 0x2a, 0x0b, 0x83, 0x8e, + 0x42, 0xc1, 0x94, 0x9a, 0x6a, 0xcf, 0xdc, 0xae, 0xe6, 0x35, 0x7e, 0x99, 0x8f, 0xf4, 0xff, 0xb3, + 0x6f, 0xff, 0xd3, 0xb9, 0xbf, 0xff, 0xff, 0xf7, 0xb6, 0x9d, 0x48, 0xf5, 0x92, 0x54, 0x90, 0x1d, + 0x4c, 0x0d, 0xf1, 0x3d, 0x0c, 0x00, 0x10, 0x06, 0x0c, 0x00, 0x00, 0x02, 0x4c, 0x01, 0xe0, 0x04, + 0xcc, 0x07, 0x30, 0x19, 0x8f, 0xb6, 0x95, 0x63, 0x4e, 0x52, 0x1c, 0x05, 0x1c, 0x45, 0x83, 0x49, + 0x02, 0xd5, 0xe0, 0x49, 0x45, 0xd3, 0xd6, 0xdb, 0xff, 0xf3, 0x40, 0xc4, 0x2d, 0x0f, 0x98, 0x52, + 0x1c, 0x00, 0x7f, 0xf8, 0x24, 0xf6, 0x3f, 0xec, 0xfb, 0xbf, 0xff, 0xf6, 0xfb, 0x6a, 0xff, 0xff, + 0xff, 0x7b, 0xd5, 0x77, 0xfe, 0xdd, 0x0a, 0xe6, 0xb7, 0x72, 0x09, 0x21, 0x00, 0x03, 0x0f, 0xa4, + 0xe9, 0x30, 0x02, 0x01, 0x93, 0x00, 0x30, 0x08, 0x30, 0x07, 0xc0, 0x16, 0x30, 0x1c, 0x80, 0x73, + 0x3e, 0xba, 0x97, 0xd8, 0x39, 0x30, 0x84, 0x0c, 0x6e, 0x12, 0x0c, 0xa4, 0x13, 0x51, 0x81, 0xe6, + 0xee, 0x63, 0x57, 0xfa, 0x3f, 0x4d, 0x3f, 0xff, 0xf5, 0xed, 0x67, 0x45, 0x7f, 0xd7, 0xb3, 0xff, + 0xf4, 0x7f, 0xa3, 0xff, 0x72, 0x2a, 0xcb, 0x7a, 0xbb, 0x05, 0x10, 0x00, 0x09, 0x88, 0xaa, 0x6e, + 0xff, 0xf3, 0x42, 0xc4, 0x49, 0x0f, 0x90, 0x56, 0x1c, 0x00, 0xf7, 0xf8, 0x40, 0x18, 0x02, 0x80, + 0xc1, 0x80, 0x20, 0x04, 0x98, 0x03, 0xc0, 0x0c, 0x98, 0x0e, 0x20, 0x3f, 0x1f, 0x4b, 0x6d, 0x05, + 0x9c, 0x8c, 0x4c, 0x02, 0x36, 0x87, 0x06, 0x92, 0x05, 0xa9, 0x40, 0x93, 0x15, 0x72, 0xaf, 0xf4, + 0x53, 0xfd, 0x3f, 0xf6, 0xff, 0xaa, 0xed, 0x7a, 0xfd, 0x7f, 0xff, 0xff, 0xf7, 0xfa, 0xbf, 0xe8, + 0x5d, 0x54, 0xed, 0x4c, 0x10, 0x00, 0x10, 0x00, 0x00, 0xc3, 0x00, 0xb0, 0x02, 0x23, 0x00, 0x9c, + 0x07, 0x33, 0x02, 0xe8, 0x37, 0x13, 0x00, 0xd4, 0x24, 0x33, 0x0d, 0x54, 0x2b, 0x93, 0x10, 0xe0, + 0x5d, 0xe3, 0x18, 0x78, 0x17, 0xe3, 0xa8, 0xf1, 0x0f, 0xff, 0xf3, 0x40, 0xc4, 0x66, 0x0f, 0x68, + 0x56, 0x1c, 0x00, 0xf7, 0xf8, 0x40, 0x63, 0x18, 0xf4, 0x29, 0x13, 0x07, 0x30, 0x25, 0xe3, 0x06, + 0x20, 0x10, 0x63, 0x04, 0x08, 0x0a, 0x23, 0x00, 0xa4, 0x07, 0x31, 0x60, 0x11, 0x87, 0x00, 0x0b, + 0x08, 0x01, 0x0c, 0x0c, 0x00, 0x23, 0xa9, 0x67, 0xfb, 0xbf, 0xff, 0xff, 0xf6, 0xaa, 0xe4, 0x46, + 0x2b, 0x62, 0x41, 0x58, 0xd0, 0x5a, 0x34, 0x1a, 0x89, 0x00, 0x1b, 0x55, 0x04, 0xc4, 0x0a, 0x00, + 0x86, 0x5f, 0xd9, 0xd1, 0x09, 0x8e, 0x19, 0x74, 0xb0, 0xca, 0xd1, 0x16, 0x89, 0x17, 0x01, 0xd4, + 0x4a, 0xc6, 0x0b, 0x78, 0xdd, 0x08, 0x03, 0xb0, 0xd5, 0x63, 0x26, 0x6c, 0x40, 0x48, 0x2f, 0x0b, + 0x60, 0xff, 0xf3, 0x42, 0xc4, 0x83, 0x13, 0xc8, 0x5a, 0x24, 0x01, 0x5f, 0x00, 0x00, 0x2c, 0x82, + 0x20, 0x3a, 0x85, 0x04, 0x28, 0x2f, 0x10, 0x0c, 0xdd, 0x33, 0x52, 0x89, 0x15, 0x22, 0xa6, 0x5f, + 0x17, 0x39, 0x13, 0x15, 0xa0, 0x82, 0x83, 0x20, 0x41, 0x87, 0x38, 0xc4, 0xba, 0x4c, 0xff, 0x1c, + 0xf1, 0xcf, 0x27, 0xc7, 0x30, 0x8a, 0x13, 0x84, 0x1c, 0xc8, 0xd8, 0xca, 0x92, 0x4b, 0xff, 0x8e, + 0x79, 0x3e, 0x41, 0x0b, 0x86, 0x86, 0xe8, 0x31, 0x9a, 0x28, 0xa9, 0x23, 0x25, 0xa2, 0x8a, 0xbf, + 0xfe, 0x5f, 0x37, 0x22, 0x84, 0x50, 0xd0, 0x8b, 0x91, 0x73, 0x72, 0x28, 0x5c, 0x34, 0x27, 0xd3, + 0x2f, 0x17, 0x81, 0x53, 0xb2, 0xc1, 0x53, 0xbf, 0xee, 0xd6, 0xff, 0xf3, 0x40, 0xc4, 0x8f, 0x25, + 0x8a, 0x2e, 0xc5, 0xbf, 0x9a, 0x88, 0x02, 0x50, 0xe0, 0x7c, 0xa8, 0x88, 0x2a, 0x0a, 0xd5, 0x58, + 0x20, 0x08, 0x8c, 0xa2, 0x2d, 0x73, 0x26, 0x8e, 0xb3, 0x95, 0xda, 0xf2, 0xaa, 0xa8, 0x00, 0x66, + 0x20, 0xa5, 0x6b, 0xd4, 0xa9, 0xa0, 0x72, 0xf6, 0x98, 0x82, 0xd5, 0xcb, 0xda, 0x59, 0x14, 0x15, + 0x79, 0x5f, 0x67, 0x2a, 0x1e, 0xbe, 0x70, 0x30, 0x08, 0x29, 0x2f, 0xe8, 0x94, 0xf6, 0xaa, 0xf2, + 0x44, 0x8d, 0x39, 0x12, 0x33, 0xe8, 0x91, 0x2c, 0xa2, 0x44, 0xab, 0xc9, 0xa4, 0x40, 0xa0, 0xa9, + 0xd1, 0x11, 0xe0, 0x68, 0x3b, 0xce, 0xfe, 0x22, 0xe5, 0x4e, 0xad, 0xd0, 0x6a, 0x1d, 0x4c, 0x41, + 0x4d, 0x45, 0xff, 0xf3, 0x42, 0xc4, 0x53, 0x13, 0xc0, 0xfe, 0x10, 0x01, 0xd8, 0x30, 0x00, 0x33, + 0x2e, 0x31, 0x30, 0x30, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, +}; + +int failures = 0; + +void check(bool ok, const char* what) +{ + std::printf("%-64s %s\n", what, ok ? "ok" : "FAILED"); + if (!ok) ++failures; +} + +// The FLAC fixture's source: a triangle wave per channel (periods 400 and 500) +// plus 4 bits of noise from a 32-bit LCG, interleaved. +std::vector flac_signal(unsigned frames, unsigned channels) +{ + std::vector out; + std::uint32_t x = 12345; + for (unsigned n = 0; n < frames; ++n) { + for (unsigned c = 0; c < channels; ++c) { + x = x * 1664525u + 1013904223u; + int noise = int((x >> 16) & 15) - 8; + int p = 400 + 100 * int(c), t = int(n) % p; + int tri = t < p / 2 ? (t * 4 * 8000) / p - 8000 : 24000 - (t * 4 * 8000) / p; + out.push_back(drflac_int16(tri + noise)); + } + } + return out; +} + +// Goertzel power of `hz` in a mono signal. +double power(const std::vector& s, double hz, double rate) +{ + const double k = 2.0 * std::cos(2.0 * 3.14159265358979323846 * hz / rate); + double a = 0, b = 0; + for (float v : s) { double y = v + k * a - b; b = a; a = y; } + return a * a + b * b - k * a * b; +} + +void wav_round_trip(drwav_container container, const char* label) +{ + const unsigned frames = 1000; + std::vector pcm(frames * 2); + for (unsigned i = 0; i < pcm.size(); ++i) pcm[i] = drwav_int16((int(i) * 131) % 65536 - 32768); + + drwav_data_format fmt{}; + fmt.container = container; + fmt.format = DR_WAVE_FORMAT_PCM; + fmt.channels = 2; + fmt.sampleRate = 48000; + fmt.bitsPerSample = 16; + void* data = nullptr; + size_t size = 0; + drwav w; + char what[96]; + std::snprintf(what, sizeof what, "%s: drwav_init_memory_write", label); + check(drwav_init_memory_write(&w, &data, &size, &fmt, nullptr) == DRWAV_TRUE, what); + std::snprintf(what, sizeof what, "%s: drwav_write_pcm_frames writes all frames", label); + check(drwav_write_pcm_frames(&w, frames, pcm.data()) == frames, what); + drwav_uninit(&w); + + drwav r; + std::snprintf(what, sizeof what, "%s: drwav_init_memory reads it back", label); + check(drwav_init_memory(&r, data, size, nullptr) == DRWAV_TRUE, what); + std::snprintf(what, sizeof what, "%s: 2 channels, 48000 Hz, 16 bits, 1000 frames", label); + check(r.channels == 2 && r.sampleRate == 48000 && r.bitsPerSample == 16 && r.totalPCMFrameCount == frames && + r.container == container && drwav_fmt_get_format(&r.fmt) == DR_WAVE_FORMAT_PCM, what); + std::vector back(pcm.size()); + std::snprintf(what, sizeof what, "%s: PCM16 sample-exact", label); + check(drwav_read_pcm_frames_s16(&r, frames, back.data()) == frames && back == pcm, what); + std::vector f(pcm.size()); + drwav_seek_to_pcm_frame(&r, 0); + bool exact = drwav_read_pcm_frames_f32(&r, frames, f.data()) == frames; + for (size_t i = 0; exact && i < f.size(); ++i) exact = f[i] == float(pcm[i]) / 32768.0f; + std::snprintf(what, sizeof what, "%s: read as f32, each sample s / 32768", label); + check(exact, what); + drwav_uninit(&r); + drwav_free(data, nullptr); +} + +void wav_float_and_mulaw() +{ + // IEEE float, bit-exact. + std::vector f(512); + for (unsigned i = 0; i < f.size(); ++i) f[i] = float(std::sin(i * 0.05)) * 0.75f; + drwav_data_format fmt{drwav_container_riff, DR_WAVE_FORMAT_IEEE_FLOAT, 1, 44100, 32}; + void* data = nullptr; + size_t size = 0; + drwav w; + check(drwav_init_memory_write(&w, &data, &size, &fmt, nullptr) == DRWAV_TRUE && + drwav_write_pcm_frames(&w, f.size(), f.data()) == f.size(), "IEEE float WAV written"); + drwav_uninit(&w); + drwav r; + std::vector back(f.size()); + check(drwav_init_memory(&r, data, size, nullptr) == DRWAV_TRUE && + drwav_fmt_get_format(&r.fmt) == DR_WAVE_FORMAT_IEEE_FLOAT && + drwav_read_pcm_frames_f32(&r, f.size(), back.data()) == f.size() && + std::memcmp(back.data(), f.data(), f.size() * sizeof(float)) == 0, + "IEEE float WAV read back bit-exact"); + drwav_uninit(&r); + drwav_free(data, nullptr); + + // mu-law: every code, decoded through the reader and through the table. + std::vector codes(256); + for (unsigned i = 0; i < 256; ++i) codes[i] = drwav_uint8(i); + drwav_data_format mu{drwav_container_riff, DR_WAVE_FORMAT_MULAW, 1, 8000, 8}; + data = nullptr; + size = 0; + check(drwav_init_memory_write(&w, &data, &size, &mu, nullptr) == DRWAV_TRUE && + drwav_write_pcm_frames(&w, 256, codes.data()) == 256, "mu-law WAV written (all 256 codes)"); + drwav_uninit(&w); + std::vector viaReader(256), viaTable(256); + drwav_mulaw_to_s16(viaTable.data(), codes.data(), 256); + check(drwav_init_memory(&r, data, size, nullptr) == DRWAV_TRUE && + drwav_read_pcm_frames_s16(&r, 256, viaReader.data()) == 256 && viaReader == viaTable && + viaTable[0] == -32124 && viaTable[255] == 0, + "mu-law WAV decoded by the reader equals drwav_mulaw_to_s16"); + drwav_uninit(&r); + drwav_free(data, nullptr); +} + +struct FlacMeta { + drflac_uint8 md5[16]{}; + bool streaminfo = false; + char vendor[32]{}; +}; + +void on_flac_meta(void* user, drflac_metadata* m) +{ + auto* meta = static_cast(user); + if (m->type == DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO) { + std::memcpy(meta->md5, m->data.streaminfo.md5, 16); + meta->streaminfo = true; + } else if (m->type == DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT) { + unsigned n = m->data.vorbis_comment.vendorLength < 31 ? m->data.vorbis_comment.vendorLength : 31; + std::memcpy(meta->vendor, m->data.vorbis_comment.vendor, n); + } +} + +void flac() +{ + static const drflac_uint8 md5[16] = {0x29, 0x02, 0x2c, 0x35, 0x13, 0xe9, 0xa6, 0xfe, + 0xa7, 0x6a, 0x96, 0x0f, 0xd2, 0x14, 0x70, 0xc2}; + FlacMeta meta; + drflac* f = drflac_open_memory_with_metadata(kToneFlac, sizeof kToneFlac, on_flac_meta, &meta, nullptr); + check(f != nullptr, "drflac_open_memory_with_metadata"); + if (!f) return; + check(f->channels == 2 && f->sampleRate == 44100 && f->bitsPerSample == 16 && f->totalPCMFrameCount == 2048, + "FLAC: 2 channels, 44100 Hz, 16 bits, 2048 frames"); + check(meta.streaminfo && std::memcmp(meta.md5, md5, 16) == 0, "FLAC: STREAMINFO MD5 is the source signal's"); + check(std::strcmp(meta.vendor, "ffmpeg") == 0, "FLAC: VORBIS_COMMENT vendor string"); + const auto want = flac_signal(2048, 2); + std::vector got(want.size()); + check(drflac_read_pcm_frames_s16(f, 2048, got.data()) == 2048 && got == want, + "FLAC: decoded sample-exact (lossless)"); + std::vector tail(2 * 100); + check(drflac_seek_to_pcm_frame(f, 1100) && drflac_read_pcm_frames_s16(f, 100, tail.data()) == 100 && + std::memcmp(tail.data(), want.data() + 2 * 1100, tail.size() * 2) == 0, + "FLAC: seek to frame 1100, then sample-exact"); + drflac_close(f); +} + +void mp3() +{ + drmp3 m; + check(drmp3_init_memory(&m, kToneMp3, sizeof kToneMp3, nullptr) == DRMP3_TRUE, "drmp3_init_memory"); + check(m.channels == 1 && m.sampleRate == 22050, "MP3: 1 channel, 22050 Hz"); + const drmp3_uint64 frames = drmp3_get_pcm_frame_count(&m); + std::printf(" MP3 PCM frames: %llu\n", (unsigned long long)frames); + check(frames == 4410, "MP3: the LAME tag's gapless length, 4410 frames"); + drmp3_seek_to_pcm_frame(&m, 0); + std::vector s(frames); + check(drmp3_read_pcm_frames_f32(&m, frames, s.data()) == frames, "MP3: every frame decoded as f32"); + const double p440 = power(s, 440, 22050), p1000 = power(s, 1000, 22050), p220 = power(s, 220, 22050); + double peak = 0; + for (float v : s) peak = std::fmax(peak, std::fabs(v)); + std::printf(" MP3 peak %.3f, power 440 Hz / 1000 Hz = %.1f, / 220 Hz = %.1f\n", peak, p440 / p1000, p440 / p220); + check(peak > 0.3 && peak < 0.45 && p440 > 1000 * p1000 && p440 > 1000 * p220, + "MP3: a 440 Hz sine at amplitude 12000 / 32768"); + drmp3_uninit(&m); +} + +} // namespace + +int main() +{ + check(std::strcmp(drwav_version_string(), "0.14.5") == 0, "dr_wav 0.14.5"); + check(std::strcmp(drflac_version_string(), "0.13.3") == 0, "dr_flac 0.13.3"); + check(std::strcmp(drmp3_version_string(), "0.7.3") == 0, "dr_mp3 0.7.3"); + wav_round_trip(drwav_container_riff, "RIFF"); + wav_round_trip(drwav_container_w64, "Wave64"); + wav_float_and_mulaw(); + flac(); + mp3(); + std::printf("%d failure(s)\n", failures); + return failures == 0 ? 0 : 1; +}