Menu system fixes; made state less global
This commit is contained in:
parent
cfc2390b8b
commit
209959e2de
14 changed files with 964 additions and 731 deletions
|
@ -12,7 +12,7 @@
|
|||
platform = teensy
|
||||
board = teensy40
|
||||
framework = arduino
|
||||
build_flags = -D USB_MIDI_SERIAL -D TEENSY_OPT_FASTER
|
||||
build_flags = -D USB_MIDI_SERIAL -g
|
||||
board_build.f_cpu = 528000000L
|
||||
lib_deps =
|
||||
adafruit/Adafruit MPR121@^1.1.1
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
1. LED abstraction code
|
||||
2. Encoder code
|
||||
3. Menu refactor
|
||||
4. Refactor note play behavior into module
|
||||
5. Refactor CV behavior into module
|
||||
6. 9dof sensor code
|
||||
7. Alternate fingerings
|
||||
8. Encoder midi
|
||||
8. Encoder midi
|
||||
|
||||
- Lever mode: pb
|
||||
- Breath mode: relative
|
||||
- Breath suck control?
|
||||
-
|
|
@ -1,187 +0,0 @@
|
|||
#include <array>
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include "menu.h"
|
||||
#include "globals.h"
|
||||
#include "config.h"
|
||||
#include "hardware.h"
|
||||
#include "settings.h"
|
||||
|
||||
//***********************************************************
|
||||
|
||||
extern Adafruit_SSD1306 display;
|
||||
extern Adafruit_MPR121 touchSensorUtil;
|
||||
extern Adafruit_MPR121 touchSensorKeys;
|
||||
extern Adafruit_MPRLS pressureSensorMain;
|
||||
extern Adafruit_MPRLS pressureSensorAlt;
|
||||
extern byte cursorNow;
|
||||
|
||||
int16_t ctouchVal = 0;
|
||||
|
||||
// Track pixels for faster redrawing
|
||||
struct AdjustDrawing {
|
||||
int row;
|
||||
int thrX;
|
||||
int maxX;
|
||||
int valX;
|
||||
};
|
||||
|
||||
struct AdjustValue {
|
||||
const char *title;
|
||||
const int16_t &value;
|
||||
int16_t &thrVal;
|
||||
int16_t &maxVal;
|
||||
const int16_t limitLow;
|
||||
const int16_t limitHigh;
|
||||
|
||||
// If not null, thr and max are relative to zeroPoint
|
||||
const int16_t *zeroPoint;
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
class AdjustMenuScreen : public MenuScreen {
|
||||
public:
|
||||
AdjustMenuScreen(const char* title, std::array<AdjustValue, N> entries) : _title(title), _entries(entries) { }
|
||||
void update(InputState input, bool redraw) {
|
||||
bool redrawIndicators = false;
|
||||
if (input.changed) {
|
||||
if (input.knobMenu) {
|
||||
_selectedEntry = _selectedEntry + input.knobMenu;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
AdjustValue value = _entries[_selectedEntry];
|
||||
if (input.knobVal1) {
|
||||
value.thrVal += input.knobVal1;
|
||||
redrawIndicators = true;
|
||||
}
|
||||
|
||||
if (input.knobVal2) {
|
||||
value.maxVal += input.knobVal2;
|
||||
redrawIndicators = true;
|
||||
}
|
||||
} else {
|
||||
draw(redrawIndicators, redraw);
|
||||
}
|
||||
}
|
||||
const char *title() {
|
||||
return _title;
|
||||
}
|
||||
private:
|
||||
void draw(bool redrawIndicators, bool redraw) {
|
||||
size_t scrollPos = 0;
|
||||
if (_entries.size() >= ADJUST_NUM_ROWS) {
|
||||
if ((_selectedEntry - scrollPos) > (ADJUST_NUM_ROWS-2) ) {
|
||||
scrollPos = _selectedEntry - (ADJUST_NUM_ROWS-2);
|
||||
} else if( (_selectedEntry - scrollPos) < 1) {
|
||||
scrollPos = _selectedEntry - 1;
|
||||
}
|
||||
|
||||
scrollPos = constrain(scrollPos, 0, _entries.size() - ADJUST_NUM_ROWS);
|
||||
}
|
||||
|
||||
int end = constrain(scrollPos + ADJUST_NUM_ROWS, 0, N);
|
||||
for (size_t i = scrollPos; i < end; i++) {
|
||||
if (redraw) {
|
||||
drawAdjustRow(_entries[i], _rowDrawings[i], i == _selectedEntry);
|
||||
} else if (redrawIndicators && i == _selectedEntry) {
|
||||
drawAdjustIndicators(_entries[i], _rowDrawings[i]);
|
||||
} else {
|
||||
drawAdjustValues(_entries[i], _rowDrawings[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* _title;
|
||||
size_t _selectedEntry = 0;
|
||||
std::array<AdjustValue, N> _entries;
|
||||
std::array<AdjustDrawing, N> _rowDrawings;
|
||||
};
|
||||
|
||||
std::array<AdjustValue, 8> adjustValues = {{
|
||||
{"BREATH", state.breathSignal, calibration.breathThrValOffset, calibration.breathMaxValOffset,
|
||||
BREATH_LO_LIMIT, BREATH_HI_LIMIT, &state.breathZero},
|
||||
{"BR ALT", state.breathAltSignal, calibration.breathAltThrValOffset, calibration.breathAltMaxValOffset,
|
||||
BREATH_LO_LIMIT, BREATH_HI_LIMIT, &state.breathAltZero},
|
||||
{"BITE",state.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, BITE_LO_LIMIT, BITE_HI_LIMIT, NULL},
|
||||
{"PB DOWN",state.pbDnSignal, calibration.pbDnThrVal, calibration.pbDnMaxVal, PITCHB_LO_LIMIT, PITCHB_HI_LIMIT, NULL},
|
||||
{"PB UP", state.pbUpSignal, calibration.pbUpThrVal, calibration.pbUpMaxVal, PITCHB_LO_LIMIT, PITCHB_HI_LIMIT, NULL},
|
||||
{"EXTRA", state.extraSignal, calibration.extraThrVal, calibration.extraMaxVal, EXTRA_LO_LIMIT, EXTRA_HI_LIMIT, NULL},
|
||||
{"LEVER", state.leverSignal, calibration.leverThrVal, calibration.leverMaxVal, LEVER_LO_LIMIT, LEVER_HI_LIMIT, NULL},
|
||||
{"TOUCH", ctouchVal, calibration.ctouchThrVal, calibration.ctouchThrVal, CTOUCH_LO_LIMIT, CTOUCH_HI_LIMIT, NULL},
|
||||
}};
|
||||
|
||||
const MenuScreen adjustMenu = AdjustMenuScreen<8>("ADJUST", adjustValues);
|
||||
|
||||
void autoCalSelected() {
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
|
||||
|
||||
static void drawIndicator(int x, int row, int color) {
|
||||
display.fillTriangle(x-2, row+1, x+2, row+1, x, row+3, color);
|
||||
display.fillTriangle(x-2, row+10, x+2, row+10, x, row+7, color);
|
||||
}
|
||||
|
||||
static void drawAdjustIndicators(const AdjustValue &value, AdjustDrawing &drawing) {
|
||||
const int thrX = mapConstrain(value.thrVal, value.limitLow, value.limitHigh, 1, 127);
|
||||
const int maxX = mapConstrain(value.maxVal, value.limitLow, value.limitHigh, 1, 127);
|
||||
if (drawing.maxX != maxX) {
|
||||
drawIndicator(drawing.thrX, drawing.row, BLACK);
|
||||
drawIndicator(thrX, drawing.row, WHITE);
|
||||
drawing.maxX = maxX;
|
||||
}
|
||||
|
||||
if (drawing.thrX != thrX) {
|
||||
drawIndicator(drawing.thrX, drawing.row, BLACK);
|
||||
drawIndicator(thrX, drawing.row, WHITE);
|
||||
drawing.thrX = thrX;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawAdjustTitle(const AdjustValue &value, AdjustDrawing &drawing, bool highlight) {
|
||||
display.setTextSize(1);
|
||||
if (highlight) {
|
||||
display.setTextColor(BLACK, WHITE);
|
||||
} else {
|
||||
display.setTextColor(WHITE, BLACK);
|
||||
}
|
||||
display.setCursor(0, drawing.row);
|
||||
display.println(value.title);
|
||||
}
|
||||
|
||||
static void drawAdjustValues(const AdjustValue &value, AdjustDrawing &drawing) {
|
||||
char buffer[13];
|
||||
snprintf(buffer, 13, "%d>%d<%d", value.thrVal, value.value, value.maxVal);
|
||||
display.setTextSize(1);
|
||||
display.setCursor(128 - 6 * strlen(buffer), drawing.row);
|
||||
display.println(buffer);
|
||||
|
||||
const int valX = mapConstrain(value.value, value.limitLow, value.limitHigh, 1, 127);
|
||||
if (drawing.valX != valX) {
|
||||
display.drawFastVLine(drawing.valX, drawing.row+4, 4, BLACK);
|
||||
display.drawFastVLine(valX, drawing.row+4, 4, WHITE);
|
||||
drawing.valX = valX;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawAdjustFrame(int line) {
|
||||
display.drawLine(25,line,120,line,WHITE); // Top line
|
||||
display.drawLine(25,line+12,120,line+12,WHITE); // Bottom line
|
||||
|
||||
display.drawLine(25,line+1,25,line+2,WHITE);
|
||||
display.drawLine(120,line+1,120,line+2,WHITE);
|
||||
|
||||
display.drawLine(120,line+10,120,line+11,WHITE);
|
||||
display.drawLine(25,line+10,25,line+11,WHITE);
|
||||
}
|
||||
|
||||
static void drawAdjustRow(const AdjustValue &value, AdjustDrawing &drawing, bool highlight) {
|
||||
display.fillRect(0, drawing.row, 128, 21, BLACK);
|
||||
drawAdjustFrame(drawing.row);
|
||||
drawAdjustTitle(value, drawing, highlight);
|
||||
drawAdjustValues(value, drawing);
|
||||
drawAdjustIndicators(value, drawing);
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
#define CAP_SENS_ABSOLUTE_MAX 1000 // For inverting capacitive sensors
|
||||
#define PRESSURE_SENS_MULTIPLIER 10 // Multiply pressure sens so it's not a float
|
||||
#define CALIBRATE_SAMPLE_COUNT 4
|
||||
#define MENU_AUTO_OFF_TIME 30000
|
||||
|
||||
|
||||
// Statup buttons
|
||||
|
|
|
@ -74,14 +74,13 @@ enum PortamentoMode : uint8_t {
|
|||
};
|
||||
|
||||
struct instrument_state_t {
|
||||
int mainState; // The state of the main state machine
|
||||
uint8_t patch; // 1-128
|
||||
byte activeMIDIchannel = 1; // MIDI channel
|
||||
byte activeNote = 0; // note playing
|
||||
byte activePatch = 0;
|
||||
byte doPatchUpdate = 0;
|
||||
int8_t transpose = 0;
|
||||
uint8_t octave = 0;
|
||||
int8_t octave = 0;
|
||||
PolySelect polyMode = PolySelect::EHarmonizerOff;
|
||||
|
||||
// Raw sensor signals
|
||||
|
@ -93,6 +92,7 @@ struct instrument_state_t {
|
|||
int16_t pbDnSignal = 0;
|
||||
int16_t extraSignal = 0;
|
||||
int16_t vibSignal = 0;
|
||||
int16_t avgCTouchSignal = 0;
|
||||
|
||||
// MIDI values
|
||||
int breathCCVal = 0;
|
||||
|
@ -127,8 +127,6 @@ struct instrument_state_t {
|
|||
int16_t vibThrBiteLo;
|
||||
};
|
||||
|
||||
extern instrument_state_t state;
|
||||
|
||||
extern const std::array<const unsigned short*, 13> curves;
|
||||
extern const unsigned short curveIn[];
|
||||
|
||||
|
|
|
@ -103,8 +103,22 @@ void errorWait() {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the knob value accounting for 4x precision - NB this might not work on other kinds of encoder
|
||||
*/
|
||||
int readKnob(uint8_t n) {
|
||||
return knobs[n].readAndReset();
|
||||
int out = 0;
|
||||
int32_t val = knobs[n].read();
|
||||
if (val > 4) {
|
||||
out = val / 4;
|
||||
} else if (val < -4) {
|
||||
out = val / 4;
|
||||
}
|
||||
|
||||
if (out != 0) {
|
||||
knobs[n].write(0);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int readTouchKey(uint8_t n) {
|
||||
|
|
|
@ -31,24 +31,24 @@ int readAltPressure();
|
|||
// I2C
|
||||
#define MainI2CBus Wire1
|
||||
#define AuxI2CBus Wire
|
||||
#define KeysI2CAddr 0x5B
|
||||
#define UtilI2CAddr 0x5A
|
||||
#define KeysI2CAddr 0x5A
|
||||
#define UtilI2CAddr 0x5B
|
||||
|
||||
// Digital pins for encoder buttons
|
||||
#define b1Pin 0
|
||||
#define b2Pin 2
|
||||
#define b3Pin 3
|
||||
#define b4Pin 4
|
||||
#define b1Pin 4
|
||||
#define b2Pin 3
|
||||
#define b3Pin 2
|
||||
#define b4Pin 0
|
||||
|
||||
// Digital pins for encoder quadrature
|
||||
#define e1aPin 5
|
||||
#define e2aPin 6
|
||||
#define e1aPin 6
|
||||
#define e2aPin 8
|
||||
#define e3aPin 7
|
||||
#define e4aPin 8
|
||||
#define e4aPin 5
|
||||
|
||||
#define e1bPin 20
|
||||
#define e1bPin 22
|
||||
#define e2bPin 21
|
||||
#define e3bPin 22
|
||||
#define e3bPin 20
|
||||
#define e4bPin 23
|
||||
|
||||
// CV pins
|
||||
|
@ -64,33 +64,34 @@ int readAltPressure();
|
|||
|
||||
// Key pins
|
||||
// RH keys
|
||||
#define K1Pin 0
|
||||
#define K2Pin 1
|
||||
#define K1Pin 5
|
||||
#define K2Pin 6
|
||||
#define K3Pin 2
|
||||
#define K4Pin 3
|
||||
#define K4Pin 11
|
||||
#define K5Pin 4
|
||||
#define K6Pin 5
|
||||
#define K7Pin 6
|
||||
#define K8Pin 7
|
||||
#define K6Pin 7
|
||||
#define K7Pin 9
|
||||
#define K8Pin 10
|
||||
|
||||
// LH keys
|
||||
#define K9Pin 8
|
||||
#define K10Pin 9
|
||||
#define K11Pin 10
|
||||
#define K12Pin 11
|
||||
#define K9Pin 3
|
||||
#define K10Pin 8
|
||||
#define K11Pin 0
|
||||
#define K12Pin 1
|
||||
|
||||
// Octave roller pins
|
||||
#define R1Pin 0
|
||||
#define R2Pin 1
|
||||
#define R3Pin 2
|
||||
#define R4Pin 3
|
||||
#define R5Pin 4
|
||||
#define R6Pin 5
|
||||
#define R1Pin 11
|
||||
#define R2Pin 10
|
||||
#define R3Pin 9
|
||||
#define R4Pin 8
|
||||
#define R5Pin 7
|
||||
#define R6Pin 6
|
||||
|
||||
// Additional pins
|
||||
#define bitePin 6
|
||||
#define pbUpPin 7
|
||||
#define pbDnPin 8
|
||||
#define vibratoPin 9
|
||||
#define bitePin 0
|
||||
#define extraPin 2
|
||||
#define pbUpPin 4
|
||||
#define pbDnPin 5
|
||||
#define vibratoPin 3
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,7 @@ void statusLedBlink() {
|
|||
statusLedFlash(300);
|
||||
}
|
||||
|
||||
void updateSensorLEDs() {
|
||||
ledHalfMeter(1, state.breathCCVal, 0x00FF00);
|
||||
ledQuarterMeter(3, state.biteVal, 0x0000FF);
|
||||
void updateSensorLEDs(instrument_state_t *state) {
|
||||
ledHalfMeter(1, state->breathCCVal, 0x00FF00);
|
||||
ledQuarterMeter(3, state->biteVal, 0x0000FF);
|
||||
}
|
||||
|
|
1066
NuEVI/src/menu.cpp
1066
NuEVI/src/menu.cpp
File diff suppressed because it is too large
Load diff
|
@ -2,6 +2,7 @@
|
|||
#define __MENU_H
|
||||
|
||||
#include "wiring.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define MENU_ROW_HEIGHT 9
|
||||
#define MENU_HEADER_OFFSET 12
|
||||
|
@ -28,17 +29,18 @@ struct InputState {
|
|||
int knobPreset = 0;
|
||||
};
|
||||
|
||||
struct MenuScreen {
|
||||
class MenuScreen {
|
||||
public:
|
||||
MenuScreen() {};
|
||||
virtual const char *title() { return ""; };
|
||||
virtual void update(InputState input, bool redraw) {};
|
||||
virtual bool update(state_t &state, InputState &input, bool redraw) = 0;
|
||||
virtual ~MenuScreen() {};
|
||||
};
|
||||
extern const MenuScreen adjustMenu;
|
||||
|
||||
void initDisplay();
|
||||
void displayOff();
|
||||
void showVersion();
|
||||
void displayError(const char *error);
|
||||
void handleMenu(bool draw);
|
||||
void handleMenu(state_t &state, bool draw);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,11 +32,11 @@ uint16_t readInt(uint16_t address) {
|
|||
return data.val;
|
||||
}
|
||||
|
||||
void writeCalibration() {
|
||||
void writeCalibration(calibration_t &calibration) {
|
||||
EEPROM.put(SETTINGS_OFFSET, calibration);
|
||||
}
|
||||
|
||||
void readCalibration() {
|
||||
void readCalibration(calibration_t &calibration) {
|
||||
EEPROM.get(SETTINGS_OFFSET, calibration);
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,6 @@ bool receiveSysexSettings(const uint8_t* data, const uint16_t length) {
|
|||
uint16_t *preset_buffer = (uint16_t*)presets;
|
||||
for(uint16_t i=0; i<payload_size/2; i++) {
|
||||
uint16_t addr = i*2;
|
||||
uint16_t val;
|
||||
|
||||
preset_buffer[addr] = convertFromMidiValue(data+(payload_pos+addr));
|
||||
}
|
||||
|
@ -270,7 +269,7 @@ void handleSysex(uint8_t *data, unsigned int length) {
|
|||
}
|
||||
|
||||
//Get message code
|
||||
char messageCode[3];
|
||||
char messageCode[4];
|
||||
strncpy(messageCode, (char*)(data+9), 3);
|
||||
|
||||
if(!strncmp(messageCode, "c00", 3)) { //Config dump request
|
||||
|
@ -319,7 +318,7 @@ void configModeLoop() {
|
|||
}
|
||||
|
||||
//Read settings from eeprom. Returns wether or not anything was written (due to factory reset or upgrade)
|
||||
void readEEPROM(const bool factoryReset) {
|
||||
void readEEPROM(const bool factoryReset, calibration_t &calibration) {
|
||||
|
||||
// if stored settings are not for current version, or Enter+Menu are pressed at startup, they are replaced by factory settings
|
||||
uint16_t settings_version = readInt(EEPROM_VERSION_ADDR);
|
||||
|
@ -329,7 +328,7 @@ void readEEPROM(const bool factoryReset) {
|
|||
settings_version = 0;
|
||||
} else {
|
||||
readPresets();
|
||||
readCalibration();
|
||||
readCalibration(calibration);
|
||||
}
|
||||
|
||||
if(settings_version != EEPROM_VERSION) {
|
||||
|
|
|
@ -95,8 +95,15 @@ struct preset_t {
|
|||
|
||||
static_assert(sizeof(preset_t) == PRESET_MAX_SIZE, "preset_t must be 128 bytes");
|
||||
extern preset_t presets[PRESET_COUNT];
|
||||
extern calibration_t calibration;
|
||||
extern preset_t *currentPreset;
|
||||
|
||||
// Application state
|
||||
struct state_t {
|
||||
int mainState; // The state of the main state machine
|
||||
|
||||
instrument_state_t *instrument;
|
||||
preset_t *currentPreset;
|
||||
calibration_t *calibration;
|
||||
};
|
||||
|
||||
#define NO_CHECKSUM 0x7F007F00
|
||||
|
||||
|
|
|
@ -27,12 +27,14 @@ void handleTestMode() {
|
|||
if (keys != oldKeys) {
|
||||
Serial.print("Keys:");
|
||||
Serial.println(keys, HEX);
|
||||
oldKeys = keys;
|
||||
}
|
||||
|
||||
uint16_t util = utilTouched();
|
||||
if (util != oldUtil) {
|
||||
Serial.print("Util:");
|
||||
Serial.println(util, HEX);
|
||||
oldUtil = util;
|
||||
}
|
||||
|
||||
if (buttons == 0x01) {
|
||||
|
@ -48,10 +50,12 @@ void handleTestMode() {
|
|||
}
|
||||
|
||||
for (int i = 0; i < 12; i++) {
|
||||
Serial.print(">util");
|
||||
Serial.print(">util");
|
||||
Serial.print(i);
|
||||
Serial.print(":");
|
||||
Serial.println(readTouchUtil(i));
|
||||
}
|
||||
}
|
||||
|
||||
delay(2);
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
#include "config.h"
|
||||
#include "settings.h"
|
||||
#include "led.h"
|
||||
#include "test.h"
|
||||
|
||||
/*
|
||||
NAME: xEVI
|
||||
|
@ -28,9 +29,15 @@ FUNCTION: EVI Wind Controller using MPRLS pressure sensors and capac
|
|||
#endif
|
||||
|
||||
preset_t presets[PRESET_COUNT];
|
||||
instrument_state_t state;
|
||||
preset_t *currentPreset;
|
||||
instrument_state_t instrument;
|
||||
preset_t *currentPreset = &presets[0];
|
||||
calibration_t calibration;
|
||||
state_t state = {
|
||||
NOTE_OFF,
|
||||
&instrument,
|
||||
currentPreset,
|
||||
&calibration,
|
||||
};
|
||||
|
||||
static const int pbDepthList[13] = { 8192, 8192, 4096, 2731, 2048, 1638, 1365, 1170, 1024, 910, 819, 744, 683 };
|
||||
static const float vibDepth[10] = { 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.40, 0.45 }; // max pitch bend values (+/-) for the vibrato settings
|
||||
|
@ -98,20 +105,20 @@ inline int noteValueCheck(int note) {
|
|||
//***********************************************************
|
||||
|
||||
void port(int portCC) {
|
||||
if (portCC == state.portamentoVal) {
|
||||
if (portCC == instrument.portamentoVal) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentPreset->portamentoMode == PortamentoMode::PON || currentPreset->portamentoMode == PortamentoMode::PGLIDE_ONLY) {
|
||||
if (state.portamentoVal > 0 && portCC == 0) {
|
||||
if (instrument.portamentoVal > 0 && portCC == 0) {
|
||||
midiSendControlChange(CCN_PortOnOff, 0);
|
||||
} else if (state.portamentoVal == 0 && portCC > 0) {
|
||||
} else if (instrument.portamentoVal == 0 && portCC > 0) {
|
||||
midiSendControlChange(CCN_PortOnOff, 127);
|
||||
}
|
||||
}
|
||||
|
||||
midiSendControlChange(CCN_Port, portCC);
|
||||
state.portamentoVal = portCC;
|
||||
instrument.portamentoVal = portCC;
|
||||
}
|
||||
|
||||
// Update CV output pin, run from timer.
|
||||
|
@ -120,43 +127,43 @@ void cvUpdate() {
|
|||
uint32_t currentTime = millis();
|
||||
int cvPressure = readPressure();
|
||||
analogWrite(cvBreathPin, cvPressure);
|
||||
state.targetPitch = (state.activeNote - 24) * 42;
|
||||
state.targetPitch += map(state.pitchBend, 0, 16383, -84, 84);
|
||||
state.targetPitch -= state.quarterToneTrigger * 21;
|
||||
if (state.portamentoVal > 0) {
|
||||
if (state.targetPitch > state.cvPitch) {
|
||||
instrument.targetPitch = (instrument.activeNote - 24) * 42;
|
||||
instrument.targetPitch += map(instrument.pitchBend, 0, 16383, -84, 84);
|
||||
instrument.targetPitch -= instrument.quarterToneTrigger * 21;
|
||||
if (instrument.portamentoVal > 0) {
|
||||
if (instrument.targetPitch > instrument.cvPitch) {
|
||||
if (!cvPortaTuneCount) {
|
||||
state.cvPitch += 1 + (127 - state.portamentoVal) / 4;
|
||||
instrument.cvPitch += 1 + (127 - instrument.portamentoVal) / 4;
|
||||
} else {
|
||||
cvPortaTuneCount++;
|
||||
if (cvPortaTuneCount > CVPORTATUNE)
|
||||
cvPortaTuneCount = 0;
|
||||
}
|
||||
if (state.cvPitch > state.targetPitch)
|
||||
state.cvPitch = state.targetPitch;
|
||||
} else if (state.targetPitch < state.cvPitch) {
|
||||
if (instrument.cvPitch > instrument.targetPitch)
|
||||
instrument.cvPitch = instrument.targetPitch;
|
||||
} else if (instrument.targetPitch < instrument.cvPitch) {
|
||||
if (!cvPortaTuneCount) {
|
||||
state.cvPitch -= 1 + (127 - state.portamentoVal) / 4;
|
||||
instrument.cvPitch -= 1 + (127 - instrument.portamentoVal) / 4;
|
||||
} else {
|
||||
cvPortaTuneCount++;
|
||||
if (cvPortaTuneCount > CVPORTATUNE)
|
||||
cvPortaTuneCount = 0;
|
||||
}
|
||||
if (state.cvPitch < state.targetPitch)
|
||||
state.cvPitch = state.targetPitch;
|
||||
if (instrument.cvPitch < instrument.targetPitch)
|
||||
instrument.cvPitch = instrument.targetPitch;
|
||||
} else {
|
||||
state.cvPitch = state.targetPitch;
|
||||
instrument.cvPitch = instrument.targetPitch;
|
||||
}
|
||||
} else {
|
||||
state.cvPitch = state.targetPitch;
|
||||
instrument.cvPitch = instrument.targetPitch;
|
||||
}
|
||||
|
||||
if (currentPreset->cvVibRate) {
|
||||
int timeDivider = timeDividerList[currentPreset->cvVibRate];
|
||||
int cvVib = map(((waveformsTable[map(currentTime % timeDivider, 0, timeDivider, 0, maxSamplesNum - 1)] - 2047)), -259968, 259969, -11, 11);
|
||||
state.cvPitch += cvVib;
|
||||
instrument.cvPitch += cvVib;
|
||||
}
|
||||
int cvPitchTuned = 2 * (currentPreset->cvTune) + map(state.cvPitch, 0, 4032, 0, 4032 + 2 * (currentPreset->cvScale));
|
||||
int cvPitchTuned = 2 * (currentPreset->cvTune) + map(instrument.cvPitch, 0, 4032, 0, 4032 + 2 * (currentPreset->cvScale));
|
||||
analogWrite(cvPitchPin, constrain(cvPitchTuned, 0, 4095));
|
||||
}
|
||||
|
||||
|
@ -209,7 +216,7 @@ int breath() {
|
|||
|
||||
int breathCCval, breathCCvalFine;
|
||||
unsigned int breathCCvalHires;
|
||||
breathCCvalHires = breathCurve(mapConstrain(state.breathSignal, state.breathThrVal, state.breathMaxVal, 0, 16383));
|
||||
breathCCvalHires = breathCurve(mapConstrain(instrument.breathSignal, instrument.breathThrVal, instrument.breathMaxVal, 0, 16383));
|
||||
breathCCval = (breathCCvalHires >> 7) & 0x007F;
|
||||
breathCCvalFine = breathCCvalHires & 0x007F;
|
||||
if (breathCCval != oldbreath) { // only send midi data if breath has changed from previous value
|
||||
|
@ -246,10 +253,10 @@ void pitch_bend() {
|
|||
byte pbTouched = 0;
|
||||
int vibRead = 0;
|
||||
int vibReadBite = 0;
|
||||
state.pbUpSignal = readTouchUtil(pbUpPin); // PCB PIN "Pu"
|
||||
state.pbDnSignal = readTouchUtil(pbDnPin); // PCB PIN "Pd"
|
||||
bool halfPitchBendKey = (currentPreset->pinkySetting == PBD) && state.pinkyKey; // hold pinky key for 1/2 pitchbend value
|
||||
state.quarterToneTrigger = (currentPreset->pinkySetting == QTN) && state.pinkyKey; // pinky key for a quarter tone down using pitch bend (assuming PB range on synth is set to 2 semitones)
|
||||
instrument.pbUpSignal = readTouchUtil(pbUpPin); // PCB PIN "Pu"
|
||||
instrument.pbDnSignal = readTouchUtil(pbDnPin); // PCB PIN "Pd"
|
||||
bool halfPitchBendKey = (currentPreset->pinkySetting == PBD) && instrument.pinkyKey; // hold pinky key for 1/2 pitchbend value
|
||||
instrument.quarterToneTrigger = (currentPreset->pinkySetting == QTN) && instrument.pinkyKey; // pinky key for a quarter tone down using pitch bend (assuming PB range on synth is set to 2 semitones)
|
||||
|
||||
calculatedPBdepth = pbDepthList[currentPreset->PBdepth];
|
||||
if (halfPitchBendKey)
|
||||
|
@ -268,31 +275,31 @@ void pitch_bend() {
|
|||
vibMaxBite = vibMaxBiteList[currentPreset->vibSens - 1];
|
||||
vibReadBite = readTouchUtil(bitePin); // get sensor data, do some smoothing - SENSOR PIN 17 - PCB PINS LABELED "BITE" (GND left, sensor pin right)
|
||||
|
||||
if (vibReadBite < state.vibThrBite) {
|
||||
state.vibSignal = (state.vibSignal + mapConstrain(
|
||||
vibReadBite, (state.vibZeroBite - vibMaxBite), state.vibThrBite, calculatedDepth, 0)
|
||||
if (vibReadBite < instrument.vibThrBite) {
|
||||
instrument.vibSignal = (instrument.vibSignal + mapConstrain(
|
||||
vibReadBite, (instrument.vibZeroBite - vibMaxBite), instrument.vibThrBite, calculatedDepth, 0)
|
||||
) / 2;
|
||||
} else if (vibReadBite > state.vibThrBiteLo) {
|
||||
state.vibSignal = (state.vibSignal + mapConstrain(
|
||||
vibReadBite, (state.vibZeroBite + vibMaxBite), state.vibThrBite, calculatedDepth, 0)
|
||||
} else if (vibReadBite > instrument.vibThrBiteLo) {
|
||||
instrument.vibSignal = (instrument.vibSignal + mapConstrain(
|
||||
vibReadBite, (instrument.vibZeroBite + vibMaxBite), instrument.vibThrBite, calculatedDepth, 0)
|
||||
) / 2;
|
||||
} else {
|
||||
state.vibSignal = state.vibSignal / 2;
|
||||
instrument.vibSignal = instrument.vibSignal / 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (ExtraControl::VIBRATO == currentPreset->leverControl) { // lever vibrato
|
||||
vibRead = readTouchUtil(vibratoPin);
|
||||
if (vibRead < state.vibThr) {
|
||||
state.vibSignal = (state.vibSignal +
|
||||
mapConstrain(vibRead, (state.vibZero - vibMax), state.vibThr, calculatedDepth, 0)
|
||||
if (vibRead < instrument.vibThr) {
|
||||
instrument.vibSignal = (instrument.vibSignal +
|
||||
mapConstrain(vibRead, (instrument.vibZero - vibMax), instrument.vibThr, calculatedDepth, 0)
|
||||
) / 2;
|
||||
} else if (vibRead > state.vibThrLo) {
|
||||
state.vibSignal = (state.vibSignal +
|
||||
mapConstrain(vibRead, (state.vibZero + vibMax), state.vibThr, calculatedDepth, 0)
|
||||
} else if (vibRead > instrument.vibThrLo) {
|
||||
instrument.vibSignal = (instrument.vibSignal +
|
||||
mapConstrain(vibRead, (instrument.vibZero + vibMax), instrument.vibThr, calculatedDepth, 0)
|
||||
) / 2;
|
||||
} else {
|
||||
state.vibSignal = state.vibSignal / 2;
|
||||
instrument.vibSignal = instrument.vibSignal / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,53 +308,53 @@ void pitch_bend() {
|
|||
// keep vibZero value
|
||||
break;
|
||||
case 1:
|
||||
state.vibZero = state.vibZero * 0.95 + vibRead * 0.05;
|
||||
state.vibZeroBite = state.vibZeroBite * 0.95 + vibReadBite * 0.05;
|
||||
instrument.vibZero = instrument.vibZero * 0.95 + vibRead * 0.05;
|
||||
instrument.vibZeroBite = instrument.vibZeroBite * 0.95 + vibReadBite * 0.05;
|
||||
break;
|
||||
case 2:
|
||||
state.vibZero = state.vibZero * 0.9 + vibRead * 0.1;
|
||||
state.vibZeroBite = state.vibZeroBite * 0.9 + vibReadBite * 0.1;
|
||||
instrument.vibZero = instrument.vibZero * 0.9 + vibRead * 0.1;
|
||||
instrument.vibZeroBite = instrument.vibZeroBite * 0.9 + vibReadBite * 0.1;
|
||||
break;
|
||||
case 3:
|
||||
state.vibZero = state.vibZero * 0.8 + vibRead * 0.2;
|
||||
state.vibZeroBite = state.vibZeroBite * 0.8 + vibReadBite * 0.2;
|
||||
instrument.vibZero = instrument.vibZero * 0.8 + vibRead * 0.2;
|
||||
instrument.vibZeroBite = instrument.vibZeroBite * 0.8 + vibReadBite * 0.2;
|
||||
break;
|
||||
case 4:
|
||||
state.vibZero = state.vibZero * 0.6 + vibRead * 0.4;
|
||||
state.vibZeroBite = state.vibZeroBite * 0.6 + vibReadBite * 0.4;
|
||||
instrument.vibZero = instrument.vibZero * 0.6 + vibRead * 0.4;
|
||||
instrument.vibZeroBite = instrument.vibZeroBite * 0.6 + vibReadBite * 0.4;
|
||||
}
|
||||
state.vibThr = state.vibZero - currentPreset->vibSquelch;
|
||||
state.vibThrLo = state.vibZero + currentPreset->vibSquelch;
|
||||
state.vibThrBite = state.vibZeroBite - currentPreset->vibSquelch;
|
||||
state.vibThrBiteLo = state.vibZeroBite + currentPreset->vibSquelch;
|
||||
int pbPos = mapConstrain(state.pbUpSignal, calibration.pbUpMaxVal, calibration.pbUpThrVal, calculatedPBdepth, 0);
|
||||
int pbNeg = mapConstrain(state.pbDnSignal, calibration.pbDnMaxVal, calibration.pbDnThrVal, calculatedPBdepth, 0);
|
||||
instrument.vibThr = instrument.vibZero - currentPreset->vibSquelch;
|
||||
instrument.vibThrLo = instrument.vibZero + currentPreset->vibSquelch;
|
||||
instrument.vibThrBite = instrument.vibZeroBite - currentPreset->vibSquelch;
|
||||
instrument.vibThrBiteLo = instrument.vibZeroBite + currentPreset->vibSquelch;
|
||||
int pbPos = mapConstrain(instrument.pbUpSignal, calibration.pbUpMaxVal, calibration.pbUpThrVal, calculatedPBdepth, 0);
|
||||
int pbNeg = mapConstrain(instrument.pbDnSignal, calibration.pbDnMaxVal, calibration.pbDnThrVal, calculatedPBdepth, 0);
|
||||
int pbSum = 8193 + pbPos - pbNeg;
|
||||
int pbDif = abs(pbPos - pbNeg);
|
||||
|
||||
if ((state.pbUpSignal < calibration.pbUpThrVal || state.pbDnSignal < calibration.pbDnThrVal) && currentPreset->PBdepth) {
|
||||
if ((instrument.pbUpSignal < calibration.pbUpThrVal || instrument.pbDnSignal < calibration.pbDnThrVal) && currentPreset->PBdepth) {
|
||||
if (pbDif < 10) {
|
||||
state.pitchBend = 8192;
|
||||
instrument.pitchBend = 8192;
|
||||
} else {
|
||||
state.pitchBend = state.pitchBend * 0.6 + 0.4 * pbSum;
|
||||
instrument.pitchBend = instrument.pitchBend * 0.6 + 0.4 * pbSum;
|
||||
}
|
||||
pbTouched = 1;
|
||||
}
|
||||
if (!pbTouched) {
|
||||
state.pitchBend = state.pitchBend * 0.6 + 8192 * 0.4; // released, so smooth your way back to zero
|
||||
if ((state.pitchBend > 8187) && (state.pitchBend < 8197))
|
||||
state.pitchBend = 8192; // 8192 is 0 pitch bend, don't miss it bc of smoothing
|
||||
instrument.pitchBend = instrument.pitchBend * 0.6 + 8192 * 0.4; // released, so smooth your way back to zero
|
||||
if ((instrument.pitchBend > 8187) && (instrument.pitchBend < 8197))
|
||||
instrument.pitchBend = 8192; // 8192 is 0 pitch bend, don't miss it bc of smoothing
|
||||
}
|
||||
|
||||
state.pitchBend = state.pitchBend + state.vibSignal;
|
||||
state.pitchBend = constrain(state.pitchBend, 0, 16383);
|
||||
instrument.pitchBend = instrument.pitchBend + instrument.vibSignal;
|
||||
instrument.pitchBend = constrain(instrument.pitchBend, 0, 16383);
|
||||
|
||||
state.pbSend = state.pitchBend - state.quarterToneTrigger * calculatedPBdepth * 0.25;
|
||||
state.pbSend = constrain(state.pbSend, 0, 16383);
|
||||
instrument.pbSend = instrument.pitchBend - instrument.quarterToneTrigger * calculatedPBdepth * 0.25;
|
||||
instrument.pbSend = constrain(instrument.pbSend, 0, 16383);
|
||||
|
||||
if (state.pbSend != oldpb) { // only send midi data if pitch bend has changed from previous value
|
||||
midiSendPitchBend(state.pbSend);
|
||||
oldpb = state.pbSend;
|
||||
if (instrument.pbSend != oldpb) { // only send midi data if pitch bend has changed from previous value
|
||||
midiSendPitchBend(instrument.pbSend);
|
||||
oldpb = instrument.pbSend;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,23 +368,23 @@ void portamento_() {
|
|||
|
||||
int portSumCC = 0;
|
||||
if (currentPreset->pinkySetting == GLD) {
|
||||
if (state.pinkyKey) {
|
||||
if (instrument.pinkyKey) {
|
||||
portSumCC += currentPreset->portamentoLimit;
|
||||
}
|
||||
}
|
||||
if (ExtraControl::GLIDE == currentPreset->biteControl) {
|
||||
// Portamento is controlled with the bite sensor in the mouthpiece
|
||||
state.biteSignal = readTouchUtil(bitePin);
|
||||
if (state.biteSignal >= calibration.biteThrVal) { // if we are enabled and over the threshold, send portamento
|
||||
portSumCC += mapConstrain(state.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, 0, currentPreset->portamentoLimit);
|
||||
instrument.biteSignal = readTouchUtil(bitePin);
|
||||
if (instrument.biteSignal >= calibration.biteThrVal) { // if we are enabled and over the threshold, send portamento
|
||||
portSumCC += mapConstrain(instrument.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, 0, currentPreset->portamentoLimit);
|
||||
}
|
||||
}
|
||||
|
||||
if (ExtraControl::GLIDE == currentPreset->leverControl) {
|
||||
// Portamento is controlled with thumb lever
|
||||
state.leverSignal = readTouchUtil(vibratoPin);
|
||||
if (((3000 - state.leverSignal) >= calibration.leverThrVal)) { // if we are enabled and over the threshold, send portamento
|
||||
portSumCC += mapConstrain((3000 - state.leverSignal), calibration.leverThrVal, calibration.leverMaxVal, 0, currentPreset->portamentoLimit);
|
||||
instrument.leverSignal = readTouchUtil(vibratoPin);
|
||||
if (((3000 - instrument.leverSignal) >= calibration.leverThrVal)) { // if we are enabled and over the threshold, send portamento
|
||||
portSumCC += mapConstrain((3000 - instrument.leverSignal), calibration.leverThrVal, calibration.leverMaxVal, 0, currentPreset->portamentoLimit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,41 +396,41 @@ void portamento_() {
|
|||
void biteCC_() {
|
||||
int biteVal = 0;
|
||||
if (ExtraControl::CC == currentPreset->biteControl) {
|
||||
state.biteSignal = readTouchUtil(bitePin); // get sensor data, do some smoothing - SENSOR PIN 17 - PCB PINS LABELED "BITE" (GND left, sensor pin right)
|
||||
if (state.biteSignal >= calibration.biteThrVal) { // we are over the threshold, calculate CC value
|
||||
biteVal = mapConstrain(state.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, 0, 127);
|
||||
instrument.biteSignal = readTouchUtil(bitePin); // get sensor data, do some smoothing - SENSOR PIN 17 - PCB PINS LABELED "BITE" (GND left, sensor pin right)
|
||||
if (instrument.biteSignal >= calibration.biteThrVal) { // we are over the threshold, calculate CC value
|
||||
biteVal = mapConstrain(instrument.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, 0, 127);
|
||||
}
|
||||
|
||||
if (biteVal != state.biteVal) {
|
||||
if (biteVal != instrument.biteVal) {
|
||||
midiSendControlChange(currentPreset->biteCC, biteVal);
|
||||
}
|
||||
state.biteVal = biteVal;
|
||||
instrument.biteVal = biteVal;
|
||||
}
|
||||
}
|
||||
|
||||
void autoCal() {
|
||||
state.vibZero = state.vibZeroBite = 0;
|
||||
instrument.vibZero = instrument.vibZeroBite = 0;
|
||||
for(int i = 1 ; i <= CALIBRATE_SAMPLE_COUNT; ++i) {
|
||||
state.breathZero += readPressure();
|
||||
state.breathAltZero += readAltPressure();
|
||||
state.vibZero += readTouchUtil(vibratoPin);
|
||||
state.vibZeroBite += readTouchUtil(bitePin);
|
||||
instrument.breathZero += readPressure();
|
||||
instrument.breathAltZero += readAltPressure();
|
||||
instrument.vibZero += readTouchUtil(vibratoPin);
|
||||
instrument.vibZeroBite += readTouchUtil(bitePin);
|
||||
}
|
||||
|
||||
state.breathZero /= CALIBRATE_SAMPLE_COUNT;
|
||||
state.breathAltZero /= CALIBRATE_SAMPLE_COUNT;
|
||||
state.vibZero /= CALIBRATE_SAMPLE_COUNT;
|
||||
state.vibZeroBite /= CALIBRATE_SAMPLE_COUNT;
|
||||
instrument.breathZero /= CALIBRATE_SAMPLE_COUNT;
|
||||
instrument.breathAltZero /= CALIBRATE_SAMPLE_COUNT;
|
||||
instrument.vibZero /= CALIBRATE_SAMPLE_COUNT;
|
||||
instrument.vibZeroBite /= CALIBRATE_SAMPLE_COUNT;
|
||||
|
||||
state.vibThr = state.vibZero - currentPreset->vibSquelch;
|
||||
state.vibThrLo = state.vibZero + currentPreset->vibSquelch;
|
||||
state.vibThrBite = state.vibZeroBite - currentPreset->vibSquelch;
|
||||
state.vibThrBiteLo = state.vibZeroBite + currentPreset->vibSquelch;
|
||||
instrument.vibThr = instrument.vibZero - currentPreset->vibSquelch;
|
||||
instrument.vibThrLo = instrument.vibZero + currentPreset->vibSquelch;
|
||||
instrument.vibThrBite = instrument.vibZeroBite - currentPreset->vibSquelch;
|
||||
instrument.vibThrBiteLo = instrument.vibZeroBite + currentPreset->vibSquelch;
|
||||
|
||||
state.breathThrVal = state.breathZero + calibration.breathThrValOffset;
|
||||
state.breathMaxVal = state.breathThrVal + calibration.breathMaxValOffset;
|
||||
state.breathAltThrVal = state.breathAltZero + calibration.breathAltThrValOffset;
|
||||
state.breathAltMaxVal = state.breathAltThrVal + calibration.breathAltMaxValOffset;
|
||||
instrument.breathThrVal = instrument.breathZero + calibration.breathThrValOffset;
|
||||
instrument.breathMaxVal = instrument.breathThrVal + calibration.breathMaxValOffset;
|
||||
instrument.breathAltThrVal = instrument.breathAltZero + calibration.breathAltThrValOffset;
|
||||
instrument.breathAltMaxVal = instrument.breathAltThrVal + calibration.breathAltMaxValOffset;
|
||||
|
||||
}
|
||||
|
||||
|
@ -550,9 +557,9 @@ int readOctave() {
|
|||
} else if (FingeringMode::HRN == fingering) { // HRN fingering
|
||||
return 12 + offset + rollerHarmonic[K4][octaveR]; // roller harmonics
|
||||
} else if (FingeringMode::EVR == fingering) { // HRN fingering
|
||||
return 12 * (6 - octaveR) + offset;
|
||||
return 12 * (6 - octaveR) + offset + instrument.octave;
|
||||
} else { // EVI
|
||||
return 12 * octaveR + offset;
|
||||
return 12 * octaveR + offset + instrument.octave;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -564,10 +571,15 @@ int readSwitches() {
|
|||
|
||||
// Read touch pads (MPR121), compare against threshold value
|
||||
bool touchKeys[12];
|
||||
int16_t touchSum = 0;
|
||||
for (byte i = 0; i < 12; i++) {
|
||||
touchKeys[i] = readTouchKey(i) < calibration.ctouchThrVal;
|
||||
int16_t val = readTouchKey(i);
|
||||
touchKeys[i] = calibration.ctouchThrVal;
|
||||
touchSum += val;
|
||||
}
|
||||
|
||||
instrument.avgCTouchSignal = touchSum / 12;
|
||||
|
||||
// Valves and trill keys, TRUE (1) for pressed, FALSE (0) for not pressed
|
||||
byte K1 = touchKeys[K1Pin]; // Valve 1 (pitch change -2)
|
||||
byte K2 = touchKeys[K2Pin]; // Valve 2 (pitch change -1)
|
||||
|
@ -577,9 +589,9 @@ int readSwitches() {
|
|||
byte K6 = touchKeys[K6Pin]; // Trill key 2 (pitch change +1)
|
||||
byte K7 = touchKeys[K7Pin]; // Trill key 3 (pitch change +4)
|
||||
|
||||
state.pinkyKey = touchKeys[K8Pin];
|
||||
instrument.pinkyKey = touchKeys[K8Pin];
|
||||
|
||||
int qTransp = (state.pinkyKey && (currentPreset->pinkySetting < 25)) ? currentPreset->pinkySetting - 12 : 0;
|
||||
int qTransp = (instrument.pinkyKey && (currentPreset->pinkySetting < 25)) ? currentPreset->pinkySetting - 12 : 0;
|
||||
|
||||
// Calculate midi note number from pressed keys
|
||||
int fingeredNoteUntransposed = 0;
|
||||
|
@ -609,7 +621,7 @@ int readSwitches() {
|
|||
fingeredNoteUntransposed += 4;
|
||||
}
|
||||
|
||||
int fingeredNoteRead = fingeredNoteUntransposed + state.transpose - 12 + qTransp;
|
||||
int fingeredNoteRead = fingeredNoteUntransposed + instrument.transpose - 12 + qTransp;
|
||||
|
||||
if (fingeredNoteRead != lastFingering) { //
|
||||
// reset the debouncing timer
|
||||
|
@ -618,7 +630,7 @@ int readSwitches() {
|
|||
|
||||
if ((millis() - lastDeglitchTime) > currentPreset->deglitch) {
|
||||
// whatever the reading is at, it's been there for longer
|
||||
// than the debounce delay, so take it as the actual current state
|
||||
// than the debounce delay, so take it as the actual current instrument
|
||||
fingeredNote = fingeredNoteRead;
|
||||
}
|
||||
|
||||
|
@ -630,10 +642,10 @@ int readSwitches() {
|
|||
void noteOn(int fingeredNote, float pressureSensor, int initial_breath_value) {
|
||||
// Yes, so calculate MIDI note and velocity, then send a note on event
|
||||
// We should be at tonguing peak, so set velocity based on current pressureSensor value unless fixed velocity is set
|
||||
state.breathSignal = constrain(max(pressureSensor, initial_breath_value), state.breathThrVal, state.breathMaxVal);
|
||||
instrument.breathSignal = constrain(max(pressureSensor, initial_breath_value), instrument.breathThrVal, instrument.breathMaxVal);
|
||||
byte velocitySend;
|
||||
if (!currentPreset->fixedVelocity) {
|
||||
unsigned int breathValHires = breathCurve(mapConstrain(state.breathSignal, state.breathThrVal, state.breathMaxVal, 0, 16383));
|
||||
unsigned int breathValHires = breathCurve(mapConstrain(instrument.breathSignal, instrument.breathThrVal, instrument.breathMaxVal, 0, 16383));
|
||||
velocitySend = (breathValHires >> 7) & 0x007F;
|
||||
velocitySend = constrain(velocitySend + velocitySend * .1 * currentPreset->velBias, 1, 127);
|
||||
} else {
|
||||
|
@ -642,18 +654,18 @@ void noteOn(int fingeredNote, float pressureSensor, int initial_breath_value) {
|
|||
|
||||
breath(); // send breath data
|
||||
midiSendNoteOn(fingeredNote, velocitySend); // send Note On message for new note
|
||||
state.activeNote = fingeredNote;
|
||||
instrument.activeNote = fingeredNote;
|
||||
}
|
||||
|
||||
void handleOffStateActions() {
|
||||
if (state.activeMIDIchannel != currentPreset->MIDIchannel) {
|
||||
state.activeMIDIchannel = currentPreset->MIDIchannel; // only switch channel if no active note
|
||||
midiSetChannel(state.activeMIDIchannel);
|
||||
if (instrument.activeMIDIchannel != currentPreset->MIDIchannel) {
|
||||
instrument.activeMIDIchannel = currentPreset->MIDIchannel; // only switch channel if no active note
|
||||
midiSetChannel(instrument.activeMIDIchannel);
|
||||
}
|
||||
if ((state.activePatch != state.patch) && state.doPatchUpdate) {
|
||||
state.activePatch = state.patch;
|
||||
midiSendProgramChange(state.activePatch);
|
||||
state.doPatchUpdate = 0;
|
||||
if ((instrument.activePatch != instrument.patch) && instrument.doPatchUpdate) {
|
||||
instrument.activePatch = instrument.patch;
|
||||
midiSendProgramChange(instrument.activePatch);
|
||||
instrument.doPatchUpdate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -661,10 +673,10 @@ void handleOffStateActions() {
|
|||
Initialize the main instrument state
|
||||
*/
|
||||
void initState() {
|
||||
state.activePatch = 0;
|
||||
instrument.activePatch = 0;
|
||||
state.mainState = NOTE_OFF; // initialize main state machine
|
||||
|
||||
state.activeMIDIchannel = currentPreset->MIDIchannel;
|
||||
instrument.activeMIDIchannel = currentPreset->MIDIchannel;
|
||||
midiInitialize(currentPreset->MIDIchannel);
|
||||
}
|
||||
|
||||
|
@ -709,18 +721,18 @@ void runStateMachine() {
|
|||
int fingeredNote = noteValueCheck(readSwitches() + readOctave());
|
||||
if (state.mainState == NOTE_OFF) {
|
||||
handleOffStateActions();
|
||||
if ((state.breathSignal > state.breathThrVal)) {
|
||||
if ((instrument.breathSignal > instrument.breathThrVal)) {
|
||||
// Value has risen above threshold. Move to the RISE_WAIT
|
||||
// state. Record time and initial breath value.
|
||||
breath_on_time = millis();
|
||||
initial_breath_value = state.breathSignal;
|
||||
initial_breath_value = instrument.breathSignal;
|
||||
state.mainState = RISE_WAIT; // Go to next state
|
||||
}
|
||||
} else if (state.mainState == RISE_WAIT) {
|
||||
if ((state.breathSignal > state.breathThrVal)) {
|
||||
if ((instrument.breathSignal > instrument.breathThrVal)) {
|
||||
// Has enough time passed for us to collect our second sample?
|
||||
if ((millis() - breath_on_time > currentPreset->velSmpDl) || (0 == currentPreset->velSmpDl) || currentPreset->fixedVelocity) {
|
||||
noteOn(fingeredNote, state.breathSignal, initial_breath_value);
|
||||
noteOn(fingeredNote, instrument.breathSignal, initial_breath_value);
|
||||
state.mainState = NOTE_ON;
|
||||
}
|
||||
} else {
|
||||
|
@ -728,19 +740,19 @@ void runStateMachine() {
|
|||
state.mainState = NOTE_OFF;
|
||||
}
|
||||
} else if (state.mainState == NOTE_ON) {
|
||||
if ((state.breathSignal < state.breathThrVal)) {
|
||||
if ((instrument.breathSignal < instrument.breathThrVal)) {
|
||||
// Value has fallen below threshold - turn the note off
|
||||
midiSendNoteOff(state.activeNote); // send Note Off message
|
||||
state.breathSignal = 0;
|
||||
midiSendNoteOff(instrument.activeNote); // send Note Off message
|
||||
instrument.breathSignal = 0;
|
||||
state.mainState = NOTE_OFF;
|
||||
} else {
|
||||
if (fingeredNote != state.activeNote) {
|
||||
if (fingeredNote != instrument.activeNote) {
|
||||
// Player has moved to a new fingering while still blowing.
|
||||
// Send a note off for the current note and a note on for
|
||||
// the new note.
|
||||
noteOn(fingeredNote, state.breathSignal, 0);
|
||||
noteOn(fingeredNote, instrument.breathSignal, 0);
|
||||
delayMicroseconds(2000); // delay for midi recording fix
|
||||
midiSendNoteOff(state.activeNote); // send Note Off message
|
||||
midiSendNoteOff(instrument.activeNote); // send Note Off message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -748,16 +760,26 @@ void runStateMachine() {
|
|||
|
||||
void setup() {
|
||||
if (checkButtonState(DEBUG_CONFIG)) {
|
||||
Serial.begin(9600); // debug
|
||||
Serial.println("Debug Startup");
|
||||
}
|
||||
Serial.begin(9600); // debug
|
||||
Serial.println("Debug Startup");
|
||||
if (CrashReport) {
|
||||
while (!Serial) ; // wait for serial monitor open
|
||||
Serial.print(CrashReport);
|
||||
}
|
||||
|
||||
initHardware();
|
||||
delay(100);
|
||||
Serial.println(buttonState());
|
||||
bool factoryReset = checkButtonState(STARTUP_FACTORY_RESET);
|
||||
configManagementMode = checkButtonState(STARTUP_CONFIG);
|
||||
testMode = checkButtonState(TEST_CONFIG);
|
||||
|
||||
initDisplay(); // Start up display and show logo
|
||||
initHardware();
|
||||
|
||||
if (CrashReport) {
|
||||
displayError("CRASH WARNING");
|
||||
}
|
||||
|
||||
// If going into config management mode, stop here before we even touch the EEPROM.
|
||||
if (configManagementMode) {
|
||||
|
@ -766,24 +788,25 @@ void setup() {
|
|||
}
|
||||
|
||||
// Read eeprom data into global vars
|
||||
readEEPROM(factoryReset);
|
||||
// readEEPROM(factoryReset);
|
||||
|
||||
statusLedFlash(500);
|
||||
statusLedOff();
|
||||
|
||||
if (factoryReset) {
|
||||
// Full calibration
|
||||
fullAutoCal();
|
||||
// fullAutoCal();
|
||||
} else {
|
||||
// Minimal startup calibration (atmo pressure)
|
||||
autoCal();
|
||||
// autoCal();
|
||||
}
|
||||
|
||||
showVersion();
|
||||
delay(1000);
|
||||
|
||||
initState(); // Set up midi/etc
|
||||
// initState(); // Set up midi/etc
|
||||
statusLedOn(); // Switch on the onboard LED to indicate power on/ready
|
||||
displayOff();
|
||||
}
|
||||
|
||||
//_______________________________________________________________________________________________ MAIN LOOP
|
||||
|
@ -792,6 +815,9 @@ void loop() {
|
|||
static unsigned long pixelUpdateTime = 0;
|
||||
static const unsigned long pixelUpdateInterval = 80;
|
||||
|
||||
handleMenu(state, false);
|
||||
return;
|
||||
|
||||
// If in config mgmt loop, do that and nothing else
|
||||
if (configManagementMode) {
|
||||
configModeLoop();
|
||||
|
@ -799,10 +825,11 @@ void loop() {
|
|||
}
|
||||
|
||||
if (testMode) {
|
||||
|
||||
handleTestMode();
|
||||
return;
|
||||
}
|
||||
|
||||
state.breathSignal = constrain(readPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT); // Get the filtered pressure sensor reading from analog pin A0, input from sensor MP3V5004GP
|
||||
instrument.breathSignal = constrain(readPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT); // Get the filtered pressure sensor reading from analog pin A0, input from sensor MP3V5004GP
|
||||
|
||||
runStateMachine();
|
||||
sendCCs();
|
||||
|
@ -815,9 +842,9 @@ void loop() {
|
|||
// this is one of the big reasons the display is for setup use only
|
||||
// TODO: is this still true on teensy 4?
|
||||
pixelUpdateTime = millis();
|
||||
handleMenu(true);
|
||||
handleMenu(state, true);
|
||||
} else {
|
||||
handleMenu(false);
|
||||
handleMenu(state, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue