New poly modes, processing improvements
This commit is contained in:
parent
c09177c0ee
commit
4211a85562
9 changed files with 258 additions and 162 deletions
|
@ -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();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue