Consistent clock behavior for ext cv and midi.
This commit is contained in:
58
clock.h
58
clock.h
@ -24,7 +24,10 @@
|
||||
#define MIDI_CONTINUE 0xFB
|
||||
|
||||
const int DEFAULT_TEMPO = 120;
|
||||
static bool MIDI_ENABLED = false;
|
||||
|
||||
typedef void (*ExtCallback)(void);
|
||||
static ExtCallback extUserCallback = nullptr;
|
||||
static void serialEventNoop(uint8_t msg, uint8_t status) {}
|
||||
|
||||
enum Source {
|
||||
SOURCE_INTERNAL,
|
||||
@ -38,12 +41,12 @@ class Clock {
|
||||
public:
|
||||
void Init() {
|
||||
NeoSerial.begin(31250);
|
||||
NeoSerial.attachInterrupt(onSerialEvent);
|
||||
|
||||
// Static pin definition for pulse out.
|
||||
pinMode(PULSE_OUT_PIN, OUTPUT);
|
||||
|
||||
// Initialize the clock library
|
||||
uClock.setExtIntervalBuffer(32);
|
||||
uClock.init();
|
||||
uClock.setClockMode(uClock.INTERNAL_CLOCK);
|
||||
uClock.setOutputPPQN(uClock.PPQN_96);
|
||||
@ -52,14 +55,15 @@ class Clock {
|
||||
// MIDI events.
|
||||
uClock.setOnClockStart(sendMIDIStart);
|
||||
uClock.setOnClockStop(sendMIDIStop);
|
||||
uClock.setOnSync24(sendMidiClock);
|
||||
uClock.setOnSync24(sendMIDIClock);
|
||||
uClock.setOnSync48(sendPulseOut);
|
||||
|
||||
uClock.start();
|
||||
}
|
||||
|
||||
// Handler for receiving clock trigger(PPQN_4 or PPQN_24).
|
||||
void AttachExtHandler(void (*callback)(void)) {
|
||||
// Handle external clock tick and call user callback when receiving clock trigger (PPQN_4, PPQN_24, or MIDI).
|
||||
void AttachExtHandler(void (*callback)()) {
|
||||
extUserCallback = callback;
|
||||
attachInterrupt(digitalPinToInterrupt(EXT_PIN), callback, RISING);
|
||||
}
|
||||
|
||||
@ -70,8 +74,13 @@ class Clock {
|
||||
|
||||
// Set the source of the clock mode.
|
||||
void SetSource(Source source) {
|
||||
bool was_playing = !IsPaused();
|
||||
uClock.stop();
|
||||
MIDI_ENABLED = false;
|
||||
// If source is currently MIDI, disable the serial interrupt handler.
|
||||
if (source_ == SOURCE_EXTERNAL_MIDI) {
|
||||
NeoSerial.attachInterrupt(serialEventNoop);
|
||||
}
|
||||
source_ = source;
|
||||
switch (source) {
|
||||
case SOURCE_INTERNAL:
|
||||
uClock.setClockMode(uClock.INTERNAL_CLOCK);
|
||||
@ -87,52 +96,64 @@ class Clock {
|
||||
case SOURCE_EXTERNAL_MIDI:
|
||||
uClock.setClockMode(uClock.EXTERNAL_CLOCK);
|
||||
uClock.setInputPPQN(uClock.PPQN_24);
|
||||
MIDI_ENABLED = true;
|
||||
NeoSerial.attachInterrupt(onSerialEvent);
|
||||
break;
|
||||
}
|
||||
uClock.start();
|
||||
if (was_playing) {
|
||||
uClock.start();
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if the current selected source is externl (PPQN_4, PPQN_24, or MIDI).
|
||||
bool ExternalSource() {
|
||||
return uClock.getClockMode() == uClock.EXTERNAL_CLOCK;
|
||||
}
|
||||
|
||||
// Return true if the current selected source is the internal master clock.
|
||||
bool InternalSource() {
|
||||
return uClock.getClockMode() == uClock.INTERNAL_CLOCK;
|
||||
}
|
||||
|
||||
// Returns the current BPM tempo.
|
||||
int Tempo() {
|
||||
return uClock.getTempo();
|
||||
}
|
||||
|
||||
// Set the clock tempo to a int between 1 and 400.
|
||||
void SetTempo(int tempo) {
|
||||
return uClock.setTempo(tempo);
|
||||
}
|
||||
|
||||
// Record an external clock tick received to process external/internal syncronization.
|
||||
void Tick() {
|
||||
uClock.clockMe();
|
||||
}
|
||||
|
||||
void Pause() {
|
||||
uClock.pause();
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
// Start the internal clock.
|
||||
void Start() {
|
||||
uClock.start();
|
||||
}
|
||||
|
||||
// Stop internal clock clock.
|
||||
void Stop() {
|
||||
uClock.stop();
|
||||
}
|
||||
|
||||
// Returns true if the clock is not running.
|
||||
bool IsPaused() {
|
||||
return uClock.clock_state == uClock.PAUSED;
|
||||
}
|
||||
|
||||
private:
|
||||
Source source_ = SOURCE_INTERNAL;
|
||||
|
||||
static void onSerialEvent(uint8_t msg, uint8_t status) {
|
||||
// if (!MIDI_ENABLED) {
|
||||
// return;
|
||||
// }
|
||||
// Note: uClock start and stop will echo to MIDI.
|
||||
switch (msg) {
|
||||
case MIDI_CLOCK:
|
||||
uClock.clockMe();
|
||||
if (extUserCallback) {
|
||||
extUserCallback();
|
||||
}
|
||||
break;
|
||||
case MIDI_STOP:
|
||||
uClock.stop();
|
||||
@ -141,7 +162,6 @@ class Clock {
|
||||
case MIDI_CONTINUE:
|
||||
uClock.start();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,7 +173,7 @@ class Clock {
|
||||
NeoSerial.write(MIDI_STOP);
|
||||
}
|
||||
|
||||
static void sendMidiClock(uint32_t tick) {
|
||||
static void sendMIDIClock(uint32_t tick) {
|
||||
NeoSerial.write(MIDI_CLOCK);
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
*
|
||||
* BTN1: Play/pause the internal clock.
|
||||
*
|
||||
* BTN2: Reset all clocks.
|
||||
* BTN2: Stop all clocks.
|
||||
*
|
||||
*/
|
||||
|
||||
@ -68,8 +68,8 @@ void setup() {
|
||||
gravity.Init();
|
||||
|
||||
// Clock handlers.
|
||||
gravity.clock.AttachExtHandler(ExtClock);
|
||||
gravity.clock.AttachIntHandler(IntClock);
|
||||
gravity.clock.AttachIntHandler(HandleIntClockTick);
|
||||
gravity.clock.AttachExtHandler(HandleExtClockTick);
|
||||
|
||||
// Encoder rotate and press handlers.
|
||||
gravity.encoder.AttachPressHandler(HandleEncoderPressed);
|
||||
@ -95,16 +95,9 @@ void loop() {
|
||||
// Firmware handlers.
|
||||
//
|
||||
|
||||
void ExtClock() {
|
||||
if (gravity.clock.ExternalSource()) {
|
||||
gravity.clock.Tick();
|
||||
app.refresh_screen = true;
|
||||
}
|
||||
}
|
||||
|
||||
void IntClock(uint32_t tick) {
|
||||
void HandleIntClockTick(uint32_t tick) {
|
||||
for (int i = 0; i < OUTPUT_COUNT; i++) {
|
||||
const auto& channel = app.channel[i];
|
||||
auto& channel = app.channel[i];
|
||||
auto& output = gravity.outputs[i];
|
||||
|
||||
const uint32_t mod_pulses = clock_mod_pulses[channel.clock_mod_index];
|
||||
@ -126,18 +119,27 @@ void IntClock(uint32_t tick) {
|
||||
}
|
||||
}
|
||||
|
||||
void HandlePlayPressed() {
|
||||
gravity.clock.Pause();
|
||||
if (gravity.clock.IsPaused()) {
|
||||
for (int i = 0; i < OUTPUT_COUNT; i++) {
|
||||
gravity.outputs[i].Low();
|
||||
}
|
||||
void HandleExtClockTick() {
|
||||
// Ignore tick if not using external source.
|
||||
if (!gravity.clock.ExternalSource()) {
|
||||
return;
|
||||
}
|
||||
gravity.clock.Tick();
|
||||
app.refresh_screen = true;
|
||||
}
|
||||
|
||||
void HandlePlayPressed() {
|
||||
gravity.clock.IsPaused()
|
||||
? gravity.clock.Start()
|
||||
: gravity.clock.Stop();
|
||||
ResetOutputs();
|
||||
app.refresh_screen = true;
|
||||
}
|
||||
|
||||
void HandleShiftPressed() {
|
||||
gravity.clock.Reset();
|
||||
gravity.clock.Stop();
|
||||
ResetOutputs();
|
||||
app.refresh_screen = true;
|
||||
}
|
||||
|
||||
void HandleEncoderPressed() {
|
||||
@ -228,6 +230,12 @@ Channel& GetSelectedChannel() {
|
||||
return app.channel[app.selected_channel - 1];
|
||||
}
|
||||
|
||||
void ResetOutputs() {
|
||||
for (int i = 0; i < OUTPUT_COUNT; i++) {
|
||||
gravity.outputs[i].Low();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// UI Display functions.
|
||||
//
|
||||
@ -352,7 +360,7 @@ void DisplayChannelPage() {
|
||||
gravity.display.setFontMode(1);
|
||||
gravity.display.setDrawColor(2);
|
||||
gravity.display.setFont(LARGE_FONT);
|
||||
|
||||
|
||||
int textWidth;
|
||||
int textY = 26;
|
||||
int subTextY = 42;
|
||||
|
||||
16
gravity.cpp
16
gravity.cpp
@ -12,17 +12,17 @@
|
||||
#include "gravity.h"
|
||||
|
||||
void Gravity::Init() {
|
||||
InitClock();
|
||||
InitInputs();
|
||||
InitOutputs();
|
||||
InitDisplay();
|
||||
initClock();
|
||||
initInputs();
|
||||
initOutputs();
|
||||
initDisplay();
|
||||
}
|
||||
|
||||
void Gravity::InitClock() {
|
||||
void Gravity::initClock() {
|
||||
clock.Init();
|
||||
}
|
||||
|
||||
void Gravity::InitInputs() {
|
||||
void Gravity::initInputs() {
|
||||
shift_button.Init(SHIFT_BTN_PIN);
|
||||
play_button.Init(PLAY_BTN_PIN);
|
||||
|
||||
@ -40,7 +40,7 @@ void Gravity::InitInputs() {
|
||||
PCMSK1 |= B00001000;
|
||||
}
|
||||
|
||||
void Gravity::InitOutputs() {
|
||||
void Gravity::initOutputs() {
|
||||
// Initialize each of the outputs with it's GPIO pins and probability.
|
||||
outputs[0].Init(OUT_CH1);
|
||||
outputs[1].Init(OUT_CH2);
|
||||
@ -49,7 +49,7 @@ void Gravity::InitOutputs() {
|
||||
outputs[4].Init(OUT_CH5);
|
||||
outputs[5].Init(OUT_CH6);
|
||||
}
|
||||
void Gravity::InitDisplay() {
|
||||
void Gravity::initDisplay() {
|
||||
// OLED Display configuration.
|
||||
display.begin();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user