sowbug / groove

A digital audio workstation (DAW) engine.
Other
20 stars 0 forks source link

There might be two clocks #30

Closed sowbug closed 1 year ago

sowbug commented 1 year ago

If we want MIDI hardware to play our instruments at any time, then parts of the current loop should be running all the time, even when nothing is playing.

One approach: Clock is always ticking, and Controllers learn not to start until they're triggered (maybe that's what the Play action really is). All time references are relative to that start time, and components just have to deal with it. Since the sample counter is a usize, we could run for about 27 hours at 44.1KHz on a 32-bit machine before that rolls over and weirdness ensues.

Another approach: it's understood that a tick() is always one sample later than the last tick(), and anyone who cares to count samples can do so on their own time (ha ha). E.g., an Oscillator might increment an internal counter on each tick. Everyone keeps getting their tick() or source_audio() calls, nonstop, and all they know is the sample rate and maybe BPM/time signature. Then Clock is once again more like how it is now, where its time zero is the start of the performance. MIDI events can come in at any time and are handled by Controllers or Instruments, keeping time on their own (of course, all staying in sync via tick + sample rate = time).

These approaches aren't all that different. I think I like the second one better, because even if we don't have a zero-based Clock for the performance, we'd have to synthesize one to give meaningful updates to the user. Either the start is zero, or some random T - a start time equal to T. And that's probably what all the individual components would do.

sowbug commented 1 year ago

This is starting to become relevant. As I'm refactoring for batching (#55), I'm understanding that EnvelopeGenerator and the GeneratesEnvelope trait don't need much of Clock to get things done. They do care about the sample rate so that they can advance internal state by the right amount, but a global clock isn't all that interesting to them. Even if the global clock rewinds (the user drags the scrubber earlier in the project while playing, as captured in #19 ), time keeps moving forward for them. There will be issues such as an attack needing to be paired with a release, or an envelope whose shape depends on the time signature/tempo of the project. But the Clock monolith only barely helps with that.

sowbug commented 1 year ago

This work is beyond the point of no return. I don't need this issue anymore to remind me to do it.