Adding a time-signature based sequencer for INSTRUMENT

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