NuEVI and NuRAD: Timing and speed issue solved - SSD1306 display library needed editing to prevent it from lowering I2C bus speed. Added setting to enable/disable the on the fly key switching. NuRAD: Changed touch sensor reading equalisation from offset to multiplier to improve coherence of readings.

This commit is contained in:
Johan Berglund 2020-07-22 13:24:56 +02:00
parent cc188f2196
commit b9a8742fc1
11 changed files with 10772 additions and 25 deletions

View file

@ -98,7 +98,9 @@ unsigned short fwcType; // 6, m6, 7, m7
unsigned short fwcLockH; // OFF:ON
unsigned short fwcDrop2; // OFF:ON
unsigned short hmzKey; // 0-11 (0 is C)
unsigned short hmzLimit; // 2-5:
unsigned short hmzLimit; // 2-5
unsigned short otfKey; //OFF:ON
unsigned short breathInterval = 6; // 3-15
unsigned short vibSens = 2; // vibrato sensitivity
unsigned short vibRetn = 2; // vibrato return speed
@ -169,6 +171,8 @@ byte activeMIDIchannel; // MIDI channel
byte activePatch=0;
byte doPatchUpdate=0;
byte cvPortaTuneCount = 0;
uint16_t legacy = 0;
uint16_t legacyBrAct = 0;
byte halfTime = 0;
@ -190,7 +194,7 @@ int breathCalZero;
int leverPortZero;
#if defined(NURAD)
int leverPortThr = 40;
int leverPortThr = 50;
#else
int leverPortThr = 50;
#endif
@ -550,7 +554,7 @@ void setup() {
analogReadResolution(12); // set resolution of ADCs to 12 bit
analogWriteResolution(12);
analogWriteFrequency(pwmDacPin,11718.75);
Wire.setClock(400000);
Wire.setClock(1000000);
pinMode(dPin, INPUT_PULLUP);
pinMode(ePin, INPUT_PULLUP);
@ -1293,7 +1297,8 @@ void loop() {
}
// Is it time to send more CC data?
currentTime = millis();
if (currentTime - ccBreathSendTime > (CC_BREATH_INTERVAL+slowMidi*SLOW_MIDI_ADD)){
//if (currentTime - ccBreathSendTime > (CC_BREATH_INTERVAL+slowMidi*SLOW_MIDI_ADD)){
if (currentTime - ccBreathSendTime > (breathInterval-1)){
breath();
ccBreathSendTime = currentTime;
}
@ -1331,10 +1336,22 @@ void loop() {
targetPitch = (fingeredNote-24)*42;
if (portIsOn){
if (targetPitch > cvPitch){
cvPitch += 1+(127-oldport)/4;
if (!cvPortaTuneCount) {
cvPitch += 1+(127-oldport)/4;
}
else {
cvPortaTuneCount++;
if (cvPortaTuneCount > CVPORTATUNE) cvPortaTuneCount=0;
}
if (cvPitch > targetPitch) cvPitch = targetPitch;
} else if (targetPitch < cvPitch){
cvPitch -= 1+(127-oldport)/4;
if (!cvPortaTuneCount) {
cvPitch -= 1+(127-oldport)/4;
}
else {
cvPortaTuneCount++;
if (cvPortaTuneCount > CVPORTATUNE) cvPortaTuneCount=0;
}
if (cvPitch < targetPitch) cvPitch = targetPitch;
} else {
cvPitch = targetPitch;
@ -1842,7 +1859,8 @@ void readSwitches() {
// Octave rollers
int touchValueRollers[12];
for (byte i=0; i<6; i++){
touchValueRollers[i]=touchSensorRollers.filteredData(i) - calOffsetRollers[i];
//touchValueRollers[i]=touchSensorRollers.filteredData(i) - calOffsetRollers[i];
touchValueRollers[i]=touchSensorRollers.filteredData(i) * (300-calOffsetRollers[i])/300;
}
// 6-pin version
octaveR = 0;
@ -1852,6 +1870,13 @@ void readSwitches() {
else if (R3=(touchValueRollers[rPin3] < ctouchThrVal)) octaveR = 3; //R3 (store for combo check)
else if (R2=(touchValueRollers[rPin2] < ctouchThrVal)) octaveR = 2; //R2 (store for combo check)
else if (touchValueRollers[rPin1] < ctouchThrVal) octaveR = 1; //R1
else if (lastOctaveR > 1) {
octaveR = lastOctaveR;
if (otfKey && polySelect && (polySelect<RT1) && rotatorOn && (mainState == NOTE_OFF)) hmzKey = fingeredNote%12;
}
//if rollers are released and we are not coming down from roller 1, stay at the higher octave
lastOctaveR = octaveR;
/*
//5-pin version
octaveR = 0;
@ -1867,7 +1892,8 @@ void readSwitches() {
// RH keys
int touchValueRH[12];
for (byte i=0; i<12; i++){
touchValueRH[i]=touchSensorRH.filteredData(i) - calOffsetRH[i];
//touchValueRH[i]=touchSensorRH.filteredData(i) - calOffsetRH[i];
touchValueRH[i]=touchSensorRH.filteredData(i) * (300-calOffsetRH[i])/300;
}
RHs=(touchValueRH[RHsPin] < ctouchThrVal);
RH1=(touchValueRH[RH1Pin] < ctouchThrVal);
@ -1882,7 +1908,8 @@ void readSwitches() {
// LH keys
int touchValueLH[12];
for (byte i=0; i<12; i++){
touchValueLH[i]=touchSensorLH.filteredData(i) - calOffsetLH[i];
//touchValueLH[i]=touchSensorLH.filteredData(i) - calOffsetLH[i];
touchValueLH[i]=touchSensorLH.filteredData(i) * (300-calOffsetLH[i])/300;
}
LHs=(touchValueLH[LHsPin] < ctouchThrVal);
LHb=(touchValueLH[LHbPin] < ctouchThrVal);
@ -1984,7 +2011,10 @@ void readSwitches() {
else if (R3 && lastOctaveR) octaveR = 3; //R3
else if (R2) octaveR = 2; //R2
else if (R1) octaveR = 1; //R1
else if (lastOctaveR > 1) octaveR = lastOctaveR;
else if (lastOctaveR > 1) {
octaveR = lastOctaveR;
if (otfKey && polySelect && (polySelect<RT1) && rotatorOn && (mainState == NOTE_OFF)) hmzKey = fingeredNote%12;
}
//if rollers are released and we are not coming down from roller 1, stay at the higher octave
//CV filter leak prevention when putting NuEVI aside

9
NuEVI/adjustmenu.cpp Executable file → Normal file
View file

@ -240,17 +240,20 @@ void plotSensorPixels(){
else if(adjustOption == 4) {
display.drawLine(28,37,118,37,BLACK);
for (byte i=0; i<12; i++){
int pos = map(constrain(touchSensorRH.filteredData(i) - calOffsetRH[i], ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
//int pos = map(constrain(touchSensorRH.filteredData(i) - calOffsetRH[i], ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
int pos = map(constrain(touchSensorRH.filteredData(i) * (300-calOffsetRH[i])/300, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
display.drawPixel(pos, 37, WHITE);
}
display.drawLine(28,38,118,38,BLACK);
for (byte i=0; i<12; i++){
int pos = map(constrain(touchSensorLH.filteredData(i) - calOffsetLH[i], ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
//int pos = map(constrain(touchSensorLH.filteredData(i) - calOffsetLH[i], ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
int pos = map(constrain(touchSensorLH.filteredData(i) * (300-calOffsetLH[i])/300, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
display.drawPixel(pos, 38, WHITE);
}
display.drawLine(28,39,118,39,BLACK);
for (byte i=0; i<6; i++){
int pos = map(constrain(touchSensorRollers.filteredData(i) - calOffsetRollers[i], ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
//int pos = map(constrain(touchSensorRollers.filteredData(i) - calOffsetRollers[i], ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
int pos = map(constrain(touchSensorRollers.filteredData(i) * (300-calOffsetRollers[i])/300, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
display.drawPixel(pos, 39, WHITE);
}
redraw = 1;

View file

@ -5,7 +5,7 @@
// Compile options, comment/uncomment to change
#define FIRMWARE_VERSION "1.4.7" // FIRMWARE VERSION NUMBER HERE <<<<<<<<<<<<<<<<<<<<<<<
#define FIRMWARE_VERSION "1.4.8" // 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
@ -13,12 +13,13 @@
#define CCN_PortSE02 9 // Controller number for portamento type on Roland SE-02
// Send breath CC data no more than every CC_BREATH_INTERVAL
// milliseconds (due to timing errors, the value should be about half the actual wanted value)
#define CC_BREATH_INTERVAL 1
// milliseconds
#define CC_BREATH_INTERVAL 5
#define SLOW_MIDI_ADD 7
#define CC_INTERVAL 13
#define CC_INTERVAL2 19
#define CC_INTERVAL3 37
#define CVPORTATUNE 2
#define breathLoLimit 0

View file

@ -107,6 +107,8 @@ extern unsigned short fwcLockH; // OFF:ON
extern unsigned short fwcDrop2; // OFF:ON
extern unsigned short hmzKey; // 0-11 (0 is C)
extern unsigned short hmzLimit; // 2-5
extern unsigned short otfKey; //OFF:ON
extern unsigned short breathInterval; // 3-15
extern uint16_t gateOpenEnable;
extern uint16_t specialKeyEnable;
extern byte rotatorOn;

View file

@ -2,7 +2,7 @@
#define __HARDWARE_H
#define REVB
//#define NURAD
#define NURAD
#if defined(NURAD) //NuRAD <<<<<<<<<<<<<<<<<<<<<<<

View file

@ -822,9 +822,26 @@ const MenuEntrySub hmzLimitMenu = {
hmzLimitOptionGet, hmzLimitSave, nullptr,
};
static void otfKeyOptionGet(SubMenuRef __unused, char* out, const char** __unused) {
if (otfKey) strncpy(out, "ON", 4);
else strncpy(out, "OFF", 4);
}
static void otfKeySave(SubMenuRef __unused) {
writeSetting(OTFKEY_ADDR,otfKey);
}
const MenuEntrySub otfKeyMenu = {
MenuType::ESub, "OTF KEY", "OTF KEYSW", &otfKey, 0,1, MenuEntryFlags::EMenuEntryWrap,
otfKeyOptionGet, otfKeySave, nullptr,
};
const MenuEntry* rotatorMenuEntries[] = {
(MenuEntry*)&polySelectMenu,
(MenuEntry*)&hmzKeyMenu,
(MenuEntry*)&otfKeyMenu,
(MenuEntry*)&hmzLimitMenu,
(MenuEntry*)&fwcTypeMenu,
(MenuEntry*)&fwcLockHMenu,
@ -885,14 +902,16 @@ const MenuEntrySub octaveMenu = {
};
static void midiSaveFunc(const MenuEntrySub & __unused sub) { writeSetting(MIDI_ADDR, MIDIchannel); }
static void midiCustomDrawFunc(SubMenuRef __unused, char* __unused, const char** __unused) {
char buff[7];
numToString(MIDIchannel, buff);
plotSubOption(buff);
if (slowMidi) {
display.setTextSize(1);
display.setCursor(116,51);
display.print("S");
//replaced with breathInterval setting and not used anymore.. do cleanup later removing all slowMidi related stuff
//display.setTextSize(1);
//display.setCursor(116,51);
//display.print("S");
}
}
@ -1057,6 +1076,8 @@ const MenuPage extrasMenuPage = {
};
static bool midiEnterHandlerFunc() {
/*
//this switching is removed due to new breathInterval setting
readSwitches();
if (pinkyKey){
slowMidi = !slowMidi;
@ -1067,6 +1088,9 @@ static bool midiEnterHandlerFunc() {
writeSetting(MIDI_ADDR, MIDIchannel);
return true;
}
*/
writeSetting(MIDI_ADDR, MIDIchannel);
return true;
}
const MenuEntrySub midiMenu = {
@ -1196,7 +1220,7 @@ const MenuEntrySub velSmpDlMenu = {
[](SubMenuRef __unused, char *out, const char** label) {
if (velSmpDl) {
numToString(velSmpDl, out);
*label = "";
*label = "ms";
} else strncpy(out, "OFF", 4);
},
[](const MenuEntrySub & __unused sub) { writeSetting(VEL_SMP_DL_ADDR,velSmpDl); }
@ -1213,6 +1237,15 @@ const MenuEntrySub velBiasMenu = {
, nullptr
};
const MenuEntrySub breathIntervalMenu = {
MenuType::ESub, "BR INTERV", "CC INTERV", &breathInterval, 3, 15, MenuEntryFlags::ENone,
[](SubMenuRef __unused, char* out, const char** __unused unit) {
numToString(breathInterval, out, false);
},
[](SubMenuRef __unused) { writeSetting(BRINTERV_ADDR, breathInterval); }
, nullptr
};
const MenuEntry* breathMenuEntries[] = {
(MenuEntry*)&breathCCMenu,
(MenuEntry*)&breathCC2Menu,
@ -1221,7 +1254,8 @@ const MenuEntry* breathMenuEntries[] = {
(MenuEntry*)&velocityMenu,
(MenuEntry*)&curveMenu,
(MenuEntry*)&velSmpDlMenu,
(MenuEntry*)&velBiasMenu
(MenuEntry*)&velBiasMenu,
(MenuEntry*)&breathIntervalMenu
};
const MenuPage breathMenuPage = {

View file

@ -146,6 +146,11 @@ void readEEPROM(const bool factoryReset) {
if(settingsVersion < 38) {
writeSetting(HMZLIMIT_ADDR, HMZLIMIT_FACTORY);
}
if(settingsVersion < 39) {
writeSetting(BRINTERV_ADDR, BRINTERV_FACTORY);
writeSetting(OTFKEY_ADDR, OTFKEY_FACTORY);
}
writeSetting(VERSION_ADDR, EEPROM_VERSION);
@ -230,6 +235,8 @@ void readEEPROM(const bool factoryReset) {
rotationsc[1] = readSettingBounded(ROTC2_ADDR, 0, 48, ROTC2_FACTORY);
rotationsc[2] = readSettingBounded(ROTC3_ADDR, 0, 48, ROTC3_FACTORY);
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);
//Flags stored in bit field
fastBoot = (dipSwBits & (1<<DIPSW_FASTBOOT))?1:0;

View file

@ -79,8 +79,10 @@
#define FWCLCH_ADDR 152
#define FWCDP2_ADDR 154
#define HMZLIMIT_ADDR 156
#define BRINTERV_ADDR 158
#define OTFKEY_ADDR 160
#define EEPROM_SIZE 158 //Last address +2
#define EEPROM_SIZE 162 //Last address +2
//DAC output modes
@ -97,7 +99,7 @@
//"factory" values for settings
#define EEPROM_VERSION 38
#define EEPROM_VERSION 39
#define BREATH_THR_FACTORY 1400
#define BREATH_MAX_FACTORY 4000
#define PORTAM_THR_FACTORY 2600
@ -122,7 +124,7 @@
#define OCTAVE_FACTORY 3 // 3 is 0 octave change
#define CTOUCH_THR_FACTORY 125 // MPR121 touch threshold
#define BREATHCURVE_FACTORY 4 // 0 to 12 (-4 to +4, S1 to S4)
#define VEL_SMP_DL_FACTORY 15 // 0 to 30
#define VEL_SMP_DL_FACTORY 20 // 0 to 30
#define VEL_BIAS_FACTORY 0 // 0 to 9
#define PINKY_KEY_FACTORY 12 // 0 - 11 (QuickTranspose -12 to -1), 12 (pb/2), 13 - 22 (QuickTranspose +1 to +12)
#define DIPSW_BITS_FACTORY 0 // virtual dip switch settings for special modes (work in progress)
@ -167,6 +169,8 @@
#define FWCLCH_FACTORY 0
#define FWCDP2_FACTORY 0
#define HMZLIMIT_FACTORY 5
#define BRINTERV_FACTORY 6
#define OTFKEY_FACTORY 0
#define NO_CHECKSUM 0x7F007F00

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,68 @@
POLY PLAY
In the Poly Play menu you configure everything having to do with polyphonic playing functions.
POLY PLAY POLY MODE
Here you select which type of harmonization or which rotator setup will be activated by touching/holding MOD key (NuRAD) or Pinky Key (NuEVI) and then touching Special Key(s). Deactivate by just touching Special Key(s).
OFF disables all Special Key functionality, including the Parallel Chord, Slur Sustain and Sub Octave functions
MGR Major Gospel Root a gospel type triad voicing
MGD Major Gospel Dominant same as MGR, but with a dominant on V instead of an inversion of the root
MA9 Major add9 pop style add9 harmonization
MND minor Dorian jazz type minor
MNA minor Aeolian classical minor
MNH minor 4-voice Hip a more hip dorian minor
FWC Four Way Close old school block chord harmony (with additional options further down in the Poly Play menu)
RTA Rotator A
RTB Rotator B
RTC - Rotator C
POLY PLAY HMZ KEY
Selects the key you are playing in for the key based harmonizations.
POLY PLAY OTF KEY
Enables on the fly key change for the key based harmonizers. To change key on the fly while playing, finger the key (not blowing) and briefly lift your thumb off the rollers (when in octave two or higher). Key change on the fly will not be stored when powered off.
POLY PLAY HMZ LIMIT
Limits the number of voices to be played, starting elimination from lowest note and up. Applies to the key based harmonizations only, not Rotator, Parallel Chord or Slur Sustain.
POLY PLAY FWC TYPE
Type of block chord for the Four Way Close harmonization. (6, m6, 7 or m7)
POLY PLAY FWC LOCKH
"Lock Hands" (double melody) adds another melody note one octave down for the Four Way Close harmonizations. (OFF/ON)
POLY PLAY FWC DROP2
"Drop 2" moves the second note (the one below melody note) one octave down for the FWC. (OFF/ON)
POLY PLAY PRIORITY
Sets which note will get priority when playing mono patches (sounds really great to layer a mono patch with a poly patch for use with with the Poly Play functions). MEL will play the melody note as the mono lead and ROT will play the rotated note or last note of other poly modes.
POLY PLAY RTA PARAL
POLY PLAY RTA ROT 1
POLY PLAY RTA ROT 2
POLY PLAY RTA ROT 3
POLY PLAY RTA ROT 4
POLY PLAY RTB PARAL
POLY PLAY RTB ROT 1
POLY PLAY RTB ROT 2
POLY PLAY RTB ROT 3
POLY PLAY RTB ROT 4
POLY PLAY RTC PARAL
POLY PLAY RTC ROT 1
POLY PLAY RTC ROT 2
POLY PLAY RTC ROT 3
POLY PLAY RTC ROT 4
This last section of settings is for the three rotators. They create a three note chord using the melody note, a fixed interval parallel note and a third note taken from a rotating selection of four notes. For every new note triggered, the rotation is advanced one step, and a new combination of notes is played. For each uf the three selectable rotator setups you can configure the fixed interval with RTx PARAL and the four intervals to be rotated for the third note with RTx ROT 1 to RTx ROT4, where x represents rotators A through C.