Added better support for ACC mode
This commit is contained in:
parent
b401b34bb4
commit
e3c91fa6ee
5 changed files with 118 additions and 47 deletions
|
@ -32,6 +32,12 @@ enum FingeringMode : uint8_t {
|
|||
HRN = 3,
|
||||
};
|
||||
|
||||
enum NoteMode : uint8_t {
|
||||
BREATH_TRIGGER = 1,
|
||||
LEVER_TRIGGER = 2,
|
||||
NO_TRIGGER = 3,
|
||||
};
|
||||
|
||||
enum RollerMode : uint8_t {
|
||||
HIGHEST = 1,
|
||||
HIGHEST_EXTEND = 2,
|
||||
|
@ -62,6 +68,7 @@ enum ExtraControl : uint8_t {
|
|||
CC = 3,
|
||||
BEND = 4,
|
||||
VIB_BEND = 5,
|
||||
VELOCITY_RETRIGGER = 6,
|
||||
};
|
||||
|
||||
enum PolySelect : uint8_t {
|
||||
|
|
|
@ -982,18 +982,25 @@ PresetValueMenu<1, uint8_t> vibRetnMenu("RETURN", &preset_t::vibRetn, 0, 4, true
|
|||
PresetValueMenu<0, uint8_t> vibSenseMenu("SENSE LVR", &preset_t::vibSens, 0, 12);
|
||||
PresetValueMenu<0, uint8_t> vibSquelchMenu("SQUELCH LVR", &preset_t::vibSquelch, 0, 12);
|
||||
ChoiceMenu<2, VibratoMode> vibDirMenu("DIRECTION", &preset_t::vibratoMode, { {VSTART_DOWN, VSTART_UP} }, { "DWN", "UP" });
|
||||
ChoiceMenu<4, ExtraControl> biteCtlMenu("BITE CTL", &preset_t::biteControl, { {OFF, VIBRATO, GLIDE, CC} }, { {
|
||||
ChoiceMenu<3, NoteMode> noteModeMenu("NOTE MODE", &preset_t::noteMode, { {BREATH_TRIGGER, LEVER_TRIGGER, NO_TRIGGER} }, { {
|
||||
"BREATH",
|
||||
"LEVER",
|
||||
"OFF",
|
||||
} });
|
||||
ChoiceMenu<5, ExtraControl> biteCtlMenu("BITE CTL", &preset_t::biteControl, { {OFF, VIBRATO, GLIDE, CC, VELOCITY_RETRIGGER} }, { {
|
||||
"OFF",
|
||||
"VIBRATO",
|
||||
"GLIDE",
|
||||
"CC"
|
||||
"CC",
|
||||
"VEL RT"
|
||||
} });
|
||||
PresetValueMenu<128, uint8_t> biteCCMenu("BITE CC", &preset_t::biteCC, 0, 127, true, CC_NAMES);
|
||||
ChoiceMenu<4, ExtraControl> leverCtlMenu("LEVER CTL", &preset_t::leverControl, { {OFF, VIBRATO, GLIDE, CC} }, {
|
||||
ChoiceMenu<5, ExtraControl> leverCtlMenu("LEVER CTL", &preset_t::leverControl, { {OFF, VIBRATO, GLIDE, CC, VELOCITY_RETRIGGER} }, {
|
||||
"OFF",
|
||||
"VIB",
|
||||
"GLD",
|
||||
"CC"
|
||||
"CC",
|
||||
"VEL RT"
|
||||
});
|
||||
PresetValueMenu<128, uint8_t> leverCCMenu("LEVER CC", &preset_t::leverCC, 0, 127, true, CC_NAMES);
|
||||
ChoiceMenu<4, PortamentoMode> portMenu("GLIDE MOD", &preset_t::portamentoMode, { {POFF, PON, PSWITCH_ONLY, PGLIDE_ONLY} }, {
|
||||
|
@ -1006,7 +1013,7 @@ PresetValueMenu<0, uint8_t> portLimitMenu("GLIDE LMT", &preset_t::portamentoLimi
|
|||
PresetValueMenu<0, uint8_t> pitchBendMenu("PITCHBEND", &preset_t::PBdepth, 0, 12, true);
|
||||
ChoiceMenu<4, ExtraControl> extraCtlMenu("EXT CTL", &preset_t::extraControl, { {OFF, VIBRATO, GLIDE, CC} }, { "OFF", "VIBRATO", "GLIDE", "CC" });
|
||||
PresetValueMenu<128, uint8_t> extraCCMenu("EXT CC", &preset_t::extraCC, 0, 127, true, CC_NAMES);
|
||||
ChoiceMenu<6, ExtraControl> pbCtlMenu("PB CTL", &preset_t::pbControl, { {OFF, VIBRATO, GLIDE, CC, BEND, VIB_BEND} }, { "OFF", "VIBRATO", "GLIDE", "CC", "BEND", "VIB_BEND" });
|
||||
ChoiceMenu<7, ExtraControl> pbCtlMenu("PB CTL", &preset_t::pbControl, { {OFF, VIBRATO, GLIDE, CC, BEND, VIB_BEND, VELOCITY_RETRIGGER} }, { "OFF", "VIBRATO", "GLIDE", "CC", "BEND", "VIB+BEND", "VEL RT" });
|
||||
PresetValueMenu<128, uint8_t> pbCCMenu("PB CC", &preset_t::pbCC, 0, 127, true, CC_NAMES);
|
||||
PresetValueMenu<128, uint8_t> pbYCCMenu("PB Y CC", &preset_t::pbYCC, 0, 127, true, CC_NAMES);
|
||||
PresetValueMenu<128, uint8_t> stickXCCMenu("STICK X CC", &preset_t::stickXCC, 0, 127, true, CC_NAMES);
|
||||
|
@ -1088,10 +1095,11 @@ std::array<MenuScreen *const, 11> breathMenuEntries = {
|
|||
};
|
||||
SubMenu<11> breathMenu("BR SETUP", breathMenuEntries);
|
||||
|
||||
const std::array<MenuScreen *const, 25> controlMenuEntries = {
|
||||
const std::array<MenuScreen *const, 26> controlMenuEntries = {
|
||||
&fingeringMenu,
|
||||
&polyMenu,
|
||||
&rollerMenu,
|
||||
¬eModeMenu,
|
||||
&biteCtlMenu,
|
||||
&biteCCMenu,
|
||||
&pbCtlMenu,
|
||||
|
@ -1115,7 +1123,7 @@ const std::array<MenuScreen *const, 25> controlMenuEntries = {
|
|||
&accelModeMenu,
|
||||
&accelCCMenu,
|
||||
};
|
||||
SubMenu<25> controlMenu("CTL SETUP", controlMenuEntries);
|
||||
SubMenu<26> controlMenu("CTL SETUP", controlMenuEntries);
|
||||
|
||||
const std::array<MenuScreen *const, 5> vibratoMenuEntries = {
|
||||
&vibDepthMenu,
|
||||
|
|
|
@ -347,6 +347,9 @@ void readEEPROM(const bool factoryReset, calibration_t &calibration) {
|
|||
presets[i].spikeOnFactor = 5;
|
||||
presets[i].spikeOffFactor = 5;
|
||||
}
|
||||
if (settings_version < 6) {
|
||||
presets[i].noteMode = BREATH_TRIGGER;
|
||||
}
|
||||
}
|
||||
|
||||
writePresets();
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "globals.h"
|
||||
|
||||
|
||||
#define EEPROM_VERSION 5
|
||||
#define EEPROM_VERSION 6
|
||||
#define EEPROM_VERSION_ADDR 0
|
||||
#define SETTINGS_OFFSET 2
|
||||
#define PRESET_MAX_SIZE 128 // Leave extra space for future settings
|
||||
|
@ -106,8 +106,9 @@ struct preset_t {
|
|||
uint8_t pbYCC = 13; // pbY CC selection
|
||||
uint8_t stickXCC = 14; // stickX CC selection
|
||||
uint8_t stickYCC = 15; // stickY CC selection
|
||||
NoteMode noteMode = NoteMode::BREATH_TRIGGER;
|
||||
|
||||
uint8_t _reserved[77];
|
||||
uint8_t _reserved[76];
|
||||
};
|
||||
|
||||
static_assert(sizeof(preset_t) == PRESET_MAX_SIZE, "preset_t must be 128 bytes");
|
||||
|
|
|
@ -217,12 +217,36 @@ int patchLimit(int value) {
|
|||
|
||||
int breath() {
|
||||
static int oldbreath = 0;
|
||||
static unsigned int oldbreathhires = 0;
|
||||
static int oldbreathhires = 0;
|
||||
|
||||
int breathCCval, breathCCvalFine;
|
||||
unsigned int breathCCvalHires;
|
||||
breathCCvalHires = breathCurve(mapConstrain(instrument.breathSignal, instrument.breathBaseline, instrument.breathMaxVal, 0, 16383));
|
||||
breathCCvalHires = breathCCFilter.input(breathCCvalHires);
|
||||
int breathCCvalHires;
|
||||
if (state.currentPreset->breathMode == BREATH_ACC || state.currentPreset->breathMode == BREATH_ACC_AT) {
|
||||
int diff = instrument.breathSignal - instrument.breathZero;
|
||||
if (instrument.mode == MODE_DEBUG) {
|
||||
Serial.print(">accdiff:");
|
||||
Serial.println(diff);
|
||||
}
|
||||
if (abs(diff) > calibration.breathThrValOffset) {
|
||||
if (diff > 0) {
|
||||
breathCCvalHires = breathCurve(mapConstrain(diff, calibration.breathThrValOffset, calibration.breathMaxValOffset, 0, 16383));
|
||||
} else {
|
||||
breathCCvalHires = -breathCurve(mapConstrain(-diff, calibration.breathThrValOffset, calibration.breathMaxValOffset, 0, 16383));
|
||||
}
|
||||
// breathCCvalHires = breathCCFilter.input(breathCCvalHires);
|
||||
if (instrument.mode == MODE_DEBUG) {
|
||||
Serial.print(">accdelta:");
|
||||
Serial.println(breathCCvalHires);
|
||||
}
|
||||
breathCCvalHires = constrain(oldbreathhires + breathCCvalHires / 4, 0, 16383);
|
||||
} else {
|
||||
breathCCvalHires = oldbreathhires;
|
||||
}
|
||||
} else {
|
||||
breathCCvalHires = breathCurve(mapConstrain(instrument.breathSignal, instrument.breathBaseline, instrument.breathMaxVal, 0, 16383));
|
||||
breathCCvalHires = breathCCFilter.input(breathCCvalHires);
|
||||
}
|
||||
|
||||
breathCCval = (breathCCvalHires >> 7) & 0x007F;
|
||||
breathCCvalFine = breathCCvalHires & 0x007F;
|
||||
if (breathCCval != oldbreath) { // only send midi data if breath has changed from previous value
|
||||
|
@ -240,7 +264,7 @@ int breath() {
|
|||
}
|
||||
|
||||
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|| state.currentPreset->breathMode == BreathMode::BREATH_ACC)) {
|
||||
midiSendControlChange(state.currentPreset->breathCC + 32, breathCCvalFine);
|
||||
}
|
||||
|
||||
|
@ -396,7 +420,7 @@ void portamento_() {
|
|||
|
||||
void sendCC() {
|
||||
if (ExtraControl::CC == state.currentPreset->biteControl) {
|
||||
int biteVal = mapConstrain(instrument.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, 0, 127);
|
||||
int biteVal = mapConstrain(instrument.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, 127, 0);
|
||||
|
||||
if (biteVal != instrument.biteVal) {
|
||||
midiSendControlChange(state.currentPreset->biteCC, biteVal);
|
||||
|
@ -413,14 +437,13 @@ void sendCC() {
|
|||
instrument.extraVal = extraVal;
|
||||
}
|
||||
|
||||
int leverVal = mapConstrain(instrument.leverSignal, calibration.leverMinVal, calibration.leverMaxVal, 0, 127);
|
||||
if (ExtraControl::CC == state.currentPreset->leverControl) {
|
||||
int leverVal = mapConstrain(instrument.leverSignal, calibration.leverMinVal, calibration.leverMaxVal, 0, 127);
|
||||
|
||||
if (leverVal != instrument.leverVal) {
|
||||
midiSendControlChange(state.currentPreset->leverCC, leverVal);
|
||||
}
|
||||
instrument.leverVal = leverVal;
|
||||
}
|
||||
instrument.leverVal = leverVal;
|
||||
|
||||
if (ExtraControl::CC == state.currentPreset->pbControl) {
|
||||
int pbVal = mapConstrain(instrument.pbSignal, calibration.pbMinVal, calibration.pbMaxVal, 0, 127);
|
||||
|
@ -778,20 +801,42 @@ void readSwitches() {
|
|||
lastOctave = fingeredOctave;
|
||||
}
|
||||
|
||||
void noteOn(int fingeredNote, int pressureSensor, int initial_breath_value) {
|
||||
// Yes, so calculate MIDI note and velocity, then send a note on event
|
||||
// We should be at tonguing peak, so set velocity based on current pressureSensor value unless fixed velocity is set
|
||||
instrument.breathSignal = constrain(max(pressureSensor, initial_breath_value), instrument.breathBaseline, instrument.breathMaxVal);
|
||||
byte velocitySend;
|
||||
if (!state.currentPreset->fixedVelocity) {
|
||||
unsigned int breathValHires = breathCurve(mapConstrain(instrument.breathSignal, instrument.breathBaseline, instrument.breathMaxVal, 0, 16383));
|
||||
velocitySend = (breathValHires >> 7) & 0x007F;
|
||||
velocitySend = constrain(velocitySend + velocitySend * .1 * state.currentPreset->velBias, 1, 127);
|
||||
} else {
|
||||
velocitySend = state.currentPreset->fixedVelocity;
|
||||
uint8_t controlVel() {
|
||||
uint8_t velocity = 0;
|
||||
if (ExtraControl::VELOCITY_RETRIGGER == state.currentPreset->biteControl) {
|
||||
velocity = mapConstrain(instrument.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, 127, 1);
|
||||
}
|
||||
|
||||
midiSendNoteOn(fingeredNote, velocitySend); // send Note Off message
|
||||
if (ExtraControl::VELOCITY_RETRIGGER == state.currentPreset->leverControl) {
|
||||
velocity = mapConstrain(instrument.leverSignal, calibration.leverMinVal, calibration.leverMaxVal, 1, 127);
|
||||
}
|
||||
|
||||
if (ExtraControl::VELOCITY_RETRIGGER == state.currentPreset->pbControl) {
|
||||
velocity = mapConstrain(instrument.pbSignal, calibration.pbMinVal, calibration.pbMaxVal, 1, 127);
|
||||
}
|
||||
|
||||
return velocity;
|
||||
}
|
||||
|
||||
uint8_t breathVel() {
|
||||
// Set velocity based on current pressureSensor value unless fixed velocity is set
|
||||
int velocitySend;
|
||||
if (state.currentPreset->fixedVelocity) {
|
||||
return state.currentPreset->fixedVelocity;
|
||||
}
|
||||
if (state.currentPreset->noteMode == LEVER_TRIGGER) {
|
||||
return instrument.leverVal;
|
||||
}
|
||||
|
||||
unsigned int breathValHires = breathCurve(mapConstrain(instrument.breathSignal, instrument.breathBaseline, instrument.breathMaxVal, 0, 16383));
|
||||
velocitySend = (breathValHires >> 7) & 0x007F;
|
||||
velocitySend = constrain(velocitySend + velocitySend * .1 * state.currentPreset->velBias, 1, 127);
|
||||
|
||||
return velocitySend;
|
||||
}
|
||||
|
||||
void noteOn(int fingeredNote) {
|
||||
midiSendNoteOn(fingeredNote, breathVel());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -803,15 +848,20 @@ void changeNote(int fingeredNote, int activeNote, int fingeredNote2, int activeN
|
|||
return;
|
||||
}
|
||||
|
||||
int velocity = controlVel();
|
||||
if (!velocity) {
|
||||
velocity = breathVel();
|
||||
}
|
||||
|
||||
// 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);
|
||||
midiSendNoteOn(fingeredNote, velocity);
|
||||
}
|
||||
|
||||
if (fingeredNote2 != fingeredNote && fingeredNote2 != activeNote && fingeredNote2 != activeNote2) {
|
||||
noteOn(fingeredNote2, instrument.breathSignal, 0);
|
||||
midiSendNoteOn(fingeredNote2, velocity);
|
||||
}
|
||||
|
||||
delayMicroseconds(2000); // delay for midi recording fix
|
||||
|
@ -896,6 +946,11 @@ void handleCCs() {
|
|||
}
|
||||
}
|
||||
|
||||
int adjustRetriggerVel(int initialVel) {
|
||||
int vel = initialVel;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the breath sensors according to the active mode
|
||||
*/
|
||||
|
@ -906,14 +961,7 @@ void readBreath() {
|
|||
int16_t breathAltSignal = constrain(readAltPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT) + instrument.breathAltZeroOffset;
|
||||
int16_t spikeSignal = constrain(readSpikePressure(), -SPIKE_HI_LIMIT, SPIKE_HI_LIMIT);
|
||||
int16_t diffSignal = breathAltSignal - breathSignal;
|
||||
if (state.currentPreset->breathMode == BREATH_ACC || state.currentPreset->breathMode == BREATH_ACC_AT) {
|
||||
int delta = breathSignal - instrument.breathZero;
|
||||
if (abs(delta) > state.calibration->breathThrValOffset) {
|
||||
instrument.breathSignal = constrain(instrument.breathSignal + delta / 15, instrument.breathZero, instrument.breathMaxVal);
|
||||
}
|
||||
} else {
|
||||
instrument.breathSignal = breathSignal + diffSignal + (spikeSignal > 0 ? spikeSignal * state.currentPreset->spikeOnFactor : spikeSignal * state.currentPreset->spikeOffFactor);
|
||||
}
|
||||
instrument.breathSignal = breathSignal + diffSignal + (spikeSignal > 0 ? spikeSignal * state.currentPreset->spikeOnFactor : spikeSignal * state.currentPreset->spikeOffFactor);
|
||||
instrument.breathAltSignal = breathAltSignal;
|
||||
|
||||
|
||||
|
@ -962,23 +1010,27 @@ 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
|
||||
bool lever_trigger = state.currentPreset->noteMode == LEVER_TRIGGER;
|
||||
if (state.currentPreset->noteMode == NO_TRIGGER) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.mainState == NOTE_OFF) {
|
||||
handleOffStateActions();
|
||||
if (instrument.breathSignal > instrument.breathThrVal && state.mainState == NOTE_OFF) {
|
||||
bool crossed_threshold = lever_trigger ? instrument.leverVal > 0 : instrument.breathSignal > instrument.breathThrVal;
|
||||
if (crossed_threshold && 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();
|
||||
initial_breath_value = instrument.breathSignal;
|
||||
state.mainState = RISE_WAIT; // Go to next state
|
||||
}
|
||||
} else if (state.mainState == RISE_WAIT) {
|
||||
if ((instrument.breathSignal > instrument.breathMovingThrVal)) {
|
||||
if ((lever_trigger ? instrument.leverVal > 0 : 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(instrument.fingeredNote, instrument.breathSignal, initial_breath_value);
|
||||
noteOn(instrument.fingeredNote);
|
||||
if (instrument.fingeredNote != instrument.fingeredNote2) {
|
||||
noteOn(instrument.fingeredNote2, instrument.breathSignal, initial_breath_value);
|
||||
noteOn(instrument.fingeredNote2);
|
||||
}
|
||||
breath(); // send breath data
|
||||
state.mainState = NOTE_ON;
|
||||
|
@ -990,7 +1042,7 @@ void runStateMachine() {
|
|||
state.mainState = NOTE_OFF;
|
||||
}
|
||||
} else if (state.mainState == NOTE_ON) {
|
||||
if (instrument.breathSignal < instrument.breathThrOffVal) {
|
||||
if (lever_trigger ? instrument.leverVal <= 0 : instrument.breathSignal < instrument.breathThrOffVal) {
|
||||
// Value has fallen below threshold - turn the note off
|
||||
midiSendNoteOff(instrument.activeNote); // send Note Off message
|
||||
if (instrument.activeNote != instrument.activeNote2) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue