HAGIWO MOD1用にプログラミングしたデュアルユークリッド・シーケンサーです。
主にサンプラーのスネア・クローズハイハット&オープンハイハットの組み合わせに適したセッティングです。
1つ目のシーケンサーは16ステップで固定されており、POT1でトリガー回数を設定します。ステップはシフトレジストしており、1周目は5ステップ目から有効になります。
2つ目のシーケンサーも16ステップで固定されており、POT2でトリガー回数を設定します。また、POT3はランダムコイントスで、生成したユークリィアンパターンを、さらに確率的に2つの出力に振り分けます。こちらは1ステップ目から有効です。
1つ目のシーケンサーをスネアに、2つ目のシーケンサーの出力をCLOSE/OPENハイハットに振り分けることで、有機的でランダムなドラムパターンを生成できます。
注意事項:chatGPTで作成したプロンプトです。プログラミング知識は一切ないため、動作の安定性は保証はできません。趣味用途でお使いください
[機能紹介]
※入力したクロックをもとに、リズムパターンを生成する
※トリガー長は5msで設定しています。トリガー長は delayMicroseconds(5000); の箇所で変更可能です。(5ms=5000)
POT1:出力1のユークリディアンパターンが使用するトリガー数を設定します。
POT2:出力2のユークリディアンパターンが使用するトリガー数を設定します。
POT3:出力2で設定したユークリディアンパターンを、確率でD10pin、D11pinに振り分けます。中間でおよそ50:50、最小にすると常にD10pinから出力され、最大にすると常にD11pinから出力されます
F1:トリガーIN
F2:出力1のトリガー出力
F3:出力2のトリガー出力1
F4:出力2のトリガー出力2
LED:F1に連動する
[プログラム](ArduinoでMOD1にプログラミングしてください)
// 2-output Euclidean sequencer with probabilistic branching like Mutable Instruments Branches
// Now includes 4-step delay on Output 1 using an 8-bit shift register emulation
const int triggerInputPin = 17;
const int buttonPin = 2;
const int ledPin = 3;
const int out1Pin = 9;
const int out2aPin = 10;
const int out2bPin = 11;
const int knob1Pin = A0;
const int knob2Pin = A1;
const int probKnobPin = A2;
const int numSteps = 16;
bool pattern1[numSteps];
bool pattern2[numSteps];
int currentStep = 0;
unsigned long lastClockTime = 0;
bool internalClock = false;
unsigned long lastTapTime = 0;
unsigned long bpmInterval = 0;
bool lastButtonState = HIGH;
bool lastTriggerState = LOW;
unsigned long lastTriggerReceived = 0;
const unsigned long triggerTimeout = 300;
// — 8-bit shift register for delayed output1 —
const int shiftSize = 8;
bool shiftRegister[shiftSize] = {false}; // stores pattern1 history
int shiftIndex = 0;
// — Functions —
void generateEuclideanPattern(bool* pattern, int pulses) {
for (int i = 0; i < numSteps; i++) {
pattern[i] = (i * pulses) % numSteps < pulses;
}
}
void sendTrigger(int pin) {
digitalWrite(pin, HIGH);
delayMicroseconds(5000);
digitalWrite(pin, LOW);
}
int readKnobSteps(int analogPin) {
int raw = analogRead(analogPin);
int step = raw / (1024 / (numSteps + 1));
if (step > numSteps) step = numSteps;
return step;
}
float readProbability() {
return analogRead(probKnobPin) / 1023.0;
}
void setup() {
pinMode(triggerInputPin, INPUT);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
pinMode(out1Pin, OUTPUT);
pinMode(out2aPin, OUTPUT);
pinMode(out2bPin, OUTPUT);
generateEuclideanPattern(pattern1, 0);
generateEuclideanPattern(pattern2, 0);
randomSeed(analogRead(A3));
lastTriggerState = digitalRead(triggerInputPin);
lastTriggerReceived = millis();
}
bool checkClock() {
bool triggered = false;
bool currentTrigger = digitalRead(triggerInputPin);
unsigned long now = millis();
if (currentTrigger && !lastTriggerState) {
if (now – lastTriggerReceived > triggerTimeout) {
currentStep = 0;
}
lastTriggerReceived = now;
lastClockTime = now;
internalClock = false;
triggered = true;
}
lastTriggerState = currentTrigger;
if (internalClock && bpmInterval > 0 && now – lastClockTime >= bpmInterval) {
lastClockTime = now;
triggered = true;
}
return triggered;
}
void updateTapTempo() {
bool currentButton = digitalRead(buttonPin);
if (!currentButton && lastButtonState) {
unsigned long now = millis();
if (lastTapTime > 0) {
bpmInterval = now – lastTapTime;
internalClock = true;
}
lastTapTime = now;
}
lastButtonState = currentButton;
}
void loop() {
updateTapTempo();
if (checkClock()) {
digitalWrite(ledPin, HIGH);
delayMicroseconds(1000);
digitalWrite(ledPin, LOW);
int steps1 = readKnobSteps(knob1Pin);
int steps2 = readKnobSteps(knob2Pin);
generateEuclideanPattern(pattern1, steps1);
generateEuclideanPattern(pattern2, steps2);
// — Store current pattern1 state into shift register —
shiftRegister[shiftIndex] = pattern1[currentStep];
// — Calculate delayed index (4 steps behind current) —
int delayedIndex = (shiftIndex + shiftSize – 4) % shiftSize;
if (shiftRegister[delayedIndex]) {
sendTrigger(out1Pin); // delayed output
}
// — Normal Output 2 with branching —
if (pattern2[currentStep]) {
float prob = readProbability();
if (random(0, 1000) < prob * 1000.0) {
sendTrigger(out2bPin);
} else {
sendTrigger(out2aPin);
}
}
// — Advance step and shift index —
currentStep = (currentStep + 1) % numSteps;
shiftIndex = (shiftIndex + 1) % shiftSize;
}
}