Automation on the exact sample
The problem
A host records automation with sample positions. If a plugin only learns the value once per block, a change that should happen on frame 300 of a 512-frame block is applied on frame 0 or frame 512 instead. Fast automation turns into steps, and the size of the steps depends on the host’s buffer setting.
In JUCE
AudioProcessor::processBlock receives audio and a MIDI buffer. Parameter changes are not part of the call; a processor reads each parameter’s current value, which the host updates between blocks. In May 2026 a member of the JUCE team said sample-accurate automation would not be ready for the first release of JUCE 9 (forum thread).
In Manguebyte
The process call carries an EventBuffer in which every parameter change has the frame it falls on. split_at_events renders up to each event, applies it, and continues, using AudioBuffer::windowed to narrow the buffer in place. Nothing is copied or allocated.
Check it
automation_lands_on_its_exact_frame_and_updates_the_parameter schedules changes on frames 100, 101 and 250 and asserts the output sample by sample. automation_lands_on_its_frame_when_processing_in_place does the same through the CLAP C interface, and a test of the same name does it through VST 3, where a host sends a queue of points per parameter and every point is delivered. (JUCE’s VST3 wrapper applies the last point of each queue: processParameterChanges in juce_audio_plugin_client_VST3.cpp.)
VST 3 adds a trap of its own. A host reports each change twice: to the processor with a frame number, and to the controller on the main thread so that an editor can follow. If the controller’s copy is stored into the parameter, the plugin jumps to a value that is slightly early or late until the next point corrects it. While blocks are running, Manguebyte’s wrapper keeps the controller’s copy for display only; what_the_controller_is_told_does_not_disturb_running_automation checks it.
- pluginautomation_
lands_ okon_ its_ exact_ frame_ and_ updates_ the_ parameter - clapautomation_
lands_ okon_ its_ frame_ when_ processing_ in_ place - vst3automation_
lands_ okon_ its_ frame_ when_ processing_ in_ place - vst3what_
the_ okcontroller_ is_ told_ does_ not_ disturb_ running_ automation
Show the test
#[test]
fn automation_lands_on_its_exact_frame_and_updates_the_parameter() {
let mut harness = Harness::<Level>::new(48_000.0, 64);
harness.automate(100, "level", 2.0);
harness.automate(101, "level", 3.0);
harness.automate(250, "level", 0.5);
let output = harness.process(&ones(2, 300));
let left = output.channel(0);
assert_eq!(&left[..100], &[1.0; 100]);
assert_eq!(left[100], 2.0);
assert_eq!(&left[101..250], &[3.0; 149]);
assert_eq!(&left[250..], &[0.5; 50]);
assert_eq!(output.channel(1), left);
// Anything polling the parameter sees where automation left it.
assert_eq!(harness.params().level.value(), 0.5);
assert_eq!(harness.position(), 300);
}
c5835bf, as it is in the file.