54class PlaybackHandler {
60 void playButtonPressed(int32_t buttonPressLatency);
61 void recordButtonPressed();
62 void setupPlaybackUsingInternalClock(int32_t buttonPressLatencyForTempolessRecord = 0,
bool allowCountIn =
true,
63 bool restartingPlayback =
false,
bool restartingPlaybackAtBeginning =
false);
64 void setupPlaybackUsingExternalClock(
bool switchingFromInternalClock =
false,
bool fromContinueCommand =
false);
65 void setupPlayback(int32_t newPlaybackState, int32_t playFromPos,
bool doOneLastAudioRoutineCall =
false,
66 bool shouldShiftAccordingToClipInstance =
true,
67 int32_t buttonPressLatencyForTempolessRecord = 0);
69 void inputTick(
bool fromTriggerClock =
false, uint32_t time = 0);
70 void startMessageReceived();
71 void continueMessageReceived();
72 void stopMessageReceived();
73 void clockMessageReceived(uint32_t time);
74 void tempoEncoderAction(int8_t offset,
bool encoderButtonPressed,
bool shiftButtonPressed);
75 bool isCurrentlyRecording();
76 void positionPointerReceived(uint8_t data1, uint8_t data2);
77 void doSongSwap(
bool preservePlayPosition =
false);
78 void forceResetPlayPos(
Song* song,
bool restartingPlaybackAtBeginning =
false);
80 void setMidiInClockEnabled(
bool newValue);
81 int32_t getActualArrangementRecordPos();
82 int32_t getArrangementRecordPosAtLastActionedSwungTick();
84 void scheduleSwungTickFromExternalClock();
85 int32_t getNumSwungTicksInSinceLastTimerTick(uint32_t* timeRemainder =
nullptr);
86 int32_t getNumSwungTicksInSinceLastActionedSwungTick(uint32_t* timeRemainder =
nullptr);
87 int64_t getActualSwungTickCount(uint32_t* timeRemainder =
nullptr);
88 int64_t getCurrentInternalTickCount(uint32_t* remainder =
nullptr);
89 void scheduleSwungTick();
90 int32_t getInternalTickTime(int64_t internalTickCount);
91 void scheduleTriggerClockOutTick();
92 void scheduleMIDIClockOutTick();
93 void scheduleNextTimerTick(uint32_t doubleSwingInterval);
96 bool midiClockOutTickScheduled;
97 uint32_t timeNextMIDIClockOutTick;
98 int64_t lastMIDIClockOutTickDone;
101 uint32_t timeLastMIDIClockOutTickSent;
104 uint8_t playbackState;
105 bool usingAnalogClockInput;
106 RecordingMode recording;
107 bool ignoringMidiClockInput;
109 int32_t posToNextContinuePlaybackFrom;
110 uint32_t timeLastMIDIStartOrContinueMessageSent;
113 int64_t lastTimerTickActioned;
114 int64_t nextTimerTickScheduled;
116 uint64_t timeNextTimerTickBig;
117 uint64_t timeLastTimerTickBig;
120 uint32_t timeLastInputTicks[kNumInputTicksForMovingAverage];
121 uint32_t timePerInputTickMovingAverage;
122 uint8_t numInputTickTimesCounted;
124 bool tempoMagnitudeMatchingActiveNow;
127 timeVeryFirstInputTick;
128 int64_t lastInputTickReceived;
129 unsigned long targetedTimePerInputTick;
132 bool swungTickScheduled;
133 uint32_t scheduledSwungTickTime;
140 int64_t lastSwungTickActioned;
143 bool firstSwungTickPending;
146 bool triggerClockOutTickScheduled;
147 uint32_t timeNextTriggerClockOutTick;
148 int64_t lastTriggerClockOutTickDone;
152 uint32_t timeLastTriggerClockOutTickSent;
154 uint32_t analogOutTicksPPQN;
155 uint32_t analogInTicksPPQN;
156 uint32_t timeLastAnalogClockInputRisingEdge;
157 bool analogClockInputAutoStart;
159 bool songSwapShouldPreserveTempo;
163 bool midiOutClockEnabled;
164 bool midiInClockEnabled;
165 bool tempoMagnitudeMatchingEnabled;
168 int32_t swungTicksTilNextEvent;
170 int32_t ticksLeftInCountIn;
171 int32_t currentVisualCountForCountIn;
173 int32_t metronomeOffset;
176 void tapTempoAutoSwitchOff();
177 void reassessInputTickScaling();
178 void resyncInternalTicksToInputTicks(
Song* song);
179 bool shouldRecordNotesNow();
180 void stopAnyRecording();
181 uint32_t getTimePerInternalTick();
182 uint64_t getTimePerInternalTickBig();
183 float getTimePerInternalTickFloat();
184 uint32_t getTimePerInternalTickInverse(
bool getStickyValue =
false);
185 void tapTempoButtonPress(
bool useNormalTapTempoBehaviour);
186 void doTriggerClockOutTick();
187 void doMIDIClockOutTick();
188 void resyncAnalogOutTicksToInternalTicks();
189 void resyncMIDIClockOutTicksToInternalTicks();
190 void analogClockRisingEdge(uint32_t time);
191 void toggleMetronomeStatus();
192 void commandDisplayTempo();
193 void setMidiOutClockMode(
bool newValue);
194 void pitchBendReceived(
MIDICable& cable, uint8_t channel, uint8_t data1, uint8_t data2,
bool* doingMidiThru);
195 void midiCCReceived(
MIDICable& cable, uint8_t channel, uint8_t ccNumber, uint8_t value,
bool* doingMidiThru);
196 void programChangeReceived(
MIDICable& cable, int32_t channel, int32_t program);
197 void aftertouchReceived(
MIDICable& cable, int32_t channel, int32_t value, int32_t noteCode,
198 bool* doingMidiThru);
199 void loopCommand(OverDubType overdubNature);
200 void grabTempoFromClip(
Clip* clip);
201 int32_t getTimeLeftInCountIn();
203 void noteMessageReceived(
MIDICable& cable,
bool on, int32_t channel, int32_t note, int32_t velocity,
204 bool* doingMidiThru);
205 bool subModeAllowsRecording();
207 float calculateBPM(
float timePerInternalTick);
208 float getTempoBPMAtArrangementPos(int32_t pos);
209 void getTempoParamsAtArrangementPos(int32_t pos, int32_t* magnitude, int8_t* whichValue);
210 void switchToArrangement();
211 void switchToSession();
212 void finishTempolessRecording(
bool startPlaybackAgain, int32_t buttonLatencyForTempolessRecord,
213 bool shouldExitRecordMode =
true);
215 int32_t arrangementPosToStartAtOnSwitch;
217 bool stopOutputRecordingAtLoopEnd;
219 void actionTimerTick();
220 void actionTimerTickPart2();
221 void actionSwungTick();
222 void scheduleSwungTickFromInternalClock();
223 bool currentlySendingMIDIOutputClocks();
225 inline bool isExternalClockActive() {
return (playbackState & PLAYBACK_CLOCK_EXTERNAL_ACTIVE); }
226 inline bool isInternalClockActive() {
return (playbackState & PLAYBACK_CLOCK_INTERNAL_ACTIVE); }
227 inline bool isEitherClockActive() {
return (playbackState & PLAYBACK_CLOCK_EITHER_ACTIVE); }
231 void commandEditSwingAmount(int8_t offset);
233 void commandEditSwingInterval(int8_t offset);
234 void commandNudgeClock(int8_t offset);
235 void commandEditClockOutScale(int8_t offset);
236 void commandEditTempoCoarse(int8_t offset);
237 void commandEditTempoFine(int8_t offset);
238 void commandDisplayTempo(int8_t offset);
239 void commandClearTempoAutomation();
241 void getTempoStringForOLED(
float tempoBPM,
StringBuf& buffer);
243 void tryLoopCommand(GlobalMIDICommand command);
245 float calculateBPMForDisplay();
248 uint32_t timerTicksToOutputTicks(uint32_t timerTicks);
251 uint32_t timePerInternalTickMovingAverage;
252 uint32_t veryCurrentTimePerInternalTickInverse;
253 uint32_t stickyCurrentTimePerInternalTickInverse;
254 uint32_t lowpassedTimePerInternalTick;
255 uint32_t slowpassedTimePerInternalTick;
256 uint32_t stickyTimePerInternalTick;
258 uint16_t tapTempoNumPresses;
259 uint32_t tapTempoFirstPressTime;
261 int32_t numOutputClocksWaitingToBeSent;
262 int32_t numInputTicksToSkip;
263 uint32_t skipAnalogClocks;
264 uint32_t skipMidiClocks;
266 void resetTimePerInternalTickMovingAverage();
267 void getCurrentTempoParams(int32_t* magnitude, int8_t* whichValue);
268 void getTempoParamsFromTimePer(uint64_t timePer, int32_t* magnitude, int8_t* whichValue);
269 void displayTempoFromParams(int32_t magnitude, int8_t whichValue);
270 void displayTempoBPM(
float tempoBPM);
271 void getAnalogOutTicksToInternalTicksRatio(uint32_t* internalTicksPer, uint32_t* analogOutTicksPer);
272 void getMIDIClockOutTicksToInternalTicksRatio(uint32_t* internalTicksPer, uint32_t* midiClockOutTicksPer);
273 void getInternalTicksToInputTicksRatio(uint32_t* inputTicksPer, uint32_t* internalTicksPer);
274 void sendOutPositionViaMIDI(int32_t pos,
bool outputClocksWereSwitchedOff =
false);
276 bool startIgnoringMidiClockInputIfNecessary();
277 uint32_t setTempoFromAudioClipLength(uint64_t loopLengthSamples,
Action* action);
278 bool offerNoteToLearnedThings(
MIDICable& cable,
bool on, int32_t channel, int32_t note);
279 bool tryGlobalMIDICommands(
MIDICable& cable, int32_t channel, int32_t note);
280 bool tryGlobalMIDICommandsOff(
MIDICable& cable, int32_t channel, int32_t note);
281 void decideOnCurrentPlaybackMode();
282 float getCurrentInternalTickFloatFollowingExternalClock();
283 void scheduleTriggerClockOutTickParamsKnown(uint32_t analogOutTicksPer, uint64_t fractionLastTimerTick,
284 uint64_t fractionNextAnalogOutTick);
285 void scheduleTriggerClockOutTickFromExternalClock();
286 void scheduleMIDIClockOutTickParamsKnown(uint32_t midiClockOutTicksPer, uint64_t fractionLastTimerTick,
287 uint64_t fractionNextMIDIClockOutTick);
288 void scheduleMIDIClockOutTickFromExternalClock();