# JustOneCacophony — C++ Core [中文](README.md) · [Mathematics](docs/math.en.md) · [Binaural rendering](docs/binaural.en.md) · [SIMD dispatch](docs/simd.en.md) The C++ implementation of JustOneCacophony: an execution core for E-AC-3 JOC bitstream parsing, object reconstruction and rendering. It extracts EMDF, ID14 JOC parameters and ID11 OAMD metadata from E-AC-3 syncframes, combines them with the core 5.1 PCM decoded by FFmpeg to rebuild the LFE and 15 object signals, and writes ADM BWF, a WAV for a chosen speaker layout, or a binaural WAV using a compiled HRTF directional field. This is research code, not a complete, standard-conformant or production JOC decoder. It covers the bitstream forms it implements and reports an explicit error on unknown variants instead of pretending everything is in harmony. ## Building ```powershell cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release cmake --build build ctest --test-dir build --output-on-failure ``` Only MSVC (VS 2022, static CRT) is validated locally; Linux and macOS are built and unit-tested by `.github/workflows/ci.yml`. Floating-point behaviour is part of the byte-exact acceptance, so fast-math is never enabled: `/fp:precise` on MSVC, `-fno-fast-math` elsewhere. Windows Release builds target AVX2 by default (`JOC_ENABLE_AVX2`, ON, see `CMakeLists.txt`). That switch is itself part of the byte-exact acceptance — the SHA-256 of every rendered output is identical — and buys 12.4% on the SOFA binaural kernel and 1.8% on Rosella. The price is a runtime requirement: such a `joc_core.dll` executes AVX2 instructions and dies on an illegal instruction on pre-2013 x86. There is no runtime dispatch, so a binary is one or the other: ```powershell cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DJOC_ENABLE_AVX2=OFF ``` gives a baseline-ISA (SSE2) build that runs on any x86-64. Non-MSVC builds never receive the flag. ### Paths and encoding Every path inside the library is **UTF-8**, converted only at the OS boundary (`src/foundation/fs_utf8.*`): on Windows through `std::filesystem::path` (UTF-16 inside) into `_wfopen`/`CreateProcessW`, and as plain bytes elsewhere. Command line arguments are re-parsed from `GetCommandLineW` + `CommandLineToArgvW` on Windows and the console code page is set to UTF-8, so non-ASCII paths (Japanese, Chinese, ...) work for the input, the ffmpeg child process and the output files alike; a non-ASCII path regression case runs in `ctest`. ## Artifacts | Artifact | Purpose | |---|---| | `joc_core.dll` | The engine: bitstream parsing, JOC/OAMD, DSP, speaker and binaural rendering, ADM BWF/WAV writing, file task, streaming surface | | `joc_cli.exe` | Command line frontend for file tasks | | `include/joc_core.h` | Engine, telemetry and file-task interface (pure C) | | `include/joc_stream.h` | Embedder-facing streaming push/pull interface (pure C, self-contained) | ## Command line The arguments match the reference Python CLI exactly: the input is positional, **ADM BWF is the default output**, `--speaker-layout` or `--binaural` selects the other two modes, and without `-o` the result lands in `output/`. ```powershell # Default: ADM BWF (inherently 24-bit, so there is no format option) joc_cli "07. Gold Forever (2021 Master).m4a" # -> output/07. Gold Forever (2021 Master).adm.wav joc_cli input.m4a -o out/adm.wav # explicit output # Speaker layout joc_cli input.m4a --speaker-layout 5.1 # -> output/.5.1.wav joc_cli input.m4a --speaker-layout 7.1.4 --speaker-output out/714.wav --speaker-format int24 # Binaural (HRTF defaults to /HRTF/binaural.sofa, then /HRTF/binaural.personalized_headphone) joc_cli input.m4a --binaural joc_cli input.m4a --binaural --sofa-hrtf HRTF/other.sofa # another SOFA joc_cli input.m4a --binaural --personalized-headphone # Rosella personalisation # -> output/.binaural.wav # Other common switches joc_cli input.m4a --duration 30 --gain-db -3 --trajectory-mode dense64 joc_cli input.eac3 --metadata-only --print-metadata summary # parse and print metadata only ``` `--speaker-format` / `--binaural-format` default to `float32`; an `int24` request that would clip follows `--clip-action` (default `ask`; a non-interactive terminal must pass `continue`, `float32` or `abort`). `--duration` is in **seconds**, and `--object-delay-samples`, `--speaker-metadata-offset`, `--binaural-tail-seconds` and `--binaural-tail-threshold` (1e-8, the binaural tail trim) keep the reference defaults. A run always writes `.report.json` (`--report-json` overrides it). **Differences from the reference:** `--sofa-hrtf`, `--personalized-headphone`, `--backend python` and the metadata sidecars (`--metadata-dir`, `--metadata-cache`, `--metadata-backend sidecar`) are unavailable in this build and fail immediately with an explanation instead of being ignored. This build adds `--bed` (pre-decoded 6-channel float32 PCM, which skips ffmpeg decoding), `--kernels`, `--work-dir`, `--report-json`, `--dry-run` and `--quiet`. ## Library integration The engine and the file task are exposed by `joc_core.h`: `joc_task_validate` / `joc_task_execute` run a file task and report state events through a callback, and `joc_task_result` carries frame counts, peak, byte count and SHA-256. Players and decoder components use `joc_stream.h`: the caller pushes E-AC-3 bytes and the matching core PCM (or already-rebuilt objects16) at its own pace and pulls rendered PCM. Any chunking is allowed, and the result is byte-identical to the file task. ```c joc_stream_config config = {0}; config.struct_size = sizeof(config); config.input = JOC_STREAM_IN_EAC3; /* or JOC_STREAM_IN_PCM_OBJECTS16 */ config.output = JOC_STREAM_OUT_SPEAKER; /* or BINAURAL / PCM_OBJECTS16 */ config.speaker_layout_name = "5.1"; joc_stream* stream = NULL; joc_stream_create(&config, &stream); /* loop: joc_stream_push(...) / joc_stream_pull(...) */ joc_stream_flush(stream); joc_stream_destroy(stream); ``` Contract: state is instance-private, so streams coexist; push and pull on one instance must come from the same thread; rendering is stateful, so **this version offers no seek** - repositioning means decoding from the start of the stream. The kernel latency is 961 samples for speaker/binaural output and `joc_stream_flush` drains the binaural room tail. ## Layout ```text include/ public C ABI: joc_core.h (engine/file task), joc_stream.h (streaming), eac3joc_core.h (upstream ABI) src/ implementation: eac3_transport, emdf, joc_bitstream, joc_core, oamd, timeline, speaker, binaural, hrtf, adm, io, telemetry, task, stream, api, cli, simd tests/ unit tests (CTest, self-contained, no external data) docs/ mathematics, the binaural rendering flow and SIMD dispatch ``` Eight files under `src/` are byte-identical copies of the upstream JustOneCacophony native library and are never edited (see [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)). ## Compatibility note `object_delay_samples` defaults to **1473**, preserving the behaviour of the existing implementation; it is a configurable field and changing it changes the OAMD/ADM time alignment. Upstream investigation suggests the value should be 0; this project keeps the current default to stay byte-identical. ## License MIT, see [LICENSE](LICENSE). Third-party provenance and patent boundaries are in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).