I’m just getting my feet wet with Juce. While I’ve found most features to be incredibly useful, nicely documented and really quite intuitive, there’s one issue I can’t crack yet. Any help would be hugely appreciated.
I’m working on a MIDI plugin with high latency. Let’s call it 100000 samples. Everything works fine during regular processing but when playback stops, the plugin keeps working on the remaining queue for another 100000 samples, resulting in extra unwanted notes for a while. However, I’d like everything to cease immediately. I’ve tried using prepareToPlay and releaseResources to coordinate various triggers to stop the processing, empty the queue and/or reduce latency to 0, but due to the timing of these function calls they don’t seem to make any difference at all.
Thanks so much for the replies Jules and Matkat. I’ll put some code up shortly.
Yes, the plugin reports its latency and the output is indeed perfectly synchronised when delaying the input by the same amount. In this situation I’m not at all worried about playability because this particular mode is for playback only. It does require an extremely high latency (usually more like 500,000 samples) to work properly.
The only problem I’m having is that when I hit stop, it takes that many samples to settle down again, so there’s an incredibly long tail of unwanted events from the stopping point until the queue is processed and empty again, 10 seconds or so later. Instead of this, I’d like to flush the buffers immediately once the stop message has been received. Is there any way to do this?
My current strategy is to set a flag in releaseResources to tell processBlock to do various combinations of:
stop processing any further queue items
delete all existing queue items
set the latency to 0
I’ve even tried doing the same sorts of things in prepareToPlay. Admittedly quite heavy-handed, but still nothing ever seems to do what I expect when I expect it. Of course, I wouldn’t be surprised if I’m doing it all wrong.
Haha well I’ve had it working fine on other plugin platforms, so that’s obviously a slight over-generalisation.
Sorry if I’ve been unclear. Not everything is delayed. The plugin just saves events up to release them at the right time (obviously with suitable transformations applied to them in a real-world scenario). But the incoming event receiver in processBlock should still be right up-to-date, shouldn’t it?
Are the transport start/stop messages also delayed by this amount before they get to processBlock? I can’t think why they should be. EDIT: hmmm… unless that’s a limitation of VSTs under latency, of course. That’s a bit of a deal-breaker.
releaseResources is called when it’s time to completely reset your plugin’s state, so of course you should clear stuff like this when that happens. You don’t need a ‘stopped’ flag, just clear your queues in releaseResources and/or prepareToPlay and it’ll achieve the same thing.
Sorry Jules, I think I must be doing some fairly eccentric things with my plugins, because nobody ever seems to get exactly what I’m on about.
And thank you, of course you’re right about that boolean. I had changed the structure around a few times, trying different angles on the problem, but your suggestion is the most straightforward approach, although none of it makes any difference anyway so it’s all redundant code.
At least for now it’s all working rather well aside from the latency jetlag on stop. It’s a vaguely annoying cosmetic detail I was hoping to eliminate early in the piece. I’ll test out different VST host settings tomorrow and see how I go with those.
Well, silly me, it turns out I was using the wrong tool for the job.
As a potentially helpful note to others (or me again in a few weeks’ time), when I checked the value of isPlaying() from AudioPlayHead::CurrentPositionInfo to detect transport start/stop everything worked perfectly. Yay!