Some years ago I create two nice modular synths, but one thing what was really missing was an arpeggiator. Normally I used the sequencer of my drum machine to play the modular synths but with an arp you will have much more variance in your sound. The last weeks I found the time to create such an Arpeggiator and will share it now with you.
The arp is based on an arduino nano an SSD1306 OLED Display and MCP 4725 DAC.
Function Description:
Parameters:
Buttons and Potentiometer:
There are two buttons, with Button1 you can step through the Modes (Up, Up/Down ... ) and go through the sequence step by step. With Button2 you can go through the Parameters.
Arp Modes:
"Up", "Down", "UpDown", "Random Step", "Random Sequence"
With the adjustable parameters and the different arp mode you can set a lot of sound variation.
As Input is a Gate signal needed and the output is a simple Controlled Voltage Out (CV by MCP4725 Dac). The sequence starts with the gate signal will be start new with next gate signal, independent from the sequence status.
Please be aware, there is no Gate Output on the Frontpanel, I route it synth internal to an 4 fold distributer panel.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_MCP4725.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SSD1306_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_MCP4725 dac;
// 'Minart Modular final', 128x64px
const unsigned char image [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x10, 0x88, 0x80, 0x08, 0xc4, 0x13,
0x00, 0xff, 0xfc, 0xff, 0xef, 0xfe, 0xff, 0xff, 0xf7, 0xbc, 0xff, 0xf9, 0xbf, 0xff, 0x9f, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x00,
0x01, 0xc3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc7, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x01, 0xc0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x02, 0x00, 0x20, 0x07, 0x00,
0x02, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x63, 0xe9, 0x14, 0x40, 0x00, 0x00, 0x07, 0x00,
0x00, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0x83, 0x83, 0xfe, 0xfe, 0xc0, 0x00, 0x00, 0x06, 0x00,
0x00, 0xc0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x00,
0x01, 0xc0, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3b, 0x07, 0x00,
0x00, 0xc0, 0x3f, 0x04, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x03, 0x07, 0x00,
0x00, 0xc0, 0xfd, 0xde, 0x3f, 0x00, 0x03, 0x0e, 0x01, 0xf8, 0x07, 0x08, 0x3f, 0xfe, 0x05, 0x00,
0x00, 0xc1, 0x87, 0xff, 0xff, 0x87, 0x0f, 0xff, 0x83, 0xff, 0x1f, 0xbe, 0x7f, 0xf8, 0x07, 0x00,
0x00, 0xc1, 0xf3, 0xc7, 0xc7, 0x9f, 0x87, 0xef, 0xc7, 0x3f, 0x87, 0xde, 0x1e, 0x00, 0x07, 0x00,
0x00, 0xc0, 0xe3, 0xc7, 0xc7, 0x87, 0x87, 0xc3, 0xc0, 0x07, 0x87, 0x80, 0x0e, 0x00, 0x03, 0x00,
0x00, 0xc0, 0x03, 0xc7, 0xc7, 0x87, 0x87, 0xc7, 0xc0, 0x07, 0x87, 0xc0, 0x1f, 0x00, 0x07, 0x00,
0x01, 0xc0, 0x02, 0xc7, 0xc7, 0x87, 0x87, 0xc3, 0xc1, 0xfd, 0x87, 0xc0, 0x1f, 0x00, 0x06, 0x00,
0x00, 0xc0, 0x03, 0xc7, 0xc7, 0x87, 0x83, 0xc3, 0xc7, 0x87, 0x87, 0x80, 0x1f, 0x00, 0x07, 0x00,
0x01, 0xc0, 0x03, 0xc7, 0xc7, 0x87, 0x83, 0xc7, 0xcf, 0x07, 0x87, 0x80, 0x0f, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x03, 0x47, 0xc7, 0x87, 0x87, 0xc3, 0xcf, 0x87, 0x87, 0x80, 0x1e, 0x30, 0x07, 0x00,
0x00, 0xc0, 0x07, 0xe7, 0xce, 0xcf, 0xc7, 0xc7, 0xef, 0xff, 0xe7, 0xc0, 0x3f, 0xe0, 0x06, 0x00,
0x00, 0x00, 0x03, 0xc3, 0x07, 0x87, 0xc7, 0xc3, 0xc1, 0xe3, 0xc3, 0xc0, 0x0f, 0x80, 0x42, 0x00,
0x01, 0x00, 0x00, 0x80, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x01, 0xc0, 0x00, 0x31, 0x8e, 0x01, 0x01, 0x60, 0x00, 0x06, 0x02, 0x03, 0x10, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0xff, 0xff, 0x87, 0xc7, 0xfc, 0xe3, 0x8e, 0x0f, 0xc7, 0xfc, 0x00, 0x07, 0x00,
0x00, 0xe0, 0x00, 0x39, 0xc7, 0x39, 0xe3, 0x9c, 0xf3, 0x87, 0x19, 0xe3, 0x98, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x39, 0xe7, 0x30, 0xe3, 0x9c, 0x73, 0x87, 0x00, 0xe3, 0x80, 0x00, 0x06, 0x00,
0x00, 0xc0, 0x00, 0x39, 0xe7, 0x38, 0xe3, 0x9c, 0x73, 0x8e, 0x07, 0xe3, 0x80, 0x00, 0x07, 0x01,
0x00, 0xc0, 0x00, 0x39, 0xe7, 0x38, 0xe3, 0x9c, 0x73, 0x8e, 0x38, 0xe3, 0x80, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x39, 0xe7, 0x3c, 0xe3, 0x9c, 0x7f, 0x8e, 0x38, 0xe3, 0x80, 0x00, 0x06, 0x00,
0x00, 0x80, 0x00, 0x7d, 0xef, 0x9f, 0x8e, 0xf3, 0xff, 0xff, 0xbf, 0xf7, 0xe0, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x10, 0x01, 0x00, 0x00, 0x80, 0x20, 0x82, 0x08, 0x41, 0x80, 0x00, 0x06, 0x00,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc7, 0xc7, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00,
0x08, 0xc3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc7, 0x00,
0x00, 0xc3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x87, 0x00,
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
0x02, 0xfc, 0x48, 0x71, 0xb7, 0xfd, 0x42, 0x3d, 0x56, 0xa2, 0x9e, 0x5a, 0x9f, 0x87, 0xcf, 0x00,
0x00, 0x7f, 0xff, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xff, 0x9b, 0xff, 0xff, 0xff, 0x9f, 0xfe, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20
};
#define TASTER1_PIN 3
#define TASTER3_PIN 5
#define POTI_PIN A0
#define GATE_INPUT_PIN 2
#define GATE_OUTPUT_PIN 6
// Globale Variablen
struct Step {
int note; // Notenhöhe
int gateWidth; // Gate-Breite
};
Step sequence[8]; // Sequenz mit 8 festen Steps
int sequenceLength = 8;
int currentStep = 0; // Aktueller bearbeiteter Step
int tempo = 30; // Tempo in BPM
unsigned long lastStepTime = 0; // Zeit des letzten Steps
bool sequenceRunning = false; // Sequenz aktiv/inaktiv
bool lastGateState = false; // Zustand des letzten Gate-Signals
bool sequenceRestart = false; // Flag zum Neustarten der Sequenz bei neuem Gate
unsigned long lastPotUpdate = 0; // Zeit des letzten Potentiometer-Updates
const unsigned long potUpdateInterval = 200; // Mindestzeit zwischen Potentiometer-Updates (ms)
int parameterMode = 0; // 0: Tempo, 1: Note, 2: Gate
int lastPotValue = -1; // Initial auf -1 setzen, da es keinen gültigen Potentiometer-Wert gibt
const int potThreshold = 1; // Mindeständerung des Potentiometer-Werts
volatile bool gateTriggered = false; // Interrupt-gesteuertes Gate-Flag
bool randomEnabled = false; // Flag, ob Random-Modus aktiv ist
// Neue Modi
enum SequenceMode {
//FREE_MODE,
UP_MODE,
DOWN_MODE,
UP_DOWN_MODE,
RANDOM_STEP_MODE,
RANDOM_SEQ_MODE
};
SequenceMode currentMode = UP_MODE; // Standardmodus
// Liste harmonischer Noten
const int harmonicNotes[] = {48, 50, 52, 53, 55, 57, 59, 60}; // MIDI-Noten für C-Dur
const int harmonicNoteCount = sizeof(harmonicNotes) / sizeof(harmonicNotes[0]);
void setup() {
// Serial Monitor zur Debug-Ausgabe
Serial.begin(9600);
// Display initialisieren
if (!display.begin(SSD1306_ADDRESS, 0x3C)) {
while (true); // Anhalten, wenn das Display nicht initialisiert werden kann
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// 1. Bild anzeigen
display.drawBitmap(0, 0, image, 128, 64, WHITE);
display.display();
delay(2000);
// Text anzeigen
display.clearDisplay(); // Anzeige aktualisieren
display.setCursor(0, 10);
display.print(F("Arpeggiator"));
display.setCursor(0, 20); // Weitere 10 Pixel nach unten
display.print(F("Version: arp_3.6"));
display.display(); // Anzeige aktualisieren
delay(2000); // Begrüßungstext für 2 Sekunden anzeigen
// DAC initialisieren
if (!dac.begin(0x60)) {
while (true); // Anhalten, wenn der DAC nicht initialisiert werden kann
}
// Pins konfigurieren
pinMode(TASTER1_PIN, INPUT_PULLUP);
pinMode(TASTER3_PIN, INPUT_PULLUP);
pinMode(GATE_INPUT_PIN, INPUT);
pinMode(GATE_OUTPUT_PIN, OUTPUT);
digitalWrite(GATE_OUTPUT_PIN, LOW);
// Interrupt für das Gate-Signal
attachInterrupt(digitalPinToInterrupt(GATE_INPUT_PIN), handleGateInterrupt, RISING);
// Sequenz initialisieren mit mitteltiefer Acid-Bassline
sequence[0] = {58, 220};
sequence[1] = {42, 170};
sequence[2] = {53, 100};
sequence[3] = {46, 90};
sequence[4] = {57, 170};
sequence[5] = {46, 120};
sequence[6] = {42, 90};
sequence[7] = {43, 160};
drawSequence();
}
void handleGateInterrupt() {
gateTriggered = true;
if (currentMode == UP_DOWN_MODE) {
sequenceRunning = true;
}
}
void loop() {
bool taster1 = digitalRead(TASTER1_PIN) == LOW;
bool taster3 = digitalRead(TASTER3_PIN) == LOW;
// Gate-Signal starten und Sequenz neu starten, wenn nötig
if (gateTriggered) {
gateTriggered = false;
sequenceRunning = true;
sequenceRestart = true; // Signal, dass die Sequenz neu gestartet werden soll
lastStepTime = millis();
}
// Navigation zwischen Steps oder Modi umschalten
if (taster1 && parameterMode == 0) {
currentMode = static_cast<SequenceMode>((currentMode + 1) % 5); // Modi durchschalten
drawSequence();
delay(200); // Entprellen
} else if (taster1) {
currentStep = (currentStep + 1) % sequenceLength;
drawSequence();
delay(200); // Entprellen
}
// Wechsel zwischen Parameter-Modi: Tempo, Note, Gate
if (taster3) {
parameterMode = (parameterMode + 1) % 3; // Umschalten zwischen 0, 1, 2
drawSequence();
delay(200); // Entprellen
}
// Potentiometer-Werte abhängig vom Modus anpassen
unsigned long currentTime = millis();
if (currentTime - lastPotUpdate >= potUpdateInterval) {
int potValue = analogRead(POTI_PIN);
// Prüfen, ob sich der Potentiometer-Wert signifikant geändert hat
if (lastPotValue == -1 || abs(potValue - lastPotValue) > potThreshold) {
lastPotValue = potValue; // Aktuellen Wert als Referenz speichern
if (parameterMode == 0) {
tempo = map(potValue, 0, 1023, 10, 60); // Tempo anpassen
} else if (parameterMode == 1) {
sequence[currentStep].note = map(potValue, 0, 1023, 36, 62); // Notenhöhe anpassen (MIDI 36–84)
} else if (parameterMode == 2) {
sequence[currentStep].gateWidth = map(potValue, 0, 1023, 50, 240); // Gate-Breite anpassen
}
drawSequence(); // Änderungen im Display anzeigen
} else {
// Display aktualisieren, um andere Statusinformationen anzuzeigen
drawSequence();
}
lastPotUpdate = currentTime; // Zeit des letzten Updates speichern
}
// Sequenz abspielen, wenn aktiv
if (sequenceRunning) {
playSequence();
}
}
void drawSequence() {
display.clearDisplay();
int stepWidth = SCREEN_WIDTH / sequenceLength;
for (int i = 0; i < sequenceLength; i++) {
int x = i * stepWidth;
int barHeight = map(sequence[i].note, 36, 84, 0, SCREEN_HEIGHT);
int barWidth = map(sequence[i].gateWidth, 50, 240, 2, stepWidth);
if (i == currentStep) {
display.fillRect(x, SCREEN_HEIGHT - barHeight, barWidth, barHeight, SSD1306_WHITE);
} else {
display.drawRect(x, SCREEN_HEIGHT - barHeight, barWidth, barHeight, SSD1306_WHITE);
}
}
// Aktueller Modus und Parameter anzeigen
display.setCursor(0, 0);
display.setTextSize(2); // Setze größere Textgröße (z.B. 2)
display.setTextColor(SSD1306_WHITE);
if (parameterMode == 0) {
display.print(F("Tempo: "));
display.print(tempo);
display.setCursor(0, 18); // Unterhalb von Tempo anzeigen
display.setTextSize(1);
switch (currentMode) {
// case FREE_MODE: display.print(F("Mode: FREE")); break;
case RANDOM_SEQ_MODE: display.print(F("RANDOM SEQ")); break;
case UP_MODE: display.print(F("UP")); break;
case DOWN_MODE: display.print(F("DOWN")); break;
case UP_DOWN_MODE: display.print(F("UP/DOWN")); break;
case RANDOM_STEP_MODE: display.print(F("RANDOM STEP")); break;
}
} else if (parameterMode == 1) {
display.setTextSize(2);
display.print(F("Note: "));
display.setCursor(60, 0);
display.print(sequence[currentStep].note);
} else if (parameterMode == 2) {
display.setTextSize(2);
display.print(F("Gate: "));
display.setCursor(60, 0);
display.print(sequence[currentStep].gateWidth);
}
display.setTextSize(1);
display.display();
}
void playSequence() {
unsigned long stepInterval = 60000 / tempo / sequenceLength; // Schrittintervall basierend auf Tempo
static bool upDirection = true; // Für den UP_DOWN_MODE
static int stepsRemaining = 0; // Schritte bis zum Stopp im UP_DOWN_MODE
if (sequenceRestart) {
currentStep = (currentMode == DOWN_MODE) ? sequenceLength - 1 : 0; // Startpunkt abhängig vom Modus
sequenceRestart = false;
stepsRemaining = (currentMode == UP_DOWN_MODE) ? 2 * sequenceLength - 2 : 0; // Hin- und Rücklauf initialisieren
if (currentMode == RANDOM_SEQ_MODE) { // Random-Modus aktiv
for (int i = 0; i < sequenceLength; i++) {
sequence[i].note = harmonicNotes[random(0, harmonicNoteCount)]; // Zufällige Note aus der Liste
sequence[i].gateWidth = random(50, 240); // Zufällige Gate-Breite im Bereich 50–150 ms
}
}
}
if (millis() - lastStepTime >= stepInterval) {
lastStepTime = millis();
Step step = sequence[currentStep];
if (step.note != 36) { // Nur Gate ausgeben, wenn Note nicht 36 ist
int dacValue = map(step.note, 36, 84, 0, 4095);
dac.setVoltage(dacValue, false);
digitalWrite(GATE_OUTPUT_PIN, HIGH);
delay(step.gateWidth); // Gate an für die eingestellte Dauer
digitalWrite(GATE_OUTPUT_PIN, LOW);
}
// UP_MODE logic
if (currentMode == UP_MODE) {
currentStep++;
if (currentStep >= sequenceLength) {
sequenceRunning = false; // Sequenz beenden nach 8 Schritten
currentStep = 0;
}
// DOWN_MODE logic
} else if (currentMode == DOWN_MODE) {
currentStep--;
if (currentStep < 0) {
sequenceRunning = false; // Sequenz beenden nach 8 Schritten
currentStep = sequenceLength - 1; // Zurück zum letzten Schritt
}
// UP_DOWN_MODE logic
} else if (currentMode == UP_DOWN_MODE) {
if (stepsRemaining > 0) {
if (gateTriggered) {
gateTriggered = false; // Reagiere sofort auf ein neues Gate
upDirection = !upDirection; // Richtung wechseln
// Schritte basierend auf aktueller Position neu berechnen
stepsRemaining = upDirection
? (sequenceLength - 1 - currentStep) + currentStep
: currentStep + (sequenceLength - 1 - currentStep);
}
if (upDirection) {
if (currentStep < sequenceLength - 1) {
currentStep++;
} else {
upDirection = false; // Richtung wechseln am Ende
currentStep--; // Direkt zum vorherigen Schritt
}
} else {
if (currentStep > 0) {
currentStep--;
} else {
upDirection = true; // Richtung wechseln am Anfang
currentStep++; // Direkt zum nächsten Schritt
}
}
stepsRemaining--;
}
if (stepsRemaining <= 0) {
if (!gateTriggered) {
sequenceRunning = false; // Sequenz endgültig stoppen, wenn kein Gate kommt
} else {
gateTriggered = false; // Neues Gate-Flag zurücksetzen
stepsRemaining = 2 * sequenceLength - 2; // Neues Hin- und Rücklaufintervall
}
}
// RANDOM_STEP_MODE logic
} else if (currentMode == RANDOM_STEP_MODE) {
if (sequenceRestart || stepsRemaining <= 0) {
sequenceRestart = false;
stepsRemaining = 8; // Stelle sicher, dass 8 zufällige Schritte ausgeführt werden
}
if (stepsRemaining > 0) {
currentStep = random(0, sequenceLength); // Zufälligen Schritt auswählen
Step step = sequence[currentStep];
if (step.note != 36) { // Nur Gate ausgeben, wenn Note nicht 36 ist
int dacValue = map(step.note, 36, 84, 0, 4095);
dac.setVoltage(dacValue, false);
digitalWrite(GATE_OUTPUT_PIN, HIGH);
//delay(step.gateWidth);
//delay(100);// Gate an für die eingestellte Dauer
digitalWrite(GATE_OUTPUT_PIN, LOW);
}
stepsRemaining--;
if (stepsRemaining <= 0) {
sequenceRunning = false; // Beenden nach genau 8 zufälligen Schritten
}
}
// RANDOM_SEQ_MODE logic
} else if (currentMode == RANDOM_SEQ_MODE) {
currentStep++;
if (currentStep >= sequenceLength) {
sequenceRunning = false; // Sequenz beenden nach 8 Schritten im Random-Modus
currentStep = 0; // Zurücksetzen auf den Anfang
}
}
}
}
Diese Webseite wurde mit Jimdo erstellt! Jetzt kostenlos registrieren auf https://de.jimdo.com