Adding a time-signature based sequencer for INSTRUMENT
This old musical notation tool has me choosing between wait/interrupt vs. polling based approaches
INSTRUMENT's previous sequencer is really cool and solid. However, it doesn't properly handle time signatures, or any sort of beat/bar restrictions.
This has been fun because it allows for a lot of flexibility when creating patterns, and innately favor polyrhythmic approaches, but it does have a bunch of downsides:
- Forces the player to be careful about matching pattern lengths
- Can't properly start patterns at the precise moment you want them
- Makes it hard to sync different instruments
Until now, whenever I want to sync instruments, I have used the .go function, sort of like this:
(
i.bass.go(0);
i.drums.go(0);
)
This does the trick, but it is quite time-consuming and cumbersome.
Because of this, I will start experimenting with a time signature based sequencer, that will take care of starting patterns at the correct time, which I'm sure will make for a much more musical experience.
A few questions remain unanswered:
Musical question: How to handle patterns with a different length than the current time signature? My current hunch is that non-regular patterns should be allowed to fall out of sync, after starting in the first beat of a bar in their first repetition. This allows for polyrhythmic expression. On the other hand: it's important to let musicians make mistakes while performing. Whether this works nicely is something that I will, however, not be able to answer until I hear it, so let's code this damn thing first.
Technical question: Should I use a polling based approach, triggering events based on the current time position? Or would it be better to use a wait/interrupt based approach, where the sequencer waits for the current event to happen at the right time, while simultaneously keeping track of current position inside the time signature? I am currently thinking that the second approach is better for preserving CPU resources, but am aware that the time-keeping part of this strategy is a lot more complex.
Basically: which of the following approaches should I use?
Wait based approach
inf.do {
// perform current event
var waitTime = event.duration
// wait until next event
waitTime.wait;
}
Polling based approach
inf.do {
// check if its time for next event
// wait for 10 microseconds:
0.00001.wait;
}
I will now code a small experiment and see if the wait/interrupt based approach is not too hard to tackle