Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Testing without a host

The apf-test crate loads a plugin through the CLAP entry points, exactly as a host does, and lets a test play it in memory. No sound card is opened, no window appears, and a test runs in milliseconds.

[dev-dependencies]
apf-test = { path = "../apf/crates/apf-test" }     # or `.workspace = true` inside the APF workspace
use apf_test::{allocations_in_process, frequency, CountingAllocator, Event, Instance};

#[global_allocator]
static ALLOCATOR: CountingAllocator = CountingAllocator;

#[test]
fn a_note_has_the_right_pitch() {
    let mut p = Instance::load(my_plugin::apf_entry_init, my_plugin::apf_entry_get_factory);
    p.activate(48_000.0, 4800);
    let audio = p.render(&[Event::note_on(1000, 69, 1.0)], 4800);   // A4 at sample 1000
    assert!(audio.left[..1000].iter().all(|&s| s == 0.0));
    assert!((frequency(&audio.left[2000..], 48_000.0) - 440.0).abs() < 1.0);
    assert_eq!(allocations_in_process(), 0);
}
WhatHow
play notes, MIDI, automationEvent::note_on/off, cc, pitch_bend, param, midi, at a sample position
an instrumentrender(&events, frames)
an effectrender_effect(&events, &left, &right, block_size)
parameters as a host sees themparam_id("Name"), host_value, value_to_text, set_text("Gain", "-6 dB")
a saved projectsave_state(), load_state(bytes)
measurerms, frequency

The pattern of every example’s test: render audio, then measure it (its pitch, its level, its spectrum with a Goertzel filter), and run the whole thing under the counting allocator.

Presets can be tested without any host: apf::preset::Factory::parse(P::FACTORY_PRESETS) parses the factory presets, and apf::preset::save_in(dir, ...) saves a user preset into a scratch folder (example 08).

Beyond unit tests

apf-host is a minimal CLAP host in this repository. It loads a built .clap, renders audio and drives the web view end to end:

cargo run --release -p apf-host -- "dist/release/APF Example 07 GUI.clap" --gui-test
cargo run --release -p apf-host -- "dist/release/APF Example 07 GUI.clap" --gui 3 --screenshot out.png

--gui-test opens the web view, edits a parameter from the page and checks that the host sees it, then the other way round, then resizes the window and sends keys. Nothing is played to a sound card.

cargo xtask validate <plugin> runs the third-party validators on the plugin that cargo xtask bundle built: clap-validator, the Steinberg VST3 validator, Apple’s auval (macOS, on the installed Audio Units), and APF’s own state checks (a restored session must sound the same, in several restore orders). clap-validator is installed separately; the command says how when it is missing. Validation lists the tools and what they found. With --hot it also checks that the hot-reload shell swaps in a new build in a CLAP host and in both Audio Unit versions. The run expects a plugin with parameters, and the web view check at least three; a plugin without parameters makes clap-validator 0.4.1 fail its parameter test.