New poly modes, processing improvements

This commit is contained in:
Brian Hrebec 2024-01-30 22:16:15 -06:00
parent c09177c0ee
commit 4211a85562
9 changed files with 258 additions and 162 deletions

View file

@ -89,9 +89,6 @@ const int rollerHarmonic[2][7] = { {0, 7, 12, 16, 19, 24, 26}, // F horn 2,3,4
const int trumpetHarmonic[2][7] = { {0, 7, 12, 16, 19, 26, 31}, //! K4: hrm 8->9, 10->12
{0, 7, 12, 16, 19, 24, 28} }; // trumpet 2,3,4,5,6,8,10 hrm
bool configManagementMode = false;
bool testMode = false;
FilterOnePole breathCCFilter;
FilterOnePole breathBaselineFilter;
@ -242,8 +239,8 @@ int breath() {
oldbreath = breathCCval;
}
if (breathCCvalHires != oldbreathhires
&& (state.currentPreset->breathMode == BreathMode::BREATH_LSB || state.currentPreset->breathMode == BreathMode::BREATH_LSB_AT)) {
if (breathCCvalHires != oldbreathhires &&
(state.currentPreset->breathMode == BreathMode::BREATH_LSB || state.currentPreset->breathMode == BreathMode::BREATH_LSB_AT)) {
midiSendControlChange(state.currentPreset->breathCC + 32, breathCCvalFine);
}
@ -641,25 +638,17 @@ int readOctave() {
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;
return octave;
}
int readSwitches() {
void readSwitches() {
// Keep the last fingering value for debouncing
static int lastFingering = 0;
static int fingeredNote = 0;
static int lastFingering2 = 0;
static int lastOctave = 0;
static unsigned long lastDeglitchTime = 0; // The last time the fingering was changed
int fingeredNoteUntransposed = 0;
int fingeredNote2Untransposed = 0;
// Read touch pads (MPR121), compare against threshold value
bool touchKeys[12];
@ -676,34 +665,54 @@ int readSwitches() {
byte K1 = touchKeys[K1Pin]; // Valve 1 (pitch change -2)
byte K2 = touchKeys[K2Pin]; // Valve 2 (pitch change -1)
byte K3 = touchKeys[K3Pin]; // Valve 3 (pitch change -3)
byte K4 = touchKeys[K4Pin]; // Left Hand index finger (pitch change -5)
byte K4 = touchKeys[K4Pin]; // Value 4 (pitch change -5)
byte K5 = touchKeys[K5Pin]; // Trill key 1 (pitch change +2)
byte K6 = touchKeys[K6Pin]; // Trill key 2 (pitch change +1)
byte K7 = touchKeys[K7Pin]; // Trill key 3 (pitch change +4)
byte K8 = touchKeys[K8Pin]; // Pinky Key
byte K9 = touchKeys[K9Pin]; // LH Key 1
byte K10 = touchKeys[K10Pin]; // LH Key 2
byte K11 = touchKeys[K11Pin]; // LH Key 3
byte K12 = touchKeys[K12Pin]; // LH Key 4
instrument.pinkyKey = touchKeys[K8Pin];
instrument.pinkyKey = K8;
int qTransp = (instrument.pinkyKey && (state.currentPreset->pinkySetting < 25)) ? state.currentPreset->pinkySetting - 12 : 0;
int qTransp = (K8 && (state.currentPreset->pinkySetting < 25)) ? state.currentPreset->pinkySetting - 12 : 0;
// Calculate midi note number from pressed keys
int fingeredNoteUntransposed = 0;
if (EVI == state.currentPreset->fingering) { // EVI fingering
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves"
switch (state.currentPreset->fingering) {
case EVI:
case EVR:
fingeredNoteUntransposed = START_NOTE
- 2 * K1
- K2
- 3 * K3 //"Trumpet valves"
- 5 * K4 // Fifth key
+ 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 + 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 + 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 + state.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
break;
case TPT:
fingeredNoteUntransposed = START_NOTE
- 2 * K1
- K2
- 3 * K3 //"Trumpet valves"
- 2 // Trumpet in B flat
+ 2 * K5
+ K6
+ state.currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
break;
case HRN:
fingeredNoteUntransposed = START_NOTE
- 2 * K1
- K2
- 3 * K3 //"Trumpet valves"
+ 5 * K4 // Switch to Bb horn
+ 5 // Horn in F
+ 2 * K5
+ K6
+ state.currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
break;
}
if (K3 && K7) {
@ -713,9 +722,31 @@ int readSwitches() {
fingeredNoteUntransposed += 4;
}
int fingeredNoteRead = fingeredNoteUntransposed + instrument.transpose - 12 + qTransp;
fingeredNote2Untransposed =
- 2 * K9
- K10
- 3 * K11
- 7 * K12;
if (fingeredNoteRead != lastFingering) { //
switch (state.currentPreset->polyMode) {
case EHarmonizerOff: // LH affects main instrument
fingeredNoteUntransposed += fingeredNote2Untransposed;
fingeredNote2Untransposed = fingeredNoteUntransposed;
break;
case EDuo: // Duo (absolute) mode
fingeredNote2Untransposed = START_NOTE + fingeredNote2Untransposed;
break;
case EDouble: // Double-stop (relative) mode
fingeredNote2Untransposed = fingeredNoteUntransposed + fingeredNote2Untransposed;
break;
}
int fingeredNoteRead = fingeredNoteUntransposed + instrument.transpose - 12 + qTransp;
int fingeredNote2Read = fingeredNote2Untransposed + instrument.transpose - 12 + qTransp;
int fingeredOctave = readOctave();
if (fingeredOctave != lastOctave || fingeredNoteRead != lastFingering || fingeredNote2Read != lastFingering2) { //
// reset the debouncing timer
lastDeglitchTime = millis();
}
@ -723,12 +754,14 @@ int readSwitches() {
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;
instrument.fingeredNote = noteValueCheck(fingeredNoteRead + fingeredOctave);
instrument.fingeredNote2 = noteValueCheck(fingeredNote2Read + fingeredOctave);
instrument.fingeredOctave = fingeredOctave;
}
lastFingering = fingeredNoteRead;
return fingeredNote;
lastFingering2 = fingeredNote2Read;
lastOctave = fingeredOctave;
}
void noteOn(int fingeredNote, int pressureSensor, int initial_breath_value) {
@ -744,8 +777,39 @@ void noteOn(int fingeredNote, int pressureSensor, int initial_breath_value) {
velocitySend = state.currentPreset->fixedVelocity;
}
breath(); // send breath data
midiSendNoteOn(fingeredNote, velocitySend); // send Note On message for new note
midiSendNoteOn(fingeredNote, velocitySend); // send Note Off message
}
/**
* Send a new note message if it has changed
*/
void changeNote(int fingeredNote, int activeNote, int fingeredNote2, int activeNote2) {
if (fingeredNote == activeNote && fingeredNote2 == activeNote2) {
// No change
return;
}
// 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.
if (fingeredNote != activeNote && fingeredNote != activeNote2) {
noteOn(fingeredNote, instrument.breathSignal, 0);
}
if (fingeredNote2 != activeNote && fingeredNote2 != activeNote2) {
noteOn(fingeredNote2, instrument.breathSignal, 0);
}
delayMicroseconds(2000); // delay for midi recording fix
// send Note Off messages
if (activeNote != fingeredNote && activeNote != fingeredNote2) {
midiSendNoteOff(activeNote);
}
if (activeNote2 != fingeredNote && activeNote2 != fingeredNote2) {
midiSendNoteOff(activeNote2);
}
}
void handleOffStateActions() {
@ -825,6 +889,7 @@ void handleCCs() {
void readBreath() {
int16_t breathSignal = constrain(readPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT); // Get the filtered pressure sensor reading from analog pin A0, input from sensor MP3V5004GP
int16_t breathAltSignal = constrain(readAltPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT); // Get the filtered pressure sensor reading from analog pin A0, input from sensor MP3V5004GP
int16_t spikeSignal = constrain(readSpikePressure(), -SPIKE_HI_LIMIT, SPIKE_HI_LIMIT);
instrument.breathMovingThrVal = constrain(
breathBaselineFilter.input((breathSignal + instrument.breathZero) / 2),
@ -840,20 +905,24 @@ void readBreath() {
} else {
instrument.breathSignal = breathSignal + (spikeSignal > 0 ? spikeSignal * state.currentPreset->spikeOnFactor : spikeSignal * state.currentPreset->spikeOffFactor);
}
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.breathAltSignal = breathAltSignal;
Serial.print(">breathThr:");
Serial.println(instrument.breathThrVal);
if (instrument.mode == MODE_DEBUG) {
Serial.print(">breath:");
Serial.println(breathSignal);
Serial.print(">breathAlt:");
Serial.println(breathAltSignal);
Serial.print(">Diff:");
Serial.println(breathSignal - breathAltSignal);
Serial.print(">breathMovingThr:");
Serial.println(instrument.breathMovingThrVal);
Serial.print(">note:");
Serial.println(state.mainState);
Serial.print(">spike:");
Serial.println(spikeSignal);
Serial.print(">breath:");
Serial.println(breathSignal);
Serial.print(">combo:");
Serial.println(instrument.breathSignal);
}
}
/**
@ -862,7 +931,6 @@ void readBreath() {
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
int fingeredNote = noteValueCheck(readSwitches() + readOctave());
if (state.mainState == NOTE_OFF) {
handleOffStateActions();
if (instrument.breathSignal > instrument.breathMovingThrVal && state.mainState == NOTE_OFF) {
@ -876,9 +944,14 @@ void runStateMachine() {
if ((instrument.breathSignal > instrument.breathMovingThrVal)) {
// Has enough time passed for us to collect our second sample?
if ((millis() - breath_on_time > state.currentPreset->velSmpDl) || (0 == state.currentPreset->velSmpDl) || state.currentPreset->fixedVelocity) {
noteOn(fingeredNote, instrument.breathSignal, initial_breath_value);
noteOn(instrument.fingeredNote, instrument.breathSignal, initial_breath_value);
if (instrument.fingeredNote != instrument.fingeredNote2) {
noteOn(instrument.fingeredNote2, instrument.breathSignal, initial_breath_value);
}
breath(); // send breath data
state.mainState = NOTE_ON;
instrument.activeNote = fingeredNote;
instrument.activeNote = instrument.fingeredNote;
instrument.activeNote2 = instrument.fingeredNote2;
}
} else {
// Value fell below threshold before velocity sample delay time passed. Return to NOTE_OFF state
@ -888,38 +961,30 @@ void runStateMachine() {
if (instrument.breathSignal < instrument.breathMovingThrVal) {
// Value has fallen below threshold - turn the note off
midiSendNoteOff(instrument.activeNote); // send Note Off message
if (instrument.activeNote != instrument.activeNote2) {
midiSendNoteOff(instrument.activeNote2); // send Note Off message
}
instrument.breathSignal = 0;
state.mainState = NOTE_OFF;
} else {
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, instrument.breathSignal, 0);
delayMicroseconds(2000); // delay for midi recording fix
midiSendNoteOff(instrument.activeNote); // send Note Off message
instrument.activeNote = fingeredNote;
}
changeNote(instrument.fingeredNote, instrument.activeNote, instrument.fingeredNote2, instrument.activeNote2);
instrument.activeNote = instrument.fingeredNote;
instrument.activeNote2 = instrument.fingeredNote2;
}
}
}
void setup() {
if (checkButtonState(DEBUG_CONFIG)) {
}
Serial.begin(9600); // debug
Serial.println("Debug Startup");
if (CrashReport) {
Serial.begin(9600); // debug
Serial.println("Debug Startup");
while (!Serial); // wait for serial monitor open
Serial.print(CrashReport);
}
initHardware();
delay(100); // Make sure the inputs settle
Serial.println(buttonState());
bool factoryReset = checkButtonState(STARTUP_FACTORY_RESET);
configManagementMode = checkButtonState(STARTUP_CONFIG);
testMode = checkButtonState(TEST_CONFIG);
initDisplay(); // Start up display and show logo
@ -927,12 +992,6 @@ void setup() {
displayError("CRASH WARNING");
}
// If going into config management mode, stop here before we even touch the EEPROM.
if (configManagementMode) {
configModeSetup();
return;
}
// Read eeprom data into global vars
readEEPROM(factoryReset, *state.calibration);
updateFilters(*state.currentPreset);
@ -967,18 +1026,18 @@ void loop() {
lastUpdate = time;
// If in config mgmt loop, do that and nothing else
if (configManagementMode) {
configModeLoop();
if (instrument.mode == MODE_CONFIG) {
configModeLoop(state);
return;
}
if (testMode) {
handleTestMode();
if (instrument.mode == MODE_TEST) {
handleTestMode(state);
return;
}
readBreath();
readSwitches();
runStateMachine();
handleCCs();