Fixes; additional input filtering

This commit is contained in:
Brian Hrebec 2023-08-30 19:49:22 -05:00
parent 209959e2de
commit 7740c09375
11 changed files with 802 additions and 513 deletions

View file

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