Menu system fixes; made state less global

This commit is contained in:
Brian Hrebec 2023-08-29 13:32:56 -05:00
parent cfc2390b8b
commit 209959e2de
14 changed files with 964 additions and 731 deletions

View file

@ -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);
}
}