Initial commit for midi. Midi out is working, Midi In is still a work in progress.

This commit is contained in:
2025-06-01 22:53:51 -07:00
parent 20f65d9bdf
commit 8cf64fefca
3 changed files with 75 additions and 6 deletions

65
clock.h
View File

@ -12,28 +12,49 @@
#ifndef CLOCK_H #ifndef CLOCK_H
#define CLOCK_H #define CLOCK_H
#include <NeoHWSerial.h>
#include <uClock.h> #include <uClock.h>
#include "peripherials.h" #include "peripherials.h"
// MIDI clock, start, stop, and continue byte definitions - based on MIDI 1.0 Standards.
#define MIDI_CLOCK 0xF8
#define MIDI_START 0xFA
#define MIDI_STOP 0xFC
#define MIDI_CONTINUE 0xFB
const int DEFAULT_TEMPO = 120; const int DEFAULT_TEMPO = 120;
static bool MIDI_ENABLED = false;
enum Source { enum Source {
SOURCE_INTERNAL, SOURCE_INTERNAL,
SOURCE_EXTERNAL_PPQN_24, SOURCE_EXTERNAL_PPQN_24,
SOURCE_EXTERNAL_PPQN_4, SOURCE_EXTERNAL_PPQN_4,
// SOURCE_MIDI, SOURCE_EXTERNAL_MIDI,
SOURCE_LAST, SOURCE_LAST,
}; };
class Clock { class Clock {
public: public:
void Init() { void Init() {
NeoSerial.begin(31250);
NeoSerial.attachInterrupt(onSerialEvent);
// Static pin definition for pulse out.
pinMode(PULSE_OUT_PIN, OUTPUT);
// Initialize the clock library // Initialize the clock library
uClock.init(); uClock.init();
uClock.setClockMode(uClock.INTERNAL_CLOCK); uClock.setClockMode(uClock.INTERNAL_CLOCK);
uClock.setOutputPPQN(uClock.PPQN_96); uClock.setOutputPPQN(uClock.PPQN_96);
uClock.setTempo(DEFAULT_TEMPO); uClock.setTempo(DEFAULT_TEMPO);
// MIDI events.
uClock.setOnClockStart(sendMIDIStart);
uClock.setOnClockStop(sendMIDIStop);
uClock.setOnSync24(sendMidiClock);
uClock.setOnSync48(sendPulseOut);
uClock.start(); uClock.start();
} }
@ -50,6 +71,7 @@ class Clock {
// Set the source of the clock mode. // Set the source of the clock mode.
void SetSource(Source source) { void SetSource(Source source) {
uClock.stop(); uClock.stop();
MIDI_ENABLED = false;
switch (source) { switch (source) {
case SOURCE_INTERNAL: case SOURCE_INTERNAL:
uClock.setClockMode(uClock.INTERNAL_CLOCK); uClock.setClockMode(uClock.INTERNAL_CLOCK);
@ -62,6 +84,11 @@ class Clock {
uClock.setClockMode(uClock.EXTERNAL_CLOCK); uClock.setClockMode(uClock.EXTERNAL_CLOCK);
uClock.setInputPPQN(uClock.PPQN_4); uClock.setInputPPQN(uClock.PPQN_4);
break; break;
case SOURCE_EXTERNAL_MIDI:
uClock.setClockMode(uClock.EXTERNAL_CLOCK);
uClock.setInputPPQN(uClock.PPQN_24);
MIDI_ENABLED = true;
break;
} }
uClock.start(); uClock.start();
} }
@ -97,6 +124,42 @@ class Clock {
bool IsPaused() { bool IsPaused() {
return uClock.clock_state == uClock.PAUSED; return uClock.clock_state == uClock.PAUSED;
} }
private:
static void onSerialEvent(uint8_t msg, uint8_t status) {
// if (!MIDI_ENABLED) {
// return;
// }
switch (msg) {
case MIDI_CLOCK:
uClock.clockMe();
break;
case MIDI_STOP:
uClock.stop();
break;
case MIDI_START:
case MIDI_CONTINUE:
uClock.start();
break;
}
}
static void sendMIDIStart() {
NeoSerial.write(MIDI_START);
}
static void sendMIDIStop() {
NeoSerial.write(MIDI_STOP);
}
static void sendMidiClock(uint32_t tick) {
NeoSerial.write(MIDI_CLOCK);
}
static void sendPulseOut(uint32_t tick) {
digitalWrite(PULSE_OUT_PIN, !digitalRead(PULSE_OUT_PIN));
}
}; };
#endif #endif

View File

@ -39,7 +39,7 @@ AppState app;
// The number of clock mod options, hepls validate choices and pulses arrays are the same size. // The number of clock mod options, hepls validate choices and pulses arrays are the same size.
const int MOD_CHOICE_SIZE = 21; const int MOD_CHOICE_SIZE = 21;
// negative=multiply, positive=divide // Negative for multiply, positive for divide.
const int clock_mod[MOD_CHOICE_SIZE] = {-24, -12, -8, -6, -4, -3, -2, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 24, 32, 64, 128}; const int clock_mod[MOD_CHOICE_SIZE] = {-24, -12, -8, -6, -4, -3, -2, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 24, 32, 64, 128};
// This represents the number of clock pulses for a 96 PPQN clock source that match the above div/mult mods. // This represents the number of clock pulses for a 96 PPQN clock source that match the above div/mult mods.
@ -317,9 +317,14 @@ void DisplayMainPage() {
textWidth = gravity.display.getUTF8Width("4 PPQN"); textWidth = gravity.display.getUTF8Width("4 PPQN");
gravity.display.drawStr(32 - (textWidth / 2), subTextY, "4 PPQN"); gravity.display.drawStr(32 - (textWidth / 2), subTextY, "4 PPQN");
break; break;
// case SOURCE_EXTERNAL_MIDI: case SOURCE_EXTERNAL_MIDI:
// gravity.display.print(F("EXT MIDI")); gravity.display.setFont(LARGE_FONT);
// break; textWidth = gravity.display.getUTF8Width("EXT");
gravity.display.drawStr(32 - (textWidth / 2), textY, "EXT");
gravity.display.setFont(TEXT_FONT);
textWidth = gravity.display.getUTF8Width("MIDI");
gravity.display.drawStr(32 - (textWidth / 2), subTextY, "MIDI");
break;
} }
} }
@ -366,7 +371,7 @@ void DisplayChannelPage() {
gravity.display.drawStr(32 - (textWidth / 2), subTextY, "Divide"); gravity.display.drawStr(32 - (textWidth / 2), subTextY, "Divide");
} else { } else {
sprintf(mod_str, "X%d", abs(clock_mod[ch.clock_mod_index])); sprintf(mod_str, "x%d", abs(clock_mod[ch.clock_mod_index]));
textWidth = gravity.display.getUTF8Width(mod_str); textWidth = gravity.display.getUTF8Width(mod_str);
gravity.display.drawStr(32 - (textWidth / 2), textY, mod_str); gravity.display.drawStr(32 - (textWidth / 2), textY, mod_str);
gravity.display.setFont(TEXT_FONT); gravity.display.setFont(TEXT_FONT);

View File

@ -25,6 +25,7 @@
#define EXT_PIN 2 #define EXT_PIN 2
#define CV1_PIN A7 #define CV1_PIN A7
#define CV2_PIN A6 #define CV2_PIN A6
#define PULSE_OUT_PIN 3
// Button pins // Button pins
#define SHIFT_BTN_PIN 12 #define SHIFT_BTN_PIN 12