switched to from ms based to internal ppqn clock
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
software/.DS_Store
|
||||||
|
.DS_Store
|
||||||
@ -1,8 +1,17 @@
|
|||||||
|
Features:
|
||||||
|
- 6 output channels
|
||||||
|
- Master BPM
|
||||||
|
- Separate divider per chennel
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
|
- Add multipliers
|
||||||
- Add min and max values
|
- Add min and max values
|
||||||
- External clock
|
- External clock
|
||||||
- Switch to U8G2 for screen
|
- Switch to U8G2 for screen
|
||||||
- Save state to EEPROM when stopped
|
- Save state to EEPROM when stopped
|
||||||
|
- swing
|
||||||
|
- long-press encoder for settings (input mode, pulse length)
|
||||||
|
- analogue input for modulations
|
||||||
|
|
||||||
Timer library available here
|
Timer library available here
|
||||||
https://github.com/PaulStoffregen/FlexiTimer2
|
https://github.com/PaulStoffregen/FlexiTimer2
|
||||||
|
|||||||
@ -7,30 +7,35 @@
|
|||||||
|
|
||||||
#define SCREEN_ADDRESS 0x3C
|
#define SCREEN_ADDRESS 0x3C
|
||||||
|
|
||||||
|
#define PPQN 24 //24 is good for triplets. each pulse is 1/512th note
|
||||||
|
#define PULSE_LENGTH 5
|
||||||
|
|
||||||
#define INPUT_CONNECTED_PIN 12
|
#define INPUT_CONNECTED_PIN 12
|
||||||
#define INPUT_PIN 2
|
#define INPUT_PIN 2
|
||||||
#define ENC_BTN_PIN 17
|
#define ENC_BTN_PIN 17
|
||||||
#define ENC_D1_PIN 4
|
#define ENC_D1_PIN 4
|
||||||
#define ENC_D2_PIN 3
|
#define ENC_D2_PIN 3
|
||||||
#define START_STOP_BTN_PIN 14
|
#define START_STOP_BTN_PIN 14
|
||||||
//Output pins are defined in the array below
|
|
||||||
|
|
||||||
int outsPins[6] = {5, 6, 7, 8, 9, 10};
|
int outsPins[6] = {5, 6, 7, 8, 9, 10};
|
||||||
|
|
||||||
int outsValues[6] = {1, 2, 4, -4, 1, 1}; //positive - divide, negative - multiply, 0 - off
|
|
||||||
|
int outsValues[6] = {1, 2, 4, -4, 0, 0}; //positive - divide, negative - multiply, 0 - off /2 /3 /4 /5 /6 /7 /8 /16 /32 /random x2 x3 x4 x6 x8 x12 x16 x24
|
||||||
int outsPeriods[6];
|
int outsPeriods[6];
|
||||||
int outsClocksCounts[6] = {0, 0, 0, 0, 0, 0};
|
int outsClocksCounts[6];
|
||||||
|
|
||||||
bool clockMode;
|
bool clockMode;
|
||||||
bool clockModeOld;
|
bool clockModeOld;
|
||||||
int inputMode; //clock, reset, start/stop
|
int inputMode; //clock, reset, start/stop
|
||||||
int clockCount = 0;
|
int clockCount = 0;
|
||||||
|
|
||||||
int bpm = 120;
|
int bpm = 127;
|
||||||
int bpmPeriod;
|
int pulseClockCount = 0;
|
||||||
int bpmClockCount;
|
int pulseCount = 0;
|
||||||
|
int pulsePeriod;
|
||||||
bool isPlaying = 0;
|
bool isPlaying = 0;
|
||||||
int needToResetChannel;
|
int needToResetChannel;
|
||||||
|
bool pulseCounted = false;
|
||||||
|
|
||||||
int displayTab = 0;
|
int displayTab = 0;
|
||||||
int displayTabOld;
|
int displayTabOld;
|
||||||
@ -71,40 +76,51 @@ void loop() {
|
|||||||
|
|
||||||
void internalClock() {
|
void internalClock() {
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
for (int i = 0; i<6; i++) {
|
|
||||||
if (outsClocksCounts[i] >= outsPeriods[i]) {
|
// pulse rules for dividers (multipliers should be in separate for loop, as this one occurs only on pulse 0 (bpm))
|
||||||
outsClocksCounts[i] = 0;
|
if (pulseCount == 0 && !pulseCounted) {
|
||||||
|
for (int i = 0; i<6; i++) {
|
||||||
|
if (outsValues[i] > 0) { //Dividers (>0)
|
||||||
|
if (outsClocksCounts[i] == 0) { //Pulse on 0
|
||||||
|
digitalWrite(outsPins[i], HIGH);
|
||||||
|
}
|
||||||
|
if (outsClocksCounts[i] < (outsValues[i]-1)) {
|
||||||
|
outsClocksCounts[i]++;
|
||||||
|
if (i == 0) {Serial.println(outsClocksCounts[i]);}
|
||||||
|
} else {
|
||||||
|
outsClocksCounts[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (outsClocksCounts[i] == 0) {
|
pulseCounted = true;
|
||||||
digitalWrite(outsPins[i], HIGH);
|
}
|
||||||
}
|
|
||||||
if (outsClocksCounts[i] == 15) { //15ms pulse
|
//lets get internal pulse going
|
||||||
|
if (pulseClockCount == 0) {
|
||||||
|
pulseCount++;
|
||||||
|
pulseCounted = false;
|
||||||
|
}
|
||||||
|
if (pulseClockCount < pulsePeriod) {
|
||||||
|
pulseClockCount++;
|
||||||
|
} else {
|
||||||
|
pulseClockCount = 0;
|
||||||
|
}
|
||||||
|
if (pulseCount >= PPQN) {
|
||||||
|
pulseCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull low all outputs after set pulse length
|
||||||
|
if (pulseClockCount >= PULSE_LENGTH) {
|
||||||
|
for (int i = 0; i<6; i++) {
|
||||||
digitalWrite(outsPins[i], LOW);
|
digitalWrite(outsPins[i], LOW);
|
||||||
}
|
}
|
||||||
outsClocksCounts[i]++;
|
|
||||||
}
|
|
||||||
if (bpmClockCount < bpmPeriod) {
|
|
||||||
bpmClockCount++;
|
|
||||||
} else {
|
|
||||||
bpmClockCount = 0;
|
|
||||||
if (needToResetChannel>=0) {
|
|
||||||
outsClocksCounts[needToResetChannel] = 0;
|
|
||||||
updatePeriods();
|
|
||||||
needToResetChannel = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updatePeriods() {
|
void updatePeriods() {
|
||||||
bpmPeriod = 60000 / bpm;
|
pulsePeriod = 60000 / (bpm * PPQN);
|
||||||
for (int i = 0; i<6; i++) {
|
|
||||||
if (outsValues[i]>0) {
|
|
||||||
outsPeriods[i] = bpmPeriod * outsValues[i];
|
|
||||||
} else {
|
|
||||||
outsPeriods[i] = bpmPeriod / outsValues[i] * - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetClocks() {
|
void resetClocks() {
|
||||||
@ -114,16 +130,18 @@ void resetClocks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void checkInputs() {
|
void checkInputs() {
|
||||||
|
|
||||||
|
//input jack switcch
|
||||||
clockMode = digitalRead(INPUT_CONNECTED_PIN);
|
clockMode = digitalRead(INPUT_CONNECTED_PIN);
|
||||||
if (clockMode != clockModeOld) {
|
if (clockMode != clockModeOld) {
|
||||||
updateScreen();
|
updateScreen();
|
||||||
clockModeOld = clockMode;
|
clockModeOld = clockMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//encoder button
|
||||||
if (needToChangeTab == 0 && digitalRead(ENC_BTN_PIN) == 0) {
|
if (needToChangeTab == 0 && digitalRead(ENC_BTN_PIN) == 0) {
|
||||||
needToChangeTab = 1;
|
needToChangeTab = 1;
|
||||||
}
|
} else if (needToChangeTab == 1 && digitalRead(ENC_BTN_PIN) == 1) {
|
||||||
|
|
||||||
if (needToChangeTab == 1 && digitalRead(ENC_BTN_PIN) == 1) {
|
|
||||||
displayTabOld = displayTab;
|
displayTabOld = displayTab;
|
||||||
displayTab++;
|
displayTab++;
|
||||||
if (displayTab>6) {
|
if (displayTab>6) {
|
||||||
@ -133,6 +151,7 @@ void checkInputs() {
|
|||||||
updateScreen();
|
updateScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//encoder
|
||||||
encoder.tick();
|
encoder.tick();
|
||||||
int encPosition = encoder.getPosition();
|
int encPosition = encoder.getPosition();
|
||||||
if (encPositionOld != encPosition) {
|
if (encPositionOld != encPosition) {
|
||||||
@ -147,6 +166,7 @@ void checkInputs() {
|
|||||||
encPositionOld = encPosition;
|
encPositionOld = encPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//play button
|
||||||
if (!digitalRead(START_STOP_BTN_PIN) && !buttonPushed) {
|
if (!digitalRead(START_STOP_BTN_PIN) && !buttonPushed) {
|
||||||
isPlaying = !isPlaying;
|
isPlaying = !isPlaying;
|
||||||
resetClocks();
|
resetClocks();
|
||||||
@ -163,7 +183,7 @@ void updateScreen() {
|
|||||||
display.setCursor(0,0);
|
display.setCursor(0,0);
|
||||||
display.setTextSize(1);
|
display.setTextSize(1);
|
||||||
if (displayTab == 0) {
|
if (displayTab == 0) {
|
||||||
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);resetClocks();
|
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
|
||||||
display.print(F(" "));
|
display.print(F(" "));
|
||||||
display.setTextColor(SSD1306_WHITE);
|
display.setTextColor(SSD1306_WHITE);
|
||||||
display.print(F(" bpm "));
|
display.print(F(" bpm "));
|
||||||
@ -186,26 +206,26 @@ void updateScreen() {
|
|||||||
display.print(i);
|
display.print(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
|
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
|
||||||
display.println(F(" "));
|
display.println(F(" "));
|
||||||
|
|
||||||
display.println();
|
display.println();
|
||||||
|
|
||||||
//Content
|
//Content
|
||||||
display.setTextSize(3);
|
display.setTextSize(3);
|
||||||
display.setTextColor(SSD1306_WHITE);
|
display.setTextColor(SSD1306_WHITE);
|
||||||
|
|
||||||
if (displayTab == 0) {
|
if (displayTab == 0) {
|
||||||
display.print(bpm);
|
display.print(bpm);
|
||||||
display.println(F("bpm"));
|
display.println(F("bpm"));
|
||||||
} else {
|
} else {
|
||||||
if (outsValues[displayTab-1]>0) {
|
if (outsValues[displayTab-1]==0) {
|
||||||
|
display.print(F("OFF"));
|
||||||
|
} else if (outsValues[displayTab-1]>0) {
|
||||||
display.print(F("/"));
|
display.print(F("/"));
|
||||||
|
display.print(abs(outsValues[displayTab-1]));
|
||||||
} else {
|
} else {
|
||||||
display.print(F("x"));
|
display.print(F("x"));
|
||||||
|
display.print(abs(outsValues[displayTab-1]));
|
||||||
}
|
}
|
||||||
display.print(abs(outsValues[displayTab-1]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
display.display();
|
display.display();
|
||||||
|
|||||||
Reference in New Issue
Block a user