Fuck it, we're doing pointers for everything!
This commit is contained in:
@ -111,4 +111,3 @@ void UpdateDisplay() {
|
|||||||
gravity.display.display();
|
gravity.display.display();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -33,8 +33,11 @@ class EncoderDir {
|
|||||||
Direction dir;
|
Direction dir;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EncoderDir() : encoder_(ENCODER_PIN1, ENCODER_PIN2, RotaryEncoder::LatchMode::FOUR3),
|
EncoderDir() {
|
||||||
button_(ENCODER_SW_PIN) {}
|
encoder_ = new RotaryEncoder(ENCODER_PIN1, ENCODER_PIN2, RotaryEncoder::LatchMode::FOUR3);
|
||||||
|
button_ = new Button(ENCODER_SW_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
~EncoderDir() {}
|
~EncoderDir() {}
|
||||||
|
|
||||||
// Set to true if the encoder read direction should be reversed.
|
// Set to true if the encoder read direction should be reversed.
|
||||||
@ -55,15 +58,15 @@ class EncoderDir {
|
|||||||
|
|
||||||
// Parse EncoderButton increment direction.
|
// Parse EncoderButton increment direction.
|
||||||
Direction RotateDirection() {
|
Direction RotateDirection() {
|
||||||
int dir = (int)(encoder_.getDirection());
|
int dir = (int)(encoder_->getDirection());
|
||||||
return rotate_(dir, reversed_);
|
return rotate_(dir, reversed_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process() {
|
void Process() {
|
||||||
// Get encoder position change amount.
|
// Get encoder position change amount.
|
||||||
int encoder_rotated = _rotate_change() != 0;
|
int encoder_rotated = _rotate_change() != 0;
|
||||||
bool button_pressed = button_.On();
|
bool button_pressed = button_->On();
|
||||||
button_.Process();
|
button_->Process();
|
||||||
|
|
||||||
// Handle encoder position change and button press.
|
// Handle encoder position change and button press.
|
||||||
if (button_pressed && encoder_rotated) {
|
if (button_pressed && encoder_rotated) {
|
||||||
@ -71,32 +74,32 @@ class EncoderDir {
|
|||||||
if (on_press_rotate != NULL) on_press_rotate(dir, change);
|
if (on_press_rotate != NULL) on_press_rotate(dir, change);
|
||||||
} else if (!button_pressed && encoder_rotated) {
|
} else if (!button_pressed && encoder_rotated) {
|
||||||
if (on_rotate != NULL) on_rotate(dir, change);
|
if (on_rotate != NULL) on_rotate(dir, change);
|
||||||
} else if (button_.Change() == Button::CHANGE_RELEASED && !rotated_while_held_) {
|
} else if (button_->Change() == Button::CHANGE_RELEASED && !rotated_while_held_) {
|
||||||
if (on_press != NULL) on_press();
|
if (on_press != NULL) on_press();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset rotate while held state.
|
// Reset rotate while held state.
|
||||||
if (button_.Change() == Button::CHANGE_RELEASED && rotated_while_held_) {
|
if (button_->Change() == Button::CHANGE_RELEASED && rotated_while_held_) {
|
||||||
rotated_while_held_ = false;
|
rotated_while_held_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the encoder state and update the read position.
|
// Read the encoder state and update the read position.
|
||||||
void UpdateEncoder() {
|
void UpdateEncoder() {
|
||||||
encoder_.tick();
|
encoder_->tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int previous_pos_;
|
int previous_pos_;
|
||||||
bool rotated_while_held_;
|
bool rotated_while_held_;
|
||||||
bool reversed_ = true;
|
bool reversed_ = true;
|
||||||
RotaryEncoder encoder_;
|
RotaryEncoder * encoder_ = nullptr;
|
||||||
Button button_;
|
Button * button_ = nullptr;
|
||||||
|
|
||||||
// Return the number of ticks change since last polled.
|
// Return the number of ticks change since last polled.
|
||||||
int _rotate_change() {
|
int _rotate_change() {
|
||||||
int position = encoder_.getPosition();
|
int position = encoder_->getPosition();
|
||||||
unsigned long ms = encoder_.getMillisBetweenRotations();
|
unsigned long ms = encoder_->getMillisBetweenRotations();
|
||||||
|
|
||||||
// Validation (TODO: add debounce check).
|
// Validation (TODO: add debounce check).
|
||||||
if (previous_pos_ == position) {
|
if (previous_pos_ == position) {
|
||||||
|
|||||||
@ -61,16 +61,16 @@ void setup() {
|
|||||||
gravity.Init();
|
gravity.Init();
|
||||||
|
|
||||||
// Clock handlers.
|
// Clock handlers.
|
||||||
gravity.clock.AttachExtHandler(ExtClock);
|
gravity.clock->AttachExtHandler(ExtClock);
|
||||||
gravity.clock.AttachIntHandler(IntClock);
|
gravity.clock->AttachIntHandler(IntClock);
|
||||||
|
|
||||||
// Encoder rotate and press handlers.
|
// Encoder rotate and press handlers.
|
||||||
gravity.encoder.AttachPressHandler(HandleEncoderPressed);
|
gravity.encoder->AttachPressHandler(HandleEncoderPressed);
|
||||||
gravity.encoder.AttachRotateHandler(HandleRotate);
|
gravity.encoder->AttachRotateHandler(HandleRotate);
|
||||||
gravity.encoder.AttachPressRotateHandler(HandlePressedRotate);
|
gravity.encoder->AttachPressRotateHandler(HandlePressedRotate);
|
||||||
|
|
||||||
// Button press handlers.
|
// Button press handlers.
|
||||||
gravity.play_button.AttachPressHandler(HandlePlayPressed);
|
gravity.play_button->AttachPressHandler(HandlePlayPressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
@ -88,8 +88,8 @@ void loop() {
|
|||||||
//
|
//
|
||||||
|
|
||||||
void ExtClock() {
|
void ExtClock() {
|
||||||
if (gravity.clock.ExternalSource()) {
|
if (gravity.clock->ExternalSource()) {
|
||||||
gravity.clock.Tick();
|
gravity.clock->Tick();
|
||||||
app.refresh_screen = true;
|
app.refresh_screen = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ void IntClock(uint32_t tick) {
|
|||||||
for (int i = 0; i < OUTPUT_COUNT; i++) {
|
for (int i = 0; i < OUTPUT_COUNT; i++) {
|
||||||
const auto& channel = app.channel[i];
|
const auto& channel = app.channel[i];
|
||||||
auto& output = gravity.outputs[i];
|
auto& output = gravity.outputs[i];
|
||||||
|
|
||||||
const uint32_t mod_pulses = clock_mod_pulses[channel.clock_mod_index];
|
const uint32_t mod_pulses = clock_mod_pulses[channel.clock_mod_index];
|
||||||
const uint32_t current_tick_offset = tick + channel.offset_pulses;
|
const uint32_t current_tick_offset = tick + channel.offset_pulses;
|
||||||
|
|
||||||
@ -119,8 +119,8 @@ void IntClock(uint32_t tick) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandlePlayPressed() {
|
void HandlePlayPressed() {
|
||||||
gravity.clock.Pause();
|
gravity.clock->Pause();
|
||||||
if (gravity.clock.IsPaused()) {
|
if (gravity.clock->IsPaused()) {
|
||||||
for (int i = 0; i < OUTPUT_COUNT; i++) {
|
for (int i = 0; i < OUTPUT_COUNT; i++) {
|
||||||
gravity.outputs[i].Low();
|
gravity.outputs[i].Low();
|
||||||
}
|
}
|
||||||
@ -149,21 +149,21 @@ void HandleRotate(Direction dir, int val) {
|
|||||||
if (app.selected_channel == 0) {
|
if (app.selected_channel == 0) {
|
||||||
switch (app.selected_param) {
|
switch (app.selected_param) {
|
||||||
case 0:
|
case 0:
|
||||||
if (gravity.clock.ExternalSource()) {
|
if (gravity.clock->ExternalSource()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gravity.clock.SetTempo(gravity.clock.Tempo() + val);
|
gravity.clock->SetTempo(gravity.clock->Tempo() + val);
|
||||||
app.refresh_screen = true;
|
app.refresh_screen = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
if (static_cast<Source>(app.selected_source) == 0 && val < 0) {
|
if (static_cast<Source>(app.selected_source) == 0 && val < 0) {
|
||||||
app.selected_source = static_cast<Source>(SOURCE_LAST - 1);
|
app.selected_source = static_cast<Source>(SOURCE_LAST - 1);
|
||||||
} else {
|
} else {
|
||||||
app.selected_source = static_cast<Source>((app.selected_source + val) % SOURCE_LAST);
|
app.selected_source = static_cast<Source>((app.selected_source + val) % SOURCE_LAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
gravity.clock.SetSource(app.selected_source);
|
gravity.clock->SetSource(app.selected_source);
|
||||||
app.refresh_screen = true;
|
app.refresh_screen = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ Channel& GetSelectedChannel() {
|
|||||||
|
|
||||||
void UpdateDisplay() {
|
void UpdateDisplay() {
|
||||||
app.refresh_screen = false;
|
app.refresh_screen = false;
|
||||||
gravity.display.clearDisplay();
|
gravity.display->clearDisplay();
|
||||||
|
|
||||||
if (app.selected_channel == 0) {
|
if (app.selected_channel == 0) {
|
||||||
DisplayMainPage();
|
DisplayMainPage();
|
||||||
@ -231,83 +231,82 @@ void UpdateDisplay() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Show selected param indicator
|
// Show selected param indicator
|
||||||
gravity.display.drawChar(0, app.selected_param * 10, 0x10, 1, 0, 1);
|
gravity.display->drawChar(0, app.selected_param * 10, 0x10, 1, 0, 1);
|
||||||
|
|
||||||
// Global channel select UI.
|
// Global channel select UI.
|
||||||
DisplaySelectedChannel();
|
DisplaySelectedChannel();
|
||||||
|
|
||||||
gravity.display.display();
|
gravity.display->display();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplaySelectedChannel() {
|
void DisplaySelectedChannel() {
|
||||||
gravity.display.drawLine(1, 52, 126, 52, 1);
|
gravity.display->drawLine(1, 52, 126, 52, 1);
|
||||||
for (int i = 0; i < 7; i++) {
|
for (int i = 0; i < 7; i++) {
|
||||||
(app.selected_channel == i)
|
(app.selected_channel == i)
|
||||||
? gravity.display.fillRect(i * 18, 52, 18, 12, 1)
|
? gravity.display->fillRect(i * 18, 52, 18, 12, 1)
|
||||||
: gravity.display.drawLine(i * 18, 52, i * 18, 64, 1);
|
: gravity.display->drawLine(i * 18, 52, i * 18, 64, 1);
|
||||||
|
|
||||||
int selected = app.selected_channel == i;
|
int selected = app.selected_channel == i;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
char icon = gravity.clock.IsPaused() ? CHAR_PAUSE : CHAR_PLAY;
|
char icon = gravity.clock->IsPaused() ? CHAR_PAUSE : CHAR_PLAY;
|
||||||
gravity.display.drawChar((i * 18) + 7, 55, icon, !selected, selected, 1);
|
gravity.display->drawChar((i * 18) + 7, 55, icon, !selected, selected, 1);
|
||||||
} else {
|
} else {
|
||||||
gravity.display.drawChar((i * 18) + 7, 55, i + 48, !selected, selected, 1);
|
gravity.display->drawChar((i * 18) + 7, 55, i + 48, !selected, selected, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gravity.display.drawLine(126, 52, 126, 64, 1);
|
gravity.display->drawLine(126, 52, 126, 64, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayMainPage() {
|
void DisplayMainPage() {
|
||||||
gravity.display.setCursor(10, 0);
|
gravity.display->setCursor(10, 0);
|
||||||
gravity.display.print(F("Tempo: "));
|
gravity.display->print(F("Tempo: "));
|
||||||
gravity.display.print(gravity.clock.Tempo());
|
gravity.display->print(gravity.clock->Tempo());
|
||||||
|
|
||||||
gravity.display.setCursor(10, 10);
|
gravity.display->setCursor(10, 10);
|
||||||
gravity.display.print(F("Source: "));
|
gravity.display->print(F("Source: "));
|
||||||
switch (app.selected_source)
|
switch (app.selected_source) {
|
||||||
{
|
case SOURCE_INTERNAL:
|
||||||
case SOURCE_INTERNAL:
|
gravity.display->print(F("INT"));
|
||||||
gravity.display.print(F("INT"));
|
break;
|
||||||
break;
|
case SOURCE_EXTERNAL_PPQN_24:
|
||||||
case SOURCE_EXTERNAL_PPQN_24:
|
gravity.display->print(F("EXT 24 PPQN"));
|
||||||
gravity.display.print(F("EXT 24 PPQN"));
|
break;
|
||||||
break;
|
case SOURCE_EXTERNAL_PPQN_4:
|
||||||
case SOURCE_EXTERNAL_PPQN_4:
|
gravity.display->print(F("EXT 4 PPQN"));
|
||||||
gravity.display.print(F("EXT 4 PPQN"));
|
break;
|
||||||
break;
|
// case SOURCE_EXTERNAL_MIDI:
|
||||||
// case SOURCE_EXTERNAL_MIDI:
|
// gravity.display->print(F("EXT MIDI"));
|
||||||
// gravity.display.print(F("EXT MIDI"));
|
// break;
|
||||||
// break;
|
default:
|
||||||
default:
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayChannelPage() {
|
void DisplayChannelPage() {
|
||||||
auto& ch = GetSelectedChannel();
|
auto& ch = GetSelectedChannel();
|
||||||
|
|
||||||
gravity.display.setCursor(10, 0);
|
gravity.display->setCursor(10, 0);
|
||||||
gravity.display.print(F("Mod: "));
|
gravity.display->print(F("Mod: "));
|
||||||
if (clock_mod[ch.clock_mod_index] > 1) {
|
if (clock_mod[ch.clock_mod_index] > 1) {
|
||||||
gravity.display.print(F("/ "));
|
gravity.display->print(F("/ "));
|
||||||
gravity.display.print(clock_mod[ch.clock_mod_index]);
|
gravity.display->print(clock_mod[ch.clock_mod_index]);
|
||||||
} else {
|
} else {
|
||||||
gravity.display.print(F("X "));
|
gravity.display->print(F("X "));
|
||||||
gravity.display.print(abs(clock_mod[ch.clock_mod_index]));
|
gravity.display->print(abs(clock_mod[ch.clock_mod_index]));
|
||||||
}
|
}
|
||||||
|
|
||||||
gravity.display.setCursor(10, 10);
|
gravity.display->setCursor(10, 10);
|
||||||
gravity.display.print(F("Probability: "));
|
gravity.display->print(F("Probability: "));
|
||||||
gravity.display.print(ch.probability);
|
gravity.display->print(ch.probability);
|
||||||
gravity.display.print(F("%"));
|
gravity.display->print(F("%"));
|
||||||
|
|
||||||
gravity.display.setCursor(10, 20);
|
gravity.display->setCursor(10, 20);
|
||||||
gravity.display.print(F("Duty Cycle: "));
|
gravity.display->print(F("Duty Cycle: "));
|
||||||
gravity.display.print(ch.duty_cycle);
|
gravity.display->print(ch.duty_cycle);
|
||||||
gravity.display.print(F("%"));
|
gravity.display->print(F("%"));
|
||||||
|
|
||||||
gravity.display.setCursor(10, 30);
|
gravity.display->setCursor(10, 30);
|
||||||
gravity.display.print(F("Offset: "));
|
gravity.display->print(F("Offset: "));
|
||||||
gravity.display.print(ch.offset);
|
gravity.display->print(ch.offset);
|
||||||
gravity.display.print(F("%"));
|
gravity.display->print(F("%"));
|
||||||
}
|
}
|
||||||
43
gravity.cpp
43
gravity.cpp
@ -19,15 +19,22 @@ void Gravity::Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Gravity::InitClock() {
|
void Gravity::InitClock() {
|
||||||
clock.Init();
|
clock = new Clock();
|
||||||
|
clock->Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gravity::InitInputs() {
|
void Gravity::InitInputs() {
|
||||||
shift_button.Init(SHIFT_BTN_PIN);
|
shift_button = new Button();
|
||||||
play_button.Init(PLAY_BTN_PIN);
|
play_button = new Button();
|
||||||
|
shift_button->Init(SHIFT_BTN_PIN);
|
||||||
|
play_button->Init(PLAY_BTN_PIN);
|
||||||
|
|
||||||
cv1.Init(CV1_PIN);
|
cv1 = new AnalogInput();
|
||||||
cv2.Init(CV2_PIN);
|
cv2 = new AnalogInput();
|
||||||
|
cv1->Init(CV1_PIN);
|
||||||
|
cv2->Init(CV2_PIN);
|
||||||
|
|
||||||
|
encoder = new EncoderDir();
|
||||||
|
|
||||||
// Pin Change Interrupts for Encoder.
|
// Pin Change Interrupts for Encoder.
|
||||||
// Thanks to https://dronebotworkshop.com/interrupts/
|
// Thanks to https://dronebotworkshop.com/interrupts/
|
||||||
@ -50,23 +57,25 @@ void Gravity::InitOutputs() {
|
|||||||
outputs[5].Init(OUT_CH6);
|
outputs[5].Init(OUT_CH6);
|
||||||
}
|
}
|
||||||
void Gravity::InitDisplay() {
|
void Gravity::InitDisplay() {
|
||||||
|
display = new Adafruit_SSD1306(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||||
|
|
||||||
// OLED Display configuration.
|
// OLED Display configuration.
|
||||||
display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS);
|
display->begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS);
|
||||||
delay(1000);
|
delay(1000);
|
||||||
display.setRotation(2); // rotates text on OLED 1=90 degrees, 2=180 degrees
|
display->setRotation(2); // rotates text on OLED 1=90 degrees, 2=180 degrees
|
||||||
display.clearDisplay();
|
display->clearDisplay();
|
||||||
display.setTextSize(1);
|
display->setTextSize(1);
|
||||||
display.setTextColor(WHITE);
|
display->setTextColor(WHITE);
|
||||||
display.display();
|
display->display();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gravity::Process() {
|
void Gravity::Process() {
|
||||||
// Read peripherials for changes.
|
// Read peripherials for changes.
|
||||||
shift_button.Process();
|
shift_button->Process();
|
||||||
play_button.Process();
|
play_button->Process();
|
||||||
encoder.Process();
|
encoder->Process();
|
||||||
cv1.Process();
|
cv1->Process();
|
||||||
cv2.Process();
|
cv2->Process();
|
||||||
|
|
||||||
// Update Output states.
|
// Update Output states.
|
||||||
for (int i; i < OUTPUT_COUNT; i++) {
|
for (int i; i < OUTPUT_COUNT; i++) {
|
||||||
@ -75,7 +84,7 @@ void Gravity::Process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ReadEncoder() {
|
void ReadEncoder() {
|
||||||
gravity.encoder.UpdateEncoder();
|
gravity.encoder->UpdateEncoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define Encoder pin ISR.
|
// Define Encoder pin ISR.
|
||||||
|
|||||||
17
gravity.h
17
gravity.h
@ -16,8 +16,7 @@
|
|||||||
class Gravity {
|
class Gravity {
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
Gravity()
|
Gravity() {}
|
||||||
: display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1) {}
|
|
||||||
|
|
||||||
// Deconstructor
|
// Deconstructor
|
||||||
~Gravity() {}
|
~Gravity() {}
|
||||||
@ -28,14 +27,14 @@ class Gravity {
|
|||||||
// Polling check for state change of inputs and outputs.
|
// Polling check for state change of inputs and outputs.
|
||||||
void Process();
|
void Process();
|
||||||
|
|
||||||
Adafruit_SSD1306 display; // OLED display object.
|
Adafruit_SSD1306 * display = nullptr; // OLED display object.
|
||||||
Clock clock; // Clock source wrapper.
|
Clock * clock = nullptr; // Clock source wrapper.
|
||||||
DigitalOutput outputs[OUTPUT_COUNT]; // An array containing each Output object.
|
DigitalOutput outputs[OUTPUT_COUNT]; // An array containing each Output object.
|
||||||
EncoderDir encoder; // Rotary encoder with button instance
|
EncoderDir * encoder = nullptr; // Rotary encoder with button instance
|
||||||
Button shift_button;
|
Button * shift_button = nullptr;
|
||||||
Button play_button;
|
Button * play_button = nullptr;
|
||||||
AnalogInput cv1;
|
AnalogInput * cv1 = nullptr;
|
||||||
AnalogInput cv2;
|
AnalogInput * cv2 = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitClock();
|
void InitClock();
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
#define OLED_ADDRESS 0x3C
|
#define OLED_ADDRESS 0x3C
|
||||||
#define SCREEN_WIDTH 128
|
#define SCREEN_WIDTH 128
|
||||||
#define SCREEN_HEIGHT 64
|
#define SCREEN_HEIGHT 64
|
||||||
|
#define OLED_RESET -1
|
||||||
|
|
||||||
// Peripheral input pins
|
// Peripheral input pins
|
||||||
#define ENCODER_PIN1 17 // A3
|
#define ENCODER_PIN1 17 // A3
|
||||||
|
|||||||
Reference in New Issue
Block a user