diff --git a/MicroDexed.ino b/MicroDexed.ino index 6e61fe0..7b0c259 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -29,6 +29,7 @@ #include #include #include +#include #include "midi_devices.hpp" #include "dexed.h" #include "dexed_sd.h" @@ -42,6 +43,9 @@ #include "UI.hpp" #include "source_microdexed.h" +// Motherboard +NervousSuperMother * device = NervousSuperMother::getInstance(); + // Audio engines AudioSourceMicroDexed* MicroDexed[NUM_DEXED]; #if defined(USE_FX) @@ -535,6 +539,25 @@ void setup() #endif LCDML.OTHER_jumpToFunc(UI_func_voice_select); + + // Configure the ADCs + analogReadResolution(7); + analogReadAveraging(4); + analogReference(EXTERNAL); + // Init device NervousSuperMother + byte controls[3] = {0,1,4}; + device->init(controls); + + // Set the handlers + for (int i=0;isetHandlePotentiometerChange(i, onPotentiometer); + } + device->setHandleTrigger(0, onTrigger); + device->setHandleTrigger(1, onTrigger); + device->setHandleTrigger(2, onTrigger); + device->setHandleTrigger(3, onTrigger); + device->setHandleTrigger(4, onTrigger); + device->setHandleTrigger(5, onTrigger); } void loop() @@ -542,6 +565,9 @@ void loop() // MIDI input handling check_midi_devices(); + // Update Motherboard + device->update(); + // check encoder ENCODER[ENC_L].update(); ENCODER[ENC_R].update(); @@ -629,6 +655,23 @@ void loop() #endif } +void onPotentiometer(byte inputIndex, unsigned int value, int diffToPrevious) { + Serial.print("Potentiometer "); + Serial.print(inputIndex); + Serial.print(" : "); + Serial.print(value); + Serial.print(" previous was "); + Serial.println(diffToPrevious); + // String line = "Potard " + String(inputIndex) + " : " + String(value); + // device->updateLine(1, line); + handleControlChange(1, inputIndex, value); +} + +void onTrigger(byte inputIndex) { + Serial.print("Trigger ! : "); + Serial.println(inputIndex); +} + /****************************************************************************** MIDI MESSAGE HANDLER ******************************************************************************/ diff --git a/UI.hpp b/UI.hpp index 56dfcb9..2d44a22 100644 --- a/UI.hpp +++ b/UI.hpp @@ -110,8 +110,11 @@ uint8_t instance_num[8][8]; const char accepted_chars[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-abcdefghijklmnopqrstuvwxyz"; #ifdef I2C_DISPLAY -#include -Disp_Plus lcd(LCD_I2C_ADDRESS, _LCDML_DISP_cols, _LCDML_DISP_rows); +// #include +#include +Disp_Plus lcd(DISPLAY_RS, DISPLAY_RW, DISPLAY_E, DISPLAY_DB4, DISPLAY_DB5, DISPLAY_DB6, DISPLAY_DB7); +//#include +//Disp_Plus lcd(DISPLAY_RS, DISPLAY_RW, DISPLAY_E, DISPLAY_DB4, DISPLAY_DB5, DISPLAY_DB6, DISPLAY_DB7); #endif #ifdef U8X8_DISPLAY @@ -436,8 +439,9 @@ void setup_ui(void) { // LCD Begin #ifdef I2C_DISPLAY - lcd.init(); - lcd.backlight(); + lcd.begin(20, 2); + // lcd.init(); + // lcd.backlight(); lcd.clear(); lcd.noCursor(); #else diff --git a/config.h b/config.h index 02a42b9..71c5f84 100644 --- a/config.h +++ b/config.h @@ -67,17 +67,17 @@ //* MIDI HARDWARE SETTINGS //************************************************************************************************* #define MIDI_DEVICE_DIN Serial1 -#define MIDI_DEVICE_USB 1 -#define MIDI_DEVICE_USB_HOST 1 +// #define MIDI_DEVICE_USB 1 +// #define MIDI_DEVICE_USB_HOST 1 //************************************************************************************************* //* AUDIO HARDWARE SETTINGS //************************************************************************************************* // If nothing is defined Teensy internal DAC is used as audio output device! // Left and right channel audio signal is presented on pins A21 and A22. -#define AUDIO_DEVICE_USB -#define TEENSY_AUDIO_BOARD -//#define PT8211_AUDIO +// #define AUDIO_DEVICE_USB +// #define TEENSY_AUDIO_BOARD +#define PT8211_AUDIO //#define TGA_AUDIO_BOARD //#define TEENSY_DAC //#define TEENSY_DAC_SYMMETRIC @@ -108,7 +108,7 @@ // FX-CHAIN ENABLE/DISABLE #define USE_FX 1 // CHORUS parameters -#define MOD_DELAY_SAMPLE_BUFFER int32_t(TIME_MS2SAMPLES(20.0)) // 20.0 ms delay buffer. +#define MOD_DELAY_SAMPLE_BUFFER int32_t(TIME_MS2SAMPLES(20.0)) // 20.0 ms delay buffer. #define MOD_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE #define MOD_FILTER_OUTPUT MOD_BUTTERWORTH_FILTER_OUTPUT // MOD_LINKWITZ_RILEY_FILTER_OUTPUT MOD_BUTTERWORTH_FILTER_OUTPUT MOD_NO_FILTER_OUTPUT #define MOD_FILTER_CUTOFF_HZ 2000 @@ -182,7 +182,7 @@ #define LCD_I2C_ADDRESS 0x27 //#define LCD_I2C_ADDRESS 0x3f //Display size, must be set for U8X8 as well -#define LCD_cols 16 +#define LCD_cols 20 #define LCD_rows 2 #define I2C_DISPLAY // [I2C] SCL: Pin 19, SDA: Pin 18 (https://www.pjrc.com/teensy/td_libs_Wire.html) @@ -234,9 +234,9 @@ #define ENC_L_PIN_B 2 #define BUT_L_PIN 4 #if defined(ARDUINO_TEENSY36) -#define ENC_R_PIN_A 28 -#define ENC_R_PIN_B 29 -#define BUT_R_PIN 30 +#define ENC_R_PIN_A 6 +#define ENC_R_PIN_B 5 +#define BUT_R_PIN 7 #else #if defined(ARDUINO_TEENSY40) #define ENC_R_PIN_A 6 diff --git a/midi_devices.hpp b/midi_devices.hpp index 37024eb..70c2d49 100644 --- a/midi_devices.hpp +++ b/midi_devices.hpp @@ -1725,16 +1725,29 @@ void send_sysex_voice(uint8_t midi_channel, uint8_t* data) vd[160] = checksum & 0x7f; // Checksum //vd[162] = 0xF7; // SysEx end - midi_serial.sendSysEx(161, vd); // Send to DIN MIDI - midi_usb.sendSysEx(161, vd); // Send to USB MIDI - usbMIDI.sendSysEx(161, vd); // Send to USB-HOST MIDI + #ifdef MIDI_DEVICE_DIN + midi_serial.sendSysEx(161, vd); // Send to DIN MIDI + #endif + #ifdef MIDI_DEVICE_USB + usbMIDI.sendSysEx(161, vd); // Send to USB-HOST MIDI + #endif + #ifdef MIDI_DEVICE_USB_HOST + midi_usb.sendSysEx(161, vd); // Send to USB MIDI + #endif + } void send_sysex_bank(uint8_t midi_channel, uint8_t* bank_data) { - midi_serial.sendSysEx(4104, bank_data); // Send to DIN MIDI - midi_usb.sendSysEx(4104, bank_data); // Send to USB MIDI - usbMIDI.sendSysEx(4104, bank_data); // Send to USB-HOST MIDI + #ifdef MIDI_DEVICE_DIN + midi_serial.sendSysEx(4104, bank_data); // Send to DIN MIDI + #endif + #ifdef MIDI_DEVICE_USB + usbMIDI.sendSysEx(4104, bank_data); // Send to USB-HOST MIDI + #endif + #ifdef MIDI_DEVICE_USB_HOST + midi_usb.sendSysEx(4104, bank_data); // Send to USB MIDI + #endif } void send_sysex_param(uint8_t midi_channel, uint8_t var, uint8_t val, uint8_t param_group) @@ -1755,9 +1768,15 @@ void send_sysex_param(uint8_t midi_channel, uint8_t var, uint8_t val, uint8_t pa } s[4] = val & 0x7f; - midi_serial.sendSysEx(5, s); // Send to DIN MIDI - midi_usb.sendSysEx(5, s); // Send to USB MIDI - usbMIDI.sendSysEx(5, s); // Send to USB-HOST MIDI + #ifdef MIDI_DEVICE_DIN + midi_serial.sendSysEx(5, s); // Send to DIN MIDI + #endif + #ifdef MIDI_DEVICE_USB + usbMIDI.sendSysEx(5, s); // Send to USB-HOST MIDI + #endif + #ifdef MIDI_DEVICE_USB_HOST + midi_usb.sendSysEx(5, s); // Send to USB MIDI + #endif } #endif // MIDI_DEVICES_H diff --git a/third-party/NervousSuperMother/NervousSuperMother.h b/third-party/NervousSuperMother/NervousSuperMother.h new file mode 100644 index 0000000..6cd1422 --- /dev/null +++ b/third-party/NervousSuperMother/NervousSuperMother.h @@ -0,0 +1,539 @@ +#ifndef NervousSuperMother_h +#define NervousSuperMother_h + +#include "hardware/HardwareControls.h" +// #include "display/Display.h" + +/* +* NervousSuperMother +* v0.1.0 beta +*/ +class NervousSuperMother{ + +private: + static NervousSuperMother *instance; + NervousSuperMother(); + + byte *inputs; + + byte ioNumber = 6; + byte currentInput = 0; + + byte analogResolution = 7; + + // Potentiometers + unsigned int *potentiometers; + unsigned int *potentiometersPrevious; + byte potardIndex; + // For smoothing purposes + unsigned int *potentiometersTemp; + byte *potentiometersReadings; + // Buttons + bool *buttons; + byte buttonIndex; + bool *pushed; + // Encoders + long *encoders; + long *encodersPrevious; + byte encoderIndex; + long *encodersMaxValue; + // Triggers + byte triggerIndex; + + // Display + String display_line_1; + String display_line_2; + String previous_display_line_1; + String previous_display_line_2; + + // Callbacks + using PressCallback = void (*)(byte); + PressCallback *inputsPressCallback; + using LongPressCallback = void (*)(byte); + LongPressCallback *inputsLongPressCallback; + using DoublePressCallback = void (*)(byte); + DoublePressCallback *inputsDoublePressCallback; + elapsedMillis *inputsPressTime; + using PotentiometerChangeCallback = void (*)(byte, unsigned int, int); + PotentiometerChangeCallback *inputsPotentiometerChangeCallback; + using EncoderChangeCallback = void (*)(byte, long); + EncoderChangeCallback *inputsEncoderChangeCallback; + using TriggerCallback = void (*)(byte); + TriggerCallback *inputsTriggerCallback; + + + void readPotentiometer(byte inputIndex); + void readButton(byte inputIndex); + void readEncoder(byte inputIndex); + void readTrigger(byte inputIndex); + void refreshDisplay(); + + // Main clock + elapsedMicros clockMain; + const unsigned int intervalClockMain = 10000; + + // Inputs clock + const unsigned int intervalInputs = 500; + elapsedMicros clockInputs; + +public: + static NervousSuperMother *getInstance(); + void init(byte *inputs); + void update(); + int getInput(byte index); + int getAnalogMaxValue(); + int getAnalogMinValue(); + void iterateInputs(); + void readCurrentInput(); + void updateEncodeursMaxValue(byte index, long encoderMax); + void updateEncodeursValue(byte inputIndex, long encoderValue); + // void updateLine(byte line_nb, String line); + + // Callbacks + void setHandlePress(byte inputIndex, PressCallback fptr); + void setHandleLongPress(byte inputIndex, LongPressCallback fptr); + void setHandleDoublePress(byte inputIndex, DoublePressCallback fptr); + void setHandlePotentiometerChange(byte inputIndex, PotentiometerChangeCallback fptr); + void setHandleEncoderChange(byte inputIndex, EncoderChangeCallback fptr); + void setHandleTrigger(byte inputIndex, TriggerCallback fptr); +}; + +// Instance pre init +NervousSuperMother * NervousSuperMother::instance = nullptr; + +/** +* Constructor +*/ +inline NervousSuperMother::NervousSuperMother(){ + this->inputs = new byte[this->ioNumber]; + for(byte i = 0; i < this->ioNumber; i++){ + this->inputs[i] = 0; + } + + // Potentiometers + this->potardIndex = 0; + this->potentiometers = new unsigned int[ANALOG_CONTROL_PINS]; + this->potentiometersPrevious = new unsigned int[ANALOG_CONTROL_PINS]; + this->potentiometersTemp = new unsigned int[ANALOG_CONTROL_PINS]; + this->potentiometersReadings = new byte[ANALOG_CONTROL_PINS]; + this->inputsPotentiometerChangeCallback = new PotentiometerChangeCallback[ANALOG_CONTROL_PINS]; + + for(byte i = 0; i < ANALOG_CONTROL_PINS; i++){ + this->potentiometers[i] = 0; + this->potentiometersPrevious[i] = 0; + this->potentiometersTemp[i] = 0; + this->potentiometersReadings[i] = 0; + this->inputsPotentiometerChangeCallback[i] = nullptr; + } + + // Buttons + this->buttonIndex = 0; + this->buttons = new bool[BUTTON_PINS]; + this->pushed = new bool[BUTTON_PINS]; + this->inputsPressCallback = new PressCallback[BUTTON_PINS]; + this->inputsLongPressCallback = new DoublePressCallback[BUTTON_PINS]; + this->inputsDoublePressCallback = new LongPressCallback[BUTTON_PINS]; + this->inputsPressTime = new elapsedMillis[BUTTON_PINS]; + + for(byte i = 0; i < BUTTON_PINS; i++){ + this->buttons[i] = true; + this->pushed[i] = false; + this->inputsPressCallback[i] = nullptr; + this->inputsLongPressCallback[i] = nullptr; + this->inputsDoublePressCallback[i] = nullptr; + this->inputsPressTime[i] = 0; + } + + // Encoders + this->encoderIndex = 0; + this->encoders = new long[NB_ENCODER]; + this->encodersPrevious = new long[NB_ENCODER]; + this->inputsEncoderChangeCallback = new EncoderChangeCallback[NB_ENCODER]; + this->encodersMaxValue = new long[NB_ENCODER]; + + for(byte i = 0; i < NB_ENCODER; i++){ + this->encoders[i] = 0; + this->encodersPrevious[i] = -999; + this->inputsEncoderChangeCallback[i] = nullptr; + this->encodersMaxValue[i] = 0; + } + + // Triggers + this->triggerIndex = 0; + this->inputsTriggerCallback = new TriggerCallback[TRIGGER_PINS]; + for(byte i = 0; i < TRIGGER_PINS; i++){ + this->inputsTriggerCallback[i] = nullptr; + } + + // // Display + // this->display_line_1 = ""; + // this->display_line_2 = ""; + // this->previous_display_line_1 = ""; + // this->previous_display_line_2 = ""; +} + +/** +* Singleton instance +*/ +inline NervousSuperMother *NervousSuperMother::getInstance() { + if (!instance) + instance = new NervousSuperMother; + return instance; +} + +/** +* Init +*/ +inline void NervousSuperMother::init(byte *inputs){ + for(byte i = 0; i < this->ioNumber; i++){ + this->inputs[i] = inputs[i]; + } + setup_hardware_controls(); + // setup_lcd(); +} + +/** +* Update +*/ +inline void NervousSuperMother::update(){ + // Main clock + if (this->clockMain >= this->intervalClockMain) { + this->clockMain = 0; + } + if (this->clockMain > this->intervalClockMain / 2) { + return; + }else{ + // AudioNoInterrupts(); + // Inputs + // At the end of the clock we iterate to next input + if (this->clockInputs >= this->intervalInputs) { + this->iterateInputs(); + this->clockInputs = 0; + }else{ + // Reading the current input + this->readCurrentInput(); + } + // AudioInterrupts(); + } +} + +/** +* Iterate over the inputs +*/ +inline void NervousSuperMother::iterateInputs(){ + this->currentInput++; + this->currentInput = this->currentInput % this->ioNumber; +} + +/** +* Read value of current inout +*/ +inline void NervousSuperMother::readCurrentInput(){ + switch(this->inputs[this->currentInput]){ + default: + case 0: + // Silence is golden + break; + + case 1: + if(this->potardIndex < ANALOG_CONTROL_PINS) { + this->readPotentiometer(this->potardIndex); + this->potardIndex ++; + } else { + this->potardIndex = 0; + } + break; + case 2: + if(this->buttonIndex < BUTTON_PINS) { + this->readButton(this->buttonIndex); + this->buttonIndex ++; + }else { + this->buttonIndex = 0; + } + break; + case 3: + if(this->encoderIndex < NB_ENCODER) { + this->readEncoder(this->encoderIndex); + this->encoderIndex ++; + }else { + this->encoderIndex = 0; + } + break; + case 4: + if(this->triggerIndex < TRIGGER_PINS) { + this->readTrigger(this->triggerIndex); + this->triggerIndex ++; + }else { + this->triggerIndex = 0; + } + break; + case 5: + // this->refreshDisplay(); + break; + } +} + +/** +* Get potentiometer value +* @param byte inputeIndex The index of the input +*/ +inline void NervousSuperMother::readPotentiometer(byte inputIndex){ + analog_controls[inputIndex].update(); + if(analog_controls[inputIndex].hasChanged()){ + this->potentiometers[inputIndex] = analog_controls[inputIndex].getValue(); + + if(this->potentiometers[inputIndex] != this->potentiometersPrevious[inputIndex]){ + // Calling the potentiometer callback if there is one + if(this->inputsPotentiometerChangeCallback[inputIndex] != nullptr){ + this->inputsPotentiometerChangeCallback[inputIndex](inputIndex, this->potentiometers[inputIndex], this->potentiometers[inputIndex] - this->potentiometersPrevious[inputIndex] ); + } + } + this->potentiometersPrevious[inputIndex] = this->potentiometers[inputIndex]; + } + +} + +/** +* Get input value +* @param byte index The index of the input +*/ +inline int NervousSuperMother::getInput(byte index){ + switch(this->inputs[index]){ + default: + case 0: + // Empty + return 0; + break; + case 1: + // Buttons + return !this->buttons[index]; + break; + case 2: + // Potentiometer + return this->potentiometers[index]; + break; + case 3: + // Encoder + // Device is not saving the encoders values, only the latest change + // int value = this->encoders[index]; + // this->encoders[index] = 0; + // return value; + break; + } +} + +/** +* Get max analog value according to resolution +*/ +inline int NervousSuperMother::getAnalogMinValue(){ + return 0; +} + +/** +* Get max analog value according to resolution +*/ +inline int NervousSuperMother::getAnalogMaxValue(){ + return (1 << this->analogResolution) - 1; +} + +/** +* Handle potentiometer +*/ +inline void NervousSuperMother::setHandlePotentiometerChange(byte inputIndex, PotentiometerChangeCallback fptr){ + this->inputsPotentiometerChangeCallback[inputIndex] = fptr; +} + +/** +* Get button value +* @param byte inputeIndex The index of the input +*/ +inline void NervousSuperMother::readButton(byte buttonIndex) { + // If there is a short or a long press callback on that input + if(this->inputsPressCallback[buttonIndex] != nullptr || + this->inputsDoublePressCallback[buttonIndex] != nullptr || + this->inputsLongPressCallback[buttonIndex] != nullptr) { + if(digital_button[buttonIndex].update()){ + if(digital_button[buttonIndex].fallingEdge()){ + this->pushed[buttonIndex] = true; + if(this->inputsPressTime[buttonIndex] <= 400 && this->pushed[buttonIndex]){ + if(this->inputsDoublePressCallback[buttonIndex] != nullptr){ + this->inputsDoublePressCallback[buttonIndex](buttonIndex); + } + } + this->inputsPressTime[buttonIndex] = 0; + } + + if(digital_button[buttonIndex].risingEdge()){ + if(this->inputsPressTime[buttonIndex] > 150 && this->inputsPressTime[buttonIndex] < 500){ + if(this->inputsPressCallback[buttonIndex] != nullptr){ + this->inputsPressCallback[buttonIndex](buttonIndex); + } + } + this->pushed[buttonIndex] = false; + } + }else if(this->inputsPressTime[buttonIndex] >= 800 && this->pushed[buttonIndex]){ + if(this->inputsLongPressCallback[buttonIndex] != nullptr){ + this->inputsLongPressCallback[buttonIndex](buttonIndex); + } + this->pushed[buttonIndex] = false; + } + } + } + + /** + * Handle press down on a button + */ + inline void NervousSuperMother::setHandlePress(byte inputIndex, PressCallback fptr){ + this->inputsPressCallback[inputIndex] = fptr; + } + + /** + * Handle press up on a button + */ + inline void NervousSuperMother::setHandleDoublePress(byte inputIndex, DoublePressCallback fptr){ + this->inputsDoublePressCallback[inputIndex] = fptr; + } + + /** + * Handle long press down on a button + */ + inline void NervousSuperMother::setHandleLongPress(byte inputIndex, LongPressCallback fptr){ + this->inputsLongPressCallback[inputIndex] = fptr; + } + + /** + * Get encoder value + * @param byte inputeIndex The index of the input + */ + inline void NervousSuperMother::readEncoder(byte inputIndex) { + // Get rotary encoder value + // Reverse + if(this->encodersMaxValue[inputIndex] < 0){ + this->encoders[inputIndex] = encoders_knob[inputIndex].read(); + if(this->encoders[inputIndex] < this->encodersMaxValue[inputIndex]-2){ + this->encoders[inputIndex] = 0; + encoders_knob[inputIndex].write(0); + } + if(this->encoders[inputIndex] > 2){ + this->encoders[inputIndex] = this->encodersMaxValue[inputIndex]; + encoders_knob[inputIndex].write(this->encodersMaxValue[inputIndex]); + } + if (this->encoders[inputIndex]%4 == 0 && this->encoders[inputIndex] != this->encodersPrevious[inputIndex]) { + this->encodersPrevious[inputIndex] = this->encoders[inputIndex]; + // Calling the Encoder callback if there is one + if(this->inputsEncoderChangeCallback[inputIndex] != nullptr){ + this->inputsEncoderChangeCallback[inputIndex](inputIndex, abs(this->encoders[inputIndex])/4); + } + } + // Normal + }else { + this->encoders[inputIndex] = encoders_knob[inputIndex].read(); + if(this->encoders[inputIndex] > this->encodersMaxValue[inputIndex]+2){ + this->encoders[inputIndex] = 0; + encoders_knob[inputIndex].write(0); + } + if(this->encoders[inputIndex] < -2){ + this->encoders[inputIndex] = this->encodersMaxValue[inputIndex]; + encoders_knob[inputIndex].write(this->encodersMaxValue[inputIndex]); + } + if (this->encoders[inputIndex]%4 == 0 && this->encoders[inputIndex] != this->encodersPrevious[inputIndex]) { + this->encodersPrevious[inputIndex] = this->encoders[inputIndex]; + // Calling the Encoder callback if there is one + if(this->inputsEncoderChangeCallback[inputIndex] != nullptr){ + this->inputsEncoderChangeCallback[inputIndex](inputIndex, this->encoders[inputIndex]/4); + } + } + } + } + + /** + * Handle encoder change + */ + inline void NervousSuperMother::setHandleEncoderChange(byte inputIndex, EncoderChangeCallback fptr) { + this->inputsEncoderChangeCallback[inputIndex] = fptr; + } + + /** + * Update encoders max value + */ + inline void NervousSuperMother::updateEncodeursMaxValue(byte inputIndex, long encoderMax) { + this->encodersMaxValue[inputIndex] = encoderMax*4; + } + + /** + * Update encoders value + */ + inline void NervousSuperMother::updateEncodeursValue(byte inputIndex, long encoderValue) { + encoders_knob[inputIndex].write(encoderValue*4); + } + + /** + * Get trigger + * @param byte inputeIndex The index of the input + */ + inline void NervousSuperMother::readTrigger(byte inputIndex){ + digital_trigger[inputIndex].update(); + if (digital_trigger[inputIndex].fallingEdge()) { + if(this->inputsTriggerCallback[inputIndex] != nullptr){ + this->inputsTriggerCallback[inputIndex](inputIndex); + } + } + } + + /** + * Handle trigger + */ + inline void NervousSuperMother::setHandleTrigger(byte inputIndex, TriggerCallback fptr){ + this->inputsTriggerCallback[inputIndex] = fptr; + } + + /** + * Update line to display + */ + // inline void NervousSuperMother::updateLine(byte line_nb, String line) { + // if(line_nb == 1){ + // this->display_line_1 = line; + // }else if(line_nb == 2){ + // this->display_line_2 = line; + // } + // } + + /** + * Refresh the display + */ + // inline void NervousSuperMother::refreshDisplay() { + // if(this->display_line_1 != this->previous_display_line_1 || this->display_line_2 != this->previous_display_line_2){ + // byte j = 0; + // for(byte i = 0; i < this->display_line_1.length(); i++){ + // if(this->previous_display_line_1[i] != this->display_line_1[i]){ + // lcd.setCursor(i, 0); + // lcd.print(this->display_line_1[i]); + // } + // j = i+1; + // } + // if(j < 20){ + // for(byte i = j; i < 20; i++){ + // lcd.setCursor(i, 0); + // lcd.print(" "); + // } + // } + // j = 0; + // for(byte i = 0; i < this->display_line_2.length(); i++){ + // if(this->previous_display_line_2[i] != this->display_line_2[i]){ + // lcd.setCursor(i, 1); + // lcd.print(this->display_line_2[i]); + // } + // j = i+1; + // } + // if(j < 20){ + // for(byte i = j; i < 20; i++){ + // lcd.setCursor(i, 1); + // lcd.print(" "); + // } + // } + // this->previous_display_line_1 = this->display_line_1; + // this->previous_display_line_2 = this->display_line_2; + // } + // } + + #endif diff --git a/third-party/NervousSuperMother/display/Display.h b/third-party/NervousSuperMother/display/Display.h new file mode 100644 index 0000000..d685e30 --- /dev/null +++ b/third-party/NervousSuperMother/display/Display.h @@ -0,0 +1,168 @@ +#ifndef Display_h +#define Display_h + +#include "Arduino.h" +#include + +// initialize the library with the numbers of the interface pins +// LiquidCrystal lcd(RS, RW, Enable, D4, D5, D6, D7) +LiquidCrystalFast lcd(DISPLAY_RS, DISPLAY_RW, DISPLAY_E, DISPLAY_DB4, DISPLAY_DB5, DISPLAY_DB6, DISPLAY_DB7); + +int LCD_NB_COLUMNS = 20; + +/* Caractères personnalisés */ +byte START_DIV_0_OF_1[8] = { + B01111, + B11000, + B10000, + B10000, + B10000, + B10000, + B11000, + B01111 +}; // Char début 0 / 1 + +byte START_DIV_1_OF_1[8] = { + B01111, + B11000, + B10011, + B10111, + B10111, + B10011, + B11000, + B01111 +}; // Char début 1 / 1 + +byte DIV_0_OF_2[8] = { + B11111, + B00000, + B00000, + B00000, + B00000, + B00000, + B00000, + B11111 +}; // Char milieu 0 / 2 + +byte DIV_1_OF_2[8] = { + B11111, + B00000, + B11000, + B11000, + B11000, + B11000, + B00000, + B11111 +}; // Char milieu 1 / 2 + +byte DIV_2_OF_2[8] = { + B11111, + B00000, + B11011, + B11011, + B11011, + B11011, + B00000, + B11111 +}; // Char milieu 2 / 2 + +byte END_DIV_0_OF_1[8] = { + B11110, + B00011, + B00001, + B00001, + B00001, + B00001, + B00011, + B11110 +}; // Char fin 0 / 1 + +byte END_DIV_1_OF_1[8] = { + B11110, + B00011, + B11001, + B11101, + B11101, + B11001, + B00011, + B11110 +}; // Char fin 1 / 1 + +/** + * Fonction de configuration de l'écran LCD pour la barre de progression. + * Utilise les caractères personnalisés de 0 à 6 (7 reste disponible). + */ +void setup_progressbar() { + + /* Enregistre les caractères personnalisés dans la mémoire de l'écran LCD */ + lcd.createChar(0, START_DIV_0_OF_1); + lcd.createChar(1, START_DIV_1_OF_1); + lcd.createChar(2, DIV_0_OF_2); + lcd.createChar(3, DIV_1_OF_2); + lcd.createChar(4, DIV_2_OF_2); + lcd.createChar(5, END_DIV_0_OF_1); + lcd.createChar(6, END_DIV_1_OF_1); +} + +void setup_lcd(){ + // set up the LCD's number of rows and columns: + lcd.begin(20, 2); + setup_progressbar(); +} + +/** + * Fonction dessinant la barre de progression. + * + * @param percent Le pourcentage à afficher. + */ +void draw_progressbar(byte percent) { + /* Déplace le curseur sur la seconde ligne */ + lcd.setCursor(0, 1); + + /* Map la plage (0 ~ 100) vers la plage (0 ~ LCD_NB_COLUMNS * 2 - 2) */ + byte nb_columns = map(percent, 0, 100, 0, LCD_NB_COLUMNS * 2 - 2); + // Chaque caractère affiche 2 barres verticales, mais le premier et dernier caractère n'en affiche qu'une. + + /* Dessine chaque caractère de la ligne */ + for (byte i = 0; i < LCD_NB_COLUMNS; ++i) { + + if (i == 0) { // Premiére case + + /* Affiche le char de début en fonction du nombre de colonnes */ + if (nb_columns > 0) { + lcd.write(1); // Char début 1 / 1 + nb_columns -= 1; + + } else { + lcd.write((byte) 0); // Char début 0 / 1 + } + + } else if (i == LCD_NB_COLUMNS -1) { // Derniére case + + /* Affiche le char de fin en fonction du nombre de colonnes */ + if (nb_columns > 0) { + lcd.write(6); // Char fin 1 / 1 + + } else { + lcd.write(5); // Char fin 0 / 1 + } + + } else { // Autres cases + + /* Affiche le char adéquat en fonction du nombre de colonnes */ + if (nb_columns >= 2) { + lcd.write(4); // Char div 2 / 2 + nb_columns -= 2; + + } else if (nb_columns == 1) { + lcd.write(3); // Char div 1 / 2 + nb_columns -= 1; + + } else { + lcd.write(2); // Char div 0 / 2 + } + } + } +} + +#endif diff --git a/third-party/NervousSuperMother/hardware/HardwareControls.h b/third-party/NervousSuperMother/hardware/HardwareControls.h new file mode 100644 index 0000000..4ff81ef --- /dev/null +++ b/third-party/NervousSuperMother/hardware/HardwareControls.h @@ -0,0 +1,118 @@ +#ifndef HardwareControls_h +#define HardwareControls_h + +#include "Arduino.h" +// include the ResponsiveAnalogRead library for analog smoothing +#include +// include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle +#include +// This optional setting causes Encoder to use more optimized code, +// It must be defined before Encoder.h is included. +#define ENCODER_OPTIMIZE_INTERRUPTS +#include +#include "pins.h" + +// ******ANALOG CONSTANT VALUES******** +const int ANALOG_CONTROL_PINS = 18; +const int ANALOG_CONTROL[ANALOG_CONTROL_PINS] = { + SLIDE1, + SLIDE2, + SLIDE3, + SLIDE4, + SLIDE5, + SLIDE6, + SLIDE7, + SLIDE8, + SLIDE9, + SLIDE10, + POT1, + POT2, + POT3, + POT4, + POT5, + SW1, + SW2, + SW3 +}; + +// ******BUTTONS CONSTANT VALUES******** +const int BUTTON_PINS = 2; // number of Digital trigger PINS +const int BOUNCE_TIME = 5; // 5 ms is usually sufficient +const boolean toggled = true; + +// define the pins and notes for digital events +const int BUTTONS[BUTTON_PINS] = { + ENC1_SW, + ENC2_SW +}; + +// ******TRIGGERS CONSTANT VALUES******** +const int TRIGGER_PINS = 6; +const int TRIGGERS[TRIGGER_PINS] = { + TRIG1, + TRIG2, + TRIG3, + TRIG4, + TRIG5, + TRIG6 +}; + +//******VARIABLES*********** + +//************INITIALIZE LIBRARY OBJECTS************** + +// initialize the ReponsiveAnalogRead objects +ResponsiveAnalogRead analog_controls[]{ + {ANALOG_CONTROL[0],true}, + {ANALOG_CONTROL[1],true}, + {ANALOG_CONTROL[2],true}, + {ANALOG_CONTROL[3],true}, + {ANALOG_CONTROL[4],true}, + {ANALOG_CONTROL[5],true}, + {ANALOG_CONTROL[6],true}, + {ANALOG_CONTROL[7],true}, + {ANALOG_CONTROL[8],true}, + {ANALOG_CONTROL[9],true}, + {ANALOG_CONTROL[10],true}, + {ANALOG_CONTROL[11],true}, + {ANALOG_CONTROL[12],true}, + {ANALOG_CONTROL[13],true}, + {ANALOG_CONTROL[14],true}, + {ANALOG_CONTROL[15],true}, + {ANALOG_CONTROL[16],true}, + {ANALOG_CONTROL[17],true} +}; + +// initialize the bounce objects +Bounce digital_button[] = { + Bounce(BUTTONS[0],BOUNCE_TIME), + Bounce(BUTTONS[1],BOUNCE_TIME) +}; + +Bounce digital_trigger[] = { + Bounce(TRIGGERS[0],BOUNCE_TIME), + Bounce(TRIGGERS[1],BOUNCE_TIME), + Bounce(TRIGGERS[2],BOUNCE_TIME), + Bounce(TRIGGERS[3],BOUNCE_TIME), + Bounce(TRIGGERS[4],BOUNCE_TIME), + Bounce(TRIGGERS[5],BOUNCE_TIME) +}; + +const int NB_ENCODER = 2; +Encoder encoders_knob[] = { + Encoder(ENC1_1, ENC1_2), + Encoder(ENC2_1, ENC2_2) +}; + +void setup_hardware_controls(){ + // loop to configure input pins and internal pullup resisters for digital section + for (int i=0;i