RustAudio / vst-rs

VST 2.4 API implementation in rust. Create plugins or hosts. Previously rust-vst on the RustDSP group.
MIT License
1.04k stars 91 forks source link

Confusing relationship between `process_events()` and `process()` #176

Closed EarthenSky closed 2 years ago

EarthenSky commented 2 years ago

I'm finding it confusing that process_events() is called before every process() block, yet in the sine_synth example https://github.com/RustAudio/vst-rs/blob/master/examples/sine_synth.rs only 1 note is ever stored & we don't care how long it is.

I though two notes played right after each other (perhaps with a small rest between them) would commonly be part of the same block sent to process().

I couldn't find any documentation on this, however my initial assumption before was that the host gets to choose the block size (say 512 samples) then we need to know the time at which each note is played inside that block so we can know when to start adding samples, etc. However, should I actually assume that process() is only called on segments between midi event changes?

For example, would the following grid be valid, where = represents a note being played at a certain pitch and | represents the separation between blocks (aka process_events() & process() calls)?

127:  |  |=|==| | |
126:  |==|=|  | |=| 
125:  |  | |  | | |
124:  |==|=|  | | | 
askeksa commented 2 years ago

Each block can contain an arbitrary number of events, and they can happen at any time during the block. The offset within the block is given by the delta_frames field of the event. The sine_synth does not handle events correctly. It only computes the state of the oscillator at the end of the block and generates sound from that state for the entire block.

Take a look at this synth for an example of correct event handling. In process_events(), the events are pushed to the back of a queue with information about the time at which they happen. In process(), the event at the front of the queue is popped when the current time matches the timestamp of the event.

This code assumes that events are given in chronological order by the host. Any well-behaved host will do this, but I have heard rumors that some hosts are broken and can sometimes give events out of order. For the plugin to work with such broken hosts, it will need a priority queue instead of a queue.

EarthenSky commented 2 years ago

Thanks! Sorry for responding so late, but that really clears things up. Turns out the project I was using as reference had this same bug, but it was only because I was looking at an old commit...