diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..efb1add --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Preserve upstream document bytes and original whitespace on every platform. +upstream/** -text -whitespace +tests/data/** binary diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b129d04 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,139 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + mcpp: + name: mcpp (${{ matrix.os }}, ${{ matrix.toolchain }}) + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-24.04, toolchain: 'gcc@16.1.0' } + - { os: ubuntu-24.04, toolchain: 'llvm@23.1.3' } + - { os: ubuntu-24.04-arm, toolchain: 'gcc@16.1.0' } + - { os: macos-15, toolchain: 'llvm@23.1.3' } + - { os: windows-2025, toolchain: 'llvm@23.1.3' } + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + defaults: + run: + shell: bash + env: + XLINGS_NON_INTERACTIVE: 1 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Mwrap identity and bilingual README contract + run: python3 tools/check_mwrap_release.py + + - name: Install Xlings (Linux/macOS) + if: runner.os != 'Windows' + run: | + curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/refs/heads/main/tools/other/quick_install.sh | bash + echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" + + - name: Install Xlings (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex + "$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + - name: Install project tools (.xlings.json) + run: | + for attempt in 1 2 3; do + xlings update > /dev/null 2>&1 || true + if xlings install; then break; fi + [ "$attempt" = 3 ] && exit 1 + sleep 30 + done + mcpp --version + + - name: Select the toolchain + run: | + name="${{ matrix.toolchain }}" + mcpp toolchain install "${name%@*}" "${name#*@}" + mcpp toolchain default "$name" + + # Until mcpp-index publishes compat.miniaudio compiled at gnu11 + # (mcpplibs/mcpp-index#609), the compat namespace of this checkout's + # manifests resolves from that PR's branch, as an unchanged namespace + # view of its descriptors. Once published, this step does nothing. + - name: Candidate compat index (only while compat.miniaudio's gnu11 build is unpublished) + run: python3 tools/candidate_index.py --ci + + - name: Build the modules + run: mcpp build + + - name: Tests (the API on the Null backend, every macro mapping against the header, header mixing) + run: mcpp test + + - name: Export audit (the generated sources are fresh; every declaration and macro of miniaudio.h on this target) + run: python3 tools/check_exports.py + + - name: The audio file tool written against the module (tone, info, convert of WAV, FLAC and MP3) + run: python3 tools/run_examples.py + + # The Web: wasm32-emscripten (emsdk and node through mcpp), miniaudio's Web + # Audio backend compiled and linked; the tests run under node, which has no + # AudioContext, so the backend's probe reports no device there and every + # device-free test runs as on the other rows. + web: + name: mcpp (wasm32-emscripten, node) + runs-on: ubuntu-24.04 + timeout-minutes: 60 + defaults: + run: + shell: bash + env: + XLINGS_NON_INTERACTIVE: 1 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install Xlings + run: | + curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/refs/heads/main/tools/other/quick_install.sh | bash + echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" + + - name: Install project tools (.xlings.json) + run: | + for attempt in 1 2 3; do + xlings update > /dev/null 2>&1 || true + if xlings install; then break; fi + [ "$attempt" = 3 ] && exit 1 + sleep 30 + done + mcpp --version + + - name: Candidate compat index (only while compat.miniaudio's gnu11 build is unpublished) + run: python3 tools/candidate_index.py --ci + + - name: Build the modules for the Web (the Web Audio backend) + run: mcpp build --target wasm32-emscripten + + - name: Tests under node (Web Audio and Custom enabled, no Null backend; the engine without threads) + run: mcpp test --target wasm32-emscripten + + - name: Export audit on the Web target + run: python3 tools/check_exports.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..f0c6447 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,49 @@ +name: Release +on: + push: + tags: ["mwrap-*"] +permissions: + contents: read +jobs: + publish: + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: write + actions: read + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Check tag, upstream version and bilingual entry pages + run: python3 tools/check_mwrap_release.py --tag "$GITHUB_REF_NAME" + - name: Require successful source CI at this exact commit + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + result=$(gh run list --repo "$GITHUB_REPOSITORY" --workflow ci.yml --commit "$GITHUB_SHA" --limit 1 --json status,conclusion --jq '.[0] | .status == "completed" and .conclusion == "success"') + test "$result" = true || { echo 'No successful source CI at the tag commit'; exit 1; } + - name: Build immutable source asset and publish + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + version="${GITHUB_REF_NAME#mwrap-}" + repo="${GITHUB_REPOSITORY#*/}" + asset="${repo}-${version}.tar.gz" + git archive --format=tar.gz --prefix="${repo}-${version}/" "$GITHUB_SHA" > "$RUNNER_TEMP/$asset" + (cd "$RUNNER_TEMP" && sha256sum "$asset" > "$asset.sha256") + if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then + echo 'Release already exists; refusing to change immutable assets'; exit 1 + fi + extra=() + if [[ "$version" == *-rc* ]]; then extra+=(--prerelease); fi + gh release create "$GITHUB_REF_NAME" "$RUNNER_TEMP/$asset" "$RUNNER_TEMP/$asset.sha256" \ + --repo "$GITHUB_REPOSITORY" --verify-tag --title "$repo $version" \ + --notes "Module wrapper for upstream $version. New mwrap package identities become installable after mcpp-index publication; see the bilingual README for the tested support scope." "${extra[@]}" diff --git a/.github/workflows/templates.yml b/.github/workflows/templates.yml new file mode 100644 index 0000000..3250cbd --- /dev/null +++ b/.github/workflows/templates.yml @@ -0,0 +1,33 @@ +name: Actual project templates +on: + push: + branches: [main] + pull_request: + workflow_dispatch: +permissions: + contents: read +concurrency: + group: templates-${{ github.ref }} + cancel-in-progress: true +env: + MCPP_VERSION: "2026.10.26.1" +jobs: + templates: + runs-on: ubuntu-24.04 + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + - name: Install the pinned mcpp + shell: bash + run: | + archive="mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz" + curl -L -fsS -o "$archive" "https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/$archive" + tar -xzf "$archive" + echo "$PWD/mcpp-${MCPP_VERSION}-linux-x86_64/bin" >> "$GITHUB_PATH" + # The candidate index (tools/candidate_index.py) only while mcpp-index + # does not publish compat.miniaudio's gnu11 build (mcpplibs/mcpp-index#609). + - name: Actual scaffold, strict build and run of the default template + shell: bash + run: | + index=$(python3 tools/candidate_index.py --checkout-only) + python3 tools/test_template.py --toolchain gcc@16.1.0 ${index:+--index "$index"} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5b7db4e --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +target +compile_commands.json +mcpp.lock +.mcpp/ +.xlings/ +doctor.log +__pycache__/ +.cache/ diff --git a/.xlings.json b/.xlings.json new file mode 100644 index 0000000..730a8ff --- /dev/null +++ b/.xlings.json @@ -0,0 +1,5 @@ +{ + "workspace": { + "xim:mcpp": "2026.10.26.1" + } +} diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..60b4c79 --- /dev/null +++ b/NOTICE @@ -0,0 +1,20 @@ +miniaudio-m: C++ module wrapper +Copyright (c) 2026 mcpp-community contributors + +The wrapper contributions are licensed under the Apache License, Version 2.0. +Upstream code, copied interfaces and dependencies retain their original +licenses and copyright notices. miniaudio is available under a choice of the +Unlicense (public domain) or the MIT No Attribution license: + + Copyright 2025 David Reid (MIT No Attribution alternative) + +Its original README and license are retained in upstream/miniaudio/. The +decoders miniaudio.h carries (dr_wav, dr_flac, dr_mp3, as ma_dr_wav … inside +it) are by the same author under the same terms. The library itself is built +by compat.miniaudio from the same release; this wrapper links it, it does not +modify it. + +The test fixtures in tests/data are generated by tools/gen_fixtures.py and are +part of the wrapper contributions. + +Provenance and checksums are recorded in upstream/documents.json. diff --git a/README.md b/README.md index 5395bbd..19c769f 100644 --- a/README.md +++ b/README.md @@ -1 +1,111 @@ -# miniaudio-m +# miniaudio + +> miniaudio, audio playback, capture, decoding and mixing, through C++23 modules. + +**English** · [简体中文](README.zh.md) · [Upstream](https://github.com/mackron/miniaudio) · [Releases](https://github.com/mcpplibs/miniaudio-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) + +[![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) +[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE) +[![miniaudio](https://img.shields.io/badge/miniaudio-MIT--0%20%7C%20Unlicense-blue.svg)](upstream/miniaudio/LICENSE) +[![mcpp-community](https://img.shields.io/badge/mcpp--community-mwrap-blue)](https://github.com/mcpp-community) +[![CI](https://github.com/mcpplibs/miniaudio-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/miniaudio-m/actions/workflows/ci.yml) + +miniaudio plays and captures audio on every platform's native backend +(WASAPI, DirectSound, WinMM, Core Audio, ALSA, PulseAudio, JACK, AAudio, +OpenSL, Web Audio …), decodes WAV, FLAC and MP3, encodes WAV, converts and +resamples, and mixes through a node graph and a high-level engine. It is one C +file under MIT No Attribution or the Unlicense, with no dependencies. The +upstream C API is unchanged: `ma_engine_init`, `ma_device_init`, +`ma_decoder_init_file` and `MA_SUCCESS` are the upstream globals of +``. The library is `compat.miniaudio` 0.11.25. This package maps +miniaudio's value macros to constants, each checked against the header, and +runs on Linux, macOS, Windows and the Web (wasm32-emscripten, the Web Audio +backend). + +## Modules + +- `import mcpplibs.mwrap.miniaudio;`: the whole API of `` (context, device, engine, sound and sound group, node graph, resource manager, decoder, encoder, data sources, waveform and noise, converters, resamplers, filters, effects, ring buffers, logging), its enumerators, and the three inline helpers adapted in `mcpplibs::mwrap::miniaudio`; re-exports the module below +- `import mcpplibs.mwrap.miniaudio.macros;`: `MA_VERSION_STRING`, `MA_MAX_CHANNELS`, `MA_ENGINE_MAX_LISTENERS`, `MA_LISTENER_INDEX_CLOSEST` … in `mcpplibs::mwrap::miniaudio::macros` + +> More Modules API -> [Usage and API](docs/usage.md) + +## Getting started + +```sh +mcpp new tone --template mcpplibs.mwrap.miniaudio@0.11.25 +cd tone +mcpp run +``` + +The default template needs no audio device: it reads a 440 Hz tone from a +waveform data source, encodes it as WAV in memory, decodes it back and +measures it. `mcpp run -- --play` then plays it on the default device. + +```toml +[dependencies] +"mcpplibs.mwrap.miniaudio" = "0.11.25" +``` + +```cpp +import std; +import mcpplibs.mwrap.miniaudio; + +int main(int argc, char** argv) { + ma_engine engine; + if (argc < 2 || ma_engine_init(nullptr, &engine) != MA_SUCCESS) return 1; + ma_engine_play_sound(&engine, argv[1], nullptr); // WAV, FLAC or MP3 + std::println("playing {}; press Enter to quit", argv[1]); + std::cin.get(); + ma_engine_uninit(&engine); +} +``` + +## Macros + +Constants such as `MA_MAX_CHANNELS` keep the type their macro has (`int`), +`MA_LISTENER_INDEX_CLOSEST` is an `ma_uint8`, and the version string is a +`const char[]`. miniaudio's enums are named by their typedefs, so their +enumerators (`MA_SUCCESS`, `ma_format_f32`, `MA_SOUND_FLAG_DECODE` …) are +exported as they are. The compatibility names the header keeps as macros +(`ma_resource_manager_job` …) are aliases of what they name. Stringification, +attributes, `MA_API` and the platform and backend tests (`MA_WIN32`, +`MA_HAS_WASAPI` …) stay macros in ``, included +before the import. Details: [docs/usage.md](docs/usage.md). + +## Platforms + +| Target | Backends (in priority order) | Notes | +|---|---|---| +| Linux | PulseAudio, ALSA, JACK, Null | loaded at run time: no -lasound, -lpulse | +| macOS | Core Audio, Null | frameworks loaded at run time | +| Windows | WASAPI, DirectSound, WinMM, Null | | +| wasm32-emscripten | Web Audio | no Null backend upstream (it needs a thread) | + +The Custom backend is everywhere. On the Web, give the engine a resource +manager with `MA_RESOURCE_MANAGER_FLAG_NO_THREADING` unless the program is +built with threads. + +## Examples + +- [examples/miniaudio](examples/miniaudio): an audio file tool (`info`, `convert` WAV / FLAC / MP3 to WAV at + any rate, channel count and format, `tone`, `play`, `devices`), written against the module; + [tools/run_examples.py](tools/run_examples.py) runs it on every CI row. + +## Build and testing + +Linux (x86_64 GCC and LLVM, arm64 GCC), macOS and Windows CI build the +modules, run the tests (a device on the Null backend, the engine without a +device, WAV encoding and WAV / FLAC / MP3 decoding, converters, filters) and +the export audit ([tools/check_exports.py](tools/check_exports.py)), which +checks on each target, from the compiler's own preprocessing, that every +declaration of the header is exported and every macro mapped or listed. A +Web row builds for wasm32-emscripten and runs the same tests under node. A +separate job scaffolds the default template as an installed package and runs +it. + +## License + +[Apache-2.0](LICENSE) for the wrapper, by mcpp-community ([NOTICE](NOTICE)). +miniaudio is a choice of the Unlicense or MIT No Attribution +([upstream/miniaudio/LICENSE](upstream/miniaudio/LICENSE)); its README and +license are deployed beside every program that depends on this package. diff --git a/README.zh.md b/README.zh.md new file mode 100644 index 0000000..12930be --- /dev/null +++ b/README.zh.md @@ -0,0 +1,101 @@ +# miniaudio + +> 以 C++23 模块使用 miniaudio——音频播放、采集、解码与混音。 + +[English](README.md) · **简体中文** · [Upstream](https://github.com/mackron/miniaudio) · [Releases](https://github.com/mcpplibs/miniaudio-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) + +[![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) +[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE) +[![miniaudio](https://img.shields.io/badge/miniaudio-MIT--0%20%7C%20Unlicense-blue.svg)](upstream/miniaudio/LICENSE) +[![mcpp-community](https://img.shields.io/badge/mcpp--community-mwrap-blue)](https://github.com/mcpp-community) +[![CI](https://github.com/mcpplibs/miniaudio-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/miniaudio-m/actions/workflows/ci.yml) + +miniaudio 在各平台的原生后端上播放和采集音频(WASAPI、DirectSound、WinMM、 +Core Audio、ALSA、PulseAudio、JACK、AAudio、OpenSL、Web Audio 等),解码 +WAV、FLAC 与 MP3,编码 WAV,做格式转换与重采样,并通过节点图和高层引擎混音。 +它是一个 C 文件,以 MIT No Attribution 或 Unlicense 许可(二选一),没有依赖。 +上游 C API 保持不变:`ma_engine_init`、`ma_device_init`、`ma_decoder_init_file` +与 `MA_SUCCESS` 都是 `` 的上游全局名字。库本身是 +`compat.miniaudio` 0.11.25。本包把 miniaudio 的数值宏映射为常量,并逐一与头文件 +对照检查;支持 Linux、macOS、Windows 与 Web(wasm32-emscripten,Web Audio 后端)。 + +## 模块 + +- `import mcpplibs.mwrap.miniaudio;`:`` 的完整 API(context、device、engine、sound 与 sound group、节点图、资源管理器、解码器、编码器、数据源、波形与噪声、转换器、重采样器、滤波器、效果、环形缓冲、日志)及其枚举值,三个内联辅助函数在 `mcpplibs::mwrap::miniaudio` 中适配;并重新导出下面的模块 +- `import mcpplibs.mwrap.miniaudio.macros;`:`MA_VERSION_STRING`、`MA_MAX_CHANNELS`、`MA_ENGINE_MAX_LISTENERS`、`MA_LISTENER_INDEX_CLOSEST` 等,位于 `mcpplibs::mwrap::miniaudio::macros` + +> 更多模块 API -> [用法与 API](docs/usage.md) + +## 快速开始 + +```sh +mcpp new tone --template mcpplibs.mwrap.miniaudio@0.11.25 +cd tone +mcpp run +``` + +默认模板不需要音频设备:它从波形数据源读出 440 Hz 的音调,在内存中编码为 +WAV,再解码回来并测量。`mcpp run -- --play` 会在默认设备上播放它。 + +```toml +[dependencies] +"mcpplibs.mwrap.miniaudio" = "0.11.25" +``` + +```cpp +import std; +import mcpplibs.mwrap.miniaudio; + +int main(int argc, char** argv) { + ma_engine engine; + if (argc < 2 || ma_engine_init(nullptr, &engine) != MA_SUCCESS) return 1; + ma_engine_play_sound(&engine, argv[1], nullptr); // WAV、FLAC 或 MP3 + std::println("playing {}; press Enter to quit", argv[1]); + std::cin.get(); + ma_engine_uninit(&engine); +} +``` + +## 宏 + +`MA_MAX_CHANNELS` 等常量保持其宏的类型(`int`),`MA_LISTENER_INDEX_CLOSEST` +是 `ma_uint8`,版本字符串是 `const char[]`。miniaudio 的枚举由其 typedef 命名, +因此枚举值(`MA_SUCCESS`、`ma_format_f32`、`MA_SOUND_FLAG_DECODE` 等)按原样 +导出。头文件以宏保留的兼容名字(`ma_resource_manager_job` 等)映射为其所指的 +类型别名与函数引用。字符串化、属性、`MA_API` 以及平台与后端测试(`MA_WIN32`、 +`MA_HAS_WASAPI` 等)仍是宏,位于 ``,在 import 之前 +包含。详见 [docs/usage.md](docs/usage.md)。 + +## 平台 + +| 目标 | 后端(按优先级) | 说明 | +|---|---|---| +| Linux | PulseAudio、ALSA、JACK、Null | 运行时加载:无需 -lasound、-lpulse | +| macOS | Core Audio、Null | 运行时加载框架 | +| Windows | WASAPI、DirectSound、WinMM、Null | | +| wasm32-emscripten | Web Audio | 上游在此不构建 Null 后端(它需要线程) | + +Custom 后端在所有平台上都可用。在 Web 上,除非程序启用了线程,否则请给引擎 +一个带 `MA_RESOURCE_MANAGER_FLAG_NO_THREADING` 的资源管理器。 + +## 示例 + +- [examples/miniaudio](examples/miniaudio):基于模块编写的音频文件工具(`info`、把 WAV / FLAC / MP3 + 按任意采样率、声道数和格式 `convert` 为 WAV、`tone`、`play`、`devices`); + [tools/run_examples.py](tools/run_examples.py) 在每个 CI 平台上运行它。 + +## 构建与测试 + +Linux(x86_64 GCC 与 LLVM、arm64 GCC)、macOS 与 Windows 的 CI 构建模块,运行 +测试(Null 后端上的设备、无设备的引擎、WAV 编码与 WAV / FLAC / MP3 解码、转换器、 +滤波器)和导出审计([tools/check_exports.py](tools/check_exports.py)):在每个 +目标上,依据编译器自身的预处理结果,检查头文件的每个声明都已导出、每个宏都已映射 +或列出。Web 行为 wasm32-emscripten 构建,并在 node 下运行同样的测试。另有一个 +任务把默认模板作为已安装的包生成并运行。 + +## 许可 + +包装代码为 [Apache-2.0](LICENSE),作者 mcpp-community([NOTICE](NOTICE))。 +miniaudio 以 Unlicense 或 MIT No Attribution 许可(二选一, +[upstream/miniaudio/LICENSE](upstream/miniaudio/LICENSE));其 README 与许可 +文件随依赖本包的每个程序一起部署。 diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..e77514f --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,76 @@ +# Using mcpplibs.mwrap.miniaudio + +`import mcpplibs.mwrap.miniaudio;` declares miniaudio 0.11.25's API as `` does. Types, struct tags, enumerators and functions are the upstream globals, the very same entities as the header's, so a translation unit may include the header too. The library is `compat.miniaudio` 0.11.25, which compiles upstream's `miniaudio.c` (the header with `MINIAUDIO_IMPLEMENTATION`) once; the module includes the header without it, so it declares and never defines. + +## Modules + +| Module | What it holds | +|---|---| +| `mcpplibs.mwrap.miniaudio` | every type and struct tag of the API section of `` (266: `ma_context`, `ma_device`, `ma_engine`, `ma_sound`, `ma_node_graph`, `ma_resource_manager`, `ma_decoder`, `ma_encoder`, `ma_data_source`, `ma_waveform`, `ma_noise`, `ma_data_converter`, `ma_resampler`, `ma_lpf` …, the configurations `ma_*_config`, the callback types, the atomic wrappers `ma_atomic_uint32` …), the enumerators of its 48 enums (368: `MA_SUCCESS` … `MA_UNAVAILABLE`, `ma_format_*`, `ma_backend_*`, `MA_SOUND_FLAG_*` …), all 931 `MA_API` functions; the 3 adapted inline functions in `mcpplibs::mwrap::miniaudio`; re-exports the module below | +| `mcpplibs.mwrap.miniaudio.macros` | the value macros and compatibility names, in `mcpplibs::mwrap::miniaudio::macros` | + +```cpp +import std; +import mcpplibs.mwrap.miniaudio; +using namespace mcpplibs::mwrap::miniaudio; // ma_get_bytes_per_frame … (the adapted inline functions) +using namespace mcpplibs::mwrap::miniaudio::macros; // MA_MAX_CHANNELS, MA_VERSION_STRING … +``` + +Either directive may be left out when its names are not used; the C API itself needs neither. + +Every declaration is exported under the preprocessor condition the header declares it under, evaluated in the module as in the header: `ma_pthread_t`, `ma_pthread_mutex_t` and `ma_pthread_cond_t` on POSIX targets, `ma_IMMNotificationClient` where WASAPI is supported (Windows). The engine, node graph, resource manager, decoders, encoders, generators and device API are all there, as compat.miniaudio defines none of the `MA_NO_*` switches. `tools/check_exports.py` checks this on every CI row from the compiler's own preprocessing of the header. + +### The API in one paragraph + +The **engine** (`ma_engine_init`, `ma_engine_play_sound`, `ma_sound_init_from_file`, `ma_sound_group_init`) is the high-level API: it owns a device (or none, `noDevice`, and then `ma_engine_read_pcm_frames` mixes into the caller's buffer), a node graph and a resource manager that loads and decodes files. The **low-level API** is a `ma_context` (one backend) and its `ma_device`s, whose `dataCallback` the backend calls with frames to fill or read. Between them are **data sources** (`ma_decoder`, `ma_audio_buffer`, `ma_waveform`, `ma_noise`, `ma_paged_audio_buffer`, the resource manager's), all readable through `ma_data_source_read_pcm_frames`, and the **DSP** (`ma_data_converter`, `ma_resampler`, `ma_channel_converter`, the biquad, low/high/band-pass, shelf, notch and peaking filters, `ma_delay`, `ma_gainer`, `ma_panner`, `ma_spatializer`), each also a node (`ma_lpf_node` …). `ma_encoder` writes WAV. + +## The inline functions + +`ma_get_bytes_per_frame`, `ma_offset_pcm_frames_ptr_f32` and `ma_offset_pcm_frames_const_ptr_f32` are `static MA_INLINE` upstream: internal linkage, not exportable. They are adapted in `mcpplibs::mwrap::miniaudio` under the same names and signatures, each defined in `src/inline.cpp` by calling upstream's. With the header included as well, the header's functions are `::ma_get_bytes_per_frame` …, and a `using namespace mcpplibs::mwrap::miniaudio;` would make an unqualified call ambiguous: qualify one of them (see [tests/header_mix_test.cpp](../tests/header_mix_test.cpp)). + +## Macros + +A named module cannot export a macro. `mcpplibs::mwrap::miniaudio::macros` has them under their original names: + +- **Constants** (27) as `inline constexpr` values of the macro's own type: `MA_VERSION_MAJOR`, `MA_VERSION_MINOR`, `MA_VERSION_REVISION` (`int`), `MA_VERSION_STRING` (`const char[8]`), `MA_TRUE`, `MA_FALSE`, `MA_SIZEOF_PTR`, `MA_SIZE_MAX`, `MA_UINT64_MAX`, `MA_SIMD_ALIGNMENT`, `MA_MIN_CHANNELS`, `MA_MAX_CHANNELS`, `MA_MAX_FILTER_ORDER`, `MA_MAX_LOG_CALLBACKS`, `MA_CHANNEL_INDEX_NULL`, `MA_MAX_DEVICE_NAME_LENGTH`, `MA_BACKEND_COUNT`, `MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE` (`unsigned`), `MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT`, `MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT`, `MA_MAX_NODE_BUS_COUNT`, `MA_MAX_NODE_LOCAL_BUS_COUNT`, `MA_NODE_BUS_COUNT_UNKNOWN`, `MA_ENGINE_MAX_LISTENERS`, `MA_LISTENER_INDEX_CLOSEST` (`ma_uint8`), `MA_SOUND_SOURCE_CHANNEL_COUNT`, `MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING` (the enumerator it names). +- **Compatibility names** the header keeps as macros, since the resource manager's job queue became the general `ma_job` queue: `ma_resource_manager_job`, `ma_resource_manager_job_queue_config` and `ma_resource_manager_job_queue` as aliases of `ma_job`, `ma_job_queue_config` and `ma_job_queue`; `ma_resource_manager_job_init`, `ma_resource_manager_job_queue_config_init`, `ma_resource_manager_job_queue_get_heap_size`, `ma_resource_manager_job_queue_init_preallocated`, `ma_resource_manager_job_queue_init`, `ma_resource_manager_job_queue_uninit`, `ma_resource_manager_job_queue_post` and `ma_resource_manager_job_queue_next` as constexpr references to the functions they name (a call is the same call, the address the same address). + +`MA_SIZE_MAX` is `SIZE_MAX` where the header sees `` and `0xFFFFFFFF` where it does not (upstream's fallback); the module includes `` alone, so on the targets CI runs it is the fallback, as it is for a C file that includes only ``. Prefer `std::numeric_limits::max()` where the full range is meant. + +miniaudio's enums are typedef'd (`typedef enum { … } ma_result;`), so they have linkage and their enumerators are exported as they are: `MA_SUCCESS`, `ma_format_f32`, `MA_CHANNEL_FRONT_LEFT`, `MA_SOUND_FLAG_DECODE` and the rest need no mapping. + +### What stays a macro + +These cannot be a constant or a function without changing what they do. They are macros in ``, which is `` (declarations only); include it before the import: + +| Macros | Why | +|---|---| +| `MA_STRINGIFY`, `MA_XSTRINGIFY` | stringification | +| `MA_API`, `MA_PRIVATE`, `MA_DLL_IMPORT`, `MA_DLL_EXPORT`, `MA_DLL_PRIVATE`, `MA_INLINE`, `MA_NO_INLINE`, `MA_GNUC_INLINE_HINT`, `MA_ATTRIBUTE_FORMAT`, `MA_FALLTHROUGH`, `MA_ATOMIC` | attributes, storage classes and specifiers of declarations and statements | +| `MA_ATOMIC_SAFE_TYPE_DECL`, `MA_ATOMIC_SAFE_TYPE_DECL_PTR` | declare a type by token pasting (the types they declare upstream, `ma_atomic_uint32` …, are exported) | +| `MA_WIN32`, `MA_WIN32_DESKTOP`, `MA_POSIX`, `MA_UNIX`, `MA_LINUX`, `MA_APPLE`, `MA_BSD`, `MA_ANDROID`, `MA_EMSCRIPTEN` … (21) | platform tests for `#ifdef` | +| `MA_SUPPORT_*`, `MA_HAS_*` (30) | backend tests for `#ifdef`; at run time `ma_is_backend_enabled` and `ma_get_enabled_backends` answer the same question | +| `MA_NO_THREADING`, `MA_NO_RUNTIME_LINKING`, `MA_NO_RESOURCE_MANAGER` | configuration switches the header derives (DOS, the Web's runtime linking …) | + +Not mapped: `NULL`, the C library's (the header defines it only where `` did not), and the include guard. While a header macro is defined it expands even inside a qualified name, so `macros::MA_MAX_CHANNELS` is not reachable where the header is included; use the plain `MA_MAX_CHANNELS` there (see [tests/header_mix_test.cpp](../tests/header_mix_test.cpp)). [tools/gen_exports.py](../tools/gen_exports.py) lists every macro with its reason and [tools/check_exports.py](../tools/check_exports.py) accounts for each. + +## Do not define MINIAUDIO_IMPLEMENTATION + +compat.miniaudio has compiled the implementation already. Defining `MINIAUDIO_IMPLEMENTATION` (or `MA_IMPLEMENTATION`) before including the side header, or ``, in a program that links this package gives every miniaudio symbol twice: a link error, not a compile error. The same goes for configuration switches (`MA_NO_DEVICE_IO`, `MA_ENABLE_ONLY_SPECIFIC_BACKENDS` …): they are compat.miniaudio's build, and the structures the module exports have the layout that build gives them. + +## Platforms and backends + +| Target | Enabled backends | | +|---|---|---| +| Linux (glibc) | PulseAudio, ALSA, JACK, Custom, Null | the libraries are loaded with `dlopen` at run time: a machine without them builds and runs, and falls back to the next backend | +| macOS | Core Audio, Custom, Null | CoreFoundation, CoreAudio and AudioToolbox are loaded at run time; no framework is linked | +| Windows | WASAPI, DirectSound, WinMM, Custom, Null | `ole32`, `user32`, `advapi32` are loaded at run time | +| wasm32-emscripten | Web Audio, Custom | the Null backend needs a background thread and is not built on Emscripten upstream | + +### The Web + +The Web Audio backend is JavaScript in the program (`EM_ASM`); it needs an `AudioContext`, which a page has and node does not (there `ma_context_init` returns `MA_NO_BACKEND`). Without `-pthread`, a program has no threads: initialise the engine with a resource manager of your own whose `flags` include `MA_RESOURCE_MANAGER_FLAG_NO_THREADING` and whose `jobThreadCount` is 0 (as [tests/api_test.cpp](../tests/api_test.cpp) `EngineWithoutADevice` does). Browsers start an `AudioContext` only after a user gesture. AudioWorklets (`MA_ENABLE_AUDIO_WORKLETS`, `-sAUDIO_WORKLET=1 -sWASM_WORKERS=1 -sASYNCIFY`) are a configuration of compat.miniaudio's build, not of this module; the default is the ScriptProcessorNode path. + +### Decoders + +miniaudio carries dr_wav, dr_flac and dr_mp3 inside `miniaudio.h`, renamed `ma_dr_wav_*`, `ma_dr_flac_*`, `ma_dr_mp3_*`: a program may also link the separate dr_libs (`drwav_*`, `drflac_*`, `drmp3_*`) without a clash. Other formats (Vorbis, Opus) plug in as custom decoders (`ma_decoding_backend_vtable`). diff --git a/examples/miniaudio/mcpp.toml b/examples/miniaudio/mcpp.toml new file mode 100644 index 0000000..2e155bf --- /dev/null +++ b/examples/miniaudio/mcpp.toml @@ -0,0 +1,12 @@ +[package] +name = "miniaudio" +version = "0.1.0" +description = "An audio file tool written against import mcpplibs.mwrap.miniaudio: file information (format, length, peak, RMS), conversion of WAV / FLAC / MP3 to WAV at any rate, channel count and sample format, tone generation, playback and device listing; tools/run_examples.py runs it on every CI row" +license = "Apache-2.0" + +[targets.miniaudio] +kind = "bin" +main = "src/main.cpp" + +[dependencies] +"mcpplibs.mwrap.miniaudio" = { path = "../.." } diff --git a/examples/miniaudio/src/main.cpp b/examples/miniaudio/src/main.cpp new file mode 100644 index 0000000..53a5f4c --- /dev/null +++ b/examples/miniaudio/src/main.cpp @@ -0,0 +1,189 @@ +// miniaudio — an audio file tool, through import mcpplibs.mwrap.miniaudio: +// +// miniaudio info ... channels, rate, length, peak, RMS and decoded format +// miniaudio convert [--rate N] [--channels N] [--format u8|s16|s24|s32|f32] +// decode WAV / FLAC / MP3, convert, encode WAV +// miniaudio tone [--freq HZ] [--seconds S] [--rate N] [--wave sine|square|triangle|sawtooth] +// miniaudio play [--seconds S] on the default playback device +// miniaudio devices the playback and capture devices of the default backend +// +// Everything but `play` and `devices` works without an audio device. +import std; +import mcpplibs.mwrap.miniaudio; + +namespace { + +int fail(std::string_view what, ma_result r) { + std::println(std::cerr, "miniaudio: {}: {}", what, ma_result_description(r)); + return 1; +} + +std::optional option(std::span args, std::string_view name) { + for (std::size_t i = 0; i + 1 < args.size(); ++i) + if (args[i] == name) return std::string(args[i + 1]); + return std::nullopt; +} + +std::optional format_named(std::string_view s) { + for (auto [n, f] : {std::pair{"u8", ma_format_u8}, {"s16", ma_format_s16}, {"s24", ma_format_s24}, + {"s32", ma_format_s32}, {"f32", ma_format_f32}}) + if (s == n) return f; + return std::nullopt; +} + +int info(std::span files) { + int status = 0; + for (const char* path : files) { + // Decoded in the file's own format, channels and rate (0: as the file + // has them), each block measured as f32. + const ma_decoder_config config = ma_decoder_config_init(ma_format_unknown, 0, 0); + ma_decoder decoder; + if (const ma_result r = ma_decoder_init_file(path, &config, &decoder); r != MA_SUCCESS) { + status = fail(path, r); + continue; + } + const ma_format native = decoder.outputFormat; + const ma_uint32 channels = decoder.outputChannels, rate = decoder.outputSampleRate; + std::vector block(4096 * ma_get_bytes_per_sample(native) * channels); + std::vector f32(4096 * channels); + ma_uint64 frames = 0, read = 0; + double sum = 0, peak = 0; + while (ma_decoder_read_pcm_frames(&decoder, block.data(), 4096, &read) == MA_SUCCESS && read > 0) { + ma_pcm_convert(f32.data(), ma_format_f32, block.data(), native, read * channels, ma_dither_mode_none); + for (std::size_t i = 0; i < read * channels; ++i) { + sum += double(f32[i]) * f32[i]; + peak = std::max(peak, double(std::abs(f32[i]))); + } + frames += read; + } + const double rms = frames ? std::sqrt(sum / double(frames * channels)) : 0; + std::println("{}: {} ch, {} Hz, {} frames ({:.3f} s), peak {:.4f}, rms {:.4f}, decoded as {}", path, channels, + rate, frames, rate ? double(frames) / rate : 0.0, peak, rms, ma_get_format_name(native)); + ma_decoder_uninit(&decoder); + } + return status; +} + +int convert(std::span args) { + if (args.size() < 2) return fail("convert ", MA_INVALID_ARGS); + ma_format format = ma_format_s16; + if (auto f = option(args, "--format")) { + if (!format_named(*f)) return fail("--format", MA_INVALID_ARGS); + format = *format_named(*f); + } + const ma_uint32 channels = option(args, "--channels") ? std::stoul(*option(args, "--channels")) : 0; + const ma_uint32 rate = option(args, "--rate") ? std::stoul(*option(args, "--rate")) : 0; + // The decoder converts: 0 keeps the file's channels and rate. + const ma_decoder_config dconfig = ma_decoder_config_init(format, channels, rate); + ma_decoder decoder; + if (const ma_result r = ma_decoder_init_file(args[0], &dconfig, &decoder); r != MA_SUCCESS) return fail(args[0], r); + const ma_encoder_config econfig = ma_encoder_config_init(ma_encoding_format_wav, decoder.outputFormat, + decoder.outputChannels, decoder.outputSampleRate); + ma_encoder encoder; + if (const ma_result r = ma_encoder_init_file(args[1], &econfig, &encoder); r != MA_SUCCESS) { + ma_decoder_uninit(&decoder); + return fail(args[1], r); + } + std::vector block(4096 * ma_get_bytes_per_sample(decoder.outputFormat) * decoder.outputChannels); + ma_uint64 read = 0, total = 0; + while (ma_decoder_read_pcm_frames(&decoder, block.data(), 4096, &read) == MA_SUCCESS && read > 0) { + ma_encoder_write_pcm_frames(&encoder, block.data(), read, nullptr); + total += read; + } + std::println("{} -> {}: {} {} ch {} Hz, {} frames", args[0], args[1], ma_get_format_name(decoder.outputFormat), + decoder.outputChannels, decoder.outputSampleRate, total); + ma_encoder_uninit(&encoder); + ma_decoder_uninit(&decoder); + return 0; +} + +int tone(std::span args) { + if (args.empty()) return fail("tone ", MA_INVALID_ARGS); + const double freq = option(args, "--freq") ? std::stod(*option(args, "--freq")) : 440.0; + const double seconds = option(args, "--seconds") ? std::stod(*option(args, "--seconds")) : 1.0; + const ma_uint32 rate = option(args, "--rate") ? std::stoul(*option(args, "--rate")) : 48000; + ma_waveform_type type = ma_waveform_type_sine; + if (auto w = option(args, "--wave")) { + if (*w == "square") type = ma_waveform_type_square; + else if (*w == "triangle") type = ma_waveform_type_triangle; + else if (*w == "sawtooth") type = ma_waveform_type_sawtooth; + else if (*w != "sine") return fail("--wave", MA_INVALID_ARGS); + } + const ma_waveform_config wconfig = ma_waveform_config_init(ma_format_s16, 1, rate, type, 0.5, freq); + ma_waveform wave; + ma_waveform_init(&wconfig, &wave); + const ma_encoder_config econfig = ma_encoder_config_init(ma_encoding_format_wav, ma_format_s16, 1, rate); + ma_encoder encoder; + if (const ma_result r = ma_encoder_init_file(args[0], &econfig, &encoder); r != MA_SUCCESS) return fail(args[0], r); + const auto frames = static_cast(seconds * rate); + std::vector block(4096); + for (ma_uint64 done = 0; done < frames;) { + const ma_uint64 n = std::min(block.size(), frames - done); + ma_waveform_read_pcm_frames(&wave, block.data(), n, nullptr); + ma_encoder_write_pcm_frames(&encoder, block.data(), n, nullptr); + done += n; + } + ma_encoder_uninit(&encoder); + ma_waveform_uninit(&wave); + std::println("{}: {} Hz {}, {} frames at {} Hz", args[0], freq, option(args, "--wave").value_or("sine"), frames, rate); + return 0; +} + +int play(std::span args) { + if (args.empty()) return fail("play ", MA_INVALID_ARGS); + ma_engine engine; + if (const ma_result r = ma_engine_init(nullptr, &engine); r != MA_SUCCESS) return fail("no playback device", r); + ma_sound sound; + if (const ma_result r = ma_sound_init_from_file(&engine, args[0], MA_SOUND_FLAG_DECODE, nullptr, nullptr, &sound); + r != MA_SUCCESS) { + ma_engine_uninit(&engine); + return fail(args[0], r); + } + float length = 0; + ma_sound_get_length_in_seconds(&sound, &length); + const double limit = option(args, "--seconds") ? std::stod(*option(args, "--seconds")) : length; + std::println("playing {} ({:.2f} s) on {}", args[0], length, ma_engine_get_device(&engine)->playback.name); + ma_sound_start(&sound); + const auto start = std::chrono::steady_clock::now(); + while (!ma_sound_at_end(&sound) && std::chrono::duration(std::chrono::steady_clock::now() - start).count() < limit) + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + ma_sound_uninit(&sound); + ma_engine_uninit(&engine); + return 0; +} + +int devices() { + ma_context context; + if (const ma_result r = ma_context_init(nullptr, 0, nullptr, &context); r != MA_SUCCESS) return fail("context", r); + ma_device_info *playback = nullptr, *capture = nullptr; + ma_uint32 playbackCount = 0, captureCount = 0; + if (const ma_result r = ma_context_get_devices(&context, &playback, &playbackCount, &capture, &captureCount); r != MA_SUCCESS) { + ma_context_uninit(&context); + return fail("devices", r); + } + std::println("backend {}", ma_get_backend_name(context.backend)); + for (ma_uint32 i = 0; i < playbackCount; ++i) + std::println("playback {}{}", playback[i].name, playback[i].isDefault ? " (default)" : ""); + for (ma_uint32 i = 0; i < captureCount; ++i) + std::println("capture {}{}", capture[i].name, capture[i].isDefault ? " (default)" : ""); + ma_context_uninit(&context); + return 0; +} + +} // namespace + +int main(int argc, char** argv) { + const std::span args(argv + std::min(argc, 1), argv + argc); + const std::string_view command = args.empty() ? "" : args[0]; + const auto rest = args.empty() ? args : args.subspan(1); + if (command == "info" && !rest.empty()) return info(rest); + if (command == "convert") return convert(rest); + if (command == "tone") return tone(rest); + if (command == "play") return play(rest); + if (command == "devices") return devices(); + std::println(std::cerr, "usage: miniaudio info ... | convert [--rate N] [--channels N] " + "[--format u8|s16|s24|s32|f32] | tone [--freq HZ] [--seconds S] [--rate N] " + "[--wave sine|square|triangle|sawtooth] | play [--seconds S] | devices"); + std::println(std::cerr, "miniaudio {}", ma_version_string()); + return 2; +} diff --git a/include/mwrap/miniaudio/macros.hpp b/include/mwrap/miniaudio/macros.hpp new file mode 100644 index 0000000..5f6ecfc --- /dev/null +++ b/include/mwrap/miniaudio/macros.hpp @@ -0,0 +1,17 @@ +// — miniaudio's macros as macros, for the ones a +// C++ entity cannot be: stringification (MA_STRINGIFY), the attributes and +// storage classes of declarations (MA_API, MA_INLINE, MA_ATTRIBUTE_FORMAT …), +// the token-pasting type declarations (MA_ATOMIC_SAFE_TYPE_DECL), and the +// platform and backend tests of conditional compilation (MA_WIN32, MA_POSIX, +// MA_APPLE, MA_EMSCRIPTEN, MA_SUPPORT_*, MA_HAS_* …). +// +// Include it before `import mcpplibs.mwrap.miniaudio;`: it is +// as the module sees it — the declarations only. Do not define +// MINIAUDIO_IMPLEMENTATION: compat.miniaudio already compiles the +// implementation, and a second copy duplicates every symbol at link time. +// Every other macro is defined too, and while a macro is defined it expands +// even inside `mcpplibs::mwrap::miniaudio::macros::NAME`. The header's +// enumerators (MA_SUCCESS, ma_format_f32 …) are the module's own, the same +// entities. +#pragma once +#include diff --git a/mcpp.toml b/mcpp.toml new file mode 100644 index 0000000..02d6033 --- /dev/null +++ b/mcpp.toml @@ -0,0 +1,43 @@ +# Module wrapper; upstream API preserved. Policy: mcpp-index/docs/mwrap.md. +[package] +namespace = "mcpplibs.mwrap" +name = "miniaudio" +version = "0.11.25" +description = "miniaudio 0.11.25 C++ modules for mcpp (import mcpplibs.mwrap.miniaudio;): audio playback and capture on every platform's native backend and Web Audio, decoding (WAV, FLAC, MP3), WAV encoding, conversion, resampling, the node graph and the high-level engine of miniaudio.h over compat.miniaudio, its macros as constants" +license = "Apache-2.0" +authors = ["mcpp-community"] +repo = "https://github.com/mcpplibs/miniaudio-m" +platforms = ["linux", "macos", "windows", "emscripten"] + +[targets.miniaudio] +kind = "lib" + +[build] +sources = ["src/*.cppm", "src/*.cpp"] +# : the macros a C++ entity cannot be. +include_dirs = ["include"] + +[dependencies] +compat.miniaudio = "0.11.25" + +[dev-dependencies] +compat.gtest = "1.15.2" + +[package.metadata.mwrap] +upstream-version = "0.11.25" + +[[runtime.deploy]] +from = "LICENSE" +to = "licenses/miniaudio" + +[[runtime.deploy]] +from = "NOTICE" +to = "licenses/miniaudio" + +[[runtime.deploy]] +from = "upstream/miniaudio/README.md" +to = "licenses/miniaudio/upstream/miniaudio" + +[[runtime.deploy]] +from = "upstream/miniaudio/LICENSE" +to = "licenses/miniaudio/upstream/miniaudio" diff --git a/src/inline.cpp b/src/inline.cpp new file mode 100644 index 0000000..a589cf9 --- /dev/null +++ b/src/inline.cpp @@ -0,0 +1,13 @@ +// Generated by tools/gen_exports.py from miniaudio 0.11.25's miniaudio.h — do not +// edit by hand. +// +// The adaptations of the `static MA_INLINE` functions of miniaudio.h: each +// calls upstream's own, which has internal linkage in this translation unit. +module; +#include + +module mcpplibs.mwrap.miniaudio; + +ma_uint32 mcpplibs::mwrap::miniaudio::ma_get_bytes_per_frame(ma_format format, ma_uint32 channels) { return ::ma_get_bytes_per_frame(format, channels); } +float* mcpplibs::mwrap::miniaudio::ma_offset_pcm_frames_ptr_f32(float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return ::ma_offset_pcm_frames_ptr_f32(p, offsetInFrames, channels); } +const float* mcpplibs::mwrap::miniaudio::ma_offset_pcm_frames_const_ptr_f32(const float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return ::ma_offset_pcm_frames_const_ptr_f32(p, offsetInFrames, channels); } diff --git a/src/macros.cppm b/src/macros.cppm new file mode 100644 index 0000000..d1ec2d1 --- /dev/null +++ b/src/macros.cppm @@ -0,0 +1,423 @@ +// Generated by tools/gen_exports.py from miniaudio 0.11.25's miniaudio.h — do not +// edit by hand. +// +// mcpplibs.mwrap.miniaudio.macros — the macros of miniaudio.h a named module +// cannot export as they are, under their original names in +// mcpplibs::mwrap::miniaudio::macros: +// +// - 27 value macros as `inline constexpr`, each of the type its macro +// expands to (MA_MAX_CHANNELS is an `int`, as 254 is; MA_SIZE_MAX a +// `size_t`; MA_LISTENER_INDEX_CLOSEST an `ma_uint8`; MA_BACKEND_COUNT an +// `int`), the version string as a reference to a constexpr char array. +// Each is defined where the header defines it (#ifdef); +// - the compatibility names the header keeps as macros: 3 types as +// aliases of the types they name (ma_resource_manager_job is ma_job) and +// 8 functions as constexpr references to the functions they name +// (ma_resource_manager_job_queue_init is ma_job_queue_init). +// +// 69 macros stay macros — stringification, attributes and storage +// classes, the token-pasting type declarations, the platform and backend +// tests (MA_WIN32, MA_POSIX, MA_SUPPORT_*, MA_HAS_*) — in +// , included before the import; NULL is the C +// library's. tools/check_exports.py accounts for every one. +module; +#include + +export module mcpplibs.mwrap.miniaudio.macros; + +// The header's values and names, taken while its macros are defined (module linkage). +namespace mwrap_miniaudio_capture { +#ifdef MA_VERSION_MAJOR +inline constexpr auto value_MA_VERSION_MAJOR = MA_VERSION_MAJOR; +#endif +#ifdef MA_VERSION_MINOR +inline constexpr auto value_MA_VERSION_MINOR = MA_VERSION_MINOR; +#endif +#ifdef MA_VERSION_REVISION +inline constexpr auto value_MA_VERSION_REVISION = MA_VERSION_REVISION; +#endif +#ifdef MA_VERSION_STRING +inline constexpr char value_MA_VERSION_STRING[] = MA_VERSION_STRING; +#endif +#ifdef MA_SIZEOF_PTR +inline constexpr auto value_MA_SIZEOF_PTR = MA_SIZEOF_PTR; +#endif +#ifdef MA_TRUE +inline constexpr auto value_MA_TRUE = MA_TRUE; +#endif +#ifdef MA_FALSE +inline constexpr auto value_MA_FALSE = MA_FALSE; +#endif +#ifdef MA_SIZE_MAX +inline constexpr auto value_MA_SIZE_MAX = MA_SIZE_MAX; +#endif +#ifdef MA_UINT64_MAX +inline constexpr auto value_MA_UINT64_MAX = MA_UINT64_MAX; +#endif +#ifdef MA_SIMD_ALIGNMENT +inline constexpr auto value_MA_SIMD_ALIGNMENT = MA_SIMD_ALIGNMENT; +#endif +#ifdef MA_MIN_CHANNELS +inline constexpr auto value_MA_MIN_CHANNELS = MA_MIN_CHANNELS; +#endif +#ifdef MA_MAX_CHANNELS +inline constexpr auto value_MA_MAX_CHANNELS = MA_MAX_CHANNELS; +#endif +#ifdef MA_MAX_FILTER_ORDER +inline constexpr auto value_MA_MAX_FILTER_ORDER = MA_MAX_FILTER_ORDER; +#endif +#ifdef MA_MAX_LOG_CALLBACKS +inline constexpr auto value_MA_MAX_LOG_CALLBACKS = MA_MAX_LOG_CALLBACKS; +#endif +#ifdef MA_CHANNEL_INDEX_NULL +inline constexpr auto value_MA_CHANNEL_INDEX_NULL = MA_CHANNEL_INDEX_NULL; +#endif +#ifdef MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT +inline constexpr auto value_MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT = MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT; +#endif +#ifdef MA_BACKEND_COUNT +inline constexpr auto value_MA_BACKEND_COUNT = MA_BACKEND_COUNT; +#endif +#ifdef MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE +inline constexpr auto value_MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE = MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE; +#endif +#ifdef MA_MAX_DEVICE_NAME_LENGTH +inline constexpr auto value_MA_MAX_DEVICE_NAME_LENGTH = MA_MAX_DEVICE_NAME_LENGTH; +#endif +#ifdef MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING +inline constexpr auto value_MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING = MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING; +#endif +#ifdef MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT +inline constexpr auto value_MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT = MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT; +#endif +#ifdef MA_MAX_NODE_BUS_COUNT +inline constexpr auto value_MA_MAX_NODE_BUS_COUNT = MA_MAX_NODE_BUS_COUNT; +#endif +#ifdef MA_MAX_NODE_LOCAL_BUS_COUNT +inline constexpr auto value_MA_MAX_NODE_LOCAL_BUS_COUNT = MA_MAX_NODE_LOCAL_BUS_COUNT; +#endif +#ifdef MA_NODE_BUS_COUNT_UNKNOWN +inline constexpr auto value_MA_NODE_BUS_COUNT_UNKNOWN = MA_NODE_BUS_COUNT_UNKNOWN; +#endif +#ifdef MA_ENGINE_MAX_LISTENERS +inline constexpr auto value_MA_ENGINE_MAX_LISTENERS = MA_ENGINE_MAX_LISTENERS; +#endif +#ifdef MA_LISTENER_INDEX_CLOSEST +inline constexpr auto value_MA_LISTENER_INDEX_CLOSEST = MA_LISTENER_INDEX_CLOSEST; +#endif +#ifdef MA_SOUND_SOURCE_CHANNEL_COUNT +inline constexpr auto value_MA_SOUND_SOURCE_CHANNEL_COUNT = MA_SOUND_SOURCE_CHANNEL_COUNT; +#endif +#ifdef ma_resource_manager_job +using type_ma_resource_manager_job = ma_resource_manager_job; +#endif +#ifdef ma_resource_manager_job_queue_config +using type_ma_resource_manager_job_queue_config = ma_resource_manager_job_queue_config; +#endif +#ifdef ma_resource_manager_job_queue +using type_ma_resource_manager_job_queue = ma_resource_manager_job_queue; +#endif +#ifdef ma_resource_manager_job_init +inline constexpr auto& value_ma_resource_manager_job_init = ma_resource_manager_job_init; +#endif +#ifdef ma_resource_manager_job_queue_config_init +inline constexpr auto& value_ma_resource_manager_job_queue_config_init = ma_resource_manager_job_queue_config_init; +#endif +#ifdef ma_resource_manager_job_queue_get_heap_size +inline constexpr auto& value_ma_resource_manager_job_queue_get_heap_size = ma_resource_manager_job_queue_get_heap_size; +#endif +#ifdef ma_resource_manager_job_queue_init_preallocated +inline constexpr auto& value_ma_resource_manager_job_queue_init_preallocated = ma_resource_manager_job_queue_init_preallocated; +#endif +#ifdef ma_resource_manager_job_queue_init +inline constexpr auto& value_ma_resource_manager_job_queue_init = ma_resource_manager_job_queue_init; +#endif +#ifdef ma_resource_manager_job_queue_uninit +inline constexpr auto& value_ma_resource_manager_job_queue_uninit = ma_resource_manager_job_queue_uninit; +#endif +#ifdef ma_resource_manager_job_queue_post +inline constexpr auto& value_ma_resource_manager_job_queue_post = ma_resource_manager_job_queue_post; +#endif +#ifdef ma_resource_manager_job_queue_next +inline constexpr auto& value_ma_resource_manager_job_queue_next = ma_resource_manager_job_queue_next; +#endif +} // namespace mwrap_miniaudio_capture + +// The names, now free: each macro is undefined in this unit only. +#ifdef MA_VERSION_MAJOR +#undef MA_VERSION_MAJOR +#define MWRAP_HAS_MA_VERSION_MAJOR 1 +#endif +#ifdef MA_VERSION_MINOR +#undef MA_VERSION_MINOR +#define MWRAP_HAS_MA_VERSION_MINOR 1 +#endif +#ifdef MA_VERSION_REVISION +#undef MA_VERSION_REVISION +#define MWRAP_HAS_MA_VERSION_REVISION 1 +#endif +#ifdef MA_VERSION_STRING +#undef MA_VERSION_STRING +#define MWRAP_HAS_MA_VERSION_STRING 1 +#endif +#ifdef MA_SIZEOF_PTR +#undef MA_SIZEOF_PTR +#define MWRAP_HAS_MA_SIZEOF_PTR 1 +#endif +#ifdef MA_TRUE +#undef MA_TRUE +#define MWRAP_HAS_MA_TRUE 1 +#endif +#ifdef MA_FALSE +#undef MA_FALSE +#define MWRAP_HAS_MA_FALSE 1 +#endif +#ifdef MA_SIZE_MAX +#undef MA_SIZE_MAX +#define MWRAP_HAS_MA_SIZE_MAX 1 +#endif +#ifdef MA_UINT64_MAX +#undef MA_UINT64_MAX +#define MWRAP_HAS_MA_UINT64_MAX 1 +#endif +#ifdef MA_SIMD_ALIGNMENT +#undef MA_SIMD_ALIGNMENT +#define MWRAP_HAS_MA_SIMD_ALIGNMENT 1 +#endif +#ifdef MA_MIN_CHANNELS +#undef MA_MIN_CHANNELS +#define MWRAP_HAS_MA_MIN_CHANNELS 1 +#endif +#ifdef MA_MAX_CHANNELS +#undef MA_MAX_CHANNELS +#define MWRAP_HAS_MA_MAX_CHANNELS 1 +#endif +#ifdef MA_MAX_FILTER_ORDER +#undef MA_MAX_FILTER_ORDER +#define MWRAP_HAS_MA_MAX_FILTER_ORDER 1 +#endif +#ifdef MA_MAX_LOG_CALLBACKS +#undef MA_MAX_LOG_CALLBACKS +#define MWRAP_HAS_MA_MAX_LOG_CALLBACKS 1 +#endif +#ifdef MA_CHANNEL_INDEX_NULL +#undef MA_CHANNEL_INDEX_NULL +#define MWRAP_HAS_MA_CHANNEL_INDEX_NULL 1 +#endif +#ifdef MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT +#undef MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT +#define MWRAP_HAS_MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT 1 +#endif +#ifdef MA_BACKEND_COUNT +#undef MA_BACKEND_COUNT +#define MWRAP_HAS_MA_BACKEND_COUNT 1 +#endif +#ifdef MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE +#undef MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE +#define MWRAP_HAS_MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE 1 +#endif +#ifdef MA_MAX_DEVICE_NAME_LENGTH +#undef MA_MAX_DEVICE_NAME_LENGTH +#define MWRAP_HAS_MA_MAX_DEVICE_NAME_LENGTH 1 +#endif +#ifdef MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING +#undef MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING +#define MWRAP_HAS_MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING 1 +#endif +#ifdef MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT +#undef MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT +#define MWRAP_HAS_MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT 1 +#endif +#ifdef MA_MAX_NODE_BUS_COUNT +#undef MA_MAX_NODE_BUS_COUNT +#define MWRAP_HAS_MA_MAX_NODE_BUS_COUNT 1 +#endif +#ifdef MA_MAX_NODE_LOCAL_BUS_COUNT +#undef MA_MAX_NODE_LOCAL_BUS_COUNT +#define MWRAP_HAS_MA_MAX_NODE_LOCAL_BUS_COUNT 1 +#endif +#ifdef MA_NODE_BUS_COUNT_UNKNOWN +#undef MA_NODE_BUS_COUNT_UNKNOWN +#define MWRAP_HAS_MA_NODE_BUS_COUNT_UNKNOWN 1 +#endif +#ifdef MA_ENGINE_MAX_LISTENERS +#undef MA_ENGINE_MAX_LISTENERS +#define MWRAP_HAS_MA_ENGINE_MAX_LISTENERS 1 +#endif +#ifdef MA_LISTENER_INDEX_CLOSEST +#undef MA_LISTENER_INDEX_CLOSEST +#define MWRAP_HAS_MA_LISTENER_INDEX_CLOSEST 1 +#endif +#ifdef MA_SOUND_SOURCE_CHANNEL_COUNT +#undef MA_SOUND_SOURCE_CHANNEL_COUNT +#define MWRAP_HAS_MA_SOUND_SOURCE_CHANNEL_COUNT 1 +#endif +#ifdef ma_resource_manager_job +#undef ma_resource_manager_job +#define MWRAP_HAS_ma_resource_manager_job 1 +#endif +#ifdef ma_resource_manager_job_queue_config +#undef ma_resource_manager_job_queue_config +#define MWRAP_HAS_ma_resource_manager_job_queue_config 1 +#endif +#ifdef ma_resource_manager_job_queue +#undef ma_resource_manager_job_queue +#define MWRAP_HAS_ma_resource_manager_job_queue 1 +#endif +#ifdef ma_resource_manager_job_init +#undef ma_resource_manager_job_init +#define MWRAP_HAS_ma_resource_manager_job_init 1 +#endif +#ifdef ma_resource_manager_job_queue_config_init +#undef ma_resource_manager_job_queue_config_init +#define MWRAP_HAS_ma_resource_manager_job_queue_config_init 1 +#endif +#ifdef ma_resource_manager_job_queue_get_heap_size +#undef ma_resource_manager_job_queue_get_heap_size +#define MWRAP_HAS_ma_resource_manager_job_queue_get_heap_size 1 +#endif +#ifdef ma_resource_manager_job_queue_init_preallocated +#undef ma_resource_manager_job_queue_init_preallocated +#define MWRAP_HAS_ma_resource_manager_job_queue_init_preallocated 1 +#endif +#ifdef ma_resource_manager_job_queue_init +#undef ma_resource_manager_job_queue_init +#define MWRAP_HAS_ma_resource_manager_job_queue_init 1 +#endif +#ifdef ma_resource_manager_job_queue_uninit +#undef ma_resource_manager_job_queue_uninit +#define MWRAP_HAS_ma_resource_manager_job_queue_uninit 1 +#endif +#ifdef ma_resource_manager_job_queue_post +#undef ma_resource_manager_job_queue_post +#define MWRAP_HAS_ma_resource_manager_job_queue_post 1 +#endif +#ifdef ma_resource_manager_job_queue_next +#undef ma_resource_manager_job_queue_next +#define MWRAP_HAS_ma_resource_manager_job_queue_next 1 +#endif + +export namespace mcpplibs::mwrap::miniaudio::macros { +namespace c = ::mwrap_miniaudio_capture; + +// value macros (27) +#ifdef MWRAP_HAS_MA_VERSION_MAJOR +inline constexpr auto MA_VERSION_MAJOR = c::value_MA_VERSION_MAJOR; +#endif +#ifdef MWRAP_HAS_MA_VERSION_MINOR +inline constexpr auto MA_VERSION_MINOR = c::value_MA_VERSION_MINOR; +#endif +#ifdef MWRAP_HAS_MA_VERSION_REVISION +inline constexpr auto MA_VERSION_REVISION = c::value_MA_VERSION_REVISION; +#endif +#ifdef MWRAP_HAS_MA_VERSION_STRING +inline constexpr auto& MA_VERSION_STRING = c::value_MA_VERSION_STRING; +#endif +#ifdef MWRAP_HAS_MA_SIZEOF_PTR +inline constexpr auto MA_SIZEOF_PTR = c::value_MA_SIZEOF_PTR; +#endif +#ifdef MWRAP_HAS_MA_TRUE +inline constexpr auto MA_TRUE = c::value_MA_TRUE; +#endif +#ifdef MWRAP_HAS_MA_FALSE +inline constexpr auto MA_FALSE = c::value_MA_FALSE; +#endif +#ifdef MWRAP_HAS_MA_SIZE_MAX +inline constexpr auto MA_SIZE_MAX = c::value_MA_SIZE_MAX; +#endif +#ifdef MWRAP_HAS_MA_UINT64_MAX +inline constexpr auto MA_UINT64_MAX = c::value_MA_UINT64_MAX; +#endif +#ifdef MWRAP_HAS_MA_SIMD_ALIGNMENT +inline constexpr auto MA_SIMD_ALIGNMENT = c::value_MA_SIMD_ALIGNMENT; +#endif +#ifdef MWRAP_HAS_MA_MIN_CHANNELS +inline constexpr auto MA_MIN_CHANNELS = c::value_MA_MIN_CHANNELS; +#endif +#ifdef MWRAP_HAS_MA_MAX_CHANNELS +inline constexpr auto MA_MAX_CHANNELS = c::value_MA_MAX_CHANNELS; +#endif +#ifdef MWRAP_HAS_MA_MAX_FILTER_ORDER +inline constexpr auto MA_MAX_FILTER_ORDER = c::value_MA_MAX_FILTER_ORDER; +#endif +#ifdef MWRAP_HAS_MA_MAX_LOG_CALLBACKS +inline constexpr auto MA_MAX_LOG_CALLBACKS = c::value_MA_MAX_LOG_CALLBACKS; +#endif +#ifdef MWRAP_HAS_MA_CHANNEL_INDEX_NULL +inline constexpr auto MA_CHANNEL_INDEX_NULL = c::value_MA_CHANNEL_INDEX_NULL; +#endif +#ifdef MWRAP_HAS_MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT +inline constexpr auto MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT = c::value_MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT; +#endif +#ifdef MWRAP_HAS_MA_BACKEND_COUNT +inline constexpr auto MA_BACKEND_COUNT = c::value_MA_BACKEND_COUNT; +#endif +#ifdef MWRAP_HAS_MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE +inline constexpr auto MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE = c::value_MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE; +#endif +#ifdef MWRAP_HAS_MA_MAX_DEVICE_NAME_LENGTH +inline constexpr auto MA_MAX_DEVICE_NAME_LENGTH = c::value_MA_MAX_DEVICE_NAME_LENGTH; +#endif +#ifdef MWRAP_HAS_MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING +inline constexpr auto MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING = c::value_MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING; +#endif +#ifdef MWRAP_HAS_MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT +inline constexpr auto MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT = c::value_MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT; +#endif +#ifdef MWRAP_HAS_MA_MAX_NODE_BUS_COUNT +inline constexpr auto MA_MAX_NODE_BUS_COUNT = c::value_MA_MAX_NODE_BUS_COUNT; +#endif +#ifdef MWRAP_HAS_MA_MAX_NODE_LOCAL_BUS_COUNT +inline constexpr auto MA_MAX_NODE_LOCAL_BUS_COUNT = c::value_MA_MAX_NODE_LOCAL_BUS_COUNT; +#endif +#ifdef MWRAP_HAS_MA_NODE_BUS_COUNT_UNKNOWN +inline constexpr auto MA_NODE_BUS_COUNT_UNKNOWN = c::value_MA_NODE_BUS_COUNT_UNKNOWN; +#endif +#ifdef MWRAP_HAS_MA_ENGINE_MAX_LISTENERS +inline constexpr auto MA_ENGINE_MAX_LISTENERS = c::value_MA_ENGINE_MAX_LISTENERS; +#endif +#ifdef MWRAP_HAS_MA_LISTENER_INDEX_CLOSEST +inline constexpr auto MA_LISTENER_INDEX_CLOSEST = c::value_MA_LISTENER_INDEX_CLOSEST; +#endif +#ifdef MWRAP_HAS_MA_SOUND_SOURCE_CHANNEL_COUNT +inline constexpr auto MA_SOUND_SOURCE_CHANNEL_COUNT = c::value_MA_SOUND_SOURCE_CHANNEL_COUNT; +#endif + +// compatibility type names (3) +#ifdef MWRAP_HAS_ma_resource_manager_job +using ma_resource_manager_job = c::type_ma_resource_manager_job; +#endif +#ifdef MWRAP_HAS_ma_resource_manager_job_queue_config +using ma_resource_manager_job_queue_config = c::type_ma_resource_manager_job_queue_config; +#endif +#ifdef MWRAP_HAS_ma_resource_manager_job_queue +using ma_resource_manager_job_queue = c::type_ma_resource_manager_job_queue; +#endif + +// compatibility function names (8) +#ifdef MWRAP_HAS_ma_resource_manager_job_init +inline constexpr auto& ma_resource_manager_job_init = c::value_ma_resource_manager_job_init; +#endif +#ifdef MWRAP_HAS_ma_resource_manager_job_queue_config_init +inline constexpr auto& ma_resource_manager_job_queue_config_init = c::value_ma_resource_manager_job_queue_config_init; +#endif +#ifdef MWRAP_HAS_ma_resource_manager_job_queue_get_heap_size +inline constexpr auto& ma_resource_manager_job_queue_get_heap_size = c::value_ma_resource_manager_job_queue_get_heap_size; +#endif +#ifdef MWRAP_HAS_ma_resource_manager_job_queue_init_preallocated +inline constexpr auto& ma_resource_manager_job_queue_init_preallocated = c::value_ma_resource_manager_job_queue_init_preallocated; +#endif +#ifdef MWRAP_HAS_ma_resource_manager_job_queue_init +inline constexpr auto& ma_resource_manager_job_queue_init = c::value_ma_resource_manager_job_queue_init; +#endif +#ifdef MWRAP_HAS_ma_resource_manager_job_queue_uninit +inline constexpr auto& ma_resource_manager_job_queue_uninit = c::value_ma_resource_manager_job_queue_uninit; +#endif +#ifdef MWRAP_HAS_ma_resource_manager_job_queue_post +inline constexpr auto& ma_resource_manager_job_queue_post = c::value_ma_resource_manager_job_queue_post; +#endif +#ifdef MWRAP_HAS_ma_resource_manager_job_queue_next +inline constexpr auto& ma_resource_manager_job_queue_next = c::value_ma_resource_manager_job_queue_next; +#endif + +} // namespace mcpplibs::mwrap::miniaudio::macros diff --git a/src/miniaudio.cppm b/src/miniaudio.cppm new file mode 100644 index 0000000..3a314f3 --- /dev/null +++ b/src/miniaudio.cppm @@ -0,0 +1,1664 @@ +// Generated by tools/gen_exports.py from miniaudio 0.11.25's miniaudio.h — do not +// edit by hand. +// +// mcpplibs.mwrap.miniaudio — miniaudio, audio playback, capture, decoding, +// encoding, conversion, mixing and the high-level engine in one library, as a +// C++ module. Every exported name is the upstream global of , +// unchanged: the types and struct tags, the enumerators of its enums, and +// every MA_API function (context, device, engine, sound, node graph, resource +// manager, decoder, encoder, data sources, converters, resamplers, filters, +// effects, ring buffers, logging, allocation). Each is exported under the +// condition the header declares it under: the POSIX thread types on POSIX, +// ma_IMMNotificationClient on Windows. The three `static MA_INLINE` functions +// are adapted in mcpplibs::mwrap::miniaudio (src/inline.cpp). The root also +// re-exports the macro mappings. The library is compat.miniaudio, built from +// the same release; the module includes only the declarations (no +// MINIAUDIO_IMPLEMENTATION). +module; +#include + +export module mcpplibs.mwrap.miniaudio; + +export import mcpplibs.mwrap.miniaudio.macros; + +// types and struct tags (265) +export using ::ma_int8; +export using ::ma_uint8; +export using ::ma_int16; +export using ::ma_uint16; +export using ::ma_int32; +export using ::ma_uint32; +export using ::ma_int64; +export using ::ma_uint64; +export using ::ma_uintptr; +export using ::ma_bool8; +export using ::ma_bool32; +export using ::ma_float; +export using ::ma_double; +export using ::ma_handle; +export using ::ma_ptr; +export using ::ma_proc; +#if (!defined(MA_WIN32) && !defined(MA_DOS)) && (!defined(MA_NO_THREADING)) +export using ::ma_pthread_t; +export using ::ma_pthread_mutex_t; +export using ::ma_pthread_cond_t; +#endif +export using ::ma_wchar_win32; +export using ::ma_log_level; +export using ::ma_context; +export using ::ma_device; +export using ::ma_channel; +export using ::_ma_channel_position; +export using ::ma_result; +export using ::ma_stream_format; +export using ::ma_stream_layout; +export using ::ma_dither_mode; +export using ::ma_format; +export using ::ma_standard_sample_rate; +export using ::ma_channel_mix_mode; +export using ::ma_standard_channel_map; +export using ::ma_performance_profile; +export using ::ma_allocation_callbacks; +export using ::ma_lcg; +export using ::ma_atomic_uint32; +export using ::ma_atomic_int32; +export using ::ma_atomic_uint64; +export using ::ma_atomic_float; +export using ::ma_atomic_bool32; +export using ::ma_spinlock; +#if !defined(MA_NO_THREADING) +export using ::ma_thread_priority; +#endif +#if ((!defined(MA_NO_THREADING)) && (defined(MA_POSIX))) || ((!defined(MA_NO_THREADING)) && (!(defined(MA_POSIX)) && (defined(MA_WIN32)))) +export using ::ma_thread; +export using ::ma_mutex; +export using ::ma_event; +export using ::ma_semaphore; +#endif +export using ::ma_log_callback_proc; +export using ::ma_log_callback; +export using ::ma_log; +export using ::ma_biquad_coefficient; +export using ::ma_biquad_config; +export using ::ma_biquad; +export using ::ma_lpf1_config; +export using ::ma_lpf2_config; +export using ::ma_lpf1; +export using ::ma_lpf2; +export using ::ma_lpf_config; +export using ::ma_lpf; +export using ::ma_hpf1_config; +export using ::ma_hpf2_config; +export using ::ma_hpf1; +export using ::ma_hpf2; +export using ::ma_hpf_config; +export using ::ma_hpf; +export using ::ma_bpf2_config; +export using ::ma_bpf2; +export using ::ma_bpf_config; +export using ::ma_bpf; +export using ::ma_notch2_config; +export using ::ma_notch_config; +export using ::ma_notch2; +export using ::ma_peak2_config; +export using ::ma_peak_config; +export using ::ma_peak2; +export using ::ma_loshelf2_config; +export using ::ma_loshelf_config; +export using ::ma_loshelf2; +export using ::ma_hishelf2_config; +export using ::ma_hishelf_config; +export using ::ma_hishelf2; +export using ::ma_delay_config; +export using ::ma_delay; +export using ::ma_gainer_config; +export using ::ma_gainer; +export using ::ma_pan_mode; +export using ::ma_panner_config; +export using ::ma_panner; +export using ::ma_fader_config; +export using ::ma_fader; +export using ::ma_vec3f; +export using ::ma_atomic_vec3f; +export using ::ma_attenuation_model; +export using ::ma_positioning; +export using ::ma_handedness; +export using ::ma_spatializer_listener_config; +export using ::ma_spatializer_listener; +export using ::ma_spatializer_config; +export using ::ma_spatializer; +export using ::ma_linear_resampler_config; +export using ::ma_linear_resampler; +export using ::ma_resampler_config; +export using ::ma_resampling_backend; +export using ::ma_resampling_backend_vtable; +export using ::ma_resample_algorithm; +export using ::ma_resampler; +export using ::ma_channel_conversion_path; +export using ::ma_mono_expansion_mode; +export using ::ma_channel_converter_config; +export using ::ma_channel_converter; +export using ::ma_data_converter_config; +export using ::ma_data_converter_execution_path; +export using ::ma_data_converter; +export using ::ma_data_source; +export using ::ma_data_source_vtable; +export using ::ma_data_source_get_next_proc; +export using ::ma_data_source_config; +export using ::ma_data_source_base; +export using ::ma_audio_buffer_ref; +export using ::ma_audio_buffer_config; +export using ::ma_audio_buffer; +export using ::ma_paged_audio_buffer_page; +export using ::ma_paged_audio_buffer_data; +export using ::ma_paged_audio_buffer_config; +export using ::ma_paged_audio_buffer; +export using ::ma_rb; +export using ::ma_pcm_rb; +export using ::ma_duplex_rb; +export using ::ma_fence; +export using ::ma_async_notification; +export using ::ma_async_notification_callbacks; +export using ::ma_async_notification_poll; +export using ::ma_async_notification_event; +export using ::ma_slot_allocator_config; +export using ::ma_slot_allocator_group; +export using ::ma_slot_allocator; +export using ::ma_job; +export using ::ma_job_proc; +export using ::ma_job_type; +export using ::ma_job_queue_flags; +export using ::ma_job_queue_config; +export using ::ma_job_queue; +#if !defined(MA_NO_DEVICE_IO) +export using ::ma_device_state; +export using ::ma_atomic_device_state; +#endif +#if (!defined(MA_NO_DEVICE_IO)) && (defined(MA_SUPPORT_WASAPI)) +export using ::ma_IMMNotificationClient; +#endif +#if !defined(MA_NO_DEVICE_IO) +export using ::ma_backend; +export using ::ma_device_job_thread_config; +export using ::ma_device_job_thread; +export using ::ma_device_notification_type; +export using ::ma_device_notification; +export using ::ma_device_notification_proc; +export using ::ma_device_data_proc; +export using ::ma_stop_proc; +export using ::ma_device_type; +export using ::ma_share_mode; +export using ::ma_ios_session_category; +export using ::ma_ios_session_category_option; +export using ::ma_opensl_stream_type; +export using ::ma_opensl_recording_preset; +export using ::ma_wasapi_usage; +export using ::ma_aaudio_usage; +export using ::ma_aaudio_content_type; +export using ::ma_aaudio_input_preset; +export using ::ma_aaudio_allowed_capture_policy; +export using ::ma_timer; +export using ::ma_device_id; +export using ::ma_context_config; +export using ::ma_device_config; +export using ::ma_backend_callbacks; +export using ::ma_device_info; +export using ::ma_enum_devices_callback_proc; +export using ::ma_device_descriptor; +export using ::ma_context_command__wasapi; +#endif +export using ::ma_vfs; +export using ::ma_vfs_file; +export using ::ma_open_mode_flags; +export using ::ma_seek_origin; +export using ::ma_file_info; +export using ::ma_vfs_callbacks; +export using ::ma_default_vfs; +export using ::ma_read_proc; +export using ::ma_seek_proc; +export using ::ma_tell_proc; +#if !defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING) +export using ::ma_encoding_format; +#endif +#if !defined(MA_NO_DECODING) +export using ::ma_decoder; +export using ::ma_decoding_backend_config; +export using ::ma_decoding_backend_vtable; +export using ::ma_decoder_read_proc; +export using ::ma_decoder_seek_proc; +export using ::ma_decoder_tell_proc; +export using ::ma_decoder_config; +#endif +#if !defined(MA_NO_ENCODING) +export using ::ma_encoder; +export using ::ma_encoder_write_proc; +export using ::ma_encoder_seek_proc; +export using ::ma_encoder_init_proc; +export using ::ma_encoder_uninit_proc; +export using ::ma_encoder_write_pcm_frames_proc; +export using ::ma_encoder_config; +#endif +#if !defined(MA_NO_GENERATION) +export using ::ma_waveform_type; +export using ::ma_waveform_config; +export using ::ma_waveform; +export using ::ma_pulsewave_config; +export using ::ma_pulsewave; +export using ::ma_noise_type; +export using ::ma_noise_config; +export using ::ma_noise; +#endif +#if !defined(MA_NO_RESOURCE_MANAGER) +export using ::ma_resource_manager; +export using ::ma_resource_manager_data_buffer_node; +export using ::ma_resource_manager_data_buffer; +export using ::ma_resource_manager_data_stream; +export using ::ma_resource_manager_data_source; +export using ::ma_resource_manager_data_source_flags; +export using ::ma_resource_manager_pipeline_stage_notification; +export using ::ma_resource_manager_pipeline_notifications; +export using ::ma_resource_manager_flags; +export using ::ma_resource_manager_data_source_config; +export using ::ma_resource_manager_data_supply_type; +export using ::ma_resource_manager_data_supply; +export using ::ma_resource_manager_config; +#endif +#if !defined(MA_NO_NODE_GRAPH) +export using ::ma_stack; +export using ::ma_node_graph; +export using ::ma_node; +export using ::ma_node_flags; +export using ::ma_node_state; +export using ::ma_node_vtable; +export using ::ma_node_config; +export using ::ma_node_output_bus; +export using ::ma_node_input_bus; +export using ::ma_node_base; +export using ::ma_node_graph_config; +export using ::ma_data_source_node_config; +export using ::ma_data_source_node; +export using ::ma_splitter_node_config; +export using ::ma_splitter_node; +export using ::ma_biquad_node_config; +export using ::ma_biquad_node; +export using ::ma_lpf_node_config; +export using ::ma_lpf_node; +export using ::ma_hpf_node_config; +export using ::ma_hpf_node; +export using ::ma_bpf_node_config; +export using ::ma_bpf_node; +export using ::ma_notch_node_config; +export using ::ma_notch_node; +export using ::ma_peak_node_config; +export using ::ma_peak_node; +export using ::ma_loshelf_node_config; +export using ::ma_loshelf_node; +export using ::ma_hishelf_node_config; +export using ::ma_hishelf_node; +export using ::ma_delay_node_config; +export using ::ma_delay_node; +#endif +#if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH) +export using ::ma_engine; +export using ::ma_sound; +export using ::ma_sound_flags; +export using ::ma_engine_node_type; +export using ::ma_engine_node_config; +export using ::ma_engine_node; +export using ::ma_sound_end_proc; +export using ::ma_sound_config; +export using ::ma_sound_inlined; +export using ::ma_sound_group_config; +export using ::ma_sound_group; +export using ::ma_engine_process_proc; +export using ::ma_engine_config; +#endif + +// enumerators (368) +export using ::MA_LOG_LEVEL_DEBUG; +export using ::MA_LOG_LEVEL_INFO; +export using ::MA_LOG_LEVEL_WARNING; +export using ::MA_LOG_LEVEL_ERROR; +export using ::MA_CHANNEL_NONE; +export using ::MA_CHANNEL_MONO; +export using ::MA_CHANNEL_FRONT_LEFT; +export using ::MA_CHANNEL_FRONT_RIGHT; +export using ::MA_CHANNEL_FRONT_CENTER; +export using ::MA_CHANNEL_LFE; +export using ::MA_CHANNEL_BACK_LEFT; +export using ::MA_CHANNEL_BACK_RIGHT; +export using ::MA_CHANNEL_FRONT_LEFT_CENTER; +export using ::MA_CHANNEL_FRONT_RIGHT_CENTER; +export using ::MA_CHANNEL_BACK_CENTER; +export using ::MA_CHANNEL_SIDE_LEFT; +export using ::MA_CHANNEL_SIDE_RIGHT; +export using ::MA_CHANNEL_TOP_CENTER; +export using ::MA_CHANNEL_TOP_FRONT_LEFT; +export using ::MA_CHANNEL_TOP_FRONT_CENTER; +export using ::MA_CHANNEL_TOP_FRONT_RIGHT; +export using ::MA_CHANNEL_TOP_BACK_LEFT; +export using ::MA_CHANNEL_TOP_BACK_CENTER; +export using ::MA_CHANNEL_TOP_BACK_RIGHT; +export using ::MA_CHANNEL_AUX_0; +export using ::MA_CHANNEL_AUX_1; +export using ::MA_CHANNEL_AUX_2; +export using ::MA_CHANNEL_AUX_3; +export using ::MA_CHANNEL_AUX_4; +export using ::MA_CHANNEL_AUX_5; +export using ::MA_CHANNEL_AUX_6; +export using ::MA_CHANNEL_AUX_7; +export using ::MA_CHANNEL_AUX_8; +export using ::MA_CHANNEL_AUX_9; +export using ::MA_CHANNEL_AUX_10; +export using ::MA_CHANNEL_AUX_11; +export using ::MA_CHANNEL_AUX_12; +export using ::MA_CHANNEL_AUX_13; +export using ::MA_CHANNEL_AUX_14; +export using ::MA_CHANNEL_AUX_15; +export using ::MA_CHANNEL_AUX_16; +export using ::MA_CHANNEL_AUX_17; +export using ::MA_CHANNEL_AUX_18; +export using ::MA_CHANNEL_AUX_19; +export using ::MA_CHANNEL_AUX_20; +export using ::MA_CHANNEL_AUX_21; +export using ::MA_CHANNEL_AUX_22; +export using ::MA_CHANNEL_AUX_23; +export using ::MA_CHANNEL_AUX_24; +export using ::MA_CHANNEL_AUX_25; +export using ::MA_CHANNEL_AUX_26; +export using ::MA_CHANNEL_AUX_27; +export using ::MA_CHANNEL_AUX_28; +export using ::MA_CHANNEL_AUX_29; +export using ::MA_CHANNEL_AUX_30; +export using ::MA_CHANNEL_AUX_31; +export using ::MA_CHANNEL_POSITION_COUNT; +export using ::MA_CHANNEL_LEFT; +export using ::MA_CHANNEL_RIGHT; +export using ::MA_SUCCESS; +export using ::MA_ERROR; +export using ::MA_INVALID_ARGS; +export using ::MA_INVALID_OPERATION; +export using ::MA_OUT_OF_MEMORY; +export using ::MA_OUT_OF_RANGE; +export using ::MA_ACCESS_DENIED; +export using ::MA_DOES_NOT_EXIST; +export using ::MA_ALREADY_EXISTS; +export using ::MA_TOO_MANY_OPEN_FILES; +export using ::MA_INVALID_FILE; +export using ::MA_TOO_BIG; +export using ::MA_PATH_TOO_LONG; +export using ::MA_NAME_TOO_LONG; +export using ::MA_NOT_DIRECTORY; +export using ::MA_IS_DIRECTORY; +export using ::MA_DIRECTORY_NOT_EMPTY; +export using ::MA_AT_END; +export using ::MA_NO_SPACE; +export using ::MA_BUSY; +export using ::MA_IO_ERROR; +export using ::MA_INTERRUPT; +export using ::MA_UNAVAILABLE; +export using ::MA_ALREADY_IN_USE; +export using ::MA_BAD_ADDRESS; +export using ::MA_BAD_SEEK; +export using ::MA_BAD_PIPE; +export using ::MA_DEADLOCK; +export using ::MA_TOO_MANY_LINKS; +export using ::MA_NOT_IMPLEMENTED; +export using ::MA_NO_MESSAGE; +export using ::MA_BAD_MESSAGE; +export using ::MA_NO_DATA_AVAILABLE; +export using ::MA_INVALID_DATA; +export using ::MA_TIMEOUT; +export using ::MA_NO_NETWORK; +export using ::MA_NOT_UNIQUE; +export using ::MA_NOT_SOCKET; +export using ::MA_NO_ADDRESS; +export using ::MA_BAD_PROTOCOL; +export using ::MA_PROTOCOL_UNAVAILABLE; +export using ::MA_PROTOCOL_NOT_SUPPORTED; +export using ::MA_PROTOCOL_FAMILY_NOT_SUPPORTED; +export using ::MA_ADDRESS_FAMILY_NOT_SUPPORTED; +export using ::MA_SOCKET_NOT_SUPPORTED; +export using ::MA_CONNECTION_RESET; +export using ::MA_ALREADY_CONNECTED; +export using ::MA_NOT_CONNECTED; +export using ::MA_CONNECTION_REFUSED; +export using ::MA_NO_HOST; +export using ::MA_IN_PROGRESS; +export using ::MA_CANCELLED; +export using ::MA_MEMORY_ALREADY_MAPPED; +export using ::MA_CRC_MISMATCH; +export using ::MA_FORMAT_NOT_SUPPORTED; +export using ::MA_DEVICE_TYPE_NOT_SUPPORTED; +export using ::MA_SHARE_MODE_NOT_SUPPORTED; +export using ::MA_NO_BACKEND; +export using ::MA_NO_DEVICE; +export using ::MA_API_NOT_FOUND; +export using ::MA_INVALID_DEVICE_CONFIG; +export using ::MA_LOOP; +export using ::MA_BACKEND_NOT_ENABLED; +export using ::MA_DEVICE_NOT_INITIALIZED; +export using ::MA_DEVICE_ALREADY_INITIALIZED; +export using ::MA_DEVICE_NOT_STARTED; +export using ::MA_DEVICE_NOT_STOPPED; +export using ::MA_FAILED_TO_INIT_BACKEND; +export using ::MA_FAILED_TO_OPEN_BACKEND_DEVICE; +export using ::MA_FAILED_TO_START_BACKEND_DEVICE; +export using ::MA_FAILED_TO_STOP_BACKEND_DEVICE; +export using ::ma_stream_format_pcm; +export using ::ma_stream_layout_interleaved; +export using ::ma_stream_layout_deinterleaved; +export using ::ma_dither_mode_none; +export using ::ma_dither_mode_rectangle; +export using ::ma_dither_mode_triangle; +export using ::ma_format_unknown; +export using ::ma_format_u8; +export using ::ma_format_s16; +export using ::ma_format_s24; +export using ::ma_format_s32; +export using ::ma_format_f32; +export using ::ma_format_count; +export using ::ma_standard_sample_rate_48000; +export using ::ma_standard_sample_rate_44100; +export using ::ma_standard_sample_rate_32000; +export using ::ma_standard_sample_rate_24000; +export using ::ma_standard_sample_rate_22050; +export using ::ma_standard_sample_rate_88200; +export using ::ma_standard_sample_rate_96000; +export using ::ma_standard_sample_rate_176400; +export using ::ma_standard_sample_rate_192000; +export using ::ma_standard_sample_rate_16000; +export using ::ma_standard_sample_rate_11025; +export using ::ma_standard_sample_rate_8000; +export using ::ma_standard_sample_rate_352800; +export using ::ma_standard_sample_rate_384000; +export using ::ma_standard_sample_rate_min; +export using ::ma_standard_sample_rate_max; +export using ::ma_standard_sample_rate_count; +export using ::ma_channel_mix_mode_rectangular; +export using ::ma_channel_mix_mode_simple; +export using ::ma_channel_mix_mode_custom_weights; +export using ::ma_channel_mix_mode_default; +export using ::ma_standard_channel_map_microsoft; +export using ::ma_standard_channel_map_alsa; +export using ::ma_standard_channel_map_rfc3551; +export using ::ma_standard_channel_map_flac; +export using ::ma_standard_channel_map_vorbis; +export using ::ma_standard_channel_map_sound4; +export using ::ma_standard_channel_map_sndio; +export using ::ma_standard_channel_map_webaudio; +export using ::ma_standard_channel_map_default; +export using ::ma_performance_profile_low_latency; +export using ::ma_performance_profile_conservative; +#if !defined(MA_NO_THREADING) +export using ::ma_thread_priority_idle; +export using ::ma_thread_priority_lowest; +export using ::ma_thread_priority_low; +export using ::ma_thread_priority_normal; +export using ::ma_thread_priority_high; +export using ::ma_thread_priority_highest; +export using ::ma_thread_priority_realtime; +export using ::ma_thread_priority_default; +#endif +export using ::ma_pan_mode_balance; +export using ::ma_pan_mode_pan; +export using ::ma_attenuation_model_none; +export using ::ma_attenuation_model_inverse; +export using ::ma_attenuation_model_linear; +export using ::ma_attenuation_model_exponential; +export using ::ma_positioning_absolute; +export using ::ma_positioning_relative; +export using ::ma_handedness_right; +export using ::ma_handedness_left; +export using ::ma_resample_algorithm_linear; +export using ::ma_resample_algorithm_custom; +export using ::ma_channel_conversion_path_unknown; +export using ::ma_channel_conversion_path_passthrough; +export using ::ma_channel_conversion_path_mono_out; +export using ::ma_channel_conversion_path_mono_in; +export using ::ma_channel_conversion_path_shuffle; +export using ::ma_channel_conversion_path_weights; +export using ::ma_mono_expansion_mode_duplicate; +export using ::ma_mono_expansion_mode_average; +export using ::ma_mono_expansion_mode_stereo_only; +export using ::ma_mono_expansion_mode_default; +export using ::ma_data_converter_execution_path_passthrough; +export using ::ma_data_converter_execution_path_format_only; +export using ::ma_data_converter_execution_path_channels_only; +export using ::ma_data_converter_execution_path_resample_only; +export using ::ma_data_converter_execution_path_resample_first; +export using ::ma_data_converter_execution_path_channels_first; +export using ::MA_JOB_TYPE_QUIT; +export using ::MA_JOB_TYPE_CUSTOM; +export using ::MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE; +export using ::MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE; +export using ::MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE; +export using ::MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER; +export using ::MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER; +export using ::MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM; +export using ::MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM; +export using ::MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_STREAM; +export using ::MA_JOB_TYPE_RESOURCE_MANAGER_SEEK_DATA_STREAM; +export using ::MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE; +export using ::MA_JOB_TYPE_COUNT; +export using ::MA_JOB_QUEUE_FLAG_NON_BLOCKING; +#if !defined(MA_NO_DEVICE_IO) +export using ::ma_device_state_uninitialized; +export using ::ma_device_state_stopped; +export using ::ma_device_state_started; +export using ::ma_device_state_starting; +export using ::ma_device_state_stopping; +export using ::ma_backend_wasapi; +export using ::ma_backend_dsound; +export using ::ma_backend_winmm; +export using ::ma_backend_coreaudio; +export using ::ma_backend_sndio; +export using ::ma_backend_audio4; +export using ::ma_backend_oss; +export using ::ma_backend_pulseaudio; +export using ::ma_backend_alsa; +export using ::ma_backend_jack; +export using ::ma_backend_aaudio; +export using ::ma_backend_opensl; +export using ::ma_backend_webaudio; +export using ::ma_backend_custom; +export using ::ma_backend_null; +export using ::ma_device_notification_type_started; +export using ::ma_device_notification_type_stopped; +export using ::ma_device_notification_type_rerouted; +export using ::ma_device_notification_type_interruption_began; +export using ::ma_device_notification_type_interruption_ended; +export using ::ma_device_notification_type_unlocked; +export using ::ma_device_type_playback; +export using ::ma_device_type_capture; +export using ::ma_device_type_duplex; +export using ::ma_device_type_loopback; +export using ::ma_share_mode_shared; +export using ::ma_share_mode_exclusive; +export using ::ma_ios_session_category_default; +export using ::ma_ios_session_category_none; +export using ::ma_ios_session_category_ambient; +export using ::ma_ios_session_category_solo_ambient; +export using ::ma_ios_session_category_playback; +export using ::ma_ios_session_category_record; +export using ::ma_ios_session_category_play_and_record; +export using ::ma_ios_session_category_multi_route; +export using ::ma_ios_session_category_option_mix_with_others; +export using ::ma_ios_session_category_option_duck_others; +export using ::ma_ios_session_category_option_allow_bluetooth; +export using ::ma_ios_session_category_option_default_to_speaker; +export using ::ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others; +export using ::ma_ios_session_category_option_allow_bluetooth_a2dp; +export using ::ma_ios_session_category_option_allow_air_play; +export using ::ma_opensl_stream_type_default; +export using ::ma_opensl_stream_type_voice; +export using ::ma_opensl_stream_type_system; +export using ::ma_opensl_stream_type_ring; +export using ::ma_opensl_stream_type_media; +export using ::ma_opensl_stream_type_alarm; +export using ::ma_opensl_stream_type_notification; +export using ::ma_opensl_recording_preset_default; +export using ::ma_opensl_recording_preset_generic; +export using ::ma_opensl_recording_preset_camcorder; +export using ::ma_opensl_recording_preset_voice_recognition; +export using ::ma_opensl_recording_preset_voice_communication; +export using ::ma_opensl_recording_preset_voice_unprocessed; +export using ::ma_wasapi_usage_default; +export using ::ma_wasapi_usage_games; +export using ::ma_wasapi_usage_pro_audio; +export using ::ma_aaudio_usage_default; +export using ::ma_aaudio_usage_media; +export using ::ma_aaudio_usage_voice_communication; +export using ::ma_aaudio_usage_voice_communication_signalling; +export using ::ma_aaudio_usage_alarm; +export using ::ma_aaudio_usage_notification; +export using ::ma_aaudio_usage_notification_ringtone; +export using ::ma_aaudio_usage_notification_event; +export using ::ma_aaudio_usage_assistance_accessibility; +export using ::ma_aaudio_usage_assistance_navigation_guidance; +export using ::ma_aaudio_usage_assistance_sonification; +export using ::ma_aaudio_usage_game; +export using ::ma_aaudio_usage_assitant; +export using ::ma_aaudio_usage_emergency; +export using ::ma_aaudio_usage_safety; +export using ::ma_aaudio_usage_vehicle_status; +export using ::ma_aaudio_usage_announcement; +export using ::ma_aaudio_content_type_default; +export using ::ma_aaudio_content_type_speech; +export using ::ma_aaudio_content_type_music; +export using ::ma_aaudio_content_type_movie; +export using ::ma_aaudio_content_type_sonification; +export using ::ma_aaudio_input_preset_default; +export using ::ma_aaudio_input_preset_generic; +export using ::ma_aaudio_input_preset_camcorder; +export using ::ma_aaudio_input_preset_voice_recognition; +export using ::ma_aaudio_input_preset_voice_communication; +export using ::ma_aaudio_input_preset_unprocessed; +export using ::ma_aaudio_input_preset_voice_performance; +export using ::ma_aaudio_allow_capture_default; +export using ::ma_aaudio_allow_capture_by_all; +export using ::ma_aaudio_allow_capture_by_system; +export using ::ma_aaudio_allow_capture_by_none; +#endif +export using ::MA_OPEN_MODE_READ; +export using ::MA_OPEN_MODE_WRITE; +export using ::ma_seek_origin_start; +export using ::ma_seek_origin_current; +export using ::ma_seek_origin_end; +#if !defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING) +export using ::ma_encoding_format_unknown; +export using ::ma_encoding_format_wav; +export using ::ma_encoding_format_flac; +export using ::ma_encoding_format_mp3; +export using ::ma_encoding_format_vorbis; +#endif +#if !defined(MA_NO_GENERATION) +export using ::ma_waveform_type_sine; +export using ::ma_waveform_type_square; +export using ::ma_waveform_type_triangle; +export using ::ma_waveform_type_sawtooth; +export using ::ma_noise_type_white; +export using ::ma_noise_type_pink; +export using ::ma_noise_type_brownian; +#endif +#if !defined(MA_NO_RESOURCE_MANAGER) +export using ::MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM; +export using ::MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE; +export using ::MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC; +export using ::MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT; +export using ::MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH; +export using ::MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING; +export using ::MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING; +export using ::MA_RESOURCE_MANAGER_FLAG_NO_THREADING; +export using ::ma_resource_manager_data_supply_type_unknown; +export using ::ma_resource_manager_data_supply_type_encoded; +export using ::ma_resource_manager_data_supply_type_decoded; +export using ::ma_resource_manager_data_supply_type_decoded_paged; +#endif +#if !defined(MA_NO_NODE_GRAPH) +export using ::MA_NODE_FLAG_PASSTHROUGH; +export using ::MA_NODE_FLAG_CONTINUOUS_PROCESSING; +export using ::MA_NODE_FLAG_ALLOW_NULL_INPUT; +export using ::MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES; +export using ::MA_NODE_FLAG_SILENT_OUTPUT; +export using ::ma_node_state_started; +export using ::ma_node_state_stopped; +#endif +#if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH) +export using ::MA_SOUND_FLAG_STREAM; +export using ::MA_SOUND_FLAG_DECODE; +export using ::MA_SOUND_FLAG_ASYNC; +export using ::MA_SOUND_FLAG_WAIT_INIT; +export using ::MA_SOUND_FLAG_UNKNOWN_LENGTH; +export using ::MA_SOUND_FLAG_LOOPING; +export using ::MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT; +export using ::MA_SOUND_FLAG_NO_PITCH; +export using ::MA_SOUND_FLAG_NO_SPATIALIZATION; +export using ::ma_engine_node_type_sound; +export using ::ma_engine_node_type_group; +#endif + +// MA_API functions (931) +export using ::ma_version; +export using ::ma_version_string; +export using ::ma_log_callback_init; +export using ::ma_log_init; +export using ::ma_log_uninit; +export using ::ma_log_register_callback; +export using ::ma_log_unregister_callback; +export using ::ma_log_post; +export using ::ma_log_postv; +export using ::ma_log_postf; +export using ::ma_biquad_config_init; +export using ::ma_biquad_get_heap_size; +export using ::ma_biquad_init_preallocated; +export using ::ma_biquad_init; +export using ::ma_biquad_uninit; +export using ::ma_biquad_reinit; +export using ::ma_biquad_clear_cache; +export using ::ma_biquad_process_pcm_frames; +export using ::ma_biquad_get_latency; +export using ::ma_lpf1_config_init; +export using ::ma_lpf2_config_init; +export using ::ma_lpf1_get_heap_size; +export using ::ma_lpf1_init_preallocated; +export using ::ma_lpf1_init; +export using ::ma_lpf1_uninit; +export using ::ma_lpf1_reinit; +export using ::ma_lpf1_clear_cache; +export using ::ma_lpf1_process_pcm_frames; +export using ::ma_lpf1_get_latency; +export using ::ma_lpf2_get_heap_size; +export using ::ma_lpf2_init_preallocated; +export using ::ma_lpf2_init; +export using ::ma_lpf2_uninit; +export using ::ma_lpf2_reinit; +export using ::ma_lpf2_clear_cache; +export using ::ma_lpf2_process_pcm_frames; +export using ::ma_lpf2_get_latency; +export using ::ma_lpf_config_init; +export using ::ma_lpf_get_heap_size; +export using ::ma_lpf_init_preallocated; +export using ::ma_lpf_init; +export using ::ma_lpf_uninit; +export using ::ma_lpf_reinit; +export using ::ma_lpf_clear_cache; +export using ::ma_lpf_process_pcm_frames; +export using ::ma_lpf_get_latency; +export using ::ma_hpf1_config_init; +export using ::ma_hpf2_config_init; +export using ::ma_hpf1_get_heap_size; +export using ::ma_hpf1_init_preallocated; +export using ::ma_hpf1_init; +export using ::ma_hpf1_uninit; +export using ::ma_hpf1_reinit; +export using ::ma_hpf1_process_pcm_frames; +export using ::ma_hpf1_get_latency; +export using ::ma_hpf2_get_heap_size; +export using ::ma_hpf2_init_preallocated; +export using ::ma_hpf2_init; +export using ::ma_hpf2_uninit; +export using ::ma_hpf2_reinit; +export using ::ma_hpf2_process_pcm_frames; +export using ::ma_hpf2_get_latency; +export using ::ma_hpf_config_init; +export using ::ma_hpf_get_heap_size; +export using ::ma_hpf_init_preallocated; +export using ::ma_hpf_init; +export using ::ma_hpf_uninit; +export using ::ma_hpf_reinit; +export using ::ma_hpf_process_pcm_frames; +export using ::ma_hpf_get_latency; +export using ::ma_bpf2_config_init; +export using ::ma_bpf2_get_heap_size; +export using ::ma_bpf2_init_preallocated; +export using ::ma_bpf2_init; +export using ::ma_bpf2_uninit; +export using ::ma_bpf2_reinit; +export using ::ma_bpf2_process_pcm_frames; +export using ::ma_bpf2_get_latency; +export using ::ma_bpf_config_init; +export using ::ma_bpf_get_heap_size; +export using ::ma_bpf_init_preallocated; +export using ::ma_bpf_init; +export using ::ma_bpf_uninit; +export using ::ma_bpf_reinit; +export using ::ma_bpf_process_pcm_frames; +export using ::ma_bpf_get_latency; +export using ::ma_notch2_config_init; +export using ::ma_notch2_get_heap_size; +export using ::ma_notch2_init_preallocated; +export using ::ma_notch2_init; +export using ::ma_notch2_uninit; +export using ::ma_notch2_reinit; +export using ::ma_notch2_process_pcm_frames; +export using ::ma_notch2_get_latency; +export using ::ma_peak2_config_init; +export using ::ma_peak2_get_heap_size; +export using ::ma_peak2_init_preallocated; +export using ::ma_peak2_init; +export using ::ma_peak2_uninit; +export using ::ma_peak2_reinit; +export using ::ma_peak2_process_pcm_frames; +export using ::ma_peak2_get_latency; +export using ::ma_loshelf2_config_init; +export using ::ma_loshelf2_get_heap_size; +export using ::ma_loshelf2_init_preallocated; +export using ::ma_loshelf2_init; +export using ::ma_loshelf2_uninit; +export using ::ma_loshelf2_reinit; +export using ::ma_loshelf2_process_pcm_frames; +export using ::ma_loshelf2_get_latency; +export using ::ma_hishelf2_config_init; +export using ::ma_hishelf2_get_heap_size; +export using ::ma_hishelf2_init_preallocated; +export using ::ma_hishelf2_init; +export using ::ma_hishelf2_uninit; +export using ::ma_hishelf2_reinit; +export using ::ma_hishelf2_process_pcm_frames; +export using ::ma_hishelf2_get_latency; +export using ::ma_delay_config_init; +export using ::ma_delay_init; +export using ::ma_delay_uninit; +export using ::ma_delay_process_pcm_frames; +export using ::ma_delay_set_wet; +export using ::ma_delay_get_wet; +export using ::ma_delay_set_dry; +export using ::ma_delay_get_dry; +export using ::ma_delay_set_decay; +export using ::ma_delay_get_decay; +export using ::ma_gainer_config_init; +export using ::ma_gainer_get_heap_size; +export using ::ma_gainer_init_preallocated; +export using ::ma_gainer_init; +export using ::ma_gainer_uninit; +export using ::ma_gainer_process_pcm_frames; +export using ::ma_gainer_set_gain; +export using ::ma_gainer_set_gains; +export using ::ma_gainer_set_master_volume; +export using ::ma_gainer_get_master_volume; +export using ::ma_panner_config_init; +export using ::ma_panner_init; +export using ::ma_panner_process_pcm_frames; +export using ::ma_panner_set_mode; +export using ::ma_panner_get_mode; +export using ::ma_panner_set_pan; +export using ::ma_panner_get_pan; +export using ::ma_fader_config_init; +export using ::ma_fader_init; +export using ::ma_fader_process_pcm_frames; +export using ::ma_fader_get_data_format; +export using ::ma_fader_set_fade; +export using ::ma_fader_set_fade_ex; +export using ::ma_fader_get_current_volume; +export using ::ma_spatializer_listener_config_init; +export using ::ma_spatializer_listener_get_heap_size; +export using ::ma_spatializer_listener_init_preallocated; +export using ::ma_spatializer_listener_init; +export using ::ma_spatializer_listener_uninit; +export using ::ma_spatializer_listener_get_channel_map; +export using ::ma_spatializer_listener_set_cone; +export using ::ma_spatializer_listener_get_cone; +export using ::ma_spatializer_listener_set_position; +export using ::ma_spatializer_listener_get_position; +export using ::ma_spatializer_listener_set_direction; +export using ::ma_spatializer_listener_get_direction; +export using ::ma_spatializer_listener_set_velocity; +export using ::ma_spatializer_listener_get_velocity; +export using ::ma_spatializer_listener_set_speed_of_sound; +export using ::ma_spatializer_listener_get_speed_of_sound; +export using ::ma_spatializer_listener_set_world_up; +export using ::ma_spatializer_listener_get_world_up; +export using ::ma_spatializer_listener_set_enabled; +export using ::ma_spatializer_listener_is_enabled; +export using ::ma_spatializer_config_init; +export using ::ma_spatializer_get_heap_size; +export using ::ma_spatializer_init_preallocated; +export using ::ma_spatializer_init; +export using ::ma_spatializer_uninit; +export using ::ma_spatializer_process_pcm_frames; +export using ::ma_spatializer_set_master_volume; +export using ::ma_spatializer_get_master_volume; +export using ::ma_spatializer_get_input_channels; +export using ::ma_spatializer_get_output_channels; +export using ::ma_spatializer_set_attenuation_model; +export using ::ma_spatializer_get_attenuation_model; +export using ::ma_spatializer_set_positioning; +export using ::ma_spatializer_get_positioning; +export using ::ma_spatializer_set_rolloff; +export using ::ma_spatializer_get_rolloff; +export using ::ma_spatializer_set_min_gain; +export using ::ma_spatializer_get_min_gain; +export using ::ma_spatializer_set_max_gain; +export using ::ma_spatializer_get_max_gain; +export using ::ma_spatializer_set_min_distance; +export using ::ma_spatializer_get_min_distance; +export using ::ma_spatializer_set_max_distance; +export using ::ma_spatializer_get_max_distance; +export using ::ma_spatializer_set_cone; +export using ::ma_spatializer_get_cone; +export using ::ma_spatializer_set_doppler_factor; +export using ::ma_spatializer_get_doppler_factor; +export using ::ma_spatializer_set_directional_attenuation_factor; +export using ::ma_spatializer_get_directional_attenuation_factor; +export using ::ma_spatializer_set_position; +export using ::ma_spatializer_get_position; +export using ::ma_spatializer_set_direction; +export using ::ma_spatializer_get_direction; +export using ::ma_spatializer_set_velocity; +export using ::ma_spatializer_get_velocity; +export using ::ma_spatializer_get_relative_position_and_direction; +export using ::ma_linear_resampler_config_init; +export using ::ma_linear_resampler_get_heap_size; +export using ::ma_linear_resampler_init_preallocated; +export using ::ma_linear_resampler_init; +export using ::ma_linear_resampler_uninit; +export using ::ma_linear_resampler_process_pcm_frames; +export using ::ma_linear_resampler_set_rate; +export using ::ma_linear_resampler_set_rate_ratio; +export using ::ma_linear_resampler_get_input_latency; +export using ::ma_linear_resampler_get_output_latency; +export using ::ma_linear_resampler_get_required_input_frame_count; +export using ::ma_linear_resampler_get_expected_output_frame_count; +export using ::ma_linear_resampler_reset; +export using ::ma_resampler_config_init; +export using ::ma_resampler_get_heap_size; +export using ::ma_resampler_init_preallocated; +export using ::ma_resampler_init; +export using ::ma_resampler_uninit; +export using ::ma_resampler_process_pcm_frames; +export using ::ma_resampler_set_rate; +export using ::ma_resampler_set_rate_ratio; +export using ::ma_resampler_get_input_latency; +export using ::ma_resampler_get_output_latency; +export using ::ma_resampler_get_required_input_frame_count; +export using ::ma_resampler_get_expected_output_frame_count; +export using ::ma_resampler_reset; +export using ::ma_channel_converter_config_init; +export using ::ma_channel_converter_get_heap_size; +export using ::ma_channel_converter_init_preallocated; +export using ::ma_channel_converter_init; +export using ::ma_channel_converter_uninit; +export using ::ma_channel_converter_process_pcm_frames; +export using ::ma_channel_converter_get_input_channel_map; +export using ::ma_channel_converter_get_output_channel_map; +export using ::ma_data_converter_config_init_default; +export using ::ma_data_converter_config_init; +export using ::ma_data_converter_get_heap_size; +export using ::ma_data_converter_init_preallocated; +export using ::ma_data_converter_init; +export using ::ma_data_converter_uninit; +export using ::ma_data_converter_process_pcm_frames; +export using ::ma_data_converter_set_rate; +export using ::ma_data_converter_set_rate_ratio; +export using ::ma_data_converter_get_input_latency; +export using ::ma_data_converter_get_output_latency; +export using ::ma_data_converter_get_required_input_frame_count; +export using ::ma_data_converter_get_expected_output_frame_count; +export using ::ma_data_converter_get_input_channel_map; +export using ::ma_data_converter_get_output_channel_map; +export using ::ma_data_converter_reset; +export using ::ma_pcm_u8_to_s16; +export using ::ma_pcm_u8_to_s24; +export using ::ma_pcm_u8_to_s32; +export using ::ma_pcm_u8_to_f32; +export using ::ma_pcm_s16_to_u8; +export using ::ma_pcm_s16_to_s24; +export using ::ma_pcm_s16_to_s32; +export using ::ma_pcm_s16_to_f32; +export using ::ma_pcm_s24_to_u8; +export using ::ma_pcm_s24_to_s16; +export using ::ma_pcm_s24_to_s32; +export using ::ma_pcm_s24_to_f32; +export using ::ma_pcm_s32_to_u8; +export using ::ma_pcm_s32_to_s16; +export using ::ma_pcm_s32_to_s24; +export using ::ma_pcm_s32_to_f32; +export using ::ma_pcm_f32_to_u8; +export using ::ma_pcm_f32_to_s16; +export using ::ma_pcm_f32_to_s24; +export using ::ma_pcm_f32_to_s32; +export using ::ma_pcm_convert; +export using ::ma_convert_pcm_frames_format; +export using ::ma_deinterleave_pcm_frames; +export using ::ma_interleave_pcm_frames; +export using ::ma_channel_map_get_channel; +export using ::ma_channel_map_init_blank; +export using ::ma_channel_map_init_standard; +export using ::ma_channel_map_copy; +export using ::ma_channel_map_copy_or_default; +export using ::ma_channel_map_is_valid; +export using ::ma_channel_map_is_equal; +export using ::ma_channel_map_is_blank; +export using ::ma_channel_map_contains_channel_position; +export using ::ma_channel_map_find_channel_position; +export using ::ma_channel_map_to_string; +export using ::ma_channel_position_to_string; +export using ::ma_convert_frames; +export using ::ma_convert_frames_ex; +export using ::ma_data_source_config_init; +export using ::ma_data_source_init; +export using ::ma_data_source_uninit; +export using ::ma_data_source_read_pcm_frames; +export using ::ma_data_source_seek_pcm_frames; +export using ::ma_data_source_seek_to_pcm_frame; +export using ::ma_data_source_seek_seconds; +export using ::ma_data_source_seek_to_second; +export using ::ma_data_source_get_data_format; +export using ::ma_data_source_get_cursor_in_pcm_frames; +export using ::ma_data_source_get_length_in_pcm_frames; +export using ::ma_data_source_get_cursor_in_seconds; +export using ::ma_data_source_get_length_in_seconds; +export using ::ma_data_source_set_looping; +export using ::ma_data_source_is_looping; +export using ::ma_data_source_set_range_in_pcm_frames; +export using ::ma_data_source_get_range_in_pcm_frames; +export using ::ma_data_source_set_loop_point_in_pcm_frames; +export using ::ma_data_source_get_loop_point_in_pcm_frames; +export using ::ma_data_source_set_current; +export using ::ma_data_source_get_current; +export using ::ma_data_source_set_next; +export using ::ma_data_source_get_next; +export using ::ma_data_source_set_next_callback; +export using ::ma_data_source_get_next_callback; +export using ::ma_audio_buffer_ref_init; +export using ::ma_audio_buffer_ref_uninit; +export using ::ma_audio_buffer_ref_set_data; +export using ::ma_audio_buffer_ref_read_pcm_frames; +export using ::ma_audio_buffer_ref_seek_to_pcm_frame; +export using ::ma_audio_buffer_ref_map; +export using ::ma_audio_buffer_ref_unmap; +export using ::ma_audio_buffer_ref_at_end; +export using ::ma_audio_buffer_ref_get_cursor_in_pcm_frames; +export using ::ma_audio_buffer_ref_get_length_in_pcm_frames; +export using ::ma_audio_buffer_ref_get_available_frames; +export using ::ma_audio_buffer_config_init; +export using ::ma_audio_buffer_init; +export using ::ma_audio_buffer_init_copy; +export using ::ma_audio_buffer_alloc_and_init; +export using ::ma_audio_buffer_uninit; +export using ::ma_audio_buffer_uninit_and_free; +export using ::ma_audio_buffer_read_pcm_frames; +export using ::ma_audio_buffer_seek_to_pcm_frame; +export using ::ma_audio_buffer_map; +export using ::ma_audio_buffer_unmap; +export using ::ma_audio_buffer_at_end; +export using ::ma_audio_buffer_get_cursor_in_pcm_frames; +export using ::ma_audio_buffer_get_length_in_pcm_frames; +export using ::ma_audio_buffer_get_available_frames; +export using ::ma_paged_audio_buffer_data_init; +export using ::ma_paged_audio_buffer_data_uninit; +export using ::ma_paged_audio_buffer_data_get_head; +export using ::ma_paged_audio_buffer_data_get_tail; +export using ::ma_paged_audio_buffer_data_get_length_in_pcm_frames; +export using ::ma_paged_audio_buffer_data_allocate_page; +export using ::ma_paged_audio_buffer_data_free_page; +export using ::ma_paged_audio_buffer_data_append_page; +export using ::ma_paged_audio_buffer_data_allocate_and_append_page; +export using ::ma_paged_audio_buffer_config_init; +export using ::ma_paged_audio_buffer_init; +export using ::ma_paged_audio_buffer_uninit; +export using ::ma_paged_audio_buffer_read_pcm_frames; +export using ::ma_paged_audio_buffer_seek_to_pcm_frame; +export using ::ma_paged_audio_buffer_get_cursor_in_pcm_frames; +export using ::ma_paged_audio_buffer_get_length_in_pcm_frames; +export using ::ma_rb_init_ex; +export using ::ma_rb_init; +export using ::ma_rb_uninit; +export using ::ma_rb_reset; +export using ::ma_rb_acquire_read; +export using ::ma_rb_commit_read; +export using ::ma_rb_acquire_write; +export using ::ma_rb_commit_write; +export using ::ma_rb_seek_read; +export using ::ma_rb_seek_write; +export using ::ma_rb_pointer_distance; +export using ::ma_rb_available_read; +export using ::ma_rb_available_write; +export using ::ma_rb_get_subbuffer_size; +export using ::ma_rb_get_subbuffer_stride; +export using ::ma_rb_get_subbuffer_offset; +export using ::ma_rb_get_subbuffer_ptr; +export using ::ma_pcm_rb_init_ex; +export using ::ma_pcm_rb_init; +export using ::ma_pcm_rb_uninit; +export using ::ma_pcm_rb_reset; +export using ::ma_pcm_rb_acquire_read; +export using ::ma_pcm_rb_commit_read; +export using ::ma_pcm_rb_acquire_write; +export using ::ma_pcm_rb_commit_write; +export using ::ma_pcm_rb_seek_read; +export using ::ma_pcm_rb_seek_write; +export using ::ma_pcm_rb_pointer_distance; +export using ::ma_pcm_rb_available_read; +export using ::ma_pcm_rb_available_write; +export using ::ma_pcm_rb_get_subbuffer_size; +export using ::ma_pcm_rb_get_subbuffer_stride; +export using ::ma_pcm_rb_get_subbuffer_offset; +export using ::ma_pcm_rb_get_subbuffer_ptr; +export using ::ma_pcm_rb_get_format; +export using ::ma_pcm_rb_get_channels; +export using ::ma_pcm_rb_get_sample_rate; +export using ::ma_pcm_rb_set_sample_rate; +export using ::ma_duplex_rb_init; +export using ::ma_duplex_rb_uninit; +export using ::ma_result_description; +export using ::ma_malloc; +export using ::ma_calloc; +export using ::ma_realloc; +export using ::ma_free; +export using ::ma_aligned_malloc; +export using ::ma_aligned_free; +export using ::ma_get_format_name; +export using ::ma_blend_f32; +export using ::ma_get_bytes_per_sample; +export using ::ma_log_level_to_string; +export using ::ma_spinlock_lock; +export using ::ma_spinlock_lock_noyield; +export using ::ma_spinlock_unlock; +#if !defined(MA_NO_THREADING) +export using ::ma_mutex_init; +export using ::ma_mutex_uninit; +export using ::ma_mutex_lock; +export using ::ma_mutex_unlock; +export using ::ma_event_init; +export using ::ma_event_uninit; +export using ::ma_event_wait; +export using ::ma_event_signal; +export using ::ma_semaphore_init; +export using ::ma_semaphore_uninit; +export using ::ma_semaphore_wait; +export using ::ma_semaphore_release; +#endif +export using ::ma_fence_init; +export using ::ma_fence_uninit; +export using ::ma_fence_acquire; +export using ::ma_fence_release; +export using ::ma_fence_wait; +export using ::ma_async_notification_signal; +export using ::ma_async_notification_poll_init; +export using ::ma_async_notification_poll_is_signalled; +export using ::ma_async_notification_event_init; +export using ::ma_async_notification_event_uninit; +export using ::ma_async_notification_event_wait; +export using ::ma_async_notification_event_signal; +export using ::ma_slot_allocator_config_init; +export using ::ma_slot_allocator_get_heap_size; +export using ::ma_slot_allocator_init_preallocated; +export using ::ma_slot_allocator_init; +export using ::ma_slot_allocator_uninit; +export using ::ma_slot_allocator_alloc; +export using ::ma_slot_allocator_free; +export using ::ma_job_init; +export using ::ma_job_process; +export using ::ma_job_queue_config_init; +export using ::ma_job_queue_get_heap_size; +export using ::ma_job_queue_init_preallocated; +export using ::ma_job_queue_init; +export using ::ma_job_queue_uninit; +export using ::ma_job_queue_post; +export using ::ma_job_queue_next; +#if !defined(MA_NO_DEVICE_IO) +export using ::ma_device_job_thread_config_init; +export using ::ma_device_job_thread_init; +export using ::ma_device_job_thread_uninit; +export using ::ma_device_job_thread_post; +export using ::ma_device_job_thread_next; +export using ::ma_device_id_equal; +export using ::ma_context_config_init; +export using ::ma_context_init; +export using ::ma_context_uninit; +export using ::ma_context_sizeof; +export using ::ma_context_get_log; +export using ::ma_context_enumerate_devices; +export using ::ma_context_get_devices; +export using ::ma_context_get_device_info; +export using ::ma_context_is_loopback_supported; +export using ::ma_device_config_init; +export using ::ma_device_init; +export using ::ma_device_init_ex; +export using ::ma_device_uninit; +export using ::ma_device_get_context; +export using ::ma_device_get_log; +export using ::ma_device_get_info; +export using ::ma_device_get_name; +export using ::ma_device_start; +export using ::ma_device_stop; +export using ::ma_device_is_started; +export using ::ma_device_get_state; +export using ::ma_device_post_init; +export using ::ma_device_set_master_volume; +export using ::ma_device_get_master_volume; +export using ::ma_device_set_master_volume_db; +export using ::ma_device_get_master_volume_db; +export using ::ma_device_handle_backend_data_callback; +export using ::ma_calculate_buffer_size_in_frames_from_descriptor; +export using ::ma_get_backend_name; +export using ::ma_get_backend_from_name; +export using ::ma_is_backend_enabled; +export using ::ma_get_enabled_backends; +export using ::ma_is_loopback_supported; +#endif +export using ::ma_calculate_buffer_size_in_milliseconds_from_frames; +export using ::ma_calculate_buffer_size_in_frames_from_milliseconds; +export using ::ma_copy_pcm_frames; +export using ::ma_silence_pcm_frames; +export using ::ma_offset_pcm_frames_ptr; +export using ::ma_offset_pcm_frames_const_ptr; +export using ::ma_clip_samples_u8; +export using ::ma_clip_samples_s16; +export using ::ma_clip_samples_s24; +export using ::ma_clip_samples_s32; +export using ::ma_clip_samples_f32; +export using ::ma_clip_pcm_frames; +export using ::ma_copy_and_apply_volume_factor_u8; +export using ::ma_copy_and_apply_volume_factor_s16; +export using ::ma_copy_and_apply_volume_factor_s24; +export using ::ma_copy_and_apply_volume_factor_s32; +export using ::ma_copy_and_apply_volume_factor_f32; +export using ::ma_apply_volume_factor_u8; +export using ::ma_apply_volume_factor_s16; +export using ::ma_apply_volume_factor_s24; +export using ::ma_apply_volume_factor_s32; +export using ::ma_apply_volume_factor_f32; +export using ::ma_copy_and_apply_volume_factor_pcm_frames_u8; +export using ::ma_copy_and_apply_volume_factor_pcm_frames_s16; +export using ::ma_copy_and_apply_volume_factor_pcm_frames_s24; +export using ::ma_copy_and_apply_volume_factor_pcm_frames_s32; +export using ::ma_copy_and_apply_volume_factor_pcm_frames_f32; +export using ::ma_copy_and_apply_volume_factor_pcm_frames; +export using ::ma_apply_volume_factor_pcm_frames_u8; +export using ::ma_apply_volume_factor_pcm_frames_s16; +export using ::ma_apply_volume_factor_pcm_frames_s24; +export using ::ma_apply_volume_factor_pcm_frames_s32; +export using ::ma_apply_volume_factor_pcm_frames_f32; +export using ::ma_apply_volume_factor_pcm_frames; +export using ::ma_copy_and_apply_volume_factor_per_channel_f32; +export using ::ma_copy_and_apply_volume_and_clip_samples_u8; +export using ::ma_copy_and_apply_volume_and_clip_samples_s16; +export using ::ma_copy_and_apply_volume_and_clip_samples_s24; +export using ::ma_copy_and_apply_volume_and_clip_samples_s32; +export using ::ma_copy_and_apply_volume_and_clip_samples_f32; +export using ::ma_copy_and_apply_volume_and_clip_pcm_frames; +export using ::ma_volume_linear_to_db; +export using ::ma_volume_db_to_linear; +export using ::ma_mix_pcm_frames_f32; +export using ::ma_vfs_open; +export using ::ma_vfs_open_w; +export using ::ma_vfs_close; +export using ::ma_vfs_read; +export using ::ma_vfs_write; +export using ::ma_vfs_seek; +export using ::ma_vfs_tell; +export using ::ma_vfs_info; +export using ::ma_vfs_open_and_read_file; +export using ::ma_default_vfs_init; +#if !defined(MA_NO_DECODING) +export using ::ma_decoding_backend_config_init; +export using ::ma_decoder_config_init; +export using ::ma_decoder_config_init_default; +export using ::ma_decoder_init; +export using ::ma_decoder_init_memory; +export using ::ma_decoder_init_vfs; +export using ::ma_decoder_init_vfs_w; +export using ::ma_decoder_init_file; +export using ::ma_decoder_init_file_w; +export using ::ma_decoder_uninit; +export using ::ma_decoder_read_pcm_frames; +export using ::ma_decoder_seek_to_pcm_frame; +export using ::ma_decoder_get_data_format; +export using ::ma_decoder_get_cursor_in_pcm_frames; +export using ::ma_decoder_get_length_in_pcm_frames; +export using ::ma_decoder_get_available_frames; +export using ::ma_decode_from_vfs; +export using ::ma_decode_file; +export using ::ma_decode_memory; +#endif +#if !defined(MA_NO_ENCODING) +export using ::ma_encoder_config_init; +export using ::ma_encoder_init; +export using ::ma_encoder_init_vfs; +export using ::ma_encoder_init_vfs_w; +export using ::ma_encoder_init_file; +export using ::ma_encoder_init_file_w; +export using ::ma_encoder_uninit; +export using ::ma_encoder_write_pcm_frames; +#endif +#if !defined(MA_NO_GENERATION) +export using ::ma_waveform_config_init; +export using ::ma_waveform_init; +export using ::ma_waveform_uninit; +export using ::ma_waveform_read_pcm_frames; +export using ::ma_waveform_seek_to_pcm_frame; +export using ::ma_waveform_set_amplitude; +export using ::ma_waveform_set_frequency; +export using ::ma_waveform_set_type; +export using ::ma_waveform_set_sample_rate; +export using ::ma_pulsewave_config_init; +export using ::ma_pulsewave_init; +export using ::ma_pulsewave_uninit; +export using ::ma_pulsewave_read_pcm_frames; +export using ::ma_pulsewave_seek_to_pcm_frame; +export using ::ma_pulsewave_set_amplitude; +export using ::ma_pulsewave_set_frequency; +export using ::ma_pulsewave_set_sample_rate; +export using ::ma_pulsewave_set_duty_cycle; +export using ::ma_noise_config_init; +export using ::ma_noise_get_heap_size; +export using ::ma_noise_init_preallocated; +export using ::ma_noise_init; +export using ::ma_noise_uninit; +export using ::ma_noise_read_pcm_frames; +export using ::ma_noise_set_amplitude; +export using ::ma_noise_set_seed; +export using ::ma_noise_set_type; +#endif +#if !defined(MA_NO_RESOURCE_MANAGER) +export using ::ma_resource_manager_pipeline_notifications_init; +export using ::ma_resource_manager_data_source_config_init; +export using ::ma_resource_manager_config_init; +export using ::ma_resource_manager_init; +export using ::ma_resource_manager_uninit; +export using ::ma_resource_manager_get_log; +export using ::ma_resource_manager_register_file; +export using ::ma_resource_manager_register_file_w; +export using ::ma_resource_manager_register_decoded_data; +export using ::ma_resource_manager_register_decoded_data_w; +export using ::ma_resource_manager_register_encoded_data; +export using ::ma_resource_manager_register_encoded_data_w; +export using ::ma_resource_manager_unregister_file; +export using ::ma_resource_manager_unregister_file_w; +export using ::ma_resource_manager_unregister_data; +export using ::ma_resource_manager_unregister_data_w; +export using ::ma_resource_manager_data_buffer_init_ex; +export using ::ma_resource_manager_data_buffer_init; +export using ::ma_resource_manager_data_buffer_init_w; +export using ::ma_resource_manager_data_buffer_init_copy; +export using ::ma_resource_manager_data_buffer_uninit; +export using ::ma_resource_manager_data_buffer_read_pcm_frames; +export using ::ma_resource_manager_data_buffer_seek_to_pcm_frame; +export using ::ma_resource_manager_data_buffer_get_data_format; +export using ::ma_resource_manager_data_buffer_get_cursor_in_pcm_frames; +export using ::ma_resource_manager_data_buffer_get_length_in_pcm_frames; +export using ::ma_resource_manager_data_buffer_result; +export using ::ma_resource_manager_data_buffer_set_looping; +export using ::ma_resource_manager_data_buffer_is_looping; +export using ::ma_resource_manager_data_buffer_get_available_frames; +export using ::ma_resource_manager_data_stream_init_ex; +export using ::ma_resource_manager_data_stream_init; +export using ::ma_resource_manager_data_stream_init_w; +export using ::ma_resource_manager_data_stream_uninit; +export using ::ma_resource_manager_data_stream_read_pcm_frames; +export using ::ma_resource_manager_data_stream_seek_to_pcm_frame; +export using ::ma_resource_manager_data_stream_get_data_format; +export using ::ma_resource_manager_data_stream_get_cursor_in_pcm_frames; +export using ::ma_resource_manager_data_stream_get_length_in_pcm_frames; +export using ::ma_resource_manager_data_stream_result; +export using ::ma_resource_manager_data_stream_set_looping; +export using ::ma_resource_manager_data_stream_is_looping; +export using ::ma_resource_manager_data_stream_get_available_frames; +export using ::ma_resource_manager_data_source_init_ex; +export using ::ma_resource_manager_data_source_init; +export using ::ma_resource_manager_data_source_init_w; +export using ::ma_resource_manager_data_source_init_copy; +export using ::ma_resource_manager_data_source_uninit; +export using ::ma_resource_manager_data_source_read_pcm_frames; +export using ::ma_resource_manager_data_source_seek_to_pcm_frame; +export using ::ma_resource_manager_data_source_get_data_format; +export using ::ma_resource_manager_data_source_get_cursor_in_pcm_frames; +export using ::ma_resource_manager_data_source_get_length_in_pcm_frames; +export using ::ma_resource_manager_data_source_result; +export using ::ma_resource_manager_data_source_set_looping; +export using ::ma_resource_manager_data_source_is_looping; +export using ::ma_resource_manager_data_source_get_available_frames; +export using ::ma_resource_manager_post_job; +export using ::ma_resource_manager_post_job_quit; +export using ::ma_resource_manager_next_job; +export using ::ma_resource_manager_process_job; +export using ::ma_resource_manager_process_next_job; +#endif +#if !defined(MA_NO_NODE_GRAPH) +export using ::ma_node_config_init; +export using ::ma_node_get_heap_size; +export using ::ma_node_init_preallocated; +export using ::ma_node_init; +export using ::ma_node_uninit; +export using ::ma_node_get_node_graph; +export using ::ma_node_get_input_bus_count; +export using ::ma_node_get_output_bus_count; +export using ::ma_node_get_input_channels; +export using ::ma_node_get_output_channels; +export using ::ma_node_attach_output_bus; +export using ::ma_node_detach_output_bus; +export using ::ma_node_detach_all_output_buses; +export using ::ma_node_set_output_bus_volume; +export using ::ma_node_get_output_bus_volume; +export using ::ma_node_set_state; +export using ::ma_node_get_state; +export using ::ma_node_set_state_time; +export using ::ma_node_get_state_time; +export using ::ma_node_get_state_by_time; +export using ::ma_node_get_state_by_time_range; +export using ::ma_node_get_time; +export using ::ma_node_set_time; +export using ::ma_node_graph_config_init; +export using ::ma_node_graph_init; +export using ::ma_node_graph_uninit; +export using ::ma_node_graph_get_endpoint; +export using ::ma_node_graph_read_pcm_frames; +export using ::ma_node_graph_get_channels; +export using ::ma_node_graph_get_time; +export using ::ma_node_graph_set_time; +export using ::ma_node_graph_get_processing_size_in_frames; +export using ::ma_data_source_node_config_init; +export using ::ma_data_source_node_init; +export using ::ma_data_source_node_uninit; +export using ::ma_data_source_node_set_looping; +export using ::ma_data_source_node_is_looping; +export using ::ma_splitter_node_config_init; +export using ::ma_splitter_node_init; +export using ::ma_splitter_node_uninit; +export using ::ma_biquad_node_config_init; +export using ::ma_biquad_node_init; +export using ::ma_biquad_node_reinit; +export using ::ma_biquad_node_uninit; +export using ::ma_lpf_node_config_init; +export using ::ma_lpf_node_init; +export using ::ma_lpf_node_reinit; +export using ::ma_lpf_node_uninit; +export using ::ma_hpf_node_config_init; +export using ::ma_hpf_node_init; +export using ::ma_hpf_node_reinit; +export using ::ma_hpf_node_uninit; +export using ::ma_bpf_node_config_init; +export using ::ma_bpf_node_init; +export using ::ma_bpf_node_reinit; +export using ::ma_bpf_node_uninit; +export using ::ma_notch_node_config_init; +export using ::ma_notch_node_init; +export using ::ma_notch_node_reinit; +export using ::ma_notch_node_uninit; +export using ::ma_peak_node_config_init; +export using ::ma_peak_node_init; +export using ::ma_peak_node_reinit; +export using ::ma_peak_node_uninit; +export using ::ma_loshelf_node_config_init; +export using ::ma_loshelf_node_init; +export using ::ma_loshelf_node_reinit; +export using ::ma_loshelf_node_uninit; +export using ::ma_hishelf_node_config_init; +export using ::ma_hishelf_node_init; +export using ::ma_hishelf_node_reinit; +export using ::ma_hishelf_node_uninit; +export using ::ma_delay_node_config_init; +export using ::ma_delay_node_init; +export using ::ma_delay_node_uninit; +export using ::ma_delay_node_set_wet; +export using ::ma_delay_node_get_wet; +export using ::ma_delay_node_set_dry; +export using ::ma_delay_node_get_dry; +export using ::ma_delay_node_set_decay; +export using ::ma_delay_node_get_decay; +#endif +#if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH) +export using ::ma_engine_node_config_init; +export using ::ma_engine_node_get_heap_size; +export using ::ma_engine_node_init_preallocated; +export using ::ma_engine_node_init; +export using ::ma_engine_node_uninit; +export using ::ma_sound_config_init; +export using ::ma_sound_config_init_2; +export using ::ma_sound_group_config_init; +export using ::ma_sound_group_config_init_2; +export using ::ma_engine_config_init; +export using ::ma_engine_init; +export using ::ma_engine_uninit; +export using ::ma_engine_read_pcm_frames; +export using ::ma_engine_get_node_graph; +#endif +#if (!defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH)) && (!defined(MA_NO_RESOURCE_MANAGER)) +export using ::ma_engine_get_resource_manager; +#endif +#if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH) +export using ::ma_engine_get_device; +export using ::ma_engine_get_log; +export using ::ma_engine_get_endpoint; +export using ::ma_engine_get_time_in_pcm_frames; +export using ::ma_engine_get_time_in_milliseconds; +export using ::ma_engine_set_time_in_pcm_frames; +export using ::ma_engine_set_time_in_milliseconds; +export using ::ma_engine_get_time; +export using ::ma_engine_set_time; +export using ::ma_engine_get_channels; +export using ::ma_engine_get_sample_rate; +export using ::ma_engine_start; +export using ::ma_engine_stop; +export using ::ma_engine_set_volume; +export using ::ma_engine_get_volume; +export using ::ma_engine_set_gain_db; +export using ::ma_engine_get_gain_db; +export using ::ma_engine_get_listener_count; +export using ::ma_engine_find_closest_listener; +export using ::ma_engine_listener_set_position; +export using ::ma_engine_listener_get_position; +export using ::ma_engine_listener_set_direction; +export using ::ma_engine_listener_get_direction; +export using ::ma_engine_listener_set_velocity; +export using ::ma_engine_listener_get_velocity; +export using ::ma_engine_listener_set_cone; +export using ::ma_engine_listener_get_cone; +export using ::ma_engine_listener_set_world_up; +export using ::ma_engine_listener_get_world_up; +export using ::ma_engine_listener_set_enabled; +export using ::ma_engine_listener_is_enabled; +#endif +#if (!defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH)) && (!defined(MA_NO_RESOURCE_MANAGER)) +export using ::ma_engine_play_sound_ex; +export using ::ma_engine_play_sound; +export using ::ma_sound_init_from_file; +export using ::ma_sound_init_from_file_w; +export using ::ma_sound_init_copy; +#endif +#if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH) +export using ::ma_sound_init_from_data_source; +export using ::ma_sound_init_ex; +export using ::ma_sound_uninit; +export using ::ma_sound_get_engine; +export using ::ma_sound_get_data_source; +export using ::ma_sound_start; +export using ::ma_sound_stop; +export using ::ma_sound_stop_with_fade_in_pcm_frames; +export using ::ma_sound_stop_with_fade_in_milliseconds; +export using ::ma_sound_reset_start_time; +export using ::ma_sound_reset_stop_time; +export using ::ma_sound_reset_fade; +export using ::ma_sound_reset_stop_time_and_fade; +export using ::ma_sound_set_volume; +export using ::ma_sound_get_volume; +export using ::ma_sound_set_pan; +export using ::ma_sound_get_pan; +export using ::ma_sound_set_pan_mode; +export using ::ma_sound_get_pan_mode; +export using ::ma_sound_set_pitch; +export using ::ma_sound_get_pitch; +export using ::ma_sound_set_spatialization_enabled; +export using ::ma_sound_is_spatialization_enabled; +export using ::ma_sound_set_pinned_listener_index; +export using ::ma_sound_get_pinned_listener_index; +export using ::ma_sound_get_listener_index; +export using ::ma_sound_get_direction_to_listener; +export using ::ma_sound_set_position; +export using ::ma_sound_get_position; +export using ::ma_sound_set_direction; +export using ::ma_sound_get_direction; +export using ::ma_sound_set_velocity; +export using ::ma_sound_get_velocity; +export using ::ma_sound_set_attenuation_model; +export using ::ma_sound_get_attenuation_model; +export using ::ma_sound_set_positioning; +export using ::ma_sound_get_positioning; +export using ::ma_sound_set_rolloff; +export using ::ma_sound_get_rolloff; +export using ::ma_sound_set_min_gain; +export using ::ma_sound_get_min_gain; +export using ::ma_sound_set_max_gain; +export using ::ma_sound_get_max_gain; +export using ::ma_sound_set_min_distance; +export using ::ma_sound_get_min_distance; +export using ::ma_sound_set_max_distance; +export using ::ma_sound_get_max_distance; +export using ::ma_sound_set_cone; +export using ::ma_sound_get_cone; +export using ::ma_sound_set_doppler_factor; +export using ::ma_sound_get_doppler_factor; +export using ::ma_sound_set_directional_attenuation_factor; +export using ::ma_sound_get_directional_attenuation_factor; +export using ::ma_sound_set_fade_in_pcm_frames; +export using ::ma_sound_set_fade_in_milliseconds; +export using ::ma_sound_set_fade_start_in_pcm_frames; +export using ::ma_sound_set_fade_start_in_milliseconds; +export using ::ma_sound_get_current_fade_volume; +export using ::ma_sound_set_start_time_in_pcm_frames; +export using ::ma_sound_set_start_time_in_milliseconds; +export using ::ma_sound_set_stop_time_in_pcm_frames; +export using ::ma_sound_set_stop_time_in_milliseconds; +export using ::ma_sound_set_stop_time_with_fade_in_pcm_frames; +export using ::ma_sound_set_stop_time_with_fade_in_milliseconds; +export using ::ma_sound_is_playing; +export using ::ma_sound_get_time_in_pcm_frames; +export using ::ma_sound_get_time_in_milliseconds; +export using ::ma_sound_set_looping; +export using ::ma_sound_is_looping; +export using ::ma_sound_at_end; +export using ::ma_sound_seek_to_pcm_frame; +export using ::ma_sound_seek_to_second; +export using ::ma_sound_get_data_format; +export using ::ma_sound_get_cursor_in_pcm_frames; +export using ::ma_sound_get_length_in_pcm_frames; +export using ::ma_sound_get_cursor_in_seconds; +export using ::ma_sound_get_length_in_seconds; +export using ::ma_sound_set_end_callback; +export using ::ma_sound_group_init; +export using ::ma_sound_group_init_ex; +export using ::ma_sound_group_uninit; +export using ::ma_sound_group_get_engine; +export using ::ma_sound_group_start; +export using ::ma_sound_group_stop; +export using ::ma_sound_group_set_volume; +export using ::ma_sound_group_get_volume; +export using ::ma_sound_group_set_pan; +export using ::ma_sound_group_get_pan; +export using ::ma_sound_group_set_pan_mode; +export using ::ma_sound_group_get_pan_mode; +export using ::ma_sound_group_set_pitch; +export using ::ma_sound_group_get_pitch; +export using ::ma_sound_group_set_spatialization_enabled; +export using ::ma_sound_group_is_spatialization_enabled; +export using ::ma_sound_group_set_pinned_listener_index; +export using ::ma_sound_group_get_pinned_listener_index; +export using ::ma_sound_group_get_listener_index; +export using ::ma_sound_group_get_direction_to_listener; +export using ::ma_sound_group_set_position; +export using ::ma_sound_group_get_position; +export using ::ma_sound_group_set_direction; +export using ::ma_sound_group_get_direction; +export using ::ma_sound_group_set_velocity; +export using ::ma_sound_group_get_velocity; +export using ::ma_sound_group_set_attenuation_model; +export using ::ma_sound_group_get_attenuation_model; +export using ::ma_sound_group_set_positioning; +export using ::ma_sound_group_get_positioning; +export using ::ma_sound_group_set_rolloff; +export using ::ma_sound_group_get_rolloff; +export using ::ma_sound_group_set_min_gain; +export using ::ma_sound_group_get_min_gain; +export using ::ma_sound_group_set_max_gain; +export using ::ma_sound_group_get_max_gain; +export using ::ma_sound_group_set_min_distance; +export using ::ma_sound_group_get_min_distance; +export using ::ma_sound_group_set_max_distance; +export using ::ma_sound_group_get_max_distance; +export using ::ma_sound_group_set_cone; +export using ::ma_sound_group_get_cone; +export using ::ma_sound_group_set_doppler_factor; +export using ::ma_sound_group_get_doppler_factor; +export using ::ma_sound_group_set_directional_attenuation_factor; +export using ::ma_sound_group_get_directional_attenuation_factor; +export using ::ma_sound_group_set_fade_in_pcm_frames; +export using ::ma_sound_group_set_fade_in_milliseconds; +export using ::ma_sound_group_get_current_fade_volume; +export using ::ma_sound_group_set_start_time_in_pcm_frames; +export using ::ma_sound_group_set_start_time_in_milliseconds; +export using ::ma_sound_group_set_stop_time_in_pcm_frames; +export using ::ma_sound_group_set_stop_time_in_milliseconds; +export using ::ma_sound_group_is_playing; +export using ::ma_sound_group_get_time_in_pcm_frames; +#endif + +// The static MA_INLINE functions (3): internal linkage, not exportable; +// adapted under the same names and signatures, each calling upstream's (src/inline.cpp). +export namespace mcpplibs::mwrap::miniaudio { +ma_uint32 ma_get_bytes_per_frame(ma_format format, ma_uint32 channels); +float* ma_offset_pcm_frames_ptr_f32(float* p, ma_uint64 offsetInFrames, ma_uint32 channels); +const float* ma_offset_pcm_frames_const_ptr_f32(const float* p, ma_uint64 offsetInFrames, ma_uint32 channels); +} // namespace mcpplibs::mwrap::miniaudio diff --git a/templates/tone/mcpp.toml.in b/templates/tone/mcpp.toml.in new file mode 100644 index 0000000..a637560 --- /dev/null +++ b/templates/tone/mcpp.toml.in @@ -0,0 +1,10 @@ +[package] +name = "{{project.name}}" +version = "0.1.0" + +[targets.{{project.name}}] +kind = "bin" +main = "src/main.cpp" + +[dependencies] +"{{self.name}}" = "{{self.version}}" diff --git a/templates/tone/src/main.cpp.in b/templates/tone/src/main.cpp.in new file mode 100644 index 0000000..92337af --- /dev/null +++ b/templates/tone/src/main.cpp.in @@ -0,0 +1,80 @@ +// {{project.name}} — audio through import mcpplibs.mwrap.miniaudio, no device +// needed: a 440 Hz tone from a waveform data source, encoded as a WAV file in +// memory, decoded back and measured. `--play` then plays it on the default +// playback device through the high-level engine. +import std; +import mcpplibs.mwrap.miniaudio; + +int main(int argc, char** argv) { + const bool play = argc > 1 && std::string_view(argv[1]) == "--play"; + constexpr ma_uint32 rate = 48000, frames = rate; // one second, mono + + // A sine at half scale, as 16-bit samples. + const ma_waveform_config wconfig = ma_waveform_config_init(ma_format_s16, 1, rate, ma_waveform_type_sine, 0.5, 440); + ma_waveform wave; + ma_waveform_init(&wconfig, &wave); + std::vector pcm(frames); + ma_waveform_read_pcm_frames(&wave, pcm.data(), frames, nullptr); + ma_waveform_uninit(&wave); + + // Encoded as WAV into a byte vector, through the encoder's callbacks. + struct Sink { + std::vector bytes; + std::size_t at = 0; + } sink; + const auto write = [](ma_encoder* e, const void* data, std::size_t n, std::size_t* written) -> ma_result { + auto& s = *static_cast(e->pUserData); + if (s.bytes.size() < s.at + n) s.bytes.resize(s.at + n); + std::memcpy(s.bytes.data() + s.at, data, n); + s.at += n; + *written = n; + return MA_SUCCESS; + }; + const auto seek = [](ma_encoder* e, ma_int64 offset, ma_seek_origin origin) -> ma_result { + auto& s = *static_cast(e->pUserData); + s.at = static_cast((origin == ma_seek_origin_start ? 0 : static_cast(s.at)) + offset); + return MA_SUCCESS; + }; + const ma_encoder_config econfig = ma_encoder_config_init(ma_encoding_format_wav, ma_format_s16, 1, rate); + ma_encoder encoder; + if (ma_encoder_init(write, seek, &sink, &econfig, &encoder) != MA_SUCCESS) return 1; + ma_encoder_write_pcm_frames(&encoder, pcm.data(), frames, nullptr); + ma_encoder_uninit(&encoder); + + // Decoded back from memory, as f32, and measured. + const ma_decoder_config dconfig = ma_decoder_config_init(ma_format_f32, 0, 0); + ma_decoder decoder; + if (ma_decoder_init_memory(sink.bytes.data(), sink.bytes.size(), &dconfig, &decoder) != MA_SUCCESS) return 2; + std::vector back(frames); + ma_uint64 read = 0; + ma_decoder_read_pcm_frames(&decoder, back.data(), frames, &read); + ma_decoder_uninit(&decoder); + double sum = 0, peak = 0; + for (float v : back) { + sum += double(v) * v; + peak = std::max(peak, double(std::abs(v))); + } + std::println("miniaudio {}: {} bytes of WAV, {} frames back at {} Hz, peak {:.3f}, rms {:.3f}", ma_version_string(), + sink.bytes.size(), read, rate, peak, std::sqrt(sum / double(read))); + if (read != frames || std::abs(peak - 0.5) > 1e-3) return 3; + + if (play) { + ma_engine engine; + if (ma_engine_init(nullptr, &engine) != MA_SUCCESS) { + std::println(std::cerr, "no playback device"); + return 4; + } + ma_audio_buffer_config bconfig = ma_audio_buffer_config_init(ma_format_f32, 1, read, back.data(), nullptr); + bconfig.sampleRate = rate; + ma_audio_buffer buffer; + ma_audio_buffer_init(&bconfig, &buffer); + ma_sound sound; + ma_sound_init_from_data_source(&engine, &buffer, 0, nullptr, &sound); + ma_sound_start(&sound); + std::println("playing on {}", ma_engine_get_device(&engine)->playback.name); + while (!ma_sound_at_end(&sound)) std::this_thread::sleep_for(std::chrono::milliseconds(20)); + ma_sound_uninit(&sound); + ma_audio_buffer_uninit(&buffer); + ma_engine_uninit(&engine); + } +} diff --git a/templates/tone/template.toml b/templates/tone/template.toml new file mode 100644 index 0000000..f77429c --- /dev/null +++ b/templates/tone/template.toml @@ -0,0 +1,4 @@ +[template] +description = "Audio with import mcpplibs.mwrap.miniaudio: a tone from a waveform data source, encoded as WAV in memory, decoded back and measured, then played on the default device with --play" +default = true +post_message = "Run `mcpp run`, or `mcpp run -- --play` to hear it on the default playback device." diff --git a/tests/api_test.cpp b/tests/api_test.cpp new file mode 100644 index 0000000..9c653a1 --- /dev/null +++ b/tests/api_test.cpp @@ -0,0 +1,439 @@ +// The miniaudio API through the module, spelled as documents it: +// the version, the backends of this target, a context and a playback device on +// the Null backend pulling a waveform, the Web Audio backend's own probe on +// wasm32-emscripten, waveform and noise data sources, WAV encoding into memory +// and decoding it back, decoding WAV, FLAC and MP3 from memory and from a file, +// the resampler and the data and channel converters, a low-pass filter, the +// PCM ring buffer, the high-level engine without a device (ma_engine_read_ +// pcm_frames) mixing a sound and a sound group, and the adapted inline +// functions. Only the module is imported; no miniaudio header is included. +// +// No test needs an audio device: CI has none. The Null backend (every target +// but Emscripten, where upstream does not build it: it needs a background +// thread) runs a device in real time without one. +#include + +import std; +import mcpplibs.mwrap.miniaudio; + +using namespace mcpplibs::mwrap::miniaudio::macros; // MA_VERSION_STRING, MA_MAX_CHANNELS … + +namespace { + +#include "data/fixtures.inc" + +constexpr ma_uint32 kToneFrames = 4410; // tools/gen_fixtures.py: 0.1 s of 440 Hz at 44.1 kHz +constexpr ma_uint32 kToneRate = 44100; + +std::vector decode_s16(ma_decoder& decoder) { + std::vector out; + ma_int16 block[512]; + for (;;) { + ma_uint64 read = 0; + const ma_result r = ma_decoder_read_pcm_frames(&decoder, block, 512 / decoder.outputChannels, &read); + out.insert(out.end(), block, block + read * decoder.outputChannels); + if (r != MA_SUCCESS || read == 0) break; + } + return out; +} + +std::vector decode_memory(const unsigned char* data, std::size_t size, ma_encoding_format format) { + ma_decoder_config config = ma_decoder_config_init(ma_format_s16, 1, kToneRate); + config.encodingFormat = format; + ma_decoder decoder; + if (ma_decoder_init_memory(data, size, &config, &decoder) != MA_SUCCESS) return {}; + auto pcm = decode_s16(decoder); + ma_decoder_uninit(&decoder); + return pcm; +} + +// Sign changes of a signal louder than `floor` (a Schmitt trigger: the +// near-silence of an MP3's encoder delay does not count). +int zero_crossings(std::span s, float floor = 0.05f) { + int n = 0, side = 0; + for (float v : s) { + const int now = v > floor ? 1 : v < -floor ? -1 : side; + n += side != 0 && now != side; + side = now; + } + return n; +} + +float peak(std::span s) { + float p = 0; + for (float v : s) p = std::max(p, std::abs(v)); + return p; +} + +} // namespace + +TEST(Api, Version) { + ma_uint32 major = 0, minor = 0, revision = 0; + ma_version(&major, &minor, &revision); + EXPECT_EQ(major, 0u); + EXPECT_EQ(minor, 11u); + EXPECT_EQ(revision, 25u); + EXPECT_STREQ(ma_version_string(), "0.11.25"); + EXPECT_STREQ(ma_version_string(), MA_VERSION_STRING); +} + +TEST(Api, BackendsOfThisTarget) { + ma_backend enabled[MA_BACKEND_COUNT]; + std::size_t count = 0; + ASSERT_EQ(ma_get_enabled_backends(enabled, MA_BACKEND_COUNT, &count), MA_SUCCESS); + const std::span backends(enabled, count); + const auto has = [&](ma_backend b) { return std::ranges::find(backends, b) != backends.end(); }; + EXPECT_TRUE(has(ma_backend_custom)); + EXPECT_STREQ(ma_get_backend_name(ma_backend_null), "Null"); +#if defined(__EMSCRIPTEN__) + EXPECT_TRUE(has(ma_backend_webaudio)); + EXPECT_FALSE(has(ma_backend_null)); + EXPECT_EQ(ma_is_backend_enabled(ma_backend_webaudio), MA_TRUE); +#else + EXPECT_TRUE(has(ma_backend_null)); +#endif +#if defined(_WIN32) + EXPECT_TRUE(has(ma_backend_wasapi)); +#elif defined(__APPLE__) + EXPECT_TRUE(has(ma_backend_coreaudio)); +#elif defined(__linux__) + EXPECT_TRUE(has(ma_backend_alsa)); + EXPECT_TRUE(has(ma_backend_pulseaudio)); +#endif + for (ma_backend b : backends) EXPECT_EQ(ma_is_backend_enabled(b), MA_TRUE); +} + +#if defined(__EMSCRIPTEN__) +TEST(Api, WebAudioProbesItsHost) { + // The Web Audio backend is JavaScript (EM_ASM) that asks the host for an + // AudioContext. node has none, so the context reports no backend: the + // backend's code was linked and ran. A page has one, and the same call + // succeeds there. + ma_backend webaudio = ma_backend_webaudio; + ma_context context; + EXPECT_EQ(ma_context_init(&webaudio, 1, nullptr, &context), MA_NO_BACKEND); +} +#endif + +TEST(Api, NullDevicePullsAWaveform) { + if (!ma_is_backend_enabled(ma_backend_null)) GTEST_SKIP() << "no Null backend on this target"; + ma_backend null = ma_backend_null; + ma_context context; + ASSERT_EQ(ma_context_init(&null, 1, nullptr, &context), MA_SUCCESS); + EXPECT_EQ(context.backend, ma_backend_null); + + ma_device_info* playback = nullptr; + ma_uint32 playbackCount = 0; + ASSERT_EQ(ma_context_get_devices(&context, &playback, &playbackCount, nullptr, nullptr), MA_SUCCESS); + ASSERT_GE(playbackCount, 1u); + + struct Feed { + ma_waveform wave; + std::atomic frames{0}; + } feed; + const ma_waveform_config waveConfig = ma_waveform_config_init(ma_format_f32, 2, 48000, ma_waveform_type_sine, 0.25, 440); + ASSERT_EQ(ma_waveform_init(&waveConfig, &feed.wave), MA_SUCCESS); + + ma_device_config config = ma_device_config_init(ma_device_type_playback); + config.playback.format = ma_format_f32; + config.playback.channels = 2; + config.sampleRate = 48000; + config.pUserData = &feed; + config.dataCallback = [](ma_device* device, void* output, const void*, ma_uint32 frameCount) { + auto* f = static_cast(device->pUserData); + ma_waveform_read_pcm_frames(&f->wave, output, frameCount, nullptr); + f->frames += frameCount; + }; + ma_device device; + ASSERT_EQ(ma_device_init(&context, &config, &device), MA_SUCCESS); + EXPECT_EQ(ma_device_get_state(&device), ma_device_state_stopped); + ASSERT_EQ(ma_device_start(&device), MA_SUCCESS); + EXPECT_EQ(ma_device_is_started(&device), MA_TRUE); + const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10); + while (feed.frames < 4800 && std::chrono::steady_clock::now() < deadline) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + EXPECT_EQ(ma_device_stop(&device), MA_SUCCESS); + EXPECT_GE(feed.frames.load(), 4800u); // 0.1 s, at the Null backend's real-time pace + ma_device_uninit(&device); + ma_waveform_uninit(&feed.wave); + EXPECT_EQ(ma_context_uninit(&context), MA_SUCCESS); +} + +TEST(Api, WaveformAndNoise) { + const ma_waveform_config config = ma_waveform_config_init(ma_format_f32, 1, 48000, ma_waveform_type_sine, 0.5, 480); + ma_waveform wave; + ASSERT_EQ(ma_waveform_init(&config, &wave), MA_SUCCESS); + std::vector s(4800); // 0.1 s: 48 periods + ma_uint64 read = 0; + ASSERT_EQ(ma_waveform_read_pcm_frames(&wave, s.data(), s.size(), &read), MA_SUCCESS); + EXPECT_EQ(read, s.size()); + EXPECT_NEAR(peak(s), 0.5f, 1e-3f); + EXPECT_NEAR(zero_crossings(s), 96, 1); + ma_waveform_uninit(&wave); + + // White noise from a seed is the same sequence each time. + const ma_noise_config noiseConfig = [] { + ma_noise_config c = ma_noise_config_init(ma_format_f32, 1, ma_noise_type_white, 1234, 0.5); + return c; + }(); + std::array, 2> runs; + for (auto& run : runs) { + ma_noise noise; + ASSERT_EQ(ma_noise_init(&noiseConfig, nullptr, &noise), MA_SUCCESS); + run.resize(256); + ASSERT_EQ(ma_noise_read_pcm_frames(&noise, run.data(), run.size(), nullptr), MA_SUCCESS); + ma_noise_uninit(&noise, nullptr); + } + EXPECT_EQ(runs[0], runs[1]); + EXPECT_LE(peak(runs[0]), 0.5f); + EXPECT_GT(peak(runs[0]), 0.1f); +} + +TEST(Api, EncodeWavIntoMemoryAndDecodeIt) { + struct Sink { + std::vector bytes; + std::size_t at = 0; + } sink; + const auto write = [](ma_encoder* e, const void* data, std::size_t n, std::size_t* written) -> ma_result { + auto* s = static_cast(e->pUserData); + if (s->bytes.size() < s->at + n) s->bytes.resize(s->at + n); + std::memcpy(s->bytes.data() + s->at, data, n); + s->at += n; + *written = n; + return MA_SUCCESS; + }; + const auto seek = [](ma_encoder* e, ma_int64 offset, ma_seek_origin origin) -> ma_result { + auto* s = static_cast(e->pUserData); + const ma_int64 base = origin == ma_seek_origin_start ? 0 : origin == ma_seek_origin_current + ? static_cast(s->at) : static_cast(s->bytes.size()); + s->at = static_cast(base + offset); + return MA_SUCCESS; + }; + std::vector pcm(2 * 1000); + for (std::size_t i = 0; i < pcm.size(); ++i) pcm[i] = static_cast((i * 37) % 20000 - 10000); + + const ma_encoder_config config = ma_encoder_config_init(ma_encoding_format_wav, ma_format_s16, 2, 22050); + ma_encoder encoder; + ASSERT_EQ(ma_encoder_init(write, seek, &sink, &config, &encoder), MA_SUCCESS); + ma_uint64 written = 0; + ASSERT_EQ(ma_encoder_write_pcm_frames(&encoder, pcm.data(), 1000, &written), MA_SUCCESS); + EXPECT_EQ(written, 1000u); + ma_encoder_uninit(&encoder); + ASSERT_EQ(sink.bytes.size(), 44u + pcm.size() * 2); + EXPECT_EQ(std::string_view(reinterpret_cast(sink.bytes.data()), 4), "RIFF"); + EXPECT_EQ(std::string_view(reinterpret_cast(sink.bytes.data()) + 8, 4), "WAVE"); + + ma_decoder_config dconfig = ma_decoder_config_init(ma_format_s16, 0, 0); // the file's own channels and rate + ma_decoder decoder; + ASSERT_EQ(ma_decoder_init_memory(sink.bytes.data(), sink.bytes.size(), &dconfig, &decoder), MA_SUCCESS); + ma_format format; + ma_uint32 channels = 0, rate = 0; + ASSERT_EQ(ma_decoder_get_data_format(&decoder, &format, &channels, &rate, nullptr, 0), MA_SUCCESS); + EXPECT_EQ(format, ma_format_s16); + EXPECT_EQ(channels, 2u); + EXPECT_EQ(rate, 22050u); + ma_uint64 length = 0; + ASSERT_EQ(ma_decoder_get_length_in_pcm_frames(&decoder, &length), MA_SUCCESS); + EXPECT_EQ(length, 1000u); + EXPECT_EQ(decode_s16(decoder), pcm); + ma_decoder_uninit(&decoder); +} + +TEST(Api, DecodeWavFlacMp3FromMemory) { + const auto wav = decode_memory(fixture_tone_wav, sizeof fixture_tone_wav, ma_encoding_format_wav); + const auto flac = decode_memory(fixture_tone_flac, sizeof fixture_tone_flac, ma_encoding_format_flac); + const auto mp3 = decode_memory(fixture_tone_mp3, sizeof fixture_tone_mp3, ma_encoding_format_mp3); + ASSERT_EQ(wav.size(), kToneFrames); + EXPECT_EQ(flac, wav); // lossless + // The MP3 is lossy and framed (1152 samples a frame, an encoder delay): the + // same tone, about as long, at about the same level. + ASSERT_GE(mp3.size(), kToneFrames - 1152); + ASSERT_LE(mp3.size(), kToneFrames + 2 * 1152); + std::vector a(wav.begin(), wav.end()), b(mp3.begin(), mp3.end()); + for (float& v : a) v /= 32768; + for (float& v : b) v /= 32768; + EXPECT_NEAR(peak(b), peak(a), 0.08f); + EXPECT_NEAR(zero_crossings(b), zero_crossings(a), 4); + // Any format, recognised from the bytes. + EXPECT_EQ(decode_memory(fixture_tone_flac, sizeof fixture_tone_flac, ma_encoding_format_unknown), wav); +} + +TEST(Api, DecodeFromAFile) { + const auto path = (std::filesystem::temp_directory_path() / "mwrap-miniaudio-tone.flac").string(); + { + std::ofstream out(path, std::ios::binary); + out.write(reinterpret_cast(fixture_tone_flac), sizeof fixture_tone_flac); + } + const ma_decoder_config config = ma_decoder_config_init(ma_format_s16, 0, 0); + ma_decoder decoder; + ASSERT_EQ(ma_decoder_init_file(path.c_str(), &config, &decoder), MA_SUCCESS); + EXPECT_EQ(decoder.outputFormat, ma_format_s16); + EXPECT_EQ(decoder.outputChannels, 1u); + EXPECT_EQ(decoder.outputSampleRate, kToneRate); + EXPECT_EQ(decode_s16(decoder), decode_memory(fixture_tone_wav, sizeof fixture_tone_wav, ma_encoding_format_wav)); + ma_decoder_uninit(&decoder); + std::filesystem::remove(path); +} + +TEST(Api, ResamplerAndConverters) { + // 0.1 s at 48 kHz becomes 0.1 s at 44.1 kHz. + const ma_resampler_config rconfig = ma_resampler_config_init(ma_format_f32, 1, 48000, 44100, ma_resample_algorithm_linear); + ma_resampler resampler; + ASSERT_EQ(ma_resampler_init(&rconfig, nullptr, &resampler), MA_SUCCESS); + ma_uint64 expected = 0; + ASSERT_EQ(ma_resampler_get_expected_output_frame_count(&resampler, 4800, &expected), MA_SUCCESS); + EXPECT_NEAR(static_cast(expected), 4410.0, 1.0); + std::vector in(4800, 0.25f), out(4500); + ma_uint64 frameCountIn = in.size(), frameCountOut = out.size(); + ASSERT_EQ(ma_resampler_process_pcm_frames(&resampler, in.data(), &frameCountIn, out.data(), &frameCountOut), MA_SUCCESS); + EXPECT_EQ(frameCountIn, 4800u); + EXPECT_NEAR(static_cast(frameCountOut), 4410.0, 2.0); + EXPECT_NEAR(out[frameCountOut / 2], 0.25f, 1e-4f); + ma_resampler_uninit(&resampler, nullptr); + + // f32 stereo at 48 kHz to s16 mono at 44.1 kHz in one converter. + const ma_data_converter_config cconfig = ma_data_converter_config_init(ma_format_f32, ma_format_s16, 2, 1, 48000, 44100); + ma_data_converter converter; + ASSERT_EQ(ma_data_converter_init(&cconfig, nullptr, &converter), MA_SUCCESS); + std::vector stereo(2 * 4800, 0.5f); + std::vector mono(4500); + frameCountIn = 4800; + frameCountOut = mono.size(); + ASSERT_EQ(ma_data_converter_process_pcm_frames(&converter, stereo.data(), &frameCountIn, mono.data(), &frameCountOut), MA_SUCCESS); + EXPECT_NEAR(static_cast(frameCountOut), 4410.0, 2.0); + EXPECT_NEAR(mono[frameCountOut / 2], 16384, 2); // 0.5 in both channels: 0.5 in the mix + ma_data_converter_uninit(&converter, nullptr); + + // Mono to stereo duplicates the channel. + const ma_channel_converter_config chconfig = ma_channel_converter_config_init(ma_format_f32, 1, nullptr, 2, nullptr, ma_channel_mix_mode_default); + ma_channel_converter channels; + ASSERT_EQ(ma_channel_converter_init(&chconfig, nullptr, &channels), MA_SUCCESS); + const float one[3] = {0.1f, -0.2f, 0.3f}; + float two[6] = {}; + ASSERT_EQ(ma_channel_converter_process_pcm_frames(&channels, two, one, 3), MA_SUCCESS); + for (int i = 0; i < 3; ++i) { + EXPECT_FLOAT_EQ(two[2 * i], one[i]); + EXPECT_FLOAT_EQ(two[2 * i + 1], one[i]); + } + ma_channel_converter_uninit(&channels, nullptr); + + // And sample formats on their own. + float f[2] = {0.5f, -1.0f}; + ma_int16 s[2] = {}; + ma_pcm_convert(s, ma_format_s16, f, ma_format_f32, 2, ma_dither_mode_none); + EXPECT_EQ(s[0], 16383); + EXPECT_EQ(s[1], -32767); +} + +TEST(Api, LowPassFilter) { + // A 2nd-order low-pass at 1 kHz passes 100 Hz and attenuates 10 kHz. + const auto through = [](double frequency) { + const ma_lpf_config config = ma_lpf_config_init(ma_format_f32, 1, 48000, 1000, 2); + ma_lpf lpf; + EXPECT_EQ(ma_lpf_init(&config, nullptr, &lpf), MA_SUCCESS); + const ma_waveform_config wc = ma_waveform_config_init(ma_format_f32, 1, 48000, ma_waveform_type_sine, 1.0, frequency); + ma_waveform wave; + ma_waveform_init(&wc, &wave); + std::vector in(9600), out(9600); + ma_waveform_read_pcm_frames(&wave, in.data(), in.size(), nullptr); + ma_lpf_process_pcm_frames(&lpf, out.data(), in.data(), in.size()); + ma_lpf_uninit(&lpf, nullptr); + ma_waveform_uninit(&wave); + return peak(std::span(out).subspan(4800)); + }; + EXPECT_GT(through(100), 0.9f); + EXPECT_LT(through(10000), 0.05f); +} + +TEST(Api, PcmRingBuffer) { + ma_pcm_rb rb; + ASSERT_EQ(ma_pcm_rb_init(ma_format_s16, 2, 256, nullptr, nullptr, &rb), MA_SUCCESS); + EXPECT_EQ(ma_pcm_rb_get_subbuffer_size(&rb), 256u); + ma_uint32 frames = 100; + void* p = nullptr; + ASSERT_EQ(ma_pcm_rb_acquire_write(&rb, &frames, &p), MA_SUCCESS); + ASSERT_EQ(frames, 100u); + auto* w = static_cast(p); + for (int i = 0; i < 200; ++i) w[i] = static_cast(i); + ASSERT_EQ(ma_pcm_rb_commit_write(&rb, 100), MA_SUCCESS); + EXPECT_EQ(ma_pcm_rb_available_read(&rb), 100u); + frames = 100; + ASSERT_EQ(ma_pcm_rb_acquire_read(&rb, &frames, &p), MA_SUCCESS); + EXPECT_EQ(static_cast(p)[199], 199); + ASSERT_EQ(ma_pcm_rb_commit_read(&rb, frames), MA_SUCCESS); + EXPECT_EQ(ma_pcm_rb_available_read(&rb), 0u); + ma_pcm_rb_uninit(&rb); +} + +TEST(Api, EngineWithoutADevice) { + // The high-level engine mixes into a caller's buffer when it has no + // device. Its resource manager runs without job threads, as a program + // without threads (the Web) needs. + ma_resource_manager_config rmConfig = ma_resource_manager_config_init(); + rmConfig.flags = MA_RESOURCE_MANAGER_FLAG_NO_THREADING; + rmConfig.jobThreadCount = 0; + ma_resource_manager rm; + ASSERT_EQ(ma_resource_manager_init(&rmConfig, &rm), MA_SUCCESS); + + ma_engine_config config = ma_engine_config_init(); + config.noDevice = MA_TRUE; + config.channels = 2; + config.sampleRate = 48000; + config.pResourceManager = &rm; + ma_engine engine; + ASSERT_EQ(ma_engine_init(&config, &engine), MA_SUCCESS); + EXPECT_EQ(ma_engine_get_channels(&engine), 2u); + EXPECT_EQ(ma_engine_get_sample_rate(&engine), 48000u); + EXPECT_EQ(ma_engine_get_device(&engine), nullptr); + + const ma_waveform_config wc = ma_waveform_config_init(ma_format_f32, 2, 48000, ma_waveform_type_square, 0.5, 100); + ma_waveform wave; + ASSERT_EQ(ma_waveform_init(&wc, &wave), MA_SUCCESS); + ma_sound_group group; + ASSERT_EQ(ma_sound_group_init(&engine, 0, nullptr, &group), MA_SUCCESS); + ma_sound sound; + ASSERT_EQ(ma_sound_init_from_data_source(&engine, &wave, MA_SOUND_FLAG_NO_SPATIALIZATION, &group, &sound), MA_SUCCESS); + ASSERT_EQ(ma_sound_start(&sound), MA_SUCCESS); + EXPECT_EQ(ma_sound_is_playing(&sound), MA_TRUE); + + std::vector mix(2 * 480); + ma_uint64 read = 0; + ASSERT_EQ(ma_engine_read_pcm_frames(&engine, mix.data(), 480, &read), MA_SUCCESS); + EXPECT_EQ(read, 480u); + EXPECT_NEAR(peak(mix), 0.5f, 1e-3f); + EXPECT_EQ(ma_engine_get_time_in_pcm_frames(&engine), 480u); + + ma_sound_group_set_volume(&group, 0.5f); // the group's volume scales its sounds + ASSERT_EQ(ma_engine_read_pcm_frames(&engine, mix.data(), 480, &read), MA_SUCCESS); + EXPECT_NEAR(peak(mix), 0.25f, 1e-3f); + + ma_sound_stop(&sound); // with the engine's short stop fade, then silence + EXPECT_EQ(ma_sound_is_playing(&sound), MA_FALSE); + for (int i = 0; i < 4; ++i) ASSERT_EQ(ma_engine_read_pcm_frames(&engine, mix.data(), 480, &read), MA_SUCCESS); + EXPECT_EQ(peak(mix), 0.0f); + + ma_sound_uninit(&sound); + ma_sound_group_uninit(&group); + ma_waveform_uninit(&wave); + ma_engine_uninit(&engine); + ma_resource_manager_uninit(&rm); +} + +TEST(Api, AdaptedInlineFunctions) { + namespace ma = mcpplibs::mwrap::miniaudio; + EXPECT_EQ(ma::ma_get_bytes_per_frame(ma_format_s16, 2), 4u); + EXPECT_EQ(ma::ma_get_bytes_per_frame(ma_format_f32, 6), 24u); + float frames[8] = {}; + EXPECT_EQ(ma::ma_offset_pcm_frames_ptr_f32(frames, 3, 2), frames + 6); + const float* cframes = frames; + EXPECT_EQ(ma::ma_offset_pcm_frames_const_ptr_f32(cframes, 1, 4), cframes + 4); + EXPECT_EQ(ma_get_bytes_per_sample(ma_format_s24), 3u); +} + +TEST(Api, ResultsAndFormats) { + EXPECT_STREQ(ma_result_description(MA_SUCCESS), "No error"); + EXPECT_EQ(MA_INVALID_ARGS, -2); + EXPECT_STREQ(ma_get_format_name(ma_format_f32), "32-bit IEEE Floating Point"); + static_assert(MA_MAX_CHANNELS == 254 && MA_MIN_CHANNELS == 1); + EXPECT_EQ(sizeof(ma_uint64), 8u); +} diff --git a/tests/data/fixtures.inc b/tests/data/fixtures.inc new file mode 100644 index 0000000..0ae5c4d --- /dev/null +++ b/tests/data/fixtures.inc @@ -0,0 +1,984 @@ +// Generated by tools/gen_fixtures.py from tests/data — do not edit by hand. +inline constexpr unsigned char fixture_tone_wav[8864] = { + 0x52, 0x49, 0x46, 0x46, 0x98, 0x22, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x44, 0xac, 0x00, 0x00, 0x88, 0x58, 0x01, 0x00, 0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, + 0x74, 0x22, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x01, 0x08, 0xf7, 0x0b, 0xe1, 0x0f, 0xbc, 0x13, 0x82, 0x17, 0x31, 0x1b, + 0xc4, 0x1e, 0x39, 0x22, 0x8b, 0x25, 0xb7, 0x28, 0xbb, 0x2b, 0x92, 0x2e, 0x3b, 0x31, 0xb2, 0x33, 0xf5, 0x35, 0x02, 0x38, + 0xd6, 0x39, 0x71, 0x3b, 0xcf, 0x3c, 0xf1, 0x3d, 0xd4, 0x3e, 0x77, 0x3f, 0xdc, 0x3f, 0xff, 0x3f, 0xe3, 0x3f, 0x86, 0x3f, + 0xe9, 0x3e, 0x0d, 0x3e, 0xf3, 0x3c, 0x9b, 0x3b, 0x08, 0x3a, 0x3a, 0x38, 0x33, 0x36, 0xf6, 0x33, 0x85, 0x31, 0xe2, 0x2e, + 0x10, 0x2c, 0x11, 0x29, 0xe9, 0x25, 0x9b, 0x22, 0x2b, 0x1f, 0x9a, 0x1b, 0xef, 0x17, 0x2b, 0x14, 0x52, 0x10, 0x6a, 0x0c, + 0x75, 0x08, 0x77, 0x04, 0x75, 0x00, 0x72, 0xfc, 0x73, 0xf8, 0x7c, 0xf4, 0x90, 0xf0, 0xb3, 0xec, 0xeb, 0xe8, 0x39, 0xe5, + 0xa2, 0xe1, 0x2a, 0xde, 0xd4, 0xda, 0xa3, 0xd7, 0x9b, 0xd4, 0xbe, 0xd1, 0x10, 0xcf, 0x93, 0xcc, 0x4a, 0xca, 0x37, 0xc8, + 0x5c, 0xc6, 0xbb, 0xc4, 0x56, 0xc3, 0x2d, 0xc2, 0x43, 0xc1, 0x98, 0xc0, 0x2d, 0xc0, 0x01, 0xc0, 0x17, 0xc0, 0x6c, 0xc0, + 0x02, 0xc1, 0xd6, 0xc1, 0xea, 0xc2, 0x3a, 0xc4, 0xc7, 0xc5, 0x8f, 0xc7, 0x8f, 0xc9, 0xc6, 0xcb, 0x31, 0xce, 0xcf, 0xd0, + 0x9c, 0xd3, 0x96, 0xd6, 0xb9, 0xd9, 0x03, 0xdd, 0x70, 0xe0, 0xfc, 0xe3, 0xa5, 0xe7, 0x67, 0xeb, 0x3d, 0xef, 0x24, 0xf3, + 0x18, 0xf7, 0x15, 0xfb, 0x17, 0xff, 0x19, 0x03, 0x19, 0x07, 0x11, 0x0b, 0xff, 0x0e, 0xdd, 0x12, 0xa8, 0x16, 0x5d, 0x1a, + 0xf7, 0x1d, 0x73, 0x21, 0xcd, 0x24, 0x02, 0x28, 0x0f, 0x2b, 0xf1, 0x2d, 0xa4, 0x30, 0x27, 0x33, 0x76, 0x35, 0x8f, 0x37, + 0x71, 0x39, 0x19, 0x3b, 0x85, 0x3c, 0xb4, 0x3d, 0xa6, 0x3e, 0x58, 0x3f, 0xca, 0x3f, 0xfd, 0x3f, 0xef, 0x3f, 0xa1, 0x3f, + 0x13, 0x3f, 0x45, 0x3e, 0x39, 0x3d, 0xef, 0x3b, 0x69, 0x3a, 0xa8, 0x38, 0xae, 0x36, 0x7d, 0x34, 0x18, 0x32, 0x80, 0x2f, + 0xb8, 0x2c, 0xc3, 0x29, 0xa4, 0x26, 0x5f, 0x23, 0xf6, 0x1f, 0x6c, 0x1c, 0xc6, 0x18, 0x08, 0x15, 0x34, 0x11, 0x4e, 0x0d, + 0x5c, 0x09, 0x60, 0x05, 0x5e, 0x01, 0x5b, 0xfd, 0x5b, 0xf9, 0x62, 0xf5, 0x73, 0xf1, 0x93, 0xed, 0xc5, 0xe9, 0x0e, 0xe6, + 0x70, 0xe2, 0xf1, 0xde, 0x93, 0xdb, 0x59, 0xd8, 0x47, 0xd5, 0x61, 0xd2, 0xa8, 0xcf, 0x1f, 0xcd, 0xca, 0xca, 0xab, 0xc8, + 0xc3, 0xc6, 0x15, 0xc5, 0xa2, 0xc3, 0x6b, 0xc2, 0x73, 0xc1, 0xb9, 0xc0, 0x3f, 0xc0, 0x06, 0xc0, 0x0c, 0xc0, 0x53, 0xc0, + 0xda, 0xc0, 0xa0, 0xc1, 0xa6, 0xc2, 0xe9, 0xc3, 0x68, 0xc5, 0x22, 0xc7, 0x16, 0xc9, 0x40, 0xcb, 0xa0, 0xcd, 0x32, 0xd0, + 0xf5, 0xd2, 0xe5, 0xd5, 0xff, 0xd8, 0x40, 0xdc, 0xa5, 0xdf, 0x2b, 0xe3, 0xce, 0xe6, 0x8a, 0xea, 0x5c, 0xee, 0x40, 0xf2, + 0x31, 0xf6, 0x2c, 0xfa, 0x2d, 0xfe, 0x30, 0x02, 0x31, 0x06, 0x2b, 0x0a, 0x1c, 0x0e, 0xfe, 0x11, 0xce, 0x15, 0x88, 0x19, + 0x28, 0x1d, 0xab, 0x20, 0x0d, 0x24, 0x4b, 0x27, 0x61, 0x2a, 0x4d, 0x2d, 0x0b, 0x30, 0x99, 0x32, 0xf4, 0x34, 0x1a, 0x37, + 0x08, 0x39, 0xbd, 0x3a, 0x37, 0x3c, 0x75, 0x3d, 0x74, 0x3e, 0x35, 0x3f, 0xb6, 0x3f, 0xf7, 0x3f, 0xf8, 0x3f, 0xb8, 0x3f, + 0x39, 0x3f, 0x79, 0x3e, 0x7b, 0x3d, 0x3f, 0x3c, 0xc7, 0x3a, 0x13, 0x39, 0x26, 0x37, 0x01, 0x35, 0xa8, 0x32, 0x1b, 0x30, + 0x5e, 0x2d, 0x73, 0x2a, 0x5d, 0x27, 0x20, 0x24, 0xbf, 0x20, 0x3d, 0x1d, 0x9d, 0x19, 0xe3, 0x15, 0x14, 0x12, 0x32, 0x0e, + 0x42, 0x0a, 0x48, 0x06, 0x47, 0x02, 0x45, 0xfe, 0x43, 0xfa, 0x48, 0xf6, 0x56, 0xf2, 0x73, 0xee, 0xa0, 0xea, 0xe4, 0xe6, + 0x40, 0xe3, 0xba, 0xdf, 0x54, 0xdc, 0x11, 0xd9, 0xf6, 0xd5, 0x05, 0xd3, 0x42, 0xd0, 0xae, 0xcd, 0x4e, 0xcb, 0x22, 0xc9, + 0x2d, 0xc7, 0x71, 0xc5, 0xf1, 0xc3, 0xac, 0xc2, 0xa6, 0xc1, 0xde, 0xc0, 0x55, 0xc0, 0x0d, 0xc0, 0x05, 0xc0, 0x3d, 0xc0, + 0xb6, 0xc0, 0x6e, 0xc1, 0x65, 0xc2, 0x9a, 0xc3, 0x0c, 0xc5, 0xb9, 0xc6, 0x9f, 0xc8, 0xbd, 0xca, 0x11, 0xcd, 0x98, 0xcf, + 0x50, 0xd2, 0x36, 0xd5, 0x47, 0xd8, 0x7f, 0xdb, 0xdd, 0xde, 0x5c, 0xe2, 0xf8, 0xe5, 0xaf, 0xe9, 0x7c, 0xed, 0x5c, 0xf1, + 0x4b, 0xf5, 0x44, 0xf9, 0x44, 0xfd, 0x47, 0x01, 0x48, 0x05, 0x45, 0x09, 0x37, 0x0d, 0x1d, 0x11, 0xf2, 0x14, 0xb1, 0x18, + 0x57, 0x1c, 0xe1, 0x1f, 0x4b, 0x23, 0x92, 0x26, 0xb1, 0x29, 0xa7, 0x2c, 0x70, 0x2f, 0x09, 0x32, 0x70, 0x34, 0xa2, 0x36, + 0x9d, 0x38, 0x5f, 0x3a, 0xe7, 0x3b, 0x32, 0x3d, 0x40, 0x3e, 0x0f, 0x3f, 0x9e, 0x3f, 0xee, 0x3f, 0xfd, 0x3f, 0xcc, 0x3f, + 0x5b, 0x3f, 0xaa, 0x3e, 0xba, 0x3d, 0x8c, 0x3c, 0x21, 0x3b, 0x7b, 0x39, 0x9b, 0x37, 0x83, 0x35, 0x35, 0x33, 0xb4, 0x30, + 0x01, 0x2e, 0x21, 0x2b, 0x15, 0x28, 0xe0, 0x24, 0x87, 0x21, 0x0c, 0x1e, 0x72, 0x1a, 0xbe, 0x16, 0xf3, 0x12, 0x16, 0x0f, + 0x28, 0x0b, 0x30, 0x07, 0x31, 0x03, 0x2e, 0xff, 0x2c, 0xfb, 0x2f, 0xf7, 0x3b, 0xf3, 0x53, 0xef, 0x7d, 0xeb, 0xbb, 0xe7, + 0x11, 0xe4, 0x84, 0xe0, 0x16, 0xdd, 0xcc, 0xd9, 0xa7, 0xd6, 0xad, 0xd3, 0xdf, 0xd0, 0x40, 0xce, 0xd3, 0xcb, 0x9b, 0xc9, + 0x9a, 0xc7, 0xd1, 0xc5, 0x43, 0xc4, 0xf1, 0xc2, 0xdc, 0xc1, 0x06, 0xc1, 0x6f, 0xc0, 0x18, 0xc0, 0x01, 0xc0, 0x2b, 0xc0, + 0x95, 0xc0, 0x3e, 0xc1, 0x27, 0xc2, 0x4e, 0xc3, 0xb2, 0xc4, 0x52, 0xc6, 0x2c, 0xc8, 0x3d, 0xca, 0x85, 0xcc, 0x01, 0xcf, + 0xae, 0xd1, 0x8a, 0xd4, 0x91, 0xd7, 0xc1, 0xda, 0x16, 0xde, 0x8e, 0xe1, 0x24, 0xe5, 0xd5, 0xe8, 0x9d, 0xec, 0x79, 0xf0, + 0x65, 0xf4, 0x5c, 0xf8, 0x5b, 0xfc, 0x5d, 0x00, 0x60, 0x04, 0x5d, 0x08, 0x53, 0x0c, 0x3c, 0x10, 0x14, 0x14, 0xd9, 0x17, + 0x85, 0x1b, 0x16, 0x1f, 0x88, 0x22, 0xd7, 0x25, 0xff, 0x28, 0xff, 0x2b, 0xd2, 0x2e, 0x76, 0x31, 0xe9, 0x33, 0x27, 0x36, + 0x2f, 0x38, 0xfe, 0x39, 0x93, 0x3b, 0xec, 0x3c, 0x08, 0x3e, 0xe5, 0x3e, 0x83, 0x3f, 0xe1, 0x3f, 0xff, 0x3f, 0xdd, 0x3f, + 0x7a, 0x3f, 0xd8, 0x3e, 0xf6, 0x3d, 0xd6, 0x3c, 0x79, 0x3b, 0xe0, 0x39, 0x0d, 0x38, 0x02, 0x36, 0xc0, 0x33, 0x4a, 0x31, + 0xa2, 0x2e, 0xcc, 0x2b, 0xc9, 0x28, 0x9e, 0x25, 0x4d, 0x22, 0xd9, 0x1e, 0x46, 0x1b, 0x98, 0x17, 0xd2, 0x13, 0xf8, 0x0f, + 0x0e, 0x0c, 0x18, 0x08, 0x1a, 0x04, 0x17, 0x00, 0x15, 0xfc, 0x16, 0xf8, 0x20, 0xf4, 0x35, 0xf0, 0x5b, 0xec, 0x94, 0xe8, + 0xe4, 0xe4, 0x50, 0xe1, 0xdb, 0xdd, 0x88, 0xda, 0x5b, 0xd7, 0x56, 0xd4, 0x7e, 0xd1, 0xd4, 0xce, 0x5c, 0xcc, 0x18, 0xca, + 0x09, 0xc8, 0x34, 0xc6, 0x98, 0xc4, 0x38, 0xc3, 0x15, 0xc2, 0x31, 0xc1, 0x8c, 0xc0, 0x26, 0xc0, 0x01, 0xc0, 0x1c, 0xc0, + 0x77, 0xc0, 0x12, 0xc1, 0xed, 0xc1, 0x06, 0xc3, 0x5c, 0xc4, 0xee, 0xc5, 0xbb, 0xc7, 0xc0, 0xc9, 0xfc, 0xcb, 0x6c, 0xce, + 0x0e, 0xd1, 0xdf, 0xd3, 0xdd, 0xd6, 0x04, 0xda, 0x51, 0xdd, 0xc1, 0xe0, 0x51, 0xe4, 0xfc, 0xe7, 0xbf, 0xeb, 0x97, 0xef, + 0x7f, 0xf3, 0x74, 0xf7, 0x72, 0xfb, 0x74, 0xff, 0x77, 0x03, 0x76, 0x07, 0x6d, 0x0b, 0x5a, 0x0f, 0x36, 0x13, 0x00, 0x17, + 0xb2, 0x1a, 0x49, 0x1e, 0xc2, 0x21, 0x19, 0x25, 0x4b, 0x28, 0x54, 0x2b, 0x32, 0x2e, 0xe1, 0x30, 0x5f, 0x33, 0xa9, 0x35, + 0xbe, 0x37, 0x9a, 0x39, 0x3c, 0x3b, 0xa3, 0x3c, 0xcd, 0x3d, 0xb8, 0x3e, 0x65, 0x3f, 0xd2, 0x3f, 0xfe, 0x3f, 0xeb, 0x3f, + 0x97, 0x3f, 0x03, 0x3f, 0x2f, 0x3e, 0x1d, 0x3d, 0xce, 0x3b, 0x42, 0x3a, 0x7c, 0x38, 0x7d, 0x36, 0x48, 0x34, 0xdd, 0x31, + 0x41, 0x2f, 0x75, 0x2c, 0x7c, 0x29, 0x5a, 0x26, 0x11, 0x23, 0xa5, 0x1f, 0x19, 0x1c, 0x70, 0x18, 0xaf, 0x14, 0xda, 0x10, + 0xf3, 0x0c, 0xff, 0x08, 0x03, 0x05, 0x01, 0x01, 0xfe, 0xfc, 0xfe, 0xf8, 0x06, 0xf5, 0x18, 0xf1, 0x39, 0xed, 0x6d, 0xe9, + 0xb8, 0xe5, 0x1e, 0xe2, 0xa1, 0xde, 0x46, 0xdb, 0x10, 0xd8, 0x02, 0xd5, 0x1f, 0xd2, 0x6b, 0xcf, 0xe7, 0xcc, 0x97, 0xca, + 0x7c, 0xc8, 0x99, 0xc6, 0xf0, 0xc4, 0x83, 0xc3, 0x52, 0xc2, 0x5f, 0xc1, 0xac, 0xc0, 0x37, 0xc0, 0x04, 0xc0, 0x10, 0xc0, + 0x5d, 0xc0, 0xe9, 0xc0, 0xb6, 0xc1, 0xc0, 0xc2, 0x09, 0xc4, 0x8e, 0xc5, 0x4d, 0xc7, 0x46, 0xc9, 0x75, 0xcb, 0xda, 0xcd, + 0x71, 0xd0, 0x37, 0xd3, 0x2b, 0xd6, 0x49, 0xd9, 0x8e, 0xdc, 0xf6, 0xdf, 0x7f, 0xe3, 0x24, 0xe7, 0xe2, 0xea, 0xb6, 0xee, + 0x9b, 0xf2, 0x8d, 0xf6, 0x89, 0xfa, 0x8b, 0xfe, 0x8d, 0x02, 0x8e, 0x06, 0x87, 0x0a, 0x77, 0x0e, 0x57, 0x12, 0x25, 0x16, + 0xdd, 0x19, 0x7b, 0x1d, 0xfb, 0x20, 0x5a, 0x24, 0x95, 0x27, 0xa7, 0x2a, 0x8f, 0x2d, 0x49, 0x30, 0xd2, 0x32, 0x29, 0x35, + 0x49, 0x37, 0x33, 0x39, 0xe2, 0x3a, 0x57, 0x3c, 0x8e, 0x3d, 0x88, 0x3e, 0x43, 0x3f, 0xbf, 0x3f, 0xfa, 0x3f, 0xf5, 0x3f, + 0xaf, 0x3f, 0x2a, 0x3f, 0x65, 0x3e, 0x61, 0x3d, 0x1f, 0x3c, 0xa1, 0x3a, 0xe9, 0x38, 0xf6, 0x36, 0xcd, 0x34, 0x6e, 0x32, + 0xdd, 0x2f, 0x1c, 0x2d, 0x2d, 0x2a, 0x14, 0x27, 0xd3, 0x23, 0x6f, 0x20, 0xea, 0x1c, 0x47, 0x19, 0x8c, 0x15, 0xba, 0x11, + 0xd7, 0x0d, 0xe6, 0x09, 0xeb, 0x05, 0xea, 0x01, 0xe7, 0xfd, 0xe6, 0xf9, 0xec, 0xf5, 0xfb, 0xf1, 0x19, 0xee, 0x48, 0xea, + 0x8e, 0xe6, 0xed, 0xe2, 0x69, 0xdf, 0x06, 0xdc, 0xc7, 0xd8, 0xb0, 0xd5, 0xc3, 0xd2, 0x04, 0xd0, 0x75, 0xcd, 0x19, 0xcb, + 0xf2, 0xc8, 0x02, 0xc7, 0x4c, 0xc5, 0xd1, 0xc3, 0x92, 0xc2, 0x91, 0xc1, 0xcf, 0xc0, 0x4c, 0xc0, 0x0a, 0xc0, 0x07, 0xc0, + 0x46, 0xc0, 0xc4, 0xc0, 0x82, 0xc1, 0x7e, 0xc2, 0xb9, 0xc3, 0x30, 0xc5, 0xe2, 0xc6, 0xce, 0xc8, 0xf1, 0xca, 0x4a, 0xcd, + 0xd6, 0xcf, 0x92, 0xd2, 0x7c, 0xd5, 0x90, 0xd8, 0xcc, 0xdb, 0x2d, 0xdf, 0xaf, 0xe2, 0x4e, 0xe6, 0x07, 0xea, 0xd6, 0xed, + 0xb7, 0xf1, 0xa7, 0xf5, 0xa1, 0xf9, 0xa1, 0xfd, 0xa4, 0x01, 0xa5, 0x05, 0xa1, 0x09, 0x93, 0x0d, 0x77, 0x11, 0x4a, 0x15, + 0x07, 0x19, 0xab, 0x1c, 0x32, 0x20, 0x99, 0x23, 0xdc, 0x26, 0xf8, 0x29, 0xea, 0x2c, 0xaf, 0x2f, 0x43, 0x32, 0xa5, 0x34, + 0xd2, 0x36, 0xc8, 0x38, 0x85, 0x3a, 0x07, 0x3c, 0x4d, 0x3d, 0x55, 0x3e, 0x1e, 0x3f, 0xa8, 0x3f, 0xf2, 0x3f, 0xfc, 0x3f, + 0xc5, 0x3f, 0x4e, 0x3f, 0x97, 0x3e, 0xa1, 0x3d, 0x6e, 0x3c, 0xfe, 0x3a, 0x52, 0x39, 0x6d, 0x37, 0x4f, 0x35, 0xfd, 0x32, + 0x77, 0x30, 0xc0, 0x2d, 0xdb, 0x2a, 0xcc, 0x27, 0x94, 0x24, 0x37, 0x21, 0xb9, 0x1d, 0x1d, 0x1a, 0x67, 0x16, 0x9a, 0x12, + 0xbb, 0x0e, 0xcc, 0x0a, 0xd3, 0x06, 0xd3, 0x02, 0xd1, 0xfe, 0xcf, 0xfa, 0xd3, 0xf6, 0xdf, 0xf2, 0xf9, 0xee, 0x25, 0xeb, + 0x65, 0xe7, 0xbe, 0xe3, 0x33, 0xe0, 0xc8, 0xdc, 0x81, 0xd9, 0x60, 0xd6, 0x6a, 0xd3, 0xa0, 0xd0, 0x05, 0xce, 0x9d, 0xcb, + 0x6a, 0xc9, 0x6e, 0xc7, 0xaa, 0xc5, 0x22, 0xc4, 0xd5, 0xc2, 0xc6, 0xc1, 0xf5, 0xc0, 0x64, 0xc0, 0x13, 0xc0, 0x02, 0xc0, + 0x32, 0xc0, 0xa2, 0xc0, 0x51, 0xc1, 0x3f, 0xc2, 0x6c, 0xc3, 0xd6, 0xc4, 0x7b, 0xc6, 0x59, 0xc8, 0x70, 0xca, 0xbd, 0xcc, + 0x3d, 0xcf, 0xef, 0xd1, 0xce, 0xd4, 0xd9, 0xd7, 0x0d, 0xdb, 0x65, 0xde, 0xe0, 0xe1, 0x79, 0xe5, 0x2c, 0xe9, 0xf6, 0xec, + 0xd4, 0xf0, 0xc1, 0xf4, 0xb9, 0xf8, 0xb8, 0xfc, 0xbb, 0x00, 0xbd, 0x04, 0xba, 0x08, 0xae, 0x0c, 0x96, 0x10, 0x6d, 0x14, + 0x2f, 0x18, 0xda, 0x1b, 0x68, 0x1f, 0xd6, 0x22, 0x22, 0x26, 0x47, 0x29, 0x42, 0x2c, 0x12, 0x2f, 0xb1, 0x31, 0x1f, 0x34, + 0x59, 0x36, 0x5b, 0x38, 0x25, 0x3a, 0xb5, 0x3b, 0x08, 0x3d, 0x1e, 0x3e, 0xf6, 0x3e, 0x8e, 0x3f, 0xe7, 0x3f, 0xff, 0x3f, + 0xd7, 0x3f, 0x6e, 0x3f, 0xc6, 0x3e, 0xdf, 0x3d, 0xb9, 0x3c, 0x57, 0x3b, 0xb8, 0x39, 0xe0, 0x37, 0xcf, 0x35, 0x89, 0x33, + 0x0e, 0x31, 0x62, 0x2e, 0x88, 0x2b, 0x81, 0x28, 0x52, 0x25, 0xfe, 0x21, 0x87, 0x1e, 0xf2, 0x1a, 0x41, 0x17, 0x79, 0x13, + 0x9d, 0x0f, 0xb2, 0x0b, 0xbb, 0x07, 0xbc, 0x03, 0xba, 0xff, 0xb8, 0xfb, 0xba, 0xf7, 0xc4, 0xf3, 0xdb, 0xef, 0x02, 0xec, + 0x3d, 0xe8, 0x90, 0xe4, 0xfe, 0xe0, 0x8c, 0xdd, 0x3c, 0xda, 0x13, 0xd7, 0x12, 0xd4, 0x3e, 0xd1, 0x99, 0xce, 0x25, 0xcc, + 0xe5, 0xc9, 0xdc, 0xc7, 0x0c, 0xc6, 0x76, 0xc4, 0x1b, 0xc3, 0xfe, 0xc1, 0x1f, 0xc1, 0x80, 0xc0, 0x20, 0xc0, 0x01, 0xc0, + 0x21, 0xc0, 0x83, 0xc0, 0x24, 0xc1, 0x04, 0xc2, 0x22, 0xc3, 0x7e, 0xc4, 0x16, 0xc6, 0xe8, 0xc7, 0xf2, 0xc9, 0x33, 0xcc, + 0xa7, 0xce, 0x4e, 0xd1, 0x23, 0xd4, 0x25, 0xd7, 0x4f, 0xda, 0xa0, 0xdd, 0x13, 0xe1, 0xa5, 0xe4, 0x52, 0xe8, 0x18, 0xec, + 0xf1, 0xef, 0xdb, 0xf3, 0xd1, 0xf7, 0xcf, 0xfb, 0xd1, 0xff, 0xd4, 0x03, 0xd2, 0x07, 0xc9, 0x0b, 0xb4, 0x0f, 0x8f, 0x13, + 0x57, 0x17, 0x07, 0x1b, 0x9b, 0x1e, 0x11, 0x22, 0x65, 0x25, 0x93, 0x28, 0x99, 0x2b, 0x72, 0x2e, 0x1d, 0x31, 0x96, 0x33, + 0xdc, 0x35, 0xeb, 0x37, 0xc2, 0x39, 0x5f, 0x3b, 0xc1, 0x3c, 0xe5, 0x3d, 0xcb, 0x3e, 0x71, 0x3f, 0xd8, 0x3f, 0xff, 0x3f, + 0xe6, 0x3f, 0x8c, 0x3f, 0xf2, 0x3e, 0x19, 0x3e, 0x01, 0x3d, 0xac, 0x3b, 0x1c, 0x3a, 0x50, 0x38, 0x4c, 0x36, 0x12, 0x34, + 0xa3, 0x31, 0x02, 0x2f, 0x32, 0x2c, 0x35, 0x29, 0x0f, 0x26, 0xc3, 0x22, 0x53, 0x1f, 0xc5, 0x1b, 0x1a, 0x18, 0x57, 0x14, + 0x7f, 0x10, 0x97, 0x0c, 0xa3, 0x08, 0xa5, 0x04, 0xa3, 0x00, 0xa1, 0xfc, 0xa1, 0xf8, 0xaa, 0xf4, 0xbd, 0xf0, 0xe0, 0xec, + 0x16, 0xe9, 0x63, 0xe5, 0xcb, 0xe1, 0x52, 0xde, 0xfa, 0xda, 0xc7, 0xd7, 0xbd, 0xd4, 0xde, 0xd1, 0x2e, 0xcf, 0xaf, 0xcc, + 0x64, 0xca, 0x4e, 0xc8, 0x70, 0xc6, 0xcd, 0xc4, 0x65, 0xc3, 0x39, 0xc2, 0x4c, 0xc1, 0x9e, 0xc0, 0x30, 0xc0, 0x02, 0xc0, + 0x14, 0xc0, 0x67, 0xc0, 0xf9, 0xc0, 0xcb, 0xc1, 0xdc, 0xc2, 0x2a, 0xc4, 0xb4, 0xc5, 0x79, 0xc7, 0x76, 0xc9, 0xab, 0xcb, + 0x14, 0xce, 0xaf, 0xd0, 0x7a, 0xd3, 0x72, 0xd6, 0x93, 0xd9, 0xdc, 0xdc, 0x47, 0xe0, 0xd2, 0xe3, 0x7a, 0xe7, 0x3b, 0xeb, + 0x10, 0xef, 0xf6, 0xf2, 0xea, 0xf6, 0xe6, 0xfa, 0xe8, 0xfe, 0xeb, 0x02, 0xeb, 0x06, 0xe3, 0x0a, 0xd1, 0x0e, 0xb0, 0x12, + 0x7d, 0x16, 0x32, 0x1a, 0xce, 0x1d, 0x4b, 0x21, 0xa7, 0x24, 0xde, 0x27, 0xed, 0x2a, 0xd0, 0x2d, 0x86, 0x30, 0x0b, 0x33, + 0x5c, 0x35, 0x78, 0x37, 0x5c, 0x39, 0x07, 0x3b, 0x76, 0x3c, 0xa8, 0x3d, 0x9c, 0x3e, 0x51, 0x3f, 0xc7, 0x3f, 0xfc, 0x3f, + 0xf1, 0x3f, 0xa6, 0x3f, 0x1a, 0x3f, 0x50, 0x3e, 0x46, 0x3d, 0xff, 0x3b, 0x7c, 0x3a, 0xbe, 0x38, 0xc6, 0x36, 0x98, 0x34, + 0x35, 0x32, 0x9f, 0x2f, 0xd9, 0x2c, 0xe7, 0x29, 0xca, 0x26, 0x86, 0x23, 0x1e, 0x20, 0x96, 0x1c, 0xf1, 0x18, 0x34, 0x15, + 0x61, 0x11, 0x7c, 0x0d, 0x8a, 0x09, 0x8e, 0x05, 0x8d, 0x01, 0x8a, 0xfd, 0x8a, 0xf9, 0x90, 0xf5, 0xa0, 0xf1, 0xbf, 0xed, + 0xf1, 0xe9, 0x38, 0xe6, 0x9a, 0xe2, 0x19, 0xdf, 0xb9, 0xdb, 0x7e, 0xd8, 0x6a, 0xd5, 0x81, 0xd2, 0xc6, 0xcf, 0x3c, 0xcd, + 0xe4, 0xca, 0xc2, 0xc8, 0xd8, 0xc6, 0x27, 0xc5, 0xb1, 0xc3, 0x78, 0xc2, 0x7d, 0xc1, 0xc0, 0xc0, 0x44, 0xc0, 0x07, 0xc0, + 0x0a, 0xc0, 0x4e, 0xc0, 0xd3, 0xc0, 0x96, 0xc1, 0x98, 0xc2, 0xd9, 0xc3, 0x55, 0xc5, 0x0d, 0xc7, 0xfe, 0xc8, 0x26, 0xcb, + 0x83, 0xcd, 0x13, 0xd0, 0xd4, 0xd2, 0xc2, 0xd5, 0xda, 0xd8, 0x19, 0xdc, 0x7d, 0xdf, 0x02, 0xe3, 0xa3, 0xe6, 0x5e, 0xea, + 0x2f, 0xee, 0x12, 0xf2, 0x03, 0xf6, 0xfe, 0xf9, 0xff, 0xfd, 0x01, 0x02, 0x02, 0x06, 0xfd, 0x09, 0xee, 0x0d, 0xd1, 0x11, + 0xa2, 0x15, 0x5d, 0x19, 0xfe, 0x1c, 0x83, 0x20, 0xe7, 0x23, 0x26, 0x27, 0x3e, 0x2a, 0x2c, 0x2d, 0xed, 0x2f, 0x7d, 0x32, + 0xda, 0x34, 0x02, 0x37, 0xf3, 0x38, 0xab, 0x3a, 0x27, 0x3c, 0x68, 0x3d, 0x6a, 0x3e, 0x2d, 0x3f, 0xb2, 0x3f, 0xf6, 0x3f, + 0xf9, 0x3f, 0xbc, 0x3f, 0x40, 0x3f, 0x83, 0x3e, 0x88, 0x3d, 0x4f, 0x3c, 0xd9, 0x3a, 0x28, 0x39, 0x3e, 0x37, 0x1c, 0x35, + 0xc4, 0x32, 0x3a, 0x30, 0x7f, 0x2d, 0x96, 0x2a, 0x82, 0x27, 0x47, 0x24, 0xe7, 0x20, 0x66, 0x1d, 0xc8, 0x19, 0x0f, 0x16, + 0x41, 0x12, 0x60, 0x0e, 0x70, 0x0a, 0x76, 0x06, 0x76, 0x02, 0x73, 0xfe, 0x72, 0xfa, 0x76, 0xf6, 0x84, 0xf2, 0x9f, 0xee, + 0xcc, 0xea, 0x0f, 0xe7, 0x6a, 0xe3, 0xe2, 0xdf, 0x7a, 0xdc, 0x36, 0xd9, 0x19, 0xd6, 0x27, 0xd3, 0x61, 0xd0, 0xcb, 0xcd, + 0x68, 0xcb, 0x3a, 0xc9, 0x42, 0xc7, 0x84, 0xc5, 0x01, 0xc4, 0xba, 0xc2, 0xb0, 0xc1, 0xe6, 0xc0, 0x5a, 0xc0, 0x0f, 0xc0, + 0x04, 0xc0, 0x39, 0xc0, 0xaf, 0xc0, 0x64, 0xc1, 0x58, 0xc2, 0x8a, 0xc3, 0xf9, 0xc4, 0xa4, 0xc6, 0x88, 0xc8, 0xa4, 0xca, + 0xf5, 0xcc, 0x7a, 0xcf, 0x30, 0xd2, 0x13, 0xd5, 0x22, 0xd8, 0x59, 0xdb, 0xb5, 0xde, 0x32, 0xe2, 0xce, 0xe5, 0x83, 0xe9, + 0x50, 0xed, 0x2f, 0xf1, 0x1d, 0xf5, 0x15, 0xf9, 0x15, 0xfd, 0x18, 0x01, 0x1a, 0x05, 0x16, 0x09, 0x0a, 0x0d, 0xf0, 0x10, + 0xc5, 0x14, 0x86, 0x18, 0x2e, 0x1c, 0xb9, 0x1f, 0x24, 0x23, 0x6d, 0x26, 0x8e, 0x29, 0x86, 0x2c, 0x51, 0x2f, 0xec, 0x31, + 0x55, 0x34, 0x8a, 0x36, 0x87, 0x38, 0x4c, 0x3a, 0xd6, 0x3b, 0x24, 0x3d, 0x35, 0x3e, 0x07, 0x3f, 0x99, 0x3f, 0xec, 0x3f, + 0xfe, 0x3f, 0xd0, 0x3f, 0x62, 0x3f, 0xb4, 0x3e, 0xc7, 0x3d, 0x9b, 0x3c, 0x33, 0x3b, 0x90, 0x39, 0xb2, 0x37, 0x9c, 0x35, + 0x51, 0x33, 0xd2, 0x30, 0x22, 0x2e, 0x43, 0x2b, 0x39, 0x28, 0x06, 0x25, 0xae, 0x21, 0x35, 0x1e, 0x9d, 0x1a, 0xea, 0x16, + 0x20, 0x13, 0x43, 0x0f, 0x56, 0x0b, 0x5f, 0x07, 0x5f, 0x03, 0x5d, 0xff, 0x5b, 0xfb, 0x5d, 0xf7, 0x69, 0xf3, 0x81, 0xef, + 0xa9, 0xeb, 0xe6, 0xe7, 0x3b, 0xe4, 0xad, 0xe0, 0x3d, 0xdd, 0xf1, 0xd9, 0xcb, 0xd6, 0xce, 0xd3, 0xfe, 0xd0, 0x5d, 0xce, + 0xee, 0xcb, 0xb4, 0xc9, 0xb0, 0xc7, 0xe4, 0xc5, 0x54, 0xc4, 0xff, 0xc2, 0xe7, 0xc1, 0x0e, 0xc1, 0x74, 0xc0, 0x1a, 0xc0, + 0x01, 0xc0, 0x28, 0xc0, 0x8f, 0xc0, 0x35, 0xc1, 0x1b, 0xc2, 0x3f, 0xc3, 0xa1, 0xc4, 0x3e, 0xc6, 0x15, 0xc8, 0x24, 0xca, + 0x6a, 0xcc, 0xe3, 0xce, 0x8e, 0xd1, 0x67, 0xd4, 0x6d, 0xd7, 0x9b, 0xda, 0xef, 0xdd, 0x65, 0xe1, 0xf9, 0xe4, 0xa9, 0xe8, + 0x71, 0xec, 0x4c, 0xf0, 0x37, 0xf4, 0x2e, 0xf8, 0x2c, 0xfc, 0x2f, 0x00, 0x31, 0x04, 0x2f, 0x08, 0x25, 0x0c, 0x0f, 0x10, + 0xe8, 0x13, 0xae, 0x17, 0x5b, 0x1b, 0xed, 0x1e, 0x60, 0x22, 0xb1, 0x25, 0xdb, 0x28, 0xdd, 0x2b, 0xb2, 0x2e, 0x59, 0x31, + 0xcd, 0x33, 0x0e, 0x36, 0x18, 0x38, 0xea, 0x39, 0x82, 0x3b, 0xde, 0x3c, 0xfc, 0x3d, 0xdc, 0x3e, 0x7d, 0x3f, 0xdf, 0x3f, + 0xff, 0x3f, 0xe0, 0x3f, 0x80, 0x3f, 0xe1, 0x3e, 0x02, 0x3e, 0xe5, 0x3c, 0x8a, 0x3b, 0xf4, 0x39, 0x24, 0x38, 0x1b, 0x36, + 0xdb, 0x33, 0x67, 0x31, 0xc2, 0x2e, 0xee, 0x2b, 0xed, 0x28, 0xc4, 0x25, 0x74, 0x22, 0x02, 0x1f, 0x70, 0x1b, 0xc3, 0x17, + 0xfe, 0x13, 0x25, 0x10, 0x3c, 0x0c, 0x46, 0x08, 0x48, 0x04, 0x46, 0x00, 0x44, 0xfc, 0x45, 0xf8, 0x4e, 0xf4, 0x63, 0xf0, + 0x87, 0xec, 0xbf, 0xe8, 0x0e, 0xe5, 0x79, 0xe1, 0x02, 0xde, 0xae, 0xda, 0x7f, 0xd7, 0x78, 0xd4, 0x9e, 0xd1, 0xf2, 0xce, + 0x77, 0xcc, 0x31, 0xca, 0x20, 0xc8, 0x48, 0xc6, 0xa9, 0xc4, 0x47, 0xc3, 0x21, 0xc2, 0x3a, 0xc1, 0x92, 0xc0, 0x29, 0xc0, + 0x01, 0xc0, 0x19, 0xc0, 0x72, 0xc0, 0x0a, 0xc1, 0xe2, 0xc1, 0xf8, 0xc2, 0x4b, 0xc4, 0xdb, 0xc5, 0xa5, 0xc7, 0xa7, 0xc9, + 0xe1, 0xcb, 0x4f, 0xce, 0xee, 0xd0, 0xbe, 0xd3, 0xb9, 0xd6, 0xde, 0xd9, 0x2a, 0xdd, 0x98, 0xe0, 0x26, 0xe4, 0xd1, 0xe7, + 0x93, 0xeb, 0x6a, 0xef, 0x52, 0xf3, 0x46, 0xf7, 0x43, 0xfb, 0x45, 0xff, 0x48, 0x03, 0x47, 0x07, 0x3f, 0x0b, 0x2c, 0x0f, + 0x0a, 0x13, 0xd4, 0x16, 0x87, 0x1a, 0x20, 0x1e, 0x9b, 0x21, 0xf3, 0x24, 0x27, 0x28, 0x32, 0x2b, 0x11, 0x2e, 0xc3, 0x30, + 0x43, 0x33, 0x90, 0x35, 0xa7, 0x37, 0x85, 0x39, 0x2a, 0x3b, 0x94, 0x3c, 0xc1, 0x3d, 0xaf, 0x3e, 0x5e, 0x3f, 0xce, 0x3f, + 0xfe, 0x3f, 0xed, 0x3f, 0x9c, 0x3f, 0x0b, 0x3f, 0x3a, 0x3e, 0x2b, 0x3d, 0xde, 0x3b, 0x56, 0x3a, 0x92, 0x38, 0x96, 0x36, + 0x63, 0x34, 0xfb, 0x31, 0x60, 0x2f, 0x96, 0x2c, 0xa0, 0x29, 0x7f, 0x26, 0x38, 0x23, 0xcd, 0x1f, 0x42, 0x1c, 0x9b, 0x18, + 0xdb, 0x14, 0x07, 0x11, 0x21, 0x0d, 0x2d, 0x09, 0x31, 0x05, 0x2f, 0x01, 0x2d, 0xfd, 0x2d, 0xf9, 0x34, 0xf5, 0x45, 0xf1, + 0x66, 0xed, 0x99, 0xe9, 0xe3, 0xe5, 0x47, 0xe2, 0xc9, 0xde, 0x6c, 0xdb, 0x34, 0xd8, 0x25, 0xd5, 0x40, 0xd2, 0x89, 0xcf, + 0x03, 0xcd, 0xb1, 0xca, 0x93, 0xc8, 0xae, 0xc6, 0x02, 0xc5, 0x92, 0xc3, 0x5f, 0xc2, 0x69, 0xc1, 0xb2, 0xc0, 0x3b, 0xc0, + 0x04, 0xc0, 0x0e, 0xc0, 0x58, 0xc0, 0xe2, 0xc0, 0xab, 0xc1, 0xb3, 0xc2, 0xf9, 0xc3, 0x7b, 0xc5, 0x38, 0xc7, 0x2e, 0xc9, + 0x5b, 0xcb, 0xbd, 0xcd, 0x51, 0xd0, 0x16, 0xd3, 0x08, 0xd6, 0x24, 0xd9, 0x67, 0xdc, 0xce, 0xdf, 0x55, 0xe3, 0xf9, 0xe6, + 0xb6, 0xea, 0x89, 0xee, 0x6d, 0xf2, 0x5f, 0xf6, 0x5b, 0xfa, 0x5c, 0xfe, 0x5f, 0x02, 0x5f, 0x06, 0x59, 0x0a, 0x49, 0x0e, + 0x2a, 0x12, 0xf9, 0x15, 0xb2, 0x19, 0x51, 0x1d, 0xd3, 0x20, 0x34, 0x24, 0x70, 0x27, 0x84, 0x2a, 0x6e, 0x2d, 0x2a, 0x30, + 0xb6, 0x32, 0x0f, 0x35, 0x32, 0x37, 0x1e, 0x39, 0xd0, 0x3a, 0x47, 0x3c, 0x82, 0x3d, 0x7e, 0x3e, 0x3c, 0x3f, 0xba, 0x3f, + 0xf9, 0x3f, 0xf6, 0x3f, 0xb4, 0x3f, 0x31, 0x3f, 0x6f, 0x3e, 0x6e, 0x3d, 0x2f, 0x3c, 0xb4, 0x3a, 0xfe, 0x38, 0x0e, 0x37, + 0xe7, 0x34, 0x8b, 0x32, 0xfc, 0x2f, 0x3d, 0x2d, 0x50, 0x2a, 0x39, 0x27, 0xfa, 0x23, 0x97, 0x20, 0x13, 0x1d, 0x72, 0x19, + 0xb8, 0x15, 0xe7, 0x11, 0x05, 0x0e, 0x14, 0x0a, 0x1a, 0x06, 0x19, 0x02, 0x16, 0xfe, 0x15, 0xfa, 0x1a, 0xf6, 0x29, 0xf2, + 0x46, 0xee, 0x74, 0xea, 0xb9, 0xe6, 0x16, 0xe3, 0x91, 0xdf, 0x2d, 0xdc, 0xec, 0xd8, 0xd3, 0xd5, 0xe4, 0xd2, 0x23, 0xd0, + 0x92, 0xcd, 0x33, 0xcb, 0x0a, 0xc9, 0x17, 0xc7, 0x5f, 0xc5, 0xe1, 0xc3, 0x9f, 0xc2, 0x9b, 0xc1, 0xd6, 0xc0, 0x51, 0xc0, + 0x0b, 0xc0, 0x06, 0xc0, 0x41, 0xc0, 0xbd, 0xc0, 0x78, 0xc1, 0x72, 0xc2, 0xa9, 0xc3, 0x1e, 0xc5, 0xcd, 0xc6, 0xb7, 0xc8, + 0xd7, 0xca, 0x2e, 0xcd, 0xb7, 0xcf, 0x71, 0xd2, 0x59, 0xd5, 0x6b, 0xd8, 0xa6, 0xdb, 0x05, 0xdf, 0x85, 0xe2, 0x23, 0xe6, + 0xdb, 0xe9, 0xa9, 0xed, 0x89, 0xf1, 0x79, 0xf5, 0x72, 0xf9, 0x73, 0xfd, 0x75, 0x01, 0x77, 0x05, 0x73, 0x09, 0x65, 0x0d, + 0x4a, 0x11, 0x1e, 0x15, 0xdc, 0x18, 0x81, 0x1c, 0x0a, 0x20, 0x72, 0x23, 0xb7, 0x26, 0xd5, 0x29, 0xc9, 0x2c, 0x8f, 0x2f, + 0x26, 0x32, 0x8b, 0x34, 0xba, 0x36, 0xb3, 0x38, 0x72, 0x3a, 0xf7, 0x3b, 0x40, 0x3d, 0x4a, 0x3e, 0x17, 0x3f, 0xa3, 0x3f, + 0xf0, 0x3f, 0xfc, 0x3f, 0xc9, 0x3f, 0x54, 0x3f, 0xa1, 0x3e, 0xae, 0x3d, 0x7d, 0x3c, 0x10, 0x3b, 0x67, 0x39, 0x84, 0x37, + 0x69, 0x35, 0x19, 0x33, 0x95, 0x30, 0xe1, 0x2d, 0xfe, 0x2a, 0xf0, 0x27, 0xba, 0x24, 0x5f, 0x21, 0xe2, 0x1d, 0x48, 0x1a, + 0x93, 0x16, 0xc7, 0x12, 0xe8, 0x0e, 0xfa, 0x0a, 0x02, 0x07, 0x02, 0x03, 0xff, 0xfe, 0xfd, 0xfa, 0x01, 0xf7, 0x0d, 0xf3, + 0x26, 0xef, 0x51, 0xeb, 0x90, 0xe7, 0xe7, 0xe3, 0x5b, 0xe0, 0xef, 0xdc, 0xa6, 0xd9, 0x84, 0xd6, 0x8b, 0xd3, 0xbf, 0xd0, + 0x23, 0xce, 0xb8, 0xcb, 0x83, 0xc9, 0x84, 0xc7, 0xbe, 0xc5, 0x32, 0xc4, 0xe3, 0xc2, 0xd1, 0xc1, 0xfd, 0xc0, 0x69, 0xc0, + 0x15, 0xc0, 0x02, 0xc0, 0x2e, 0xc0, 0x9b, 0xc0, 0x48, 0xc1, 0x33, 0xc2, 0x5d, 0xc3, 0xc4, 0xc4, 0x66, 0xc6, 0x42, 0xc8, + 0x57, 0xca, 0xa1, 0xcc, 0x1f, 0xcf, 0xce, 0xd1, 0xac, 0xd4, 0xb5, 0xd7, 0xe7, 0xda, 0x3e, 0xde, 0xb7, 0xe1, 0x4e, 0xe5, + 0x00, 0xe9, 0xca, 0xec, 0xa6, 0xf0, 0x93, 0xf4, 0x8a, 0xf8, 0x89, 0xfc, 0x8c, 0x00, 0x8e, 0x04, 0x8c, 0x08, 0x81, 0x0c, + 0x69, 0x10, 0x41, 0x14, 0x04, 0x18, 0xaf, 0x1b, 0x3f, 0x1f, 0xaf, 0x22, 0xfc, 0x25, 0x23, 0x29, 0x21, 0x2c, 0xf2, 0x2e, + 0x94, 0x31, 0x04, 0x34, 0x40, 0x36, 0x45, 0x38, 0x12, 0x3a, 0xa4, 0x3b, 0xfa, 0x3c, 0x13, 0x3e, 0xee, 0x3e, 0x89, 0x3f, + 0xe4, 0x3f, 0xff, 0x3f, 0xda, 0x3f, 0x74, 0x3f, 0xcf, 0x3e, 0xeb, 0x3d, 0xc8, 0x3c, 0x68, 0x3b, 0xcc, 0x39, 0xf7, 0x37, + 0xe8, 0x35, 0xa4, 0x33, 0x2c, 0x31, 0x82, 0x2e, 0xaa, 0x2b, 0xa5, 0x28, 0x78, 0x25, 0x25, 0x22, 0xb0, 0x1e, 0x1c, 0x1b, + 0x6c, 0x17, 0xa5, 0x13, 0xcb, 0x0f, 0xe0, 0x0b, 0xea, 0x07, 0xeb, 0x03, 0xe9, 0xff, 0xe6, 0xfb, 0xe8, 0xf7, 0xf2, 0xf3, + 0x08, 0xf0, 0x2e, 0xec, 0x68, 0xe8, 0xba, 0xe4, 0x27, 0xe1, 0xb3, 0xdd, 0x62, 0xda, 0x37, 0xd7, 0x34, 0xd4, 0x5e, 0xd1, + 0xb6, 0xce, 0x40, 0xcc, 0xfe, 0xc9, 0xf3, 0xc7, 0x20, 0xc6, 0x87, 0xc4, 0x2a, 0xc3, 0x0a, 0xc2, 0x28, 0xc1, 0x86, 0xc0, + 0x23, 0xc0, 0x01, 0xc0, 0x1f, 0xc0, 0x7d, 0xc0, 0x1b, 0xc1, 0xf8, 0xc1, 0x14, 0xc3, 0x6d, 0xc4, 0x02, 0xc6, 0xd1, 0xc7, + 0xd9, 0xc9, 0x17, 0xcc, 0x8a, 0xce, 0x2e, 0xd1, 0x01, 0xd4, 0x01, 0xd7, 0x29, 0xda, 0x78, 0xdd, 0xea, 0xe0, 0x7b, 0xe4, + 0x27, 0xe8, 0xec, 0xeb, 0xc4, 0xef, 0xad, 0xf3, 0xa3, 0xf7, 0xa0, 0xfb, 0xa3, 0xff, 0xa5, 0x03, 0xa4, 0x07, 0x9b, 0x0b, + 0x87, 0x0f, 0x63, 0x13, 0x2b, 0x17, 0xdc, 0x1a, 0x72, 0x1e, 0xea, 0x21, 0x3f, 0x25, 0x6f, 0x28, 0x76, 0x2b, 0x52, 0x2e, + 0xff, 0x30, 0x7b, 0x33, 0xc3, 0x35, 0xd4, 0x37, 0xae, 0x39, 0x4e, 0x3b, 0xb2, 0x3c, 0xd9, 0x3d, 0xc2, 0x3e, 0x6b, 0x3f, + 0xd5, 0x3f, 0xff, 0x3f, 0xe8, 0x3f, 0x91, 0x3f, 0xfa, 0x3e, 0x24, 0x3e, 0x0f, 0x3d, 0xbd, 0x3b, 0x2f, 0x3a, 0x66, 0x38, + 0x65, 0x36, 0x2d, 0x34, 0xc0, 0x31, 0x21, 0x2f, 0x53, 0x2c, 0x59, 0x29, 0x34, 0x26, 0xea, 0x22, 0x7c, 0x1f, 0xef, 0x1b, + 0x45, 0x18, 0x83, 0x14, 0xad, 0x10, 0xc5, 0x0c, 0xd1, 0x08, 0xd4, 0x04, 0xd2, 0x00, 0xcf, 0xfc, 0xd0, 0xf8, 0xd8, 0xf4, + 0xea, 0xf0, 0x0d, 0xed, 0x42, 0xe9, 0x8e, 0xe5, 0xf4, 0xe1, 0x79, 0xde, 0x20, 0xdb, 0xeb, 0xd7, 0xdf, 0xd4, 0xff, 0xd1, + 0x4c, 0xcf, 0xcb, 0xcc, 0x7d, 0xca, 0x65, 0xc8, 0x85, 0xc6, 0xdf, 0xc4, 0x74, 0xc3, 0x46, 0xc2, 0x56, 0xc1, 0xa5, 0xc0, + 0x34, 0xc0, 0x03, 0xc0, 0x12, 0xc0, 0x62, 0xc0, 0xf1, 0xc0, 0xc0, 0xc1, 0xce, 0xc2, 0x19, 0xc4, 0xa1, 0xc5, 0x63, 0xc7, + 0x5e, 0xc9, 0x90, 0xcb, 0xf7, 0xcd, 0x90, 0xd0, 0x59, 0xd3, 0x4f, 0xd6, 0x6e, 0xd9, 0xb5, 0xdc, 0x1f, 0xe0, 0xa9, 0xe3, + 0x4f, 0xe7, 0x0e, 0xeb, 0xe3, 0xee, 0xc9, 0xf2, 0xbb, 0xf6, 0xb8, 0xfa, 0xb9, 0xfe, 0xbc, 0x02, 0xbc, 0x06, 0xb5, 0x0a, + 0xa4, 0x0e, 0x84, 0x12, 0x51, 0x16, 0x08, 0x1a, 0xa4, 0x1d, 0x23, 0x21, 0x81, 0x24, 0xb9, 0x27, 0xca, 0x2a, 0xb0, 0x2d, + 0x68, 0x30, 0xef, 0x32, 0x43, 0x35, 0x61, 0x37, 0x47, 0x39, 0xf4, 0x3a, 0x66, 0x3c, 0x9b, 0x3d, 0x92, 0x3e, 0x4a, 0x3f, + 0xc3, 0x3f, 0xfb, 0x3f, 0xf3, 0x3f, 0xab, 0x3f, 0x22, 0x3f, 0x5a, 0x3e, 0x54, 0x3d, 0x0f, 0x3c, 0x8f, 0x3a, 0xd3, 0x38, + 0xde, 0x36, 0xb2, 0x34, 0x52, 0x32, 0xbe, 0x2f, 0xfb, 0x2c, 0x0a, 0x2a, 0xef, 0x26, 0xac, 0x23, 0x46, 0x20, 0xc0, 0x1c, + 0x1c, 0x19, 0x60, 0x15, 0x8d, 0x11, 0xaa, 0x0d, 0xb8, 0x09, 0xbd, 0x05, 0xbb, 0x01, 0xb9, 0xfd, 0xb8, 0xf9, 0xbe, 0xf5, + 0xce, 0xf1, 0xec, 0xed, 0x1d, 0xea, 0x63, 0xe6, 0xc3, 0xe2, 0x41, 0xdf, 0xe0, 0xdb, 0xa3, 0xd8, 0x8d, 0xd5, 0xa2, 0xd2, + 0xe5, 0xcf, 0x58, 0xcd, 0xff, 0xca, 0xda, 0xc8, 0xed, 0xc6, 0x39, 0xc5, 0xc1, 0xc3, 0x85, 0xc2, 0x87, 0xc1, 0xc7, 0xc0, + 0x48, 0xc0, 0x08, 0xc0, 0x09, 0xc0, 0x4a, 0xc0, 0xcb, 0xc0, 0x8c, 0xc1, 0x8b, 0xc2, 0xc9, 0xc3, 0x43, 0xc5, 0xf8, 0xc6, + 0xe6, 0xc8, 0x0c, 0xcb, 0x67, 0xcd, 0xf5, 0xcf, 0xb3, 0xd2, 0x9f, 0xd5, 0xb5, 0xd8, 0xf3, 0xdb, 0x55, 0xdf, 0xd8, 0xe2, + 0x78, 0xe6, 0x32, 0xea, 0x02, 0xee, 0xe4, 0xf1, 0xd5, 0xf5, 0xcf, 0xf9, 0xd0, 0xfd, 0xd3, 0x01, 0xd4, 0x05, 0xcf, 0x09, + 0xc0, 0x0d, 0xa4, 0x11, 0x76, 0x15, 0x32, 0x19, 0xd5, 0x1c, 0x5b, 0x20, 0xc0, 0x23, 0x01, 0x27, 0x1b, 0x2a, 0x0b, 0x2d, + 0xce, 0x2f, 0x60, 0x32, 0xc0, 0x34, 0xea, 0x36, 0xde, 0x38, 0x98, 0x3a, 0x17, 0x3c, 0x5a, 0x3d, 0x60, 0x3e, 0x26, 0x3f, + 0xad, 0x3f, 0xf4, 0x3f, 0xfa, 0x3f, 0xc1, 0x3f, 0x47, 0x3f, 0x8d, 0x3e, 0x95, 0x3d, 0x5e, 0x3c, 0xeb, 0x3a, 0x3d, 0x39, + 0x55, 0x37, 0x36, 0x35, 0xe1, 0x32, 0x58, 0x30, 0x9f, 0x2d, 0xb9, 0x2a, 0xa7, 0x27, 0x6d, 0x24, 0x0f, 0x21, 0x90, 0x1d, + 0xf2, 0x19, 0x3b, 0x16, 0x6d, 0x12, 0x8d, 0x0e, 0x9e, 0x0a, 0xa5, 0x06, 0xa5, 0x02, 0xa2, 0xfe, 0xa0, 0xfa, 0xa4, 0xf6, + 0xb2, 0xf2, 0xcc, 0xee, 0xf8, 0xea, 0x3a, 0xe7, 0x94, 0xe3, 0x0a, 0xe0, 0xa1, 0xdc, 0x5c, 0xd9, 0x3d, 0xd6, 0x48, 0xd3, + 0x80, 0xd0, 0xe8, 0xcd, 0x83, 0xcb, 0x52, 0xc9, 0x58, 0xc7, 0x97, 0xc5, 0x11, 0xc4, 0xc7, 0xc2, 0xbb, 0xc1, 0xed, 0xc0, + 0x5f, 0xc0, 0x11, 0xc0, 0x03, 0xc0, 0x36, 0xc0, 0xa8, 0xc0, 0x5a, 0xc1, 0x4c, 0xc2, 0x7b, 0xc3, 0xe7, 0xc4, 0x8f, 0xc6, + 0x71, 0xc8, 0x8a, 0xca, 0xd9, 0xcc, 0x5c, 0xcf, 0x0f, 0xd2, 0xf1, 0xd4, 0xfe, 0xd7, 0x33, 0xdb, 0x8d, 0xde, 0x09, 0xe2, + 0xa3, 0xe5, 0x58, 0xe9, 0x23, 0xed, 0x01, 0xf1, 0xef, 0xf4, 0xe7, 0xf8, 0xe7, 0xfc, 0xe9, 0x00, 0xeb, 0x04, 0xe8, 0x08, + 0xdc, 0x0c, 0xc3, 0x10, 0x99, 0x14, 0x5b, 0x18, 0x04, 0x1c, 0x90, 0x1f, 0xfd, 0x22, 0x47, 0x26, 0x6a, 0x29, 0x64, 0x2c, + 0x31, 0x2f, 0xcf, 0x31, 0x3a, 0x34, 0x71, 0x36, 0x71, 0x38, 0x39, 0x3a, 0xc6, 0x3b, 0x16, 0x3d, 0x2a, 0x3e, 0xfe, 0x3e, + 0x94, 0x3f, 0xe9, 0x3f, 0xff, 0x3f, 0xd3, 0x3f, 0x68, 0x3f, 0xbd, 0x3e, 0xd3, 0x3d, 0xaa, 0x3c, 0x45, 0x3b, 0xa4, 0x39, + 0xc9, 0x37, 0xb6, 0x35, 0x6d, 0x33, 0xf0, 0x30, 0x42, 0x2e, 0x65, 0x2b, 0x5d, 0x28, 0x2c, 0x25, 0xd6, 0x21, 0x5e, 0x1e, + 0xc7, 0x1a, 0x15, 0x17, 0x4d, 0x13, 0x70, 0x0f, 0x84, 0x0b, 0x8d, 0x07, 0x8e, 0x03, 0x8b, 0xff, 0x89, 0xfb, 0x8b, 0xf7, + 0x96, 0xf3, 0xae, 0xef, 0xd5, 0xeb, 0x11, 0xe8, 0x66, 0xe4, 0xd5, 0xe0, 0x65, 0xdd, 0x17, 0xda, 0xef, 0xd6, 0xf0, 0xd3, + 0x1e, 0xd1, 0x7b, 0xce, 0x0a, 0xcc, 0xcd, 0xc9, 0xc6, 0xc7, 0xf8, 0xc5, 0x65, 0xc4, 0x0d, 0xc3, 0xf3, 0xc1, 0x17, 0xc1, + 0x7a, 0xc0, 0x1d, 0xc0, 0x01, 0xc0, 0x24, 0xc0, 0x89, 0xc0, 0x2c, 0xc1, 0x0f, 0xc2, 0x31, 0xc3, 0x8f, 0xc4, 0x2a, 0xc6, + 0xfe, 0xc7, 0x0b, 0xca, 0x4e, 0xcc, 0xc5, 0xce, 0x6e, 0xd1, 0x45, 0xd4, 0x49, 0xd7, 0x75, 0xda, 0xc7, 0xdd, 0x3c, 0xe1, + 0xcf, 0xe4, 0x7e, 0xe8, 0x44, 0xec, 0x1f, 0xf0, 0x09, 0xf4, 0xff, 0xf7, 0xfe, 0xfb, 0x00, 0x00, 0x02, 0x04, 0x01, 0x08, + 0xf7, 0x0b, 0xe1, 0x0f, 0xbc, 0x13, 0x82, 0x17, 0x31, 0x1b, 0xc4, 0x1e, 0x39, 0x22, 0x8b, 0x25, 0xb7, 0x28, 0xbb, 0x2b, + 0x92, 0x2e, 0x3b, 0x31, 0xb2, 0x33, 0xf5, 0x35, 0x02, 0x38, 0xd6, 0x39, 0x71, 0x3b, 0xcf, 0x3c, 0xf1, 0x3d, 0xd4, 0x3e, + 0x77, 0x3f, 0xdc, 0x3f, 0xff, 0x3f, 0xe3, 0x3f, 0x86, 0x3f, 0xe9, 0x3e, 0x0d, 0x3e, 0xf3, 0x3c, 0x9b, 0x3b, 0x08, 0x3a, + 0x3a, 0x38, 0x33, 0x36, 0xf6, 0x33, 0x85, 0x31, 0xe2, 0x2e, 0x10, 0x2c, 0x11, 0x29, 0xe9, 0x25, 0x9b, 0x22, 0x2b, 0x1f, + 0x9a, 0x1b, 0xef, 0x17, 0x2b, 0x14, 0x52, 0x10, 0x6a, 0x0c, 0x75, 0x08, 0x77, 0x04, 0x75, 0x00, 0x72, 0xfc, 0x73, 0xf8, + 0x7c, 0xf4, 0x90, 0xf0, 0xb3, 0xec, 0xeb, 0xe8, 0x39, 0xe5, 0xa2, 0xe1, 0x2a, 0xde, 0xd4, 0xda, 0xa3, 0xd7, 0x9b, 0xd4, + 0xbe, 0xd1, 0x10, 0xcf, 0x93, 0xcc, 0x4a, 0xca, 0x37, 0xc8, 0x5c, 0xc6, 0xbb, 0xc4, 0x56, 0xc3, 0x2d, 0xc2, 0x43, 0xc1, + 0x98, 0xc0, 0x2d, 0xc0, 0x01, 0xc0, 0x17, 0xc0, 0x6c, 0xc0, 0x02, 0xc1, 0xd6, 0xc1, 0xea, 0xc2, 0x3a, 0xc4, 0xc7, 0xc5, + 0x8f, 0xc7, 0x8f, 0xc9, 0xc6, 0xcb, 0x31, 0xce, 0xcf, 0xd0, 0x9c, 0xd3, 0x96, 0xd6, 0xb9, 0xd9, 0x03, 0xdd, 0x70, 0xe0, + 0xfc, 0xe3, 0xa5, 0xe7, 0x67, 0xeb, 0x3d, 0xef, 0x24, 0xf3, 0x18, 0xf7, 0x15, 0xfb, 0x17, 0xff, 0x19, 0x03, 0x19, 0x07, + 0x11, 0x0b, 0xff, 0x0e, 0xdd, 0x12, 0xa8, 0x16, 0x5d, 0x1a, 0xf7, 0x1d, 0x73, 0x21, 0xcd, 0x24, 0x02, 0x28, 0x0f, 0x2b, + 0xf1, 0x2d, 0xa4, 0x30, 0x27, 0x33, 0x76, 0x35, 0x8f, 0x37, 0x71, 0x39, 0x19, 0x3b, 0x85, 0x3c, 0xb4, 0x3d, 0xa6, 0x3e, + 0x58, 0x3f, 0xca, 0x3f, 0xfd, 0x3f, 0xef, 0x3f, 0xa1, 0x3f, 0x13, 0x3f, 0x45, 0x3e, 0x39, 0x3d, 0xef, 0x3b, 0x69, 0x3a, + 0xa8, 0x38, 0xae, 0x36, 0x7d, 0x34, 0x18, 0x32, 0x80, 0x2f, 0xb8, 0x2c, 0xc3, 0x29, 0xa4, 0x26, 0x5f, 0x23, 0xf6, 0x1f, + 0x6c, 0x1c, 0xc6, 0x18, 0x08, 0x15, 0x34, 0x11, 0x4e, 0x0d, 0x5c, 0x09, 0x60, 0x05, 0x5e, 0x01, 0x5b, 0xfd, 0x5b, 0xf9, + 0x62, 0xf5, 0x73, 0xf1, 0x93, 0xed, 0xc5, 0xe9, 0x0e, 0xe6, 0x70, 0xe2, 0xf1, 0xde, 0x93, 0xdb, 0x59, 0xd8, 0x47, 0xd5, + 0x61, 0xd2, 0xa8, 0xcf, 0x1f, 0xcd, 0xca, 0xca, 0xab, 0xc8, 0xc3, 0xc6, 0x15, 0xc5, 0xa2, 0xc3, 0x6b, 0xc2, 0x73, 0xc1, + 0xb9, 0xc0, 0x3f, 0xc0, 0x06, 0xc0, 0x0c, 0xc0, 0x53, 0xc0, 0xda, 0xc0, 0xa0, 0xc1, 0xa6, 0xc2, 0xe9, 0xc3, 0x68, 0xc5, + 0x22, 0xc7, 0x16, 0xc9, 0x40, 0xcb, 0xa0, 0xcd, 0x32, 0xd0, 0xf5, 0xd2, 0xe5, 0xd5, 0xff, 0xd8, 0x40, 0xdc, 0xa5, 0xdf, + 0x2b, 0xe3, 0xce, 0xe6, 0x8a, 0xea, 0x5c, 0xee, 0x40, 0xf2, 0x31, 0xf6, 0x2c, 0xfa, 0x2d, 0xfe, 0x30, 0x02, 0x31, 0x06, + 0x2b, 0x0a, 0x1c, 0x0e, 0xfe, 0x11, 0xce, 0x15, 0x88, 0x19, 0x28, 0x1d, 0xab, 0x20, 0x0d, 0x24, 0x4b, 0x27, 0x61, 0x2a, + 0x4d, 0x2d, 0x0b, 0x30, 0x99, 0x32, 0xf4, 0x34, 0x1a, 0x37, 0x08, 0x39, 0xbd, 0x3a, 0x37, 0x3c, 0x75, 0x3d, 0x74, 0x3e, + 0x35, 0x3f, 0xb6, 0x3f, 0xf7, 0x3f, 0xf8, 0x3f, 0xb8, 0x3f, 0x39, 0x3f, 0x79, 0x3e, 0x7b, 0x3d, 0x3f, 0x3c, 0xc7, 0x3a, + 0x13, 0x39, 0x26, 0x37, 0x01, 0x35, 0xa8, 0x32, 0x1b, 0x30, 0x5e, 0x2d, 0x73, 0x2a, 0x5d, 0x27, 0x20, 0x24, 0xbf, 0x20, + 0x3d, 0x1d, 0x9d, 0x19, 0xe3, 0x15, 0x14, 0x12, 0x32, 0x0e, 0x42, 0x0a, 0x48, 0x06, 0x47, 0x02, 0x45, 0xfe, 0x43, 0xfa, + 0x48, 0xf6, 0x56, 0xf2, 0x73, 0xee, 0xa0, 0xea, 0xe4, 0xe6, 0x40, 0xe3, 0xba, 0xdf, 0x54, 0xdc, 0x11, 0xd9, 0xf6, 0xd5, + 0x05, 0xd3, 0x42, 0xd0, 0xae, 0xcd, 0x4e, 0xcb, 0x22, 0xc9, 0x2d, 0xc7, 0x71, 0xc5, 0xf1, 0xc3, 0xac, 0xc2, 0xa6, 0xc1, + 0xde, 0xc0, 0x55, 0xc0, 0x0d, 0xc0, 0x05, 0xc0, 0x3d, 0xc0, 0xb6, 0xc0, 0x6e, 0xc1, 0x65, 0xc2, 0x9a, 0xc3, 0x0c, 0xc5, + 0xb9, 0xc6, 0x9f, 0xc8, 0xbd, 0xca, 0x11, 0xcd, 0x98, 0xcf, 0x50, 0xd2, 0x36, 0xd5, 0x47, 0xd8, 0x7f, 0xdb, 0xdd, 0xde, + 0x5c, 0xe2, 0xf8, 0xe5, 0xaf, 0xe9, 0x7c, 0xed, 0x5c, 0xf1, 0x4b, 0xf5, 0x44, 0xf9, 0x44, 0xfd, 0x47, 0x01, 0x48, 0x05, + 0x45, 0x09, 0x37, 0x0d, 0x1d, 0x11, 0xf2, 0x14, 0xb1, 0x18, 0x57, 0x1c, 0xe1, 0x1f, 0x4b, 0x23, 0x92, 0x26, 0xb1, 0x29, + 0xa7, 0x2c, 0x70, 0x2f, 0x09, 0x32, 0x70, 0x34, 0xa2, 0x36, 0x9d, 0x38, 0x5f, 0x3a, 0xe7, 0x3b, 0x32, 0x3d, 0x40, 0x3e, + 0x0f, 0x3f, 0x9e, 0x3f, 0xee, 0x3f, 0xfd, 0x3f, 0xcc, 0x3f, 0x5b, 0x3f, 0xaa, 0x3e, 0xba, 0x3d, 0x8c, 0x3c, 0x21, 0x3b, + 0x7b, 0x39, 0x9b, 0x37, 0x83, 0x35, 0x35, 0x33, 0xb4, 0x30, 0x01, 0x2e, 0x21, 0x2b, 0x15, 0x28, 0xe0, 0x24, 0x87, 0x21, + 0x0c, 0x1e, 0x72, 0x1a, 0xbe, 0x16, 0xf3, 0x12, 0x16, 0x0f, 0x28, 0x0b, 0x30, 0x07, 0x31, 0x03, 0x2e, 0xff, 0x2c, 0xfb, + 0x2f, 0xf7, 0x3b, 0xf3, 0x53, 0xef, 0x7d, 0xeb, 0xbb, 0xe7, 0x11, 0xe4, 0x84, 0xe0, 0x16, 0xdd, 0xcc, 0xd9, 0xa7, 0xd6, + 0xad, 0xd3, 0xdf, 0xd0, 0x40, 0xce, 0xd3, 0xcb, 0x9b, 0xc9, 0x9a, 0xc7, 0xd1, 0xc5, 0x43, 0xc4, 0xf1, 0xc2, 0xdc, 0xc1, + 0x06, 0xc1, 0x6f, 0xc0, 0x18, 0xc0, 0x01, 0xc0, 0x2b, 0xc0, 0x95, 0xc0, 0x3e, 0xc1, 0x27, 0xc2, 0x4e, 0xc3, 0xb2, 0xc4, + 0x52, 0xc6, 0x2c, 0xc8, 0x3d, 0xca, 0x85, 0xcc, 0x01, 0xcf, 0xae, 0xd1, 0x8a, 0xd4, 0x91, 0xd7, 0xc1, 0xda, 0x16, 0xde, + 0x8e, 0xe1, 0x24, 0xe5, 0xd5, 0xe8, 0x9d, 0xec, 0x79, 0xf0, 0x65, 0xf4, 0x5c, 0xf8, 0x5b, 0xfc, 0x5d, 0x00, 0x60, 0x04, + 0x5d, 0x08, 0x53, 0x0c, 0x3c, 0x10, 0x14, 0x14, 0xd9, 0x17, 0x85, 0x1b, 0x16, 0x1f, 0x88, 0x22, 0xd7, 0x25, 0xff, 0x28, + 0xff, 0x2b, 0xd2, 0x2e, 0x76, 0x31, 0xe9, 0x33, 0x27, 0x36, 0x2f, 0x38, 0xfe, 0x39, 0x93, 0x3b, 0xec, 0x3c, 0x08, 0x3e, + 0xe5, 0x3e, 0x83, 0x3f, 0xe1, 0x3f, 0xff, 0x3f, 0xdd, 0x3f, 0x7a, 0x3f, 0xd8, 0x3e, 0xf6, 0x3d, 0xd6, 0x3c, 0x79, 0x3b, + 0xe0, 0x39, 0x0d, 0x38, 0x02, 0x36, 0xc0, 0x33, 0x4a, 0x31, 0xa2, 0x2e, 0xcc, 0x2b, 0xc9, 0x28, 0x9e, 0x25, 0x4d, 0x22, + 0xd9, 0x1e, 0x46, 0x1b, 0x98, 0x17, 0xd2, 0x13, 0xf8, 0x0f, 0x0e, 0x0c, 0x18, 0x08, 0x1a, 0x04, 0x17, 0x00, 0x15, 0xfc, + 0x16, 0xf8, 0x20, 0xf4, 0x35, 0xf0, 0x5b, 0xec, 0x94, 0xe8, 0xe4, 0xe4, 0x50, 0xe1, 0xdb, 0xdd, 0x88, 0xda, 0x5b, 0xd7, + 0x56, 0xd4, 0x7e, 0xd1, 0xd4, 0xce, 0x5c, 0xcc, 0x18, 0xca, 0x09, 0xc8, 0x34, 0xc6, 0x98, 0xc4, 0x38, 0xc3, 0x15, 0xc2, + 0x31, 0xc1, 0x8c, 0xc0, 0x26, 0xc0, 0x01, 0xc0, 0x1c, 0xc0, 0x77, 0xc0, 0x12, 0xc1, 0xed, 0xc1, 0x06, 0xc3, 0x5c, 0xc4, + 0xee, 0xc5, 0xbb, 0xc7, 0xc0, 0xc9, 0xfc, 0xcb, 0x6c, 0xce, 0x0e, 0xd1, 0xdf, 0xd3, 0xdd, 0xd6, 0x04, 0xda, 0x51, 0xdd, + 0xc1, 0xe0, 0x51, 0xe4, 0xfc, 0xe7, 0xbf, 0xeb, 0x97, 0xef, 0x7f, 0xf3, 0x74, 0xf7, 0x72, 0xfb, 0x74, 0xff, 0x77, 0x03, + 0x76, 0x07, 0x6d, 0x0b, 0x5a, 0x0f, 0x36, 0x13, 0x00, 0x17, 0xb2, 0x1a, 0x49, 0x1e, 0xc2, 0x21, 0x19, 0x25, 0x4b, 0x28, + 0x54, 0x2b, 0x32, 0x2e, 0xe1, 0x30, 0x5f, 0x33, 0xa9, 0x35, 0xbe, 0x37, 0x9a, 0x39, 0x3c, 0x3b, 0xa3, 0x3c, 0xcd, 0x3d, + 0xb8, 0x3e, 0x65, 0x3f, 0xd2, 0x3f, 0xfe, 0x3f, 0xeb, 0x3f, 0x97, 0x3f, 0x03, 0x3f, 0x2f, 0x3e, 0x1d, 0x3d, 0xce, 0x3b, + 0x42, 0x3a, 0x7c, 0x38, 0x7d, 0x36, 0x48, 0x34, 0xdd, 0x31, 0x41, 0x2f, 0x75, 0x2c, 0x7c, 0x29, 0x5a, 0x26, 0x11, 0x23, + 0xa5, 0x1f, 0x19, 0x1c, 0x70, 0x18, 0xaf, 0x14, 0xda, 0x10, 0xf3, 0x0c, 0xff, 0x08, 0x03, 0x05, 0x01, 0x01, 0xfe, 0xfc, + 0xfe, 0xf8, 0x06, 0xf5, 0x18, 0xf1, 0x39, 0xed, 0x6d, 0xe9, 0xb8, 0xe5, 0x1e, 0xe2, 0xa1, 0xde, 0x46, 0xdb, 0x10, 0xd8, + 0x02, 0xd5, 0x1f, 0xd2, 0x6b, 0xcf, 0xe7, 0xcc, 0x97, 0xca, 0x7c, 0xc8, 0x99, 0xc6, 0xf0, 0xc4, 0x83, 0xc3, 0x52, 0xc2, + 0x5f, 0xc1, 0xac, 0xc0, 0x37, 0xc0, 0x04, 0xc0, 0x10, 0xc0, 0x5d, 0xc0, 0xe9, 0xc0, 0xb6, 0xc1, 0xc0, 0xc2, 0x09, 0xc4, + 0x8e, 0xc5, 0x4d, 0xc7, 0x46, 0xc9, 0x75, 0xcb, 0xda, 0xcd, 0x71, 0xd0, 0x37, 0xd3, 0x2b, 0xd6, 0x49, 0xd9, 0x8e, 0xdc, + 0xf6, 0xdf, 0x7f, 0xe3, 0x24, 0xe7, 0xe2, 0xea, 0xb6, 0xee, 0x9b, 0xf2, 0x8d, 0xf6, 0x89, 0xfa, 0x8b, 0xfe, 0x8d, 0x02, + 0x8e, 0x06, 0x87, 0x0a, 0x77, 0x0e, 0x57, 0x12, 0x25, 0x16, 0xdd, 0x19, 0x7b, 0x1d, 0xfb, 0x20, 0x5a, 0x24, 0x95, 0x27, + 0xa7, 0x2a, 0x8f, 0x2d, 0x49, 0x30, 0xd2, 0x32, 0x29, 0x35, 0x49, 0x37, 0x33, 0x39, 0xe2, 0x3a, 0x57, 0x3c, 0x8e, 0x3d, + 0x88, 0x3e, 0x43, 0x3f, 0xbf, 0x3f, 0xfa, 0x3f, 0xf5, 0x3f, 0xaf, 0x3f, 0x2a, 0x3f, 0x65, 0x3e, 0x61, 0x3d, 0x1f, 0x3c, + 0xa1, 0x3a, 0xe9, 0x38, 0xf6, 0x36, 0xcd, 0x34, 0x6e, 0x32, 0xdd, 0x2f, 0x1c, 0x2d, 0x2d, 0x2a, 0x14, 0x27, 0xd3, 0x23, + 0x6f, 0x20, 0xea, 0x1c, 0x47, 0x19, 0x8c, 0x15, 0xba, 0x11, 0xd7, 0x0d, 0xe6, 0x09, 0xeb, 0x05, 0xea, 0x01, 0xe7, 0xfd, + 0xe6, 0xf9, 0xec, 0xf5, 0xfb, 0xf1, 0x19, 0xee, 0x48, 0xea, 0x8e, 0xe6, 0xed, 0xe2, 0x69, 0xdf, 0x06, 0xdc, 0xc7, 0xd8, + 0xb0, 0xd5, 0xc3, 0xd2, 0x04, 0xd0, 0x75, 0xcd, 0x19, 0xcb, 0xf2, 0xc8, 0x02, 0xc7, 0x4c, 0xc5, 0xd1, 0xc3, 0x92, 0xc2, + 0x91, 0xc1, 0xcf, 0xc0, 0x4c, 0xc0, 0x0a, 0xc0, 0x07, 0xc0, 0x46, 0xc0, 0xc4, 0xc0, 0x82, 0xc1, 0x7e, 0xc2, 0xb9, 0xc3, + 0x30, 0xc5, 0xe2, 0xc6, 0xce, 0xc8, 0xf1, 0xca, 0x4a, 0xcd, 0xd6, 0xcf, 0x92, 0xd2, 0x7c, 0xd5, 0x90, 0xd8, 0xcc, 0xdb, + 0x2d, 0xdf, 0xaf, 0xe2, 0x4e, 0xe6, 0x07, 0xea, 0xd6, 0xed, 0xb7, 0xf1, 0xa7, 0xf5, 0xa1, 0xf9, 0xa1, 0xfd, 0xa4, 0x01, + 0xa5, 0x05, 0xa1, 0x09, 0x93, 0x0d, 0x77, 0x11, 0x4a, 0x15, 0x07, 0x19, 0xab, 0x1c, 0x32, 0x20, 0x99, 0x23, 0xdc, 0x26, + 0xf8, 0x29, 0xea, 0x2c, 0xaf, 0x2f, 0x43, 0x32, 0xa5, 0x34, 0xd2, 0x36, 0xc8, 0x38, 0x85, 0x3a, 0x07, 0x3c, 0x4d, 0x3d, + 0x55, 0x3e, 0x1e, 0x3f, 0xa8, 0x3f, 0xf2, 0x3f, 0xfc, 0x3f, 0xc5, 0x3f, 0x4e, 0x3f, 0x97, 0x3e, 0xa1, 0x3d, 0x6e, 0x3c, + 0xfe, 0x3a, 0x52, 0x39, 0x6d, 0x37, 0x4f, 0x35, 0xfd, 0x32, 0x77, 0x30, 0xc0, 0x2d, 0xdb, 0x2a, 0xcc, 0x27, 0x94, 0x24, + 0x37, 0x21, 0xb9, 0x1d, 0x1d, 0x1a, 0x67, 0x16, 0x9a, 0x12, 0xbb, 0x0e, 0xcc, 0x0a, 0xd3, 0x06, 0xd3, 0x02, 0xd1, 0xfe, + 0xcf, 0xfa, 0xd3, 0xf6, 0xdf, 0xf2, 0xf9, 0xee, 0x25, 0xeb, 0x65, 0xe7, 0xbe, 0xe3, 0x33, 0xe0, 0xc8, 0xdc, 0x81, 0xd9, + 0x60, 0xd6, 0x6a, 0xd3, 0xa0, 0xd0, 0x05, 0xce, 0x9d, 0xcb, 0x6a, 0xc9, 0x6e, 0xc7, 0xaa, 0xc5, 0x22, 0xc4, 0xd5, 0xc2, + 0xc6, 0xc1, 0xf5, 0xc0, 0x64, 0xc0, 0x13, 0xc0, 0x02, 0xc0, 0x32, 0xc0, 0xa2, 0xc0, 0x51, 0xc1, 0x3f, 0xc2, 0x6c, 0xc3, + 0xd6, 0xc4, 0x7b, 0xc6, 0x59, 0xc8, 0x70, 0xca, 0xbd, 0xcc, 0x3d, 0xcf, 0xef, 0xd1, 0xce, 0xd4, 0xd9, 0xd7, 0x0d, 0xdb, + 0x65, 0xde, 0xe0, 0xe1, 0x79, 0xe5, 0x2c, 0xe9, 0xf6, 0xec, 0xd4, 0xf0, 0xc1, 0xf4, 0xb9, 0xf8, 0xb8, 0xfc, 0xbb, 0x00, + 0xbd, 0x04, 0xba, 0x08, 0xae, 0x0c, 0x96, 0x10, 0x6d, 0x14, 0x2f, 0x18, 0xda, 0x1b, 0x68, 0x1f, 0xd6, 0x22, 0x22, 0x26, + 0x47, 0x29, 0x42, 0x2c, 0x12, 0x2f, 0xb1, 0x31, 0x1f, 0x34, 0x59, 0x36, 0x5b, 0x38, 0x25, 0x3a, 0xb5, 0x3b, 0x08, 0x3d, + 0x1e, 0x3e, 0xf6, 0x3e, 0x8e, 0x3f, 0xe7, 0x3f, 0xff, 0x3f, 0xd7, 0x3f, 0x6e, 0x3f, 0xc6, 0x3e, 0xdf, 0x3d, 0xb9, 0x3c, + 0x57, 0x3b, 0xb8, 0x39, 0xe0, 0x37, 0xcf, 0x35, 0x89, 0x33, 0x0e, 0x31, 0x62, 0x2e, 0x88, 0x2b, 0x81, 0x28, 0x52, 0x25, + 0xfe, 0x21, 0x87, 0x1e, 0xf2, 0x1a, 0x41, 0x17, 0x79, 0x13, 0x9d, 0x0f, 0xb2, 0x0b, 0xbb, 0x07, 0xbc, 0x03, 0xba, 0xff, + 0xb8, 0xfb, 0xba, 0xf7, 0xc4, 0xf3, 0xdb, 0xef, 0x02, 0xec, 0x3d, 0xe8, 0x90, 0xe4, 0xfe, 0xe0, 0x8c, 0xdd, 0x3c, 0xda, + 0x13, 0xd7, 0x12, 0xd4, 0x3e, 0xd1, 0x99, 0xce, 0x25, 0xcc, 0xe5, 0xc9, 0xdc, 0xc7, 0x0c, 0xc6, 0x76, 0xc4, 0x1b, 0xc3, + 0xfe, 0xc1, 0x1f, 0xc1, 0x80, 0xc0, 0x20, 0xc0, 0x01, 0xc0, 0x21, 0xc0, 0x83, 0xc0, 0x24, 0xc1, 0x04, 0xc2, 0x22, 0xc3, + 0x7e, 0xc4, 0x16, 0xc6, 0xe8, 0xc7, 0xf2, 0xc9, 0x33, 0xcc, 0xa7, 0xce, 0x4e, 0xd1, 0x23, 0xd4, 0x25, 0xd7, 0x4f, 0xda, + 0xa0, 0xdd, 0x13, 0xe1, 0xa5, 0xe4, 0x52, 0xe8, 0x18, 0xec, 0xf1, 0xef, 0xdb, 0xf3, 0xd1, 0xf7, 0xcf, 0xfb, 0xd1, 0xff, + 0xd4, 0x03, 0xd2, 0x07, 0xc9, 0x0b, 0xb4, 0x0f, 0x8f, 0x13, 0x57, 0x17, 0x07, 0x1b, 0x9b, 0x1e, 0x11, 0x22, 0x65, 0x25, + 0x93, 0x28, 0x99, 0x2b, 0x72, 0x2e, 0x1d, 0x31, 0x96, 0x33, 0xdc, 0x35, 0xeb, 0x37, 0xc2, 0x39, 0x5f, 0x3b, 0xc1, 0x3c, + 0xe5, 0x3d, 0xcb, 0x3e, 0x71, 0x3f, 0xd8, 0x3f, 0xff, 0x3f, 0xe6, 0x3f, 0x8c, 0x3f, 0xf2, 0x3e, 0x19, 0x3e, 0x01, 0x3d, + 0xac, 0x3b, 0x1c, 0x3a, 0x50, 0x38, 0x4c, 0x36, 0x12, 0x34, 0xa3, 0x31, 0x02, 0x2f, 0x32, 0x2c, 0x35, 0x29, 0x0f, 0x26, + 0xc3, 0x22, 0x53, 0x1f, 0xc5, 0x1b, 0x1a, 0x18, 0x57, 0x14, 0x7f, 0x10, 0x97, 0x0c, 0xa3, 0x08, 0xa5, 0x04, 0xa3, 0x00, + 0xa1, 0xfc, 0xa1, 0xf8, 0xaa, 0xf4, 0xbd, 0xf0, 0xe0, 0xec, 0x16, 0xe9, 0x63, 0xe5, 0xcb, 0xe1, 0x52, 0xde, 0xfa, 0xda, + 0xc7, 0xd7, 0xbd, 0xd4, 0xde, 0xd1, 0x2e, 0xcf, 0xaf, 0xcc, 0x64, 0xca, 0x4e, 0xc8, 0x70, 0xc6, 0xcd, 0xc4, 0x65, 0xc3, + 0x39, 0xc2, 0x4c, 0xc1, 0x9e, 0xc0, 0x30, 0xc0, 0x02, 0xc0, 0x14, 0xc0, 0x67, 0xc0, 0xf9, 0xc0, 0xcb, 0xc1, 0xdc, 0xc2, + 0x2a, 0xc4, 0xb4, 0xc5, 0x79, 0xc7, 0x76, 0xc9, 0xab, 0xcb, 0x14, 0xce, 0xaf, 0xd0, 0x7a, 0xd3, 0x72, 0xd6, 0x93, 0xd9, + 0xdc, 0xdc, 0x47, 0xe0, 0xd2, 0xe3, 0x7a, 0xe7, 0x3b, 0xeb, 0x10, 0xef, 0xf6, 0xf2, 0xea, 0xf6, 0xe6, 0xfa, 0xe8, 0xfe, + 0xeb, 0x02, 0xeb, 0x06, 0xe3, 0x0a, 0xd1, 0x0e, 0xb0, 0x12, 0x7d, 0x16, 0x32, 0x1a, 0xce, 0x1d, 0x4b, 0x21, 0xa7, 0x24, + 0xde, 0x27, 0xed, 0x2a, 0xd0, 0x2d, 0x86, 0x30, 0x0b, 0x33, 0x5c, 0x35, 0x78, 0x37, 0x5c, 0x39, 0x07, 0x3b, 0x76, 0x3c, + 0xa8, 0x3d, 0x9c, 0x3e, 0x51, 0x3f, 0xc7, 0x3f, 0xfc, 0x3f, 0xf1, 0x3f, 0xa6, 0x3f, 0x1a, 0x3f, 0x50, 0x3e, 0x46, 0x3d, + 0xff, 0x3b, 0x7c, 0x3a, 0xbe, 0x38, 0xc6, 0x36, 0x98, 0x34, 0x35, 0x32, 0x9f, 0x2f, 0xd9, 0x2c, 0xe7, 0x29, 0xca, 0x26, + 0x86, 0x23, 0x1e, 0x20, 0x96, 0x1c, 0xf1, 0x18, 0x34, 0x15, 0x61, 0x11, 0x7c, 0x0d, 0x8a, 0x09, 0x8e, 0x05, 0x8d, 0x01, + 0x8a, 0xfd, 0x8a, 0xf9, 0x90, 0xf5, 0xa0, 0xf1, 0xbf, 0xed, 0xf1, 0xe9, 0x38, 0xe6, 0x9a, 0xe2, 0x19, 0xdf, 0xb9, 0xdb, + 0x7e, 0xd8, 0x6a, 0xd5, 0x81, 0xd2, 0xc6, 0xcf, 0x3c, 0xcd, 0xe4, 0xca, 0xc2, 0xc8, 0xd8, 0xc6, 0x27, 0xc5, 0xb1, 0xc3, + 0x78, 0xc2, 0x7d, 0xc1, 0xc0, 0xc0, 0x44, 0xc0, 0x07, 0xc0, 0x0a, 0xc0, 0x4e, 0xc0, 0xd3, 0xc0, 0x96, 0xc1, 0x98, 0xc2, + 0xd9, 0xc3, 0x55, 0xc5, 0x0d, 0xc7, 0xfe, 0xc8, 0x26, 0xcb, 0x83, 0xcd, 0x13, 0xd0, 0xd4, 0xd2, 0xc2, 0xd5, 0xda, 0xd8, + 0x19, 0xdc, 0x7d, 0xdf, 0x02, 0xe3, 0xa3, 0xe6, 0x5e, 0xea, 0x2f, 0xee, 0x12, 0xf2, 0x03, 0xf6, 0xfe, 0xf9, 0xff, 0xfd, + 0x01, 0x02, 0x02, 0x06, 0xfd, 0x09, 0xee, 0x0d, 0xd1, 0x11, 0xa2, 0x15, 0x5d, 0x19, 0xfe, 0x1c, 0x83, 0x20, 0xe7, 0x23, + 0x26, 0x27, 0x3e, 0x2a, 0x2c, 0x2d, 0xed, 0x2f, 0x7d, 0x32, 0xda, 0x34, 0x02, 0x37, 0xf3, 0x38, 0xab, 0x3a, 0x27, 0x3c, + 0x68, 0x3d, 0x6a, 0x3e, 0x2d, 0x3f, 0xb2, 0x3f, 0xf6, 0x3f, 0xf9, 0x3f, 0xbc, 0x3f, 0x40, 0x3f, 0x83, 0x3e, 0x88, 0x3d, + 0x4f, 0x3c, 0xd9, 0x3a, 0x28, 0x39, 0x3e, 0x37, 0x1c, 0x35, 0xc4, 0x32, 0x3a, 0x30, 0x7f, 0x2d, 0x96, 0x2a, 0x82, 0x27, + 0x47, 0x24, 0xe7, 0x20, 0x66, 0x1d, 0xc8, 0x19, 0x0f, 0x16, 0x41, 0x12, 0x60, 0x0e, 0x70, 0x0a, 0x76, 0x06, 0x76, 0x02, + 0x73, 0xfe, 0x72, 0xfa, 0x76, 0xf6, 0x84, 0xf2, 0x9f, 0xee, 0xcc, 0xea, 0x0f, 0xe7, 0x6a, 0xe3, 0xe2, 0xdf, 0x7a, 0xdc, + 0x36, 0xd9, 0x19, 0xd6, 0x27, 0xd3, 0x61, 0xd0, 0xcb, 0xcd, 0x68, 0xcb, 0x3a, 0xc9, 0x42, 0xc7, 0x84, 0xc5, 0x01, 0xc4, + 0xba, 0xc2, 0xb0, 0xc1, 0xe6, 0xc0, 0x5a, 0xc0, 0x0f, 0xc0, 0x04, 0xc0, 0x39, 0xc0, 0xaf, 0xc0, 0x64, 0xc1, 0x58, 0xc2, + 0x8a, 0xc3, 0xf9, 0xc4, 0xa4, 0xc6, 0x88, 0xc8, 0xa4, 0xca, 0xf5, 0xcc, 0x7a, 0xcf, 0x30, 0xd2, 0x13, 0xd5, 0x22, 0xd8, + 0x59, 0xdb, 0xb5, 0xde, 0x32, 0xe2, 0xce, 0xe5, 0x83, 0xe9, 0x50, 0xed, 0x2f, 0xf1, 0x1d, 0xf5, 0x15, 0xf9, 0x15, 0xfd, + 0x18, 0x01, 0x1a, 0x05, 0x16, 0x09, 0x0a, 0x0d, 0xf0, 0x10, 0xc5, 0x14, 0x86, 0x18, 0x2e, 0x1c, 0xb9, 0x1f, 0x24, 0x23, + 0x6d, 0x26, 0x8e, 0x29, 0x86, 0x2c, 0x51, 0x2f, 0xec, 0x31, 0x55, 0x34, 0x8a, 0x36, 0x87, 0x38, 0x4c, 0x3a, 0xd6, 0x3b, + 0x24, 0x3d, 0x35, 0x3e, 0x07, 0x3f, 0x99, 0x3f, 0xec, 0x3f, 0xfe, 0x3f, 0xd0, 0x3f, 0x62, 0x3f, 0xb4, 0x3e, 0xc7, 0x3d, + 0x9b, 0x3c, 0x33, 0x3b, 0x90, 0x39, 0xb2, 0x37, 0x9c, 0x35, 0x51, 0x33, 0xd2, 0x30, 0x22, 0x2e, 0x43, 0x2b, 0x39, 0x28, + 0x06, 0x25, 0xae, 0x21, 0x35, 0x1e, 0x9d, 0x1a, 0xea, 0x16, 0x20, 0x13, 0x43, 0x0f, 0x56, 0x0b, 0x5f, 0x07, 0x5f, 0x03, + 0x5d, 0xff, 0x5b, 0xfb, 0x5d, 0xf7, 0x69, 0xf3, 0x81, 0xef, 0xa9, 0xeb, 0xe6, 0xe7, 0x3b, 0xe4, 0xad, 0xe0, 0x3d, 0xdd, + 0xf1, 0xd9, 0xcb, 0xd6, 0xce, 0xd3, 0xfe, 0xd0, 0x5d, 0xce, 0xee, 0xcb, 0xb4, 0xc9, 0xb0, 0xc7, 0xe4, 0xc5, 0x54, 0xc4, + 0xff, 0xc2, 0xe7, 0xc1, 0x0e, 0xc1, 0x74, 0xc0, 0x1a, 0xc0, 0x01, 0xc0, 0x28, 0xc0, 0x8f, 0xc0, 0x35, 0xc1, 0x1b, 0xc2, + 0x3f, 0xc3, 0xa1, 0xc4, 0x3e, 0xc6, 0x15, 0xc8, 0x24, 0xca, 0x6a, 0xcc, 0xe3, 0xce, 0x8e, 0xd1, 0x67, 0xd4, 0x6d, 0xd7, + 0x9b, 0xda, 0xef, 0xdd, 0x65, 0xe1, 0xf9, 0xe4, 0xa9, 0xe8, 0x71, 0xec, 0x4c, 0xf0, 0x37, 0xf4, 0x2e, 0xf8, 0x2c, 0xfc, + 0x2f, 0x00, 0x31, 0x04, 0x2f, 0x08, 0x25, 0x0c, 0x0f, 0x10, 0xe8, 0x13, 0xae, 0x17, 0x5b, 0x1b, 0xed, 0x1e, 0x60, 0x22, + 0xb1, 0x25, 0xdb, 0x28, 0xdd, 0x2b, 0xb2, 0x2e, 0x59, 0x31, 0xcd, 0x33, 0x0e, 0x36, 0x18, 0x38, 0xea, 0x39, 0x82, 0x3b, + 0xde, 0x3c, 0xfc, 0x3d, 0xdc, 0x3e, 0x7d, 0x3f, 0xdf, 0x3f, 0xff, 0x3f, 0xe0, 0x3f, 0x80, 0x3f, 0xe1, 0x3e, 0x02, 0x3e, + 0xe5, 0x3c, 0x8a, 0x3b, 0xf4, 0x39, 0x24, 0x38, 0x1b, 0x36, 0xdb, 0x33, 0x67, 0x31, 0xc2, 0x2e, 0xee, 0x2b, 0xed, 0x28, + 0xc4, 0x25, 0x74, 0x22, 0x02, 0x1f, 0x70, 0x1b, 0xc3, 0x17, 0xfe, 0x13, 0x25, 0x10, 0x3c, 0x0c, 0x46, 0x08, 0x48, 0x04, + 0x46, 0x00, 0x44, 0xfc, 0x45, 0xf8, 0x4e, 0xf4, 0x63, 0xf0, 0x87, 0xec, 0xbf, 0xe8, 0x0e, 0xe5, 0x79, 0xe1, 0x02, 0xde, + 0xae, 0xda, 0x7f, 0xd7, 0x78, 0xd4, 0x9e, 0xd1, 0xf2, 0xce, 0x77, 0xcc, 0x31, 0xca, 0x20, 0xc8, 0x48, 0xc6, 0xa9, 0xc4, + 0x47, 0xc3, 0x21, 0xc2, 0x3a, 0xc1, 0x92, 0xc0, 0x29, 0xc0, 0x01, 0xc0, 0x19, 0xc0, 0x72, 0xc0, 0x0a, 0xc1, 0xe2, 0xc1, + 0xf8, 0xc2, 0x4b, 0xc4, 0xdb, 0xc5, 0xa5, 0xc7, 0xa7, 0xc9, 0xe1, 0xcb, 0x4f, 0xce, 0xee, 0xd0, 0xbe, 0xd3, 0xb9, 0xd6, + 0xde, 0xd9, 0x2a, 0xdd, 0x98, 0xe0, 0x26, 0xe4, 0xd1, 0xe7, 0x93, 0xeb, 0x6a, 0xef, 0x52, 0xf3, 0x46, 0xf7, 0x43, 0xfb, + 0x45, 0xff, 0x48, 0x03, 0x47, 0x07, 0x3f, 0x0b, 0x2c, 0x0f, 0x0a, 0x13, 0xd4, 0x16, 0x87, 0x1a, 0x20, 0x1e, 0x9b, 0x21, + 0xf3, 0x24, 0x27, 0x28, 0x32, 0x2b, 0x11, 0x2e, 0xc3, 0x30, 0x43, 0x33, 0x90, 0x35, 0xa7, 0x37, 0x85, 0x39, 0x2a, 0x3b, + 0x94, 0x3c, 0xc1, 0x3d, 0xaf, 0x3e, 0x5e, 0x3f, 0xce, 0x3f, 0xfe, 0x3f, 0xed, 0x3f, 0x9c, 0x3f, 0x0b, 0x3f, 0x3a, 0x3e, + 0x2b, 0x3d, 0xde, 0x3b, 0x56, 0x3a, 0x92, 0x38, 0x96, 0x36, 0x63, 0x34, 0xfb, 0x31, 0x60, 0x2f, 0x96, 0x2c, 0xa0, 0x29, + 0x7f, 0x26, 0x38, 0x23, 0xcd, 0x1f, 0x42, 0x1c, 0x9b, 0x18, 0xdb, 0x14, 0x07, 0x11, 0x21, 0x0d, 0x2d, 0x09, 0x31, 0x05, + 0x2f, 0x01, 0x2d, 0xfd, 0x2d, 0xf9, 0x34, 0xf5, 0x45, 0xf1, 0x66, 0xed, 0x99, 0xe9, 0xe3, 0xe5, 0x47, 0xe2, 0xc9, 0xde, + 0x6c, 0xdb, 0x34, 0xd8, 0x25, 0xd5, 0x40, 0xd2, 0x89, 0xcf, 0x03, 0xcd, 0xb1, 0xca, 0x93, 0xc8, 0xae, 0xc6, 0x02, 0xc5, + 0x92, 0xc3, 0x5f, 0xc2, 0x69, 0xc1, 0xb2, 0xc0, 0x3b, 0xc0, 0x04, 0xc0, 0x0e, 0xc0, 0x58, 0xc0, 0xe2, 0xc0, 0xab, 0xc1, + 0xb3, 0xc2, 0xf9, 0xc3, 0x7b, 0xc5, 0x38, 0xc7, 0x2e, 0xc9, 0x5b, 0xcb, 0xbd, 0xcd, 0x51, 0xd0, 0x16, 0xd3, 0x08, 0xd6, + 0x24, 0xd9, 0x67, 0xdc, 0xce, 0xdf, 0x55, 0xe3, 0xf9, 0xe6, 0xb6, 0xea, 0x89, 0xee, 0x6d, 0xf2, 0x5f, 0xf6, 0x5b, 0xfa, + 0x5c, 0xfe, 0x5f, 0x02, 0x5f, 0x06, 0x59, 0x0a, 0x49, 0x0e, 0x2a, 0x12, 0xf9, 0x15, 0xb2, 0x19, 0x51, 0x1d, 0xd3, 0x20, + 0x34, 0x24, 0x70, 0x27, 0x84, 0x2a, 0x6e, 0x2d, 0x2a, 0x30, 0xb6, 0x32, 0x0f, 0x35, 0x32, 0x37, 0x1e, 0x39, 0xd0, 0x3a, + 0x47, 0x3c, 0x82, 0x3d, 0x7e, 0x3e, 0x3c, 0x3f, 0xba, 0x3f, 0xf9, 0x3f, 0xf6, 0x3f, 0xb4, 0x3f, 0x31, 0x3f, 0x6f, 0x3e, + 0x6e, 0x3d, 0x2f, 0x3c, 0xb4, 0x3a, 0xfe, 0x38, 0x0e, 0x37, 0xe7, 0x34, 0x8b, 0x32, 0xfc, 0x2f, 0x3d, 0x2d, 0x50, 0x2a, + 0x39, 0x27, 0xfa, 0x23, 0x97, 0x20, 0x13, 0x1d, 0x72, 0x19, 0xb8, 0x15, 0xe7, 0x11, 0x05, 0x0e, 0x14, 0x0a, 0x1a, 0x06, + 0x19, 0x02, 0x16, 0xfe, 0x15, 0xfa, 0x1a, 0xf6, 0x29, 0xf2, 0x46, 0xee, 0x74, 0xea, 0xb9, 0xe6, 0x16, 0xe3, 0x91, 0xdf, + 0x2d, 0xdc, 0xec, 0xd8, 0xd3, 0xd5, 0xe4, 0xd2, 0x23, 0xd0, 0x92, 0xcd, 0x33, 0xcb, 0x0a, 0xc9, 0x17, 0xc7, 0x5f, 0xc5, + 0xe1, 0xc3, 0x9f, 0xc2, 0x9b, 0xc1, 0xd6, 0xc0, 0x51, 0xc0, 0x0b, 0xc0, 0x06, 0xc0, 0x41, 0xc0, 0xbd, 0xc0, 0x78, 0xc1, + 0x72, 0xc2, 0xa9, 0xc3, 0x1e, 0xc5, 0xcd, 0xc6, 0xb7, 0xc8, 0xd7, 0xca, 0x2e, 0xcd, 0xb7, 0xcf, 0x71, 0xd2, 0x59, 0xd5, + 0x6b, 0xd8, 0xa6, 0xdb, 0x05, 0xdf, 0x85, 0xe2, 0x23, 0xe6, 0xdb, 0xe9, 0xa9, 0xed, 0x89, 0xf1, 0x79, 0xf5, 0x72, 0xf9, + 0x73, 0xfd, 0x75, 0x01, 0x77, 0x05, 0x73, 0x09, 0x65, 0x0d, 0x4a, 0x11, 0x1e, 0x15, 0xdc, 0x18, 0x81, 0x1c, 0x0a, 0x20, + 0x72, 0x23, 0xb7, 0x26, 0xd5, 0x29, 0xc9, 0x2c, 0x8f, 0x2f, 0x26, 0x32, 0x8b, 0x34, 0xba, 0x36, 0xb3, 0x38, 0x72, 0x3a, + 0xf7, 0x3b, 0x40, 0x3d, 0x4a, 0x3e, 0x17, 0x3f, 0xa3, 0x3f, 0xf0, 0x3f, 0xfc, 0x3f, 0xc9, 0x3f, 0x54, 0x3f, 0xa1, 0x3e, + 0xae, 0x3d, 0x7d, 0x3c, 0x10, 0x3b, 0x67, 0x39, 0x84, 0x37, 0x69, 0x35, 0x19, 0x33, 0x95, 0x30, 0xe1, 0x2d, 0xfe, 0x2a, + 0xf0, 0x27, 0xba, 0x24, 0x5f, 0x21, 0xe2, 0x1d, 0x48, 0x1a, 0x93, 0x16, 0xc7, 0x12, 0xe8, 0x0e, 0xfa, 0x0a, 0x02, 0x07, + 0x02, 0x03, 0xff, 0xfe, 0xfd, 0xfa, 0x01, 0xf7, 0x0d, 0xf3, 0x26, 0xef, 0x51, 0xeb, 0x90, 0xe7, 0xe7, 0xe3, 0x5b, 0xe0, + 0xef, 0xdc, 0xa6, 0xd9, 0x84, 0xd6, 0x8b, 0xd3, 0xbf, 0xd0, 0x23, 0xce, 0xb8, 0xcb, 0x83, 0xc9, 0x84, 0xc7, 0xbe, 0xc5, + 0x32, 0xc4, 0xe3, 0xc2, 0xd1, 0xc1, 0xfd, 0xc0, 0x69, 0xc0, 0x15, 0xc0, 0x02, 0xc0, 0x2e, 0xc0, 0x9b, 0xc0, 0x48, 0xc1, + 0x33, 0xc2, 0x5d, 0xc3, 0xc4, 0xc4, 0x66, 0xc6, 0x42, 0xc8, 0x57, 0xca, 0xa1, 0xcc, 0x1f, 0xcf, 0xce, 0xd1, 0xac, 0xd4, + 0xb5, 0xd7, 0xe7, 0xda, 0x3e, 0xde, 0xb7, 0xe1, 0x4e, 0xe5, 0x00, 0xe9, 0xca, 0xec, 0xa6, 0xf0, 0x93, 0xf4, 0x8a, 0xf8, + 0x89, 0xfc, 0x8c, 0x00, 0x8e, 0x04, 0x8c, 0x08, 0x81, 0x0c, 0x69, 0x10, 0x41, 0x14, 0x04, 0x18, 0xaf, 0x1b, 0x3f, 0x1f, + 0xaf, 0x22, 0xfc, 0x25, 0x23, 0x29, 0x21, 0x2c, 0xf2, 0x2e, 0x94, 0x31, 0x04, 0x34, 0x40, 0x36, 0x45, 0x38, 0x12, 0x3a, + 0xa4, 0x3b, 0xfa, 0x3c, 0x13, 0x3e, 0xee, 0x3e, 0x89, 0x3f, 0xe4, 0x3f, 0xff, 0x3f, 0xda, 0x3f, 0x74, 0x3f, 0xcf, 0x3e, + 0xeb, 0x3d, 0xc8, 0x3c, 0x68, 0x3b, 0xcc, 0x39, 0xf7, 0x37, 0xe8, 0x35, 0xa4, 0x33, 0x2c, 0x31, 0x82, 0x2e, 0xaa, 0x2b, + 0xa5, 0x28, 0x78, 0x25, 0x25, 0x22, 0xb0, 0x1e, 0x1c, 0x1b, 0x6c, 0x17, 0xa5, 0x13, 0xcb, 0x0f, 0xe0, 0x0b, 0xea, 0x07, + 0xeb, 0x03, 0xe9, 0xff, 0xe6, 0xfb, 0xe8, 0xf7, 0xf2, 0xf3, 0x08, 0xf0, 0x2e, 0xec, 0x68, 0xe8, 0xba, 0xe4, 0x27, 0xe1, + 0xb3, 0xdd, 0x62, 0xda, 0x37, 0xd7, 0x34, 0xd4, 0x5e, 0xd1, 0xb6, 0xce, 0x40, 0xcc, 0xfe, 0xc9, 0xf3, 0xc7, 0x20, 0xc6, + 0x87, 0xc4, 0x2a, 0xc3, 0x0a, 0xc2, 0x28, 0xc1, 0x86, 0xc0, 0x23, 0xc0, 0x01, 0xc0, 0x1f, 0xc0, 0x7d, 0xc0, 0x1b, 0xc1, + 0xf8, 0xc1, 0x14, 0xc3, 0x6d, 0xc4, 0x02, 0xc6, 0xd1, 0xc7, 0xd9, 0xc9, 0x17, 0xcc, 0x8a, 0xce, 0x2e, 0xd1, 0x01, 0xd4, + 0x01, 0xd7, 0x29, 0xda, 0x78, 0xdd, 0xea, 0xe0, 0x7b, 0xe4, 0x27, 0xe8, 0xec, 0xeb, 0xc4, 0xef, 0xad, 0xf3, 0xa3, 0xf7, + 0xa0, 0xfb, 0xa3, 0xff, 0xa5, 0x03, 0xa4, 0x07, 0x9b, 0x0b, 0x87, 0x0f, 0x63, 0x13, 0x2b, 0x17, 0xdc, 0x1a, 0x72, 0x1e, + 0xea, 0x21, 0x3f, 0x25, 0x6f, 0x28, 0x76, 0x2b, 0x52, 0x2e, 0xff, 0x30, 0x7b, 0x33, 0xc3, 0x35, 0xd4, 0x37, 0xae, 0x39, + 0x4e, 0x3b, 0xb2, 0x3c, 0xd9, 0x3d, 0xc2, 0x3e, 0x6b, 0x3f, 0xd5, 0x3f, 0xff, 0x3f, 0xe8, 0x3f, 0x91, 0x3f, 0xfa, 0x3e, + 0x24, 0x3e, 0x0f, 0x3d, 0xbd, 0x3b, 0x2f, 0x3a, 0x66, 0x38, 0x65, 0x36, 0x2d, 0x34, 0xc0, 0x31, 0x21, 0x2f, 0x53, 0x2c, + 0x59, 0x29, 0x34, 0x26, 0xea, 0x22, 0x7c, 0x1f, 0xef, 0x1b, 0x45, 0x18, 0x83, 0x14, 0xad, 0x10, 0xc5, 0x0c, 0xd1, 0x08, + 0xd4, 0x04, 0xd2, 0x00, 0xcf, 0xfc, 0xd0, 0xf8, 0xd8, 0xf4, 0xea, 0xf0, 0x0d, 0xed, 0x42, 0xe9, 0x8e, 0xe5, 0xf4, 0xe1, + 0x79, 0xde, 0x20, 0xdb, 0xeb, 0xd7, 0xdf, 0xd4, 0xff, 0xd1, 0x4c, 0xcf, 0xcb, 0xcc, 0x7d, 0xca, 0x65, 0xc8, 0x85, 0xc6, + 0xdf, 0xc4, 0x74, 0xc3, 0x46, 0xc2, 0x56, 0xc1, 0xa5, 0xc0, 0x34, 0xc0, 0x03, 0xc0, 0x12, 0xc0, 0x62, 0xc0, 0xf1, 0xc0, + 0xc0, 0xc1, 0xce, 0xc2, 0x19, 0xc4, 0xa1, 0xc5, 0x63, 0xc7, 0x5e, 0xc9, 0x90, 0xcb, 0xf7, 0xcd, 0x90, 0xd0, 0x59, 0xd3, + 0x4f, 0xd6, 0x6e, 0xd9, 0xb5, 0xdc, 0x1f, 0xe0, 0xa9, 0xe3, 0x4f, 0xe7, 0x0e, 0xeb, 0xe3, 0xee, 0xc9, 0xf2, 0xbb, 0xf6, + 0xb8, 0xfa, 0xb9, 0xfe, 0xbc, 0x02, 0xbc, 0x06, 0xb5, 0x0a, 0xa4, 0x0e, 0x84, 0x12, 0x51, 0x16, 0x08, 0x1a, 0xa4, 0x1d, + 0x23, 0x21, 0x81, 0x24, 0xb9, 0x27, 0xca, 0x2a, 0xb0, 0x2d, 0x68, 0x30, 0xef, 0x32, 0x43, 0x35, 0x61, 0x37, 0x47, 0x39, + 0xf4, 0x3a, 0x66, 0x3c, 0x9b, 0x3d, 0x92, 0x3e, 0x4a, 0x3f, 0xc3, 0x3f, 0xfb, 0x3f, 0xf3, 0x3f, 0xab, 0x3f, 0x22, 0x3f, + 0x5a, 0x3e, 0x54, 0x3d, 0x0f, 0x3c, 0x8f, 0x3a, 0xd3, 0x38, 0xde, 0x36, 0xb2, 0x34, 0x52, 0x32, 0xbe, 0x2f, 0xfb, 0x2c, + 0x0a, 0x2a, 0xef, 0x26, 0xac, 0x23, 0x46, 0x20, 0xc0, 0x1c, 0x1c, 0x19, 0x60, 0x15, 0x8d, 0x11, 0xaa, 0x0d, 0xb8, 0x09, + 0xbd, 0x05, 0xbb, 0x01, 0xb9, 0xfd, 0xb8, 0xf9, 0xbe, 0xf5, 0xce, 0xf1, 0xec, 0xed, 0x1d, 0xea, 0x63, 0xe6, 0xc3, 0xe2, + 0x41, 0xdf, 0xe0, 0xdb, 0xa3, 0xd8, 0x8d, 0xd5, 0xa2, 0xd2, 0xe5, 0xcf, 0x58, 0xcd, 0xff, 0xca, 0xda, 0xc8, 0xed, 0xc6, + 0x39, 0xc5, 0xc1, 0xc3, 0x85, 0xc2, 0x87, 0xc1, 0xc7, 0xc0, 0x48, 0xc0, 0x08, 0xc0, 0x09, 0xc0, 0x4a, 0xc0, 0xcb, 0xc0, + 0x8c, 0xc1, 0x8b, 0xc2, 0xc9, 0xc3, 0x43, 0xc5, 0xf8, 0xc6, 0xe6, 0xc8, 0x0c, 0xcb, 0x67, 0xcd, 0xf5, 0xcf, 0xb3, 0xd2, + 0x9f, 0xd5, 0xb5, 0xd8, 0xf3, 0xdb, 0x55, 0xdf, 0xd8, 0xe2, 0x78, 0xe6, 0x32, 0xea, 0x02, 0xee, 0xe4, 0xf1, 0xd5, 0xf5, + 0xcf, 0xf9, 0xd0, 0xfd, 0xd3, 0x01, 0xd4, 0x05, 0xcf, 0x09, 0xc0, 0x0d, 0xa4, 0x11, 0x76, 0x15, 0x32, 0x19, 0xd5, 0x1c, + 0x5b, 0x20, 0xc0, 0x23, 0x01, 0x27, 0x1b, 0x2a, 0x0b, 0x2d, 0xce, 0x2f, 0x60, 0x32, 0xc0, 0x34, 0xea, 0x36, 0xde, 0x38, + 0x98, 0x3a, 0x17, 0x3c, 0x5a, 0x3d, 0x60, 0x3e, 0x26, 0x3f, 0xad, 0x3f, 0xf4, 0x3f, 0xfa, 0x3f, 0xc1, 0x3f, 0x47, 0x3f, + 0x8d, 0x3e, 0x95, 0x3d, 0x5e, 0x3c, 0xeb, 0x3a, 0x3d, 0x39, 0x55, 0x37, 0x36, 0x35, 0xe1, 0x32, 0x58, 0x30, 0x9f, 0x2d, + 0xb9, 0x2a, 0xa7, 0x27, 0x6d, 0x24, 0x0f, 0x21, 0x90, 0x1d, 0xf2, 0x19, 0x3b, 0x16, 0x6d, 0x12, 0x8d, 0x0e, 0x9e, 0x0a, + 0xa5, 0x06, 0xa5, 0x02, 0xa2, 0xfe, 0xa0, 0xfa, 0xa4, 0xf6, 0xb2, 0xf2, 0xcc, 0xee, 0xf8, 0xea, 0x3a, 0xe7, 0x94, 0xe3, + 0x0a, 0xe0, 0xa1, 0xdc, 0x5c, 0xd9, 0x3d, 0xd6, 0x48, 0xd3, 0x80, 0xd0, 0xe8, 0xcd, 0x83, 0xcb, 0x52, 0xc9, 0x58, 0xc7, + 0x97, 0xc5, 0x11, 0xc4, 0xc7, 0xc2, 0xbb, 0xc1, 0xed, 0xc0, 0x5f, 0xc0, 0x11, 0xc0, 0x03, 0xc0, 0x36, 0xc0, 0xa8, 0xc0, + 0x5a, 0xc1, 0x4c, 0xc2, 0x7b, 0xc3, 0xe7, 0xc4, 0x8f, 0xc6, 0x71, 0xc8, 0x8a, 0xca, 0xd9, 0xcc, 0x5c, 0xcf, 0x0f, 0xd2, + 0xf1, 0xd4, 0xfe, 0xd7, 0x33, 0xdb, 0x8d, 0xde, 0x09, 0xe2, 0xa3, 0xe5, 0x58, 0xe9, 0x23, 0xed, 0x01, 0xf1, 0xef, 0xf4, + 0xe7, 0xf8, 0xe7, 0xfc, 0xe9, 0x00, 0xeb, 0x04, 0xe8, 0x08, 0xdc, 0x0c, 0xc3, 0x10, 0x99, 0x14, 0x5b, 0x18, 0x04, 0x1c, + 0x90, 0x1f, 0xfd, 0x22, 0x47, 0x26, 0x6a, 0x29, 0x64, 0x2c, 0x31, 0x2f, 0xcf, 0x31, 0x3a, 0x34, 0x71, 0x36, 0x71, 0x38, + 0x39, 0x3a, 0xc6, 0x3b, 0x16, 0x3d, 0x2a, 0x3e, 0xfe, 0x3e, 0x94, 0x3f, 0xe9, 0x3f, 0xff, 0x3f, 0xd3, 0x3f, 0x68, 0x3f, + 0xbd, 0x3e, 0xd3, 0x3d, 0xaa, 0x3c, 0x45, 0x3b, 0xa4, 0x39, 0xc9, 0x37, 0xb6, 0x35, 0x6d, 0x33, 0xf0, 0x30, 0x42, 0x2e, + 0x65, 0x2b, 0x5d, 0x28, 0x2c, 0x25, 0xd6, 0x21, 0x5e, 0x1e, 0xc7, 0x1a, 0x15, 0x17, 0x4d, 0x13, 0x70, 0x0f, 0x84, 0x0b, + 0x8d, 0x07, 0x8e, 0x03, 0x8b, 0xff, 0x89, 0xfb, 0x8b, 0xf7, 0x96, 0xf3, 0xae, 0xef, 0xd5, 0xeb, 0x11, 0xe8, 0x66, 0xe4, + 0xd5, 0xe0, 0x65, 0xdd, 0x17, 0xda, 0xef, 0xd6, 0xf0, 0xd3, 0x1e, 0xd1, 0x7b, 0xce, 0x0a, 0xcc, 0xcd, 0xc9, 0xc6, 0xc7, + 0xf8, 0xc5, 0x65, 0xc4, 0x0d, 0xc3, 0xf3, 0xc1, 0x17, 0xc1, 0x7a, 0xc0, 0x1d, 0xc0, 0x01, 0xc0, 0x24, 0xc0, 0x89, 0xc0, + 0x2c, 0xc1, 0x0f, 0xc2, 0x31, 0xc3, 0x8f, 0xc4, 0x2a, 0xc6, 0xfe, 0xc7, 0x0b, 0xca, 0x4e, 0xcc, 0xc5, 0xce, 0x6e, 0xd1, + 0x45, 0xd4, 0x49, 0xd7, 0x75, 0xda, 0xc7, 0xdd, 0x3c, 0xe1, 0xcf, 0xe4, 0x7e, 0xe8, 0x44, 0xec, 0x1f, 0xf0, 0x09, 0xf4, + 0xff, 0xf7, 0xfe, 0xfb, +}; +inline constexpr unsigned char fixture_tone_flac[9588] = { + 0x66, 0x4c, 0x61, 0x43, 0x00, 0x00, 0x00, 0x22, 0x12, 0x00, 0x12, 0x00, 0x00, 0x05, 0x14, 0x00, 0x05, 0x14, 0x0a, 0xc4, + 0x40, 0xf0, 0x00, 0x00, 0x11, 0x3a, 0xca, 0xe7, 0x9b, 0x98, 0x24, 0x69, 0x63, 0xeb, 0xa2, 0x39, 0xaf, 0xb8, 0x71, 0x27, + 0x9c, 0xcd, 0x04, 0x00, 0x00, 0x2e, 0x0d, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x76, 0x66, 0x36, 0x30, 0x2e, 0x31, 0x36, 0x2e, + 0x31, 0x30, 0x30, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x3d, 0x4c, + 0x61, 0x76, 0x66, 0x36, 0x30, 0x2e, 0x31, 0x36, 0x2e, 0x31, 0x30, 0x30, 0x81, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x79, 0x08, 0x00, 0x11, 0x39, 0x8c, 0x4e, 0x00, 0x00, 0x04, + 0x02, 0x08, 0x01, 0x0b, 0xf7, 0x0f, 0xe1, 0x13, 0xbc, 0x17, 0x82, 0x1b, 0x31, 0xe6, 0xb7, 0x72, 0x05, 0x25, 0xab, 0x8b, + 0x78, 0x57, 0xd3, 0x71, 0x6a, 0x42, 0xd3, 0x3c, 0x1d, 0x00, 0x13, 0x99, 0xf2, 0x9a, 0x14, 0xd9, 0x4a, 0xce, 0xc9, 0x4d, + 0x25, 0xc9, 0xa1, 0xc9, 0x99, 0x24, 0x92, 0x64, 0x98, 0x48, 0x61, 0x84, 0x24, 0x90, 0x93, 0x26, 0x43, 0xc9, 0x92, 0x1c, + 0x9e, 0x4a, 0x73, 0x66, 0x9e, 0x9f, 0x9b, 0x98, 0xc3, 0x49, 0xc9, 0xe6, 0x4e, 0x13, 0x21, 0x27, 0x09, 0x21, 0x92, 0x42, + 0x64, 0x24, 0x30, 0x9c, 0x84, 0xc9, 0xc9, 0x33, 0xe4, 0xe7, 0xf9, 0x7d, 0x2e, 0x5a, 0x1d, 0x93, 0x53, 0xe5, 0x30, 0xa6, + 0x4c, 0x90, 0xce, 0x43, 0x0e, 0x13, 0x0c, 0x92, 0x64, 0x24, 0x93, 0x09, 0x92, 0x4e, 0x61, 0x49, 0xc9, 0x2c, 0xfc, 0xf4, + 0xff, 0x3e, 0x9a, 0x6e, 0x59, 0xe6, 0x73, 0x32, 0x70, 0x87, 0x24, 0x92, 0x42, 0x64, 0x92, 0x61, 0x09, 0x32, 0x42, 0x72, + 0x1e, 0x19, 0xcc, 0x9a, 0x72, 0xfd, 0xe5, 0xfe, 0xe6, 0x6c, 0xf9, 0x4c, 0xce, 0x43, 0x30, 0x92, 0x61, 0x24, 0x84, 0xc9, + 0x24, 0x26, 0x42, 0x49, 0x24, 0x26, 0x43, 0x92, 0x4c, 0xe1, 0x9c, 0x93, 0xf3, 0x65, 0x34, 0xec, 0xf2, 0xf3, 0xd2, 0x1a, + 0x79, 0xe4, 0x39, 0x24, 0xcc, 0x84, 0x38, 0x61, 0x98, 0x61, 0x30, 0x90, 0x99, 0x09, 0x92, 0x42, 0x64, 0xcc, 0x39, 0x39, + 0x9c, 0xa5, 0x2e, 0x5a, 0x6b, 0x2d, 0x25, 0xcd, 0x32, 0x7c, 0xcc, 0x9c, 0x92, 0x49, 0x32, 0x64, 0x90, 0xc2, 0x4c, 0x24, + 0x92, 0x4c, 0xc8, 0x4e, 0x48, 0x4c, 0x93, 0x99, 0x9f, 0x64, 0xfb, 0xd7, 0x36, 0x86, 0xcd, 0xce, 0x92, 0x5a, 0x43, 0xc8, + 0x66, 0x90, 0x99, 0x92, 0x42, 0x49, 0x90, 0x86, 0x84, 0x24, 0xc8, 0x61, 0x32, 0x13, 0x93, 0x93, 0x34, 0xe1, 0x65, 0x97, + 0x96, 0x92, 0xdc, 0xb2, 0xcb, 0x73, 0x9e, 0x4f, 0x24, 0xc9, 0xc2, 0x12, 0x92, 0x19, 0x81, 0x38, 0x42, 0x66, 0x12, 0x61, + 0x26, 0x12, 0x4e, 0x19, 0x33, 0x49, 0x97, 0x3c, 0xb4, 0x92, 0xbc, 0xb3, 0xe4, 0xa7, 0x92, 0xca, 0x72, 0x49, 0xc9, 0x09, + 0x38, 0x4c, 0x90, 0x99, 0x24, 0x26, 0x61, 0x32, 0x61, 0xc2, 0x1c, 0xc9, 0xa4, 0x85, 0x33, 0xa4, 0xf3, 0x72, 0xe9, 0x66, + 0x9d, 0x3b, 0x9b, 0x9f, 0x21, 0x9c, 0xc9, 0x32, 0x4c, 0x98, 0x70, 0x81, 0xc2, 0x42, 0x64, 0x84, 0xe1, 0x0e, 0x49, 0xe1, + 0x09, 0xf0, 0x96, 0x4d, 0x92, 0x95, 0x0d, 0x9f, 0x9a, 0x79, 0xe9, 0xa4, 0xe9, 0x93, 0xc9, 0x0e, 0x43, 0x24, 0xc3, 0x09, + 0x84, 0x92, 0x42, 0x70, 0x86, 0x49, 0x98, 0x4e, 0x10, 0x94, 0xc9, 0xb0, 0xfc, 0xbc, 0xd3, 0xf4, 0x95, 0x3b, 0xcd, 0x98, + 0x53, 0x49, 0x49, 0x0e, 0x64, 0x90, 0xe1, 0x32, 0x48, 0x4e, 0x10, 0x87, 0x21, 0x26, 0x12, 0x4c, 0x21, 0xcc, 0x26, 0x4c, + 0xc9, 0x29, 0x94, 0xce, 0xc9, 0x1c, 0xe9, 0x36, 0x4b, 0x4f, 0xd9, 0x39, 0x99, 0x9c, 0x26, 0x19, 0x84, 0x93, 0x24, 0x32, + 0x48, 0x4c, 0x26, 0x19, 0x0c, 0x86, 0x4c, 0x93, 0x93, 0x90, 0xbc, 0x3d, 0x26, 0xa4, 0xae, 0x65, 0xe9, 0x3b, 0x33, 0x49, + 0x0d, 0x42, 0x4f, 0x21, 0xc8, 0x64, 0x84, 0x38, 0x48, 0x4e, 0x42, 0x49, 0x24, 0x84, 0xe4, 0x92, 0x49, 0x33, 0x21, 0xcc, + 0xd9, 0x26, 0xf2, 0xe5, 0xbf, 0x7d, 0xf9, 0x73, 0xc9, 0x28, 0x64, 0xc9, 0x26, 0x61, 0x32, 0x10, 0xc9, 0x09, 0x30, 0x90, + 0xc2, 0x49, 0x84, 0xc9, 0x30, 0xca, 0x4e, 0x73, 0x3a, 0x4b, 0x49, 0x4b, 0x94, 0xb3, 0x66, 0x5f, 0x3e, 0x1b, 0x0e, 0x72, + 0x49, 0x90, 0xc2, 0x4c, 0x26, 0x42, 0x19, 0x0c, 0x99, 0x09, 0x24, 0x24, 0x92, 0x48, 0x61, 0x90, 0x93, 0x99, 0x0f, 0x3c, + 0xfc, 0xac, 0xf7, 0x2f, 0xbe, 0xc3, 0xa6, 0x4e, 0x4e, 0x4c, 0xc9, 0x09, 0x92, 0x42, 0x49, 0x24, 0x84, 0x92, 0x48, 0x70, + 0xc8, 0x4c, 0xc8, 0x53, 0x24, 0xf2, 0x79, 0xe9, 0x3d, 0x25, 0xff, 0xb2, 0x5c, 0xe7, 0xe6, 0x87, 0x90, 0xe1, 0x92, 0x49, + 0x92, 0x49, 0x86, 0x42, 0x4c, 0x90, 0x92, 0x61, 0x26, 0x42, 0x53, 0x26, 0x4c, 0xc9, 0x67, 0xe4, 0xd9, 0xec, 0xa5, 0xcb, + 0x72, 0x5a, 0x74, 0x33, 0x9c, 0x9c, 0x84, 0x86, 0x48, 0x49, 0x84, 0x92, 0x42, 0x42, 0x4c, 0x24, 0xc9, 0x24, 0x92, 0x49, + 0x92, 0x72, 0x73, 0x92, 0x5c, 0xf2, 0xf3, 0x4b, 0x2e, 0x90, 0xd9, 0x73, 0x3c, 0x85, 0x86, 0x90, 0xf2, 0x1c, 0x84, 0x99, + 0x24, 0xc8, 0x12, 0x48, 0x64, 0x24, 0x26, 0x49, 0x38, 0x66, 0x49, 0xcd, 0x26, 0x7e, 0x69, 0x99, 0x7a, 0x7f, 0x9e, 0xc2, + 0xcf, 0x92, 0xc2, 0x9c, 0x92, 0x72, 0x19, 0x24, 0x86, 0x19, 0x0c, 0x32, 0x49, 0x92, 0x43, 0x24, 0x39, 0xc3, 0x99, 0x9c, + 0xcf, 0x94, 0xd0, 0xa6, 0xca, 0x56, 0x76, 0x4a, 0x69, 0x2e, 0x4d, 0x0e, 0x4c, 0xc9, 0x24, 0x93, 0x24, 0xc2, 0x43, 0x0c, + 0x21, 0x24, 0x84, 0x99, 0x32, 0x1e, 0x4c, 0x90, 0xe4, 0xf2, 0x53, 0x9b, 0x34, 0xf4, 0xfc, 0xdc, 0xc6, 0x1a, 0x4e, 0x4f, + 0x32, 0x70, 0x99, 0x09, 0x38, 0x49, 0x0c, 0x92, 0x13, 0x21, 0x21, 0x84, 0xe4, 0x26, 0x4e, 0x49, 0x9f, 0x27, 0x3f, 0xcb, + 0xe9, 0x72, 0xd0, 0xec, 0x9a, 0x9f, 0x29, 0x85, 0x32, 0x64, 0x86, 0x72, 0x18, 0x70, 0x98, 0x64, 0x93, 0x21, 0x24, 0x98, + 0x4c, 0x92, 0x73, 0x0a, 0x4e, 0x49, 0x67, 0xe7, 0xa7, 0xf9, 0xf4, 0xd3, 0x72, 0xcf, 0x33, 0x99, 0x93, 0x84, 0x39, 0x24, + 0x92, 0x13, 0x24, 0x93, 0x08, 0x49, 0x92, 0x13, 0x90, 0xf0, 0xce, 0x64, 0xd3, 0x97, 0xef, 0x2f, 0xf7, 0x33, 0x67, 0xca, + 0x66, 0x72, 0x19, 0x84, 0x93, 0x09, 0x24, 0x26, 0x49, 0x21, 0x32, 0x12, 0x49, 0x21, 0x32, 0x1c, 0x92, 0x67, 0x0c, 0xe4, + 0x9f, 0x9b, 0x29, 0xa7, 0x67, 0x97, 0x9e, 0x90, 0xd3, 0xcf, 0x21, 0xc9, 0x26, 0x64, 0x21, 0xc3, 0x0c, 0xc3, 0x09, 0x84, + 0x84, 0xc8, 0x4c, 0x92, 0x13, 0x26, 0x61, 0xc9, 0xcc, 0xe5, 0x29, 0x72, 0xd3, 0x59, 0x69, 0x2e, 0x69, 0x93, 0xe6, 0x64, + 0xe4, 0x92, 0x49, 0x93, 0x24, 0x86, 0x12, 0x61, 0x24, 0x92, 0x66, 0x42, 0x72, 0x42, 0x64, 0x9c, 0xcc, 0xfb, 0x27, 0xde, + 0xb9, 0xb4, 0x36, 0x6e, 0x74, 0x92, 0xd2, 0x1e, 0x43, 0x34, 0x84, 0xcc, 0x92, 0x12, 0x4c, 0x84, 0x34, 0x21, 0x26, 0x43, + 0x09, 0x90, 0x9c, 0x9c, 0x99, 0xa7, 0x0b, 0x2c, 0xbc, 0xb4, 0x96, 0xe5, 0x96, 0x5b, 0x9c, 0xf2, 0x79, 0x26, 0x4e, 0x10, + 0x94, 0x90, 0xcc, 0x09, 0xc2, 0x13, 0x30, 0x93, 0x09, 0x30, 0x92, 0x70, 0xc9, 0x9a, 0x4c, 0xb9, 0xe5, 0xa4, 0x95, 0xe5, + 0x9f, 0x25, 0x3c, 0x96, 0x53, 0x92, 0x4e, 0x48, 0x49, 0xc2, 0x64, 0x84, 0xc9, 0x21, 0x33, 0x09, 0x93, 0x0e, 0x10, 0xe6, + 0x4d, 0x24, 0x29, 0x9d, 0x27, 0x9b, 0x97, 0x4b, 0x34, 0xe9, 0xdc, 0xdc, 0xf9, 0x0c, 0xe6, 0x49, 0x92, 0x64, 0xc3, 0x84, + 0x0e, 0x12, 0x13, 0x24, 0x27, 0x08, 0x72, 0x4f, 0x08, 0x4f, 0x84, 0xb2, 0x6c, 0x94, 0xa8, 0x6c, 0xfc, 0xd3, 0xcf, 0x4d, + 0x27, 0x4c, 0x9e, 0x48, 0x72, 0x19, 0x26, 0x18, 0x4c, 0x24, 0x92, 0x13, 0x84, 0x32, 0x4c, 0xc2, 0x70, 0x84, 0xa6, 0x4d, + 0x87, 0xe5, 0xe6, 0x9f, 0xa4, 0xa9, 0xde, 0x6c, 0xc2, 0x9a, 0x4a, 0x48, 0x73, 0x24, 0x87, 0x09, 0x92, 0x42, 0x70, 0x84, + 0x39, 0x09, 0x30, 0x92, 0x61, 0x0e, 0x61, 0x32, 0x66, 0x49, 0x4c, 0xa6, 0x76, 0x48, 0xe7, 0x49, 0xb2, 0x5a, 0x7e, 0xc9, + 0xcc, 0xcc, 0xe1, 0x30, 0xcc, 0x24, 0x99, 0x21, 0x92, 0x42, 0x61, 0x30, 0xc8, 0x64, 0x32, 0x64, 0x9c, 0x9c, 0x85, 0xe1, + 0xe9, 0x35, 0x25, 0x73, 0x2f, 0x49, 0xd9, 0x9a, 0x48, 0x6a, 0x12, 0x79, 0x0e, 0x43, 0x24, 0x21, 0xc2, 0x42, 0x72, 0x12, + 0x49, 0x24, 0x27, 0x24, 0x92, 0x49, 0x99, 0x0e, 0x66, 0xc9, 0x37, 0x97, 0x2d, 0xfb, 0xef, 0xcb, 0x9e, 0x49, 0x43, 0x26, + 0x49, 0x33, 0x09, 0x90, 0x86, 0x48, 0x49, 0x84, 0x86, 0x12, 0x4c, 0x26, 0x49, 0x86, 0x52, 0x73, 0x99, 0xd2, 0x5a, 0x4a, + 0x5c, 0xa5, 0x9b, 0x32, 0xf9, 0xf0, 0xd8, 0x73, 0x92, 0x4c, 0x86, 0x12, 0x61, 0x32, 0x10, 0xc8, 0x64, 0xc8, 0x49, 0x21, + 0x24, 0x92, 0x43, 0x0c, 0x84, 0x9c, 0xc8, 0x79, 0xe7, 0xe5, 0x67, 0xb9, 0x7d, 0xf6, 0x1d, 0x32, 0x72, 0x72, 0x66, 0x48, + 0x4c, 0x92, 0x12, 0x49, 0x24, 0x24, 0x92, 0x43, 0x86, 0x42, 0x66, 0x42, 0x99, 0x27, 0x93, 0xcf, 0x49, 0xe9, 0x2f, 0xfd, + 0x92, 0xe7, 0x3f, 0x34, 0x3c, 0x87, 0x0c, 0x92, 0x4c, 0x92, 0x4c, 0x32, 0x12, 0x64, 0x84, 0x93, 0x09, 0x32, 0x12, 0x99, + 0x32, 0x66, 0x4b, 0x3f, 0x26, 0xcf, 0x65, 0x2e, 0x5b, 0x92, 0xd3, 0xa1, 0x9c, 0xe4, 0xe4, 0x24, 0x32, 0x42, 0x4c, 0x24, + 0x92, 0x12, 0x12, 0x61, 0x26, 0x49, 0x24, 0x92, 0x4c, 0x93, 0x93, 0x9c, 0x92, 0xe7, 0x97, 0x9a, 0x59, 0x74, 0x86, 0xcb, + 0x99, 0xe4, 0x2c, 0x34, 0x87, 0x90, 0xe4, 0x24, 0xc9, 0x26, 0x40, 0x92, 0x43, 0x21, 0x21, 0x32, 0x49, 0xc3, 0x32, 0x4e, + 0x69, 0x33, 0xf3, 0x4c, 0xcb, 0xd3, 0xfc, 0xf6, 0x16, 0x7c, 0x96, 0x14, 0xe4, 0x93, 0x90, 0xc9, 0x24, 0x30, 0xc8, 0x61, + 0x92, 0x4c, 0x92, 0x19, 0x21, 0xc8, 0x7f, 0xbe, +}; +inline constexpr unsigned char fixture_tone_mp3[1044] = { + 0xff, 0xfb, 0x50, 0xc4, 0x00, 0x00, 0x0a, 0x4c, 0x43, 0x3e, 0x55, 0x94, 0x80, 0x01, 0x7a, 0x10, 0xea, 0x37, 0x36, 0xd0, + 0x00, 0x07, 0xaa, 0xc3, 0x8e, 0x33, 0x85, 0xd3, 0x64, 0xf1, 0xa1, 0xc1, 0x08, 0x1c, 0x58, 0x1f, 0x5e, 0x1f, 0x18, 0x1c, + 0x46, 0x04, 0x1e, 0x89, 0xe5, 0xb3, 0x2e, 0x5a, 0x0f, 0xa8, 0x3b, 0x13, 0x6b, 0xf0, 0xf8, 0x60, 0x50, 0x14, 0x04, 0x03, + 0x02, 0x82, 0x44, 0x0c, 0x4e, 0x68, 0xd1, 0xa3, 0x6c, 0x1f, 0x78, 0x80, 0x10, 0x04, 0x31, 0x38, 0x3f, 0xc1, 0x07, 0x4e, + 0x74, 0xf9, 0xce, 0x5f, 0xce, 0x72, 0xfe, 0xee, 0x9f, 0x77, 0x2e, 0x0f, 0x87, 0xc4, 0xe0, 0xf8, 0x20, 0x08, 0x44, 0x00, + 0x30, 0x7d, 0xf2, 0x60, 0x00, 0x06, 0x75, 0x80, 0xc0, 0x60, 0x50, 0x20, 0x0c, 0x08, 0x06, 0x00, 0x00, 0x01, 0x16, 0x30, + 0x3f, 0x27, 0x40, 0xc2, 0xee, 0xa0, 0x43, 0x13, 0x34, 0x36, 0xe1, 0xd6, 0x04, 0x73, 0xc0, 0x14, 0x21, 0x31, 0x92, 0x53, + 0x4b, 0x26, 0x32, 0x32, 0x46, 0x85, 0xd7, 0xeb, 0x61, 0x35, 0x05, 0x77, 0xc1, 0x59, 0x13, 0xe1, 0x32, 0xfc, 0x4b, 0x89, + 0x11, 0xea, 0x38, 0x7f, 0xc7, 0x70, 0xc3, 0x09, 0x71, 0x22, 0x3d, 0x7f, 0xf2, 0x44, 0xc8, 0xbc, 0x5e, 0x44, 0xbb, 0xf9, + 0x51, 0x10, 0x54, 0x15, 0xfe, 0x22, 0x0a, 0x82, 0xa2, 0x23, 0xdf, 0xeb, 0x05, 0x44, 0x41, 0x50, 0x54, 0x44, 0x30, 0x21, + 0x00, 0xdb, 0x30, 0x23, 0x00, 0xdb, 0x30, 0x7c, 0xff, 0xfb, 0x52, 0xc4, 0x05, 0x03, 0xc9, 0x80, 0x27, 0x10, 0x1d, 0xf1, + 0x00, 0x00, 0xfe, 0x85, 0x62, 0x01, 0xdf, 0xf4, 0x48, 0x82, 0x41, 0x30, 0x18, 0x81, 0xf8, 0x30, 0x3f, 0x42, 0xb2, 0x38, + 0x1f, 0xfe, 0x75, 0x36, 0x65, 0x0f, 0x23, 0x31, 0xf9, 0x85, 0x17, 0x30, 0xf5, 0x82, 0xc5, 0x30, 0x74, 0xc2, 0x4c, 0x30, + 0x85, 0x42, 0x08, 0x30, 0x90, 0x41, 0xbc, 0x30, 0x30, 0xc0, 0xb0, 0x44, 0x65, 0xbe, 0x91, 0x32, 0x19, 0xa1, 0x81, 0xaf, + 0x4d, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0xe5, 0x69, 0x77, 0xff, 0xff, 0xff, 0x4f, 0x29, 0xea, 0x30, 0x94, 0x2d, 0x32, 0x28, + 0x96, 0x34, 0x35, 0x2d, 0x37, 0xda, 0x68, 0x31, 0x22, 0xc7, 0x5f, 0x37, 0x66, 0x38, 0x67, 0x37, 0x39, 0xc7, 0x65, 0x31, + 0x28, 0x02, 0xa8, 0x38, 0xb5, 0xc7, 0x34, 0xb5, 0x4d, 0x34, 0x49, 0x2a, 0x34, 0x45, 0xfd, 0x32, 0xac, 0x9d, 0x30, 0x88, + 0x0a, 0x45, 0x36, 0xb8, 0xff, 0xc6, 0x29, 0x2d, 0xf2, 0xdf, 0xff, 0xfb, 0x7f, 0xff, 0xb7, 0xfb, 0xff, 0xff, 0x45, 0x32, + 0x3c, 0x9e, 0x32, 0x70, 0xd3, 0x33, 0x55, 0x4a, 0x35, 0x9a, 0x7d, 0x30, 0xcd, 0xc7, 0xa6, 0x35, 0x5e, 0xbb, 0x52, 0x35, + 0x3a, 0x47, 0x7a, 0x30, 0xbd, 0x02, 0x25, 0x35, 0xfa, 0x48, 0xca, 0x46, 0x53, 0x6a, 0xad, 0x0e, 0x21, 0x67, 0x35, 0xc1, + 0xac, 0xc4, 0xe0, 0x04, 0xd5, 0x75, 0xa7, 0x6f, 0x89, 0xbf, 0xf4, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x52, + 0xc4, 0x1d, 0x03, 0xc7, 0xa0, 0x25, 0x12, 0x0e, 0xff, 0x82, 0x41, 0x24, 0x85, 0x61, 0xc1, 0xdf, 0xf4, 0x48, 0xff, 0xff, + 0xee, 0x30, 0xe0, 0x2a, 0x32, 0xac, 0xa5, 0x34, 0xf9, 0x4a, 0x39, 0x3e, 0xa7, 0x31, 0x53, 0x08, 0x18, 0x38, 0x9e, 0xfd, + 0xde, 0x38, 0x6a, 0x08, 0x22, 0x31, 0x58, 0xc2, 0xf7, 0x3a, 0x12, 0x04, 0x35, 0x59, 0x82, 0x34, 0xd5, 0x61, 0x34, 0xba, + 0x54, 0x32, 0xf8, 0xba, 0x30, 0xa4, 0x11, 0x40, 0x03, 0x3b, 0x7f, 0x23, 0x74, 0xf6, 0x33, 0x60, 0xaf, 0xf9, 0xef, 0xf6, + 0x7f, 0x7f, 0xff, 0xdd, 0xd5, 0xff, 0xe9, 0xff, 0x4f, 0xef, 0xff, 0xf7, 0x73, 0xd4, 0x2a, 0x32, 0x30, 0x9f, 0x32, 0x64, + 0xd6, 0x33, 0x31, 0x51, 0x35, 0x66, 0x8c, 0x30, 0xc5, 0x87, 0xd3, 0x35, 0x29, 0x7c, 0x99, 0x35, 0x06, 0x07, 0xa7, 0x30, + 0xb4, 0x42, 0x36, 0x35, 0x52, 0x8c, 0xcb, 0xe5, 0x83, 0x6e, 0x2a, 0xce, 0x33, 0x58, 0x35, 0xe9, 0x98, 0x04, 0x4d, 0x49, + 0x27, 0x56, 0x5d, 0x7b, 0x41, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xf5, 0x7f, 0xff, 0xff, 0xed, 0xf4, 0xf5, 0x98, 0x05, + 0x00, 0x1e, 0x98, 0x0f, 0x60, 0x88, 0x98, 0x40, 0xe0, 0xe0, 0x98, 0x38, 0x82, 0x1c, 0x18, 0x8e, 0x04, 0x57, 0x1d, 0x65, + 0x9c, 0x28, 0x9c, 0xb5, 0xa9, 0x47, 0x99, 0x41, 0xa3, 0x84, 0x98, 0xab, 0x61, 0x48, 0x98, 0x35, 0xe1, 0xa1, 0x98, 0x5d, + 0xa1, 0x51, 0x98, 0x5a, 0x21, 0x50, 0xff, 0xfb, 0x52, 0xc4, 0x37, 0x83, 0xc7, 0xe4, 0x27, 0x12, 0x0e, 0xff, 0x82, 0x41, + 0x4a, 0x85, 0x61, 0xc2, 0xbe, 0x60, 0x00, 0x98, 0x15, 0xa0, 0x78, 0x98, 0x05, 0xa0, 0x04, 0x87, 0x00, 0x1e, 0x97, 0x8e, + 0x23, 0xf0, 0x08, 0x41, 0x0b, 0x7f, 0xf7, 0x7e, 0xd6, 0x7f, 0xfb, 0xae, 0xb3, 0xee, 0xfb, 0x7f, 0xff, 0xff, 0xb7, 0xff, + 0xff, 0xa2, 0x10, 0x00, 0x00, 0xa5, 0x6b, 0x35, 0xc5, 0x6c, 0x56, 0x1f, 0x0b, 0x86, 0xe2, 0xe1, 0x30, 0x03, 0x4c, 0x20, + 0x18, 0x00, 0x01, 0x9a, 0x53, 0x01, 0x36, 0x7f, 0x1e, 0xee, 0x82, 0x8c, 0xeb, 0x10, 0x54, 0xf9, 0x71, 0xe0, 0xb0, 0x6f, + 0x08, 0x21, 0x0b, 0x01, 0x81, 0xe5, 0x00, 0xa3, 0xa8, 0x3e, 0x6f, 0xec, 0xe4, 0x52, 0x56, 0x11, 0x33, 0x70, 0x91, 0x41, + 0x88, 0xc0, 0x4b, 0xba, 0xdd, 0xbc, 0x38, 0xc1, 0x14, 0xbe, 0x5f, 0x6d, 0x61, 0x9f, 0x56, 0x72, 0xc3, 0x7f, 0xff, 0xfd, + 0xa6, 0xa1, 0x2d, 0x7b, 0x97, 0x00, 0xb2, 0x11, 0x27, 0xf9, 0xda, 0x94, 0xc6, 0x7f, 0xff, 0xff, 0xe2, 0x8d, 0x7d, 0xcb, + 0x8b, 0xb5, 0xc7, 0xf2, 0x33, 0x96, 0x59, 0x7e, 0x5f, 0xff, 0xff, 0xfe, 0xea, 0x2e, 0xb7, 0x2e, 0x2e, 0xe2, 0x4b, 0x2c, + 0x65, 0x56, 0x53, 0x19, 0xad, 0x1a, 0x8d, 0x7f, 0xff, 0xff, 0xff, 0xfd, 0xfd, 0x73, 0x3a, 0x7b, 0x74, 0x94, 0x96, 0x31, + 0xa5, 0xa5, 0xc8, 0x1a, 0x12, 0x9d, 0xf8, 0x3e, 0x0e, 0x06, 0x03, 0xe8, 0xd4, 0x15, 0x05, 0xff, 0xfb, 0x52, 0xc4, 0x4c, + 0x80, 0x13, 0x4c, 0xf3, 0x7b, 0xf9, 0xac, 0x04, 0x51, 0x2c, 0x0e, 0xa0, 0xc3, 0xb2, 0xf0, 0x00, 0x44, 0x40, 0x56, 0x0e, + 0xdd, 0x0f, 0x5a, 0x80, 0x59, 0x0a, 0x0e, 0x69, 0x22, 0x34, 0x69, 0x82, 0xc1, 0xcb, 0x30, 0x62, 0xa0, 0x92, 0x8d, 0x13, + 0x01, 0x47, 0x3b, 0xe5, 0xfd, 0x2d, 0xaa, 0x74, 0xc8, 0x54, 0xa4, 0xa4, 0x4d, 0x48, 0x4a, 0xa6, 0x12, 0xb9, 0x9b, 0x76, + 0x7c, 0xf9, 0xf6, 0xff, 0xb4, 0x2a, 0xff, 0x6d, 0xfa, 0xbd, 0x7b, 0x6c, 0xd6, 0xb5, 0xf6, 0x7c, 0xfb, 0x56, 0x85, 0x63, + 0xc0, 0xa8, 0x6c, 0x15, 0x0d, 0x28, 0x1a, 0x50, 0x35, 0xff, 0xdf, 0xc4, 0xb5, 0x4c, 0x41, 0x4d, 0x45, 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, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, +}; diff --git a/tests/data/tone.flac b/tests/data/tone.flac new file mode 100644 index 0000000..5b494d8 Binary files /dev/null and b/tests/data/tone.flac differ diff --git a/tests/data/tone.mp3 b/tests/data/tone.mp3 new file mode 100644 index 0000000..22a4e8d Binary files /dev/null and b/tests/data/tone.mp3 differ diff --git a/tests/data/tone.wav b/tests/data/tone.wav new file mode 100644 index 0000000..6843fd4 Binary files /dev/null and b/tests/data/tone.wav differ diff --git a/tests/header_mix_test.cpp b/tests/header_mix_test.cpp new file mode 100644 index 0000000..7fe9fe1 --- /dev/null +++ b/tests/header_mix_test.cpp @@ -0,0 +1,75 @@ +// The raw header and the import in one translation unit (the side header +// first, the canonical order): the module's names are the very same entities +// as the header's; the macros a C++ entity cannot be work beside them — MA_API +// on a declaration of one's own, the platform and backend tests, the token- +// pasting atomic declarations; and the adapted inline functions beside the +// header's own. +#include +#include + +import std; +import mcpplibs.mwrap.miniaudio; + +// A declaration of one's own in miniaudio's style. +extern "C" { +MA_API int mwrap_miniaudio_test_entry(int value); +} +extern "C" int mwrap_miniaudio_test_entry(int value) { return value + 1; } + +// A type declared by miniaudio's own macro. +typedef ma_uint32 ma_mwrap_counter; +MA_ATOMIC_SAFE_TYPE_DECL(32, 4, mwrap_counter) + +TEST(HeaderMix, SameEntities) { + // One declaration each, whichever way it was introduced. + static_assert(std::is_same_v); + static_assert(std::is_same_v<::ma_engine, ma_engine> && sizeof(::ma_device) == sizeof(ma_device)); + static_assert(std::is_same_v<::ma_result, ma_result> && ::MA_SUCCESS == MA_SUCCESS); + EXPECT_EQ(&::ma_version_string, &ma_version_string); + EXPECT_EQ(mwrap_miniaudio_test_entry(41), 42); + ma_atomic_mwrap_counter counter{}; + counter.value = 7; + EXPECT_EQ(counter.value, 7u); + static_assert(sizeof(ma_atomic_uint32) == 4); +} + +TEST(HeaderMix, MacrosBesideTheMappings) { + namespace m = mcpplibs::mwrap::miniaudio::macros; + // An object-like macro expands even in a qualified name: set it aside to + // name the constant. + constexpr auto raw = MA_MAX_CHANNELS; +#pragma push_macro("MA_MAX_CHANNELS") +#undef MA_MAX_CHANNELS + static_assert(m::MA_MAX_CHANNELS == raw); +#pragma pop_macro("MA_MAX_CHANNELS") + EXPECT_STREQ(MA_XSTRINGIFY(MA_VERSION_MINOR), "11"); +} + +TEST(HeaderMix, PlatformAndBackendTests) { + // The header's tests, beside the run-time answer. +#if defined(MA_HAS_NULL) + EXPECT_EQ(ma_is_backend_enabled(ma_backend_null), MA_TRUE); +#else + EXPECT_EQ(ma_is_backend_enabled(ma_backend_null), MA_FALSE); +#endif +#if defined(MA_EMSCRIPTEN) + EXPECT_EQ(ma_is_backend_enabled(ma_backend_webaudio), MA_TRUE); +#elif defined(MA_WIN32) + EXPECT_EQ(ma_is_backend_enabled(ma_backend_wasapi), MA_TRUE); +#elif defined(MA_APPLE) + EXPECT_EQ(ma_is_backend_enabled(ma_backend_coreaudio), MA_TRUE); +#elif defined(MA_LINUX) + EXPECT_EQ(ma_is_backend_enabled(ma_backend_alsa), MA_TRUE); +#endif +#if defined(MA_POSIX) + static_assert(std::is_same_v); +#endif +} + +TEST(HeaderMix, AdaptedInlineBesideTheHeaders) { + // The header's static inline function and the module's adaptation give + // the same result; the qualified name selects the adaptation. + EXPECT_EQ(::ma_get_bytes_per_frame(ma_format_s24, 2), mcpplibs::mwrap::miniaudio::ma_get_bytes_per_frame(ma_format_s24, 2)); + float f[4] = {}; + EXPECT_EQ(::ma_offset_pcm_frames_ptr_f32(f, 1, 2), mcpplibs::mwrap::miniaudio::ma_offset_pcm_frames_ptr_f32(f, 1, 2)); +} diff --git a/tests/macros_mix_test.cpp b/tests/macros_mix_test.cpp new file mode 100644 index 0000000..9489210 --- /dev/null +++ b/tests/macros_mix_test.cpp @@ -0,0 +1,243 @@ +// Generated by tools/gen_exports.py from miniaudio 0.11.25's miniaudio.h — do not +// edit by hand. +// +// Every mapping against the raw header, in one translation unit that includes +// (that is, ) beside the import: +// +// - each constant has its macro's type and value (the macro is set aside +// with push_macro around the comparison: while it is defined it expands +// even inside `m::NAME`); +// - each compatibility type is the type its macro names, and each +// compatibility function the very function its macro names. +#include +#include + +import std; +import mcpplibs.mwrap.miniaudio; + +namespace m = mcpplibs::mwrap::miniaudio::macros; + +// ── the raw values, while the macros are defined ──────────────────────────── +constexpr auto raw_MA_VERSION_MAJOR = MA_VERSION_MAJOR; +constexpr auto raw_MA_VERSION_MINOR = MA_VERSION_MINOR; +constexpr auto raw_MA_VERSION_REVISION = MA_VERSION_REVISION; +using raw_type_MA_VERSION_STRING = decltype(MA_VERSION_STRING); +constexpr std::string_view raw_MA_VERSION_STRING = MA_VERSION_STRING; +constexpr auto raw_MA_SIZEOF_PTR = MA_SIZEOF_PTR; +constexpr auto raw_MA_TRUE = MA_TRUE; +constexpr auto raw_MA_FALSE = MA_FALSE; +constexpr auto raw_MA_SIZE_MAX = MA_SIZE_MAX; +constexpr auto raw_MA_UINT64_MAX = MA_UINT64_MAX; +constexpr auto raw_MA_SIMD_ALIGNMENT = MA_SIMD_ALIGNMENT; +constexpr auto raw_MA_MIN_CHANNELS = MA_MIN_CHANNELS; +constexpr auto raw_MA_MAX_CHANNELS = MA_MAX_CHANNELS; +constexpr auto raw_MA_MAX_FILTER_ORDER = MA_MAX_FILTER_ORDER; +constexpr auto raw_MA_MAX_LOG_CALLBACKS = MA_MAX_LOG_CALLBACKS; +constexpr auto raw_MA_CHANNEL_INDEX_NULL = MA_CHANNEL_INDEX_NULL; +constexpr auto raw_MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT = MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT; +constexpr auto raw_MA_BACKEND_COUNT = MA_BACKEND_COUNT; +constexpr auto raw_MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE = MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE; +constexpr auto raw_MA_MAX_DEVICE_NAME_LENGTH = MA_MAX_DEVICE_NAME_LENGTH; +constexpr auto raw_MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING = MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING; +constexpr auto raw_MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT = MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT; +constexpr auto raw_MA_MAX_NODE_BUS_COUNT = MA_MAX_NODE_BUS_COUNT; +constexpr auto raw_MA_MAX_NODE_LOCAL_BUS_COUNT = MA_MAX_NODE_LOCAL_BUS_COUNT; +constexpr auto raw_MA_NODE_BUS_COUNT_UNKNOWN = MA_NODE_BUS_COUNT_UNKNOWN; +constexpr auto raw_MA_ENGINE_MAX_LISTENERS = MA_ENGINE_MAX_LISTENERS; +constexpr auto raw_MA_LISTENER_INDEX_CLOSEST = MA_LISTENER_INDEX_CLOSEST; +constexpr auto raw_MA_SOUND_SOURCE_CHANNEL_COUNT = MA_SOUND_SOURCE_CHANNEL_COUNT; +using raw_type_ma_resource_manager_job = ma_resource_manager_job; +using raw_type_ma_resource_manager_job_queue_config = ma_resource_manager_job_queue_config; +using raw_type_ma_resource_manager_job_queue = ma_resource_manager_job_queue; +constexpr auto* raw_ma_resource_manager_job_init = &ma_resource_manager_job_init; +constexpr auto* raw_ma_resource_manager_job_queue_config_init = &ma_resource_manager_job_queue_config_init; +constexpr auto* raw_ma_resource_manager_job_queue_get_heap_size = &ma_resource_manager_job_queue_get_heap_size; +constexpr auto* raw_ma_resource_manager_job_queue_init_preallocated = &ma_resource_manager_job_queue_init_preallocated; +constexpr auto* raw_ma_resource_manager_job_queue_init = &ma_resource_manager_job_queue_init; +constexpr auto* raw_ma_resource_manager_job_queue_uninit = &ma_resource_manager_job_queue_uninit; +constexpr auto* raw_ma_resource_manager_job_queue_post = &ma_resource_manager_job_queue_post; +constexpr auto* raw_ma_resource_manager_job_queue_next = &ma_resource_manager_job_queue_next; + +// ── the module's, with each macro set aside ───────────────────────────────── +#pragma push_macro("MA_VERSION_MAJOR") +#undef MA_VERSION_MAJOR +#pragma push_macro("MA_VERSION_MINOR") +#undef MA_VERSION_MINOR +#pragma push_macro("MA_VERSION_REVISION") +#undef MA_VERSION_REVISION +#pragma push_macro("MA_VERSION_STRING") +#undef MA_VERSION_STRING +#pragma push_macro("MA_SIZEOF_PTR") +#undef MA_SIZEOF_PTR +#pragma push_macro("MA_TRUE") +#undef MA_TRUE +#pragma push_macro("MA_FALSE") +#undef MA_FALSE +#pragma push_macro("MA_SIZE_MAX") +#undef MA_SIZE_MAX +#pragma push_macro("MA_UINT64_MAX") +#undef MA_UINT64_MAX +#pragma push_macro("MA_SIMD_ALIGNMENT") +#undef MA_SIMD_ALIGNMENT +#pragma push_macro("MA_MIN_CHANNELS") +#undef MA_MIN_CHANNELS +#pragma push_macro("MA_MAX_CHANNELS") +#undef MA_MAX_CHANNELS +#pragma push_macro("MA_MAX_FILTER_ORDER") +#undef MA_MAX_FILTER_ORDER +#pragma push_macro("MA_MAX_LOG_CALLBACKS") +#undef MA_MAX_LOG_CALLBACKS +#pragma push_macro("MA_CHANNEL_INDEX_NULL") +#undef MA_CHANNEL_INDEX_NULL +#pragma push_macro("MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT") +#undef MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT +#pragma push_macro("MA_BACKEND_COUNT") +#undef MA_BACKEND_COUNT +#pragma push_macro("MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE") +#undef MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE +#pragma push_macro("MA_MAX_DEVICE_NAME_LENGTH") +#undef MA_MAX_DEVICE_NAME_LENGTH +#pragma push_macro("MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING") +#undef MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING +#pragma push_macro("MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT") +#undef MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT +#pragma push_macro("MA_MAX_NODE_BUS_COUNT") +#undef MA_MAX_NODE_BUS_COUNT +#pragma push_macro("MA_MAX_NODE_LOCAL_BUS_COUNT") +#undef MA_MAX_NODE_LOCAL_BUS_COUNT +#pragma push_macro("MA_NODE_BUS_COUNT_UNKNOWN") +#undef MA_NODE_BUS_COUNT_UNKNOWN +#pragma push_macro("MA_ENGINE_MAX_LISTENERS") +#undef MA_ENGINE_MAX_LISTENERS +#pragma push_macro("MA_LISTENER_INDEX_CLOSEST") +#undef MA_LISTENER_INDEX_CLOSEST +#pragma push_macro("MA_SOUND_SOURCE_CHANNEL_COUNT") +#undef MA_SOUND_SOURCE_CHANNEL_COUNT +#pragma push_macro("ma_resource_manager_job") +#undef ma_resource_manager_job +#pragma push_macro("ma_resource_manager_job_queue_config") +#undef ma_resource_manager_job_queue_config +#pragma push_macro("ma_resource_manager_job_queue") +#undef ma_resource_manager_job_queue +#pragma push_macro("ma_resource_manager_job_init") +#undef ma_resource_manager_job_init +#pragma push_macro("ma_resource_manager_job_queue_config_init") +#undef ma_resource_manager_job_queue_config_init +#pragma push_macro("ma_resource_manager_job_queue_get_heap_size") +#undef ma_resource_manager_job_queue_get_heap_size +#pragma push_macro("ma_resource_manager_job_queue_init_preallocated") +#undef ma_resource_manager_job_queue_init_preallocated +#pragma push_macro("ma_resource_manager_job_queue_init") +#undef ma_resource_manager_job_queue_init +#pragma push_macro("ma_resource_manager_job_queue_uninit") +#undef ma_resource_manager_job_queue_uninit +#pragma push_macro("ma_resource_manager_job_queue_post") +#undef ma_resource_manager_job_queue_post +#pragma push_macro("ma_resource_manager_job_queue_next") +#undef ma_resource_manager_job_queue_next +static_assert(std::is_same_v); +static_assert(m::MA_VERSION_MAJOR == raw_MA_VERSION_MAJOR); +static_assert(std::is_same_v); +static_assert(m::MA_VERSION_MINOR == raw_MA_VERSION_MINOR); +static_assert(std::is_same_v); +static_assert(m::MA_VERSION_REVISION == raw_MA_VERSION_REVISION); +static_assert(std::is_same_v); +static_assert(std::string_view(m::MA_VERSION_STRING) == raw_MA_VERSION_STRING); +static_assert(std::is_same_v); +static_assert(m::MA_SIZEOF_PTR == raw_MA_SIZEOF_PTR); +static_assert(std::is_same_v); +static_assert(m::MA_TRUE == raw_MA_TRUE); +static_assert(std::is_same_v); +static_assert(m::MA_FALSE == raw_MA_FALSE); +static_assert(std::is_same_v); +static_assert(m::MA_SIZE_MAX == raw_MA_SIZE_MAX); +static_assert(std::is_same_v); +static_assert(m::MA_UINT64_MAX == raw_MA_UINT64_MAX); +static_assert(std::is_same_v); +static_assert(m::MA_SIMD_ALIGNMENT == raw_MA_SIMD_ALIGNMENT); +static_assert(std::is_same_v); +static_assert(m::MA_MIN_CHANNELS == raw_MA_MIN_CHANNELS); +static_assert(std::is_same_v); +static_assert(m::MA_MAX_CHANNELS == raw_MA_MAX_CHANNELS); +static_assert(std::is_same_v); +static_assert(m::MA_MAX_FILTER_ORDER == raw_MA_MAX_FILTER_ORDER); +static_assert(std::is_same_v); +static_assert(m::MA_MAX_LOG_CALLBACKS == raw_MA_MAX_LOG_CALLBACKS); +static_assert(std::is_same_v); +static_assert(m::MA_CHANNEL_INDEX_NULL == raw_MA_CHANNEL_INDEX_NULL); +static_assert(std::is_same_v); +static_assert(m::MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT == raw_MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT); +static_assert(std::is_same_v); +static_assert(m::MA_BACKEND_COUNT == raw_MA_BACKEND_COUNT); +static_assert(std::is_same_v); +static_assert(m::MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE == raw_MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE); +static_assert(std::is_same_v); +static_assert(m::MA_MAX_DEVICE_NAME_LENGTH == raw_MA_MAX_DEVICE_NAME_LENGTH); +static_assert(std::is_same_v); +static_assert(m::MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING == raw_MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING); +static_assert(std::is_same_v); +static_assert(m::MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT == raw_MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT); +static_assert(std::is_same_v); +static_assert(m::MA_MAX_NODE_BUS_COUNT == raw_MA_MAX_NODE_BUS_COUNT); +static_assert(std::is_same_v); +static_assert(m::MA_MAX_NODE_LOCAL_BUS_COUNT == raw_MA_MAX_NODE_LOCAL_BUS_COUNT); +static_assert(std::is_same_v); +static_assert(m::MA_NODE_BUS_COUNT_UNKNOWN == raw_MA_NODE_BUS_COUNT_UNKNOWN); +static_assert(std::is_same_v); +static_assert(m::MA_ENGINE_MAX_LISTENERS == raw_MA_ENGINE_MAX_LISTENERS); +static_assert(std::is_same_v); +static_assert(m::MA_LISTENER_INDEX_CLOSEST == raw_MA_LISTENER_INDEX_CLOSEST); +static_assert(std::is_same_v); +static_assert(m::MA_SOUND_SOURCE_CHANNEL_COUNT == raw_MA_SOUND_SOURCE_CHANNEL_COUNT); +static_assert(std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); + +TEST(MacrosMix, CompatibilityFunctionsAreTheFunctions) { + EXPECT_EQ(&m::ma_resource_manager_job_init, raw_ma_resource_manager_job_init); + EXPECT_EQ(&m::ma_resource_manager_job_queue_config_init, raw_ma_resource_manager_job_queue_config_init); + EXPECT_EQ(&m::ma_resource_manager_job_queue_get_heap_size, raw_ma_resource_manager_job_queue_get_heap_size); + EXPECT_EQ(&m::ma_resource_manager_job_queue_init_preallocated, raw_ma_resource_manager_job_queue_init_preallocated); + EXPECT_EQ(&m::ma_resource_manager_job_queue_init, raw_ma_resource_manager_job_queue_init); + EXPECT_EQ(&m::ma_resource_manager_job_queue_uninit, raw_ma_resource_manager_job_queue_uninit); + EXPECT_EQ(&m::ma_resource_manager_job_queue_post, raw_ma_resource_manager_job_queue_post); + EXPECT_EQ(&m::ma_resource_manager_job_queue_next, raw_ma_resource_manager_job_queue_next); +} +#pragma pop_macro("ma_resource_manager_job_queue_next") +#pragma pop_macro("ma_resource_manager_job_queue_post") +#pragma pop_macro("ma_resource_manager_job_queue_uninit") +#pragma pop_macro("ma_resource_manager_job_queue_init") +#pragma pop_macro("ma_resource_manager_job_queue_init_preallocated") +#pragma pop_macro("ma_resource_manager_job_queue_get_heap_size") +#pragma pop_macro("ma_resource_manager_job_queue_config_init") +#pragma pop_macro("ma_resource_manager_job_init") +#pragma pop_macro("ma_resource_manager_job_queue") +#pragma pop_macro("ma_resource_manager_job_queue_config") +#pragma pop_macro("ma_resource_manager_job") +#pragma pop_macro("MA_SOUND_SOURCE_CHANNEL_COUNT") +#pragma pop_macro("MA_LISTENER_INDEX_CLOSEST") +#pragma pop_macro("MA_ENGINE_MAX_LISTENERS") +#pragma pop_macro("MA_NODE_BUS_COUNT_UNKNOWN") +#pragma pop_macro("MA_MAX_NODE_LOCAL_BUS_COUNT") +#pragma pop_macro("MA_MAX_NODE_BUS_COUNT") +#pragma pop_macro("MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT") +#pragma pop_macro("MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING") +#pragma pop_macro("MA_MAX_DEVICE_NAME_LENGTH") +#pragma pop_macro("MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE") +#pragma pop_macro("MA_BACKEND_COUNT") +#pragma pop_macro("MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT") +#pragma pop_macro("MA_CHANNEL_INDEX_NULL") +#pragma pop_macro("MA_MAX_LOG_CALLBACKS") +#pragma pop_macro("MA_MAX_FILTER_ORDER") +#pragma pop_macro("MA_MAX_CHANNELS") +#pragma pop_macro("MA_MIN_CHANNELS") +#pragma pop_macro("MA_SIMD_ALIGNMENT") +#pragma pop_macro("MA_UINT64_MAX") +#pragma pop_macro("MA_SIZE_MAX") +#pragma pop_macro("MA_FALSE") +#pragma pop_macro("MA_TRUE") +#pragma pop_macro("MA_SIZEOF_PTR") +#pragma pop_macro("MA_VERSION_STRING") +#pragma pop_macro("MA_VERSION_REVISION") +#pragma pop_macro("MA_VERSION_MINOR") +#pragma pop_macro("MA_VERSION_MAJOR") diff --git a/tests/macros_test.cpp b/tests/macros_test.cpp new file mode 100644 index 0000000..07f18b2 --- /dev/null +++ b/tests/macros_test.cpp @@ -0,0 +1,50 @@ +// The macros module on its own (no header, no root module): the constants and +// the compatibility names are constant expressions, as the macros are, so they +// work in constant-initialised tables, array bounds and static_asserts. +import std; +import mcpplibs.mwrap.miniaudio.macros; + +using namespace mcpplibs::mwrap::miniaudio::macros; + +// Every constant has the type its macro expands to. +static_assert(std::is_same_v); +static_assert(std::is_same_v); // 254 +// MA_SIZE_MAX is SIZE_MAX where the header sees , and 0xFFFFFFFF +// where it does not: the module includes alone. +static_assert(std::is_same_v || std::is_same_v); +static_assert(std::is_same_v // ma_uint64 + || std::is_same_v); +static_assert(std::is_same_v); // ((ma_uint8)-1) +static_assert(std::is_same_v); // (1U << 1) +static_assert(std::is_same_v); // 0xFFFFFFFF +static_assert(std::is_same_v); + +static_assert(MA_VERSION_MAJOR == 0 && MA_VERSION_MINOR == 11 && MA_VERSION_REVISION == 25); +static_assert(std::string_view(MA_VERSION_STRING) == "0.11.25"); +static_assert(MA_TRUE == 1 && MA_FALSE == 0); +static_assert(MA_MIN_CHANNELS == 1 && MA_MAX_CHANNELS == 254 && MA_MAX_FILTER_ORDER == 8); +static_assert(MA_SIZE_MAX == std::numeric_limits::max() || MA_SIZE_MAX == 0xFFFFFFFFu); +static_assert(MA_UINT64_MAX == std::numeric_limits::max()); +static_assert(MA_SIZEOF_PTR == sizeof(void*)); +static_assert(MA_SIMD_ALIGNMENT == 32 && MA_MAX_LOG_CALLBACKS == 4 && MA_CHANNEL_INDEX_NULL == 255); +static_assert(MA_MAX_NODE_BUS_COUNT == 254 && MA_MAX_NODE_LOCAL_BUS_COUNT == 2 && MA_NODE_BUS_COUNT_UNKNOWN == 255); +static_assert(MA_ENGINE_MAX_LISTENERS == 4 && MA_LISTENER_INDEX_CLOSEST == 255); +static_assert(MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT == 64 && MA_MAX_DEVICE_NAME_LENGTH == 255); +static_assert(MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE == 2u && MA_SOUND_SOURCE_CHANNEL_COUNT == 0xFFFFFFFFu); +static_assert(MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT == 1); +static_assert(MA_BACKEND_COUNT > 10); // ma_backend_null + 1 + +// An array bound and a table, at compile time. +constexpr std::array listeners{}; +static_assert(listeners.size() == 4); +char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; + +// The compatibility names are the job queue's. +static_assert(std::is_class_v && std::is_class_v); +static_assert(sizeof(ma_resource_manager_job_queue_config) > 0); +static_assert(std::is_function_v>); + +int main() { + name[0] = 0; + return listeners[0] + name[0]; +} diff --git a/tools/candidate_index.py b/tools/candidate_index.py new file mode 100644 index 0000000..26d75b8 --- /dev/null +++ b/tools/candidate_index.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +"""The compat namespace from mcpp-index's candidate branch, while the published +index does not yet carry compat.miniaudio's gnu11 build. + +compat.miniaudio 0.11.25 is on the published index, compiled at c11 — which +Emscripten refuses for miniaudio's Web Audio backend (EM_ASM needs a GNU C +dialect). mcpplibs/mcpp-index#609 compiles it at gnu11. Until that descriptor +is on the index's main branch, this tool clones the PR's branch, prepares the +unchanged namespace views of its descriptors (the index's own +tests/prepare_mwrap_indices.py) and prints the checkout. + + --checkout-only print the candidate checkout (nothing once published), + for tools/test_template.py --index + --ci also append `[indices] compat = { path = }` to this + checkout's manifests (the root and examples/miniaudio), in + CI's working copy only + +Once the published index has the gnu11 descriptor, it does nothing. +""" +import argparse +from pathlib import Path +import subprocess +import sys +import urllib.error +import urllib.request + +INDEX = 'https://github.com/mcpplibs/mcpp-index' +BRANCH = 'compat-miniaudio-web' +PUBLISHED = 'https://raw.githubusercontent.com/mcpplibs/mcpp-index/main/pkgs/c/compat.miniaudio.lua' +MANIFESTS = ['mcpp.toml', 'examples/miniaudio/mcpp.toml'] + + +def published() -> bool: + try: + with urllib.request.urlopen(PUBLISHED, timeout=60) as response: + return 'c_standard = "gnu11"' in response.read().decode('utf-8') + except urllib.error.HTTPError as error: + if error.code == 404: + return False + raise + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + mode = parser.add_mutually_exclusive_group(required=True) + mode.add_argument('--checkout-only', action='store_true') + mode.add_argument('--ci', action='store_true') + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + if published(): + print('compat.miniaudio (gnu11) is published: the published index is used', file=sys.stderr) + return + checkout = root / 'target/candidate-index' + if not (checkout / 'index.toml').exists(): + subprocess.run(['git', 'clone', '--quiet', '--depth', '1', '--branch', BRANCH, INDEX + '.git', str(checkout)], + check=True, stdout=sys.stderr) + subprocess.run([sys.executable, str(checkout / 'tests/prepare_mwrap_indices.py')], cwd=checkout, check=True, + stdout=sys.stderr) + view = checkout / 'tests/mwrap/.indices/compat' + if not (view / 'pkgs/view/compat.miniaudio.lua').exists(): + sys.exit(f'{INDEX} {BRANCH} has no compat.miniaudio') + if args.ci: + for manifest in MANIFESTS: + with (root / manifest).open('a', encoding='utf-8', newline='\n') as out: + out.write('\n# CI only (tools/candidate_index.py): compat.miniaudio (gnu11) from ' + BRANCH + '\n') + out.write('[indices]\ncompat = { path = "' + view.as_posix() + '" }\n') + print('candidate compat index for', manifest, file=sys.stderr) + print(checkout.as_posix()) + + +if __name__ == '__main__': + main() diff --git a/tools/check_exports.py b/tools/check_exports.py new file mode 100644 index 0000000..1470bbc --- /dev/null +++ b/tools/check_exports.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python3 +"""Audit the module against miniaudio 0.11.25's miniaudio.h, on this machine's target. + +1. The generated sources are what tools/gen_exports.py writes from the + pinned header (src/miniaudio.cppm, src/inline.cpp, src/macros.cppm, + tests/macros_mix_test.cpp). +2. The raw header, every #if branch read: each declaration of the API + section is exported (or listed in NOT_EXPORTED with its reason), each + `static MA_INLINE` function adapted, each macro mapped, kept as a macro in + with its reason, or listed as not mapped; and + every mapping is checked against the header by tests/macros_mix_test.cpp. +3. This target, as the compiler sees it: the header is preprocessed with the + module's own compile command (from compile_commands.json, so run `mcpp + build` first), and so are the module sources. Every function, type, struct + tag and enumerator the header declares here must be exported here, and + every macro it leaves defined here must be mapped here or listed. Run on + every CI row: POSIX declares the pthread types, Windows + ma_IMMNotificationClient, Emscripten no Null backend. +""" +from __future__ import annotations + +import json +import os +from pathlib import Path +import re +import shlex +import subprocess +import sys + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +from inventory import fetch, surface # noqa: E402 +import gen_exports # noqa: E402 + + +def compile_command(root: Path) -> list[str]: + # The configuration databases mcpp keeps in target///: + # the newest one is the last `mcpp build`'s. + found = sorted(list(root.glob('target/*/*/compile_commands.json')) + list(root.glob('compile_commands.json')), + key=lambda p: p.stat().st_mtime, reverse=True) + norm = lambda p: os.path.normcase(str(Path(p).resolve())) # noqa: E731 + module = norm(root / 'src/miniaudio.cppm') + for db in found: + entries = [e for e in json.loads(db.read_text(encoding='utf-8')) + if norm(Path(e['directory'], e['file'])) == module] + if entries: + entry = entries[0] + break + else: + sys.exit('no compile command for src/miniaudio.cppm (target/*/*/compile_commands.json): run `mcpp build` first') + args = entry.get('arguments') or shlex.split(entry['command'], posix=os.name != 'nt') + out, skip = [], False + for a in args: + if skip: + skip = False + continue + if a in ('-c', '-o', '-x', '-MF', '-MT', '-MQ'): + skip = a != '-c' + continue + if a == entry['file'] or a.endswith('miniaudio.cppm') or a.startswith( + ('-fmodule', '-fprebuilt-module-path', '-fmodules', '-fdeps-', '--precompile', '-MD', '-MMD')): + continue + out.append(a) + return out + + +def preprocess(cmd: list[str], source: str, work: Path, name: str) -> str: + work.mkdir(parents=True, exist_ok=True) + path = work / name + path.write_text(source, encoding='utf-8') + run = subprocess.run(cmd + ['-x', 'c++', '-E', '-dD', str(path)], + capture_output=True, text=True, encoding='utf-8', errors='replace') + if run.returncode != 0: + sys.exit(f'preprocessing {name} failed:\n{run.stderr[-4000:]}') + return run.stdout + + +def from_miniaudio_h(text: str) -> tuple[str, set[str]]: + """The code miniaudio.h contributes and the macros it leaves defined, from -E -dD output.""" + code, macros, current = [], set(), False + for line in text.splitlines(): + m = re.match(r'#\s*(?:line\s+)?\d+\s+"([^"]*)"', line) + if m: + current = m.group(1).replace('\\\\', '/').replace('\\', '/').endswith('/miniaudio.h') + continue + d = re.match(r'#\s*(define|undef)\s+(\w+)', line) + if d: + if d.group(1) == 'define' and current: + macros.add(d.group(2)) + elif d.group(1) == 'undef': + macros.discard(d.group(2)) + continue + if line.startswith('#'): + continue + if current: + code.append(line) + return '\n'.join(code), macros + + +def module_text(path: Path) -> str: + """A module source without its module and import declarations, to preprocess.""" + return '\n'.join(line for line in path.read_text(encoding='utf-8').splitlines() + if not re.match(r'\s*(export\s+)?(module|import)\b[^;]*;\s*$', line)) + '\n' + + +def declared(code: str) -> tuple[set[str], set[str]]: + """(exportable names, static inline functions) of preprocessed C declarations.""" + names, inlines = set(), set() + # The C++ view of the header is inside `extern "C" { … }`: read it as C. + code = re.sub(r'extern\s+"C"\s*\{', ' ', code) + statement, depth = '', 0 + for ch in code: + if ch == '}' and depth == 0: + continue # the extern "C" block's closing brace + statement += ch + if ch == '{': + depth += 1 + elif ch == '}': + depth -= 1 + if depth == 0 and re.match(r'\s*static\b', statement) and '(' in statement.split('{', 1)[0]: + head = statement.split('{', 1)[0] + inlines.add(re.findall(r'\b(\w+)\s*\(', head)[-1]) + statement = '' + elif ch == ';' and depth == 0: + text = ' '.join(statement.split()) + statement = '' + if not text or text == ';' or text.startswith(('extern "C"', 'namespace ')): + continue + text = re.sub(r'__attribute__\s*\(\(.*?\)\)\s*', '', text) + text = re.sub(r'__declspec\s*\(\w+\)\s*', '', text) + if text.startswith('extern ') and '(' in text: + names.add(re.match(r'extern [^(]*?\b(\w+)\s*\(', text).group(1)) + continue + if not text.startswith(('typedef ', 'struct ', 'union ')): + sys.exit('a preprocessed declaration this audit does not know: ' + text[:200]) + for tag in re.findall(r'^(?:typedef\s+)?(?:struct|union|enum)\s+(\w+)', text): + names.add(tag) + if '{' in text: + if re.match(r'typedef enum\b', text): + body = text[text.index('{') + 1:text.rindex('}')] + names.update(re.findall(r'(?:^|,)\s*([A-Za-z_]\w*)', body)) + tail = text[text.rindex('}') + 1:] + else: + tail = text + if text.startswith('typedef'): + fp = re.search(r'\(\s*\*\s*(\w+)\s*\)\s*\(', tail) + if fp: + names.add(fp.group(1)) + else: + for decl in tail.rstrip(';').split(','): + m = re.search(r'(\w+)\s*(?:\[[^\]]*\])?\s*$', decl) + if m: + names.add(m.group(1)) + names.discard('typedef') + return names, inlines + + +def main(): + root = Path(__file__).resolve().parents[1] + problems = [] + + # 1. generated sources + generated = subprocess.run([sys.executable, str(root / 'tools/gen_exports.py'), '--check'], + capture_output=True, text=True) + if generated.returncode != 0: + problems.append(generated.stderr.strip() or generated.stdout.strip()) + + # 2. the raw header, every branch + sf = surface(fetch(root)) + module = (root / 'src/miniaudio.cppm').read_text(encoding='utf-8') + exported = set(re.findall(r'^export using ::(\w+);', module, flags=re.M)) + raw = (set(sf.types) | set(sf.enumerators) | set(sf.functions)) - gen_exports.NOT_EXPORTED.keys() + if raw - exported: + problems.append('declared but not exported: ' + ', '.join(sorted(raw - exported))) + if exported - raw: + problems.append('exported but not declared: ' + ', '.join(sorted(exported - raw))) + adapted = set(re.findall(r'^[\w\s\*]+?\b(ma_\w+)\(', module.split('export namespace mcpplibs::mwrap::miniaudio {')[1], + flags=re.M)) + if adapted != {f.name for f in sf.inlines}: + problems.append(f'static inline functions {sorted(f.name for f in sf.inlines)} != adapted {sorted(adapted)}') + constants, alias_types, alias_functions = gen_exports.classify(sf) + mapped = set(constants) | set(alias_types) | set(alias_functions) + listed = gen_exports.SIDE_HEADER.keys() | gen_exports.NOT_MAPPED.keys() + if sf.macros.keys() - mapped - listed: + problems.append('macros neither mapped nor listed: ' + ', '.join(sorted(sf.macros.keys() - mapped - listed))) + if listed - sf.macros.keys(): + problems.append('listed but not in the header: ' + ', '.join(sorted(listed - sf.macros.keys()))) + test = (root / 'tests/macros_mix_test.cpp').read_text(encoding='utf-8') + untested = {n for n in mapped if f'm::{n}' not in test} + if untested: + problems.append('mapped but not checked against the header: ' + ', '.join(sorted(untested))) + side = (root / 'include/mwrap/miniaudio/macros.hpp').read_text(encoding='utf-8') + if '#include ' not in side: + problems.append(' does not include ') + + # 3. this target + cmd = compile_command(root) + work = root / 'target/check-exports' + header_code, header_macros = from_miniaudio_h(preprocess(cmd, '#include \n', work, 'header.cpp')) + here, here_inline = declared(header_code) + here -= gen_exports.NOT_EXPORTED.keys() + module_pp = preprocess(cmd, module_text(root / 'src/miniaudio.cppm'), work, 'module.cpp') + exported_here = set(re.findall(r'^\s*export using ::(\w+);', module_pp, flags=re.M)) + if here - exported_here: + problems.append('declared on this target but not exported here: ' + ', '.join(sorted(here - exported_here))) + if exported_here - here: + problems.append('exported here but not declared on this target: ' + ', '.join(sorted(exported_here - here))) + if here_inline != adapted: + problems.append(f'static inline functions on this target {sorted(here_inline)} != adapted {sorted(adapted)}') + macros_pp = preprocess(cmd, module_text(root / 'src/macros.cppm'), work, 'macros.cpp') + defined_here = set(re.findall(r'^inline constexpr auto&? (\w+) = c::value_\1;', macros_pp, flags=re.M)) + defined_here |= set(re.findall(r'^using (\w+) = c::type_\1;', macros_pp, flags=re.M)) + header_macros.discard('miniaudio_h') + unaccounted = header_macros - mapped - listed + if unaccounted: + problems.append('macros defined on this target neither mapped nor listed: ' + ', '.join(sorted(unaccounted))) + missing = (header_macros & mapped) - defined_here + if missing: + problems.append('macros defined on this target but not mapped here: ' + ', '.join(sorted(missing))) + + if problems: + sys.exit('\n'.join(problems)) + print(f'{len(sf.types)} types and struct tags, {len(sf.enumerators)} enumerators and {len(sf.functions)} MA_API ' + f'functions in the header (every branch), each exported under its condition; {len(sf.inlines)} static ' + f'inline functions adapted; {len(sf.macros)} macros: {len(constants)} constants, {len(alias_types)} type ' + f'and {len(alias_functions)} function compatibility names mapped (each checked against the header), ' + f'{len(gen_exports.SIDE_HEADER)} kept as macros, {len(gen_exports.NOT_MAPPED)} not mapped. On this target: ' + f'{len(here)} declarations, all exported; {len(header_macros)} macros, all accounted for ' + f'({len(header_macros & mapped)} mapped).') + + +if __name__ == '__main__': + main() diff --git a/tools/check_mwrap_release.py b/tools/check_mwrap_release.py new file mode 100644 index 0000000..9bedddb --- /dev/null +++ b/tools/check_mwrap_release.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +"""Check the immutable mwrap release coordinate and bilingual entry pages.""" +import argparse +import hashlib +import json +from pathlib import Path +import re +import tomllib + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--tag', help='release tag; omitted during PR checks') + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + package = tomllib.loads((root / 'mcpp.toml').read_text(encoding="utf-8"))['package'] + assert package['namespace'] == 'mcpplibs.mwrap', package + assert re.fullmatch(r'[A-Za-z_][A-Za-z_0-9]*', package['name']), package['name'] + upstream = package['metadata']['mwrap']['upstream-version'] + version = package['version'] + assert version == upstream or re.fullmatch(re.escape(upstream) + r'\.[1-9][0-9]*', version), (version, upstream) + if args.tag: + assert args.tag == 'mwrap-' + version, (args.tag, version) + assert package['license'] == 'Apache-2.0', package['license'] + assert package['authors'] == ['mcpp-community'], package.get('authors') + license_text = (root / 'LICENSE').read_text(encoding='utf-8') + assert 'Apache License' in license_text and 'Version 2.0' in license_text + assert 'mcpp-community' in (root / 'NOTICE').read_text(encoding='utf-8') + documents = json.loads((root / 'upstream/documents.json').read_text(encoding='utf-8'))['documents'] + assert any(Path(d['path']).name.startswith('README') for d in documents) + assert any(Path(d['path']).name.startswith(('LICENSE', 'COPYING')) for d in documents) + deployed = {entry['from'] for entry in tomllib.loads((root / 'mcpp.toml').read_text(encoding='utf-8')).get('runtime', {}).get('deploy', [])} + assert {'LICENSE', 'NOTICE'} <= deployed + for document in documents: + path = Path(document['path']) + assert not path.is_absolute() and '..' not in path.parts and path.parts[0] == 'upstream' + assert hashlib.sha256((root / path).read_bytes()).hexdigest() == document['sha256'], path + assert document['source'] and path.as_posix() in deployed, path + identity = package['namespace'] + '.' + package['name'] + for name, other in [('README.md', 'README.zh.md'), ('README.zh.md', 'README.md')]: + text = (root / name).read_text(encoding="utf-8") + assert len(text.splitlines()) <= 150, name + assert '](' + other + ')' in '\n'.join(text.splitlines()[:12]), name + assert identity in text and version in text, name + assert text.count('```') % 2 == 0, name + print(identity + '@' + version) + + +if __name__ == '__main__': + main() diff --git a/tools/gen_exports.py b/tools/gen_exports.py new file mode 100644 index 0000000..d2766e6 --- /dev/null +++ b/tools/gen_exports.py @@ -0,0 +1,320 @@ +#!/usr/bin/env python3 +"""Write the module sources and the generated macro test from miniaudio.h. + +- src/miniaudio.cppm exports every type, struct tag, enumerator and MA_API + function of the API section of miniaudio.h by `export using` (the upstream + globals, unchanged), each under the preprocessor condition the header + declares it under; it declares the adaptations of the three `static + MA_INLINE` functions in mcpplibs::mwrap::miniaudio and re-exports the + macros module. +- src/inline.cpp defines those adaptations, each calling upstream's own. +- src/macros.cppm holds, in mcpplibs::mwrap::miniaudio::macros under their + own names: + * the value macros (MA_VERSION_*, MA_MAX_CHANNELS, MA_SIZE_MAX, + MA_LISTENER_INDEX_CLOSEST …) as `inline constexpr` of the type of the + macro's own expansion, the version string as a reference to a + constexpr char array, each defined where the header defines it; + * the compatibility names the header keeps as macros + (ma_resource_manager_job → ma_job, ma_resource_manager_job_queue_init → + ma_job_queue_init …): the types as aliases, the functions as constexpr + references to the functions they name, the flag as a constant. +- tests/macros_mix_test.cpp checks each mapping against the raw header in a + translation unit that includes it beside the import. + +With --check, nothing is written and a difference fails. +""" +from __future__ import annotations + +import argparse +from pathlib import Path +import sys + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +from inventory import Surface, condition_text, fetch, surface # noqa: E402 + +VERSION = '0.11.25' +NOTICE = (f'// Generated by tools/gen_exports.py from miniaudio {VERSION}\'s miniaudio.h — do not\n' + '// edit by hand.\n') + +# Macros that stay macros, in (which is ), with the reason. +STRINGIFY = 'stringification' +DECLARES = 'declares a type by token pasting (the atomic wrappers ma_atomic_uint32 …, exported as types)' +ATTRIBUTE = 'an attribute, storage class or inline specifier of declarations' +PLATFORM = 'a platform test for conditional compilation (#ifdef)' +BACKEND = 'a backend test for conditional compilation (#ifdef); at run time ma_is_backend_enabled()' +CONFIG = 'a configuration switch for conditional compilation (#ifdef)' +SIDE_HEADER = { + 'MA_STRINGIFY': STRINGIFY, 'MA_XSTRINGIFY': STRINGIFY, + 'MA_ATOMIC': 'an alignment specifier of a declaration', + 'MA_ATOMIC_SAFE_TYPE_DECL': DECLARES, 'MA_ATOMIC_SAFE_TYPE_DECL_PTR': DECLARES, + 'MA_ATTRIBUTE_FORMAT': ATTRIBUTE, 'MA_FALLTHROUGH': 'a statement attribute', 'MA_INLINE': ATTRIBUTE, + 'MA_NO_INLINE': ATTRIBUTE, 'MA_GNUC_INLINE_HINT': ATTRIBUTE, 'MA_DLL_IMPORT': ATTRIBUTE, + 'MA_DLL_EXPORT': ATTRIBUTE, 'MA_DLL_PRIVATE': ATTRIBUTE, 'MA_API': ATTRIBUTE, 'MA_PRIVATE': ATTRIBUTE, + 'MA_NO_THREADING': CONFIG, 'MA_NO_RUNTIME_LINKING': CONFIG, 'MA_NO_RESOURCE_MANAGER': CONFIG, +} +PLATFORMS = ['MA_WIN32', 'MA_WIN32_UWP', 'MA_WIN32_GDK', 'MA_WIN32_NXDK', 'MA_WIN32_DESKTOP', 'MA_XBOX', + 'MA_XBOX_NXDK', 'MA_DOS', 'MA_POSIX', 'MA_UNIX', 'MA_LINUX', 'MA_APPLE', 'MA_BSD', 'MA_ANDROID', + 'MA_EMSCRIPTEN', 'MA_ORBIS', 'MA_PROSPERO', 'MA_3DS', 'MA_SWITCH', 'MA_BEOS', 'MA_HAIKU'] +SIDE_HEADER.update({name: PLATFORM for name in PLATFORMS}) +# Not mapped: the C library's. +NOT_MAPPED = {'NULL': "the C library's (the header defines it only where did not)"} +# Not exported: a typedef the header writes for MSVC's C mode, a keyword in C++. +NOT_EXPORTED = {'wchar_t': 'a keyword in C++ (the typedef is for MSVC C without _WCHAR_T_DEFINED)'} + +# The compatibility names the header keeps as macros (the resource manager's +# job queue became the general ma_job queue): what each names. +ALIAS_TYPES = ['ma_resource_manager_job', 'ma_resource_manager_job_queue_config', 'ma_resource_manager_job_queue'] + + +def is_backend(name: str) -> bool: + return name.startswith(('MA_SUPPORT_', 'MA_HAS_')) + + +def classify(sf: Surface): + """(constants, alias types, alias functions); every other macro is listed.""" + for name in sf.macros: + if is_backend(name): + SIDE_HEADER.setdefault(name, BACKEND) + constants, functions = [], [] + for name, macro in sf.macros.items(): + if name in SIDE_HEADER or name in NOT_MAPPED or name in ALIAS_TYPES: + continue + if macro.params is not None: + sys.exit(f'{name}: a function-like macro without a decision') + if any(not body for body in macro.bodies): + sys.exit(f'{name}: an empty macro without a decision') + if name.startswith('ma_'): + if not all(b in sf.functions for b in macro.bodies): + sys.exit(f'{name}: a lower-case macro that names no function: {macro.bodies}') + functions.append(name) + else: + constants.append(name) + return constants, [n for n in ALIAS_TYPES if n in sf.macros], functions + + +def emit_grouped(entries: list[tuple[str, str]]) -> list[str]: + """`export using ::name;` lines, consecutive equal conditions in one #if.""" + out, current = [], None + for name, cond in entries: + if cond != current: + if current: + out.append('#endif') + if cond: + out.append(f'#if {cond}') + current = cond + out.append(f'export using ::{name};') + if current: + out.append('#endif') + return out + + +def module_source(sf: Surface) -> str: + types = [(n, condition_text(c)) for n, c in sf.types.items() if n not in NOT_EXPORTED] + enumerators = [(n, condition_text(c)) for n, c in sf.enumerators.items()] + functions = [(n, condition_text(c)) for n, c in sf.functions.items()] + lines = [NOTICE.rstrip('\n'), '''// +// mcpplibs.mwrap.miniaudio — miniaudio, audio playback, capture, decoding, +// encoding, conversion, mixing and the high-level engine in one library, as a +// C++ module. Every exported name is the upstream global of , +// unchanged: the types and struct tags, the enumerators of its enums, and +// every MA_API function (context, device, engine, sound, node graph, resource +// manager, decoder, encoder, data sources, converters, resamplers, filters, +// effects, ring buffers, logging, allocation). Each is exported under the +// condition the header declares it under: the POSIX thread types on POSIX, +// ma_IMMNotificationClient on Windows. The three `static MA_INLINE` functions +// are adapted in mcpplibs::mwrap::miniaudio (src/inline.cpp). The root also +// re-exports the macro mappings. The library is compat.miniaudio, built from +// the same release; the module includes only the declarations (no +// MINIAUDIO_IMPLEMENTATION). +module; +#include + +export module mcpplibs.mwrap.miniaudio; + +export import mcpplibs.mwrap.miniaudio.macros; +'''] + lines.append(f'// types and struct tags ({len(types)})') + lines += emit_grouped(types) + lines.append('') + lines.append(f'// enumerators ({len(enumerators)})') + lines += emit_grouped(enumerators) + lines.append('') + lines.append(f'// MA_API functions ({len(functions)})') + lines += emit_grouped(functions) + lines.append('') + lines.append(f'// The static MA_INLINE functions ({len(sf.inlines)}): internal linkage, not exportable;') + lines.append('// adapted under the same names and signatures, each calling upstream\'s (src/inline.cpp).') + lines.append('export namespace mcpplibs::mwrap::miniaudio {') + for f in sf.inlines: + if f.condition: + sys.exit(f'{f.name}: a conditional inline function') + lines.append(f'{f.returns} {f.name}({f.params});') + lines.append('} // namespace mcpplibs::mwrap::miniaudio') + return '\n'.join(lines) + '\n' + + +def inline_source(sf: Surface) -> str: + lines = [NOTICE.rstrip('\n'), '''// +// The adaptations of the `static MA_INLINE` functions of miniaudio.h: each +// calls upstream's own, which has internal linkage in this translation unit. +module; +#include + +module mcpplibs.mwrap.miniaudio; +'''] + for f in sf.inlines: + lines.append(f'{f.returns} mcpplibs::mwrap::miniaudio::{f.name}({f.params}) {{ ' + f'return ::{f.name}({", ".join(f.args)}); }}') + return '\n'.join(lines) + '\n' + + +def macros_source(sf: Surface) -> str: + constants, alias_types, alias_functions = classify(sf) + lines = [NOTICE.rstrip('\n'), f'''// +// mcpplibs.mwrap.miniaudio.macros — the macros of miniaudio.h a named module +// cannot export as they are, under their original names in +// mcpplibs::mwrap::miniaudio::macros: +// +// - {len(constants)} value macros as `inline constexpr`, each of the type its macro +// expands to (MA_MAX_CHANNELS is an `int`, as 254 is; MA_SIZE_MAX a +// `size_t`; MA_LISTENER_INDEX_CLOSEST an `ma_uint8`; MA_BACKEND_COUNT an +// `int`), the version string as a reference to a constexpr char array. +// Each is defined where the header defines it (#ifdef); +// - the compatibility names the header keeps as macros: {len(alias_types)} types as +// aliases of the types they name (ma_resource_manager_job is ma_job) and +// {len(alias_functions)} functions as constexpr references to the functions they name +// (ma_resource_manager_job_queue_init is ma_job_queue_init). +// +// {len(SIDE_HEADER)} macros stay macros — stringification, attributes and storage +// classes, the token-pasting type declarations, the platform and backend +// tests (MA_WIN32, MA_POSIX, MA_SUPPORT_*, MA_HAS_*) — in +// , included before the import; NULL is the C +// library's. tools/check_exports.py accounts for every one. +module; +#include + +export module mcpplibs.mwrap.miniaudio.macros; + +// The header's values and names, taken while its macros are defined (module linkage). +namespace mwrap_miniaudio_capture {{'''] + for name in constants: + lines.append(f'#ifdef {name}') + if name == 'MA_VERSION_STRING': + lines.append(f'inline constexpr char value_{name}[] = {name};') + else: + lines.append(f'inline constexpr auto value_{name} = {name};') + lines.append('#endif') + for name in alias_types: + lines += [f'#ifdef {name}', f'using type_{name} = {name};', '#endif'] + for name in alias_functions: + lines += [f'#ifdef {name}', f'inline constexpr auto& value_{name} = {name};', '#endif'] + lines.append('} // namespace mwrap_miniaudio_capture') + lines.append('') + lines.append('// The names, now free: each macro is undefined in this unit only.') + for name in constants + alias_types + alias_functions: + lines += [f'#ifdef {name}', f'#undef {name}', f'#define MWRAP_HAS_{name} 1', '#endif'] + lines.append('') + lines.append('export namespace mcpplibs::mwrap::miniaudio::macros {') + lines.append('namespace c = ::mwrap_miniaudio_capture;') + lines.append('') + lines.append(f'// value macros ({len(constants)})') + for name in constants: + ref = '&' if name == 'MA_VERSION_STRING' else '' + lines += [f'#ifdef MWRAP_HAS_{name}', f'inline constexpr auto{ref} {name} = c::value_{name};', '#endif'] + lines.append('') + lines.append(f'// compatibility type names ({len(alias_types)})') + for name in alias_types: + lines += [f'#ifdef MWRAP_HAS_{name}', f'using {name} = c::type_{name};', '#endif'] + lines.append('') + lines.append(f'// compatibility function names ({len(alias_functions)})') + for name in alias_functions: + lines += [f'#ifdef MWRAP_HAS_{name}', f'inline constexpr auto& {name} = c::value_{name};', '#endif'] + lines.append('') + lines.append('} // namespace mcpplibs::mwrap::miniaudio::macros') + return '\n'.join(lines) + '\n' + + +def mix_test_source(sf: Surface) -> str: + constants, alias_types, alias_functions = classify(sf) + lines = [NOTICE.rstrip('\n'), '''// +// Every mapping against the raw header, in one translation unit that includes +// (that is, ) beside the import: +// +// - each constant has its macro's type and value (the macro is set aside +// with push_macro around the comparison: while it is defined it expands +// even inside `m::NAME`); +// - each compatibility type is the type its macro names, and each +// compatibility function the very function its macro names. +#include +#include + +import std; +import mcpplibs.mwrap.miniaudio; + +namespace m = mcpplibs::mwrap::miniaudio::macros; + +// ── the raw values, while the macros are defined ────────────────────────────'''] + for name in constants: + if name == 'MA_VERSION_STRING': + lines += [f'using raw_type_{name} = decltype({name});', + f'constexpr std::string_view raw_{name} = {name};'] + else: + lines.append(f'constexpr auto raw_{name} = {name};') + for name in alias_types: + lines.append(f'using raw_type_{name} = {name};') + for name in alias_functions: + lines.append(f'constexpr auto* raw_{name} = &{name};') + lines.append('') + lines.append('// ── the module\'s, with each macro set aside ─────────────────────────────────') + for name in constants + alias_types + alias_functions: + lines += [f'#pragma push_macro("{name}")', f'#undef {name}'] + for name in constants: + if name == 'MA_VERSION_STRING': + lines.append(f'static_assert(std::is_same_v);') + lines.append(f'static_assert(std::string_view(m::{name}) == raw_{name});') + else: + lines.append(f'static_assert(std::is_same_v);') + lines.append(f'static_assert(m::{name} == raw_{name});') + for name in alias_types: + lines.append(f'static_assert(std::is_same_v);') + lines.append('') + lines.append('TEST(MacrosMix, CompatibilityFunctionsAreTheFunctions) {') + for name in alias_functions: + lines.append(f' EXPECT_EQ(&m::{name}, raw_{name});') + lines.append('}') + for name in reversed(constants + alias_types + alias_functions): + lines.append(f'#pragma pop_macro("{name}")') + return '\n'.join(lines) + '\n' + + +def outputs(root: Path) -> dict[Path, str]: + sf = surface(fetch(root)) + return { + root / 'src/miniaudio.cppm': module_source(sf), + root / 'src/inline.cpp': inline_source(sf), + root / 'src/macros.cppm': macros_source(sf), + root / 'tests/macros_mix_test.cpp': mix_test_source(sf), + } + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--check', action='store_true', help='fail if a generated file differs') + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + stale = [] + for path, text in outputs(root).items(): + old = path.read_text(encoding='utf-8') if path.exists() else None + if old == text: + continue # unchanged: keep the file (and its timestamp) as it is + if args.check: + stale.append(path.relative_to(root).as_posix()) + else: + path.write_bytes(text.encode('utf-8')) + print('wrote', path.relative_to(root).as_posix()) + if stale: + sys.exit('stale generated sources (run tools/gen_exports.py): ' + ', '.join(stale)) + + +if __name__ == '__main__': + main() diff --git a/tools/gen_fixtures.py b/tools/gen_fixtures.py new file mode 100644 index 0000000..4a9861f --- /dev/null +++ b/tools/gen_fixtures.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +"""Write the decoder fixtures of tests/ (wrapper contributions, Apache-2.0). + +tests/data/tone.wav is 0.1 s of a 440 Hz sine at half scale, mono, 44.1 kHz, +16-bit PCM, written here sample by sample. tests/data/tone.flac is the same +samples losslessly (ffmpeg's FLAC encoder), tests/data/tone.mp3 the same tone +at 64 kbit/s (ffmpeg with libmp3lame). tests/data/fixtures.inc holds the three +files as byte arrays, so the tests decode them from memory, and from a file +they write, on every target — wasm32-emscripten under node included. + +The committed files are the measured ones: the tests read them, not this +script, which only needs to run again to change them. +""" +import math +from pathlib import Path +import struct +import subprocess + +RATE, FRAMES, FREQ = 44100, 4410, 440.0 + + +def main(): + data = Path(__file__).resolve().parents[1] / 'tests/data' + data.mkdir(parents=True, exist_ok=True) + samples = [round(0.5 * 32767 * math.sin(2 * math.pi * FREQ * n / RATE)) for n in range(FRAMES)] + pcm = struct.pack(f'<{FRAMES}h', *samples) + header = (b'RIFF' + struct.pack(' Path: + pins = json.loads((root / 'upstream/documents.json').read_text(encoding='utf-8')) + cache = root / 'target/upstream' + cache.mkdir(parents=True, exist_ok=True) + archive = cache / ('miniaudio-' + pins['upstream_version'] + '.tar.gz') + if not archive.exists() or hashlib.sha256(archive.read_bytes()).hexdigest() != pins['upstream_sha256']: + print('+ fetch', pins['upstream'], flush=True, file=sys.stderr) + with urllib.request.urlopen(pins['upstream'], timeout=120) as response: + archive.write_bytes(response.read()) + digest = hashlib.sha256(archive.read_bytes()).hexdigest() + if digest != pins['upstream_sha256']: + sys.exit(f'upstream archive checksum {digest} != {pins["upstream_sha256"]}') + with tarfile.open(archive) as tar: + top = tar.getmembers()[0].name.split('/')[0] + if not (cache / top / 'miniaudio.h').exists(): + tar.extractall(cache, members=[m for m in tar.getmembers() + if m.name in (top, f'{top}/miniaudio.h')], filter='data') + return cache / top + + +@dataclass +class Macro: + name: str + params: list[str] | None # None: object-like + bodies: list[str] # one per #define of it (the header defines some per platform) + + +@dataclass +class Inline: + """A `static MA_INLINE` function: internal linkage, adapted by the module.""" + name: str + returns: str + params: str # the parameter list as declared + args: list[str] # the parameter names + condition: tuple + + +@dataclass +class Surface: + # name -> the conditions it is declared under (one per declaration; () is unconditional) + types: dict[str, list[str]] = field(default_factory=dict) # typedef names and struct tags + enumerators: dict[str, list[str]] = field(default_factory=dict) + enum_of: dict[str, str] = field(default_factory=dict) # enumerator -> its enum's typedef + functions: dict[str, list[str]] = field(default_factory=dict) # MA_API + inlines: list[Inline] = field(default_factory=list) + macros: dict[str, Macro] = field(default_factory=dict) + order: list[tuple[str, str]] = field(default_factory=list) # (kind, name) in header order + + +def strip_comments(text: str) -> str: + # Keep the newlines a comment spans, so line structure survives. + text = re.sub(r'/\*.*?\*/', lambda m: '\n' * m.group(0).count('\n') or ' ', text, flags=re.S) + return re.sub(r'//[^\n]*', '', text) + + +def api_section(upstream: Path) -> str: + text = (upstream / 'miniaudio.h').read_text(encoding='utf-8') + begin = text.index(API_BEGIN) + end = text.index(API_END, begin) + # Without the include guard itself (`#ifndef miniaudio_h` / `#define + # miniaudio_h` … `#endif`): it is defined by the time anything evaluates. + body = text[begin + len(API_BEGIN):end] + body = body.replace('#define miniaudio_h', '', 1) + return strip_comments(body).replace('\\\n', ' ') + + +def directive_expr(kind: str, rest: str) -> str: + rest = ' '.join(rest.split()) + if kind == 'ifdef': + return f'defined({rest})' + if kind == 'ifndef': + return f'!defined({rest})' + return rest + + +# The header's #if chains: frame id -> the condition of each branch (None: #else). +FRAMES: dict[int, list[str | None]] = {} + +Path_ = tuple # a condition: ((frame id, branch index), …), outermost first; () is unconditional + + +def lines_with_conditions(text: str): + """Yield (code line, condition) for every non-directive line; and the + macro definitions as ('#define', name, params, body, condition).""" + FRAMES.clear() + stack: list[int] = [] # the open #if chains + for line in text.split('\n'): + m = re.match(r'^[ \t]*#[ \t]*(\w+)(.*)$', line) + if not m: + yield ('code', line, condition(stack)) + continue + kind, rest = m.group(1), m.group(2).strip() + if kind in ('if', 'ifdef', 'ifndef'): + FRAMES[len(FRAMES)] = [directive_expr(kind, rest)] + stack.append(len(FRAMES) - 1) + elif kind == 'elif': + FRAMES[stack[-1]].append(directive_expr('if', rest)) + elif kind == 'else': + FRAMES[stack[-1]].append(None) + elif kind == 'endif': + stack.pop() + elif kind == 'define': + d = re.match(r'(\w+)(\(([^)]*)\))?\s*(.*)$', rest) + params = [p.strip() for p in d.group(3).split(',')] if d.group(2) else None + yield ('define', d.group(1), params, ' '.join(d.group(4).split()), condition(stack)) + if stack: + sys.exit('unbalanced conditionals in the API section') + + +def condition(stack: list[int]) -> Path_: + return tuple((frame, len(FRAMES[frame]) - 1) for frame in stack) + + +def branch_expr(frame: int, branch: int) -> str: + """The condition of one branch of an #if/#elif/#else chain.""" + branches = FRAMES[frame] + parts = [f'!({b})' for b in branches[:branch]] + if branches[branch] is not None: + parts.append(f'({branches[branch]})' if parts else branches[branch]) + return ' && '.join(parts) + + +def render(path: Path_) -> str: + exprs = [branch_expr(f, b) for f, b in path] + return exprs[0] if len(exprs) == 1 else ' && '.join(f'({e})' for e in exprs) + + +def simplify(paths: list[Path_]) -> list[Path_]: + """The conditions a name is declared under, with every chain whose + branches (an #else among them) all declare it removed: `ma_int64` is + declared in each branch of `#if defined(MA_USE_STDINT) … #else … #endif`, + so it is declared whatever that chain selects.""" + paths = set(paths) + changed = True + while changed: + changed = False + for p in sorted(paths, key=len, reverse=True): + if not p: + continue + frame = p[-1][0] + total = FRAMES[frame] + siblings = {q for q in paths if q[:-1] == p[:-1] and q and q[-1][0] == frame} + if None in total and {q[-1][1] for q in siblings} == set(range(len(total))): + paths = (paths - siblings) | {p[:-1]} + changed = True + break + if () in paths: + return [()] + return sorted(paths) + + +def condition_text(paths: list[Path_]) -> str: + """One preprocessor expression for the conditions ('' if unconditional).""" + paths = simplify(paths) + if paths == [()]: + return '' + return render(paths[0]) if len(paths) == 1 else ' || '.join(f'({render(p)})' for p in paths) + + +def surface(upstream: Path) -> Surface: + s = Surface() + code: list[tuple[str, str]] = [] + for item in lines_with_conditions(api_section(upstream)): + if item[0] == 'define': + _, name, params, body, _cond = item + if name in s.macros: + s.macros[name].bodies.append(body) + else: + s.macros[name] = Macro(name, params, [body]) + else: + code.append((item[1], item[2])) + + # C++ only: the extern "C" brackets are in `#ifdef __cplusplus` blocks. + code = [(line, cond) for line, cond in code if 'defined(__cplusplus)' not in render(cond)] + + # Statements at brace depth 0, each with the condition of its first line. + def add(kind: str, table: dict[str, list[str]], name: str, cond: str): + if name not in table: + s.order.append((kind, name)) + table.setdefault(name, []).append(cond) + + statement, start_cond, depth = '', None, 0 + for line, cond in code: + for ch in line + '\n': + if not statement.strip() and not ch.isspace(): + start_cond = cond + statement += ch + if ch == '{': + depth += 1 + elif ch == '}': + depth -= 1 + elif ch == ';' and depth == 0: + declaration(s, add, ' '.join(statement.split()), start_cond, statement) + statement, start_cond = '', None + elif ch == ')' and depth == 0 and re.fullmatch(r'\s*MA_ATOMIC_SAFE_TYPE_DECL(_PTR)?\s*\([^()]*\)\s*', statement): + # The atomic wrappers are declared by a macro (no `;` after it). + m = re.match(r'\s*MA_ATOMIC_SAFE_TYPE_DECL(_PTR)?\s*\(([^()]*)\)', statement) + args = [a.strip() for a in m.group(2).split(',')] + add('type', s.types, ('ma_atomic_ptr_' if m.group(1) else 'ma_atomic_') + args[-1], start_cond) + statement, start_cond = '', None + # A static inline function definition ends at its closing brace. + if depth == 0 and re.match(r'\s*static\s+MA_INLINE\b', statement) and statement.rstrip().endswith('}'): + inline(s, ' '.join(statement.split()), start_cond) + statement, start_cond = '', None + if statement.strip(): + sys.exit('trailing text in the API section: ' + ' '.join(statement.split())[:200]) + return s + + +def inline(s: Surface, text: str, cond: str): + m = re.match(r'static MA_INLINE (.+?)\b(ma_\w+)\s*\((.*?)\)\s*\{', text) + if not m: + sys.exit('a static inline definition the inventory does not know: ' + text[:200]) + params = m.group(3).strip() + args = [re.search(r'(\w+)\s*$', p).group(1) for p in params.split(',')] if params and params != 'void' else [] + s.inlines.append(Inline(m.group(2), m.group(1).strip(), params, args, cond)) + s.order.append(('inline', m.group(2))) + + +def declaration(s: Surface, add, text: str, cond: str, raw: str): + if text in (';', ''): + return + if text.startswith('MA_API '): + f = re.match(r'MA_API [^(]*?\b(\w+)\s*\(', text) + if not f: + sys.exit('MA_API on something that is not a function: ' + text[:200]) + add('function', s.functions, f.group(1), cond) + return + m = re.match(r'typedef enum\s*(\w+)?\s*\{(.*)\}\s*(\w+)\s*;$', text) + if m: + add('type', s.types, m.group(3), cond) + if m.group(1): + add('type', s.types, m.group(1), cond) + # Enumerators, each under the enum's condition and any inside it. + body = raw[raw.index('{') + 1:raw.rindex('}')] + for e in re.findall(r'(?:^|[,{\s])([A-Za-z_]\w*)\s*(?:=[^,]*)?(?=,|\s*$)', body, flags=re.M): + add('enumerator', s.enumerators, e, cond) + s.enum_of[e] = m.group(3) + return + m = re.match(r'typedef (struct|union)\s*(\w+)?\s*\{.*\}\s*(\w+(?:\s*,\s*\w+)*)\s*;$', text) + if m: + if m.group(2): + add('type', s.types, m.group(2), cond) + for name in m.group(3).split(','): # `} ma_lpf1_config, ma_lpf2_config;` + add('type', s.types, name.strip(), cond) + return + m = re.match(r'typedef (struct|union) (\w+) (\w+);$', text) + if m: + add('type', s.types, m.group(2), cond) + add('type', s.types, m.group(3), cond) + return + m = re.match(r'(struct|union) (\w+)\s*\{.*\}\s*;$', text) + if m: + add('type', s.types, m.group(2), cond) + return + m = re.match(r'typedef [^;(]*\(\s*\*\s*(\w+)\s*\)\s*\(.*\)\s*;$', text) + if m: + add('type', s.types, m.group(1), cond) + return + m = re.match(r'typedef [\w\s\*]+?\b(\w+)\s*;$', text) + if m: + add('type', s.types, m.group(1), cond) + return + m = re.match(r'typedef [\w\s]+?\b(\w+)\s*\[\s*\w+\s*\]\s*;$', text) + if m: + add('type', s.types, m.group(1), cond) + return + sys.exit('a declaration the inventory does not know: ' + text[:300]) + + +if __name__ == '__main__': + root = Path(__file__).resolve().parents[1] + sf = surface(fetch(root)) + conditional = lambda table: sum(1 for c in table.values() if condition_text(c)) # noqa: E731 + print(f'{len(sf.types)} types ({conditional(sf.types)} conditional), ' + f'{len(sf.enumerators)} enumerators ({conditional(sf.enumerators)} conditional), ' + f'{len(sf.functions)} functions ({conditional(sf.functions)} conditional), ' + f'{len(sf.inlines)} static inline functions, {len(sf.macros)} macros') + for kind, table in (('type', sf.types), ('enumerator', sf.enumerators), ('function', sf.functions)): + for name, conds in table.items(): + if condition_text(conds): + print(f' {kind} {name}: {condition_text(conds)}') diff --git a/tools/run_examples.py b/tools/run_examples.py new file mode 100644 index 0000000..b13c60f --- /dev/null +++ b/tools/run_examples.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +"""Build examples/miniaudio, an audio file tool written against the module, and +check what it does on this target without an audio device: a tone written as +WAV, the decoder fixtures of tests/data (WAV, FLAC, MP3) measured, and each +converted to WAV at another rate, channel count and sample format, then +measured again. `devices` and `play` run on the default backend, which on a +CI machine is the Null backend. + + --target build and run for that target (wasm32-emscripten: under node) +""" +import argparse +from pathlib import Path +import re +import subprocess +import sys +import tempfile + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--mcpp', default='mcpp') + parser.add_argument('--target') + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + example = root / 'examples/miniaudio' + target = ['--target', args.target] if args.target else [] + subprocess.run([args.mcpp, 'build', *target], cwd=example, check=True) + + def run(*argv: str) -> str: + out = subprocess.run([args.mcpp, 'run', *target, '--', *argv], cwd=example, check=True, + capture_output=True, text=True) + print('$ miniaudio', ' '.join(argv), '\n' + out.stdout.rstrip(), flush=True) + return out.stdout + + def measured(line: str) -> dict: + m = re.search(r': (\d+) ch, (\d+) Hz, (\d+) frames \(([\d.]+) s\), peak ([\d.]+), rms ([\d.]+)', line) + assert m, line + return dict(channels=int(m[1]), rate=int(m[2]), frames=int(m[3]), peak=float(m[5]), rms=float(m[6])) + + data = root / 'tests/data' + with tempfile.TemporaryDirectory(prefix='miniaudio-examples-') as tmp: + tone = Path(tmp) / 'tone.wav' + run('tone', str(tone), '--freq', '1000', '--seconds', '0.5', '--rate', '48000') + t = measured(run('info', str(tone))) + assert (t['channels'], t['rate'], t['frames']) == (1, 48000, 24000), t + assert abs(t['peak'] - 0.5) < 1e-3 and abs(t['rms'] - 0.5 / 2 ** 0.5) < 2e-3, t + for name in ('tone.wav', 'tone.flac', 'tone.mp3'): + src = measured(run('info', str(data / name))) + assert (src['channels'], src['rate']) == (1, 44100), src + out = Path(tmp) / (name + '.wav') + run('convert', str(data / name), str(out), '--rate', '48000', '--channels', '2', '--format', 'f32') + dst = measured(run('info', str(out))) + assert (dst['channels'], dst['rate']) == (2, 48000), dst + assert abs(dst['frames'] - src['frames'] * 48000 / 44100) <= 2, (src, dst) + assert abs(dst['rms'] - src['rms']) < 0.01, (src, dst) + # The default backend's devices and playback: reported, not required — + # whether a CI machine has an audio endpoint is the machine's business. + if not args.target or 'emscripten' not in args.target: + for argv in (['devices'], ['play', str(tone), '--seconds', '0.2']): + out = subprocess.run([args.mcpp, 'run', *target, '--', *argv], cwd=example, + capture_output=True, text=True) + print('$ miniaudio', ' '.join(argv), f'(exit {out.returncode})\n' + (out.stdout + out.stderr).rstrip()) + print('examples ok') + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/test_template.py b/tools/test_template.py new file mode 100644 index 0000000..81ea805 --- /dev/null +++ b/tools/test_template.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +"""Render an installed candidate's default mcpp template, then build and run it.""" +import argparse +import json +import os +from pathlib import Path +import shutil +import subprocess +import tempfile +import tomllib + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--mcpp", default="mcpp") + parser.add_argument("--namespace", help="index namespace for legacy manifests without package.namespace") + parser.add_argument("--toolchain", default="llvm@23.1.3") + parser.add_argument("--template", help="named template; omit for the package default") + parser.add_argument("--run-arg", action="append", default=[]) + parser.add_argument("--index", type=Path, help="candidate SDK/wrapper index for unpublished feature dependencies") + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + metadata = tomllib.loads((root / "mcpp.toml").read_text())["package"] + namespace = metadata.get("namespace", args.namespace) + assert namespace, "Supply the published index namespace for this legacy manifest" + name, version = metadata["name"], metadata["version"] + identity = namespace + "." + name + with tempfile.TemporaryDirectory(prefix=name + "-template-") as directory: + temporary = Path(directory) + home = temporary / "home" + package = home / "registry/data/xpkgs" / (namespace + "-x-" + name) / version / (name + "-" + version) + shutil.copytree(root, package, ignore=shutil.ignore_patterns( + ".git", "target", ".mcpp", ".xlings", ".candidate-index", "__pycache__", "mcpp.lock", "compile_commands.json", "mcpp-2026.*")) + index = home / "indices/mcpplibs/pkgs/mwrap" + index.mkdir(parents=True) + entry = '{url="https://example.invalid/candidate.tar.gz",sha256="fixture"}' + descriptor = ('package={spec="1",namespace=' + json.dumps(namespace) + ',name=' + json.dumps(name) + + ',description="Installed template fixture",type="package",mcpp="mcpp.toml",xpm={') + descriptor += ",".join(platform + "={[" + json.dumps(version) + "]=" + entry + "}" + for platform in ("linux", "macosx", "windows")) + "}}\n" + (index / (identity + ".lua")).write_text(descriptor) + env = dict(os.environ, MCPP_HOME=str(home)) + selector = identity + "@" + version + for command in ([args.mcpp, "new", "--list-templates", selector], + [args.mcpp, "new", "quickstart", "--template", selector + (":" + args.template if args.template else "")]): + print("+", " ".join(command), flush=True) + subprocess.run(command, cwd=temporary, env=env, check=True) + project = temporary / "quickstart" + manifest = project / "mcpp.toml" + text = manifest.read_text() + dependency = tomllib.loads(text)["dependencies"][identity] + options = {"version": dependency} if isinstance(dependency, str) else dependency + assert options["version"] == version, options + replacement = '{ path = ' + json.dumps(package.as_posix()) + if options.get("features"): + replacement += ', features = ' + json.dumps(options["features"]) + replacement += ' }' + lines = text.splitlines() + matches = [i for i, line in enumerate(lines) if line.startswith(json.dumps(identity) + " =")] + assert len(matches) == 1, "Expected exactly one qualified dependency from self.name" + lines[matches[0]] = json.dumps(identity) + " = " + replacement + manifest.write_text("\n".join(lines) + "\n") + if args.index: + candidate_index = args.index.resolve() + subprocess.run([os.sys.executable, str(candidate_index / "tests/prepare_mwrap_indices.py")], + cwd=candidate_index, check=True) + with manifest.open("a") as out: + out.write("\n[indices]\n") + for namespace in ("compat", "mcpplibs.mwrap"): + view = candidate_index / "tests/mwrap/.indices" / namespace + out.write(json.dumps(namespace) + ' = { path = ' + json.dumps(view.as_posix()) + ' }\n') + command = [args.mcpp, "build", "--toolchain", args.toolchain, "--strict"] + print("+", " ".join(command), flush=True) + subprocess.run(command, cwd=project, check=True) + command = [args.mcpp, "run", "--toolchain", args.toolchain] + if args.run_arg: + command += ["--", *args.run_arg] + print("+", " ".join(command), flush=True) + subprocess.run(command, cwd=project, check=True) + + +if __name__ == "__main__": + main() diff --git a/upstream/documents.json b/upstream/documents.json new file mode 100644 index 0000000..c18b1f9 --- /dev/null +++ b/upstream/documents.json @@ -0,0 +1,18 @@ +{ + "upstream": "https://github.com/mackron/miniaudio/archive/refs/tags/0.11.25.tar.gz", + "upstream_version": "0.11.25", + "upstream_sha256": "b900edcffe979816e2560a0580b9b1216d674b4f17fbadeca8f777a7f8ab0274", + "pruning": "Nothing of miniaudio is vendored: the library is compat.miniaudio 0.11.25, built from the same tag archive (upstream's miniaudio.c, which compiles miniaudio.h with MINIAUDIO_IMPLEMENTATION). Its README and license (a choice of the Unlicense / public domain or MIT No Attribution) are retained here.", + "documents": [ + { + "path": "upstream/miniaudio/README.md", + "source": "https://github.com/mackron/miniaudio/blob/0.11.25/README.md", + "sha256": "3189aa9039ba073fab747948435e0fa5e279a32384c311ac87e9ff970eef037e" + }, + { + "path": "upstream/miniaudio/LICENSE", + "source": "https://github.com/mackron/miniaudio/blob/0.11.25/LICENSE", + "sha256": "457f1b500e0adf6bc059edddfa78a2f62012e7c3bb43476c20e0bd23b25ba0eb" + } + ] +} diff --git a/upstream/miniaudio/LICENSE b/upstream/miniaudio/LICENSE new file mode 100644 index 0000000..2f9423a --- /dev/null +++ b/upstream/miniaudio/LICENSE @@ -0,0 +1,47 @@ +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - Public Domain (www.unlicense.org) +=============================================================================== +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. + +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2025 David Reid + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/upstream/miniaudio/README.md b/upstream/miniaudio/README.md new file mode 100644 index 0000000..7d88537 --- /dev/null +++ b/upstream/miniaudio/README.md @@ -0,0 +1,213 @@ +

+ miniaudio +
+

+ +

An audio playback and capture library in a single source file.

+ +

+ discord + x +

+ +

+ Features - + Examples - + Building - + Documentation - + Supported Platforms - + Security - + License +

+ +miniaudio is written in C with no dependencies except the standard library and should compile clean on all major +compilers without the need to install any additional development packages. All major desktop and mobile platforms +are supported. + + +Features +======== +- Simple build system with no external dependencies. +- Simple and flexible API. +- Low-level API for direct access to raw audio data. +- High-level API for sound management, mixing, effects and optional 3D spatialization. +- Flexible node graph system for advanced mixing and effect processing. +- Resource management for loading sound files. +- Decoding, with built-in support for WAV, FLAC, and MP3, in addition to being able to plug in custom decoders. +- Encoding (WAV only). +- Data conversion. +- Resampling, including custom resamplers. +- Channel mapping. +- Basic generation of waveforms and noise. +- Basic effects and filters. + +Refer to the [Programming Manual](https://miniaud.io/docs/manual/) for a more complete description of +available features in miniaudio. + + +Examples +======== + +This example shows one way to play a sound using the high level API. + +```c +#include "miniaudio/miniaudio.h" + +#include + +int main() +{ + ma_result result; + ma_engine engine; + + result = ma_engine_init(NULL, &engine); + if (result != MA_SUCCESS) { + return -1; + } + + ma_engine_play_sound(&engine, "sound.wav", NULL); + + printf("Press Enter to quit..."); + getchar(); + + ma_engine_uninit(&engine); + + return 0; +} +``` + +This example shows how to decode and play a sound using the low level API. + +```c +#include "miniaudio/miniaudio.h" + +#include + +void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) +{ + ma_decoder* pDecoder = (ma_decoder*)pDevice->pUserData; + if (pDecoder == NULL) { + return; + } + + ma_decoder_read_pcm_frames(pDecoder, pOutput, frameCount, NULL); + + (void)pInput; +} + +int main(int argc, char** argv) +{ + ma_result result; + ma_decoder decoder; + ma_device_config deviceConfig; + ma_device device; + + if (argc < 2) { + printf("No input file.\n"); + return -1; + } + + result = ma_decoder_init_file(argv[1], NULL, &decoder); + if (result != MA_SUCCESS) { + return -2; + } + + deviceConfig = ma_device_config_init(ma_device_type_playback); + deviceConfig.playback.format = decoder.outputFormat; + deviceConfig.playback.channels = decoder.outputChannels; + deviceConfig.sampleRate = decoder.outputSampleRate; + deviceConfig.dataCallback = data_callback; + deviceConfig.pUserData = &decoder; + + if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) { + printf("Failed to open playback device.\n"); + ma_decoder_uninit(&decoder); + return -3; + } + + if (ma_device_start(&device) != MA_SUCCESS) { + printf("Failed to start playback device.\n"); + ma_device_uninit(&device); + ma_decoder_uninit(&decoder); + return -4; + } + + printf("Press Enter to quit..."); + getchar(); + + ma_device_uninit(&device); + ma_decoder_uninit(&decoder); + + return 0; +} +``` + +More examples can be found in the [examples](examples) folder or online here: https://miniaud.io/docs/examples/ + + +Building +======== +Just compile miniaudio.c like any other source file and include miniaudio.h like a normal header. There's no need +to install any dependencies. On Windows and macOS there's no need to link to anything. On Linux and BSD just link +to `-lpthread` and `-lm`. On iOS you need to compile as Objective-C. Link to `-ldl` if you get errors about +`dlopen()`, etc. + +If you get errors about undefined references to `__sync_val_compare_and_swap_8`, `__atomic_load_8`, etc. you +need to link with `-latomic`. + +ABI compatibility is not guaranteed between versions so take care if compiling as a DLL/SO. The suggested way +to integrate miniaudio is by adding it directly to your source tree. + +You can also use CMake if that's your preference. + + +Documentation +============= +Online documentation can be found here: https://miniaud.io/docs/ + +Documentation can also be found at the top of [miniaudio.h](https://raw.githubusercontent.com/mackron/miniaudio/master/miniaudio.h) +which is always the most up-to-date and authoritative source of information on how to use miniaudio. All other +documentation is generated from this in-code documentation. + + +Supported Platforms +=================== +- Windows +- macOS, iOS +- Linux +- FreeBSD / OpenBSD / NetBSD +- Android +- Raspberry Pi +- Emscripten / HTML5 + +miniaudio should compile clean on other platforms, but it will not include any support for playback or capture +by default. To support that, you would need to implement a custom backend. You can do this without needing to +modify the miniaudio source code. See the [custom_backend](examples/custom_backend.c) example. + +Backends +-------- +- WASAPI +- DirectSound +- WinMM +- Core Audio (Apple) +- ALSA +- PulseAudio +- JACK +- sndio (OpenBSD) +- audio(4) (NetBSD and OpenBSD) +- OSS (FreeBSD) +- AAudio (Android 8.0+) +- OpenSL|ES (Android only) +- Web Audio (Emscripten) +- Null (Silence) +- Custom + + +Security +======== +See the miniaudio [security policy](.github/SECURITY.md). + + +License +======= +Your choice of either public domain or [MIT No Attribution](https://github.com/aws/mit-0).