From c3ec7b1bb0d5796422917530e997e7733b8ea7ce Mon Sep 17 00:00:00 2001 From: alemi Date: Mon, 4 Mar 2019 18:53:16 +0100 Subject: [PATCH 1/5] Commited previous testing branch Completely rewriting my code to make it more modular and debuggable. Pushing to master previous status because the code currently in master is just way too old --- cvkeyboard.ino | 140 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 112 insertions(+), 28 deletions(-) diff --git a/cvkeyboard.ino b/cvkeyboard.ino index ea04489..af1360b 100644 --- a/cvkeyboard.ino +++ b/cvkeyboard.ino @@ -18,24 +18,37 @@ #define Oct4 10 #define noteOffset 36 -#define offCounter 100 +#define offCounter 0 +#define MINUTE 60000 #include #include MIDI_CREATE_DEFAULT_INSTANCE(); int note[12] = { - C, Db, D, Eb, E, F, Gb, G, Ab, A, Bb, B }; // Pin delle note : 0 -> C , 11 -> B + C, Db, D, Eb, E, F, Gb, G, Ab, A, Bb, B }; // Note Pins above int octave[4] = { - Oct1, Oct2, Oct3, Oct4 }; // Pin delle ottave : 0 -> 2 , 3 -> 5 + Oct1, Oct2, Oct3, Oct4 }; // Octave Pins above + int noteCounter[49] = { 0 }; -boolean status[49] = { LOW }; // Array di stato, aggiornato durante ogni ciclo. 0 -> C2 , 11 -> C3 , 23 -> C4 -> , 35 -> C5 , 48 -> C6 +boolean status[49] = { LOW }; boolean flip[49] = { LOW }; -boolean buffer = LOW; // Usato come buffer per lo stato di ogni pin, per non chiamare una lettura ogni volta. -int octBuffer; // Usato per non ripetere l'aritmetica ad ogni accesso all'array di stato. +boolean buffer = LOW; + +int octBuffer; byte noteBuffer; -byte velocity = 100; // Placeholder. -int channel = 7; // Placeholder. + + +byte velocity = 100; // Placeholder. Will need something to change it +int channel = 7; // Placeholder. Will need something to change it +int bpm = 120; // Placeholder. Will need something to change it +int gate = 300; // Placeholder. Will need something to change it + +unsigned long nextBeat = 0; +int step = 0; +int lastStep = 0; +boolean notePlayed = LOW; + void setup() @@ -48,11 +61,86 @@ void setup() } MIDI.begin(MIDI_CHANNEL_OFF); Serial.begin(115200); + nextBeat = millis() + (MINUTE / bpm); } void loop() { + if (millis() < nextBeat) return; + notePlayed = LOW; + while (notePlayed == LOW) { + cleanScan(); + arp(); + } + nextBeat += (MINUTE / bpm); +} + +void cleanScan() { + int c; + for (c = 0; c < 49; c++) noteCounter[c] = 0; scan(); + for (c = 0; c < 49; c++) { + if (status[c] == HIGH) noteCounter[c]++; + } + scan(); + for (c = 0; c < 49; c++) { + if (status[c] == HIGH) noteCounter[c]++; + } + scan(); + for (c = 0; c < 49; c++) { + if (status[c] == HIGH) noteCounter[c]++; + } + for (c = 0; c < 49; c++) { + if (noteCounter[c] == 3) status[c] = HIGH; + else status[c] = LOW; + } +} + +void send() { + for (int c = 48; c >= 0; c--) { + if (flip[c] == HIGH) { + flip[c] = LOW; + if (noteCounter[c] > 0) { + noteCounter[c]--; + } + else { + noteCounter[c] = offCounter; + noteBuffer = c + noteOffset; + if (status[c] == HIGH) { + MIDI.sendNoteOn(noteBuffer, velocity, channel); + } + else if (status[c] == LOW) { + MIDI.sendNoteOff(noteBuffer, velocity, channel); + } + } + } + } +} + +void playNote(int c, boolean status) { + if (status == HIGH) { + MIDI.sendNoteOn(c + noteOffset, velocity, channel); + } + else if (status == LOW) { + MIDI.sendNoteOff(c + noteOffset, velocity, channel); + } +} + +void arp() { + step++; + while (step < 49 && status[step] == LOW) { + step++; + } + if (step == 49) { + step = 0; + } + else { + playNote(lastStep, LOW); + playNote(step, HIGH); + lastStep = step; + notePlayed = HIGH; + } + return; } void scan() { @@ -62,31 +150,27 @@ void scan() { for (int cNote = 0; cNote < 12; cNote++) { - if (noteCounter[cNote + octBuffer] > 0) { - noteCounter[cNote + octBuffer]--; + buffer = digitalRead(note[cNote]); + + if (buffer ^ status[cNote + octBuffer]) { + status[cNote + octBuffer] = buffer; + flip[cNote + octBuffer] = HIGH; } else { - noteCounter[cNote + octBuffer] = offCounter; - - buffer = digitalRead(note[cNote]); - - if (buffer ^ status[cNote + octBuffer]) { - status[cNote + octBuffer] = buffer; - flip[cNote + octBuffer] = HIGH; - noteBuffer = cNote + octBuffer + noteOffset; - if (buffer == HIGH) { - MIDI.sendNoteOn(noteBuffer, velocity, 1); - } - if (buffer == LOW) { - MIDI.sendNoteOff(noteBuffer, velocity, 1); - } - } - else { - flip[cNote + octBuffer] = LOW; - } + flip[cNote + octBuffer] = LOW; } } digitalWrite(octave[cOctave], LOW); } + +} + +int nPressed() { + int c, n = 0; + for (c = 0; c < 49; c++) { + if (status[c] == HIGH) { + n++; + } + } } From 731a05bc57850c856f2dbb78ba286e7a50bb0fa5 Mon Sep 17 00:00:00 2001 From: alemi Date: Fri, 8 Mar 2019 21:18:30 +0100 Subject: [PATCH 2/5] Forgot to update before adding new stuff. This is the testing build without the new stuff. Arpeggiator is buggy but sorta working (with fixed bpm). Raw mode is working ok. --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e915029 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ + +/.vs From 4f6486bc75de85b5d0d09aeb9f6d4578089a3441 Mon Sep 17 00:00:00 2001 From: alemi Date: Fri, 8 Mar 2019 21:19:06 +0100 Subject: [PATCH 3/5] Actual commit (previous one was staged?) --- .gitignore | 1 + cvkeyboard.ino | 203 +++++++++++++++++++------------------------------ 2 files changed, 78 insertions(+), 126 deletions(-) diff --git a/.gitignore b/.gitignore index e915029..01d8aed 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ ################################################################################ /.vs +/CppProperties.json diff --git a/cvkeyboard.ino b/cvkeyboard.ino index af1360b..1acff96 100644 --- a/cvkeyboard.ino +++ b/cvkeyboard.ino @@ -18,159 +18,110 @@ #define Oct4 10 #define noteOffset 36 -#define offCounter 0 #define MINUTE 60000 #include #include + MIDI_CREATE_DEFAULT_INSTANCE(); +typedef struct OctaveStatus { + bool stat[12]; + int nOct; +} octst; + int note[12] = { C, Db, D, Eb, E, F, Gb, G, Ab, A, Bb, B }; // Note Pins above int octave[4] = { - Oct1, Oct2, Oct3, Oct4 }; // Octave Pins above - -int noteCounter[49] = { 0 }; -boolean status[49] = { LOW }; -boolean flip[49] = { LOW }; -boolean buffer = LOW; - -int octBuffer; -byte noteBuffer; - - -byte velocity = 100; // Placeholder. Will need something to change it -int channel = 7; // Placeholder. Will need something to change it -int bpm = 120; // Placeholder. Will need something to change it -int gate = 300; // Placeholder. Will need something to change it + Oct1, Oct2, Oct3, Oct4 }; // Octave Pins above +int clock = 0; // Used if arp to cycle through notes +octst buff; +bool kboard[49]; +bool raw; // Global Settings. RAW = signal is sent when key is detected +byte velocity = 100; +byte channel = 1; +int bpm = 360; unsigned long nextBeat = 0; -int step = 0; -int lastStep = 0; -boolean notePlayed = LOW; +unsigned long gate = 50; //ms of keypress if arpeggiator +int npressed; - - -void setup() -{ +void setup() { for (int cOctave = 0; cOctave < 4; cOctave++) { pinMode(octave[cOctave], OUTPUT); } for (int cNote = 0; cNote < 12; cNote++) { pinMode(note[cNote], INPUT); } + MIDI.begin(MIDI_CHANNEL_OFF); Serial.begin(115200); - nextBeat = millis() + (MINUTE / bpm); -} + nextBeat = millis() + (MINUTE / bpm); + pinMode(2, INPUT_PULLUP); + + for (int cStat = 0; cStat < 49; cStat++) kboard[cStat] = LOW; +} void loop() { - if (millis() < nextBeat) return; - notePlayed = LOW; - while (notePlayed == LOW) { - cleanScan(); - arp(); - } - nextBeat += (MINUTE / bpm); -} - -void cleanScan() { - int c; - for (c = 0; c < 49; c++) noteCounter[c] = 0; - scan(); - for (c = 0; c < 49; c++) { - if (status[c] == HIGH) noteCounter[c]++; - } - scan(); - for (c = 0; c < 49; c++) { - if (status[c] == HIGH) noteCounter[c]++; - } - scan(); - for (c = 0; c < 49; c++) { - if (status[c] == HIGH) noteCounter[c]++; - } - for (c = 0; c < 49; c++) { - if (noteCounter[c] == 3) status[c] = HIGH; - else status[c] = LOW; - } -} - -void send() { - for (int c = 48; c >= 0; c--) { - if (flip[c] == HIGH) { - flip[c] = LOW; - if (noteCounter[c] > 0) { - noteCounter[c]--; - } - else { - noteCounter[c] = offCounter; - noteBuffer = c + noteOffset; - if (status[c] == HIGH) { - MIDI.sendNoteOn(noteBuffer, velocity, channel); - } - else if (status[c] == LOW) { - MIDI.sendNoteOff(noteBuffer, velocity, channel); - } - } - } - } -} - -void playNote(int c, boolean status) { - if (status == HIGH) { - MIDI.sendNoteOn(c + noteOffset, velocity, channel); - } - else if (status == LOW) { - MIDI.sendNoteOff(c + noteOffset, velocity, channel); - } -} - -void arp() { - step++; - while (step < 49 && status[step] == LOW) { - step++; - } - if (step == 49) { - step = 0; - } - else { - playNote(lastStep, LOW); - playNote(step, HIGH); - lastStep = step; - notePlayed = HIGH; - } - return; -} - -void scan() { + npressed = 0; + raw = digitalRead(2); for (int cOctave = 0; cOctave < 4; cOctave++) { - octBuffer = 12 * cOctave; digitalWrite(octave[cOctave], HIGH); - - - for (int cNote = 0; cNote < 12; cNote++) { - buffer = digitalRead(note[cNote]); - - if (buffer ^ status[cNote + octBuffer]) { - status[cNote + octBuffer] = buffer; - flip[cNote + octBuffer] = HIGH; - } - else { - flip[cNote + octBuffer] = LOW; - } - - } + npressed += eval(scan(cOctave)); digitalWrite(octave[cOctave], LOW); } - -} - -int nPressed() { - int c, n = 0; - for (c = 0; c < 49; c++) { - if (status[c] == HIGH) { - n++; + if (raw) { + nextBeat = millis(); + return; + } + if (npressed < 1) return; + if (millis() >= nextBeat) { + nextBeat += (MINUTE / bpm); + clock++; + while (kboard[clock] == LOW) { + clock++; + if (clock == 49) clock = 0; } + playNote(clock, HIGH); + delay(gate); + playNote(clock, LOW); } } + + +octst scan(int nOct) { // This function reads the 12 note pins and returns a struct + int c; // with 1 bool for each note + octst output; + + output.nOct = nOct; + + for (c = 0; c < 12; c++) { + output.stat[c] = digitalRead(note[c]); + } + return output; +} + +int eval(octst input) { + int pressed = 0; + int snote = input.nOct * 12; + + for (int c = 0; c < 12; c++) { + if (input.stat[c] ^ kboard[c + snote]) { + if (raw) playNote(c + snote, input.stat[c]); + kboard[c + snote] = input.stat[c]; + } + if (kboard[c + snote] == HIGH) pressed++; + } + return pressed; +} + +void playNote(int c, bool status) { + byte n = c + noteOffset; + if (status == HIGH) { + MIDI.sendNoteOn(n, velocity, channel); + } + else if (status == LOW) { + MIDI.sendNoteOff(n, velocity, channel); + } +} \ No newline at end of file From b89ce7c72a83b3e3436352ed4a1c818afc6f4da0 Mon Sep 17 00:00:00 2001 From: alemi Date: Sun, 10 Mar 2019 02:33:40 +0100 Subject: [PATCH 4/5] Cleaned the code, receiving clock from MIDI Commented, removed many #define and many general code improvements. Arpeggiator waits for MIDI clock. --- cvkeyboard.ino | 144 +++++++++++++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 53 deletions(-) diff --git a/cvkeyboard.ino b/cvkeyboard.ino index 1acff96..ad855e4 100644 --- a/cvkeyboard.ino +++ b/cvkeyboard.ino @@ -1,50 +1,50 @@ -#define C 22 -#define Db 24 -#define D 26 -#define Eb 28 -#define E 30 -#define F 32 -#define Gb 34 -#define G 36 -#define Ab 38 -#define A 40 -#define Bb 42 -#define B 44 -#define testLed 13 - -#define Oct1 12 -#define Oct2 9 -#define Oct3 8 -#define Oct4 10 - #define noteOffset 36 +#define DRUMNOTE 60 #define MINUTE 60000 +#define MIDICLOCK 0xf8 +#include #include #include MIDI_CREATE_DEFAULT_INSTANCE(); -typedef struct OctaveStatus { +typedef struct OctaveStatus { // This struct is for an octave status. Each bool is for 1 note bool stat[12]; int nOct; } octst; -int note[12] = { - C, Db, D, Eb, E, F, Gb, G, Ab, A, Bb, B }; // Note Pins above -int octave[4] = { - Oct1, Oct2, Oct3, Oct4 }; // Octave Pins above -int clock = 0; // Used if arp to cycle through notes -octst buff; -bool kboard[49]; -bool raw; // Global Settings. RAW = signal is sent when key is detected -byte velocity = 100; -byte channel = 1; -int bpm = 360; -unsigned long nextBeat = 0; -unsigned long gate = 50; //ms of keypress if arpeggiator -int npressed; +// PIN DECLARATIONS +int note[12] = { // Pins used to read each note (C is 0, B is 11) + 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44 }; +int octave[4] = { // Pins associated to each octave's contact bar + 12, 9, 8, 10 }; +int sendPin[3] = { // Pins used as sender for capacitive touch buttons + 5, 4, 16 }; +int receivePin[3] = { // Pins used as receiver for capacitive touch buttons + 6, 3, 17 }; + +// GLOBAL SETTINGS +bool raw; // Signal is sent when key is detected + + // PLACEHOLDERS +byte velocity = 100; // +byte channel = 1; // +int bpm = 360; // +unsigned long gate = 50; // ms of keypress if arpeggiator +unsigned long nextBeat = 0; // Used to keep track of beats. Useless if receiving MIDI clock. + + // SYSTEM VARIABLES +int arp = 0; // Keeps track of last played note if arpeggiating +int midiclock = 0; // Used to sync with MIDI clock +int semA = 0; // Basic semaphore implementation with global counter +int semB = 0; +int npressed; // Number of keys pressed, used to avoid doing anything when no keys are pressed +bool kboard[49]; // Last status of keyboard +bool bCapStat[3]; // Last status of Capacitive Buttons +CapacitiveSensor* bCap[3]; + void setup() { for (int cOctave = 0; cOctave < 4; cOctave++) { @@ -53,17 +53,27 @@ void setup() { for (int cNote = 0; cNote < 12; cNote++) { pinMode(note[cNote], INPUT); } + for (int cButton = 0; cButton < 3; cButton++) { // Capacitive Buttons configuration + bCap[cButton] = new CapacitiveSensor(sendPin[cButton], receivePin[cButton]); // Initialized + bCap[cButton]->set_CS_AutocaL_Millis(0xFFFFFFFF); // No recalibration + bCap[cButton]->set_CS_Timeout_Millis(200); // Timeout set to 200ms (instead of 2s) + bCapStat[cButton] = LOW; // Button starts LOW + } + + for (int cStat = 0; cStat < 49; cStat++) kboard[cStat] = LOW; // All keyboard keys start LOW MIDI.begin(MIDI_CHANNEL_OFF); Serial.begin(115200); - nextBeat = millis() + (MINUTE / bpm); - pinMode(2, INPUT_PULLUP); - - for (int cStat = 0; cStat < 49; cStat++) kboard[cStat] = LOW; + pinMode(2, INPUT_PULLUP); // Used for RAW switch } void loop() { + sync(); + + for (int cButton = 0; cButton < 3; cButton++) { + bCapStat[cButton] = evalButton(bCap[cButton], bCapStat[cButton], DRUMNOTE + cButton); + } npressed = 0; raw = digitalRead(2); for (int cOctave = 0; cOctave < 4; cOctave++) { @@ -71,27 +81,27 @@ void loop() { npressed += eval(scan(cOctave)); digitalWrite(octave[cOctave], LOW); } - if (raw) { - nextBeat = millis(); - return; - } + if (raw) return; if (npressed < 1) return; - if (millis() >= nextBeat) { - nextBeat += (MINUTE / bpm); - clock++; - while (kboard[clock] == LOW) { - clock++; - if (clock == 49) clock = 0; + + if (semA > 0) { + semA--; + arp++; + while (kboard[arp] == LOW) { + arp++; + if (arp == 49) arp = 0; } - playNote(clock, HIGH); - delay(gate); - playNote(clock, LOW); + playNote(arp, HIGH); + } + if (semB > 0) { + semB--; + playNote(arp, LOW); } } octst scan(int nOct) { // This function reads the 12 note pins and returns a struct - int c; // with 1 bool for each note + int c; // with 1 bool for each note octst output; output.nOct = nOct; @@ -124,4 +134,32 @@ void playNote(int c, bool status) { else if (status == LOW) { MIDI.sendNoteOff(n, velocity, channel); } -} \ No newline at end of file +} + +bool evalButton(CapacitiveSensor* b, bool value, byte note) { + long sensor = b->capacitiveSensor(1); + + if (sensor > 15) { + if (value) return HIGH; + else { + MIDI.sendNoteOn(note, velocity, (byte)7); + return HIGH; + } + } + else { + if (!value) return LOW; + else { + MIDI.sendNoteOff(note, velocity, (byte)7); + return LOW; + } + } +} + +void sync() { + if (Serial.available() && Serial.read() == MIDICLOCK) { + midiclock++; + if (midiclock == 11 && semA == 0) semA++; + else if (midiclock == 5 && semB == 0) semB++; + else if (midiclock == 12) midiclock = 0; + } +} From 22191ec00d5093cc7cd4d68b49b3be3b8b773b75 Mon Sep 17 00:00:00 2001 From: alemi Date: Fri, 28 Jun 2019 01:52:21 +0200 Subject: [PATCH 5/5] Updated gitignore --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index 01d8aed..e29e6a7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,10 @@ /.vs /CppProperties.json +.vscode/arduino.json +.vscode/c_cpp_properties.json +.vscode/settings.json +.vscode/ipch/2a8fc4e60d41b99f/mmap_address.bin +.vscode/ipch/a05e84ed92aede25/mmap_address.bin +.vscode/ipch/f3a41dbca76912c5/WIRING_DIGITAL.ipch +.vscode/ipch/f3a41dbca76912c5/mmap_address.bin