save, load, reset, PPQN, run
This commit is contained in:
parent
5f762f0907
commit
5c7fe5e88d
8 changed files with 233 additions and 35 deletions
|
|
@ -35,8 +35,20 @@ class DisplayHandler {
|
|||
"Mute"
|
||||
};
|
||||
bool onOutScreen = 0;
|
||||
|
||||
bool onSettingsScreen = 0;
|
||||
std::array<std::string, 6> settings = {
|
||||
"Save",
|
||||
"Load",
|
||||
"Reset",
|
||||
"PPQN",
|
||||
"Run",
|
||||
"Exit"
|
||||
};
|
||||
|
||||
void renderMainPage();
|
||||
void renderOutPage();
|
||||
void renderSettingsPage();
|
||||
|
||||
|
||||
public:
|
||||
|
|
@ -51,6 +63,8 @@ class DisplayHandler {
|
|||
void setup();
|
||||
void render();
|
||||
void handleClick();
|
||||
void exitSettingsScreen();
|
||||
void flashMessage(std::string msg);
|
||||
void moveCursor(bool dir = 1);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public:
|
|||
uint16_t clk_last_state;
|
||||
|
||||
void setup();
|
||||
static void gpio_callback(uint gpio, uint32_t events);
|
||||
// static void gpio_callback(uint gpio, uint32_t events);
|
||||
void moveCursor(bool dir = 1);
|
||||
void update();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ struct DeviceSettings {
|
|||
uint32_t version;
|
||||
OutputConfig configs[MAX_OUTPUTS];
|
||||
ModSlot slots[16];
|
||||
bool play;
|
||||
uint8_t bpm;
|
||||
bool run;
|
||||
uint8_t ppqnidx;
|
||||
};
|
||||
|
||||
void save();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ static constexpr uint8_t OUT_6_PIN = 10;
|
|||
static constexpr uint8_t OUT_7_PIN = 12;
|
||||
static constexpr uint8_t OUT_8_PIN = 14;
|
||||
|
||||
static constexpr uint8_t IN_RUN_PIN = 17;
|
||||
|
||||
static constexpr uint8_t SCREEN_SCL_PIN = 18;
|
||||
static constexpr uint8_t SCREEN_SDA_PIN = 19;
|
||||
|
||||
|
|
@ -28,6 +30,8 @@ static constexpr uint8_t ENCODER_CLK_PIN = 20;
|
|||
static constexpr uint8_t ENCODER_DT_PIN = 21;
|
||||
static constexpr uint8_t ENCODER_SW_PIN = 22;
|
||||
|
||||
void gpio_callback(uint gpio, uint32_t events);
|
||||
|
||||
// TIME BASED
|
||||
extern volatile bool PLAY;
|
||||
extern volatile uint8_t BPM;
|
||||
|
|
@ -35,6 +39,11 @@ static constexpr uint32_t MINUTE_US = 60000000;
|
|||
static constexpr uint8_t PPQN = 96;
|
||||
extern volatile uint32_t MASTER_TICK;
|
||||
|
||||
extern volatile bool RUN;
|
||||
|
||||
extern volatile uint8_t EXTPPQNIdx;
|
||||
#define PPQN_OPTS_LEN 5
|
||||
extern const uint16_t PPQNOPTS[PPQN_OPTS_LEN];
|
||||
|
||||
enum WaveShape { SQUARE, TRIANGLE, SAW, RAMP, EXP, HALFSINE, REXP, LOG, SINE, BOUNCE, SIGMO, WOBBLE, STEPDW, STEPUP, SH, SHAPE_COUNT};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
// DisplayHandler.cpp
|
||||
#include "DisplayHandler.h"
|
||||
#include "Mod.h"
|
||||
#include "Settings.h"
|
||||
#include "globals.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <pico/time.h>
|
||||
#include <string>
|
||||
|
||||
#include "hardware/i2c.h"
|
||||
#include "pico-ssd1306/shapeRenderer/ShapeRenderer.h"
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
#include "pico-ssd1306/textRenderer/TextRenderer.h"
|
||||
#include "textRenderer/12x16_font.h"
|
||||
#include "textRenderer/8x8_font.h"
|
||||
|
||||
pico_ssd1306::SSD1306 *display = nullptr;
|
||||
extern void update_BPM(bool up);
|
||||
|
|
@ -292,6 +297,7 @@ void DisplayHandler::moveCursor(bool dir) {
|
|||
cursorPosition--;
|
||||
}
|
||||
|
||||
if (!onSettingsScreen) {
|
||||
if (cursorPosition > mainMaxCursorPosition) {
|
||||
cursorPosition = 0;
|
||||
}
|
||||
|
|
@ -299,6 +305,16 @@ void DisplayHandler::moveCursor(bool dir) {
|
|||
if (cursorPosition < 0) {
|
||||
cursorPosition = mainMaxCursorPosition;
|
||||
}
|
||||
} else if (onSettingsScreen) {
|
||||
|
||||
if (cursorPosition > 5) {
|
||||
cursorPosition = 0;
|
||||
}
|
||||
|
||||
if (cursorPosition < 0) {
|
||||
cursorPosition = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -308,7 +324,7 @@ void DisplayHandler::moveCursor(bool dir) {
|
|||
void DisplayHandler::handleClick() {
|
||||
cursorClick ^= true;
|
||||
|
||||
if (onOutScreen) {
|
||||
if (onOutScreen && !onSettingsScreen) {
|
||||
if (currentScreen == 0) { // exit screen
|
||||
cursorPosition = currentOut + 1;
|
||||
currentOut = -1;
|
||||
|
|
@ -324,7 +340,7 @@ void DisplayHandler::handleClick() {
|
|||
}
|
||||
} else {
|
||||
|
||||
if (currentScreen == 0) { // on main screen
|
||||
if (currentScreen == 0 && !onSettingsScreen) { // on main screen
|
||||
if (cursorPosition == 0) { // Change BPM
|
||||
|
||||
} else if (cursorPosition > 0 && cursorPosition < 9) { // go to out screen
|
||||
|
|
@ -335,6 +351,81 @@ void DisplayHandler::handleClick() {
|
|||
cursorClick = 0;
|
||||
} else if (cursorPosition == 9) { // PLAY/PAUSE BUTTON
|
||||
PLAY ^= true;
|
||||
} else if (cursorPosition == 10) { // GLOBAL SETTINGS
|
||||
cursorPosition = 0;
|
||||
onSettingsScreen = 1;
|
||||
cursorClick = 0;
|
||||
}
|
||||
} else if (onSettingsScreen) {
|
||||
if (cursorPosition == 0) { // SAVE
|
||||
flashMessage("Saving...");
|
||||
|
||||
for (int i = 0; i < 8; 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();
|
||||
|
||||
exitSettingsScreen();
|
||||
} else if (cursorPosition == 1) { // LOAD
|
||||
flashMessage("Loading...");
|
||||
PLAY = false;
|
||||
bool loaded_defaults = load();
|
||||
|
||||
if (!loaded_defaults) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
matrix.slots[i] = globalSettings.slots[i];
|
||||
}
|
||||
|
||||
BPM = globalSettings.bpm;
|
||||
PLAY = globalSettings.play;
|
||||
RUN = globalSettings.run;
|
||||
EXTPPQNIdx = globalSettings.ppqnidx;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
outputs[i]->unpack(globalSettings.configs[i]);
|
||||
}
|
||||
|
||||
exitSettingsScreen();
|
||||
} else if (cursorPosition == 2) { // RESET
|
||||
flashMessage("Resetting...");
|
||||
PLAY = false;
|
||||
load_default();
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
outputs[i]->unpack(globalSettings.configs[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeof(outputs); i++) {
|
||||
outputs[i]->setupPatches();
|
||||
}
|
||||
|
||||
PLAY = true;
|
||||
exitSettingsScreen();
|
||||
} else if (cursorPosition == 3) { // PPQN
|
||||
EXTPPQNIdx++;
|
||||
|
||||
if (EXTPPQNIdx >= PPQN_OPTS_LEN) {
|
||||
EXTPPQNIdx = 0;
|
||||
}
|
||||
|
||||
} else if (cursorPosition == 4) { // RUN
|
||||
RUN ^= true;
|
||||
|
||||
if (RUN) {
|
||||
PLAY = false;
|
||||
}
|
||||
|
||||
} else if (cursorPosition == 5) { // EXIT
|
||||
exitSettingsScreen();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -342,14 +433,25 @@ void DisplayHandler::handleClick() {
|
|||
updateScreen = 1;
|
||||
}
|
||||
|
||||
void DisplayHandler::exitSettingsScreen() {
|
||||
onOutScreen = 0;
|
||||
onSettingsScreen = 0;
|
||||
cursorPosition = 10;
|
||||
cursorClick = 0;
|
||||
currentScreen = 0;
|
||||
}
|
||||
|
||||
void DisplayHandler::render() {
|
||||
if (updateScreen) {
|
||||
display->clear();
|
||||
|
||||
if (currentScreen == 0 && currentOut == -1) { // main screen
|
||||
if (!onSettingsScreen && currentScreen == 0 &&
|
||||
currentOut == -1) { // main screen
|
||||
renderMainPage();
|
||||
} else if (currentOut != -1) {
|
||||
} else if (!onSettingsScreen && currentOut != -1) {
|
||||
renderOutPage();
|
||||
} else if (onSettingsScreen) {
|
||||
renderSettingsPage();
|
||||
}
|
||||
|
||||
display->sendBuffer();
|
||||
|
|
@ -503,3 +605,38 @@ void DisplayHandler::renderOutPage() {
|
|||
pico_ssd1306::drawText(display, font_12x16, param_string.c_str(), 1, 45);
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayHandler::flashMessage(std::string msg) {
|
||||
|
||||
display->clear();
|
||||
|
||||
pico_ssd1306::drawText(display, font_12x16, msg.c_str(), 1, 1);
|
||||
|
||||
display->sendBuffer();
|
||||
}
|
||||
|
||||
void DisplayHandler::renderSettingsPage() {
|
||||
uint8_t y = 3;
|
||||
for (int i = 0; i < settings.size(); i++) {
|
||||
if (cursorPosition == i) {
|
||||
pico_ssd1306::fillRect(display, 0, y, 50, y + 8);
|
||||
pico_ssd1306::drawText(display, font_8x8, settings[i].c_str(), 1, y,
|
||||
pico_ssd1306::WriteMode::SUBTRACT);
|
||||
|
||||
if (settings[i] == "Run") {
|
||||
std::string param = RUN ? "ON" : "OFF";
|
||||
pico_ssd1306::drawText(display, font_12x16, param.c_str(), 70, 20);
|
||||
}
|
||||
|
||||
if (settings[i] == "PPQN") {
|
||||
std::string param = std::to_string(PPQNOPTS[EXTPPQNIdx]);
|
||||
pico_ssd1306::drawText(display, font_12x16, param.c_str(), 70, 20);
|
||||
}
|
||||
|
||||
} else {
|
||||
pico_ssd1306::drawText(display, font_8x8, settings[i].c_str(), 1, y);
|
||||
}
|
||||
|
||||
y += 10;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,18 +17,6 @@ EncoderHandler::EncoderHandler(DisplayHandler *display_handler) {
|
|||
button_pressed = 0;
|
||||
}
|
||||
|
||||
void EncoderHandler::gpio_callback(uint gpio, uint32_t events) {
|
||||
uint64_t now = to_us_since_boot(get_absolute_time());
|
||||
static uint64_t last_sw_time = 0;
|
||||
|
||||
if (gpio == ENCODER_SW_PIN) {
|
||||
if (now - last_sw_time > 200000) { // 200ms debounce
|
||||
self->display_handler->handleClick();
|
||||
last_sw_time = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EncoderHandler::setup() {
|
||||
self = this;
|
||||
|
||||
|
|
@ -36,8 +24,7 @@ void EncoderHandler::setup() {
|
|||
gpio_set_dir(ENCODER_SW_PIN, GPIO_IN);
|
||||
gpio_pull_up(ENCODER_SW_PIN);
|
||||
|
||||
gpio_set_irq_enabled_with_callback(ENCODER_SW_PIN, GPIO_IRQ_EDGE_FALL, true,
|
||||
&EncoderHandler::gpio_callback);
|
||||
gpio_set_irq_enabled_with_callback(ENCODER_SW_PIN, GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
|
||||
|
||||
PIO pio = pio0;
|
||||
uint offset = pio_add_program(pio, &quadrature_encoder_program);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ void load_default() {
|
|||
s->p = 100;
|
||||
s->level = 100;
|
||||
s->shape = 0;
|
||||
|
||||
BPM = 60;
|
||||
PLAY = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
64
src/main.cpp
64
src/main.cpp
|
|
@ -6,6 +6,7 @@
|
|||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <hardware/gpio.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "DisplayHandler.h"
|
||||
|
|
@ -22,6 +23,9 @@ volatile uint8_t BPM = 60;
|
|||
volatile bool PLAY = true;
|
||||
volatile uint32_t period_us = 0;
|
||||
volatile uint32_t MASTER_TICK;
|
||||
volatile bool RUN = false;
|
||||
const uint16_t PPQNOPTS[] = {1, 2, 4, 24, 48};
|
||||
volatile uint8_t EXTPPQNIdx = 0;
|
||||
|
||||
ModMatrix matrix;
|
||||
|
||||
|
|
@ -89,6 +93,11 @@ void full_save() {
|
|||
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();
|
||||
|
|
@ -110,16 +119,6 @@ void setup_outs() {
|
|||
g->setLen(period_us);
|
||||
g->setupPatches();
|
||||
}
|
||||
|
||||
// // manual setup
|
||||
// out1.shape = SQUARE;
|
||||
// out1.setDiv(3);
|
||||
// out1.setWidth(50);
|
||||
// out1.level = 100;
|
||||
//
|
||||
// out2.shape = SINE;
|
||||
// out2.setDiv(14);
|
||||
// out2.setWidth(100);
|
||||
}
|
||||
|
||||
void handle_outs() {
|
||||
|
|
@ -130,6 +129,40 @@ void handle_outs() {
|
|||
}
|
||||
}
|
||||
|
||||
void gpio_callback(uint gpio, uint32_t events) {
|
||||
|
||||
if (gpio == IN_RUN_PIN) {
|
||||
if (RUN) {
|
||||
if (events & GPIO_IRQ_EDGE_RISE) {
|
||||
PLAY = true;
|
||||
} else if (events & GPIO_IRQ_EDGE_FALL) {
|
||||
PLAY = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gpio == ENCODER_SW_PIN) {
|
||||
uint64_t now = to_us_since_boot(get_absolute_time());
|
||||
static uint64_t last_sw_time = 0;
|
||||
if (now - last_sw_time > 200000) { // 200ms debounce
|
||||
display_handler.handleClick();
|
||||
last_sw_time = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup_ins() {
|
||||
// SETUP RUN
|
||||
gpio_init(IN_RUN_PIN);
|
||||
gpio_set_dir(IN_RUN_PIN, GPIO_IN);
|
||||
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);
|
||||
|
||||
// SETUP CLOCK
|
||||
|
||||
// SETUP CV INS
|
||||
}
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
sleep_ms(200);
|
||||
|
|
@ -145,6 +178,11 @@ int main() {
|
|||
for (int i = 0; i < 16; i++) {
|
||||
matrix.slots[i] = globalSettings.slots[i];
|
||||
}
|
||||
|
||||
BPM = globalSettings.bpm;
|
||||
PLAY = globalSettings.play;
|
||||
RUN = globalSettings.run;
|
||||
EXTPPQNIdx = globalSettings.ppqnidx;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
|
|
@ -159,6 +197,12 @@ int main() {
|
|||
|
||||
bool lastPlayState = false;
|
||||
|
||||
setup_ins();
|
||||
|
||||
if (RUN) {
|
||||
PLAY = false;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
encoder_handler.update();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue