Skip to content

Release v1.2.0#1

Merged
libraz merged 129 commits into
mainfrom
develop
May 27, 2026
Merged

Release v1.2.0#1
libraz merged 129 commits into
mainfrom
develop

Conversation

@libraz
Copy link
Copy Markdown
Owner

@libraz libraz commented May 26, 2026

Summary

Release v1.2.0. Bumps the version across all 5 locations (CMake, sonare.h, Python, wasm, node) and updates the changelog. Includes ~50 commits since v1.1.0 — no breaking changes.

Highlights:

  • Mixing engine: channel strips, sends/FX buses, automation lanes, scene presets, AudioWorklet bridge, offline render.
  • Mastering engine: monitor bus + automation telemetry, RT-safe dynamics, per-platform loudness targets, ducking/loudnessOptimize, de-esser.
  • Analysis/features: cosine-similarity tempogram, DSP correctness fixes (iSTFT windowing, chroma folding, K-weighting, NumPy-matching percentile interpolation).
  • Bindings: mastering assistant/profile/preview, streaming chord/pattern progression, inverse Mel/MFCC across C/Node/WASM.

Also in this PR:

  • chore(deps): ncu -u on bindings (vitest, biome 2.4.15, cmake-js 8, node-addon-api); @types/node kept at ^22 to match the Node 22 runtime; fixed biome 2.4.15 lint.
  • ci: run ctest with --parallel in the Makefile and publish workflow (ci.yml already did).
  • Fixed the stale SONARE_VERSION_* macros (were 1.0.4) so runtime version() is correct.

Test plan

  • CI green (C++ build/tests, sanitizers, wasm lint/test, coverage)
  • Local: wasm 187/187, node 102/103 pass; both bindings lint clean; native + wasm builds succeed

libraz added 30 commits May 19, 2026 21:43
…r v1.2 APIs

- types.h: add AcousticResult, DownbeatResult, MeterResult, KeyCandidateResult,
  ChordHmmResult, and LoudnessResult structs; tighten optional<float> usage for
  blind-mode c50/c80 (null vs NaN)
- exception.h: add AnalysisException subclass for analysis-layer errors
- sonare.h: expose all new analysis module headers
- quick.h/cpp: add quick_detect_acoustic, quick_detect_downbeats,
  quick_detect_meter, quick_get_key_candidates convenience wrappers
…ation

- Blind estimation mode derives room acoustics from music signals using
  energy-decay curve fitting and statistical modeling
- Impulse-response mode processes measured IR for precise RT60 per octave band
  (125 Hz through 8 kHz), EDT, and clarity metrics
- C50/C80 exposed as null (not NaN) in blind mode where undefined
- AcousticResult carries per-band octave results alongside broadband summary
…fier

- downbeat_analyzer: Viterbi decoding over beat-synchronous chroma and
  spectral flux to assign downbeat positions; outputs DownbeatResult with
  beat-level confidence scores
- meter_analyzer: classifies 3/4, 4/4, and 6/8 compound meter via
  auto-correlation of onset strength at candidate beat subdivisions;
  candidate lookup is value-based (not enum-cast) to avoid silent mismatches
- Both analyzers consume BeatResult from beat_analyzer as input
…ntext scoring

- chord_hmm: Viterbi-based HMM over chroma-template posteriors; backtrack
  guard prevents out-of-bounds access on very short segments
- chord_analyzer: integrates HMM smoother; adds detect-inversions flag (bass
  note tracking via chroma lowest-weighted bin) and key-context rescoring that
  boosts diatonic chords for the detected key
- chord_templates: expand template set with suspended, augmented, diminished,
  and add9 voicings; normalize template vectors for cosine-distance matching
- nnls_chroma: non-negative least squares chroma from log-frequency spectrogram;
  more accurate than standard chroma for polyphonic music, enabled via --nnls flag
- chroma: refactor to share filterbank logic with NNLS path; add tuning
  compensation pre-processing
- rhythm: add compute_tempogram (Fourier), compute_cyclic_tempogram, and
  tempogram_ratio helpers used by the enhanced BPM/beat pipeline
- key_analyzer/key_profiles: add Krumhansl-Kessler, Temperley, Shaath, and
  EDMA profiles selectable at runtime; expose key candidates with correlation
  scores; add mode (major/minor) and genre-hint weighting
- bpm_analyzer: integrate tempogram-based BPM refinement for librosa parity;
  add fractional BPM via parabolic interpolation
- beat_analyzer: use tempogram for initial period estimate; add librosa-parity
  beat tracking with dynamic-programming cost function
- music_analyzer: wire all new sub-analyzers; expose top-level detect_downbeats
  and detect_meter entry points
- rhythm_analyzer: align onset-strength parameters with librosa defaults
…ain stages

- lufs: implement integrated, momentary, and short-term loudness per EBU R128;
  correct overlap windows for momentary (400 ms/75%) and short-term (3 s/66%);
  add LRA (loudness range) and multichannel K-weighting support
- presets: add streaming, youtube, broadcast, podcast, audiobook, cinema,
  jpop, ambient, lofi, and classical target presets
- named_processor: add repair/dynamics chain stages (noise gate, transient
  shaper, de-esser) and progress callback support per stage
…ules

- sonare_c.h/cpp: add sonare_detect_acoustic, sonare_analyze_impulse_response,
  sonare_detect_downbeats, sonare_detect_meter, sonare_get_key_candidates,
  sonare_measure_loudness, and sonare_free_* counterparts
- sonare_c_internal: route new entry points through music_analyzer and
  acoustic_analyzer with proper lifetime management
- sonare_c_memory: register all new result types in the memory-tracking table
- sonare_c_compat: preserve deprecated symbol aliases for backward compatibility
- wasm/bindings.cpp: expose all new C++ types and functions via embind;
  register optional<float> value_or binding for nullable fields
…yping

- Node addon: add napi wrappers for detectAcoustic, analyzeImpulseResponse,
  detectDownbeats, detectMeter, getKeyCandidates, measureLoudness in
  sonare_wrap_analysis.cpp; update index.ts and types.ts
- Python: add detect_acoustic, analyze_impulse_response, detect_downbeats,
  detect_meter, get_key_candidates, measure_loudness to analyzer.py and _ffi.py;
  generate PEP 561 .pyi stubs for all public modules (__init__, analyzer, audio,
  types) and add py.typed marker
- WASM: extend public_types.ts, wasm_types.ts, sonare.js.d.ts, and index.ts
  with all new result types and entry points
- tools/gen-typescript-types.ts: code-gen script that derives TypeScript
  interfaces from C++ type definitions to keep bindings in sync
- sonare_cli.cpp: add acoustic, downbeats, meter, key-candidates, loudness
  subcommands; add --use-hmm, --detect-inversions, --key-context, --nnls,
  --use-hpss, --hpss, --loudness-weighted flags
- cli_support.cpp: fix boolean-flag registration bug where --use-hpss, --hpss,
  --loudness-weighted, --nnls, --use-hmm, --detect-inversions, and --key-context
  were consuming the next positional argument instead of acting as switches
- cli.py: add Python CLI equivalents for all new subcommands and flags
…and fixture tooling

- New C++ tests: acoustic_analyzer, downbeat_analyzer, meter_analyzer,
  nnls_chroma, chord_synthetic_matrix, key_synthetic_matrix, ebu_r128_compliance;
  tighten tolerances in bpm/beat/chord/key tests after review fixes
- Librosa high-level parity: beat_tracking_test, bpm_parity_test exercise the
  tempogram-backed pipeline against librosa reference outputs
- Fixture infrastructure: manifest TSVs (acoustic, ebu_r128, music_eval/*) plus
  Python tooling (audit_manifests, run_optional_fixture_report,
  evaluate_optional_fixture_targets, compare_optional_fixture_reports, json_safe)
  for optional dataset-based regression evaluation
- Typing smoke tests: node_smoke.ts and python_smoke.py verify that generated
  type stubs compile/import without errors
…or v1.2

- CMakeLists (root/src/tests/node): register acoustic_analyzer, downbeat_analyzer,
  meter_analyzer, chord_hmm, nnls_chroma new source files; add test targets for
  all new test files; wire gen-typescript-types into build
- .github/workflows/ci.yml: extend matrix with new test binaries; add EBU R128
  compliance job; update coverage paths
- .gitignore: exclude fixture result caches and Python __pycache__ artefacts
- Makefile: add gen-types and fixture-eval convenience targets
- README.md / README_ja.md: document all new analysis APIs, CLI flags, Python
  stubs, and mastering presets
- bindings/*/README.md: update Node, Python, and WASM binding docs
- pyproject.toml / requirements-dev.lock: bump version, add py.typed, update
  dev dependencies
…n C API and WASM embind

- Add sonare_onset_strength, sonare_fourier_tempogram, sonare_tempogram_ratio,
  and sonare_nnls_chroma to sonare_c.h / sonare_c_features.cpp /
  sonare_c_compat.cpp
- Add SonareLufsResult struct and sonare_lufs / sonare_momentary_lufs /
  sonare_short_term_lufs (no heap pointer in struct; no free required)
- Add corresponding WASM embind functions in src/wasm/bindings.cpp:
  js_onset_envelope, js_fourier_tempogram, js_tempogram_ratio,
  js_nnls_chroma, js_lufs, js_momentary_lufs, js_short_term_lufs
- Register all new functions in the EMSCRIPTEN_BINDINGS block
…FS in Node, Python, and WASM bindings

- Node (N-API): add OnsetEnvelope, FourierTempogram, TempogramRatio, NnlsChroma,
  Lufs, MomentaryLufs, ShortTermLufs in sonare_wrap_features/analysis.cpp;
  register in sonare_wrap.cpp/.h; export typed wrappers and Audio methods in
  index.ts; add LufsResult interface in types.ts
- Python: add SonareLufsResult ctypes struct and FFI signatures for all seven
  new functions in _ffi.py; implement onset_envelope, fourier_tempogram,
  tempogram_ratio, nnls_chroma, lufs, momentary_lufs, short_term_lufs in
  analyzer.py with .pyi stubs; expose LufsResult dataclass in types.py;
  re-export everything via __init__.py; add Audio convenience methods in
  audio.py/.pyi
- WASM TypeScript: add typed wrappers for all new embind functions in
  index.ts; add LufsResult and chromagram object types in public_types.ts,
  wasm_types.ts, and sonare.js.d.ts
…pogram-ratio, and nnls-chroma subcommands

- C++ CLI (tools/sonare_cli.cpp): add cmd_acoustic (blind and IR-based RT60/EDT/
  C50/C80/D50), cmd_lufs (integrated + optional momentary/short-term series),
  cmd_onset_envelope, cmd_fourier_tempogram, cmd_tempogram_ratio, cmd_nnls_chroma;
  register all in get_commands()
- Python CLI (cli.py): add matching subcommands for acoustic, rhythm, dynamics,
  timbre, lufs (--series flag), onset-envelope, nnls-chroma, tempogram, plp,
  mastering, mastering-processor, and mastering-pair-analyze; add _write_wav,
  _array_stats, and _parse_kv_params helpers
…nls_chroma, and LUFS

- C++ (tests/api/sonare_c_test.cpp): add TEST_CASEs for sonare_onset_strength,
  sonare_fourier_tempogram (shape: n_bins x n_frames), sonare_tempogram_ratio
  (default 5 factors + explicit factors), sonare_nnls_chroma, sonare_lufs,
  sonare_momentary_lufs, sonare_short_term_lufs; include null/invalid-param
  rejection checks for each
- C++ (tests/librosa/tempogram_test.cpp): fix clang-format line-length in
  existing double-cast expression
- Node (bindings/node/tests/basic.test.ts): add test suite covering
  onsetEnvelope, fourierTempogram, tempogramRatio, nnlsChroma, lufs,
  momentaryLufs, shortTermLufs, and Audio method equivalents
- Python (bindings/python/tests/test_analyzer.py): add test_onset_envelope,
  test_fourier_tempogram, test_tempogram_ratio (default and explicit factors),
  test_nnls_chroma (non-negative NNLS output), test_lufs (louder > quieter),
  test_momentary_and_short_term_lufs
- WASM (bindings/wasm/tests/new-apis.test.ts): new file covering onset, Fourier
  tempogram, tempogram ratio, PLP, NNLS chroma, and full LUFS metering suite
…S in README

- Update feature bullet and capability table to include downbeat tracking,
  time signature, HMM/inversion chord detection, NNLS chroma, Fourier
  tempogram / PLP, and EBU R128 LUFS
- Add TypeScript code examples for rhythm/chord extras and the
  onsetEnvelope -> tempogram -> tempogramRatio -> nnlsChroma -> lufs pipeline
- Add Python examples for the same APIs via Audio methods and module functions
- Expand Python CLI reference with acoustic, lufs --series, rhythm, dynamics,
  timbre, tempogram, nnls-chroma, and updated mastering examples
- Mirror all additions in README_ja.md with Japanese prose
- Implement frequency-domain pseudo-inverse using the cached CQT kernel
- Add librosa reference test with icqt.json for output validation
- Extend generate_librosa_reference.py to produce icqt fixtures
- Implement pYIN (Mauch & Dixon) fundamental-frequency estimation
- Add HMM/Viterbi decoding for voiced/unvoiced state transitions
- Match librosa.pyin API and output behavior
- Add unit tests and pyin.json reference fixtures for parity validation
Validates predominant-local-pulse output against the existing plp.json
reference fixture, increasing coverage of the tempogram family.
…on units

- Move JSON serialization into chain_json.cpp
- Move flat-params bridge into chain_params.cpp
- Move StreamingMasteringChain into chain_streaming.cpp
- Move processor-name registry into named_processor_registry.cpp
- Update src/CMakeLists.txt to list the new translation units

Pure code move with no logic change; chain.h and chain.cpp retain only
the core MasteringChain class.
- Add DrumAndBass, Techno, Metal, Trap, RnB, Jazz, KPop, Trance, and
  GameOst presets to presets.h/presets.cpp
- Expose new preset names in Node, Python, and WASM type definitions
- Add preset_test.cpp coverage for all nine new presets
- Add audio_profile.h/cpp for loudness, dynamic range, and spectral
  profiling of an input signal
- Add suggester.h/cpp for genre inference and chain recommendation
  based on the audio profile
- Wire assistant into the CLI via a --assistant flag in sonare_cli.cpp
- Register assistant translation units in src/CMakeLists.txt
- Add assistant_test.cpp and cli_test.cpp coverage
…ic drive

- Design real RBJ/Vicanek biquads in linear_phase.cpp and evaluate
  the true magnitude response via a new biquad_magnitude() helper
  instead of prior ad-hoc approximations
- Add harmonic_drive blend control to TubeSaturator (default 1.0
  preserves existing behavior)
- Extend eq_test.cpp and saturation_test.cpp for new behavior
Documents that repair/denoise is intentionally classical DSP
(spectral subtraction, MMSE-STSA, LogMMSE) and that DNN restoration,
source separation, and spectral repair are explicitly out of scope.
…ure tooling

- Add golden_hash_test.cpp for preset output hash regression testing
- Add property_test.cpp for property-based mastering chain invariants
- Add preset_hashes.tsv as the golden baseline for hash comparisons
- Add ebu_r128/README.md documenting the EBU R128 fixture contract
- Add --require-complete option to run_optional_fixture_report.py
- Register property_test and golden_hash_test in tests/CMakeLists.txt
Update the masteringPresetNames() example output in the Node, Python,
and WASM READMEs to include the nine new presets: drumAndBass, techno,
metal, trap, rnb, jazz, kpop, trance, gameOst.
… editor, voice changer, and C/WASM bindings

New modules:
- rt/: Shared DSP primitives extracted from mastering/common (biquad, delay
  line, envelope follower, oversampler, param smoother, partitioned convolver,
  true-peak filter, polyphase FIR, ADAA, nonlinearities, scoped-no-denormals,
  sliding max, processor base/chain). mastering/common headers now re-export
  from rt/ for backward compatibility.
- mixing/: Gain, pan law (equal-power), panner, channel strip (pre/post EQ,
  aux send, metering), bus, FX bus, send, VCA group, alignment delay, meter
  (peak/RMS/LUFS), stereo width, goniometer buffer, mixer controller.
- graph/: Audio routing graph with topological sort, cycle detection, and
  latency compensation (connection.h, graph.cpp/.h, node.cpp/.h).
- effects/reverb/: Dattorro plate, velvet-noise, FDN with per-line damping,
  and partitioned-convolution reverb.
- effects/delay/: Stereo delay with tap/feedback/LPF.
- effects/modulation/: LFO, modulated delay line, chorus, flanger, phaser.
- effects/native_spectral_stretch + phase_vocoder: Dependency-free phase-
  locked spectral stretch replacing Signalsmith adapter (dropped).
- analysis/pitch_editor/: F0 provider, note segmenter, scale quantizer, note
  editor, per-frame TD-PSOLA pitch corrector.
- analysis/voice_changer/: LPC-envelope formant warp, grain-OLA streaming
  retune, voice changer core/controller.
- tools/sonare_cli.cpp: CLI frontend for analysis and effects.
- src/sonare_c_daw.cpp: C API extensions covering mixing/graph/DAW surfaces.
- wasm/bindings.cpp: WASM embind coverage for new DAW surfaces.

Quality hardening (review reconciliation):
- Real reverb topologies (Dattorro, velvet noise, FDN, partitioned convolution)
  replacing earlier stubs.
- Real LPC-envelope formant warp in voice changer (was placeholder).
- Real grain-OLA streaming pitch shift in streaming_retune.
- RT-safety: no audio-thread allocation in alignment_delay or
  convolution_reverb; sidechain HPF state preallocated; graph guards against
  duplicate connections.
- DC blocker made sample-rate-dependent.
- Mono pan-law corrected.
- pitch_shift duration bug fixed to match librosa semantics (duration
  preserved rather than extended by shift ratio).

Tests: 1122 cases / 771,319 assertions all pass
…FS metering

The channel strip was a thin fader+pan wrapper; this commit turns it into
a production-ready stage matching typical DAW architecture.

ChannelStrip (channel_strip.h/cpp):
- Add ParametricEq stage with atomic EqPosition (PreFader / PostFader)
- Add pre/post-fader tap buffers (zero-allocation after prepare())
- Add MeterProcessor embedded at the end of the chain
- Add dynamic aux-send bus via add_send() / mix_send(); pre/post-fader
  routing derived from send timing; send gain is smoothed
- Warm up ParametricEq during prepare() so first process() is RT-safe
- Extend reset() to cover eq, meter, sends, and scratch buffers

MeterProcessor (meter.h/cpp):
- Add optional BS.1770-3 K-weighting (high-shelf pre-filter + RLB highpass)
  using hardcoded 48 kHz coefficients or runtime biquad design
- Add momentary (400 ms), short-term (3 s), and gated-integrated LUFS
  via a single shared ring buffer and a bounded loudness histogram
- Replace double-buffer snapshot with a seqlock for wait-free reads
- Add MeterConfig to gate LUFS work; peak/RMS path unchanged when disabled
- Default MeterSnapshot fields use constants::kFloorDb instead of -120 f literals

GainProcessor (gain.h/cpp):
- Make gain_db() read from an atomic<float> for thread-safe observer access

Support files:
- panner.h/cpp, stereo_width.h/cpp: minor accessor and smoothing cleanups
- Reverb headers (dattorro, fdn, velvet): align trailing comment whitespace
- dc_blocker, phase_vocoder, graph, voice changer, pitch corrector:
  clang-format line-length fixes only

tests/mixing/mixing_test.cpp (+361 lines):
- StereoWidthProcessor: steady-state convergence and zipper-noise guard
- MeterProcessor: seqlock seq counter, peak/RMS finiteness, LUFS sine
  reference against offline LUFS calculation, integrated gating, and
  MeterConfig disable path
- ChannelStrip: EQ insertion, pre/post-fader EQ position, aux send
  pre/post routing, and embedded meter reads
…g surface

Expand the mixing module with sample-accurate automation, a JSON scene
schema with three built-in presets, and a unified C / Python / Node /
WASM / CLI surface.

Channel strip (src/mixing/):
- AutomationLane: lock-free SPSC ring buffer for fader, pan, width, and
  per-send automation; block splitting via consume_block template
- ChannelStrip: process_at() with block segmentation, polarity invert,
  AlignmentDelay, StereoWidthProcessor, dual pre/post MeterProcessor,
  GoniometerBuffer, pre/post insert slots, schedule_*_automation()
- AlignmentDelay: sub-sample fractional delay (Q8 fixed-point) exposed
  via delay_samples_q8()
- Panner: balance / stereo-pan / dual-pan modes
- api/scene.h + scene_json.cpp: pure-data Scene schema with Strip, Bus,
  VcaGroup, Connection; scene_to_json / scene_from_json
- api/presets.h + presets.cpp: VocalReverbSend, DrumBusSubgroup,
  CommentaryDucking presets

Graph (src/graph/):
- Latency compensation upgraded to Q8 fixed-point arithmetic
- FractionalDelayLine path for sub-sample compensation in process_block

C API (src/sonare_c.h + src/sonare_c_mixing.cpp):
- SonareMixer / SonareStrip opaque types
- sonare_mixer_create/destroy, sonare_mixer_add_strip
- sonare_strip_set_{fader_db,pan,dual_pan,width,muted}
- sonare_strip_add_send, sonare_strip_set_send_db
- sonare_mixer_process_stereo, sonare_mixer_{to,from}_scene_json
- sonare_mixing_scene_preset_{names,json}

WASM (src/wasm/bindings.cpp): mixStereo, mixingScenePresetNames/Json

Python (bindings/python/): mix_stereo, mixing_scene_preset_{names,json},
MixResult type; FFI stubs for add_send, set_send_db, from/to_scene_json

Node/TypeScript (bindings/node/): same surface via N-API addon

Tests and QA:
- tests/mixing/golden_hash_test.cpp: FNV-1a quantized stereo hashes for
  unity-balance, panned-fader, stereo-pan-wide scenarios
- tests/mixing/no_alloc_test.cpp: RT no-allocation process checks
- tests/mixing/mixing_test.cpp: round-trip scene JSON, C API coverage
- tests/graph/graph_test.cpp: fractional delay and Q8 latency tests
- tests/mixing/golden/strip_hashes.tsv: reference hash fixture

CI / build / docs:
- .github/workflows/ci.yml: native-matrix job (macos-latest, windows-latest)
- benchmarks/mixing_bench.cpp: mixing throughput benchmark target
- README.md / README_ja.md: mixing section, CMake flag docs, CLI examples
- CHANGELOG.md: Unreleased mixing entry
libraz added 19 commits May 26, 2026 19:44
…ssover helper

- dereverb_classical.cpp regularization now uses constants::kSpectrumEpsilon
- Rename butterworth_section_specs to unscaled_rt_butterworth_sections
  in crossover.cpp
- Update doc comment to state the librosa default returns the biased
  autocorrelation matrix
- Add chordStartTime to progressive estimate types in wasm index.ts,
  sonare.js.d.ts, stream_types.ts, and wasm_types.ts
- Add Python stream-type stub exports to __init__.py, __init__.pyi,
  and types.pyi
…ocated channel state

Pre-allocate per-channel state up to kPreparedChannels = 64 in prepare()
for Gate, Compressor, Expander, DeEsser, TransientShaper, UpwardCompressor,
and UpwardExpander. process() now throws std::invalid_argument if
num_channels exceeds prepared capacity instead of heap-allocating on the
audio thread.

- Gate/Compressor: pre-size hpf_x1_/hpf_y1_ to 64 in prepare(); throw on overflow
- Expander/DeEsser: pre-resize followers/filter state to 64; throw on overflow
- TransientShaper: move all channel-state allocation into prepare(); store
  max_block_size_ for use in set_config(); introduce kEnvelopeFloor constant
- UpwardCompressor/UpwardExpander: raise kPreparedChannels from 2 to 64;
  ensure_followers() throws instead of reallocating
- wasm/bindings.cpp: expose DeEsserConfig bandpassQ field
- tests/mixing/no_alloc_test.cpp: add zero-allocation tests for all seven
  processors covering mono/stereo channel-count changes after prepare
…aming-safe flag

- Add resolve_platform_loudness() in suggester.cpp that maps target_platform
  to preset LUFS/ceiling pairs (broadcast: -23/-1, podcast: -16/-1,
  club/cd: -9/-0.3) while only overriding values the caller left at default
- Gate denoise repair stage behind !prefer_streaming_safe so streaming-safe
  mode keeps declick but skips denoise; adjust explanation text accordingly
- Add TEST_CASE in tests/mastering/assistant_test.cpp covering broadcast
  loudness resolution, streaming-safe repair exclusion, and full offline repair
…malize_matrix helper

- chroma.cpp: remove hand-written L1/L2/Inf per-column loops; delegate to
  normalize_matrix(axis=0) with NormType mapped from the norm integer arg
- nnls_chroma.cpp: replace per-frame max-norm loop with normalize_matrix
  (NormType::Inf); add #include "util/vector_normalize.h"
- nnls_chroma.cpp: clarify kStddevFloor comment explaining why it exceeds
  constants::kEpsilon (prevent over-amplification of flat CQT rows)
- No behavior change; 42 lines removed, 10 added
… NumPy

- Replace std::nth_element on a rounded index with std::sort + linear
  interpolation between the two surrounding ranks
- Matches NumPy/librosa percentile behavior (method='linear')
- Affects dynamics percentile calculations in acoustic_analyzer.cpp
- Add TempogramMode enum (kAutocorrelation default, kCosine) to rhythm.h
- Cosine mode normalizes each lagged-onset dot product by the product of
  slice magnitudes, making output scale-invariant and bounded to [-1, 1]
- Expose sonare_tempogram_with_mode() in sonare_c.h; original
  sonare_tempogram() becomes a thin wrapper forwarding kAutocorrelation
- Thread mode through Node addon (TempogramModeFromValue), WASM embind
  (tempogramModeFromValue), and Python ctypes (_ffi.py + _conversions.py)
- All binding public APIs accept 'autocorrelation'/'auto'/'ac'/'cosine' or
  numeric 0/1; TypeScript TempogramMode union type added to all targets
- Tests: scale-invariance and [-1,1] bound verified in C++ (librosa + C
  API suites), Node, Python, and WASM
…tics

Monitor/cue bus:
- Add process_with_monitor() writing PFL/AFL cue into a dedicated
  monitor_out buffer instead of folding it into the main output
- Refactor process() and process_subblock() to share process_impl()
  with a fold_monitor_to_main flag; existing callers retain foldback
- Extract block_end_frame/command_belongs_to_block helpers and replace
  duplicate inline arithmetic in drain_commands
- Expose kMaxAudioChannels constant (64) replacing the magic literal

Telemetry diagnostics:
- Add TelemetryErrorCode::kAutomationBindTargetOverflow,
  kStaleAutomationLanes, kSmoothedParameterCapacity to telemetry.h
- Enqueue kAutomationBindTargetOverflow and kStaleAutomationLanes delta
  counts from process_impl() each block
- Report kSmoothedParameterCapacity (with target_id as payload) instead
  of silently falling back when all smoother slots are saturated
- Drop mutable/const from stale_lane_apply_count_ in AutomationEngine
  (atomic write now required from non-const apply path)
- Init automation_bind_overflow_reported_ and automation_stale_lane_reported_
  snapshots in prepare() to suppress spurious errors on first block

Bindings (all exposing process_with_monitor + new error enum values):
- C API: sonare_engine_process_with_monitor in sonare_c.h / sonare_c_daw.cpp
- WASM embind: bindings.cpp, worklet.ts, wasm_types.ts, public_types.ts
- Node addon: sonare_wrap_engine.cpp/.h, index.ts, types.ts
- Python: _ffi.py, engine.py/.pyi, types.py/.pyi

Tests: C++ engine, telemetry, C API, Node, Python, and WASM all updated
…l_limits.h

Each dynamics processor (Compressor, DeEsser, Expander, Gate,
TransientShaper, UpwardCompressor, UpwardExpander) previously defined
its own identical `static constexpr size_t kPreparedChannels = 64`.

- Add channel_limits.h with a single shared constant
  `kRealtimePreparedChannels = 64` in namespace
  `sonare::mastering::dynamics`
- Replace all seven local definitions with an include of that header
- Remove the now-redundant `#include <cstddef>` from each header

No behaviour change; process() paths are unaffected.
Also fixes the stale SONARE_VERSION_* macros in sonare.h (was 1.0.4)
so runtime version() reports correctly.
- Ran ncu -u in wasm/node bindings: vitest, biome 2.4.8→2.4.15,
  cmake-js 7→8, node-addon-api, typescript bumped
- Kept @types/node at ^22 to match the Node 22 runtime target
- Fixed newly-flagged biome 2.4.15 lint: removed unused wasmModule/
  SharedEngineRing, added block-statement braces, reordered imports
- Bumped biome.json $schema to 2.4.15
Align local make test/make test-optional-fixtures and the publish.yml
C++ test step with ci.yml, which already passed --parallel.
- Define NOMINMAX on MSVC so <windows.h> (via dr_libs) stops clobbering
  std::min/std::max, fixing C2589/C2059 in audio_io.cpp and resample.cpp
- Mark third_party (kissfft/dr_libs/minimp3/r8brain) and the fetched
  Eigen as SYSTEM includes and add /external:W0 so MSVC /W4 /WX no
  longer errors on third-party warnings (C4244/C4127)
- Suppress the intentional alignas-padding warning C4324 via /wd4324
- Add explicit static_cast<int> in cqt.cpp for float-to-int narrowing
  (C4244)
- Only register CLI tests when BUILD_CLI is ON; they shell out to the
  sonare binary which is absent under -DBUILD_CLI=OFF, causing exit 127
  in CI
- Flow-control the RtSnapshot concurrent-readers stress test so the
  producer never runs more than kRetain/2 generations ahead of the
  slowest reader, making it robust under parallel oversubscription (was
  a heap-use-after-free / bad_read under ctest --parallel; the
  RtSnapshot primitive itself is correct for its documented bounded
  contract and is unchanged)
- Replace EqualizerProcessor exact-hash golden assertion with a
  tolerance-based (WithinAbs 1e-4) comparison against reference
  samples; exact float hashes are not portable across compilers and
  failed on Linux GCC
Reorder includes to satisfy Google style include ordering enforced by
clang-format; no logic changes.
ASan caught stack-use-after-scope in ChannelStrip::process_insert_chain
and SidechainRouter::set_sidechain (via BusProcessor). The graph
StripNode/BusNode build a transient on-stack key[2] array of channel
pointers and pass it to set_insert_sidechain, which previously stored
the borrowed array-of-pointers; it was dereferenced after the stack
array went out of scope. InsertSidechain now owns a by-value copy of
the channel pointers (the pointed-to sample buffers stay valid for the
block), eliminating the dangling borrow.
On Windows CI there is no system Eigen, so the fetched-Eigen fallback
was used with non-system includes, making MSVC /W4 /WX error on
warnings inside Eigen (C4127 etc.). Mark the fetched eigen target's
includes as system (INTERFACE_SYSTEM_INCLUDE_DIRECTORIES); find_package'd
Eigen on Linux/macOS is already system.
The test prepared the limiter with max_block_size 512 but processed
2048-sample blocks, overrunning the oversampled buffers
(heap-buffer-overflow / Linux segfault). process() must never receive
more samples than the prepared maximum; prepare with 2048 to match the
blocks it feeds.
@codecov-commenter
Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment

Thanks for integrating Codecov - We've got you covered ☂️

libraz added 7 commits May 27, 2026 02:57
Populate the fetched-Eigen fallback as headers-only (manual SYSTEM INTERFACE
target) instead of running Eigen's CMake project, which on platforms without a
system Eigen (Windows and macOS CI, WASM) registered Eigen's ~880 unit tests
into our CTest where they failed as "Unable to find executable". Also define
_CRT_SECURE_NO_WARNINGS on MSVC so C4996 deprecation of standard C functions
(e.g. strncpy in the C API) does not break the /WX build.
The control thread hammered set_tempo() thousands of times unpaced while the
audio thread processed, exceeding RtSnapshot's 64-generation retention window
under parallel oversubscription and tripping a heap-use-after-free in
TempoMap. Pace the control loop (20us/iteration) and shrink the CI case to 256
blocks so it stays within the retention window deterministically; move the
heavy 20000-block soak into a hidden [.stress] test that the default CI run
does not execute. The engine/RtSnapshot code is correct for its documented
bounded contract and is unchanged.
MSVC /W4 flags double->float, size_t->int, and literal narrowing (C4244/C4267/
C4305) that the primary GCC/Clang build does not, since -Wall -Wextra
deliberately excludes -Wconversion. This audio library performs such narrowing
intentionally, so silence those warnings on MSVC to hold all toolchains to the
same established bar rather than a stricter one.
… init

- Set splitting: false in tsup.config.ts so each entry point (index.js,
  worklet.js) is a fully self-contained bundle; a real AudioWorkletGlobalScope
  cannot resolve sibling code-split chunks, so the worklet must stand alone
- Re-export init/isInitialized from worklet.ts so the worklet realm can
  initialize its own wasm module instance independently of the main thread
- Initialize both modules in worklet.test.ts beforeAll, since each bundle
  owns its own module singleton after code-splitting is disabled
- Clean stale chunk-*.js / *-*.d.ts artifacts in build:js before running
  tsup to avoid leftover files from prior code-split builds
Adds .github/workflows/develop-ci.yml with three jobs triggered on push
and PR to develop (docs/markdown paths excluded):

- clang-format: verifies C/C++ formatting across all non-third-party sources
- lint: runs Biome on bindings/wasm (Node 22 + Yarn cache)
- build-and-test: single-platform Linux/Debug CMake build + ctest

The heavy multi-OS, ASan/UBSan, coverage, and WASM validation stays in
ci.yml as the pre-release gate (PRs to main, pushes to main). Concurrency
group with cancel-in-progress avoids redundant runs on rapid pushes.
MSVC rejected the Windows CI build with C1061 ("blocks nested too
deeply") because apply_one_param_to_config was a single ~140-branch
else-if chain; MSVC counts each else-if as a nested block and hits its
compiler limit, whereas GCC/Clang accept it without complaint.

- Extract five flat per-stage helpers: apply_repair_param,
  apply_eq_dynamics_param, apply_saturation_param,
  apply_spectral_stereo_param, apply_maximizer_loudness_param
- Each helper uses independent early-return if blocks (nesting depth 1)
  instead of else-if chains
- Dispatcher calls helpers in sequence and throws on an unknown key
- All 126 parameter keys preserved; semantics unchanged
These tests built on GCC/Clang but failed the newly-enabled Windows MSVC
CI job:

- Replaced all M_PI usages (66 occurrences across 32 files) with
  sonare::constants::kPiD and added the util/constants.h include. MSVC
  does not define M_PI without _USE_MATH_DEFINES, and the project bans
  M_PI in favour of sonare::constants.
- Promoted function-local constexpr values referenced inside lambdas to
  static constexpr in eq_test, routing_test, mixing_test and
  realtime_engine_test; MSVC otherwise tries to capture them and rejects
  their use as std::array sizes / constant expressions (C2975 / C3493).
- Made no_alloc_test aligned allocation portable: _aligned_malloc /
  _aligned_free on Windows, posix_memalign / std::free elsewhere (C3861).
- Added MSVC warning(disable : 4996) branches alongside the existing
  GCC/Clang -Wdeprecated-declarations suppression in vqt_test, which
  intentionally exercises the deprecated ivqt API (C2220 under /WX).
The cqt tests intentionally exercise the deprecated icqt API and already
suppressed the GCC/Clang -Wdeprecated-declarations warning; add the
matching MSVC warning(disable : 4996) branch so the Windows /WX build
does not treat C4996 as a fatal C2220 error.
@libraz libraz merged commit affbd1c into main May 27, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants