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
5. Refactor CV behavior into module
6. 9dof sensor code
7. Alternate fingerings
8. Encoder midi
7. LH fingerings
- 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 CCN_Port 5 // Controller number for portamento level
#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 BREATH_THR_MAX_BOOST 40.0
#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 CALIBRATE_SAMPLE_COUNT 4
@ -31,6 +32,7 @@
#define BTN_PRESET 0x8
#define KNOB_CURVE_THRESHOLD 100
#define KNOB_CURVE_MULTIPLIER 5
#define KNOB_DISPLAY_TIME 500
// Send breath CC data no more than every CC_BREATH_INTERVAL
// milliseconds

View file

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

View file

@ -9,6 +9,8 @@
FilterOnePole breathFilter;
FilterOnePole breathAltFilter;
FilterOnePole spikeFilter;
FilterOnePole tiltFilter;
FilterOnePole rollFilter;
Adafruit_MPR121 touchSensorKeys = 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
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
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);
ledStrip.begin();
@ -179,7 +183,7 @@ icm_result_t readICM() {
icmSensor.getEvent(&accel, &gyro, &temp, &mag);
return {
mag.magnetic.y,
mag.magnetic.x,
tiltFilter.input(mag.magnetic.y),
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
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;
ledStrip.setBrightness(1);
for (int i = 0; i < 8; i++) {
@ -79,5 +87,9 @@ void statusLedBlink() {
}
void updateSensorLEDs(instrument_state_t &state) {
ledFullMeter(state.breathCCVal, 0x0000FF);
if (millis() - state.lastKnobTime < KNOB_DISPLAY_TIME) {
ledFullMeter(state.lastKnobVal, 0x00FF00);
} else {
ledFullMeter(state.breathCCVal, 0x0000FF);
}
}

View file

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

View file

@ -13,6 +13,7 @@
#include "led.h"
#include "test.h"
#include "FilterOnePole.h"
#include "icm.h"
/*
NAME: xEVI
@ -92,6 +93,7 @@ bool configManagementMode = false;
bool testMode = false;
FilterOnePole breathCCFilter;
FilterOnePole breathBaselineFilter;
//_______________________________________________________________________________________________ SETUP
@ -444,33 +446,13 @@ void sendCC() {
midiSendControlChange(state.currentPreset->knob4CC, val);
break;
}
state.instrument->knobVals[i] = val;
state.instrument->lastKnobVal = val;
state.instrument->lastKnobTime = millis();
}
state.instrument->knobVals[i] = val;
}
}
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
@ -602,7 +584,7 @@ int readOctave() {
if (rollers[0]) {
octaveR = 1;
} else if (rollers[5]) {
octaveR = 6;
octaveR = 7;
}
}
} else if (rollerMode == RollerMode::PARTIAL || rollerMode == RollerMode::PARTIAL_EXTEND) {
@ -632,6 +614,8 @@ int readOctave() {
if (extend && octaveR == 0) {
if (rollerMode == RollerMode::HIGHEST_EXTEND && lastOctaveR == 6) {
octaveR = 7;
} else if (rollerMode == RollerMode::HIGHEST_PAIR_EXTEND && lastOctaveR == 7) {
octaveR = 8;
} else if (rollerMode == RollerMode::PARTIAL_EXTEND && lastOctaveR == 7) {
octaveR = 8;
} else if (lastOctaveR == 1) {
@ -785,7 +769,8 @@ void initState() {
instrument.activeMIDIchannel = 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
*/
void sendCCs() {
void handleCCs() {
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 ccSendTime2 = 0L; // The last time we sent CC values 2 (slower)
@ -819,6 +804,7 @@ void sendCCs() {
readUtil();
pitch_bend();
sendCC();
checkICM(state);
ccSendTime = currentTime;
}
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
*/
@ -842,7 +865,7 @@ void runStateMachine() {
int fingeredNote = noteValueCheck(readSwitches() + readOctave());
if (state.mainState == NOTE_OFF) {
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
// state. Record time and initial breath value.
breath_on_time = millis();
@ -850,7 +873,7 @@ void runStateMachine() {
state.mainState = RISE_WAIT; // Go to next state
}
} 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?
if ((millis() - breath_on_time > state.currentPreset->velSmpDl) || (0 == state.currentPreset->velSmpDl) || state.currentPreset->fixedVelocity) {
noteOn(fingeredNote, instrument.breathSignal, initial_breath_value);
@ -862,7 +885,7 @@ void runStateMachine() {
state.mainState = NOTE_OFF;
}
} 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
midiSendNoteOff(instrument.activeNote); // send Note Off message
instrument.breathSignal = 0;
@ -954,35 +977,10 @@ void loop() {
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
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);
*/
readBreath();
runStateMachine();
sendCCs();
handleCCs();
// cvUpdate();
midiDiscardInput();