cleanup-dhandler #3
7 changed files with 429 additions and 682 deletions
|
|
@ -34,9 +34,12 @@ class DisplayHandler {
|
||||||
"CV2 INV",
|
"CV2 INV",
|
||||||
"Mute"
|
"Mute"
|
||||||
};
|
};
|
||||||
bool onOutScreen = 0;
|
|
||||||
|
|
||||||
bool onSettingsScreen = 0;
|
bool onOutScreen = false;
|
||||||
|
bool onMainScreen = true;
|
||||||
|
bool onSettingsScreen = false;
|
||||||
|
bool engageBPM = false;
|
||||||
|
|
||||||
std::array<std::string, 6> settings = {
|
std::array<std::string, 6> settings = {
|
||||||
"Save",
|
"Save",
|
||||||
"Load",
|
"Load",
|
||||||
|
|
@ -49,6 +52,11 @@ class DisplayHandler {
|
||||||
void renderMainPage();
|
void renderMainPage();
|
||||||
void renderOutPage();
|
void renderOutPage();
|
||||||
void renderSettingsPage();
|
void renderSettingsPage();
|
||||||
|
void handleCursorOnOutputScreen(bool dir);
|
||||||
|
void handleClickOnOutputScreen();
|
||||||
|
void handleCursorOnMainScreen(bool dir);
|
||||||
|
void handleClickOnMainScreen();
|
||||||
|
void handleClickOnSettingsScreen();
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -61,6 +69,7 @@ class DisplayHandler {
|
||||||
int8_t currentOut;
|
int8_t currentOut;
|
||||||
bool cursorClick;
|
bool cursorClick;
|
||||||
void setup();
|
void setup();
|
||||||
|
uint8_t modifyParameter(uint8_t dir, int8_t target, uint8_t clampMax, uint8_t clampMin = 0, bool overflow = true);
|
||||||
void render();
|
void render();
|
||||||
void handleClick();
|
void handleClick();
|
||||||
void exitSettingsScreen();
|
void exitSettingsScreen();
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ static constexpr uint8_t OUT_6_PIN = 10;
|
||||||
static constexpr uint8_t OUT_7_PIN = 12;
|
static constexpr uint8_t OUT_7_PIN = 12;
|
||||||
static constexpr uint8_t OUT_8_PIN = 14;
|
static constexpr uint8_t OUT_8_PIN = 14;
|
||||||
|
|
||||||
|
static constexpr uint8_t IN_CLK_PIN = 16;
|
||||||
static constexpr uint8_t IN_RUN_PIN = 17;
|
static constexpr uint8_t IN_RUN_PIN = 17;
|
||||||
|
|
||||||
static constexpr uint8_t SCREEN_SCL_PIN = 18;
|
static constexpr uint8_t SCREEN_SCL_PIN = 18;
|
||||||
|
|
@ -44,6 +45,9 @@ extern volatile bool RUN;
|
||||||
extern volatile uint8_t EXTPPQNIdx;
|
extern volatile uint8_t EXTPPQNIdx;
|
||||||
#define PPQN_OPTS_LEN 5
|
#define PPQN_OPTS_LEN 5
|
||||||
extern const uint16_t PPQNOPTS[PPQN_OPTS_LEN];
|
extern const uint16_t PPQNOPTS[PPQN_OPTS_LEN];
|
||||||
|
extern volatile uint64_t last_clk_us;
|
||||||
|
extern volatile uint64_t last_valid_clk_us;
|
||||||
|
extern volatile bool EXTERNAL_CLOCK;
|
||||||
|
|
||||||
enum WaveShape { SQUARE, TRIANGLE, SAW, RAMP, EXP, HALFSINE, REXP, LOG, SINE, BOUNCE, SIGMO, WOBBLE, STEPDW, STEPUP, SH, SHAPE_COUNT};
|
enum WaveShape { SQUARE, TRIANGLE, SAW, RAMP, EXP, HALFSINE, REXP, LOG, SINE, BOUNCE, SIGMO, WOBBLE, STEPDW, STEPUP, SH, SHAPE_COUNT};
|
||||||
|
|
||||||
|
|
|
||||||
263
master_clock.ino
263
master_clock.ino
|
|
@ -1,263 +0,0 @@
|
||||||
#include <SPI.h>
|
|
||||||
#include <Wire.h>
|
|
||||||
#include <U8g2lib.h>
|
|
||||||
#include <TimerOne.h>
|
|
||||||
|
|
||||||
#include "globals.h"
|
|
||||||
#include "Out.h"
|
|
||||||
|
|
||||||
#define SCREEN_WIDTH 128
|
|
||||||
#define SCREEN_HEIGHT 64
|
|
||||||
#define OLED_RESET -1
|
|
||||||
#define SCREEN_ADDRESS 0x3C
|
|
||||||
#define CLK 2
|
|
||||||
#define DT 3
|
|
||||||
|
|
||||||
|
|
||||||
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
|
|
||||||
|
|
||||||
byte play = 1;
|
|
||||||
byte BPM = 100;
|
|
||||||
|
|
||||||
unsigned long minute = 60000000L;
|
|
||||||
byte ppqn = 96;
|
|
||||||
unsigned long period = (minute / BPM) / ppqn;
|
|
||||||
|
|
||||||
volatile boolean beatToggle = false;
|
|
||||||
|
|
||||||
Out out1(4);
|
|
||||||
Out out2(5);
|
|
||||||
Out out3(6);
|
|
||||||
Out out4(7);
|
|
||||||
Out out5(8);
|
|
||||||
Out out6(9);
|
|
||||||
Out out7(10);
|
|
||||||
Out out8(11);
|
|
||||||
|
|
||||||
byte btnPin = 13;
|
|
||||||
byte btnState = 0;
|
|
||||||
|
|
||||||
volatile long rPotPos = 0;
|
|
||||||
unsigned long rPotLastUpdate = 0;
|
|
||||||
const unsigned long rPotThrottle = 50;
|
|
||||||
|
|
||||||
unsigned long screenLastUpdate = 0;
|
|
||||||
const unsigned long screenThrottle = 200;
|
|
||||||
byte forceScreenUpdate = 1;
|
|
||||||
|
|
||||||
byte currentScreen = 0;
|
|
||||||
byte editMode = 0;
|
|
||||||
int mainScreenCursorPos = 0;
|
|
||||||
byte maxMainScreenPos = 8;
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
|
|
||||||
pinMode(btnPin, INPUT_PULLUP);
|
|
||||||
|
|
||||||
// rotary encoder set up
|
|
||||||
pinMode(CLK, INPUT_PULLUP);
|
|
||||||
pinMode(DT, INPUT_PULLUP);
|
|
||||||
attachInterrupt(digitalPinToInterrupt(CLK), updateEncoder, FALLING);
|
|
||||||
|
|
||||||
// screen setup
|
|
||||||
u8g2.begin();
|
|
||||||
u8g2.setFontMode(1);
|
|
||||||
|
|
||||||
// display.clearDisplay();
|
|
||||||
// display.setTextSize(2);
|
|
||||||
// display.setTextColor(WHITE);
|
|
||||||
// display.setCursor(0, 0);
|
|
||||||
//
|
|
||||||
// String bpmString = "BPM: ";
|
|
||||||
// String bpmCalculatedString = bpmString + BPM;
|
|
||||||
// display.println(bpmCalculatedString);
|
|
||||||
//
|
|
||||||
// display.display();
|
|
||||||
|
|
||||||
// init timer
|
|
||||||
Timer1.initialize(1000000);
|
|
||||||
Timer1.attachInterrupt(clock);
|
|
||||||
Timer1.setPeriod(period);
|
|
||||||
|
|
||||||
// init outputs
|
|
||||||
out1.setLen(period);
|
|
||||||
out2.setLen(period);
|
|
||||||
out3.setLen(period);
|
|
||||||
out4.setLen(period);
|
|
||||||
out5.setLen(period);
|
|
||||||
out6.setLen(period);
|
|
||||||
out7.setLen(period);
|
|
||||||
out8.setLen(period);
|
|
||||||
|
|
||||||
// manual setup
|
|
||||||
out1.setDiv(8, 0);
|
|
||||||
out1.setWidth(50);
|
|
||||||
|
|
||||||
out2.setDiv(4, 0);
|
|
||||||
out2.setWidth(50);
|
|
||||||
|
|
||||||
out3.setDiv(2, 0);
|
|
||||||
out3.setWidth(50);
|
|
||||||
|
|
||||||
out4.setDiv(1);
|
|
||||||
out4.setWidth(50);
|
|
||||||
|
|
||||||
out5.setDiv(2);
|
|
||||||
out5.setWidth(50);
|
|
||||||
|
|
||||||
out6.setDiv(4);
|
|
||||||
out6.setWidth(50);
|
|
||||||
|
|
||||||
out7.setDiv(8);
|
|
||||||
out7.setWidth(50);
|
|
||||||
|
|
||||||
out8.setDiv(16);
|
|
||||||
out8.setWidth(50);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clock(void) {
|
|
||||||
if (play == 1) {
|
|
||||||
beatToggle = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (beatToggle) {
|
|
||||||
out1.turnOn();
|
|
||||||
out2.turnOn();
|
|
||||||
out3.turnOn();
|
|
||||||
out4.turnOn();
|
|
||||||
out5.turnOn();
|
|
||||||
out6.turnOn();
|
|
||||||
out7.turnOn();
|
|
||||||
out8.turnOn();
|
|
||||||
|
|
||||||
beatToggle = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
out1.turnOff();
|
|
||||||
out2.turnOff();
|
|
||||||
out3.turnOff();
|
|
||||||
out4.turnOff();
|
|
||||||
out5.turnOff();
|
|
||||||
out6.turnOff();
|
|
||||||
out7.turnOff();
|
|
||||||
out8.turnOff();
|
|
||||||
|
|
||||||
checkBtn();
|
|
||||||
checkRPot();
|
|
||||||
updateScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateScreen() {
|
|
||||||
unsigned long currentTime = millis();
|
|
||||||
if (currentTime - screenLastUpdate >= screenThrottle && forceScreenUpdate == 1) {
|
|
||||||
screenLastUpdate = currentTime;
|
|
||||||
forceScreenUpdate = 0;
|
|
||||||
u8g2.firstPage();
|
|
||||||
do {
|
|
||||||
// 12px - nonbold
|
|
||||||
if (mainScreenCursorPos == 0) {
|
|
||||||
u8g2.setFont(u8g2_font_7x14B_mf);
|
|
||||||
} else {
|
|
||||||
u8g2.setFont(u8g2_font_7x14_mf);
|
|
||||||
}
|
|
||||||
|
|
||||||
u8g2.setCursor(0, 15);
|
|
||||||
u8g2.print(F("BPM: "));
|
|
||||||
u8g2.print(BPM);
|
|
||||||
|
|
||||||
u8g2.setFont(u8g2_font_7x14_mf);
|
|
||||||
u8g2.setCursor(0, 45);
|
|
||||||
|
|
||||||
char buffer[5];
|
|
||||||
for (byte i = 1; i < 9; i++) {
|
|
||||||
if (i == 5) {
|
|
||||||
u8g2.setCursor(0, 60);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainScreenCursorPos == i) {
|
|
||||||
u8g2.setFont(u8g2_font_7x14B_mf);
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(buffer, "[%d] ", i);
|
|
||||||
u8g2.print(buffer);
|
|
||||||
|
|
||||||
if (mainScreenCursorPos == i) {
|
|
||||||
u8g2.setFont(u8g2_font_7x14_mf);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} while (u8g2.nextPage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkBtn() {
|
|
||||||
byte currentBtnState = digitalRead(btnPin);
|
|
||||||
if (currentBtnState != btnState) {
|
|
||||||
if (currentBtnState == 1) {
|
|
||||||
play = (play == 1) ? 0 : 1;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
btnState = currentBtnState;
|
|
||||||
};
|
|
||||||
|
|
||||||
void checkRPot() {
|
|
||||||
if (millis() - rPotLastUpdate >= rPotThrottle) {
|
|
||||||
|
|
||||||
noInterrupts();
|
|
||||||
long currentPos = rPotPos;
|
|
||||||
interrupts();
|
|
||||||
|
|
||||||
// Print position only if it has changed
|
|
||||||
static long previousPos = -999;
|
|
||||||
if (currentPos != previousPos) {
|
|
||||||
Serial.print("Encoder Position: ");
|
|
||||||
Serial.println(currentPos);
|
|
||||||
|
|
||||||
// on home screen
|
|
||||||
if (currentScreen == 0) {
|
|
||||||
if (editMode == 0) {
|
|
||||||
if (currentPos > previousPos) {
|
|
||||||
mainScreenCursorPos++;
|
|
||||||
if (mainScreenCursorPos > maxMainScreenPos) {
|
|
||||||
mainScreenCursorPos = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mainScreenCursorPos--;
|
|
||||||
if (mainScreenCursorPos < 0) {
|
|
||||||
mainScreenCursorPos = maxMainScreenPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
forceScreenUpdate = 1;
|
|
||||||
|
|
||||||
previousPos = currentPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
rPotLastUpdate = millis(); // Reset the timer for throttling the output
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleBPMChange(byte increase) {
|
|
||||||
if (increase == 1) {
|
|
||||||
BPM++;
|
|
||||||
} else {
|
|
||||||
BPM--;
|
|
||||||
}
|
|
||||||
|
|
||||||
period = (minute / BPM) / ppqn;
|
|
||||||
Timer1.setPeriod(period);
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateEncoder() {
|
|
||||||
// The ISR should be as short and fast as possible
|
|
||||||
// Check the state of the DT pin to determine direction
|
|
||||||
if (digitalRead(3) == LOW) {
|
|
||||||
rPotPos++; // Clockwise
|
|
||||||
} else {
|
|
||||||
rPotPos--; // Counter-clockwise
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -43,131 +43,75 @@ void DisplayHandler::setup() {
|
||||||
display->setOrientation(0);
|
display->setOrientation(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayHandler::moveCursor(bool dir) {
|
uint8_t DisplayHandler::modifyParameter(uint8_t dir, int8_t target, uint8_t clampMax, uint8_t clampMin, bool overflow) {
|
||||||
if (onOutScreen) {
|
|
||||||
if (cursorClick == 0) {
|
|
||||||
if (dir == 1) {
|
if (dir == 1) {
|
||||||
cursorPosition++;
|
target++;
|
||||||
currentScreen++;
|
|
||||||
} else {
|
} else {
|
||||||
cursorPosition--;
|
target--;
|
||||||
currentScreen--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursorPosition > outMaxCursorPosition) {
|
if (target > clampMax) {
|
||||||
cursorPosition = 0;
|
if (overflow) {
|
||||||
currentScreen = 0;
|
target = clampMin;
|
||||||
|
} else {
|
||||||
|
target = clampMax;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursorPosition < 0) {
|
if (target < clampMin) {
|
||||||
cursorPosition = outMaxCursorPosition;
|
if (overflow) {
|
||||||
currentScreen = outMaxCursorPosition;
|
target = clampMax;
|
||||||
|
} else {
|
||||||
|
target = clampMin;
|
||||||
}
|
}
|
||||||
} else { // click = 1
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayHandler::handleCursorOnMainScreen(bool dir) {
|
||||||
|
if (cursorPosition == 0 && cursorClick == 1) { // Engage BPM on Main Screen
|
||||||
|
update_BPM(dir);
|
||||||
|
} else {
|
||||||
|
cursorPosition = modifyParameter(dir, cursorPosition, mainMaxCursorPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayHandler::handleCursorOnOutputScreen(bool dir) {
|
||||||
|
if (cursorClick == 0) { // No click, scroll through options
|
||||||
|
currentScreen = modifyParameter(dir, cursorPosition, outMaxCursorPosition, 0);
|
||||||
|
cursorPosition = currentScreen;
|
||||||
|
} else {
|
||||||
if (currentScreen == 1) { // mod screen
|
if (currentScreen == 1) { // mod screen
|
||||||
outputs[currentOut]->editing = 1;
|
outputs[currentOut]->editing = 1;
|
||||||
if (dir == 1) {
|
|
||||||
outputs[currentOut]->modifierSelectionIndex++;
|
|
||||||
} else {
|
|
||||||
outputs[currentOut]->modifierSelectionIndex--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputs[currentOut]->modifierSelectionIndex < 0) {
|
outputs[currentOut]->modifierSelectionIndex = modifyParameter(dir, outputs[currentOut]->modifierSelectionIndex, std::size(MOD_TYPES) - 1);
|
||||||
outputs[currentOut]->modifierSelectionIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputs[currentOut]->modifierSelectionIndex >
|
|
||||||
std::size(MOD_TYPES) - 1) {
|
|
||||||
outputs[currentOut]->modifierSelectionIndex =
|
|
||||||
std::size(MOD_TYPES) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (currentScreen == 2) { // shape control
|
} else if (currentScreen == 2) { // shape control
|
||||||
int currentShape = (int)outputs[currentOut]->shape;
|
int8_t currentShape = (int8_t)outputs[currentOut]->shape;
|
||||||
|
|
||||||
if (dir == 1) {
|
currentShape = modifyParameter(dir, currentShape, SHAPE_COUNT -1, 0);
|
||||||
currentShape++;
|
|
||||||
} else {
|
|
||||||
currentShape--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentShape >= SHAPE_COUNT) {
|
|
||||||
currentShape = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentShape < 0) {
|
|
||||||
currentShape = SHAPE_COUNT - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
outputs[currentOut]->shape = (WaveShape)currentShape;
|
outputs[currentOut]->shape = (WaveShape)currentShape;
|
||||||
outputs[currentOut]->writeAnalog(0);
|
outputs[currentOut]->writeAnalog(0);
|
||||||
|
|
||||||
} else if (currentScreen == 3) { // level control
|
} else if (currentScreen == 3) { // level control
|
||||||
outputs[currentOut]->editing = 1;
|
outputs[currentOut]->editing = 1;
|
||||||
if (dir == 1) {
|
outputs[currentOut]->level = modifyParameter(dir, outputs[currentOut]->level, 100, 1, false);
|
||||||
outputs[currentOut]->level++;
|
|
||||||
} else {
|
|
||||||
outputs[currentOut]->level--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputs[currentOut]->level > 100) {
|
|
||||||
outputs[currentOut]->level = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputs[currentOut]->level < 1) {
|
|
||||||
outputs[currentOut]->level = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (currentScreen == 4) { // width control
|
} else if (currentScreen == 4) { // width control
|
||||||
outputs[currentOut]->editing = 1;
|
outputs[currentOut]->editing = 1;
|
||||||
if (dir == 1) {
|
outputs[currentOut]->width = modifyParameter(dir, outputs[currentOut]->width, 100, 1, false);
|
||||||
outputs[currentOut]->width++;
|
|
||||||
} else {
|
|
||||||
outputs[currentOut]->width--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputs[currentOut]->width > 100) {
|
|
||||||
outputs[currentOut]->width = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputs[currentOut]->width < 1) {
|
|
||||||
outputs[currentOut]->width = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
outputs[currentOut]->setWidth(outputs[currentOut]->width);
|
outputs[currentOut]->setWidth(outputs[currentOut]->width);
|
||||||
|
|
||||||
} else if (currentScreen == 5) { // SWING
|
} else if (currentScreen == 5) { // SWING
|
||||||
|
|
||||||
outputs[currentOut]->editing = 1;
|
outputs[currentOut]->editing = 1;
|
||||||
if (dir == 1) {
|
outputs[currentOut]->swing = modifyParameter(dir, outputs[currentOut]->swing, 75, 50, false);
|
||||||
outputs[currentOut]->swing++;
|
|
||||||
} else {
|
|
||||||
outputs[currentOut]->swing--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputs[currentOut]->swing > 100) {
|
|
||||||
outputs[currentOut]->swing = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputs[currentOut]->swing < 50) {
|
|
||||||
outputs[currentOut]->swing = 50;
|
|
||||||
}
|
|
||||||
} else if (currentScreen == 6) { // PROBABILITY
|
} else if (currentScreen == 6) { // PROBABILITY
|
||||||
|
|
||||||
outputs[currentOut]->editing = 1;
|
outputs[currentOut]->editing = 1;
|
||||||
if (dir == 1) {
|
outputs[currentOut]->p = modifyParameter(dir, outputs[currentOut]->p, 100, 0, false);
|
||||||
outputs[currentOut]->p++;
|
|
||||||
} else {
|
|
||||||
outputs[currentOut]->p--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputs[currentOut]->p > 100) {
|
|
||||||
outputs[currentOut]->p = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputs[currentOut]->p < 0) {
|
|
||||||
outputs[currentOut]->p = 0;
|
|
||||||
}
|
|
||||||
} else if (currentScreen == 7) { // STICKY
|
} else if (currentScreen == 7) { // STICKY
|
||||||
outputs[currentOut]->sticky ^= true;
|
outputs[currentOut]->sticky ^= true;
|
||||||
|
|
||||||
|
|
@ -216,15 +160,10 @@ void DisplayHandler::moveCursor(bool dir) {
|
||||||
currentDest = DEST_COUNT - 1;
|
currentDest = DEST_COUNT - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
matrix.slots[outputs[currentOut]->slotIdx1].destParam =
|
matrix.slots[outputs[currentOut]->slotIdx1].destParam = (ModDest)currentDest;
|
||||||
(ModDest)currentDest;
|
|
||||||
|
|
||||||
} else if (currentScreen == 11) { // CV1 AMT
|
} else if (currentScreen == 11) { // CV1 AMT
|
||||||
if (dir == 1) {
|
matrix.slots[outputs[currentOut]->slotIdx1].amount = modifyParameter(dir, matrix.slots[outputs[currentOut]->slotIdx1].amount, 100, 0, false);
|
||||||
matrix.slots[outputs[currentOut]->slotIdx1].amount++;
|
|
||||||
} else {
|
|
||||||
matrix.slots[outputs[currentOut]->slotIdx1].amount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (currentScreen == 12) { // CV1 INV
|
} else if (currentScreen == 12) { // CV1 INV
|
||||||
matrix.slots[outputs[currentOut]->slotIdx1].inverted ^= true;
|
matrix.slots[outputs[currentOut]->slotIdx1].inverted ^= true;
|
||||||
|
|
@ -271,92 +210,84 @@ void DisplayHandler::moveCursor(bool dir) {
|
||||||
(ModDest)currentDest;
|
(ModDest)currentDest;
|
||||||
|
|
||||||
} else if (currentScreen == 16) { // CV2 AMT
|
} else if (currentScreen == 16) { // CV2 AMT
|
||||||
if (dir == 1) {
|
matrix.slots[outputs[currentOut]->slotIdx2].amount = modifyParameter(dir, matrix.slots[outputs[currentOut]->slotIdx2].amount, 100, 0, false);
|
||||||
matrix.slots[outputs[currentOut]->slotIdx2].amount++;
|
|
||||||
} else {
|
|
||||||
matrix.slots[outputs[currentOut]->slotIdx2].amount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (currentScreen == 17) { // CV2 INV
|
} else if (currentScreen == 17) { // CV2 INV
|
||||||
matrix.slots[outputs[currentOut]->slotIdx2].inverted ^= true;
|
matrix.slots[outputs[currentOut]->slotIdx2].inverted ^= true;
|
||||||
|
|
||||||
} else if (currentScreen == 18) { // MUTE
|
} else if (currentScreen == 18) { // MUTE
|
||||||
|
|
||||||
outputs[currentOut]->editing = 1;
|
|
||||||
outputs[currentOut]->isEnabled ^= true;
|
outputs[currentOut]->isEnabled ^= true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
if (cursorPosition == 0 && cursorClick == 1) { // Engage BPM on Main Screen
|
|
||||||
update_BPM(dir);
|
|
||||||
} else {
|
|
||||||
if (dir == 1) {
|
|
||||||
cursorPosition++;
|
|
||||||
} else {
|
|
||||||
cursorPosition--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!onSettingsScreen) {
|
void DisplayHandler::moveCursor(bool dir) {
|
||||||
if (cursorPosition > mainMaxCursorPosition) {
|
if (onOutScreen) {
|
||||||
cursorPosition = 0;
|
handleCursorOnOutputScreen(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursorPosition < 0) {
|
if (onMainScreen) {
|
||||||
cursorPosition = mainMaxCursorPosition;
|
handleCursorOnMainScreen(dir);
|
||||||
}
|
|
||||||
} else if (onSettingsScreen) {
|
|
||||||
|
|
||||||
if (cursorPosition > 5) {
|
|
||||||
cursorPosition = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursorPosition < 0) {
|
if (onSettingsScreen) {
|
||||||
cursorPosition = 5;
|
cursorPosition = modifyParameter(dir, cursorPosition, 5, 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateScreen = 1;
|
updateScreen = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayHandler::handleClick() {
|
void DisplayHandler::handleClickOnOutputScreen() {
|
||||||
cursorClick ^= true;
|
|
||||||
|
|
||||||
if (onOutScreen && !onSettingsScreen) {
|
|
||||||
if (currentScreen == 0) { // exit screen
|
if (currentScreen == 0) { // exit screen
|
||||||
cursorPosition = currentOut + 1;
|
cursorPosition = currentOut + 1;
|
||||||
|
onMainScreen = true;
|
||||||
|
onOutScreen = false;
|
||||||
|
onSettingsScreen = false;
|
||||||
currentOut = -1;
|
currentOut = -1;
|
||||||
currentScreen = 0;
|
currentScreen = 0;
|
||||||
onOutScreen = 0;
|
|
||||||
cursorClick = false;
|
cursorClick = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// move this out to the other group
|
||||||
if (currentScreen == 1 && outputs[currentOut]->editing == 1) {
|
if (currentScreen == 1 && outputs[currentOut]->editing == 1) {
|
||||||
outputs[currentOut]->setDiv(outputs[currentOut]->modifierSelectionIndex);
|
outputs[currentOut]->setDiv(outputs[currentOut]->modifierSelectionIndex);
|
||||||
outputs[currentOut]->editing = 0;
|
outputs[currentOut]->editing = 0;
|
||||||
cursorClick = false;
|
cursorClick = false;
|
||||||
}
|
}
|
||||||
|
updateScreen = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DisplayHandler::handleClickOnMainScreen() {
|
||||||
|
if (cursorPosition == 0) {
|
||||||
|
if (engageBPM) {
|
||||||
|
cursorClick = 0;
|
||||||
|
engageBPM = false;
|
||||||
} else {
|
} else {
|
||||||
|
engageBPM = true;
|
||||||
if (currentScreen == 0 && !onSettingsScreen) { // on main screen
|
cursorClick = 1;
|
||||||
if (cursorPosition == 0) { // Change BPM
|
}
|
||||||
|
} if (cursorPosition > 0 && cursorPosition < 9) { // GO TO OUTPUT
|
||||||
} else if (cursorPosition > 0 && cursorPosition < 9) { // go to out screen
|
|
||||||
currentOut = cursorPosition - 1;
|
currentOut = cursorPosition - 1;
|
||||||
cursorPosition = 1;
|
cursorPosition = 1;
|
||||||
currentScreen = 1;
|
currentScreen = 1;
|
||||||
onOutScreen = 1;
|
onOutScreen = true;
|
||||||
|
onMainScreen = false;
|
||||||
|
onSettingsScreen = false;
|
||||||
cursorClick = 0;
|
cursorClick = 0;
|
||||||
} else if (cursorPosition == 9) { // PLAY/PAUSE BUTTON
|
} else if (cursorPosition == 9) { // PLAY/PAUSE BUTTON
|
||||||
PLAY ^= true;
|
PLAY ^= true;
|
||||||
|
cursorClick = 0;
|
||||||
} else if (cursorPosition == 10) { // GLOBAL SETTINGS
|
} else if (cursorPosition == 10) { // GLOBAL SETTINGS
|
||||||
cursorPosition = 0;
|
cursorPosition = 0;
|
||||||
onSettingsScreen = 1;
|
onSettingsScreen = true;
|
||||||
|
onMainScreen = false;
|
||||||
|
onOutScreen = false;
|
||||||
cursorClick = 0;
|
cursorClick = 0;
|
||||||
}
|
}
|
||||||
} else if (onSettingsScreen) {
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DisplayHandler::handleClickOnSettingsScreen() {
|
||||||
if (cursorPosition == 0) { // SAVE
|
if (cursorPosition == 0) { // SAVE
|
||||||
flashMessage("Saving...");
|
flashMessage("Saving...");
|
||||||
|
|
||||||
|
|
@ -364,13 +295,6 @@ void DisplayHandler::handleClick() {
|
||||||
outputs[i]->pack(globalSettings.configs[i]);
|
outputs[i]->pack(globalSettings.configs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
globalSettings.bpm = BPM;
|
|
||||||
globalSettings.play = PLAY;
|
|
||||||
globalSettings.run = RUN;
|
|
||||||
globalSettings.ppqnidx = EXTPPQNIdx;
|
|
||||||
|
|
||||||
memcpy(globalSettings.slots, matrix.slots, sizeof(ModSlot) * 16);
|
|
||||||
|
|
||||||
save();
|
save();
|
||||||
|
|
||||||
exitSettingsScreen();
|
exitSettingsScreen();
|
||||||
|
|
@ -427,28 +351,40 @@ void DisplayHandler::handleClick() {
|
||||||
} else if (cursorPosition == 5) { // EXIT
|
} else if (cursorPosition == 5) { // EXIT
|
||||||
exitSettingsScreen();
|
exitSettingsScreen();
|
||||||
}
|
}
|
||||||
}
|
cursorClick = 0;
|
||||||
}
|
|
||||||
|
|
||||||
updateScreen = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayHandler::exitSettingsScreen() {
|
void DisplayHandler::exitSettingsScreen() {
|
||||||
onOutScreen = 0;
|
onOutScreen = false;
|
||||||
onSettingsScreen = 0;
|
onSettingsScreen = false;
|
||||||
|
onMainScreen = true;
|
||||||
|
|
||||||
cursorPosition = 10;
|
cursorPosition = 10;
|
||||||
cursorClick = 0;
|
cursorClick = 0;
|
||||||
currentScreen = 0;
|
currentScreen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayHandler::handleClick() {
|
||||||
|
cursorClick ^= true;
|
||||||
|
|
||||||
|
if (onOutScreen) {
|
||||||
|
handleClickOnOutputScreen();
|
||||||
|
} else if (onMainScreen) { // on main screen
|
||||||
|
handleClickOnMainScreen();
|
||||||
|
} else if (onSettingsScreen) {
|
||||||
|
handleClickOnSettingsScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateScreen = 1;
|
||||||
|
}
|
||||||
|
|
||||||
void DisplayHandler::render() {
|
void DisplayHandler::render() {
|
||||||
if (updateScreen) {
|
if (updateScreen) {
|
||||||
display->clear();
|
display->clear();
|
||||||
|
|
||||||
if (!onSettingsScreen && currentScreen == 0 &&
|
if (onMainScreen) { // main screen
|
||||||
currentOut == -1) { // main screen
|
|
||||||
renderMainPage();
|
renderMainPage();
|
||||||
} else if (!onSettingsScreen && currentOut != -1) {
|
} else if (onOutScreen) {
|
||||||
renderOutPage();
|
renderOutPage();
|
||||||
} else if (onSettingsScreen) {
|
} else if (onSettingsScreen) {
|
||||||
renderSettingsPage();
|
renderSettingsPage();
|
||||||
|
|
|
||||||
|
|
@ -293,6 +293,10 @@ void Gate::update() {
|
||||||
|
|
||||||
if (elapsedUs >= pulseDurationUs) {
|
if (elapsedUs >= pulseDurationUs) {
|
||||||
state = 0;
|
state = 0;
|
||||||
|
if (width < 100) {
|
||||||
|
scheduledTick = 0xFFFFFFFF;
|
||||||
|
lastTriggerTick = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
if (!sticky)
|
if (!sticky)
|
||||||
writeAnalog(0);
|
writeAnalog(0);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,14 @@
|
||||||
DeviceSettings globalSettings;
|
DeviceSettings globalSettings;
|
||||||
|
|
||||||
void save() {
|
void save() {
|
||||||
|
|
||||||
|
globalSettings.bpm = BPM;
|
||||||
|
globalSettings.play = PLAY;
|
||||||
|
globalSettings.run = RUN;
|
||||||
|
globalSettings.ppqnidx = EXTPPQNIdx;
|
||||||
|
|
||||||
|
memcpy(globalSettings.slots, matrix.slots, sizeof(ModSlot) * 16);
|
||||||
|
|
||||||
const uint32_t WRITE_SIZE = (sizeof(DeviceSettings) + 255) & ~255;
|
const uint32_t WRITE_SIZE = (sizeof(DeviceSettings) + 255) & ~255;
|
||||||
|
|
||||||
static uint8_t __attribute__((aligned(4))) write_buf[2048];
|
static uint8_t __attribute__((aligned(4))) write_buf[2048];
|
||||||
|
|
@ -30,6 +38,8 @@ void save() {
|
||||||
multicore_lockout_end_blocking();
|
multicore_lockout_end_blocking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void load_default() {
|
void load_default() {
|
||||||
memset(&globalSettings.slots, 0, sizeof(globalSettings.slots));
|
memset(&globalSettings.slots, 0, sizeof(globalSettings.slots));
|
||||||
|
|
||||||
|
|
|
||||||
49
src/main.cpp
49
src/main.cpp
|
|
@ -7,6 +7,8 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <hardware/gpio.h>
|
#include <hardware/gpio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <pico/types.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "DisplayHandler.h"
|
#include "DisplayHandler.h"
|
||||||
|
|
@ -26,6 +28,9 @@ volatile uint32_t MASTER_TICK;
|
||||||
volatile bool RUN = false;
|
volatile bool RUN = false;
|
||||||
const uint16_t PPQNOPTS[] = {1, 2, 4, 24, 48};
|
const uint16_t PPQNOPTS[] = {1, 2, 4, 24, 48};
|
||||||
volatile uint8_t EXTPPQNIdx = 0;
|
volatile uint8_t EXTPPQNIdx = 0;
|
||||||
|
volatile uint64_t last_clk_us = 0;
|
||||||
|
volatile uint64_t last_valid_clk_us;
|
||||||
|
volatile bool EXTERNAL_CLOCK = false;
|
||||||
|
|
||||||
ModMatrix matrix;
|
ModMatrix matrix;
|
||||||
|
|
||||||
|
|
@ -75,6 +80,12 @@ void update_BPM(bool up) {
|
||||||
for (auto g : outputs) {
|
for (auto g : outputs) {
|
||||||
g->setWidth(g->width);
|
g->setWidth(g->width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!EXTERNAL_CLOCK) {
|
||||||
|
init_timer(period_us);
|
||||||
|
} else {
|
||||||
|
cancel_repeating_timer(&bpm_timer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void core1_entry() {
|
void core1_entry() {
|
||||||
|
|
@ -130,6 +141,35 @@ void handle_outs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_callback(uint gpio, uint32_t events) {
|
void gpio_callback(uint gpio, uint32_t events) {
|
||||||
|
// CLK LOGIC
|
||||||
|
if (gpio == IN_CLK_PIN && (events & GPIO_IRQ_EDGE_RISE)) {
|
||||||
|
uint64_t now = to_us_since_boot(get_absolute_time());
|
||||||
|
|
||||||
|
if (now - last_valid_clk_us < 5000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
last_valid_clk_us = now;
|
||||||
|
|
||||||
|
uint16_t incomingPPQN;
|
||||||
|
if (last_clk_us > 0) {
|
||||||
|
uint64_t diff = now - last_clk_us;
|
||||||
|
incomingPPQN = PPQNOPTS[EXTPPQNIdx];
|
||||||
|
float calculatedBPM = 60000000.0f / (float)(diff * incomingPPQN);
|
||||||
|
|
||||||
|
if (calculatedBPM >= 30 && calculatedBPM <= 255) {
|
||||||
|
if (fabsf((float)BPM - calculatedBPM) > 0.5f) {
|
||||||
|
BPM = (uint8_t)(calculatedBPM + 0.5f);
|
||||||
|
|
||||||
|
update_period();
|
||||||
|
for (auto g : outputs) {
|
||||||
|
g->setWidth(g->width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MASTER_TICK += (PPQN / incomingPPQN);
|
||||||
|
last_clk_us = now;
|
||||||
|
}
|
||||||
|
|
||||||
if (gpio == IN_RUN_PIN) {
|
if (gpio == IN_RUN_PIN) {
|
||||||
if (RUN) {
|
if (RUN) {
|
||||||
|
|
@ -156,9 +196,16 @@ void setup_ins() {
|
||||||
gpio_init(IN_RUN_PIN);
|
gpio_init(IN_RUN_PIN);
|
||||||
gpio_set_dir(IN_RUN_PIN, GPIO_IN);
|
gpio_set_dir(IN_RUN_PIN, GPIO_IN);
|
||||||
gpio_pull_down(IN_RUN_PIN);
|
gpio_pull_down(IN_RUN_PIN);
|
||||||
gpio_set_irq_enabled_with_callback(IN_RUN_PIN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
|
gpio_set_irq_enabled_with_callback(IN_RUN_PIN,
|
||||||
|
GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL,
|
||||||
|
true, &gpio_callback);
|
||||||
|
|
||||||
// SETUP CLOCK
|
// SETUP CLOCK
|
||||||
|
gpio_init(IN_CLK_PIN);
|
||||||
|
gpio_set_dir(IN_CLK_PIN, GPIO_IN);
|
||||||
|
gpio_pull_down(IN_CLK_PIN);
|
||||||
|
// Add to existing callback
|
||||||
|
gpio_set_irq_enabled(IN_CLK_PIN, GPIO_IRQ_EDGE_RISE, true);
|
||||||
|
|
||||||
// SETUP CV INS
|
// SETUP CV INS
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue