|
|
|
@ -12,6 +12,7 @@
|
|
|
|
|
#include "settings.h"
|
|
|
|
|
#include "led.h"
|
|
|
|
|
#include "test.h"
|
|
|
|
|
#include "FilterOnePole.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
NAME: xEVI
|
|
|
|
@ -30,13 +31,13 @@ FUNCTION: EVI Wind Controller using MPRLS pressure sensors and capac
|
|
|
|
|
|
|
|
|
|
preset_t presets[PRESET_COUNT];
|
|
|
|
|
instrument_state_t instrument;
|
|
|
|
|
preset_t *currentPreset = &presets[0];
|
|
|
|
|
calibration_t calibration;
|
|
|
|
|
state_t state = {
|
|
|
|
|
NOTE_OFF,
|
|
|
|
|
&instrument,
|
|
|
|
|
currentPreset,
|
|
|
|
|
&presets[0],
|
|
|
|
|
&calibration,
|
|
|
|
|
0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const int pbDepthList[13] = { 8192, 8192, 4096, 2731, 2048, 1638, 1365, 1170, 1024, 910, 819, 744, 683 };
|
|
|
|
@ -90,6 +91,8 @@ const int trumpetHarmonic[2][7] = { {0, 7, 12, 16, 19, 26, 31}, //! K4: hrm 8->
|
|
|
|
|
bool configManagementMode = false;
|
|
|
|
|
bool testMode = false;
|
|
|
|
|
|
|
|
|
|
FilterOnePole breathCCFilter;
|
|
|
|
|
|
|
|
|
|
//_______________________________________________________________________________________________ SETUP
|
|
|
|
|
|
|
|
|
|
// MIDI note value check with out of range octave repeat
|
|
|
|
@ -109,7 +112,7 @@ void port(int portCC) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (currentPreset->portamentoMode == PortamentoMode::PON || currentPreset->portamentoMode == PortamentoMode::PGLIDE_ONLY) {
|
|
|
|
|
if (state.currentPreset->portamentoMode == PortamentoMode::PON || state.currentPreset->portamentoMode == PortamentoMode::PGLIDE_ONLY) {
|
|
|
|
|
if (instrument.portamentoVal > 0 && portCC == 0) {
|
|
|
|
|
midiSendControlChange(CCN_PortOnOff, 0);
|
|
|
|
|
} else if (instrument.portamentoVal == 0 && portCC > 0) {
|
|
|
|
@ -158,12 +161,12 @@ void cvUpdate() {
|
|
|
|
|
instrument.cvPitch = instrument.targetPitch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (currentPreset->cvVibRate) {
|
|
|
|
|
int timeDivider = timeDividerList[currentPreset->cvVibRate];
|
|
|
|
|
if (state.currentPreset->cvVibRate) {
|
|
|
|
|
int timeDivider = timeDividerList[state.currentPreset->cvVibRate];
|
|
|
|
|
int cvVib = map(((waveformsTable[map(currentTime % timeDivider, 0, timeDivider, 0, maxSamplesNum - 1)] - 2047)), -259968, 259969, -11, 11);
|
|
|
|
|
instrument.cvPitch += cvVib;
|
|
|
|
|
}
|
|
|
|
|
int cvPitchTuned = 2 * (currentPreset->cvTune) + map(instrument.cvPitch, 0, 4032, 0, 4032 + 2 * (currentPreset->cvScale));
|
|
|
|
|
int cvPitchTuned = 2 * (state.currentPreset->cvTune) + map(instrument.cvPitch, 0, 4032, 0, 4032 + 2 * (state.currentPreset->cvScale));
|
|
|
|
|
analogWrite(cvPitchPin, constrain(cvPitchTuned, 0, 4095));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -197,9 +200,12 @@ unsigned int multiMap(unsigned short val, const unsigned short* _in, const unsig
|
|
|
|
|
|
|
|
|
|
// map breath values to selected curve
|
|
|
|
|
unsigned int breathCurve(unsigned int inputVal) {
|
|
|
|
|
if (currentPreset->breathCurve >= curves.size())
|
|
|
|
|
|
|
|
|
|
if (state.currentPreset->breathCurve >= curves.size()) {
|
|
|
|
|
return inputVal;
|
|
|
|
|
return multiMap(inputVal, curveIn, curves[currentPreset->breathCurve], 17);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return multiMap(inputVal, curveIn, curves[state.currentPreset->breathCurve], 17);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//**************************************************************
|
|
|
|
@ -217,14 +223,15 @@ int breath() {
|
|
|
|
|
int breathCCval, breathCCvalFine;
|
|
|
|
|
unsigned int breathCCvalHires;
|
|
|
|
|
breathCCvalHires = breathCurve(mapConstrain(instrument.breathSignal, instrument.breathThrVal, instrument.breathMaxVal, 0, 16383));
|
|
|
|
|
breathCCvalHires = breathCCFilter.input(breathCCvalHires);
|
|
|
|
|
breathCCval = (breathCCvalHires >> 7) & 0x007F;
|
|
|
|
|
breathCCvalFine = breathCCvalHires & 0x007F;
|
|
|
|
|
if (breathCCval != oldbreath) { // only send midi data if breath has changed from previous value
|
|
|
|
|
if (currentPreset->breathCC) {
|
|
|
|
|
if (state.currentPreset->breathCC) {
|
|
|
|
|
// send midi cc
|
|
|
|
|
midiSendControlChange(currentPreset->breathCC, breathCCval);
|
|
|
|
|
midiSendControlChange(state.currentPreset->breathCC, breathCCval);
|
|
|
|
|
}
|
|
|
|
|
if (currentPreset->breathMode == BreathMode::BREATH_AT || currentPreset->breathMode == BreathMode::BREATH_LSB_AT) {
|
|
|
|
|
if (state.currentPreset->breathMode == BreathMode::BREATH_AT || state.currentPreset->breathMode == BreathMode::BREATH_LSB_AT) {
|
|
|
|
|
// send aftertouch
|
|
|
|
|
midiSendAfterTouch(breathCCval);
|
|
|
|
|
}
|
|
|
|
@ -232,8 +239,8 @@ int breath() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (breathCCvalHires != oldbreathhires
|
|
|
|
|
&& (currentPreset->breathMode == BreathMode::BREATH_LSB || currentPreset->breathMode == BreathMode::BREATH_LSB_AT)) {
|
|
|
|
|
midiSendControlChange(currentPreset->breathCC + 32, breathCCvalFine);
|
|
|
|
|
&& (state.currentPreset->breathMode == BreathMode::BREATH_LSB || state.currentPreset->breathMode == BreathMode::BREATH_LSB_AT)) {
|
|
|
|
|
midiSendControlChange(state.currentPreset->breathCC + 32, breathCCvalFine);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oldbreathhires = breathCCvalHires;
|
|
|
|
@ -253,33 +260,31 @@ void pitch_bend() {
|
|
|
|
|
byte pbTouched = 0;
|
|
|
|
|
int vibRead = 0;
|
|
|
|
|
int vibReadBite = 0;
|
|
|
|
|
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)
|
|
|
|
|
bool halfPitchBendKey = (state.currentPreset->pinkySetting == PBD) && instrument.pinkyKey; // hold pinky key for 1/2 pitchbend value
|
|
|
|
|
instrument.quarterToneTrigger = (state.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];
|
|
|
|
|
calculatedPBdepth = pbDepthList[state.currentPreset->PBdepth];
|
|
|
|
|
if (halfPitchBendKey)
|
|
|
|
|
calculatedPBdepth = calculatedPBdepth * 0.5;
|
|
|
|
|
|
|
|
|
|
vibMax = vibMaxList[currentPreset->vibSens - 1];
|
|
|
|
|
vibMax = vibMaxList[state.currentPreset->vibSens - 1];
|
|
|
|
|
|
|
|
|
|
float calculatedDepth = 0;
|
|
|
|
|
if (currentPreset->vibratoMode == VibratoMode::VSTART_DOWN) {
|
|
|
|
|
calculatedDepth = calculatedPBdepth * vibDepth[currentPreset->vibratoDepth];
|
|
|
|
|
if (state.currentPreset->vibratoMode == VibratoMode::VSTART_DOWN) {
|
|
|
|
|
calculatedDepth = calculatedPBdepth * vibDepth[state.currentPreset->vibratoDepth];
|
|
|
|
|
} else {
|
|
|
|
|
calculatedDepth = (0 - calculatedPBdepth * vibDepth[currentPreset->vibratoDepth]);
|
|
|
|
|
calculatedDepth = (0 - calculatedPBdepth * vibDepth[state.currentPreset->vibratoDepth]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ExtraControl::VIBRATO == currentPreset->biteControl) { // bite vibrato
|
|
|
|
|
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 (ExtraControl::VIBRATO == state.currentPreset->biteControl) { // bite vibrato
|
|
|
|
|
vibMaxBite = vibMaxBiteList[state.currentPreset->vibSens - 1];
|
|
|
|
|
vibReadBite = instrument.biteSignal;
|
|
|
|
|
|
|
|
|
|
if (vibReadBite < instrument.vibThrBite) {
|
|
|
|
|
if (vibReadBite > instrument.vibThrBite) {
|
|
|
|
|
instrument.vibSignal = (instrument.vibSignal + mapConstrain(
|
|
|
|
|
vibReadBite, (instrument.vibZeroBite - vibMaxBite), instrument.vibThrBite, calculatedDepth, 0)
|
|
|
|
|
) / 2;
|
|
|
|
|
} else if (vibReadBite > instrument.vibThrBiteLo) {
|
|
|
|
|
} else if (vibReadBite < instrument.vibThrBiteLo) {
|
|
|
|
|
instrument.vibSignal = (instrument.vibSignal + mapConstrain(
|
|
|
|
|
vibReadBite, (instrument.vibZeroBite + vibMaxBite), instrument.vibThrBite, calculatedDepth, 0)
|
|
|
|
|
) / 2;
|
|
|
|
@ -288,13 +293,13 @@ void pitch_bend() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ExtraControl::VIBRATO == currentPreset->leverControl) { // lever vibrato
|
|
|
|
|
vibRead = readTouchUtil(vibratoPin);
|
|
|
|
|
if (vibRead < instrument.vibThr) {
|
|
|
|
|
if (ExtraControl::VIBRATO == state.currentPreset->leverControl) { // lever vibrato
|
|
|
|
|
vibRead = instrument.leverSignal;
|
|
|
|
|
if (vibRead > instrument.vibThr) {
|
|
|
|
|
instrument.vibSignal = (instrument.vibSignal +
|
|
|
|
|
mapConstrain(vibRead, (instrument.vibZero - vibMax), instrument.vibThr, calculatedDepth, 0)
|
|
|
|
|
) / 2;
|
|
|
|
|
} else if (vibRead > instrument.vibThrLo) {
|
|
|
|
|
} else if (vibRead < instrument.vibThrLo) {
|
|
|
|
|
instrument.vibSignal = (instrument.vibSignal +
|
|
|
|
|
mapConstrain(vibRead, (instrument.vibZero + vibMax), instrument.vibThr, calculatedDepth, 0)
|
|
|
|
|
) / 2;
|
|
|
|
@ -303,7 +308,7 @@ void pitch_bend() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (currentPreset->vibRetn) { // moving baseline
|
|
|
|
|
switch (state.currentPreset->vibRetn) { // moving baseline
|
|
|
|
|
case 0:
|
|
|
|
|
// keep vibZero value
|
|
|
|
|
break;
|
|
|
|
@ -323,16 +328,18 @@ void pitch_bend() {
|
|
|
|
|
instrument.vibZero = instrument.vibZero * 0.6 + vibRead * 0.4;
|
|
|
|
|
instrument.vibZeroBite = instrument.vibZeroBite * 0.6 + vibReadBite * 0.4;
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
instrument.vibThr = instrument.vibZero + state.currentPreset->vibSquelch;
|
|
|
|
|
instrument.vibThrLo = instrument.vibZero - state.currentPreset->vibSquelch;
|
|
|
|
|
instrument.vibThrBite = instrument.vibZeroBite + state.currentPreset->vibSquelch;
|
|
|
|
|
instrument.vibThrBiteLo = instrument.vibZeroBite - state.currentPreset->vibSquelch;
|
|
|
|
|
|
|
|
|
|
// PB calculation
|
|
|
|
|
int pbPos = mapConstrain(instrument.pbUpSignal, calibration.pbUpThrVal, calibration.pbUpMaxVal, calculatedPBdepth, 0);
|
|
|
|
|
int pbNeg = mapConstrain(instrument.pbDnSignal, calibration.pbDnThrVal, calibration.pbDnMaxVal, calculatedPBdepth, 0);
|
|
|
|
|
int pbSum = 8193 + pbPos - pbNeg;
|
|
|
|
|
int pbDif = abs(pbPos - pbNeg);
|
|
|
|
|
|
|
|
|
|
if ((instrument.pbUpSignal < calibration.pbUpThrVal || instrument.pbDnSignal < calibration.pbDnThrVal) && currentPreset->PBdepth) {
|
|
|
|
|
if ((instrument.pbUpSignal > calibration.pbUpThrVal || instrument.pbDnSignal > calibration.pbDnThrVal) && state.currentPreset->PBdepth) {
|
|
|
|
|
if (pbDif < 10) {
|
|
|
|
|
instrument.pitchBend = 8192;
|
|
|
|
|
} else {
|
|
|
|
@ -361,93 +368,127 @@ void pitch_bend() {
|
|
|
|
|
//***********************************************************
|
|
|
|
|
|
|
|
|
|
void portamento_() {
|
|
|
|
|
if (currentPreset->portamentoMode == PortamentoMode::POFF) {
|
|
|
|
|
if (state.currentPreset->portamentoMode == PortamentoMode::POFF) {
|
|
|
|
|
port(0); // ensure it's off
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int portSumCC = 0;
|
|
|
|
|
if (currentPreset->pinkySetting == GLD) {
|
|
|
|
|
if (state.currentPreset->pinkySetting == GLD) {
|
|
|
|
|
if (instrument.pinkyKey) {
|
|
|
|
|
portSumCC += currentPreset->portamentoLimit;
|
|
|
|
|
portSumCC += state.currentPreset->portamentoLimit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ExtraControl::GLIDE == currentPreset->biteControl) {
|
|
|
|
|
if (ExtraControl::GLIDE == state.currentPreset->biteControl) {
|
|
|
|
|
// Portamento is controlled with the bite sensor in the mouthpiece
|
|
|
|
|
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);
|
|
|
|
|
portSumCC += mapConstrain(instrument.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, 0, state.currentPreset->portamentoLimit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ExtraControl::GLIDE == currentPreset->leverControl) {
|
|
|
|
|
if (ExtraControl::GLIDE == state.currentPreset->leverControl) {
|
|
|
|
|
// Portamento is controlled with thumb lever
|
|
|
|
|
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);
|
|
|
|
|
portSumCC += mapConstrain((3000 - instrument.leverSignal), calibration.leverThrVal, calibration.leverMaxVal, 0, state.currentPreset->portamentoLimit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
port(constrain(portSumCC, 0, currentPreset->portamentoLimit)); // Total output glide rate limited to glide max setting
|
|
|
|
|
port(constrain(portSumCC, 0, state.currentPreset->portamentoLimit)); // Total output glide rate limited to glide max setting
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***********************************************************
|
|
|
|
|
|
|
|
|
|
void biteCC_() {
|
|
|
|
|
void sendCC() {
|
|
|
|
|
int biteVal = 0;
|
|
|
|
|
if (ExtraControl::CC == currentPreset->biteControl) {
|
|
|
|
|
instrument.biteSignal = readTouchUtil(bitePin); // get sensor data, do some smoothing - SENSOR PIN 17 - PCB PINS LABELED "BITE" (GND left, sensor pin right)
|
|
|
|
|
if (ExtraControl::CC == state.currentPreset->biteControl) {
|
|
|
|
|
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 != instrument.biteVal) {
|
|
|
|
|
midiSendControlChange(currentPreset->biteCC, biteVal);
|
|
|
|
|
midiSendControlChange(state.currentPreset->biteCC, biteVal);
|
|
|
|
|
}
|
|
|
|
|
instrument.biteVal = biteVal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int extraVal = 0;
|
|
|
|
|
if (ExtraControl::CC == state.currentPreset->extraControl) {
|
|
|
|
|
if (instrument.extraSignal >= calibration.extraThrVal) { // we are over the threshold, calculate CC value
|
|
|
|
|
extraVal = mapConstrain(instrument.extraSignal, calibration.extraThrVal, calibration.extraMaxVal, 0, 127);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (extraVal != instrument.extraVal) {
|
|
|
|
|
midiSendControlChange(state.currentPreset->extraCC, extraVal);
|
|
|
|
|
}
|
|
|
|
|
instrument.extraVal = extraVal;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void autoCal() {
|
|
|
|
|
instrument.vibZero = instrument.vibZeroBite = 0;
|
|
|
|
|
for(int i = 1 ; i <= CALIBRATE_SAMPLE_COUNT; ++i) {
|
|
|
|
|
instrument.breathZero += readPressure();
|
|
|
|
|
instrument.breathAltZero += readAltPressure();
|
|
|
|
|
instrument.vibZero += readTouchUtil(vibratoPin);
|
|
|
|
|
instrument.vibZeroBite += readTouchUtil(bitePin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
instrument.breathZero /= CALIBRATE_SAMPLE_COUNT;
|
|
|
|
|
instrument.breathAltZero /= CALIBRATE_SAMPLE_COUNT;
|
|
|
|
|
instrument.vibZero /= CALIBRATE_SAMPLE_COUNT;
|
|
|
|
|
instrument.vibZeroBite /= CALIBRATE_SAMPLE_COUNT;
|
|
|
|
|
|
|
|
|
|
instrument.vibThr = instrument.vibZero - currentPreset->vibSquelch;
|
|
|
|
|
instrument.vibThrLo = instrument.vibZero + currentPreset->vibSquelch;
|
|
|
|
|
instrument.vibThrBite = instrument.vibZeroBite - currentPreset->vibSquelch;
|
|
|
|
|
instrument.vibThrBiteLo = instrument.vibZeroBite + currentPreset->vibSquelch;
|
|
|
|
|
// Re-zero floating calibration values
|
|
|
|
|
void rezero() {
|
|
|
|
|
instrument.vibThr = instrument.vibZero + state.currentPreset->vibSquelch;
|
|
|
|
|
instrument.vibThrLo = instrument.vibZero - state.currentPreset->vibSquelch;
|
|
|
|
|
instrument.vibThrBite = instrument.vibZeroBite + state.currentPreset->vibSquelch;
|
|
|
|
|
instrument.vibThrBiteLo = instrument.vibZeroBite - state.currentPreset->vibSquelch;
|
|
|
|
|
|
|
|
|
|
instrument.breathThrVal = instrument.breathZero + calibration.breathThrValOffset;
|
|
|
|
|
instrument.breathMaxVal = instrument.breathThrVal + calibration.breathMaxValOffset;
|
|
|
|
|
instrument.breathAltThrVal = instrument.breathAltZero + calibration.breathAltThrValOffset;
|
|
|
|
|
instrument.breathAltMaxVal = instrument.breathAltThrVal + calibration.breathAltMaxValOffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void autoCal() {
|
|
|
|
|
instrument.vibZero = instrument.vibZeroBite = 0;
|
|
|
|
|
long int bZero = 0;
|
|
|
|
|
long int bAltZero = 0;
|
|
|
|
|
for(int i = 1 ; i <= CALIBRATE_SAMPLE_COUNT; ++i) {
|
|
|
|
|
bZero += readPressure();
|
|
|
|
|
bAltZero += readAltPressure();
|
|
|
|
|
instrument.vibZero += readTouchUtil(leverPin);
|
|
|
|
|
instrument.vibZeroBite += readTouchUtil(bitePin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
instrument.breathZero = bZero / CALIBRATE_SAMPLE_COUNT;
|
|
|
|
|
instrument.breathAltZero = bAltZero / CALIBRATE_SAMPLE_COUNT;
|
|
|
|
|
instrument.vibZero /= CALIBRATE_SAMPLE_COUNT;
|
|
|
|
|
instrument.vibZeroBite /= CALIBRATE_SAMPLE_COUNT;
|
|
|
|
|
|
|
|
|
|
rezero();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void fullAutoCal() {
|
|
|
|
|
int calRead;
|
|
|
|
|
int calReadNext;
|
|
|
|
|
|
|
|
|
|
calibration.breathAltThrValOffset = 5;
|
|
|
|
|
calibration.breathAltMaxValOffset = 1500 ;
|
|
|
|
|
calibration.breathThrValOffset = 5;
|
|
|
|
|
calibration.breathMaxValOffset = 1500 ;
|
|
|
|
|
autoCal();
|
|
|
|
|
|
|
|
|
|
// Lever
|
|
|
|
|
calRead = 3000 - readTouchUtil(vibratoPin);
|
|
|
|
|
calibration.leverThrVal = constrain(calRead + 60, LEVER_LO_LIMIT, LEVER_HI_LIMIT);
|
|
|
|
|
calibration.leverMaxVal = constrain(calRead + 120, LEVER_LO_LIMIT, LEVER_HI_LIMIT);
|
|
|
|
|
calRead = readTouchUtil(leverPin);
|
|
|
|
|
calibration.leverThrVal = constrain(calRead + 100, LEVER_LO_LIMIT, LEVER_HI_LIMIT);
|
|
|
|
|
calibration.leverMaxVal = constrain(calRead + 300, LEVER_LO_LIMIT, LEVER_HI_LIMIT);
|
|
|
|
|
|
|
|
|
|
// Extra
|
|
|
|
|
calRead = readTouchUtil(extraPin);
|
|
|
|
|
calibration.extraThrVal = constrain(calRead + 100, EXTRA_LO_LIMIT, EXTRA_HI_LIMIT);
|
|
|
|
|
calibration.extraMaxVal = constrain(calRead + 300, EXTRA_LO_LIMIT, EXTRA_HI_LIMIT);
|
|
|
|
|
|
|
|
|
|
// Bite sensor
|
|
|
|
|
calRead = readTouchUtil(bitePin);
|
|
|
|
|
calibration.biteThrVal = constrain(calRead + 100, BITE_LO_LIMIT, BITE_HI_LIMIT);
|
|
|
|
|
calibration.biteMaxVal = constrain(calibration.biteThrVal + 300, BITE_LO_LIMIT, BITE_HI_LIMIT);
|
|
|
|
|
calibration.biteMaxVal = constrain(calRead + 300, BITE_LO_LIMIT, BITE_HI_LIMIT);
|
|
|
|
|
|
|
|
|
|
// PB
|
|
|
|
|
calRead = readTouchUtil(pbDnPin);
|
|
|
|
|
calibration.pbDnThrVal = constrain(calRead + 100, BITE_LO_LIMIT, BITE_HI_LIMIT);
|
|
|
|
|
calibration.pbDnMaxVal = constrain(calRead + 300, BITE_LO_LIMIT, BITE_HI_LIMIT);
|
|
|
|
|
|
|
|
|
|
calRead = readTouchUtil(pbUpPin);
|
|
|
|
|
calibration.pbUpThrVal = constrain(calRead + 100, BITE_LO_LIMIT, BITE_HI_LIMIT);
|
|
|
|
|
calibration.pbUpMaxVal = constrain(calRead + 300, BITE_LO_LIMIT, BITE_HI_LIMIT);
|
|
|
|
|
|
|
|
|
|
// Touch sensors
|
|
|
|
|
calRead = CTOUCH_HI_LIMIT;
|
|
|
|
@ -457,7 +498,7 @@ void fullAutoCal() {
|
|
|
|
|
calRead = calReadNext; // use lowest value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
calibration.ctouchThrVal = calRead - 20;
|
|
|
|
|
calibration.ctouchThrVal = calRead + 50;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***********************************************************
|
|
|
|
@ -467,6 +508,9 @@ void fullAutoCal() {
|
|
|
|
|
*/
|
|
|
|
|
int readOctave() {
|
|
|
|
|
static byte lastOctaveR = 0;
|
|
|
|
|
static unsigned long lastDeglitchTime = 0; // The last time the fingering was changed
|
|
|
|
|
static unsigned long lastOctave = 0; // The last time the fingering was changed
|
|
|
|
|
static unsigned long fingeredOctave = 0; // The last time the fingering was changed
|
|
|
|
|
|
|
|
|
|
// Roller modes
|
|
|
|
|
// 1: Highest touched roller, release memory
|
|
|
|
@ -475,20 +519,20 @@ int readOctave() {
|
|
|
|
|
// 4: Touched roller pair, extend range
|
|
|
|
|
// 5: Touched roller, pair = 5th partial
|
|
|
|
|
// 6: Touched roller, pair = 5th partial, extend range
|
|
|
|
|
RollerMode rollerMode = currentPreset->rollerMode;
|
|
|
|
|
byte extend = rollerMode == RollerMode::HIGHEST_EXTEND || rollerMode == RollerMode::HIGHEST_PAIR_EXTEND || rollerMode == RollerMode::PARTIAL_EXTEND ? 1 : 0;
|
|
|
|
|
RollerMode rollerMode = state.currentPreset->rollerMode;
|
|
|
|
|
bool extend = rollerMode == RollerMode::HIGHEST_EXTEND || rollerMode == RollerMode::HIGHEST_PAIR_EXTEND || rollerMode == RollerMode::PARTIAL_EXTEND ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
byte rollers[6];
|
|
|
|
|
bool rollers[6];
|
|
|
|
|
uint16_t ctouchThrVal = calibration.ctouchThrVal;
|
|
|
|
|
rollers[0] = readTouchUtil(R1Pin) < ctouchThrVal;
|
|
|
|
|
rollers[1] = readTouchUtil(R2Pin) < ctouchThrVal;
|
|
|
|
|
rollers[2] = readTouchUtil(R3Pin) < ctouchThrVal;
|
|
|
|
|
rollers[3] = readTouchUtil(R4Pin) < ctouchThrVal;
|
|
|
|
|
rollers[4] = readTouchUtil(R5Pin) < ctouchThrVal;
|
|
|
|
|
rollers[5] = readTouchUtil(R6Pin) < ctouchThrVal;
|
|
|
|
|
rollers[0] = readTouchUtil(R1Pin) > ctouchThrVal;
|
|
|
|
|
rollers[1] = readTouchUtil(R2Pin) > ctouchThrVal;
|
|
|
|
|
rollers[2] = readTouchUtil(R3Pin) > ctouchThrVal;
|
|
|
|
|
rollers[3] = readTouchUtil(R4Pin) > ctouchThrVal;
|
|
|
|
|
rollers[4] = readTouchUtil(R5Pin) > ctouchThrVal;
|
|
|
|
|
rollers[5] = readTouchUtil(R6Pin) > ctouchThrVal;
|
|
|
|
|
|
|
|
|
|
byte offset = 0;
|
|
|
|
|
byte octaveR = 0;
|
|
|
|
|
int offset = 0;
|
|
|
|
|
int octaveR = 0;
|
|
|
|
|
if (rollerMode == RollerMode::HIGHEST || rollerMode == RollerMode::HIGHEST_EXTEND) {
|
|
|
|
|
for (int i = 5; i >= 0; i--) {
|
|
|
|
|
if (rollers[i]) {
|
|
|
|
@ -550,17 +594,32 @@ int readOctave() {
|
|
|
|
|
|
|
|
|
|
lastOctaveR = octaveR;
|
|
|
|
|
|
|
|
|
|
FingeringMode fingering = currentPreset->fingering;
|
|
|
|
|
int octave = 0;
|
|
|
|
|
|
|
|
|
|
FingeringMode fingering = state.currentPreset->fingering;
|
|
|
|
|
byte K4 = readTouchKey(K4Pin) < calibration.ctouchThrVal;
|
|
|
|
|
if (FingeringMode::TPT == fingering) { // TPT fingering
|
|
|
|
|
return 24 + offset + trumpetHarmonic[K4][octaveR]; // roller harmonics
|
|
|
|
|
octave = 24 + offset + trumpetHarmonic[K4][octaveR]; // roller harmonics
|
|
|
|
|
} else if (FingeringMode::HRN == fingering) { // HRN fingering
|
|
|
|
|
return 12 + offset + rollerHarmonic[K4][octaveR]; // roller harmonics
|
|
|
|
|
octave = 12 + offset + rollerHarmonic[K4][octaveR]; // roller harmonics
|
|
|
|
|
} else if (FingeringMode::EVR == fingering) { // HRN fingering
|
|
|
|
|
return 12 * (6 - octaveR) + offset + instrument.octave;
|
|
|
|
|
octave = 12 * (6 - octaveR) + offset + instrument.octave * 12;
|
|
|
|
|
} else { // EVI
|
|
|
|
|
return 12 * octaveR + offset + instrument.octave;
|
|
|
|
|
octave = 12 * octaveR + offset + instrument.octave * 12;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (octave != lastOctave) { //
|
|
|
|
|
// reset the debouncing timer
|
|
|
|
|
lastDeglitchTime = millis();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((millis() - lastDeglitchTime) > state.currentPreset->deglitch) {
|
|
|
|
|
fingeredOctave = octave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastOctave = octave;
|
|
|
|
|
|
|
|
|
|
return fingeredOctave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int readSwitches() {
|
|
|
|
@ -574,7 +633,7 @@ int readSwitches() {
|
|
|
|
|
int16_t touchSum = 0;
|
|
|
|
|
for (byte i = 0; i < 12; i++) {
|
|
|
|
|
int16_t val = readTouchKey(i);
|
|
|
|
|
touchKeys[i] = calibration.ctouchThrVal;
|
|
|
|
|
touchKeys[i] = val > calibration.ctouchThrVal;
|
|
|
|
|
touchSum += val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -591,31 +650,31 @@ int readSwitches() {
|
|
|
|
|
|
|
|
|
|
instrument.pinkyKey = touchKeys[K8Pin];
|
|
|
|
|
|
|
|
|
|
int qTransp = (instrument.pinkyKey && (currentPreset->pinkySetting < 25)) ? currentPreset->pinkySetting - 12 : 0;
|
|
|
|
|
int qTransp = (instrument.pinkyKey && (state.currentPreset->pinkySetting < 25)) ? state.currentPreset->pinkySetting - 12 : 0;
|
|
|
|
|
|
|
|
|
|
// Calculate midi note number from pressed keys
|
|
|
|
|
int fingeredNoteUntransposed = 0;
|
|
|
|
|
if (EVI == currentPreset->fingering) { // EVI fingering
|
|
|
|
|
if (EVI == state.currentPreset->fingering) { // EVI fingering
|
|
|
|
|
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves"
|
|
|
|
|
- 5 * K4 // Fifth key
|
|
|
|
|
+ 2 * K5 + K6 + currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
|
|
|
|
} else if (EVR == currentPreset->fingering) { // EVR fingering
|
|
|
|
|
+ 2 * K5 + K6 + state.currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
|
|
|
|
} else if (EVR == state.currentPreset->fingering) { // EVR fingering
|
|
|
|
|
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves"
|
|
|
|
|
- 5 * K4 // Fifth key
|
|
|
|
|
+ 2 * K5 + K6 + currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
|
|
|
|
} else if (TPT == currentPreset->fingering) { // TPT fingering
|
|
|
|
|
+ 2 * K5 + K6 + state.currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
|
|
|
|
} else if (TPT == state.currentPreset->fingering) { // TPT fingering
|
|
|
|
|
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves"
|
|
|
|
|
- 2 // Trumpet in B flat
|
|
|
|
|
+ 2 * K5 + K6 + currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
|
|
|
|
} else if (HRN == currentPreset->fingering) { // HRN fingering
|
|
|
|
|
+ 2 * K5 + K6 + state.currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
|
|
|
|
} else if (HRN == state.currentPreset->fingering) { // HRN fingering
|
|
|
|
|
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves"
|
|
|
|
|
+ 5 * K4 // Switch to Bb horn
|
|
|
|
|
+ 5 // Horn in F
|
|
|
|
|
+ 2 * K5 + K6 + currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
|
|
|
|
+ 2 * K5 + K6 + state.currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (K3 && K7) {
|
|
|
|
|
if (4 == currentPreset->trill3_interval)
|
|
|
|
|
if (4 == state.currentPreset->trill3_interval)
|
|
|
|
|
fingeredNoteUntransposed += 2;
|
|
|
|
|
else
|
|
|
|
|
fingeredNoteUntransposed += 4;
|
|
|
|
@ -628,7 +687,7 @@ int readSwitches() {
|
|
|
|
|
lastDeglitchTime = millis();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((millis() - lastDeglitchTime) > currentPreset->deglitch) {
|
|
|
|
|
if ((millis() - lastDeglitchTime) > state.currentPreset->deglitch) {
|
|
|
|
|
// whatever the reading is at, it's been there for longer
|
|
|
|
|
// than the debounce delay, so take it as the actual current instrument
|
|
|
|
|
fingeredNote = fingeredNoteRead;
|
|
|
|
@ -639,27 +698,26 @@ int readSwitches() {
|
|
|
|
|
return fingeredNote;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void noteOn(int fingeredNote, float pressureSensor, int initial_breath_value) {
|
|
|
|
|
void noteOn(int fingeredNote, int 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
|
|
|
|
|
instrument.breathSignal = constrain(max(pressureSensor, initial_breath_value), instrument.breathThrVal, instrument.breathMaxVal);
|
|
|
|
|
byte velocitySend;
|
|
|
|
|
if (!currentPreset->fixedVelocity) {
|
|
|
|
|
if (!state.currentPreset->fixedVelocity) {
|
|
|
|
|
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);
|
|
|
|
|
velocitySend = constrain(velocitySend + velocitySend * .1 * state.currentPreset->velBias, 1, 127);
|
|
|
|
|
} else {
|
|
|
|
|
velocitySend = currentPreset->fixedVelocity;
|
|
|
|
|
velocitySend = state.currentPreset->fixedVelocity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
breath(); // send breath data
|
|
|
|
|
midiSendNoteOn(fingeredNote, velocitySend); // send Note On message for new note
|
|
|
|
|
instrument.activeNote = fingeredNote;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handleOffStateActions() {
|
|
|
|
|
if (instrument.activeMIDIchannel != currentPreset->MIDIchannel) {
|
|
|
|
|
instrument.activeMIDIchannel = currentPreset->MIDIchannel; // only switch channel if no active note
|
|
|
|
|
if (instrument.activeMIDIchannel != state.currentPreset->MIDIchannel) {
|
|
|
|
|
instrument.activeMIDIchannel = state.currentPreset->MIDIchannel; // only switch channel if no active note
|
|
|
|
|
midiSetChannel(instrument.activeMIDIchannel);
|
|
|
|
|
}
|
|
|
|
|
if ((instrument.activePatch != instrument.patch) && instrument.doPatchUpdate) {
|
|
|
|
@ -676,8 +734,20 @@ void initState() {
|
|
|
|
|
instrument.activePatch = 0;
|
|
|
|
|
state.mainState = NOTE_OFF; // initialize main state machine
|
|
|
|
|
|
|
|
|
|
instrument.activeMIDIchannel = currentPreset->MIDIchannel;
|
|
|
|
|
midiInitialize(currentPreset->MIDIchannel);
|
|
|
|
|
instrument.activeMIDIchannel = state.currentPreset->MIDIchannel;
|
|
|
|
|
midiInitialize(state.currentPreset->MIDIchannel);
|
|
|
|
|
breathCCFilter.setFilter(LOWPASS, 3, 0.0); // create a one pole (RC) lowpass filter
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read all utility sensors
|
|
|
|
|
*/
|
|
|
|
|
void readUtil() {
|
|
|
|
|
instrument.biteSignal = readTouchUtil(bitePin);
|
|
|
|
|
instrument.leverSignal = readTouchUtil(leverPin);
|
|
|
|
|
instrument.pbUpSignal = readTouchUtil(pbUpPin); // PCB PIN "Pu"
|
|
|
|
|
instrument.pbDnSignal = readTouchUtil(pbDnPin); // PCB PIN "Pd"
|
|
|
|
|
instrument.extraSignal = readTouchUtil(extraPin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -690,23 +760,26 @@ void sendCCs() {
|
|
|
|
|
static unsigned long ccSendTime3 = 0L; // The last time we sent CC values 3 (and slower)
|
|
|
|
|
|
|
|
|
|
// Is it time to send more CC data?
|
|
|
|
|
uint32_t currentTime = millis();
|
|
|
|
|
if ((currentTime - ccBreathSendTime) > (currentPreset->breathInterval - 1u)) {
|
|
|
|
|
unsigned long currentTime = millis();
|
|
|
|
|
if ((currentTime - ccBreathSendTime) > (state.currentPreset->breathInterval)) {
|
|
|
|
|
breath();
|
|
|
|
|
ccBreathSendTime = currentTime;
|
|
|
|
|
}
|
|
|
|
|
if (currentTime - ccSendTime > CC_INTERVAL_PRIMARY) {
|
|
|
|
|
// deal with Pitch Bend, Modulation, etc.
|
|
|
|
|
readUtil();
|
|
|
|
|
pitch_bend();
|
|
|
|
|
biteCC_();
|
|
|
|
|
sendCC();
|
|
|
|
|
ccSendTime = currentTime;
|
|
|
|
|
}
|
|
|
|
|
if (currentTime - ccSendTime2 > CC_INTERVAL_PORT) {
|
|
|
|
|
readUtil();
|
|
|
|
|
portamento_();
|
|
|
|
|
ccSendTime2 = currentTime;
|
|
|
|
|
}
|
|
|
|
|
if (currentTime - ccSendTime3 > CC_INTERVAL_OTHER) {
|
|
|
|
|
updateSensorLEDs();
|
|
|
|
|
readUtil();
|
|
|
|
|
updateSensorLEDs(*state.instrument);
|
|
|
|
|
ccSendTime3 = currentTime;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -718,10 +791,19 @@ void runStateMachine() {
|
|
|
|
|
static unsigned long breath_on_time = 0L; // Time when breath sensor value went over the ON threshold
|
|
|
|
|
static int initial_breath_value = 0; // The breath value at the time we observed the transition
|
|
|
|
|
|
|
|
|
|
Serial.print(">breath:");
|
|
|
|
|
Serial.println(instrument.breathSignal);
|
|
|
|
|
Serial.print(">breathThr:");
|
|
|
|
|
Serial.println(instrument.breathThrVal);
|
|
|
|
|
Serial.print(">spike:");
|
|
|
|
|
Serial.println(instrument.spikeSignal);
|
|
|
|
|
Serial.print(">note:");
|
|
|
|
|
Serial.println(state.mainState);
|
|
|
|
|
|
|
|
|
|
int fingeredNote = noteValueCheck(readSwitches() + readOctave());
|
|
|
|
|
if (state.mainState == NOTE_OFF) {
|
|
|
|
|
handleOffStateActions();
|
|
|
|
|
if ((instrument.breathSignal > instrument.breathThrVal)) {
|
|
|
|
|
if (instrument.breathSignal > instrument.breathThrVal && state.mainState == NOTE_OFF) {
|
|
|
|
|
// Value has risen above threshold. Move to the RISE_WAIT
|
|
|
|
|
// state. Record time and initial breath value.
|
|
|
|
|
breath_on_time = millis();
|
|
|
|
@ -731,16 +813,20 @@ void runStateMachine() {
|
|
|
|
|
} else if (state.mainState == RISE_WAIT) {
|
|
|
|
|
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) {
|
|
|
|
|
if ((millis() - breath_on_time > state.currentPreset->velSmpDl) || (0 == state.currentPreset->velSmpDl) || state.currentPreset->fixedVelocity) {
|
|
|
|
|
noteOn(fingeredNote, instrument.breathSignal, initial_breath_value);
|
|
|
|
|
state.mainState = NOTE_ON;
|
|
|
|
|
instrument.activeNote = fingeredNote;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Value fell below threshold before velocity sample delay time passed. Return to NOTE_OFF state
|
|
|
|
|
state.mainState = NOTE_OFF;
|
|
|
|
|
}
|
|
|
|
|
} else if (state.mainState == NOTE_ON) {
|
|
|
|
|
if ((instrument.breathSignal < instrument.breathThrVal)) {
|
|
|
|
|
if (state.currentPreset->spikeFilterFreq && instrument.spikeSignal < -calibration.spikeThrVal) {
|
|
|
|
|
midiSendNoteOff(instrument.activeNote); // send Note Off message
|
|
|
|
|
state.mainState = SPIKE_HOLD;
|
|
|
|
|
} else if (instrument.breathSignal < instrument.breathThrVal) {
|
|
|
|
|
// Value has fallen below threshold - turn the note off
|
|
|
|
|
midiSendNoteOff(instrument.activeNote); // send Note Off message
|
|
|
|
|
instrument.breathSignal = 0;
|
|
|
|
@ -753,8 +839,17 @@ void runStateMachine() {
|
|
|
|
|
noteOn(fingeredNote, instrument.breathSignal, 0);
|
|
|
|
|
delayMicroseconds(2000); // delay for midi recording fix
|
|
|
|
|
midiSendNoteOff(instrument.activeNote); // send Note Off message
|
|
|
|
|
instrument.activeNote = fingeredNote;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (state.mainState == SPIKE_HOLD) {
|
|
|
|
|
if (state.currentPreset->spikeFilterFreq && instrument.spikeSignal > calibration.spikeThrVal) {
|
|
|
|
|
noteOn(fingeredNote, instrument.breathSignal, initial_breath_value);
|
|
|
|
|
state.mainState = NOTE_ON;
|
|
|
|
|
instrument.activeNote = fingeredNote;
|
|
|
|
|
} else if ((instrument.breathSignal < instrument.breathThrVal)) {
|
|
|
|
|
state.mainState = NOTE_OFF;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -769,7 +864,7 @@ void setup() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
initHardware();
|
|
|
|
|
delay(100);
|
|
|
|
|
delay(100); // Make sure the inputs settle
|
|
|
|
|
Serial.println(buttonState());
|
|
|
|
|
bool factoryReset = checkButtonState(STARTUP_FACTORY_RESET);
|
|
|
|
|
configManagementMode = checkButtonState(STARTUP_CONFIG);
|
|
|
|
@ -788,25 +883,26 @@ void setup() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read eeprom data into global vars
|
|
|
|
|
// readEEPROM(factoryReset);
|
|
|
|
|
readEEPROM(factoryReset, *state.calibration);
|
|
|
|
|
updateFilters(*state.currentPreset);
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
displayOff(state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//_______________________________________________________________________________________________ MAIN LOOP
|
|
|
|
@ -815,9 +911,6 @@ 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();
|
|
|
|
@ -830,6 +923,8 @@ void loop() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
instrument.breathSignal = constrain(readPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT); // Get the filtered pressure sensor reading from analog pin A0, input from sensor MP3V5004GP
|
|
|
|
|
instrument.breathAltSignal = constrain(readAltPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT); // Get the filtered pressure sensor reading from analog pin A0, input from sensor MP3V5004GP
|
|
|
|
|
instrument.spikeSignal = constrain(readSpikePressure(), -SPIKE_HI_LIMIT, SPIKE_HI_LIMIT);
|
|
|
|
|
|
|
|
|
|
runStateMachine();
|
|
|
|
|
sendCCs();
|
|
|
|
|