mirror of
https://github.com/erik-toth/audio-synth.git
synced 2026-03-12 13:17:42 +00:00
Software Update 4: Sequencer Block
Sequencer Klasse eingebaut Überprüfung noch ausständig
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
/*
|
||||
* Example Code Two
|
||||
* Example Code Three
|
||||
* with Sequencer
|
||||
*
|
||||
* Bedienung:
|
||||
* - Keyboard-Tasten: CV-Ausgabe direkt oder Recording
|
||||
* - PIN_SB_1_REC: Sequencer 1 Record Start/Stop
|
||||
* - PIN_SB_1_PLAY: Sequencer 1 Play/Stop
|
||||
* - PIN_SB_2_REC: Sequencer 2 Record Start/Stop
|
||||
* - PIN_SB_2_PLAY: Sequencer 2 Play/Stop
|
||||
*/
|
||||
#include "FIRMWARE_DEF.h"
|
||||
#include "FIRMWARE.h"
|
||||
@@ -11,7 +19,7 @@ Keyboard keyboard(N_KEYBOARD_ROW, N_KEYBOARD_COL, pins_keyboard_row, pins_keyboa
|
||||
|
||||
Adafruit_MCP4728 MCP4728;
|
||||
MCP4728_channel_t cvMap[N_CV_GATES] = {MCP4728_CHANNEL_A, MCP4728_CHANNEL_B};
|
||||
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = {
|
||||
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = { /* 83mV = 1/12V */
|
||||
1*83, 5*83, 9*83,
|
||||
2*83, 6*83, 10*83,
|
||||
3*83, 7*83, 11*83,
|
||||
@@ -20,41 +28,251 @@ uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = {
|
||||
|
||||
CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL);
|
||||
|
||||
SequencerBlock sb1(30000, 250); // 30 Sekunden max, 250ms Timeout
|
||||
SequencerBlock sb2(30000, 250);
|
||||
|
||||
// Button States
|
||||
struct ButtonState {
|
||||
bool current;
|
||||
bool last;
|
||||
unsigned long lastDebounceTime;
|
||||
};
|
||||
|
||||
ButtonState btn_sb1_rec;
|
||||
ButtonState btn_sb1_play;
|
||||
ButtonState btn_sb2_rec;
|
||||
ButtonState btn_sb2_play;
|
||||
|
||||
const unsigned long DEBOUNCE_DELAY = 50;
|
||||
|
||||
// Hilfsfunktion zum Lesen eines Buttons mit Debouncing
|
||||
bool readButton(byte pin, ButtonState &state)
|
||||
{
|
||||
bool reading = digitalRead(pin) == LOW; // LOW = gedrückt (mit Pull-Up)
|
||||
bool buttonPressed = false;
|
||||
|
||||
if(reading != state.last)
|
||||
{
|
||||
state.lastDebounceTime = millis();
|
||||
}
|
||||
|
||||
if((millis() - state.lastDebounceTime) > DEBOUNCE_DELAY)
|
||||
{
|
||||
if(reading != state.current)
|
||||
{
|
||||
state.current = reading;
|
||||
if(state.current == true) // Button wurde gerade gedrückt
|
||||
{
|
||||
buttonPressed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.last = reading;
|
||||
return buttonPressed;
|
||||
}
|
||||
|
||||
void initButtons()
|
||||
{
|
||||
pinMode(PIN_SB_1_REC, INPUT_PULLUP);
|
||||
pinMode(PIN_SB_1_PLAY, INPUT_PULLUP);
|
||||
pinMode(PIN_SB_2_REC, INPUT_PULLUP);
|
||||
pinMode(PIN_SB_2_PLAY, INPUT_PULLUP);
|
||||
|
||||
btn_sb1_rec.current = false;
|
||||
btn_sb1_rec.last = false;
|
||||
btn_sb1_rec.lastDebounceTime = 0;
|
||||
|
||||
btn_sb1_play.current = false;
|
||||
btn_sb1_play.last = false;
|
||||
btn_sb1_play.lastDebounceTime = 0;
|
||||
|
||||
btn_sb2_rec.current = false;
|
||||
btn_sb2_rec.last = false;
|
||||
btn_sb2_rec.lastDebounceTime = 0;
|
||||
|
||||
btn_sb2_play.current = false;
|
||||
btn_sb2_play.last = false;
|
||||
btn_sb2_play.lastDebounceTime = 0;
|
||||
}
|
||||
|
||||
void handleSequencerButtons()
|
||||
{
|
||||
// Sequencer 1 Record Button
|
||||
if(readButton(PIN_SB_1_REC, btn_sb1_rec))
|
||||
{
|
||||
if(sb1.isRecording())
|
||||
{
|
||||
sb1.stopRecord();
|
||||
Serial.printf("\n\r[SEQ1] Recording stopped. Steps: %i, Duration: %ims",
|
||||
sb1.getStepCount(), sb1.getTotalDuration());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sb1.isPlaying()) sb1.stopPlay();
|
||||
sb1.startRecord();
|
||||
Serial.printf("\n\r[SEQ1] Recording started...");
|
||||
}
|
||||
}
|
||||
|
||||
// Sequencer 1 Play Button
|
||||
if(readButton(PIN_SB_1_PLAY, btn_sb1_play))
|
||||
{
|
||||
if(sb1.isPlaying())
|
||||
{
|
||||
sb1.stopPlay();
|
||||
Serial.printf("\n\r[SEQ1] Playback stopped");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sb1.isRecording()) sb1.stopRecord();
|
||||
sb1.startPlay();
|
||||
Serial.printf("\n\r[SEQ1] Playback started");
|
||||
}
|
||||
}
|
||||
|
||||
// Sequencer 2 Record Button
|
||||
if(readButton(PIN_SB_2_REC, btn_sb2_rec))
|
||||
{
|
||||
if(sb2.isRecording())
|
||||
{
|
||||
sb2.stopRecord();
|
||||
Serial.printf("\n\r[SEQ2] Recording stopped. Steps: %i, Duration: %ims",
|
||||
sb2.getStepCount(), sb2.getTotalDuration());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sb2.isPlaying()) sb2.stopPlay();
|
||||
sb2.startRecord();
|
||||
Serial.printf("\n\r[SEQ2] Recording started...");
|
||||
}
|
||||
}
|
||||
|
||||
// Sequencer 2 Play Button
|
||||
if(readButton(PIN_SB_2_PLAY, btn_sb2_play))
|
||||
{
|
||||
if(sb2.isPlaying())
|
||||
{
|
||||
sb2.stopPlay();
|
||||
Serial.printf("\n\r[SEQ2] Playback stopped");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sb2.isRecording()) sb2.stopRecord();
|
||||
sb2.startPlay();
|
||||
Serial.printf("\n\r[SEQ2] Playback started");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUDRATE);
|
||||
keyboard.begin();
|
||||
cv.begin(PIN_SDA, PIN_SCL);
|
||||
Serial.begin(BAUDRATE);
|
||||
keyboard.begin();
|
||||
cv.begin(PIN_SDA, PIN_SCL);
|
||||
initButtons();
|
||||
|
||||
sb1.setLoop(false);
|
||||
sb2.setLoop(false);
|
||||
|
||||
Serial.printf("\n\r=== Sequencer System Started ===");
|
||||
Serial.printf("\n\rControls:");
|
||||
Serial.printf("\n\r PIN_SB_1_REC: SEQ1 Record Start/Stop");
|
||||
Serial.printf("\n\r PIN_SB_1_PLAY: SEQ1 Play/Stop");
|
||||
Serial.printf("\n\r PIN_SB_2_REC: SEQ2 Record Start/Stop");
|
||||
Serial.printf("\n\r PIN_SB_2_PLAY: SEQ2 Play/Stop");
|
||||
Serial.printf("\n\r================================\n\r");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
keyboard.update();
|
||||
|
||||
int n = keyboard.getQueueLength();
|
||||
|
||||
if(n > 0)
|
||||
{
|
||||
Serial.printf("\n\rCurrent queue length: %i", n);
|
||||
if(n == 1)
|
||||
keyboard.update();
|
||||
handleSequencerButtons();
|
||||
|
||||
// Sequencer Update (für Wiedergabe)
|
||||
sb1.update();
|
||||
sb2.update();
|
||||
|
||||
int n = keyboard.getQueueLength();
|
||||
|
||||
// Keyboard-Tasten verarbeiten
|
||||
if(n > 0)
|
||||
{
|
||||
cv.setVoltage(0, keyboard.getQueue(0));
|
||||
cv.setVoltage(1, NOT_A_KEY);
|
||||
// Alle Keyboard-Tasten für CV-Ausgabe verwenden
|
||||
int cvIndex = 0;
|
||||
for(int i = 0; i < n && cvIndex < N_CV_GATES; i++)
|
||||
{
|
||||
Key k = keyboard.getQueue(i);
|
||||
if(!isNotKey(k))
|
||||
{
|
||||
uint16_t voltage = keyToVoltage[k.row * N_KEYBOARD_COL + k.col];
|
||||
|
||||
// Bei Recording: Spannung aufnehmen
|
||||
if(sb1.isRecording())
|
||||
{
|
||||
sb1.addStep(voltage);
|
||||
}
|
||||
if(sb2.isRecording())
|
||||
{
|
||||
sb2.addStep(voltage);
|
||||
}
|
||||
|
||||
// Live-Ausgabe nur wenn nicht gerade wiedergegeben wird
|
||||
if(!sb1.isPlaying() && !sb2.isPlaying())
|
||||
{
|
||||
cv.setVoltage(cvIndex++, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restliche CV-Ausgänge auf 0 setzen wenn live gespielt wird
|
||||
if(!sb1.isPlaying() && !sb2.isPlaying())
|
||||
{
|
||||
for(int i = cvIndex; i < N_CV_GATES; i++)
|
||||
{
|
||||
cv.setVoltage(i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(n >= 2)
|
||||
else
|
||||
{
|
||||
cv.setVoltage(0, keyboard.getQueue(0));
|
||||
cv.setVoltage(1, keyboard.getQueue(1));
|
||||
// Keine Tasten gedrückt
|
||||
if(sb1.isRecording())
|
||||
{
|
||||
sb1.addStep(0);
|
||||
}
|
||||
if(sb2.isRecording())
|
||||
{
|
||||
sb2.addStep(0);
|
||||
}
|
||||
|
||||
if(!sb1.isPlaying() && !sb2.isPlaying())
|
||||
{
|
||||
cv.clearAll();
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; (i < N_CV_GATES) && (i < n); i++)
|
||||
|
||||
// Sequencer-Wiedergabe auf CV-Ausgänge
|
||||
if(sb1.isPlaying())
|
||||
{
|
||||
Key k = keyboard.getQueue(i);
|
||||
if(isNotKey(k)) Serial.printf("\n\rQueue position %i: NOT A KEY", i);
|
||||
else Serial.printf("\n\rQueue position %i: R%iC%i", i, k.row, k.col);
|
||||
cv.setVoltage(0, sb1.getCurrentVoltage());
|
||||
}
|
||||
}
|
||||
else cv.clearAll();
|
||||
|
||||
delay(50);
|
||||
if(sb2.isPlaying())
|
||||
{
|
||||
cv.setVoltage(1, sb2.getCurrentVoltage());
|
||||
}
|
||||
|
||||
// Time-Limit Warnung
|
||||
if(sb1.isRecording() && sb1.timeLimitReached())
|
||||
{
|
||||
sb1.stopRecord();
|
||||
Serial.printf("\n\r[SEQ1] Time limit reached! Recording stopped.");
|
||||
}
|
||||
if(sb2.isRecording() && sb2.timeLimitReached())
|
||||
{
|
||||
sb2.stopRecord();
|
||||
Serial.printf("\n\r[SEQ2] Time limit reached! Recording stopped.");
|
||||
}
|
||||
|
||||
delay(10); // Kürzeres Delay für bessere Sequencer-Auflösung
|
||||
}
|
||||
Reference in New Issue
Block a user