Re: DSPplug tick100
Posted: Wed Jun 17, 2020 3:30 pm
pshannon wrote:If the tick is so flawed, isn't everything built around the timing in FS and should our designs be flawed too?
There are at least three separate timing sources in FlowStone, and each of these runs in its own CPU thread. Generally, the three only swap data with each other during the spaces in between filling the ASIO/DS/VST audio buffers.
Audio is synced to the refreshing of the audio buffers, and always has the highest CPU priority. Whenever the host/driver requests a buffer refresh, FS drops everything else and gets the buffer filled as quickly as possible. So long as the buffer gets filled before the next request comes along, audio will flow smoothly, and samples will be timed as accurately as the crystal clock of the soundcard hardware allows.
Green is purely event driven. When a MIDI event or keyboard/mouse interaction creates a green trigger, it just executes as soon as possible. However, green has a low CPU priority - it will take a back-seat to everything else if the CPU is busy. So "as soon as possible" may not always be very soon! (NB: MIDI events are treated as something of a "special case" involving triggers processed in a higher-priority CPU thread).
Ruby is also event driven, but its events are scheduled rather than just executed ASAP - in other words, events can be given specific times at which to happen. The timing of the event scheduling is synchronised with the audio buffer refreshes when audio is running, otherwise it runs at 100Hz. Ruby has a priority somewhere between audio and "green" - it uses a more accurate timing system than green, but still won't be allowed to interrupt audio processing unnecessarily (if it's processing MIDI or Frames, it will be necessary).
What's important to note is that code never truly executes with "sample accurate timing". Audio threads execute in spurts whenever a new buffer is requested and are completely dormant in between. Some clever buffering is used so that Ruby can insert values into the host's MIDI and audio buffers at the correct indexes to line up with samples - but the Ruby code isn't actually executing at that precise moment. Green triggers are only processed in between buffer refreshes, so audio streams only see green values change once per ASIO buffer, no matter how fast you send triggers. When the ASIO buffers arrive is totally beyond our control, and may be subject to all kinds of software and/or hardware latency and jitter - the only thing which can be said for sure is that each one represents a "slice" of time of a certain duration.
Green tickers and timers make use of a timing service provided by Windows - Windows is asked to "call back later" after an approximate amount of time has elapsed. This service has very low CPU priority, so the amount of time is very approximate, and easily gets stretched out if the CPU is busy. When the "call back" happens, a new green event is triggered - and this event is subject to all of the caveats noted previously.
Hence, green triggers manipulating audio with sample-accurate timing is simply impossible. The best you could do would be to change the value at a specific inter-buffer boundary, but most people use such small ASIO buffer sizes these days that even that would be quite unlikely given the extremely loose timing of the Windows timers. Ruby can time things more accurately, but there's quite a high cost for this, as it requires additional buffering and/or special ways of synchronising value changes across the different CPU threads. As Chris pointed out earlier in the thread, if you need sample-accurate timing with relatively low CPU load, you have to do it completely in blue/white stream code.
And I have no doubt that MyCo would point out that even the above is a massive over-simplification!