Skip to content

Commit

Permalink
MIDISyncClock: Small but important bug fixes
Browse files Browse the repository at this point in the history
Wakeup times were handled quite wrong -- which bug led me to add
a wrong offset of -1 when rescheduling. Pretty bad.
  • Loading branch information
jamshark70 committed Sep 22, 2018
1 parent 4cfeea3 commit 7cf12a4
Showing 1 changed file with 24 additions and 20 deletions.
44 changes: 24 additions & 20 deletions MIDISyncClock.sc 100644 → 100755
Expand Up @@ -6,14 +6,14 @@
MIDISyncClock {
classvar <>ticksPerBeat = 24; // MIDI clock standard
classvar responseFuncs;

classvar <ticks, <beats, <startTime,
<tempo, <beatDur,
<beatsPerBar = 4, <barsPerBeat = 0.25, <baseBar, <baseBarBeat;

// private vars
classvar lastTickTime, <queue;

*initClass {
responseFuncs = IdentityDictionary[
// tick
Expand All @@ -25,30 +25,31 @@ MIDISyncClock {
lastTickDelta = nextTime - (lastTickTime ? 0);
lastTickTime = nextTime;
tempo = (beatDur = lastTickDelta * ticksPerBeat).reciprocal;

ticks = ticks + 1;
beats = ticks / ticksPerBeat;

// while loop needed because more than one thing may be scheduled for this tick
{ (queue.topPriority ?? { inf }) < ticks }.while({
{ (queue.topPriority ?? { inf }) <= ticks }.while({
// perform the action, and check if it should be rescheduled
(nextTime = (task = queue.pop).value(beats)).isNumber.if({
this.sched(nextTime, task, -1)
(nextTime = (task = queue.pop).awake(beats, this.seconds, this)).isNumber.if({
this.sched(nextTime, task, 0)
});
});
},
// start -- scheduler should be clear first
10 -> { |data|
startTime = lastTickTime = Main.elapsedTime;
ticks = beats = baseBar = baseBarBeat = 0;
beats = baseBar = baseBarBeat = 0;
ticks = -1; // because we expect a clock message to come next, should be 0
},
// stop
12 -> { |data|
this.clear;
}
];
}

*init {
// retrieve MIDI sources first
// assumes sources[0] is the MIDI clock source
Expand All @@ -65,21 +66,24 @@ MIDISyncClock {
queue = PriorityQueue.new;
beats = ticks = baseBar = baseBarBeat = 0;
}

*schedAbs { arg when, task;
queue.put(when * ticksPerBeat, task);
}

*sched { arg when, task, adjustment = 0;
queue.put((when * ticksPerBeat) + ticks + adjustment, task);
}

*tick { |index, data|
responseFuncs[index].value(data);
}

*play { arg task, when;
this.schedAbs(when.nextTimeOnGrid(this), task);
when = when.nextTimeOnGrid(this);
if(when.notNil) {
this.schedAbs(when, task);
};
}

*nextTimeOnGrid { arg quant = 1, phase = 0;
Expand All @@ -88,7 +92,7 @@ MIDISyncClock {
offset = baseBarBeat + phase;
^roundUp(this.beats - offset, quant) + offset;
}

*beatsPerBar_ { |newBeatsPerBar = 4|
this.setMeterAtBeat(newBeatsPerBar, beats)
}
Expand All @@ -105,19 +109,19 @@ MIDISyncClock {
*beats2secs { |beats|
^beats * beatDur;
}

*secs2beats { |seconds|
^seconds * tempo;
}

// elapsed time doesn't make sense because this clock only advances when told
// from outside - but, -play methods need elapsedBeats to calculate quant
*elapsedBeats { ^beats }
*seconds { ^startTime.notNil.if(Main.elapsedTime - startTime, nil) }

*clear { queue.clear }

// for debugging
// for debugging
*dumpQueue {
{ queue.topPriority.notNil }.while({
Post << "\n" << queue.topPriority << "\n";
Expand Down

0 comments on commit 7cf12a4

Please sign in to comment.