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
|
@ -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