diff --git a/cvkeyboard.ino b/cvkeyboard.ino index 30f672d..bd6b90c 100644 --- a/cvkeyboard.ino +++ b/cvkeyboard.ino @@ -2,12 +2,15 @@ #include #include +#define BPQN 24 // Ableton sends 24, VCV rack only one, by standard should be 24? + #define NOTEOffset 36 #define drumOffset 60 #define MINUTE 60000 #define MIDICLOCK 0xf8 #define MAXKEYS 48 #define MAXDPAD 3 +#define MAXSTEP 16 MIDI_CREATE_DEFAULT_INSTANCE(); @@ -21,6 +24,7 @@ typedef struct OCTAVEStatus { // This struct is for an OCTAVE status. Each typedef struct SequencerStep { bool kboard_s[MAXKEYS]; bool dpad_s[MAXDPAD]; + unsigned short stepnumber; link next; } step; @@ -49,16 +53,18 @@ int bpm = 360; // // SEQUENCER POINTERS -link head, tail, current; +link head = NULL; +link current = NULL; // SYSTEM VARIABLES -int nstep = 0; // Keeps track of the sequencer steps +unsigned short nstep = 0; // Keeps track of the sequencer steps int arp = 0; // Keeps track of last played NOTE if arpeggiating int midiclock = 0; // Used to sync with MIDI clock +bool add_step = LOW; // This is used to remember the addition of a step int sem_beat = 0; // Basic semaphore used to sync with MIDI beat int sem_gate = 0; // Basic semaphore used for gate timing unsigned long last_gate = 0; // Gate start time for last sequencer step -unsigned long gate_length = 200; // ms of keypress if arpeggiator +unsigned long gate_length = 500; // ms of keypress if arpeggiator bool dpadhit = LOW; // If any drum pad has been hit in this cycle, this is true int npressed; // Number of keys pressed, used to avoid doing anything when no keys are pressed bool kboard[MAXKEYS]; // Last status of keyboard @@ -73,7 +79,7 @@ void setup() { for (int cButton = 0; cButton < MAXDPAD; cButton++) { // Capacitive Buttons configuration bCap[cButton] = new CapacitiveSensor(SEND[cButton], RECEIVE[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) + bCap[cButton]->set_CS_Timeout_Millis(10); // Timeout set to 20ms (instead of 2s) dpad[cButton] = LOW; // Button starts LOW } @@ -84,36 +90,63 @@ void setup() { pinMode(OW, INPUT_PULLUP); // Used for overwrite switch pinMode(ADD, INPUT_PULLUP); // Used for overwrite switch + + for (int i = 0; i < 16; i++) { // Boot up fancyness! + display(i); + delay(200); + } + + display(nstep); } void loop() { + // Serial.println(midiclock); + // Serial.print("Start | "); + // Serial.print(millis()); + // Serial.print('\n'); sync(); - if (current == head) nstep = 0; - else nstep++; - display(nstep); + add_step = (add_step || !digitalRead(ADD)); + // Serial.print("SPEPS DONE | "); + // Serial.print(millis()); + // Serial.print('\n'); if (sem_beat > 0) { sem_beat--; + if (sem_gate > 0) { // If step was shorter than gate, close all open notes before next step sem_gate--; for (int i = 0; i < MAXKEYS; i++) if (current->kboard_s[i]) playNOTE(i, !current->kboard_s[i]); for (int i = 0; i < MAXDPAD; i++) if (current->dpad_s[i]) playDrum(i, !current->dpad_s[i]); } - if (digitalRead(ADD)) insertStep(); + if (add_step) { + add_step = LOW; + if (nstep < MAXSTEP) insertStep(); + } //if (digitalRead(ADD) && !digitalRead(OW)) deleteStep(); // Placeholder because I miss a button + nextStep(); + display(current->stepnumber); + if (current != NULL) { // Play all step notes and begin counting for gate for (int i = 0; i < MAXKEYS; i++) if (current->kboard_s[i]) playNOTE(i, current->kboard_s[i]); for (int i = 0; i < MAXDPAD; i++) if (current->dpad_s[i]) playDrum(i, current->dpad_s[i]); last_gate = millis(); sem_gate++; } + // Serial.print("BEAT ELABORATED AND PLAYED | "); + // Serial.print(millis()); + // Serial.print('\n'); } + if (sem_gate > 0 && (millis() - last_gate) > gate_length) { sem_gate--; for (int i = 0; i < MAXKEYS; i++) if (current->kboard_s[i]) playNOTE(i, !current->kboard_s[i]); for (int i = 0; i < MAXDPAD; i++) if (current->dpad_s[i]) playDrum(i, !current->dpad_s[i]); + // Serial.print("GATE FINISHED | "); + // Serial.print(millis()); + // Serial.print('\n'); } + dpadhit = LOW; for (int cButton = 0; cButton < MAXDPAD; cButton++) { dpad[cButton] = evalButton(bCap[cButton], dpad[cButton], cButton); @@ -126,10 +159,16 @@ void loop() { npressed += eval(scan(cOCTAVE)); digitalWrite(OCTAVE[cOCTAVE], LOW); } + // Serial.print("READ KEYBOARD | "); + // Serial.print(millis()); + // Serial.print('\n'); if (digitalRead(OW)) { if (npressed > 0) for (int i = 0; i < MAXKEYS; i++) current->kboard_s[i] = kboard[i]; if (dpadhit) for (int i = 0; i < MAXDPAD; i++) current->dpad_s[i] = dpad[i]; + // Serial.print("OVERWRITTEN STUFF | "); + // Serial.print(millis()); + // Serial.print('\n'); } } @@ -149,13 +188,14 @@ octst scan(int nOct) { // This function reads the 12 NOTE pins and retu void display(int number){ for(int i = 0; i < 4; i++) { - digitalWrite(LEDS[i], number & 1); - number >> 1; - } + digitalWrite(LEDS[i], number & (unsigned short) 1); + number = number >> 1; + } } bool evalButton(CapacitiveSensor* b, bool value, int note_number) { long sensor = b->capacitiveSensor(1); + // Serial.println(sensor); if (sensor > 15) { if (value) return HIGH; @@ -212,12 +252,14 @@ void playDrum(int c, bool status) { // Sync functions void sync() { - if (Serial.available() && Serial.read() == MIDICLOCK) { - //sem_beat++; - midiclock++; - if (midiclock == 24){ - midiclock = 0; - sem_beat++; + if (Serial.available()) { + if (Serial.read() == MIDICLOCK) { + //sem_beat++; + midiclock++; + if (midiclock == BPQN){ + midiclock = 0; + sem_beat++; + } } } } @@ -230,28 +272,35 @@ link newStep() { bool insertStep() { link newS = newStep(); + link buffer; if (newS == NULL) { free(newS); return LOW; } - for (int i = 0; i < MAXKEYS; i++) newS->kboard_s[i] = kboard[i]; - for (int i = 0; i < MAXDPAD; i++) newS->dpad_s[i] = dpad[i]; + for (int i = 0; i < MAXKEYS; i++) newS->kboard_s[i] = LOW; + for (int i = 0; i < MAXDPAD; i++) newS->dpad_s[i] = LOW; - if (nstep == 0) { + if (current == NULL) { newS->next = newS; + newS->stepnumber = (unsigned short) 0; current = newS; head = newS; + nstep = 1; } else { - newS->next = current->next; - current->next = newS; + newS->stepnumber = nstep; + buffer = current; + while (buffer->next != head) buffer = buffer->next; + buffer->next = newS; + newS->next = head; + nstep++; } - nstep++; return HIGH; } void nextStep() { + if (current == NULL) return; current = current->next; }