diff --git a/Software/Gravity/Gravity.ino b/Software/Gravity/Gravity.ino index 8ccfe93..64acb02 100644 --- a/Software/Gravity/Gravity.ino +++ b/Software/Gravity/Gravity.ino @@ -11,7 +11,7 @@ #define VERSION "V:1.2A2" -byte memCode = 'e'; //Change to different letter if you changed the data structure +byte memCode = '0'; //Change to different letter if you changed the data structure uint16_t CV1Calibration = 512; uint16_t CV2Calibration = 512; @@ -46,7 +46,46 @@ channel channels[7] = { //array of channel settings { 0, 7, 0, 0, 0, 0, 0, 0, 1, 0 } }; -bool seqA1[16] = {1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1}; //switch to struct seqs { uint32_t sequence; uint8_t length : 5 ; uint8_t currentStep : 5}. test with lengthOf +struct sequence { + uint32_t sequence; + uint8_t length : 5 ; //don't forget to add 1, values 0 - 31 +}; + +sequence sequences[] { + {0b000000000000000001001000100010001, 15}, + {0b000000000000000000000100000010000, 11}, + {0b000000000000000000001001001001001, 6}, + {0b000000000000000001100110011001100, 20}, + {0b000000000000000001110111011101110, 30}, + {0b000000000000000000101010001010100, 31}, + {0b000000000000000000111111111011111, 15}, + {0b000000000000000001101101110110011, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15}, + {0b000000000000000000000000000000000, 15} +}; +/*bool seqA1[16] = {1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1}; bool seqA2[16] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}; bool seqA3[16] = {1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0}; bool seqA4[16] = {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1}; @@ -61,10 +100,10 @@ bool seqB4[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; bool seqB5[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; bool seqB6[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; bool seqB7[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -bool seqB8[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -byte currentStep = 0; +bool seqB8[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};*/ +byte currentStep[7] = {0}; byte stepNumSelected = 0; -bool *patternToEdit; +byte patternToEdit; unsigned int channelPulseCount[7]; unsigned int channelPulsesPerCycle[7]; @@ -72,7 +111,7 @@ byte sixteenthPulseCount = 0; int playingModes[7]; // should be renamed to currentSubdivs or something. Updated from channels object on beat and with applied CV modulation int playingModesOld[7]; -unsigned int pulsePeriod; +unsigned int pulsePeriod; bool isPlaying;// = false; // replace to something like byte status where 1xxxxxx isPlaying, x1xxxxx isRecording etc bool isRecording = false; bool recordToNextStep = false; @@ -88,7 +127,7 @@ unsigned long lastExtPulseTime = 0; unsigned long newExtPulseTime = 0; bool needPulseReset[] = { true, true, true, true, true, true, true }; -uint16_t gateLengthTime[] = {120, 120, 120, 120, 120, 120, 120}; +uint16_t gateLengthTime[] = {0, 0, 0, 0, 0, 0, 0}; uint16_t gateCountDown[7]; bool stepIsOdd = 1; @@ -154,7 +193,7 @@ void setup() { resetClocks(); - FlexiTimer2::set(1, 1.0 / 10000, clock); // 1.0/1000 = 1ms period. If other than 1ms calculateBPMTiming() might need tweaking + FlexiTimer2::set(1, 1.0 / 10000, clock); // 1.0/1000 = 1ms period FlexiTimer2::start(); } @@ -213,6 +252,11 @@ void clock() { } if (bpmModulationRange != 0) { calculateBPMTiming(); + for (byte i; i < 7; i++) { + if (channels[i].mode == 4) { + calculateGate(i); + } + } } } } @@ -223,7 +267,7 @@ void clock() { } } - if (masterClockMode == 2 && MIDIClockReceived) { // MIDI should happen here (needs testing) + if (masterClockMode == 2 && MIDIClockReceived) { tickCount = 0; //to make things happen in the main clock function if (pulseCount < (PPQN - 1)) { pulseCount++; @@ -235,14 +279,19 @@ void clock() { // pull low all outputs after set pulse length for (byte i = 0; i < 7; i++) { - if (channels[i].mode != 4 && tickCount >= PULSE_LENGTH) { //everything but gate mode + if (channels[i].mode != 4 && tickCount >= PULSE_LENGTH) { //everything but gate mode digitalWrite(outsPins[i], LOW); - } else if (channels[i].mode == 4 && tickCount >= gateCountDown[i]) { //gate mode gateLengthTime[i] < pulsePeriod + } + + if (channels[i].mode == 4 && gateCountDown[i] > pulsePeriod && tickCount >= pulsePeriod) { //tickCount == 0? + gateCountDown[i] = gateCountDown[i] - pulsePeriod; // !!! Most likely something is wrong here that causing the drift + } + + if (channels[i].mode == 4 && tickCount >= gateCountDown[i]) { //gate mode digitalWrite(outsPins[i], LOW); gateCountDown[i] = gateLengthTime[i]; - } else if (channels[i].mode == 4 && gateCountDown[i] > pulsePeriod && tickCount == 0) { - gateCountDown[i] = gateCountDown[i] - pulsePeriod; } + } } @@ -307,7 +356,6 @@ void sendTriggers() { //rename to onPulse or something } //16th notes for sequencer and swing if (sixteenthPulseCount == 0) { - bool *currentSeq; stepIsOdd = !stepIsOdd; for (byte i = 0; i < (extraChannel ? 7 : 6); i++) { @@ -331,40 +379,8 @@ void sendTriggers() { //rename to onPulse or something seqPattern = channels[i].seqPattern + seqMod; } - if (seqPattern == 0) { - currentSeq = seqA1; - } else if (seqPattern == 1) { - currentSeq = seqA2; - } else if (seqPattern == 2) { - currentSeq = seqA3; - } else if (seqPattern == 3) { - currentSeq = seqA4; - } else if (seqPattern == 4) { - currentSeq = seqA5; - } else if (seqPattern == 5) { - currentSeq = seqA6; - } else if (seqPattern == 6) { - currentSeq = seqA7; - } else if (seqPattern == 7) { - currentSeq = seqA8; - } else if (seqPattern == 8) { - currentSeq = seqB1; - } else if (seqPattern == 9) { - currentSeq = seqB2; - } else if (seqPattern== 10) { - currentSeq = seqB3; - } else if (seqPattern == 11) { - currentSeq = seqB4; - } else if (seqPattern == 12) { - currentSeq = seqB5; - } else if (seqPattern == 13) { - currentSeq = seqB6; - } else if (seqPattern == 14) { - currentSeq = seqB7; - } else if (seqPattern == 15) { - currentSeq = seqB8; - } - if (channels[i].mode == 2 && currentSeq[currentStep]) { + bool currentStepValue = bitRead(sequences[channels[i].seqPattern].sequence, currentStep[i]); + if (channels[i].mode == 2 && currentStepValue) { digitalWrite(outsPins[i], HIGH); } } @@ -376,10 +392,12 @@ void sendTriggers() { //rename to onPulse or something } } else { sixteenthPulseCount = 0; - if (currentStep < 15) { - currentStep ++; - } else { - currentStep = 0; + for (byte i; i < 7; i++) { + if (channels[i].mode == 2 && currentStep[i] <= sequences[channels[i].seqPattern].length) { + currentStep[i] ++; + } else { + currentStep[i] = 0; + } } recordToNextStep = false; } @@ -392,6 +410,9 @@ void sendTriggers() { //rename to onPulse or something channelPulseCount[i] = 0; needPulseReset[i] = false; } + if (channels[i].mode == 4) { + calculateGate(i); + } } } @@ -456,17 +477,17 @@ void calculateCycles() { } else if (playingModes[i] < 0) { channelPulsesPerCycle[i] = (PPQN / abs(playingModes[i])) - 1; } - - if (channels[i].mode == 4) { - calculateGate(i); - } } } void calculateGate(uint8_t channel) { //if (subDivs[channels[channel].subDiv] > 0) { - gateLengthTime[channel] = (channelPulsesPerCycle[channel] * pulsePeriod / 100) * channels[channel].gate; - gateCountDown[channel] = gateLengthTime[channel]; + uint16_t gateLengthOld = gateLengthTime[channel]; + //gateLengthTime[channel] = ((channelPulsesPerCycle[channel] + 1) * (pulsePeriod + 1) / 100) * channels[channel].gate; // this seemed to work, but at some point started drifting + gateLengthTime[channel] = ((channelPulsesPerCycle[channel] + 1) * (pulsePeriod - 1) / 100) * channels[channel].gate; + if (gateLengthOld != gateLengthTime[channel]) { + gateCountDown[channel] = gateLengthTime[channel]; + } //} } @@ -501,7 +522,9 @@ void resetClocks() { pulseCount = 0; tickCount = 0; sixteenthPulseCount = 0; - currentStep = 0; + for (byte i; i < 7; i++) { + currentStep[i] = 0; + } stepIsOdd = 1; } @@ -517,38 +540,8 @@ void saveState() { addr = addr + sizeof(masterClockMode); EEPROM.put(addr, channels); addr = addr + sizeof(channels); - EEPROM.put(addr, seqA1); - addr = addr + sizeof(seqA1); - EEPROM.put(addr, seqA2); - addr = addr + sizeof(seqA2); - EEPROM.put(addr, seqA3); - addr = addr + sizeof(seqA3); - EEPROM.put(addr, seqA4); - addr = addr + sizeof(seqA4); - EEPROM.put(addr, seqA5); - addr = addr + sizeof(seqA5); - EEPROM.put(addr, seqA6); - addr = addr + sizeof(seqA6); - EEPROM.put(addr, seqA7); - addr = addr + sizeof(seqA7); - EEPROM.put(addr, seqA8); - addr = addr + sizeof(seqA8); - EEPROM.put(addr, seqB1); - addr = addr + sizeof(seqB1); - EEPROM.put(addr, seqB2); - addr = addr + sizeof(seqB2); - EEPROM.put(addr, seqB3); - addr = addr + sizeof(seqB3); - EEPROM.put(addr, seqB4); - addr = addr + sizeof(seqB4); - EEPROM.put(addr, seqB5); - addr = addr + sizeof(seqB5); - EEPROM.put(addr, seqB6); - addr = addr + sizeof(seqB6); - EEPROM.put(addr, seqB7); - addr = addr + sizeof(seqB7); - EEPROM.put(addr, seqB8); - addr = addr + sizeof(seqB8); + EEPROM.put(addr, sequences); + addr = addr + sizeof(sequences); EEPROM.put(addr, CV1Calibration); addr = addr + sizeof(CV1Calibration); EEPROM.put(addr, CV2Calibration); @@ -576,38 +569,8 @@ void loadState() { addr = addr + sizeof(masterClockMode); EEPROM.get(addr, channels); addr = addr + sizeof(channels); - EEPROM.get(addr, seqA1); - addr = addr + sizeof(seqA1); - EEPROM.get(addr, seqA2); - addr = addr + sizeof(seqA2); - EEPROM.get(addr, seqA3); - addr = addr + sizeof(seqA3); - EEPROM.get(addr, seqA4); - addr = addr + sizeof(seqA4); - EEPROM.get(addr, seqA5); - addr = addr + sizeof(seqA5); - EEPROM.get(addr, seqA6); - addr = addr + sizeof(seqA6); - EEPROM.get(addr, seqA7); - addr = addr + sizeof(seqA7); - EEPROM.get(addr, seqA8); - addr = addr + sizeof(seqA8); - EEPROM.get(addr, seqB1); - addr = addr + sizeof(seqB1); - EEPROM.get(addr, seqB2); - addr = addr + sizeof(seqB2); - EEPROM.get(addr, seqB3); - addr = addr + sizeof(seqB3); - EEPROM.get(addr, seqB4); - addr = addr + sizeof(seqB4); - EEPROM.get(addr, seqB5); - addr = addr + sizeof(seqB5); - EEPROM.get(addr, seqB6); - addr = addr + sizeof(seqB6); - EEPROM.get(addr, seqB7); - addr = addr + sizeof(seqB7); - EEPROM.get(addr, seqB8); - addr = addr + sizeof(seqB8); + EEPROM.get(addr, sequences); + addr = addr + sizeof(sequences); EEPROM.get(addr, CV1Calibration); addr = addr + sizeof(CV1Calibration); EEPROM.get(addr, CV2Calibration); diff --git a/Software/Gravity/Interactions.ino b/Software/Gravity/Interactions.ino index 2830b52..fe765ac 100644 --- a/Software/Gravity/Interactions.ino +++ b/Software/Gravity/Interactions.ino @@ -13,39 +13,7 @@ void checkInputs() { if (!insideTab && displayScreen == 0) { insideTab = true; } else if (insideTab && channels[displayTab - 1].mode == 2 && menuItem == 2 && displayScreen == 0) { //enter the pattern editor - if (channels[displayTab - 1].seqPattern == 0) { - patternToEdit = seqA1; - } else if (channels[displayTab - 1].seqPattern == 1) { - patternToEdit = seqA2; - } else if (channels[displayTab - 1].seqPattern == 2) { - patternToEdit = seqA3; - } else if (channels[displayTab - 1].seqPattern == 3) { - patternToEdit = seqA4; - } else if (channels[displayTab - 1].seqPattern == 4) { - patternToEdit = seqA5; - } else if (channels[displayTab - 1].seqPattern == 5) { - patternToEdit = seqA6; - } else if (channels[displayTab - 1].seqPattern == 6) { - patternToEdit = seqA7; - } else if (channels[displayTab - 1].seqPattern == 7) { - patternToEdit = seqA8; - } else if (channels[displayTab - 1].seqPattern == 8) { - patternToEdit = seqB1; - } else if (channels[displayTab - 1].seqPattern == 9) { - patternToEdit = seqB2; - } else if (channels[displayTab - 1].seqPattern == 10) { - patternToEdit = seqB3; - } else if (channels[displayTab - 1].seqPattern == 11) { - patternToEdit = seqB4; - } else if (channels[displayTab - 1].seqPattern == 12) { - patternToEdit = seqB5; - } else if (channels[displayTab - 1].seqPattern == 13) { - patternToEdit = seqB6; - } else if (channels[displayTab - 1].seqPattern == 14) { - patternToEdit = seqB7; - } else if (channels[displayTab - 1].seqPattern == 15) { - patternToEdit = seqB8; - } + patternToEdit = channels[displayTab - 1].seqPattern; displayScreen = 1; isRecording = 0; } else if (insideTab && displayScreen == 0) { @@ -377,9 +345,9 @@ void checkInputs() { } } else if (displayScreen == 1 && !isRecording) { stepNumSelected = stepNumSelected + change; - if (stepNumSelected > 100) { - stepNumSelected = 15; - } else if (stepNumSelected > 15) { + if (stepNumSelected > sequences[channels[displayTab - 1].seqPattern].length + 1) { + stepNumSelected = sequences[channels[displayTab - 1].seqPattern].length; + } else if (stepNumSelected > sequences[channels[displayTab - 1].seqPattern].length) { stepNumSelected = 0; } } else if (displayScreen == 2 && !shiftBtnPushed) { @@ -432,13 +400,13 @@ void checkInputs() { digitalWrite(outsPins[displayTab - 1], HIGH); } if (displayScreen == 1 && !isRecording) { - patternToEdit[stepNumSelected] = !patternToEdit[stepNumSelected]; + sequences[patternToEdit].sequence = bitFlip(sequences[patternToEdit].sequence, stepNumSelected); } else if (displayScreen == 1 && isRecording && !recordToNextStep) { //Recording - patternToEdit[currentStep] = 1; + bitSet(sequences[patternToEdit].sequence, currentStep[displayTab - 1]); } else if (displayScreen == 1 && isRecording && recordToNextStep && currentStep != 15) { - patternToEdit[currentStep+1] = 1; + bitSet(sequences[patternToEdit].sequence, currentStep[displayTab - 1] + 1); } else if (displayScreen == 1 && isRecording && recordToNextStep && currentStep == 15) { - patternToEdit[0] = 1; + bitSet(sequences[patternToEdit].sequence, 0); } saveState(); updateScreen(); @@ -446,9 +414,7 @@ void checkInputs() { shiftBtnPushed = false; shiftReleasedTime = millis(); if (displayScreen == 1 && shiftReleasedTime - shiftPressedTime > 500 && !encBtnPushed) { //&& shiftReleasedTime - shiftPressedTime < 2000 //Clear the sequence - for (byte i = 0; i < 16; i++) { - patternToEdit[i] = 0; - } + sequences[patternToEdit].sequence = 0b000000000000000000000000000000000; } else if (shiftReleasedTime - shiftPressedTime > 2000 && encBtnPushed) { displayScreen = 2; menuItemSelected = 1; //hack to prevent from going back when the encoder is released diff --git a/Software/Gravity/UI.ino b/Software/Gravity/UI.ino index b5bdb9b..098576a 100644 --- a/Software/Gravity/UI.ino +++ b/Software/Gravity/UI.ino @@ -302,26 +302,11 @@ void updateScreen() { valueStr = valueStr + String(pattern - 7); } u8g2.drawButtonUTF8(64, 5, U8G2_BTN_BW1|U8G2_BTN_HCENTER, 128, 0, 2, valueStr.c_str() ); - for (byte i = 0; i < 8; i++) { - if (patternToEdit[i]) { - u8g2.drawUTF8(19 + i*12, 24, "q"); - } else { - u8g2.drawUTF8(19 + i*12, 24, "p"); - } - } - for (byte i = 8; i < 16; i++) { - if (patternToEdit[i]) { - u8g2.drawUTF8(19 + (i-8)*12, 40, "q"); - } else { - u8g2.drawUTF8(19 + (i-8)*12, 40, "p"); - } + for (byte i = 0; i <= sequences[patternToEdit].length; i++) { + u8g2.drawUTF8(19 + (i % 8)*12, 18 + ((i / 8) * 11), (bitRead(sequences[patternToEdit].sequence, i) ? "q" : "p")); } if (!isRecording) { - if (stepNumSelected < 8 ) { - u8g2.drawFrame(16 + stepNumSelected * 12, 16, 11, 11); - } else { - u8g2.drawFrame(16 + (stepNumSelected-8) * 12, 32, 11, 11); - } + u8g2.drawFrame(16 + (stepNumSelected % 8)*12, 10 + ((stepNumSelected / 8) * 11), 11, 11); //cursor } if (isRecording) { diff --git a/Software/Gravity/config.h b/Software/Gravity/config.h index 2f95849..c06418e 100644 --- a/Software/Gravity/config.h +++ b/Software/Gravity/config.h @@ -37,3 +37,5 @@ const byte clockOutPin = 13; const byte outsPins[6] = {6, 11, 7, 10, 8, 9}; bool rotateScreen = true; */ + +#define bitFlip(value, bit) ((value) ^ (1UL << (bit))) \ No newline at end of file