VST3 MIDI-out timing breaks at large ASIO buffer

I am seeing a reproducible timing problem in Cubase when routing live MIDI generated by VST3 plug-ins to another VST3 instrument at a large ASIO buffer size.

The problem does not appear to be specific to one plug-in. I have reproduced essentially the same behavior with three different VST3 MIDI-generating plug-ins:

  • My Plugin — JUCE 9.0.1
  • Stepic — JUCE/VST3 MIDI sequencer
  • HY-SeqCollection2 — JUCE 8.0.8

All three generate MIDI and route it live to a separate VST3 synth.

Reproduction

  1. Set the project to 44.1 kHz.
  2. Set the ASIO buffer to 4096 samples.
  3. Disable ASIO Guard.
  4. Set the project tempo to 120 BPM.
  5. Configure the MIDI-generating VST3 to output straight 1/16 notes.
  6. Route its MIDI output live to another VST3 instrument.
  7. Start playback.

Actual result

The live audible result is rhythmically incorrect.

Instead of straight 1/16 notes, the receiving synth produces a pattern that sounds approximately half-time / triplet-like, with attacks strongly related to the 4096-sample processing-block period.

At 44.1 kHz:

4096 samples = 92.88 ms

whereas a 1/16 note at 120 BPM is:

5512.5 samples = 125 ms

The failure appears to depend on the phase relationship between the musical note interval and the processing-block interval.

Important control: recorded MIDI is correct

If I record the MIDI output produced by the VST3 sequencer in Cubase, the recorded MIDI notes are correctly spaced at straight 1/16-note intervals.

If I then:

  • remove the live MIDI-generating plug-in,
  • play that recorded MIDI into the same destination synth,
  • keep the ASIO buffer at 4096 samples,

playback is correct.

Therefore the MIDI generator itself is producing the intended musical timing, and the destination synth is capable of reproducing that timing correctly at 4096 samples.

The problem occurs specifically during live VST3 MIDI-output routing.

Independent plug-ins reproduce the same problem

Stepic

4096 samples / ASIO Guard Off / Cubase → broken

HY-SeqCollection2

4096 samples / ASIO Guard Off / Cubase → broken

Plugin I am building
4096 samples / ASIO Guard Off / Cubase → broken

This makes a plug-in-specific sequencer bug unlikely.

Ableton Live control test

I tested My Plugin, HY and Stepic in Ableton Live using a 4096-sample audio buffer.

Both perform correctly there with no audible timing problem.

Therefore the issue appears to be specific to Cubase rather than to the MIDI-generating plug-ins or the large audio buffer itself.

Native Cubase MIDI processing

Cubase’s own MIDI processing/sequencing does not show the same failure under the equivalent test. Tested Arpache.

This seems to distinguish the native Cubase MIDI path from MIDI produced by an external VST3 plug-in and routed live to another instrument.

Tempo / block-phase observation

There is another useful reproduction clue.

With my plugin at:

120 BPM → broken

but around:

162.5 BPM → works correctly

At 162.5 BPM, a 1/16 note is approximately:

4071 samples

which is very close to the 4096-sample audio block size.

At 120 BPM, a 1/16 note is 5512.5 samples, so its sample offset moves substantially through successive blocks.

The MIDI event structure itself does not materially change between these cases. What changes is primarily the relationship between the event period and the processing-block period.

This suggests the problem may involve handling/scheduling of non-zero VST3 Event::sampleOffset values during live inter-plug-in MIDI routing at large realtime block sizes.

I am deliberately describing that as a hypothesis rather than a confirmed root cause.

Additional tests performed

On my own VST3 MIDI generator I verified that:

  • internal note scheduling is sample-accurate;
  • generated MIDI recorded by Cubase is correctly timed;
  • changing the VST3 event sampleOffset experimentally changes where Cubase records/delivers the event, so Cubase is not simply ignoring sampleOffset completely;
  • VST3 note IDs are not the cause;
  • VST3 event ppqPosition is not the cause;
  • pitch-bend events are not the cause;
  • plug-in latency is 0 samples;
  • realtime processing at 44.1 kHz / 4096 samples is accepted by the plug-in;
  • the same problem occurs in independent third-party VST3 MIDI sequencers.

Expected result

MIDI events generated by a VST3 plug-in with valid in-block sampleOffset values should retain their sample-relative timing when routed live to another VST3 instrument, regardless of whether the audio block size is 128, 512, 2048 or 4096 samples.

A straight 1/16-note sequence at 120 BPM should therefore remain a straight 1/16-note sequence at a 4096-sample buffer.

Actual result

At sufficiently large buffer sizes, particularly 4096 samples, the live receiving instrument does not reproduce the timing represented by the source VST3 MIDI events correctly.

The same MIDI recorded first and played back afterward is correct.

The same VST3 sequencers are also correct at 4096 samples in Ableton Live.

I can provide

If useful, I can provide:

  • Cubase project/test setup details
  • MIDI recordings from the failing test
  • audio recordings of the live result
  • diagnostic logs containing block sizes, host PPQ positions and generated event sample offsets
  • the exact VST3 event timing generated by my own plug-in

I would be interested to know whether Steinberg can reproduce this specifically with VST3 MIDI-output → live-routed VST3 instrument at a 4096-sample realtime buffer.

Another thing is that when ASIO guard is on, loop crossings are having problems too in the described setup. They are not clean, they are only clean with Asio Guard off and low buffer sizes, sub 512

1 Like