Skip to content

Releases: CristianMoresi/DSPark

v1.7.0 — Musical Timing, Pitch & Spectral Processing

Choose a tag to compare

@CristianMoresi CristianMoresi released this 25 Aug 23:18

DSPark 1.7.0 expands the header-only framework with production-ready musical
timing, pitch, spectral processing, native file formats, and stronger real-time
contracts.

Musical timing, pitch, and spectral processing

  • Added OnsetDetector, BeatTracker, and LoopFinder for transient analysis,
    tempo/phase tracking, and bounded crossfade-ready loop discovery.
  • Added TimeStretch for independent high-quality duration and pitch control.
  • Added PitchCorrector with YIN detection, scale-aware quantization, glide,
    and formant preservation.
  • Added SpectralFreeze with phase-aware advance, reconstruction, and
    decorrelation modes.
  • Added KeyDetector and offline LoudnessNormalizer processing under a
    true-peak ceiling.

Native formats and hardened I/O

  • Added dependency-free native FLAC decoding with FlacFile.
  • Added Standard MIDI File reading and writing with MidiFile.
  • Hardened WAV, MP3, FLAC, and MIDI parsing against malformed sizes, truncated
    data, and invalid metadata without introducing runtime codec dependencies.

Real-time and public API contracts

  • Automatic analysis windows now preserve their time span across sample rates,
    with resolved sizes exposed for latency accounting.
  • Audio-thread adoption of staged multi-word state is bounded; a contended
    update may be deferred, but the callback never waits for the control thread.
  • Added Biquad::setCoeffsNow() for stream-owner, single-threaded, and offline
    coefficient updates. BiquadCoeffs and the biquad recursion now use double
    precision for all sample types.
  • AudioBufferView conversions now express const-correctness as constraints,
    and AudioProcessor now represents an unambiguous in-place mutable-buffer
    processor.
  • Allocation failures and invalid prepare() arguments preserve safe, valid
    state across the affected processors and buffers.

Validation and distribution

  • Package recipes for Conan and vcpkg are pinned to the immutable 1.7.0 source
    authority.
  • CI covers GCC, Clang, MSVC, x64, ARM64, AddressSanitizer,
    UndefinedBehaviorSanitizer, float-cast overflow, public header conformance,
    installed-header consumption, and concurrent-suite isolation.
  • Plugin, DSParkLab, documentation, examples, benchmarks, and downstream CMake
    package consumers remain part of the release validation surface.

Most 1.6.1 code remains source-compatible. Review the
1.7.0 migration guide
for analysis-window latency, BiquadCoeffs, AudioBufferView, and
AudioProcessor changes.

See the full changelog
or compare v1.6.1...v1.7.0.

v1.6.1 - Reverb Performance

Choose a tag to compare

@CristianMoresi CristianMoresi released this 11 Jul 22:02

Reverb performance - an Eco engine for constrained targets and direct control over convolution IRs, both prompted by real-world feedback from a synthesizer firmware project (#2).

Eco quality mode

  • AlgorithmicReverb::setQuality(Quality::Eco) runs a reduced engine: 8 FDN lines (alternate base delays keep the full 29.7-160 ms span, per-line gains keep T60 exact), control-rate modulation, linear interpolation in the modulated allpasses, a single-stage input scatter and a leaner output stage.
  • Measured about 3.3x cheaper per block than the default engine, with matched tail loudness and the same control set.
  • The default Full engine is bit-identical to v1.6.0; Eco is opt-in and applied like a preset change (at the next block, with a state reset).

Convolution reverb IR shaping

  • setDecayScale(0.25-2) rescales the impulse response's own T60, estimated from its Schroeder decay curve, from the direct sound onward. Values below 1 also trim the now-silent tail, so shorter decays cut convolution cost roughly in proportion.
  • setStretch(0.5-2) resamples the IR tape-speed style: larger and darker above 1, smaller and brighter below.
  • Both always reshape the IR as loaded (never cumulatively), compose predictably, and rebuild/publish the convolver bank atomically, exactly like loadIR().
  • State: new tolerant keys (quality, decayScale, stretch); blobs from older versions load unchanged.

DSParkLab

  • Quality selector on the Reverb, Decay Scale / Stretch sliders on the Convolution Reverb, for instant A/B.

v1.6.0 — The Host Contract

Choose a tag to compare

@CristianMoresi CristianMoresi released this 12 Jun 22:57

The Host Contract — the plugin layer now covers everything a host can offer an effect or an instrument. Each capability is one declarative member on your plugin struct, and each one is proven functionally in CI: measured, not just compiled.

Instruments & MIDI

  • handleMidiEvent(MidiEvent) adds a note input to every format: VST3 event bus plus IMidiMapping (pitch bend, mod wheel, sustain, channel pressure), CLAP note ports speaking both the CLAP and raw-MIDI dialects, AU MusicDevice selectors behind a lock-free queue.
  • Category::Instrument builds a true generator: no audio inputs in any format, an aumu Audio Unit, cleared output buffers that voices add into.
  • New reference instrument examples/plugin_synth/: 8 voices of Oscillator + ADSREnvelope, voice stealing, pitch bend, factory presets, sample-accurate note starts — auval-validated, and CI measures a 440 Hz note and its release decay from the audio output.

Host transport

  • setTransport(TransportInfo) delivers tempo, musical position, bar start, time signature, loop points and play/record state once per block — from the VST3 ProcessContext (requirements declared for you), the CLAP transport event and the AU host callbacks. samplesPerBeat() is the one-liner for tempo-synced delays, LFOs and gates.

Buses

  • Mono everywhere: every plugin negotiates 1-in/1-out and 2-in/2-out by default (ChannelSupport::StereoOnly restricts it for inherently stereo DSP). The sidechain always mirrors the main width.

Sample-accurate automation

  • On by default: parameter, bypass and note events ride one time-ordered stream and processing splits at 32-frame quantum boundaries, so fast curves land where the host drew them. Declarative opt-out (sampleAccurateAutomation = false) for plugins with a high fixed cost per call.

The professional details

  • Runtime latency changes notify the host natively (VST3 restartComponent, clap_host_latency, the AU property listeners) — switchable lookahead now re-compensates projects correctly.
  • setOfflineRendering(bool) exposes the render mode (VST3 kOffline, the CLAP render extension, AU OfflineRender) for higher-quality bounces.
  • factoryPresets publishes to every host's preset browser: a VST3 program list with a program-change parameter, CLAP preset-load + preset-discovery (the plugin binary is the preset container), AU factory presets with a full PresentPreset round-trip.
  • Host bypass and the active program persist in the shared state container (two real-world bugs caught by pluginval and clap-validator in CI — the bypass one latent since v1.3.0).
  • process()/render() run under DSPark's denormal guard in all three backends.

Proven by instrumentation

  • New tools/plugin_probe.cpp encodes what the wrapper delivers into its audio output, so the smoke hosts measure every capability end to end on all five CI targets: transport DC, the offline sign flip, an automation step landing on its exact sample, note pitch by zero crossings, pitch bend through both routes, the latency-changed notification, mono processing and the preset paths.
  • pluginval (strictness 8) and clap-validator now also gate the synth and the probe; macOS CI runs four auval validations including the new aumu.

Docs

  • docs/plugins.md: full contract table for the new capabilities, new "Instruments & MIDI" and "Host transport" sections, a from-a-blank-folder project guide, and the examples indexed in learning order (also in the new examples/README.md).

v1.5.0 — The Editor Everywhere

Choose a tag to compare

@CristianMoresi CristianMoresi released this 12 Jun 17:08

The WebView editor now runs on all three plugin formats and all three desktop platforms — and every one of those paths is exercised with a real web view in CI.

AU editor (macOS)

The AU backend announces a Cocoa view factory through kAudioUnitProperty_CocoaUI, registered at runtime from the plugin binary itself — still no Objective-C sources and no AppKit link anywhere in DSPark. UI edits flow through AUParameterSet and proper begin/end parameter gestures, so Logic-style hosts record automation and undo correctly. Both teardown orders (host releases the view first, or disposes the AudioUnit first) are handled and tested.

Linux editor (X11)

WebKitGTK resolved entirely through dlopen at runtime — no headers, no pkg-config, no link-time dependency — embedded in the host window with GtkPlug/XEmbed. GTK is pumped from the host's run loop (a VST3 IRunLoop timer / CLAP timer-support), never a private main loop; systems without WebKitGTK, or hosts without a usable run loop, cleanly keep the host's generic UI through the new runtime Editor::available() gate.

Proven, not just compiled

New tools/au_editor_smoke (macOS) and tools/x11_editor_smoke (Linux, under xvfb) play real hosts in CI: factory/attach, a live web view, the JS bridge ready-handshake and clean teardown — alongside the existing real-window editor host on Windows, auval, pluginval (strictness 8) and clap-validator on every commit.

Docs

docs/plugins.md (also on GitHub Pages) now carries a per-platform editor guide — build requirements, end-user runtime requirements, fallback behaviour — and the one-line dspark_add_plugin(... FORMATS VST3 CLAP AU ...) cross-platform path.

v1.4.1 — CMake package config

Choose a tag to compare

@CristianMoresi CristianMoresi released this 12 Jun 13:00

Packaging fix: find_package(dspark CONFIG) now works from any install tree or package manager — dsparkConfig.cmake/dsparkConfigVersion.cmake (ARCH_INDEPENDENT) are generated and installed alongside the targets file under lib/cmake/dspark. No library changes.

v1.4.0 — The WebView Editor

Choose a tag to compare

@CristianMoresi CristianMoresi released this 12 Jun 12:49

Custom plugin GUIs in plain HTML/CSS/JS, embedded in the host window — no GUI framework, nothing to install.

The editor layer (plugin/webview/): declare hasEditor = true and serve your page from editorHtml(); the VST3 and CLAP backends embed the platform web engine (WebView2 on Windows, WKWebView on macOS; Linux falls back to the host generic UI for now). The vendored MIT webview library and the BSD-3 WebView2 SDK header keep it zero-download.

The dspark JS bridge: onReady hands the page the parameter table with live values; setParam/onParam move plain values both ways using the same stable text ids as automation and state; beginEdit/endEdit drive host gestures and undo. DSP-to-UI sync polls the wrapper's atomic shadows — no native timers, no locks, nothing on the audio thread.

Sizing that survives real hosts (field-validated in REAPER at 200% display scaling): OS-level frame limits (WM_GETMINMAXINFO/WM_SIZING), honest VST3/CLAP size negotiation, and JUCE-style proportional content scaling with Fixed / Free / KeepAspect policies.

A real workflow: develop the UI as ordinary separate web files — dspark_add_plugin(... EDITOR_HTML ui/editor.html) inlines and embeds them at build time; editorDevFile() reloads the page from disk while iterating; editorDebug opens the browser DevTools; tools/vst3_editor_host opens any editor without a DAW and self-tests the resize chain; DSPARK_WEBVIEW_LOG=1 traces every size negotiation.

Hardened in CI: dspark_add_plugin now assembles AU .component bundles too (FORMATS VST3 CLAP AU), and every example plugin must pass Tracktion pluginval (strictness 8) and clap-validator on Windows, Linux and macOS — the latter immediately caught and got fixed a real toggle text-parsing bug in both backends.

Examples: examples/plugin_webview_editor/ (single-file, draggable SVG knobs) and examples/plugin_webview_files/ (separate-files workflow). Full guide: docs/plugins.md.