* Adjustment setting for thumb lever (for optimizing thumb portamento control). By setting THR (level of push force to activate) and MAX (level of push force to achieve maximum set portamento) values close to eachother at the desired point of activation, the new glide limit setting to desired rate will create a switching type set rate controller (similar to Crumar EVI glide key). With THR and MAX setup with separation to taste, a continous control up to level set by glide limit is achieved.

* Glide setting SWO, SWitching Only, sending only Glide on/off (CC#65) for use with synths where glide rate CC#5 is used in non standard ways, for example some DSI/Sequential synths like the Prophet REV2 or Prophet 12 where glide rates are set individually for each oscillator.

* Glide limit setting for portamento. Doubles as setting for portamento level sent using pinky key/mod key in GLD mode. (Can be changed both in menu and in GLD mode.)

* Setting of level for LVL, LVP and GLD now reqires touching both pinky/mod and third trill/RHp3 for setting mode activation, this to avoid accidental change of setting when pinky/mod key is touched.

* Rate of setting movement up and down for LVL, LVP and GLD has been adjusted. Became very much too fast after the timing issues were solved in 1.5b1

* A short delay before note offs in legato transitions is added to make playback of recorded midi behave correctly (keeping note on and note off from being registered on the same timestamp).
This commit is contained in:
Johan Berglund 2020-08-19 23:07:38 +02:00
parent 51f5ab54f6
commit ee438c200d
9 changed files with 10909 additions and 39 deletions

View file

@ -64,6 +64,8 @@ unsigned short pitchbMaxVal;// = 2400;
unsigned short extracThrVal;// = 1200;
unsigned short extracMaxVal;// = 2400;
unsigned short ctouchThrVal;// = 120;
unsigned short leverThrVal;
unsigned short leverMaxVal;
unsigned short transpose;
unsigned short MIDIchannel;
unsigned short breathCC; // OFF:MW:BR:VL:EX:MW+:BR+:VL+:EX+:CF
@ -72,6 +74,7 @@ unsigned short breathCC2Rise; // 1X:2X:3X:4X:5X
unsigned short breathAT;
unsigned short velocity;
unsigned short portamento;// switching on cc65? just cc5 enabled? SW:ON:OFF
unsigned short portLimit; // 1-127
unsigned short PBdepth; // OFF:1-12 divider
unsigned short extraCT; // OFF:MW:FP:CF:SP
unsigned short vibrato; // OFF:1-9
@ -157,6 +160,7 @@ unsigned long lastDeglitchTime = 0; // The last time the fingering was c
unsigned long ccSendTime = 0L; // The last time we sent CC values
unsigned long ccSendTime2 = 0L; // The last time we sent CC values 2 (slower)
unsigned long ccSendTime3 = 0L; // The last time we sent CC values 3 (and slower)
unsigned long lvlTime = 0L;
unsigned long ccBreathSendTime = 0L; // The last time we sent breath CC values
unsigned long breath_on_time = 0L; // Time when breath sensor value went over the ON threshold
unsigned long currentTime;
@ -194,9 +198,9 @@ int breathCalZero;
int leverPortZero;
#if defined(NURAD)
int leverPortThr = 50;
int leverPortThr = 70;
#else
int leverPortThr = 50;
int leverPortThr = 70;
#endif
int leverPortRead;
@ -909,33 +913,45 @@ void loop() {
subOctaveDouble = 0;
}
if ((pinkySetting == LVL) || (pinkySetting == LVLP)){
if (pinkyKey){
if (pinkyKey && K7){
ledMeter(levelVal);
if (K6 && (levelVal < 127)){
levelVal++;
if (levelCC) midiSendControlChange(levelCC, levelVal);
else midiSendAfterTouch(levelVal);
if (currentTime - lvlTime > (LVL_TIMER_INTERVAL)){
levelVal++;
if (levelCC) midiSendControlChange(levelCC, levelVal);
else midiSendAfterTouch(levelVal);
lvlTime = currentTime;
}
} else if (K5 && (levelVal > 0)){
levelVal--;
if (levelCC) midiSendControlChange(levelCC, levelVal);
else midiSendAfterTouch(levelVal);
if (currentTime - lvlTime > (LVL_TIMER_INTERVAL)){
levelVal--;
if (levelCC) midiSendControlChange(levelCC, levelVal);
else midiSendAfterTouch(levelVal);
lvlTime = currentTime;
}
}
} else if (lastPinkyKey){
} else if (!pinkyKey && lastPinkyKey){
writeSetting(LEVEL_VAL_ADDR,levelVal);
}
lastPinkyKey = pinkyKey;
} else if (pinkySetting == GLD){
if (pinkyKey){
ledMeter(levelVal);
if (K6 && (levelVal < 127)){
levelVal++;
midiSendControlChange(CCN_Port, levelVal);
} else if (K5 && (levelVal > 0)){
levelVal--;
midiSendControlChange(CCN_Port, levelVal);
if (pinkyKey && K7){
ledMeter(portLimit);
if (K6 && (portLimit < 127)){
if (currentTime - lvlTime > (LVL_TIMER_INTERVAL)){
portLimit++;
if (portamento && (portamento != 5)) midiSendControlChange(CCN_Port, portLimit);
lvlTime = currentTime;
}
} else if (K5 && (portLimit > 0)){
if (currentTime - lvlTime > (LVL_TIMER_INTERVAL)){
portLimit--;
if (portamento && (portamento != 5)) midiSendControlChange(CCN_Port, portLimit);
lvlTime = currentTime;
}
}
} else if (lastPinkyKey){
writeSetting(LEVEL_VAL_ADDR,levelVal);
} else if (!pinkyKey && lastPinkyKey){
writeSetting(PORTLIMIT_ADDR,portLimit);
}
lastPinkyKey = pinkyKey;
}
@ -1283,6 +1299,7 @@ void loop() {
}
if (!parallelChord && !subOctaveDouble && !rotatorOn) { // mono playing, send old note off after new note on
delayMicroseconds(2000); //delay for midi recording fix
midiSendNoteOff(activeNote); // send Note Off message
}
@ -1317,7 +1334,7 @@ void loop() {
if (currentTime - ccSendTime3 > CC_INTERVAL3) {
if (gateOpenEnable || gateOpen) doorKnobCheck();
battCheck();
if (((pinkySetting == LVL) || (pinkySetting == LVLP) || (pinkySetting == GLD)) && pinkyKey && (mainState == NOTE_OFF)){
if (((pinkySetting == LVL) || (pinkySetting == LVLP) || (pinkySetting == GLD)) && pinkyKey && K7 && (mainState == NOTE_OFF)){
// show LVL indication
} else updateSensorLEDs();
ccSendTime3 = currentTime;
@ -1768,7 +1785,7 @@ void portamento_() {
biteSensor = touchRead(bitePin); // get sensor data, do some smoothing - SENSOR PIN 17 - PCB PINS LABELED "BITE" (GND left, sensor pin right)
}
if (pinkySetting == GLD){
if (pinkyKey){
if (portamento && pinkyKey){
if (!portIsOn) {
portOn();
}
@ -1789,7 +1806,7 @@ void portamento_() {
} else if (1 == vibControl) {
// Portamento is switched to lever control
leverPortRead = touchRead(vibratoPin);
if (portamento && (leverPortRead <= (leverPortZero-leverPortThr))) { // if we are enabled and over the threshold, send portamento
if (portamento && ((3000-leverPortRead) >= leverThrVal)) { // if we are enabled and over the threshold, send portamento
if (!portIsOn) {
portOn();
}
@ -1807,7 +1824,7 @@ void portamento_() {
//***********************************************************
void portOn() {
if (portamento == 2) { // if portamento midi switching is enabled
if ((portamento == 2) || (portamento == 5)) { // if portamento midi switching is enabled
midiSendControlChange(CCN_PortOnOff, 127);
} else if (portamento == 3) { // if portamento midi switching is enabled - SE02 OFF/LIN
midiSendControlChange(CCN_PortSE02, 64);
@ -1822,12 +1839,12 @@ void portOn() {
void port() {
int portCC;
if (pinkySetting == GLD){
portCC = levelVal;
} else if (1 != vibControl)
portCC = map(constrain(biteSensor, portamThrVal, portamMaxVal), portamThrVal, portamMaxVal, 0, 127);
else
portCC = constrain((leverPortZero-leverPortThr-leverPortRead),0,127);
if (portCC != oldport) {
portCC = portLimit;
} else if (1 == vibControl)
portCC = map(constrain((3000-leverPortRead), leverThrVal, leverMaxVal), leverThrVal, leverMaxVal, 0, portLimit);
else
portCC = map(constrain(biteSensor, portamThrVal, portamMaxVal), portamThrVal, portamMaxVal, 0, portLimit);
if ((portamento != 5) && (portCC != oldport)) { // portamento setting 5 is switch only, do not transmit glide rate
midiSendControlChange(CCN_Port, portCC);
}
oldport = portCC;
@ -1836,10 +1853,10 @@ void port() {
//***********************************************************
void portOff() {
if (oldport != 0) { //did a zero get sent? if not, then send one
if ((portamento != 5) && (oldport != 0)) { //did a zero get sent? if not, then send one (unless portamento is switch only)
midiSendControlChange(CCN_Port, 0);
}
if (portamento == 2) { // if portamento midi switching is enabled
if ((portamento == 2) || (portamento == 5)) { // if portamento midi switching is enabled
midiSendControlChange(CCN_PortOnOff, 0);
} else if (portamento == 3) { // if portamento midi switching is enabled - SE02 OFF/LIN
midiSendControlChange(CCN_PortSE02, 0);
@ -1876,6 +1893,12 @@ void autoCal() {
pitchbMaxVal = constrain(pitchbThrVal+800, pitchbLoLimit, pitchbHiLimit);
writeSetting(PITCHB_THR_ADDR, pitchbThrVal);
writeSetting(PITCHB_MAX_ADDR, pitchbMaxVal);
// Lever
calRead = 3000-touchRead(vibratoPin);
leverThrVal = constrain(calRead+70, leverLoLimit, leverHiLimit);
leverMaxVal = constrain(calRead+150, leverLoLimit, leverHiLimit);
writeSetting(LEVER_THR_ADDR, leverThrVal);
writeSetting(LEVER_MAX_ADDR, leverMaxVal);
#if defined(NURAD) // NuRAD sensor calibration
// Pressure sensor
calRead = analogRead(bitePressurePin);

View file

@ -113,12 +113,29 @@ const AdjustMenuEntry ctouchAdjustMenu = {
ctouchThrSave
};
static void leverSave(const AdjustMenuEntry& e) {
writeSetting(LEVER_THR_ADDR, *e.entries[0].value);
writeSetting(LEVER_MAX_ADDR, *e.entries[1].value);
}
const AdjustMenuEntry leverAdjustMenu = {
"THUMB LEVER",
{
{ &leverThrVal, leverLoLimit, leverHiLimit },
{ &leverMaxVal, leverLoLimit, leverHiLimit }
},
leverSave
};
const AdjustMenuEntry* adjustMenuEntries[] = {
&breathAdjustMenu,
&portamentoAdjustMenu,
&pitchBendAdjustMenu,
&extraSensorAdjustMenu,
&ctouchAdjustMenu,
&leverAdjustMenu,
};
static const int numAdjustEntries = ARR_LEN(adjustMenuEntries);
@ -277,6 +294,12 @@ void plotSensorPixels(){
redraw = 1;
}
#endif
else if(adjustOption == 5) {
int pos = map(constrain(3000-touchRead(vibratoPin), leverLoLimit, leverHiLimit), leverLoLimit, leverHiLimit, 28, 118);
redraw = updateSensorPixel(pos, -1);
}
if (redraw){
display.display();
}

View file

@ -5,7 +5,7 @@
// Compile options, comment/uncomment to change
#define FIRMWARE_VERSION "1.5b1" // FIRMWARE VERSION NUMBER HERE <<<<<<<<<<<<<<<<<<<<<<<
#define FIRMWARE_VERSION "1.5b2" // FIRMWARE VERSION NUMBER HERE <<<<<<<<<<<<<<<<<<<<<<<
#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
@ -19,6 +19,7 @@
#define CC_INTERVAL 13
#define CC_INTERVAL2 19
#define CC_INTERVAL3 37
#define LVL_TIMER_INTERVAL 15
#define CVPORTATUNE 2
@ -34,6 +35,8 @@
#define ctouchHiLimit 350
#define ttouchLoLimit 50
#define ttouchHiLimit 1900
#define leverLoLimit 1400
#define leverHiLimit 2000
#define MIN_LED_BRIGHTNESS 5 // lowest PWM value that still is visible

View file

@ -65,6 +65,8 @@ extern unsigned short pitchbMaxVal;
extern unsigned short extracThrVal;
extern unsigned short extracMaxVal;
extern unsigned short ctouchThrVal;
extern unsigned short leverThrVal;
extern unsigned short leverMaxVal;
extern unsigned short transpose;
extern unsigned short MIDIchannel;
extern unsigned short breathCC; // OFF:MW:BR:VL:EX:MW+:BR+:VL+:EX+:CF:UNO
@ -73,6 +75,7 @@ extern unsigned short breathCC2Rise; // 1X:2X:3X:4X:5X
extern unsigned short breathAT;
extern unsigned short velocity;
extern unsigned short portamento;// switching on cc65? just cc5 enabled? SW:ON:OFF
extern unsigned short portLimit; // 1-127
extern unsigned short PBdepth; // OFF:1-12 divider
extern unsigned short extraCT; // OFF:MW:FP:CF:SP
extern unsigned short vibrato; // OFF:1-9
@ -128,6 +131,8 @@ extern uint16_t dacMode;
extern int touch_Thr;
extern int leverPortZero;
extern unsigned long cursorBlinkTime; // the last time the cursor was toggled
extern byte activePatch;

View file

@ -413,7 +413,7 @@ static void mainTitleGetStr(char* out) {
case 2:
vLowLimit = LIP_BAT_LOW;
}
if (vMeterReading < vLowLimit) { //2300 alkaline, 2250 lipo, 2200 nimh
if (vMeterReading <= vLowLimit) { //2300 alkaline, 2250 lipo, 2200 nimh
memcpy(splice2, "LOW ", 4);
} else {
int voltage = map(vMeterReading,2200,3060,36,50);
@ -1269,15 +1269,27 @@ const MenuPage breathMenuPage = {
//***********************************************************
// Control menu
const MenuEntrySub portMenu = {
MenuType::ESub, "PORT/GLD", "PORT/GLD", &portamento, 0, 4, MenuEntryFlags::EMenuEntryWrap,
MenuType::ESub, "GLIDE CTL", "PORT/GLD", &portamento, 0, 5, MenuEntryFlags::EMenuEntryWrap,
[](SubMenuRef __unused,char* out, const char ** __unused unit) {
const char* labs[] = { "OFF", "ON", "SW", "SEL", "SEE" };
const char* labs[] = { "OFF", "ON", "SW", "SEL", "SEE", "SWO" };
strncpy(out, labs[portamento], 4);
},
[](SubMenuRef __unused sub) { writeSetting(PORTAM_ADDR,portamento); }
, nullptr
};
const MenuEntrySub portLimitMenu = {
MenuType::ESub, "GLIDE LMT", "MAX LEVEL", &portLimit, 1, 127, MenuEntryFlags::EMenuEntryWrap,
[](SubMenuRef __unused, char* out, const char** __unused unit) {
numToString(portLimit, out);
},
[](const SubMenuRef & __unused sub) { writeSetting(PORTLIMIT_ADDR,portLimit); }
, nullptr
};
const MenuEntrySub pitchBendMenu = {
MenuType::ESub, "PITCHBEND", "PITCHBEND", &PBdepth, 0, 12, MenuEntryFlags::ENone,
[](SubMenuRef __unused, char* out, const char** __unused unit) {
@ -1429,6 +1441,7 @@ const MenuEntrySub lpinky3Menu = {
#if defined(NURAD)
const MenuEntry* controlMenuEntries[] = {
(MenuEntry*)&portMenu,
(MenuEntry*)&portLimitMenu,
(MenuEntry*)&extraMenu,
(MenuEntry*)&extraCC2Menu,
(MenuEntry*)&harmonicsMenu,
@ -1444,6 +1457,7 @@ const MenuEntry* controlMenuEntries[] = {
#else
const MenuEntry* controlMenuEntries[] = {
(MenuEntry*)&portMenu,
(MenuEntry*)&portLimitMenu,
(MenuEntry*)&extraMenu,
(MenuEntry*)&extraCC2Menu,
(MenuEntry*)&harmonicsMenu,

View file

@ -151,6 +151,12 @@ void readEEPROM(const bool factoryReset) {
writeSetting(BRINTERV_ADDR, BRINTERV_FACTORY);
writeSetting(OTFKEY_ADDR, OTFKEY_FACTORY);
}
if(settingsVersion < 40) {
writeSetting(PORTLIMIT_ADDR, PORTLIMIT_FACTORY);
writeSetting(LEVER_THR_ADDR, LEVER_THR_FACTORY);
writeSetting(LEVER_MAX_ADDR, LEVER_MAX_FACTORY);
}
writeSetting(VERSION_ADDR, EEPROM_VERSION);
@ -168,7 +174,7 @@ void readEEPROM(const bool factoryReset) {
breathCC = readSettingBounded(BREATH_CC_ADDR, 0, 10, BREATH_CC_FACTORY);
breathAT = readSettingBounded(BREATH_AT_ADDR, 0, 1, BREATH_AT_FACTORY);
velocity = readSettingBounded(VELOCITY_ADDR, 0, 127, VELOCITY_FACTORY);
portamento = readSettingBounded(PORTAM_ADDR, 0, 4, PORTAM_FACTORY);
portamento = readSettingBounded(PORTAM_ADDR, 0, 5, PORTAM_FACTORY);
PBdepth = readSettingBounded(PB_ADDR, 0, 12, PB_FACTORY);
extraCT = readSettingBounded(EXTRA_ADDR, 0, 4, EXTRA_FACTORY);
vibrato = readSettingBounded(VIBRATO_ADDR, 0, 9, VIBRATO_FACTORY);
@ -237,6 +243,9 @@ void readEEPROM(const bool factoryReset) {
rotationsc[3] = readSettingBounded(ROTC4_ADDR, 0, 48, ROTC4_FACTORY);
otfKey = readSettingBounded(OTFKEY_ADDR, 0, 1, OTFKEY_FACTORY);
breathInterval = readSettingBounded(BRINTERV_ADDR, 3, 15, BRINTERV_FACTORY);
portLimit = readSettingBounded(PORTLIMIT_ADDR, 1, 127, PORTLIMIT_FACTORY);
leverThrVal = readSettingBounded(LEVER_THR_ADDR, leverLoLimit, leverHiLimit, LEVER_THR_FACTORY);
leverMaxVal = readSettingBounded(LEVER_MAX_ADDR, leverLoLimit, leverHiLimit, LEVER_MAX_FACTORY);
//Flags stored in bit field
fastBoot = (dipSwBits & (1<<DIPSW_FASTBOOT))?1:0;

View file

@ -81,8 +81,11 @@
#define HMZLIMIT_ADDR 156
#define BRINTERV_ADDR 158
#define OTFKEY_ADDR 160
#define PORTLIMIT_ADDR 162
#define LEVER_THR_ADDR 164
#define LEVER_MAX_ADDR 166
#define EEPROM_SIZE 162 //Last address +2
#define EEPROM_SIZE 168 //Last address +2
//DAC output modes
@ -99,7 +102,7 @@
//"factory" values for settings
#define EEPROM_VERSION 39
#define EEPROM_VERSION 40
#define BREATH_THR_FACTORY 1400
#define BREATH_MAX_FACTORY 4000
@ -111,6 +114,8 @@
#define PITCHB_MAX_FACTORY 3000
#define EXTRAC_THR_FACTORY 2800
#define EXTRAC_MAX_FACTORY 3500
#define LEVER_THR_FACTORY 1700
#define LEVER_MAX_FACTORY 1800
#define TRANSP_FACTORY 12 // 12 is 0 transpose
#define MIDI_FACTORY 1 // 1-16
#define BREATH_CC_FACTORY 2 //thats CC#2, see ccList
@ -172,6 +177,7 @@
#define HMZLIMIT_FACTORY 5
#define BRINTERV_FACTORY 6
#define OTFKEY_FACTORY 0
#define PORTLIMIT_FACTORY 127
#define NO_CHECKSUM 0x7F007F00

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff