Hey ya'll,
I'm trying to program a drumsynth with a euclidean synthesizer. I'm using an OLED and four potis. While those work fine I'm having a hard time wrapping my head around the mozzi metronome. I don't get how start(), ready() and stop() are connected. It seems really easy: the time given to start() is over -> ready() gets called. There is no documentation about stop(), so i don't get what this one does.
I'm trying to have a little indicator showing me the active step. From this point i hope i'll be able to add sounds to the whole thing. Here is the complete code (yeah, i know there's loads of things to optimize
)
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
#include <MozziGuts.h>
#include <Oscil.h>
#include <Metronome.h>
#define OLED_RESET 4
Adafruit_SH1106 display(OLED_RESET);
#if (SH1106_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SH1106.h!");
#endif
#define CONTROL_RATE 128
Metronome metro(1000);
int leftBorder = 0;
int rightBorder = display.width();
int upperBorder = 0;
int lowerBorder = display.height();
int vertLine = 81;
int thick = 2;
int chHeight = 9;
int counterHeight = 4;
int fullHeight = thick + chHeight + counterHeight + 1;
int fillSize = 4;
int bpm = 120;
int speed = 500;
int len = 1;
int step = 1;
int shift = 1;
int bpmOld = bpm;
int lenOld = len;
int stepOld = step;
int shiftOld = shift;
int i = 0;
int j = 0;
int k = 0;
int beat[8];
int counter = 0;
void setup() {
startMozzi(CONTROL_RATE);
adcDisconnectAllDigitalIns();
Serial.begin(9600);
Serial.println("Starting Setup...");
pinMode(18, OUTPUT);
pinMode(19, OUTPUT);
pinMode(PCINT16, INPUT);
pinMode(PCINT17, INPUT);
pinMode(PCINT18, INPUT);
pinMode(PCINT19, INPUT);
display.begin(SH1106_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.fillScreen(1);
fillChan();
display.fillRect(vertLine + 10, 1, rightBorder - vertLine - 11, lowerBorder - 2, 0);
display.drawChar(vertLine + 12, 5, 0x0D, 1, 0, 1);
display.drawChar(vertLine + 12, 5 + fullHeight, 0x53, 1, 0, 1);
display.drawChar(vertLine + 12, 5 + fullHeight * 2, 0x46, 1, 0, 1);
display.drawChar(vertLine + 12, 5 + fullHeight * 3, 0x52, 1, 0, 1);
display.setTextColor(1);
display.setTextSize(1);
display.setTextWrap(false);
display.display();
metro.set(speed);
Serial.println("Setup done!");
}
void updateControl() {
calc();
metro.start(speed);
if (bpmOld != bpm) {
display.setCursor(vertLine + 20, 5);
display.fillRect(vertLine + 18, 5, 20, 7, 0);
display.print(bpm);
display.display();
}
if (lenOld != len) {
display.setCursor(vertLine + 20, 21);
display.fillRect(vertLine + 18, 21, 20, 7, 0);
display.print(len);
}
if (stepOld != step) {
display.setCursor(vertLine + 20, 37);
display.fillRect(vertLine + 18, 37, 20, 7, 0);
display.print(step);
}
if (shiftOld != shift) {
display.setCursor(vertLine + 20, 53);
display.fillRect(vertLine + 18, 53, 20, 7, 0);
display.print(shift);
}
int beatP[len];
if (lenOld != len || stepOld != step || shiftOld != shift) {
Serial.println("Beatchange");
fillBeat(beatP, len, step, shift);
fillChan();
for (int i = 0; i < len; i++) {
int beatPos = beatP[(len - shift + i) % len];
display.fillRect(10 + i * (fillSize + 1), 2, fillSize, 7, 0);
if (beatPos == 1) {
display.fillRect(10 + i * (fillSize + 1), 2, fillSize, 7, 1);
display.display();
} else {
display.drawLine(10 + i * (fillSize + 1), 5, 13 + i * (fillSize + 1), 5, 1);
display.display();
}
}
}
if (metro.ready()) {
display.drawRect(11 + counter * 5, chHeight + 3, 2, 2, 0);
counter++;
Serial.println(counter);
display.drawRect(11 + counter * 5, chHeight + 3, 2, 2, 1);
display.display();
if (counter == len) { counter = 0; }
}
//metro.stop();
}
AudioOutput_t updateAudio() {
}
void loop() {
audioHook();
}
void calc() {
bpmOld = bpm;
lenOld = len;
stepOld = step;
shiftOld = shift;
bpm = mozziAnalogRead(PCINT16) / 4.4 + 33;
speed = (60000 / bpm);
len = mozziAnalogRead(PCINT17) / 64 + 1;
step = ((mozziAnalogRead(PCINT18) / 64) * len / 16) + 1;
shift = (mozziAnalogRead(PCINT19) / 64) * len / 16;
// Serial.print(mozziAnalogRead(PCINT16));
// Serial.print(" - ");
// Serial.println(bpm);
// Serial.print(mozziAnalogRead(PCINT17));
// Serial.print(" - ");
// Serial.println(len);
// Serial.print(mozziAnalogRead(PCINT18));
// Serial.print(" - ");
// Serial.println(step);
// Serial.print(mozziAnalogRead(PCINT19));
// Serial.print(" - ");
// Serial.println(shift);
return speed, len, step, shift;
}
int fillBeat(int beat[], int len, int step, int shift) {
k = (-1 * step) % len;
for (int i = 0; i < len; i++) {
k = j;
j = (i * step) % len;
if (j > k) beat[i] = 0;
else if (j <= k) beat[i] = 1;
}
}
void fillChan() {
for (i = 0; i < 4; i++) {
//Channel Rectangle
display.fillRect(1, 1 + i * (fullHeight), 7, 14, 0);
//Sequencer Rectangle
display.fillRect(9, 1 + i * (fullHeight), vertLine, chHeight, 0);
//Counter Rectangle
display.fillRect(9, 1 + chHeight + 1 + i * (fullHeight), vertLine, counterHeight, 0);
//Channel Number
display.drawChar(2, 5 + 16 * i, 0x31 + i, 1, 0, 1);
}
}
Mozzis updateControl() is supposed to check if pots are turned. If they are, the corresponding part of the display is updated with the new value. After that, the new beat is calculated and projected in the corresponding channel. Only channel 1 is working for now, because i wanted to finish one before replicating everything for the other ones. But this part works fine for now. What i'm talking about is the following part:
calc();
metro.start(speed);
//code for display
if (metro.ready()) {
display.drawRect(11 + counter * 5, chHeight + 3, 2, 2, 0);
counter++;
Serial.println(counter);
display.drawRect(11 + counter * 5, chHeight + 3, 2, 2, 1);
display.display();
if (counter == len) { counter = 0; }
}
So this is supposed to happen here: calc(), among other things, is calculating the speed (in ms) from the potis position. This value is used in metro.start() for the "note length". Now I was expecting the program to go into the if condition as soon as metro hits the note length, delete the existing indicator (i know there is no first one), add 1 to counter, draw the indicator for the next step and continue to to that until counter hits length (the lenght of the beat, also calculated in calc()), then start from the first step. But for some reason the if conditional is only running once.
Any ideas why?
edit: btw, you need to rename mozzis twi_nonblock.cpp to make it work with the OLED library. Took me much too long to find that out.