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

@ -65,7 +65,7 @@ enum ExtraControl : uint8_t {
enum PolySelect : uint8_t { enum PolySelect : uint8_t {
EHarmonizerOff = 0, EHarmonizerOff = 0,
EDuo = 1, EDuo = 1,
EChord = 2, EDouble = 2,
}; };
enum PortamentoMode : uint8_t { enum PortamentoMode : uint8_t {
@ -75,15 +75,23 @@ enum PortamentoMode : uint8_t {
PGLIDE_ONLY = 3, PGLIDE_ONLY = 3,
}; };
enum InstrumentMode : uint8_t {
MODE_NORMAL,
MODE_TEST,
MODE_CONFIG,
MODE_DEBUG,
};
struct instrument_state_t { struct instrument_state_t {
InstrumentMode mode = MODE_NORMAL;
uint8_t patch; // 1-128 uint8_t patch; // 1-128
byte activeMIDIchannel = 1; // MIDI channel byte activeMIDIchannel = 1; // MIDI channel
byte activeNote = 0; // note playing byte activeNote = 0; // note playing
byte activeNote2 = 0; // note playing
byte activePatch = 0; byte activePatch = 0;
byte doPatchUpdate = 0; byte doPatchUpdate = 0;
int8_t transpose = 0; int8_t transpose = 0;
int8_t octave = 0; int8_t octave = 0;
PolySelect polyMode = PolySelect::EHarmonizerOff;
// Raw sensor signals // Raw sensor signals
int16_t breathSignal = 0; // breath level (smoothed) not mapped to CC value int16_t breathSignal = 0; // breath level (smoothed) not mapped to CC value
@ -113,6 +121,9 @@ struct instrument_state_t {
// Key states // Key states
byte quarterToneTrigger; byte quarterToneTrigger;
byte pinkyKey = 0; byte pinkyKey = 0;
byte fingeredNote = 0;
byte fingeredNote2 = 0;
byte fingeredOctave = 0;
// CV values // CV values
int cvPitch; int cvPitch;

View file

@ -166,8 +166,6 @@ int readSpikePressure() {
int readPressure() { int readPressure() {
float p = pressureSensorMain.readPressure(); float p = pressureSensorMain.readPressure();
Serial.print(">raw:");
Serial.println(p * PRESSURE_SENS_MULTIPLIER);
return breathFilter.input(p) * PRESSURE_SENS_MULTIPLIER; return breathFilter.input(p) * PRESSURE_SENS_MULTIPLIER;
} }

View file

@ -73,28 +73,28 @@ icm_result_t readICM();
// Key pins // Key pins
// RH keys // RH keys
#define K1Pin 5 #define K1Pin 1
#define K2Pin 6 #define K2Pin 7
#define K3Pin 2 #define K3Pin 3
#define K4Pin 11 #define K4Pin 10
#define K5Pin 4 #define K5Pin 2
#define K6Pin 7 #define K6Pin 6
#define K7Pin 9 #define K7Pin 4
#define K8Pin 10 #define K8Pin 11
// LH keys // LH keys
#define K9Pin 3 #define K9Pin 0
#define K10Pin 8 #define K10Pin 5
#define K11Pin 0 #define K11Pin 8
#define K12Pin 1 #define K12Pin 9
// Octave roller pins // Octave roller pins
#define R1Pin 11 #define R1Pin 6
#define R2Pin 10 #define R2Pin 7
#define R3Pin 9 #define R3Pin 8
#define R4Pin 8 #define R4Pin 9
#define R5Pin 7 #define R5Pin 10
#define R6Pin 6 #define R6Pin 11
// Additional pins // Additional pins
#define bitePin 0 #define bitePin 0

View file

@ -1024,6 +1024,11 @@ ChoiceMenu<4, FingeringMode> fingeringMenu("FINGERING", &preset_t::fingering, {
"TPT", "TPT",
"HRN", "HRN",
}); });
ChoiceMenu<3, PolySelect> polyMenu("POLYMODE", &preset_t::polyMode, { EHarmonizerOff, EDouble, EDuo }, {
"OFF",
"DOUBLE",
"DUO",
});
ChoiceMenu<6, RollerMode> rollerMenu("ROLLRMODE", &preset_t::rollerMode, { ChoiceMenu<6, RollerMode> rollerMenu("ROLLRMODE", &preset_t::rollerMode, {
HIGHEST, HIGHEST,
HIGHEST_EXTEND, HIGHEST_EXTEND,
@ -1048,6 +1053,19 @@ FuncMenu factoryResetMenu("FACT. RESET", [](state_t &state, InputState& input) {
FuncMenu saveAllPresetsMenu("SAVE PRESETS", [](state_t &state, InputState& input) { FuncMenu saveAllPresetsMenu("SAVE PRESETS", [](state_t &state, InputState& input) {
writePresets(); writePresets();
}); });
FuncMenu debugModeMenu("DEBUG MODE", [](state_t &state, InputState& input) {
Serial.begin(9600); // debug
Serial.println("Debug Startup");
state.instrument->mode = state.instrument->mode == MODE_DEBUG ? MODE_NORMAL : MODE_DEBUG;
});
FuncMenu testModeMenu("TEST MODE", [](state_t &state, InputState& input) {
display.clearDisplay();
state.instrument->mode = MODE_TEST;
});
FuncMenu configModeMenu("CONFIG MGT", [](state_t &state, InputState& input) {
configModeSetup();
state.instrument->mode = MODE_CONFIG;
});
std::array<MenuScreen *const, 11> breathMenuEntries = { std::array<MenuScreen *const, 11> breathMenuEntries = {
&breathModeMenu, &breathModeMenu,
@ -1064,8 +1082,9 @@ std::array<MenuScreen *const, 11> breathMenuEntries = {
}; };
SubMenu<11> breathMenu("BR SETUP", breathMenuEntries); SubMenu<11> breathMenu("BR SETUP", breathMenuEntries);
const std::array<MenuScreen *const, 19> controlMenuEntries = { const std::array<MenuScreen *const, 20> controlMenuEntries = {
&fingeringMenu, &fingeringMenu,
&polyMenu,
&rollerMenu, &rollerMenu,
&biteCtlMenu, &biteCtlMenu,
&biteCCMenu, &biteCCMenu,
@ -1085,7 +1104,7 @@ const std::array<MenuScreen *const, 19> controlMenuEntries = {
&accelModeMenu, &accelModeMenu,
&accelCCMenu, &accelCCMenu,
}; };
SubMenu<19> controlMenu("CTL SETUP", controlMenuEntries); SubMenu<20> controlMenu("CTL SETUP", controlMenuEntries);
const std::array<MenuScreen *const, 5> vibratoMenuEntries = { const std::array<MenuScreen *const, 5> vibratoMenuEntries = {
&vibDepthMenu, &vibDepthMenu,
@ -1099,7 +1118,7 @@ SubMenu<5> vibratoMenu("VIBRATO", vibratoMenuEntries);
AboutMenu aboutMenu = AboutMenu(); AboutMenu aboutMenu = AboutMenu();
const std::array <MenuScreen *const, 7> extrasMenuEntries = { const std::array <MenuScreen *const, 10> extrasMenuEntries = {
&trill3Menu, &trill3Menu,
&cvTuneMenu, &cvTuneMenu,
&cvScaleMenu, &cvScaleMenu,
@ -1107,8 +1126,11 @@ const std::array <MenuScreen *const, 7> extrasMenuEntries = {
&recalibrateMenu, &recalibrateMenu,
&factoryResetMenu, &factoryResetMenu,
&saveAllPresetsMenu, &saveAllPresetsMenu,
&testModeMenu,
&debugModeMenu,
&configModeMenu,
}; };
SubMenu<7> extrasMenu("EXTRAS", extrasMenuEntries); SubMenu<10> extrasMenu("EXTRAS", extrasMenuEntries);
ExitMenu exitMenu = ExitMenu(); ExitMenu exitMenu = ExitMenu();
@ -1225,6 +1247,7 @@ void initDisplay() {
// internally, this will display the splashscreen. // internally, this will display the splashscreen.
display.clearDisplay(); display.clearDisplay();
display.setRotation(2);
display.drawBitmap(0, 0, nuevi_logo_bmp, LOGO16_GLCD_WIDTH, LOGO16_GLCD_HEIGHT, 1); display.drawBitmap(0, 0, nuevi_logo_bmp, LOGO16_GLCD_WIDTH, LOGO16_GLCD_HEIGHT, 1);
display.display(); display.display();
currentMenu = &statusMenu; currentMenu = &statusMenu;

View file

@ -313,7 +313,7 @@ void configModeSetup() {
} }
//"Main loop". Just sits and wait for midi messages and lets the sysex handler do all the work. //"Main loop". Just sits and wait for midi messages and lets the sysex handler do all the work.
void configModeLoop() { void configModeLoop(state_t &state) {
usbMIDI.read(); usbMIDI.read();
} }

View file

@ -94,8 +94,9 @@ struct preset_t {
uint8_t spikeFilterFreq = 20; uint8_t spikeFilterFreq = 20;
int8_t spikeOnFactor = 5; int8_t spikeOnFactor = 5;
int8_t spikeOffFactor = 5; int8_t spikeOffFactor = 5;
PolySelect polyMode = PolySelect::EHarmonizerOff;
uint8_t _reserved[83]; uint8_t _reserved[82];
}; };
static_assert(sizeof(preset_t) == PRESET_MAX_SIZE, "preset_t must be 128 bytes"); static_assert(sizeof(preset_t) == PRESET_MAX_SIZE, "preset_t must be 128 bytes");
@ -132,6 +133,6 @@ void configInitScreen();
void configShowMessage(const char* message); void configShowMessage(const char* message);
void configModeSetup(); void configModeSetup();
void configModeLoop(); void configModeLoop(state_t &state);
#endif #endif

View file

@ -5,7 +5,7 @@ uint16_t oldKeys = 0;
uint16_t oldUtil = 0; uint16_t oldUtil = 0;
bool plotCap = false; bool plotCap = false;
void handleTestMode() { void handleTestMode(state_t &state) {
uint8_t buttons = buttonState(); uint8_t buttons = buttonState();
if (buttons != oldButtons) { if (buttons != oldButtons) {
oldButtons = buttons; oldButtons = buttons;
@ -41,6 +41,10 @@ void handleTestMode() {
plotCap = !plotCap; plotCap = !plotCap;
} }
if (buttons == 0x08) {
state.instrument->mode = MODE_NORMAL;
}
if (plotCap) { if (plotCap) {
for (int i = 0; i < 12; i++) { for (int i = 0; i < 12; i++) {
Serial.print(">key"); Serial.print(">key");

View file

@ -1,6 +1,6 @@
#ifndef __TEST_H #ifndef __TEST_H
#define __TEST_H #define __TEST_H
void handleTestMode(); void handleTestMode(state_t &state);
#endif #endif

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 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 {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 breathCCFilter;
FilterOnePole breathBaselineFilter; FilterOnePole breathBaselineFilter;
@ -242,8 +239,8 @@ int breath() {
oldbreath = breathCCval; oldbreath = breathCCval;
} }
if (breathCCvalHires != oldbreathhires if (breathCCvalHires != oldbreathhires &&
&& (state.currentPreset->breathMode == BreathMode::BREATH_LSB || state.currentPreset->breathMode == BreathMode::BREATH_LSB_AT)) { (state.currentPreset->breathMode == BreathMode::BREATH_LSB || state.currentPreset->breathMode == BreathMode::BREATH_LSB_AT)) {
midiSendControlChange(state.currentPreset->breathCC + 32, breathCCvalFine); midiSendControlChange(state.currentPreset->breathCC + 32, breathCCvalFine);
} }
@ -641,25 +638,17 @@ int readOctave() {
octave = 12 * octaveR + offset + instrument.octave * 12; octave = 12 * octaveR + offset + instrument.octave * 12;
} }
if (octave != lastOctave) { // return octave;
// reset the debouncing timer
lastDeglitchTime = millis();
}
if ((millis() - lastDeglitchTime) > state.currentPreset->deglitch) {
fingeredOctave = octave;
}
lastOctave = octave;
return fingeredOctave;
} }
int readSwitches() { void readSwitches() {
// Keep the last fingering value for debouncing // Keep the last fingering value for debouncing
static int lastFingering = 0; 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 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 // Read touch pads (MPR121), compare against threshold value
bool touchKeys[12]; bool touchKeys[12];
@ -676,34 +665,54 @@ int readSwitches() {
byte K1 = touchKeys[K1Pin]; // Valve 1 (pitch change -2) byte K1 = touchKeys[K1Pin]; // Valve 1 (pitch change -2)
byte K2 = touchKeys[K2Pin]; // Valve 2 (pitch change -1) byte K2 = touchKeys[K2Pin]; // Valve 2 (pitch change -1)
byte K3 = touchKeys[K3Pin]; // Valve 3 (pitch change -3) 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 K5 = touchKeys[K5Pin]; // Trill key 1 (pitch change +2)
byte K6 = touchKeys[K6Pin]; // Trill key 2 (pitch change +1) byte K6 = touchKeys[K6Pin]; // Trill key 2 (pitch change +1)
byte K7 = touchKeys[K7Pin]; // Trill key 3 (pitch change +4) 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 // Calculate midi note number from pressed keys
int fingeredNoteUntransposed = 0; switch (state.currentPreset->fingering) {
if (EVI == state.currentPreset->fingering) { // EVI fingering case EVI:
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves" case EVR:
fingeredNoteUntransposed = START_NOTE
- 2 * K1
- K2
- 3 * K3 //"Trumpet valves"
- 5 * K4 // Fifth key - 5 * K4 // Fifth key
+ 2 * K5 + K6 + state.currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting + 2 * K5
} else if (EVR == state.currentPreset->fingering) { // EVR fingering + K6
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves" + state.currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
- 5 * K4 // Fifth key break;
+ 2 * K5 + K6 + state.currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting case TPT:
} else if (TPT == state.currentPreset->fingering) { // TPT fingering fingeredNoteUntransposed = START_NOTE
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves" - 2 * K1
- K2
- 3 * K3 //"Trumpet valves"
- 2 // Trumpet in B flat - 2 // Trumpet in B flat
+ 2 * K5 + K6 + state.currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting + 2 * K5
} else if (HRN == state.currentPreset->fingering) { // HRN fingering + K6
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves" + 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 * K4 // Switch to Bb horn
+ 5 // Horn in F + 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;
} }
if (K3 && K7) { if (K3 && K7) {
@ -713,9 +722,31 @@ int readSwitches() {
fingeredNoteUntransposed += 4; 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 // reset the debouncing timer
lastDeglitchTime = millis(); lastDeglitchTime = millis();
} }
@ -723,12 +754,14 @@ int readSwitches() {
if ((millis() - lastDeglitchTime) > state.currentPreset->deglitch) { if ((millis() - lastDeglitchTime) > state.currentPreset->deglitch) {
// whatever the reading is at, it's been there for longer // whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current instrument // 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; lastFingering = fingeredNoteRead;
lastFingering2 = fingeredNote2Read;
return fingeredNote; lastOctave = fingeredOctave;
} }
void noteOn(int fingeredNote, int pressureSensor, int initial_breath_value) { 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; velocitySend = state.currentPreset->fixedVelocity;
} }
breath(); // send breath data midiSendNoteOn(fingeredNote, velocitySend); // send Note Off message
midiSendNoteOn(fingeredNote, velocitySend); // send Note On message for new note }
/**
* 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() { void handleOffStateActions() {
@ -825,6 +889,7 @@ void handleCCs() {
void readBreath() { 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 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); int16_t spikeSignal = constrain(readSpikePressure(), -SPIKE_HI_LIMIT, SPIKE_HI_LIMIT);
instrument.breathMovingThrVal = constrain( instrument.breathMovingThrVal = constrain(
breathBaselineFilter.input((breathSignal + instrument.breathZero) / 2), breathBaselineFilter.input((breathSignal + instrument.breathZero) / 2),
@ -840,20 +905,24 @@ void readBreath() {
} else { } else {
instrument.breathSignal = breathSignal + (spikeSignal > 0 ? spikeSignal * state.currentPreset->spikeOnFactor : spikeSignal * state.currentPreset->spikeOffFactor); 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:"); if (instrument.mode == MODE_DEBUG) {
Serial.println(instrument.breathThrVal); Serial.print(">breath:");
Serial.println(breathSignal);
Serial.print(">breathAlt:");
Serial.println(breathAltSignal);
Serial.print(">Diff:");
Serial.println(breathSignal - breathAltSignal);
Serial.print(">breathMovingThr:"); Serial.print(">breathMovingThr:");
Serial.println(instrument.breathMovingThrVal); Serial.println(instrument.breathMovingThrVal);
Serial.print(">note:"); Serial.print(">note:");
Serial.println(state.mainState); Serial.println(state.mainState);
Serial.print(">spike:"); Serial.print(">spike:");
Serial.println(spikeSignal); Serial.println(spikeSignal);
Serial.print(">breath:");
Serial.println(breathSignal);
Serial.print(">combo:"); Serial.print(">combo:");
Serial.println(instrument.breathSignal); Serial.println(instrument.breathSignal);
}
} }
/** /**
@ -862,7 +931,6 @@ void readBreath() {
void runStateMachine() { void runStateMachine() {
static unsigned long breath_on_time = 0L; // Time when breath sensor value went over the ON threshold 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 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) { if (state.mainState == NOTE_OFF) {
handleOffStateActions(); handleOffStateActions();
if (instrument.breathSignal > instrument.breathMovingThrVal && state.mainState == NOTE_OFF) { if (instrument.breathSignal > instrument.breathMovingThrVal && state.mainState == NOTE_OFF) {
@ -876,9 +944,14 @@ void runStateMachine() {
if ((instrument.breathSignal > instrument.breathMovingThrVal)) { if ((instrument.breathSignal > instrument.breathMovingThrVal)) {
// Has enough time passed for us to collect our second sample? // 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) { 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; state.mainState = NOTE_ON;
instrument.activeNote = fingeredNote; instrument.activeNote = instrument.fingeredNote;
instrument.activeNote2 = instrument.fingeredNote2;
} }
} else { } else {
// Value fell below threshold before velocity sample delay time passed. Return to NOTE_OFF state // 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) { if (instrument.breathSignal < instrument.breathMovingThrVal) {
// Value has fallen below threshold - turn the note off // Value has fallen below threshold - turn the note off
midiSendNoteOff(instrument.activeNote); // send Note Off message midiSendNoteOff(instrument.activeNote); // send Note Off message
if (instrument.activeNote != instrument.activeNote2) {
midiSendNoteOff(instrument.activeNote2); // send Note Off message
}
instrument.breathSignal = 0; instrument.breathSignal = 0;
state.mainState = NOTE_OFF; state.mainState = NOTE_OFF;
} else { } else {
if (fingeredNote != instrument.activeNote) { changeNote(instrument.fingeredNote, instrument.activeNote, instrument.fingeredNote2, instrument.activeNote2);
// Player has moved to a new fingering while still blowing. instrument.activeNote = instrument.fingeredNote;
// Send a note off for the current note and a note on for instrument.activeNote2 = instrument.fingeredNote2;
// 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;
}
} }
} }
} }
void setup() { void setup() {
if (checkButtonState(DEBUG_CONFIG)) { if (CrashReport) {
}
Serial.begin(9600); // debug Serial.begin(9600); // debug
Serial.println("Debug Startup"); Serial.println("Debug Startup");
if (CrashReport) {
while (!Serial); // wait for serial monitor open while (!Serial); // wait for serial monitor open
Serial.print(CrashReport); Serial.print(CrashReport);
} }
initHardware(); initHardware();
delay(100); // Make sure the inputs settle delay(100); // Make sure the inputs settle
Serial.println(buttonState());
bool factoryReset = checkButtonState(STARTUP_FACTORY_RESET); bool factoryReset = checkButtonState(STARTUP_FACTORY_RESET);
configManagementMode = checkButtonState(STARTUP_CONFIG);
testMode = checkButtonState(TEST_CONFIG);
initDisplay(); // Start up display and show logo initDisplay(); // Start up display and show logo
@ -927,12 +992,6 @@ void setup() {
displayError("CRASH WARNING"); 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 // Read eeprom data into global vars
readEEPROM(factoryReset, *state.calibration); readEEPROM(factoryReset, *state.calibration);
updateFilters(*state.currentPreset); updateFilters(*state.currentPreset);
@ -967,18 +1026,18 @@ void loop() {
lastUpdate = time; lastUpdate = time;
// If in config mgmt loop, do that and nothing else // If in config mgmt loop, do that and nothing else
if (configManagementMode) { if (instrument.mode == MODE_CONFIG) {
configModeLoop(); configModeLoop(state);
return; return;
} }
if (testMode) { if (instrument.mode == MODE_TEST) {
handleTestMode(); handleTestMode(state);
return; return;
} }
readBreath(); readBreath();
readSwitches();
runStateMachine(); runStateMachine();
handleCCs(); handleCCs();