Cleanup pair octaves

This commit is contained in:
Brian Hrebec 2023-09-01 11:09:09 -05:00
parent 00cdfc08e0
commit c09177c0ee
9 changed files with 119 additions and 70 deletions

View file

@ -1,9 +1,6 @@
1. LED abstraction code 1. LED abstraction code
5. Refactor CV behavior into module 5. Refactor CV behavior into module
6. 9dof sensor code 7. LH fingerings
7. Alternate fingerings
8. Encoder midi
- Lever mode: pb - Lever mode: pb
- Breath suck control? - Breath suck control?
-

View file

@ -10,8 +10,9 @@
#define ON_Delay 20 // Set Delay after ON threshold before velocity is checked (wait for tounging peak) #define ON_Delay 20 // Set Delay after ON threshold before velocity is checked (wait for tounging peak)
#define CCN_Port 5 // Controller number for portamento level #define CCN_Port 5 // Controller number for portamento level
#define CCN_PortOnOff 65// Controller number for portamento on/off #define CCN_PortOnOff 65// Controller number for portamento on/off
#define START_NOTE 24 // set startNote to C (change this value in steps of 12 to start in other octaves) #define START_NOTE 36 // set startNote to C (change this value in steps of 12 to start in other octaves)
#define FILTER_FREQ 10.0 #define FILTER_FREQ 10.0
#define BREATH_THR_MAX_BOOST 40.0
#define CAP_SENS_ABSOLUTE_MAX 1000 // For inverting capacitive sensors #define CAP_SENS_ABSOLUTE_MAX 1000 // For inverting capacitive sensors
#define PRESSURE_SENS_MULTIPLIER 10 // Multiply pressure sens so it's not a float #define PRESSURE_SENS_MULTIPLIER 10 // Multiply pressure sens so it's not a float
#define CALIBRATE_SAMPLE_COUNT 4 #define CALIBRATE_SAMPLE_COUNT 4
@ -31,6 +32,7 @@
#define BTN_PRESET 0x8 #define BTN_PRESET 0x8
#define KNOB_CURVE_THRESHOLD 100 #define KNOB_CURVE_THRESHOLD 100
#define KNOB_CURVE_MULTIPLIER 5 #define KNOB_CURVE_MULTIPLIER 5
#define KNOB_DISPLAY_TIME 500
// Send breath CC data no more than every CC_BREATH_INTERVAL // Send breath CC data no more than every CC_BREATH_INTERVAL
// milliseconds // milliseconds

View file

@ -20,9 +20,9 @@
enum PinkyMode : uint8_t { enum PinkyMode : uint8_t {
PBD = 12, PBD = 12,
GLD = 25, GLD = 26,
MOD = 26, MOD = 27,
QTN = 27, QTN = 28,
}; };
enum FingeringMode : uint8_t { enum FingeringMode : uint8_t {
@ -105,6 +105,8 @@ struct instrument_state_t {
int pitchBend = 8192; int pitchBend = 8192;
int pbSend = 8192; // Pitch bend actually sent, modified by vibrato, etc int pbSend = 8192; // Pitch bend actually sent, modified by vibrato, etc
byte knobVals[4]; byte knobVals[4];
byte lastKnobVal;
unsigned long lastKnobTime;
byte rollCCVal = 0; byte rollCCVal = 0;
byte tiltCCVal = 0; byte tiltCCVal = 0;
@ -119,6 +121,7 @@ struct instrument_state_t {
// Calibration // Calibration
int16_t breathZero; // this gets auto calibrated in setup int16_t breathZero; // this gets auto calibrated in setup
int16_t breathThrVal; // this gets auto calibrated in setup int16_t breathThrVal; // this gets auto calibrated in setup
int16_t breathMovingThrVal;
int16_t breathMaxVal; // this gets auto calibrated in setup int16_t breathMaxVal; // this gets auto calibrated in setup
int16_t breathAltZero; // this gets auto calibrated in setup int16_t breathAltZero; // this gets auto calibrated in setup
int16_t breathAltThrVal; // this gets auto calibrated in setup int16_t breathAltThrVal; // this gets auto calibrated in setup

View file

@ -9,6 +9,8 @@
FilterOnePole breathFilter; FilterOnePole breathFilter;
FilterOnePole breathAltFilter; FilterOnePole breathAltFilter;
FilterOnePole spikeFilter; FilterOnePole spikeFilter;
FilterOnePole tiltFilter;
FilterOnePole rollFilter;
Adafruit_MPR121 touchSensorKeys = Adafruit_MPR121(); Adafruit_MPR121 touchSensorKeys = Adafruit_MPR121();
Adafruit_MPR121 touchSensorUtil = Adafruit_MPR121(); Adafruit_MPR121 touchSensorUtil = Adafruit_MPR121();
@ -44,6 +46,8 @@ void initHardware() {
breathFilter.setFilter(LOWPASS, FILTER_FREQ, 0.0); // create a one pole (RC) lowpass filter breathFilter.setFilter(LOWPASS, FILTER_FREQ, 0.0); // create a one pole (RC) lowpass filter
breathAltFilter.setFilter(LOWPASS, FILTER_FREQ, 0.0); // create a one pole (RC) lowpass filter breathAltFilter.setFilter(LOWPASS, FILTER_FREQ, 0.0); // create a one pole (RC) lowpass filter
spikeFilter.setFilter(HIGHPASS, 200, 0.0); // create a one pole (RC) lowpass filter spikeFilter.setFilter(HIGHPASS, 200, 0.0); // create a one pole (RC) lowpass filter
tiltFilter.setFilter(LOWPASS, 2, 0.0); // create a one pole (RC) lowpass filter
rollFilter.setFilter(LOWPASS, 2, 0.0); // create a one pole (RC) lowpass filter
icmSensor.begin_I2C(ICM20948_I2CADDR_DEFAULT, &MainI2CBus); icmSensor.begin_I2C(ICM20948_I2CADDR_DEFAULT, &MainI2CBus);
ledStrip.begin(); ledStrip.begin();
@ -179,7 +183,7 @@ icm_result_t readICM() {
icmSensor.getEvent(&accel, &gyro, &temp, &mag); icmSensor.getEvent(&accel, &gyro, &temp, &mag);
return { return {
mag.magnetic.y, tiltFilter.input(mag.magnetic.y),
mag.magnetic.x, rollFilter.input(mag.magnetic.x),
}; };
} }

25
NuEVI/src/icm.cpp Normal file
View file

@ -0,0 +1,25 @@
#include "hardware.h"
#include "midi.h"
void checkICM(state_t &state) {
icm_result_t icmSignal = readICM();
Serial.print(">roll: ");
Serial.println(icmSignal.roll);
Serial.print(">tilt: ");
Serial.println(icmSignal.tilt);
if (ExtraControl::CC == state.currentPreset->icmRollMode) {
byte roll = mapConstrain(abs(icmSignal.roll), 0, 40, 127, 0);
if (roll != state.instrument->rollCCVal) {
midiSendControlChange(state.currentPreset->icmRollCC, roll);
state.instrument->rollCCVal = roll;
}
}
if (ExtraControl::CC == state.currentPreset->icmTiltMode) {
byte tilt = mapConstrain(abs(icmSignal.tilt), -20, 40, 0, 127);
if (tilt != state.instrument->tiltCCVal) {
midiSendControlChange(state.currentPreset->icmTiltCC, tilt);
state.instrument->tiltCCVal = tilt;
}
}
}

8
NuEVI/src/icm.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef __ICM_H
#define __ICM_H
#include "settings.h"
void checkICM(state_t &state);
#endif

View file

@ -25,6 +25,14 @@ void singleLED(int n, int color) {
// 0 -> 0, 0, 0, 0, 0, 0, 0, 0 // 0 -> 0, 0, 0, 0, 0, 0, 0, 0
void ledFullMeter(byte indicatedValue, int color){ void ledFullMeter(byte indicatedValue, int color){
static byte lastVal = 0;
static int lastColor = 0;
if (lastVal == indicatedValue && lastColor == color) {
return;
}
lastVal = indicatedValue;
lastColor = color;
int scaledVal = indicatedValue; int scaledVal = indicatedValue;
ledStrip.setBrightness(1); ledStrip.setBrightness(1);
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
@ -79,5 +87,9 @@ void statusLedBlink() {
} }
void updateSensorLEDs(instrument_state_t &state) { void updateSensorLEDs(instrument_state_t &state) {
if (millis() - state.lastKnobTime < KNOB_DISPLAY_TIME) {
ledFullMeter(state.lastKnobVal, 0x00FF00);
} else {
ledFullMeter(state.breathCCVal, 0x0000FF); ledFullMeter(state.breathCCVal, 0x0000FF);
}
} }

View file

@ -516,7 +516,7 @@ public:
} }
if (_focused && input.changed && input.knobMenu != 0) { if (_focused && input.changed && input.knobMenu != 0) {
_cursorPos = (_cursorPos + input.knobMenu) % _entries.size(); _cursorPos = ((_cursorPos + input.knobMenu) + _entries.size()) % _entries.size();
draw(false); draw(false);
redrawValue = true; redrawValue = true;
} }

View file

@ -13,6 +13,7 @@
#include "led.h" #include "led.h"
#include "test.h" #include "test.h"
#include "FilterOnePole.h" #include "FilterOnePole.h"
#include "icm.h"
/* /*
NAME: xEVI NAME: xEVI
@ -92,6 +93,7 @@ bool configManagementMode = false;
bool testMode = false; bool testMode = false;
FilterOnePole breathCCFilter; FilterOnePole breathCCFilter;
FilterOnePole breathBaselineFilter;
//_______________________________________________________________________________________________ SETUP //_______________________________________________________________________________________________ SETUP
@ -444,33 +446,13 @@ void sendCC() {
midiSendControlChange(state.currentPreset->knob4CC, val); midiSendControlChange(state.currentPreset->knob4CC, val);
break; break;
} }
}
state.instrument->knobVals[i] = val; state.instrument->knobVals[i] = val;
state.instrument->lastKnobVal = val;
state.instrument->lastKnobTime = millis();
} }
} }
icm_result_t icmSignal = readICM();
Serial.print(">roll: ");
Serial.println(icmSignal.roll);
Serial.print(">tilt: ");
Serial.println(icmSignal.tilt);
if (ExtraControl::CC == state.currentPreset->icmRollMode) {
byte roll = mapConstrain(abs(icmSignal.roll), 0, 40, 127, 0);
if (roll != state.instrument->rollCCVal) {
midiSendControlChange(state.currentPreset->icmRollCC, roll);
state.instrument->rollCCVal = roll;
} }
}
if (ExtraControl::CC == state.currentPreset->icmTiltMode) {
byte tilt = mapConstrain(abs(icmSignal.tilt), -20, 40, 0, 127);
if (tilt != state.instrument->tiltCCVal) {
midiSendControlChange(state.currentPreset->icmTiltCC, tilt);
state.instrument->tiltCCVal = tilt;
}
}
} }
// Re-zero floating calibration values // Re-zero floating calibration values
@ -602,7 +584,7 @@ int readOctave() {
if (rollers[0]) { if (rollers[0]) {
octaveR = 1; octaveR = 1;
} else if (rollers[5]) { } else if (rollers[5]) {
octaveR = 6; octaveR = 7;
} }
} }
} else if (rollerMode == RollerMode::PARTIAL || rollerMode == RollerMode::PARTIAL_EXTEND) { } else if (rollerMode == RollerMode::PARTIAL || rollerMode == RollerMode::PARTIAL_EXTEND) {
@ -632,6 +614,8 @@ int readOctave() {
if (extend && octaveR == 0) { if (extend && octaveR == 0) {
if (rollerMode == RollerMode::HIGHEST_EXTEND && lastOctaveR == 6) { if (rollerMode == RollerMode::HIGHEST_EXTEND && lastOctaveR == 6) {
octaveR = 7; octaveR = 7;
} else if (rollerMode == RollerMode::HIGHEST_PAIR_EXTEND && lastOctaveR == 7) {
octaveR = 8;
} else if (rollerMode == RollerMode::PARTIAL_EXTEND && lastOctaveR == 7) { } else if (rollerMode == RollerMode::PARTIAL_EXTEND && lastOctaveR == 7) {
octaveR = 8; octaveR = 8;
} else if (lastOctaveR == 1) { } else if (lastOctaveR == 1) {
@ -785,7 +769,8 @@ void initState() {
instrument.activeMIDIchannel = state.currentPreset->MIDIchannel; instrument.activeMIDIchannel = state.currentPreset->MIDIchannel;
midiInitialize(state.currentPreset->MIDIchannel); midiInitialize(state.currentPreset->MIDIchannel);
breathCCFilter.setFilter(LOWPASS, 3, 0.0); // create a one pole (RC) lowpass filter breathCCFilter.setFilter(LOWPASS, 3, 0.0);
breathBaselineFilter.setFilter(LOWPASS, 1, 0.0);
} }
/** /**
@ -802,7 +787,7 @@ void readUtil() {
/** /**
* Send CC data when needed * Send CC data when needed
*/ */
void sendCCs() { void handleCCs() {
static unsigned long ccBreathSendTime = 0L; // The last time we sent breath CC values static unsigned long ccBreathSendTime = 0L; // The last time we sent breath CC values
static unsigned long ccSendTime = 0L; // The last time we sent CC values static unsigned long ccSendTime = 0L; // The last time we sent CC values
static unsigned long ccSendTime2 = 0L; // The last time we sent CC values 2 (slower) static unsigned long ccSendTime2 = 0L; // The last time we sent CC values 2 (slower)
@ -819,6 +804,7 @@ void sendCCs() {
readUtil(); readUtil();
pitch_bend(); pitch_bend();
sendCC(); sendCC();
checkICM(state);
ccSendTime = currentTime; ccSendTime = currentTime;
} }
if (currentTime - ccSendTime2 > CC_INTERVAL_PORT) { if (currentTime - ccSendTime2 > CC_INTERVAL_PORT) {
@ -833,6 +819,43 @@ void sendCCs() {
} }
} }
/**
* Read the breath sensors according to the active mode
*/
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 spikeSignal = constrain(readSpikePressure(), -SPIKE_HI_LIMIT, SPIKE_HI_LIMIT);
instrument.breathMovingThrVal = constrain(
breathBaselineFilter.input((breathSignal + instrument.breathZero) / 2),
instrument.breathThrVal,
instrument.breathMaxVal
);
if (state.currentPreset->breathMode == BREATH_ACC || state.currentPreset->breathMode == BREATH_ACC_AT) {
int delta = breathSignal - instrument.breathZero;
if (abs(delta) > state.calibration->breathAltThrValOffset) {
instrument.breathSignal = constrain(instrument.breathSignal + delta / 10, instrument.breathZero, instrument.breathMaxVal);
}
} 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
Serial.print(">breathThr:");
Serial.println(instrument.breathThrVal);
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);
}
/** /**
* Main instrument state machine * Main instrument state machine
*/ */
@ -842,7 +865,7 @@ void runStateMachine() {
int fingeredNote = noteValueCheck(readSwitches() + readOctave()); int fingeredNote = noteValueCheck(readSwitches() + readOctave());
if (state.mainState == NOTE_OFF) { if (state.mainState == NOTE_OFF) {
handleOffStateActions(); handleOffStateActions();
if (instrument.breathSignal > instrument.breathThrVal && state.mainState == NOTE_OFF) { if (instrument.breathSignal > instrument.breathMovingThrVal && state.mainState == NOTE_OFF) {
// Value has risen above threshold. Move to the RISE_WAIT // Value has risen above threshold. Move to the RISE_WAIT
// state. Record time and initial breath value. // state. Record time and initial breath value.
breath_on_time = millis(); breath_on_time = millis();
@ -850,7 +873,7 @@ void runStateMachine() {
state.mainState = RISE_WAIT; // Go to next state state.mainState = RISE_WAIT; // Go to next state
} }
} else if (state.mainState == RISE_WAIT) { } else if (state.mainState == RISE_WAIT) {
if ((instrument.breathSignal > instrument.breathThrVal)) { 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(fingeredNote, instrument.breathSignal, initial_breath_value);
@ -862,7 +885,7 @@ void runStateMachine() {
state.mainState = NOTE_OFF; state.mainState = NOTE_OFF;
} }
} else if (state.mainState == NOTE_ON) { } else if (state.mainState == NOTE_ON) {
if (instrument.breathSignal < instrument.breathThrVal) { 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
instrument.breathSignal = 0; instrument.breathSignal = 0;
@ -954,35 +977,10 @@ void loop() {
return; return;
} }
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 readBreath();
int16_t spikeSignal = constrain(readSpikePressure(), -SPIKE_HI_LIMIT, SPIKE_HI_LIMIT);
if (state.currentPreset->breathMode == BREATH_ACC || state.currentPreset->breathMode == BREATH_ACC_AT) {
int delta = breathSignal - instrument.breathZero;
if (abs(delta) > state.calibration->breathAltThrValOffset) {
instrument.breathSignal = constrain(instrument.breathSignal + delta / 10, instrument.breathZero, instrument.breathMaxVal);
}
} 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
/*
Serial.print(">breathThr:");
Serial.println(instrument.breathThrVal);
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);
*/
runStateMachine(); runStateMachine();
sendCCs(); handleCCs();
// cvUpdate(); // cvUpdate();
midiDiscardInput(); midiDiscardInput();