Added breath curve settings. Made hi-res versions of breath cc settings. Made foot pedal default value for extra controller. Removed CV out option.

This commit is contained in:
Johan Berglund 2017-10-02 17:32:36 +02:00
parent f6d4b2ce08
commit 058a930bee

250
NuEVI.ino
View file

@ -21,8 +21,6 @@ PROGRAMME FUNCTION: EVI Wind Controller using the Freescale MP3V5004GP breath
// Compile options, comment/uncomment to change // Compile options, comment/uncomment to change
//#define BREATHCVOUTA14 // enables breath CV out on pin A14/DAC for Teensy 3.2
//#define BREATHCVOUTA12 // enables breath CV out on pin A12/DAC for Teensy LC
//#define REVB //#define REVB
@ -175,9 +173,10 @@ PROGRAMME FUNCTION: EVI Wind Controller using the Freescale MP3V5004GP breath
#define PATCH_ADDR 38 #define PATCH_ADDR 38
#define OCTAVE_ADDR 40 #define OCTAVE_ADDR 40
#define CTOUCH_THR_ADDR 42 #define CTOUCH_THR_ADDR 42
#define BREATHCURVE_ADDR 44
//"factory" values for settings //"factory" values for settings
#define VERSION 19 #define VERSION 22
#define BREATH_THR_FACTORY 1400 #define BREATH_THR_FACTORY 1400
#define BREATH_MAX_FACTORY 4000 #define BREATH_MAX_FACTORY 4000
#define PORTAM_THR_FACTORY 1730 #define PORTAM_THR_FACTORY 1730
@ -193,12 +192,13 @@ PROGRAMME FUNCTION: EVI Wind Controller using the Freescale MP3V5004GP breath
#define VELOCITY_FACTORY 0 // 0 is dynamic/breath controlled velocity #define VELOCITY_FACTORY 0 // 0 is dynamic/breath controlled velocity
#define PORTAM_FACTORY 2 // 0 - OFF, 1 - ON, 2 - SW #define PORTAM_FACTORY 2 // 0 - OFF, 1 - ON, 2 - SW
#define PB_FACTORY 1 // 0 - OFF, 1 - 12 #define PB_FACTORY 1 // 0 - OFF, 1 - 12
#define EXTRA_FACTORY 1 // 0 - OFF, 1 - Modulation wheel, 2 - Foot pedal, 3 - Sustain pedal #define EXTRA_FACTORY 2 // 0 - OFF, 1 - Modulation wheel, 2 - Foot pedal, 3 - Sustain pedal
#define VIBRATO_FACTORY 3 // 0 - OFF, 1 - 6 depth #define VIBRATO_FACTORY 3 // 0 - OFF, 1 - 6 depth
#define DEGLITCH_FACTORY 20 // 0 - OFF, 5 to 70 ms in steps of 5 #define DEGLITCH_FACTORY 20 // 0 - OFF, 5 to 70 ms in steps of 5
#define PATCH_FACTORY 1 // MIDI program change 1-128 #define PATCH_FACTORY 1 // MIDI program change 1-128
#define OCTAVE_FACTORY 3 // 3 is 0 octave change #define OCTAVE_FACTORY 3 // 3 is 0 octave change
#define CTOUCH_THR_FACTORY 130 // MPR121 touch threshold #define CTOUCH_THR_FACTORY 125 // MPR121 touch threshold
#define BREATHCURVE_FACTORY 2 // 0 to 4 (-2 to +2)
#define OLED_RESET 4 #define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET); Adafruit_SSD1306 display(OLED_RESET);
@ -301,7 +301,8 @@ unsigned short extraCT; // OFF:MW:FP:SP
unsigned short vibrato; // OFF:1-6 unsigned short vibrato; // OFF:1-6
unsigned short deglitch; // 0-70 ms in steps of 5 unsigned short deglitch; // 0-70 ms in steps of 5
unsigned short patch; // 1-128 unsigned short patch; // 1-128
unsigned short octave; // unsigned short octave;
unsigned short curve;
int breathLoLimit = 0; int breathLoLimit = 0;
@ -341,13 +342,14 @@ byte subMIDI = 0;
byte subBreathCC = 0; byte subBreathCC = 0;
byte subBreathAT = 0; byte subBreathAT = 0;
byte subVelocity = 0; byte subVelocity = 0;
byte subCurve = 0;
byte subPort = 0; byte subPort = 0;
byte subPB = 0; byte subPB = 0;
byte subExtra = 0; byte subExtra = 0;
byte subVibrato = 0; byte subVibrato = 0;
byte subDeglitch = 0; byte subDeglitch = 0;
byte ccList[5] = {0,1,2,7,11}; // OFF, Modulation (Hi-res), Breath, Volume, Expression byte ccList[9] = {0,1,2,7,11,1,2,7,11}; // OFF, Modulation (Hi-res), Breath, Volume, Expression (then same sent in hires)
int pbDepthList[13] = {0,8192,4096,2731,2048,1638,1365,1170,1024,910,819,744,683}; int pbDepthList[13] = {0,8192,4096,2731,2048,1638,1365,1170,1024,910,819,744,683};
@ -413,6 +415,12 @@ int lastPbDn=0;
int vibDepth[7] = {0,254,511,767,1023,1279,1535}; // max pitch bend values (+/-) for the vibrato settings int vibDepth[7] = {0,254,511,767,1023,1279,1535}; // max pitch bend values (+/-) for the vibrato settings
unsigned int curveIn[] = {0,1023,2047,3071,4095,5119,6143,7167,8191,9215,10239,11263,12287,13311,14335,15359,16383};
unsigned int curveM2[] = {0,4300,7000,8700,9800,10800,11900,12500,13300,13900,14500,15000,15500,15700,16000,16250,16383};
unsigned int curveM1[] = {0,2000,3600,5000,6450,7850,9000,10100,11100,12100,12900,13700,14400,14950,15500,16000,16383};
unsigned int curveP1[] = {0,400,800,1300,2050,2650,3500,4300,5300,6250,7400,8500,9600,11050,12400,14100,16383};
unsigned int curveP2[] = {0,100,200,400,700,1050,1500,1950,2550,3200,4000,4900,6050,7500,9300,12100,16282};
int vibThr=1900; // this gets auto calibrated in setup int vibThr=1900; // this gets auto calibrated in setup
int oldvibRead=0; int oldvibRead=0;
byte dirUp=0; // direction of first vibrato wave byte dirUp=0; // direction of first vibrato wave
@ -477,6 +485,7 @@ void setup() {
writeSetting(PATCH_ADDR,PATCH_FACTORY); writeSetting(PATCH_ADDR,PATCH_FACTORY);
writeSetting(OCTAVE_ADDR,OCTAVE_FACTORY); writeSetting(OCTAVE_ADDR,OCTAVE_FACTORY);
writeSetting(CTOUCH_THR_ADDR,CTOUCH_THR_FACTORY); writeSetting(CTOUCH_THR_ADDR,CTOUCH_THR_FACTORY);
writeSetting(BREATHCURVE_ADDR,BREATHCURVE_FACTORY);
} }
// read settings from EEPROM // read settings from EEPROM
breathThrVal = readSetting(BREATH_THR_ADDR); breathThrVal = readSetting(BREATH_THR_ADDR);
@ -500,6 +509,7 @@ void setup() {
patch = readSetting(PATCH_ADDR); patch = readSetting(PATCH_ADDR);
octave = readSetting(OCTAVE_ADDR); octave = readSetting(OCTAVE_ADDR);
ctouchThrVal = readSetting(CTOUCH_THR_ADDR); ctouchThrVal = readSetting(CTOUCH_THR_ADDR);
curve = readSetting(BREATHCURVE_ADDR);
breathStep = (breathHiLimit - breathLoLimit)/92; // 92 is the number of pixels in the settings bar breathStep = (breathHiLimit - breathLoLimit)/92; // 92 is the number of pixels in the settings bar
portamStep = (portamHiLimit - portamLoLimit)/92; portamStep = (portamHiLimit - portamLoLimit)/92;
@ -607,9 +617,11 @@ void loop() {
// Yes, so calculate MIDI note and velocity, then send a note on event // Yes, so calculate MIDI note and velocity, then send a note on event
readSwitches(); readSwitches();
// We should be at tonguing peak, so set velocity based on current pressureSensor value unless fixed velocity is set // We should be at tonguing peak, so set velocity based on current pressureSensor value unless fixed velocity is set
// If initial value is greater than value after delay, go with initial value, constrain input to keep mapped output within 1 to 127
if (!velocity) { if (!velocity) {
velocitySend = map(constrain(max(pressureSensor,initial_breath_value),breathThrVal,breathMaxVal),breathThrVal,breathMaxVal,1,127); unsigned int breathValHires = breathCurve(map(constrain(breathLevel,breathThrVal,breathMaxVal),breathThrVal,breathMaxVal,0,16383));
velocitySend = (breathValHires >>7) & 0x007F;
velocitySend = constrain(velocitySend,1,127);
//velocitySend = map(constrain(max(pressureSensor,initial_breath_value),breathThrVal,breathMaxVal),breathThrVal,breathMaxVal,1,127);
} else velocitySend = velocity; } else velocitySend = velocity;
breathLevel=constrain(max(pressureSensor,initial_breath_value),breathThrVal,breathMaxVal); breathLevel=constrain(max(pressureSensor,initial_breath_value),breathThrVal,breathMaxVal);
breath(); // send breath data breath(); // send breath data
@ -689,7 +701,10 @@ void loop() {
// Send a note off for the current note and a note on for // Send a note off for the current note and a note on for
// the new note. // the new note.
if (!velocity){ if (!velocity){
velocitySend = map(constrain(pressureSensor,breathThrVal,breathMaxVal),breathThrVal,breathMaxVal,7,127); // set new velocity value based on current pressure sensor level unsigned int breathValHires = breathCurve(map(constrain(breathLevel,breathThrVal,breathMaxVal),breathThrVal,breathMaxVal,0,16383));
velocitySend = (breathValHires >>7) & 0x007F;
velocitySend = constrain(velocitySend,1,127);
//velocitySend = map(constrain(pressureSensor,breathThrVal,breathMaxVal),breathThrVal,breathMaxVal,7,127); // set new velocity value based on current pressure sensor level
} }
activeNote=noteValueCheck(activeNote); activeNote=noteValueCheck(activeNote);
if (parallelChord || subOctaveDouble){ // poly playing, send old note off before new note on if (parallelChord || subOctaveDouble){ // poly playing, send old note off before new note on
@ -771,6 +786,57 @@ void loop() {
//_______________________________________________________________________________________________ FUNCTIONS //_______________________________________________________________________________________________ FUNCTIONS
// non linear mapping function (http://playground.arduino.cc/Main/MultiMap)
// note: the _in array should have increasing values
unsigned int multiMap(unsigned int val, unsigned int* _in, unsigned int* _out, uint8_t size)
{
// take care the value is within range
// val = constrain(val, _in[0], _in[size-1]);
if (val <= _in[0]) return _out[0];
if (val >= _in[size-1]) return _out[size-1];
// search right interval
uint8_t pos = 1; // _in[0] allready tested
while(val > _in[pos]) pos++;
// this will handle all exact "points" in the _in array
if (val == _in[pos]) return _out[pos];
// interpolate in the right segment for the rest
return (val - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1];
}
//**************************************************************
// map breath values to selected curve
unsigned int breathCurve(unsigned int inputVal){
// 0 to 16383, moving mid value up or down
switch (curve){
case 0:
// -2
return multiMap(inputVal,curveIn,curveM2,17);
break;
case 1:
// -1
return multiMap(inputVal,curveIn,curveM1,17);
break;
case 2:
// 0, linear
return inputVal;
break;
case 3:
// +1
return multiMap(inputVal,curveIn,curveP1,17);
break;
case 4:
// +2
return multiMap(inputVal,curveIn,curveP2,17);
break;
}
}
// MIDI note value check with out of range octave repeat // MIDI note value check with out of range octave repeat
int noteValueCheck(int note){ int noteValueCheck(int note){
if (note > 127){ if (note > 127){
@ -869,13 +935,16 @@ void statusLEDs() {
//************************************************************** //**************************************************************
void breath(){ void breath(){
int breathCCval; int breathCCval,breathCCvalFine;
unsigned int breathCCvalHires; unsigned int breathCCvalHires;
breathLevel = breathLevel*0.8+pressureSensor*0.2; // smoothing of breathLevel value breathLevel = breathLevel*0.8+pressureSensor*0.2; // smoothing of breathLevel value
breathCCval = map(constrain(breathLevel,breathThrVal,breathMaxVal),breathThrVal,breathMaxVal,0,127); //breathCCval = map(constrain(breathLevel,breathThrVal,breathMaxVal),breathThrVal,breathMaxVal,0,127);
breathCCvalHires = map(constrain(breathLevel,breathThrVal,breathMaxVal),breathThrVal,breathMaxVal,0,16383); breathCCvalHires = breathCurve(map(constrain(breathLevel,breathThrVal,breathMaxVal),breathThrVal,breathMaxVal,0,16383));
breathCCval = (breathCCvalHires >>7) & 0x007F;
breathCCvalFine = breathCCvalHires & 0x007F;
if (breathCCval != oldbreath){ // only send midi data if breath has changed from previous value if (breathCCval != oldbreath){ // only send midi data if breath has changed from previous value
if (ccList[breathCC] > 1){ if (breathCC){
// send midi cc // send midi cc
usbMIDI.sendControlChange(ccList[breathCC], breathCCval, activeMIDIchannel); usbMIDI.sendControlChange(ccList[breathCC], breathCCval, activeMIDIchannel);
dinMIDIsendControlChange(ccList[breathCC], breathCCval, activeMIDIchannel - 1); dinMIDIsendControlChange(ccList[breathCC], breathCCval, activeMIDIchannel - 1);
@ -887,20 +956,11 @@ void breath(){
} }
oldbreath = breathCCval; oldbreath = breathCCval;
} }
if (breathCCvalHires != oldbreathhires){ if (breathCCvalHires != oldbreathhires){
#if defined(BREATHCVOUTA14) if (breathCC > 4){ // send high resolution midi
analogWrite(A14,breathCCvalHires); // Breath CV out at A14 on Teensy 3.2 usbMIDI.sendControlChange(ccList[breathCC]+32, breathCCvalFine, activeMIDIchannel);
#endif dinMIDIsendControlChange(ccList[breathCC]+32, breathCCvalFine, activeMIDIchannel - 1);
#if defined(BREATHCVOUTA12)
analogWrite(A12,breathCCvalHires); // Breath CV out at A12 on Teensy LC
#endif
if (ccList[breathCC] == 1){ // if modulation cc is used, send high resolution midi
int fine = breathCCvalHires & 0x007F;
int coarse = (breathCCvalHires >>7) & 0x007F;
usbMIDI.sendControlChange(ccList[breathCC], coarse, activeMIDIchannel);
dinMIDIsendControlChange(ccList[breathCC], coarse, activeMIDIchannel - 1);
usbMIDI.sendControlChange(ccList[breathCC]+32, fine, activeMIDIchannel);
dinMIDIsendControlChange(ccList[breathCC]+32, fine, activeMIDIchannel - 1);
} }
oldbreathhires = breathCCvalHires; oldbreathhires = breathCCvalHires;
} }
@ -2114,7 +2174,7 @@ void menu() {
cursorBlinkTime = millis(); cursorBlinkTime = millis();
} else { } else {
plotBreathCC(BLACK); plotBreathCC(BLACK);
breathCC = 3; breathCC = 8;
plotBreathCC(WHITE); plotBreathCC(WHITE);
cursorNow = BLACK; cursorNow = BLACK;
display.display(); display.display();
@ -2131,7 +2191,7 @@ void menu() {
break; break;
case 4: case 4:
// up // up
if (breathCC < 4){ if (breathCC < 8){
plotBreathCC(BLACK); plotBreathCC(BLACK);
breathCC++; breathCC++;
plotBreathCC(WHITE); plotBreathCC(WHITE);
@ -2253,6 +2313,60 @@ void menu() {
break; break;
} }
} }
} else if (subCurve) {
if ((millis() - cursorBlinkTime) > cursorBlinkInterval) {
if (cursorNow == WHITE) cursorNow = BLACK; else cursorNow = WHITE;
plotCurve(cursorNow);
display.display();
cursorBlinkTime = millis();
}
if (buttonPressedAndNotUsed){
buttonPressedAndNotUsed = 0;
switch (deumButtonState){
case 1:
// down
plotCurve(BLACK);
if (curve > 0){
curve--;
} else curve = 4;
plotCurve(WHITE);
cursorNow = BLACK;
display.display();
cursorBlinkTime = millis();
break;
case 2:
// enter
plotCurve(WHITE);
cursorNow = BLACK;
display.display();
subCurve = 0;
if (readSetting(BREATHCURVE_ADDR) != curve) writeSetting(BREATHCURVE_ADDR,curve);
break;
case 4:
// up
plotCurve(BLACK);
if (curve < 4){
curve++;
} else curve = 0;
plotCurve(WHITE);
cursorNow = BLACK;
display.display();
cursorBlinkTime = millis();
break;
case 8:
// menu
plotCurve(WHITE);
cursorNow = BLACK;
display.display();
subCurve = 0;
if (readSetting(BREATHCURVE_ADDR) != curve) writeSetting(BREATHCURVE_ADDR,curve);
break;
}
}
} else { } else {
if ((millis() - cursorBlinkTime) > cursorBlinkInterval) { if ((millis() - cursorBlinkTime) > cursorBlinkInterval) {
if (cursorNow == WHITE) cursorNow = BLACK; else cursorNow = WHITE; if (cursorNow == WHITE) cursorNow = BLACK; else cursorNow = WHITE;
@ -2265,7 +2379,7 @@ void menu() {
switch (deumButtonState){ switch (deumButtonState){
case 1: case 1:
// down // down
if (setupBrMenuCursor < 3){ if (setupBrMenuCursor < 4){
drawMenuCursor(setupBrMenuCursor, BLACK); drawMenuCursor(setupBrMenuCursor, BLACK);
setupBrMenuCursor++; setupBrMenuCursor++;
drawMenuCursor(setupBrMenuCursor, WHITE); drawMenuCursor(setupBrMenuCursor, WHITE);
@ -2662,6 +2776,14 @@ void selectSetupBrMenu(){
display.display(); display.display();
cursorBlinkTime = millis(); cursorBlinkTime = millis();
drawSubVelocity(); drawSubVelocity();
break;
case 4:
subCurve = 1;
drawMenuCursor(setupBrMenuCursor, WHITE);
display.display();
cursorBlinkTime = millis();
drawSubCurve();
break;
} }
} }
@ -3053,20 +3175,36 @@ void plotBreathCC(int color){
if (breathCC){ if (breathCC){
switch (breathCC){ switch (breathCC){
case 1: case 1:
display.setCursor(79,33); display.setCursor(83,33);
display.println("MW+"); display.println("MW");
break; break;
case 2: case 2:
display.setCursor(83,33); display.setCursor(83,33);
display.println("BR"); display.println("BR");
break; break;
case 3: case 3:
display.setCursor(79,33); display.setCursor(83,33);
display.println("VOL"); display.println("VL");
break; break;
case 4: case 4:
display.setCursor(83,33);
display.println("EX");
break;
case 5:
display.setCursor(79,33); display.setCursor(79,33);
display.println("EXP"); display.println("MW+");
break;
case 6:
display.setCursor(79,33);
display.println("BR+");
break;
case 7:
display.setCursor(79,33);
display.println("VL+");
break;
case 8:
display.setCursor(79,33);
display.println("EX+");
break; break;
} }
} else { } else {
@ -3119,6 +3257,46 @@ void plotVelocity(int color){
} }
} }
void drawSubCurve(){
display.fillRect(63,11,64,52,BLACK);
display.drawRect(63,11,64,52,WHITE);
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(68,15);
display.println("CURVE");
plotCurve(WHITE);
display.display();
}
void plotCurve(int color){
display.setTextColor(color);
display.setTextSize(2);
switch (curve){
case 0:
display.setCursor(83,33);
display.println("-2");
break;
case 1:
display.setCursor(83,33);
display.println("-1");
break;
case 2:
display.setCursor(79,33);
display.println("LIN");
break;
case 3:
display.setCursor(83,33);
display.println("+1");
break;
case 4:
display.setCursor(83,33);
display.println("+2");
break;
}
}
void drawSubPort(){ void drawSubPort(){
display.fillRect(63,11,64,52,BLACK); display.fillRect(63,11,64,52,BLACK);
display.drawRect(63,11,64,52,WHITE); display.drawRect(63,11,64,52,WHITE);
@ -3266,7 +3444,7 @@ void drawSetupBrMenuScreen(){
display.setCursor(0,30); display.setCursor(0,30);
display.println("VELOCITY"); display.println("VELOCITY");
display.setCursor(0,39); display.setCursor(0,39);
display.println(""); display.println("CURVE");
display.setCursor(0,48); display.setCursor(0,48);
display.println(""); display.println("");
display.setCursor(0,57); display.setCursor(0,57);