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 triggerClockOutTickScheduled;
144 uint32_t timeNextTriggerClockOutTick;
145 int64_t lastTriggerClockOutTickDone;
149 uint32_t timeLastTriggerClockOutTickSent;
151 uint32_t analogOutTicksPPQN;
152 uint32_t analogInTicksPPQN;
153 uint32_t timeLastAnalogClockInputRisingEdge;
154 bool analogClockInputAutoStart;
156 bool songSwapShouldPreserveTempo;
160 bool midiOutClockEnabled;
161 bool midiInClockEnabled;
162 bool tempoMagnitudeMatchingEnabled;
165 int32_t swungTicksTilNextEvent;
167 int32_t ticksLeftInCountIn;
168 int32_t currentVisualCountForCountIn;
170 int32_t metronomeOffset;
173 void tapTempoAutoSwitchOff();
174 void reassessInputTickScaling();
175 void resyncInternalTicksToInputTicks(
Song* song);
176 bool shouldRecordNotesNow();
177 void stopAnyRecording();
178 uint32_t getTimePerInternalTick();
179 uint64_t getTimePerInternalTickBig();
180 float getTimePerInternalTickFloat();
181 uint32_t getTimePerInternalTickInverse(
bool getStickyValue =
false);
182 void tapTempoButtonPress(
bool useNormalTapTempoBehaviour);
183 void doTriggerClockOutTick();
184 void doMIDIClockOutTick();
185 void resyncAnalogOutTicksToInternalTicks();
186 void resyncMIDIClockOutTicksToInternalTicks();
187 void analogClockRisingEdge(uint32_t time);
188 void toggleMetronomeStatus();
189 void commandDisplayTempo();
190 void setMidiOutClockMode(
bool newValue);
191 void pitchBendReceived(
MIDICable& cable, uint8_t channel, uint8_t data1, uint8_t data2,
bool* doingMidiThru);
192 void midiCCReceived(
MIDICable& cable, uint8_t channel, uint8_t ccNumber, uint8_t value,
bool* doingMidiThru);
193 void programChangeReceived(
MIDICable& cable, int32_t channel, int32_t program);
194 void aftertouchReceived(
MIDICable& cable, int32_t channel, int32_t value, int32_t noteCode,
195 bool* doingMidiThru);
196 void loopCommand(OverDubType overdubNature);
197 void grabTempoFromClip(
Clip* clip);
198 int32_t getTimeLeftInCountIn();
200 void noteMessageReceived(
MIDICable& cable,
bool on, int32_t channel, int32_t note, int32_t velocity,
201 bool* doingMidiThru);
202 bool subModeAllowsRecording();
204 float calculateBPM(
float timePerInternalTick);
205 void switchToArrangement();
206 void switchToSession();
207 void finishTempolessRecording(
bool startPlaybackAgain, int32_t buttonLatencyForTempolessRecord,
208 bool shouldExitRecordMode =
true);
210 int32_t arrangementPosToStartAtOnSwitch;
212 bool stopOutputRecordingAtLoopEnd;
214 void actionTimerTick();
215 void actionTimerTickPart2();
216 void actionSwungTick();
217 void scheduleSwungTickFromInternalClock();
218 bool currentlySendingMIDIOutputClocks();
220 inline bool isExternalClockActive() {
return (playbackState & PLAYBACK_CLOCK_EXTERNAL_ACTIVE); }
221 inline bool isInternalClockActive() {
return (playbackState & PLAYBACK_CLOCK_INTERNAL_ACTIVE); }
222 inline bool isEitherClockActive() {
return (playbackState & PLAYBACK_CLOCK_EITHER_ACTIVE); }
226 void commandEditSwingAmount(int8_t offset);
228 void commandEditSwingInterval(int8_t offset);
229 void commandNudgeClock(int8_t offset);
230 void commandEditClockOutScale(int8_t offset);
231 void commandEditTempoCoarse(int8_t offset);
232 void commandEditTempoFine(int8_t offset);
233 void commandDisplayTempo(int8_t offset);
234 void commandClearTempoAutomation();
236 void getTempoStringForOLED(
float tempoBPM,
StringBuf& buffer);
238 void tryLoopCommand(GlobalMIDICommand command);
240 float calculateBPMForDisplay();
243 uint32_t timerTicksToOutputTicks(uint32_t timerTicks);
246 uint32_t timePerInternalTickMovingAverage;
247 uint32_t veryCurrentTimePerInternalTickInverse;
248 uint32_t stickyCurrentTimePerInternalTickInverse;
249 uint32_t lowpassedTimePerInternalTick;
250 uint32_t slowpassedTimePerInternalTick;
251 uint32_t stickyTimePerInternalTick;
253 uint16_t tapTempoNumPresses;
254 uint32_t tapTempoFirstPressTime;
256 int32_t numOutputClocksWaitingToBeSent;
257 int32_t numInputTicksToSkip;
258 uint32_t skipAnalogClocks;
259 uint32_t skipMidiClocks;
261 void resetTimePerInternalTickMovingAverage();
262 void getCurrentTempoParams(int32_t* magnitude, int8_t* whichValue);
263 void displayTempoFromParams(int32_t magnitude, int8_t whichValue);
264 void displayTempoBPM(
float tempoBPM);
265 void getAnalogOutTicksToInternalTicksRatio(uint32_t* internalTicksPer, uint32_t* analogOutTicksPer);
266 void getMIDIClockOutTicksToInternalTicksRatio(uint32_t* internalTicksPer, uint32_t* midiClockOutTicksPer);
267 void getInternalTicksToInputTicksRatio(uint32_t* inputTicksPer, uint32_t* internalTicksPer);
268 void sendOutPositionViaMIDI(int32_t pos,
bool outputClocksWereSwitchedOff =
false);
270 bool startIgnoringMidiClockInputIfNecessary();
271 uint32_t setTempoFromAudioClipLength(uint64_t loopLengthSamples,
Action* action);
272 bool offerNoteToLearnedThings(
MIDICable& cable,
bool on, int32_t channel, int32_t note);
273 bool tryGlobalMIDICommands(
MIDICable& cable, int32_t channel, int32_t note);
274 bool tryGlobalMIDICommandsOff(
MIDICable& cable, int32_t channel, int32_t note);
275 void decideOnCurrentPlaybackMode();
276 float getCurrentInternalTickFloatFollowingExternalClock();
277 void scheduleTriggerClockOutTickParamsKnown(uint32_t analogOutTicksPer, uint64_t fractionLastTimerTick,
278 uint64_t fractionNextAnalogOutTick);
279 void scheduleTriggerClockOutTickFromExternalClock();
280 void scheduleMIDIClockOutTickParamsKnown(uint32_t midiClockOutTicksPer, uint64_t fractionLastTimerTick,
281 uint64_t fractionNextMIDIClockOutTick);
282 void scheduleMIDIClockOutTickFromExternalClock();