mirror of
https://github.com/erik-toth/audio-synth.git
synced 2025-12-06 20:40:01 +00:00
Impplemenation of EN-Pins for CV-Gates, Metronome
This commit is contained in:
Binary file not shown.
BIN
dev/digital/ESP32-S3/History/ESP32-S3.~(23).SchDoc.Zip
Normal file
BIN
dev/digital/ESP32-S3/History/ESP32-S3.~(23).SchDoc.Zip
Normal file
Binary file not shown.
BIN
dev/digital/ESP32-S3/History/ESP32-S3.~(24).SchDoc.Zip
Normal file
BIN
dev/digital/ESP32-S3/History/ESP32-S3.~(24).SchDoc.Zip
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
@contact: etoth@tsn.at
|
||||
@date: 2025-10-26
|
||||
@updated: 2025-12-06
|
||||
@brief: Header for FIRMWARE.cpp (FIXED)
|
||||
@brief: Header for FIRMWARE.cpp (FIXED VERSION)
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
@@ -30,6 +30,7 @@ struct DualVoltageDurationPair
|
||||
uint16_t voltage_ch1;
|
||||
uint16_t voltage_ch2;
|
||||
uint16_t duration;
|
||||
bool active; // NEU: true wenn Step aktive Noten hat, false für Pausen
|
||||
};
|
||||
|
||||
const Key NOT_A_KEY = {-1, -1};
|
||||
@@ -117,6 +118,7 @@ class SequencerBlock
|
||||
uint16_t getStepCount();
|
||||
uint16_t getCurrentVoltageCh1();
|
||||
uint16_t getCurrentVoltageCh2();
|
||||
bool isCurrentStepActive(); // NEU: Prüft ob aktueller Step aktive Noten hat
|
||||
uint16_t getTotalDuration();
|
||||
|
||||
private:
|
||||
@@ -124,7 +126,7 @@ class SequencerBlock
|
||||
* @brief Memory limiting
|
||||
* @return (uint16_t) 1024
|
||||
* @attention Increasing the value might lead to an overflow
|
||||
* @note sizeOf(DualVoltageDurationPair) = 6 Byte ==> 6 Byte * 1024 = 6144 Byte
|
||||
* @note sizeOf(DualVoltageDurationPair) = 8 Byte ==> 8 Byte * 1024 = 8192 Byte
|
||||
*/
|
||||
const static uint16_t _MAX_SEQUENCE_STEPS = 1024;
|
||||
|
||||
|
||||
@@ -14,35 +14,36 @@
|
||||
// CONSTANTS DEFINITONS
|
||||
#define N_KEYBOARD_ROW 4 // for PROD. change to 5
|
||||
#define N_KEYBOARD_COL 3 // for PROD. change to 5
|
||||
#define N_CV_GATES 2
|
||||
#define N_SB 2
|
||||
#define N_CV_GATES 2 // PROD. OK
|
||||
#define N_SB 2 // PROD. OK
|
||||
#define BAUDRATE 115200
|
||||
#define N_MAX_SEQ_STEPS 512
|
||||
// PIN DEFENTITIONS
|
||||
// I2C PINS
|
||||
#define PIN_SDA 15
|
||||
#define PIN_SCL 16
|
||||
#define PIN_SDA 15 // PROD. pin OK
|
||||
#define PIN_SCL 16 // PROD. pin OK
|
||||
// KEYBOARD PINS
|
||||
#define PIN_K_R0 7
|
||||
#define PIN_K_R1 8
|
||||
#define PIN_K_R2 9
|
||||
#define PIN_K_R3 10
|
||||
#define PIN_K_R4 11 // DEV. not in use
|
||||
#define PIN_K_C0 1
|
||||
#define PIN_K_C1 2
|
||||
#define PIN_K_C2 4
|
||||
#define PIN_K_C3 5 // DEV. not in use
|
||||
#define PIN_K_C4 6 // DEV. not in use
|
||||
#define PIN_K_R0 7 // PROD. pin OK
|
||||
#define PIN_K_R1 8 // PROD. pin OK
|
||||
#define PIN_K_R2 9 // PROD. pin OK
|
||||
#define PIN_K_R3 10 // PROD. pin OK
|
||||
#define PIN_K_R4 11 // DEV. not in use - PROD. pin OK
|
||||
#define PIN_K_C0 1 // PROD. pin OK
|
||||
#define PIN_K_C1 2 // PROD. pin OK
|
||||
#define PIN_K_C2 4 // PROD. pin OK
|
||||
#define PIN_K_C3 5 // DEV. not in use - PROD. pin OK
|
||||
#define PIN_K_C4 6 // DEV. not in use - PROD. pin OK
|
||||
// SEQUENCER BUTTON PINS
|
||||
#define PIN_SB_1_REC 42 // for PROD. change to 33 / not available on dev board
|
||||
#define PIN_SB_1_PLAY 41 // for PROD. change to 34 / not available on dev board
|
||||
#define PIN_SB_2_REC 40 // 35
|
||||
#define PIN_SB_2_PLAY 39 // 36
|
||||
#define PIN_SB_1_REC 38 // for PROD. change to 33 / not available on dev board
|
||||
#define PIN_SB_1_PLAY 37 // for PROD. change to 34 / not available on dev board
|
||||
#define PIN_SB_2_REC 35 // 35
|
||||
#define PIN_SB_2_PLAY 36 // 36
|
||||
// MISC/INFO PINS
|
||||
#define PIN_ACTIVE -1 // TODO: if any key is played return HIGH
|
||||
#define PIN_REC -1 // TODO: if any sb is recording return HIGH
|
||||
#define PIN_BPM -1 // TODO: get bpm through potentiometer analog value
|
||||
#define PIN_B_METRONOME -1 // TODO: button activates/deactivates bpm led output
|
||||
#define PIN_L_METRONOME -1 // TODO: led blinks according to bpm value
|
||||
#define PIN_VCO1_EN 41 // PROD. pin 37 TODO: if there is an active key mapped to CV-Gate 1 --> HIGH
|
||||
#define PIN_VCO2_EN 40 // PROD. pin 38 TODO: if there is an active key mapped to CV-Gate 2 --> HIGH
|
||||
#define PIN_REC 39 // PROD. pin 39 TODO: if any sb is recording LED on (active-low)
|
||||
#define PIN_BPM 12 // PROD. pin 12 TODO: get bpm through potentiometer analog value -> ADC-Pin
|
||||
#define PIN_B_METRONOME 13 // PROD. pin 13 TODO: button activates/deactivates bpm led output (pull-up)
|
||||
#define PIN_L_METRONOME 14 // PROD. pin 14 TODO: led blinks according to bpm value (active-low)
|
||||
|
||||
#endif
|
||||
@@ -302,7 +302,7 @@ void SequencerBlock::addStep(uint16_t voltage_ch1, uint16_t voltage_ch2)
|
||||
unsigned long now = millis();
|
||||
|
||||
// NEU: Rate-Limiting - ignoriere zu häufige Aufrufe
|
||||
if((now - _lastAddStepTime) < 5) // Mindestens 5ms zwischen Updates
|
||||
if((unsigned long)(now - _lastAddStepTime) < 5)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -333,6 +333,7 @@ void SequencerBlock::addStep(uint16_t voltage_ch1, uint16_t voltage_ch2)
|
||||
_sequence[_stepCount].voltage_ch1 = voltage_ch1;
|
||||
_sequence[_stepCount].voltage_ch2 = voltage_ch2;
|
||||
_sequence[_stepCount].duration = 0;
|
||||
_sequence[_stepCount].active = (voltage_ch1 > 0 || voltage_ch2 > 0); // NEU: Prüfe ob Note aktiv
|
||||
_stepCount++;
|
||||
|
||||
_lastStepTime = now;
|
||||
@@ -452,6 +453,7 @@ void SequencerBlock::clear()
|
||||
_sequence[i].voltage_ch1 = 0;
|
||||
_sequence[i].voltage_ch2 = 0;
|
||||
_sequence[i].duration = 0;
|
||||
_sequence[i].active = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,6 +508,14 @@ uint16_t SequencerBlock::getTotalDuration()
|
||||
return (total > 65535) ? 65535 : (uint16_t)total; // Clamp auf uint16
|
||||
}
|
||||
|
||||
bool SequencerBlock::isCurrentStepActive()
|
||||
{
|
||||
if(!_isPlaying || _stepCount == 0) return false;
|
||||
if(_currentStep >= _stepCount || _currentStep >= _MAX_SEQUENCE_STEPS) return false;
|
||||
|
||||
return _sequence[_currentStep].active;
|
||||
}
|
||||
|
||||
void SequencerBlock::_finishCurrentStep()
|
||||
{
|
||||
if(_stepCount == 0) return;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/*
|
||||
* Example Code Three - Dual Channel Sequencer (FIXED)
|
||||
* - Bounds Checks hinzugefügt
|
||||
* - Rate-Limiting implementiert
|
||||
* - Debug-Ausgaben erweitert
|
||||
* - Stack Overflow verhindert
|
||||
* Example Code Three - Dual Channel Sequencer (COMPLETE)
|
||||
* - Alle TODOs implementiert
|
||||
* - VCO Gates, Recording LED, Metronome
|
||||
*/
|
||||
#include "FIRMWARE_DEF.h"
|
||||
#include "FIRMWARE.h"
|
||||
@@ -15,16 +13,15 @@ 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] = { /* 83mV = 1/12V */
|
||||
1*83, 5*83, 9*83, /* ROW 1: B D Fis */
|
||||
2*83, 6*83, 10*83, /* ROW 2: H Dis G */
|
||||
3*83, 7*83, 11*83, /* ROW 3: C E Gis */
|
||||
4*83, 8*83, 12*83 /* ROW 4: Cis F A' */
|
||||
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = {
|
||||
1*83, 5*83, 9*83,
|
||||
2*83, 6*83, 10*83,
|
||||
3*83, 7*83, 11*83,
|
||||
4*83, 8*83, 12*83
|
||||
};
|
||||
|
||||
CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL);
|
||||
|
||||
// Sequencer 30s max, 512 max Steps
|
||||
SequencerBlock sb1(30000, N_MAX_SEQ_STEPS);
|
||||
SequencerBlock sb2(30000, N_MAX_SEQ_STEPS);
|
||||
|
||||
@@ -39,14 +36,12 @@ ButtonState btn_sb1_rec;
|
||||
ButtonState btn_sb1_play;
|
||||
ButtonState btn_sb2_rec;
|
||||
ButtonState btn_sb2_play;
|
||||
ButtonState btn_metronome;
|
||||
|
||||
const unsigned long DEBOUNCE_DELAY = 50;
|
||||
|
||||
// Loop-Status für State Machine
|
||||
static bool seq1_loop_active = false;
|
||||
static bool seq2_loop_active = false;
|
||||
|
||||
// NEU: Tracking für Voltage Changes
|
||||
static uint16_t last_voltage_ch1 = 0xFFFF;
|
||||
static uint16_t last_voltage_ch2 = 0xFFFF;
|
||||
|
||||
@@ -82,6 +77,7 @@ void initButtons()
|
||||
pinMode(PIN_SB_1_PLAY, INPUT_PULLUP);
|
||||
pinMode(PIN_SB_2_REC, INPUT_PULLUP);
|
||||
pinMode(PIN_SB_2_PLAY, INPUT_PULLUP);
|
||||
pinMode(PIN_B_METRONOME, INPUT_PULLUP);
|
||||
|
||||
btn_sb1_rec.current = false;
|
||||
btn_sb1_rec.last = false;
|
||||
@@ -98,6 +94,30 @@ void initButtons()
|
||||
btn_sb2_play.current = false;
|
||||
btn_sb2_play.last = false;
|
||||
btn_sb2_play.lastDebounceTime = 0;
|
||||
|
||||
btn_metronome.current = false;
|
||||
btn_metronome.last = false;
|
||||
btn_metronome.lastDebounceTime = 0;
|
||||
}
|
||||
|
||||
void initOutputs()
|
||||
{
|
||||
// VCO Gates
|
||||
pinMode(PIN_VCO1_EN, OUTPUT);
|
||||
pinMode(PIN_VCO2_EN, OUTPUT);
|
||||
digitalWrite(PIN_VCO1_EN, LOW);
|
||||
digitalWrite(PIN_VCO2_EN, LOW);
|
||||
|
||||
// Recording LED (active-low)
|
||||
pinMode(PIN_REC, OUTPUT);
|
||||
digitalWrite(PIN_REC, HIGH); // OFF
|
||||
|
||||
// Metronome LED (active-low)
|
||||
pinMode(PIN_L_METRONOME, OUTPUT);
|
||||
digitalWrite(PIN_L_METRONOME, HIGH); // OFF
|
||||
|
||||
// BPM Potentiometer
|
||||
pinMode(PIN_BPM, INPUT);
|
||||
}
|
||||
|
||||
void handleSequencerButtons()
|
||||
@@ -115,13 +135,13 @@ void handleSequencerButtons()
|
||||
{
|
||||
if(sb1.isPlaying()) sb1.stopPlay();
|
||||
sb1.startRecord();
|
||||
last_voltage_ch1 = 0xFFFF; // Reset voltage tracking
|
||||
last_voltage_ch1 = 0xFFFF;
|
||||
last_voltage_ch2 = 0xFFFF;
|
||||
Serial.printf("\n\r[SEQ1] Recording started (2 channels)...");
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Sequencer 1 Play Button (3 Stati: Play / Loop / Stop) =====
|
||||
// ===== Sequencer 1 Play Button =====
|
||||
if(readButton(PIN_SB_1_PLAY, btn_sb1_play))
|
||||
{
|
||||
if(!sb1.isPlaying())
|
||||
@@ -160,13 +180,13 @@ void handleSequencerButtons()
|
||||
{
|
||||
if(sb2.isPlaying()) sb2.stopPlay();
|
||||
sb2.startRecord();
|
||||
last_voltage_ch1 = 0xFFFF; // Reset voltage tracking
|
||||
last_voltage_ch1 = 0xFFFF;
|
||||
last_voltage_ch2 = 0xFFFF;
|
||||
Serial.printf("\n\r[SEQ2] Recording started (2 channels)...");
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Sequencer 2 Play Button (3 Stati: Play / Loop / Stop) =====
|
||||
// ===== Sequencer 2 Play Button =====
|
||||
if(readButton(PIN_SB_2_PLAY, btn_sb2_play))
|
||||
{
|
||||
if(!sb2.isPlaying())
|
||||
@@ -193,16 +213,88 @@ void handleSequencerButtons()
|
||||
}
|
||||
}
|
||||
|
||||
static bool metronome_enabled = false;
|
||||
static uint16_t current_bpm = 120;
|
||||
static unsigned long last_beat_time = 0;
|
||||
static unsigned long last_pulse_end_time = 0;
|
||||
static bool metronome_led_on = false;
|
||||
|
||||
void updateMetronome()
|
||||
{
|
||||
unsigned long now = millis();
|
||||
|
||||
// BPM von Potentiometer lesen (alle 100ms)
|
||||
static unsigned long last_bpm_read = 0;
|
||||
if((now - last_bpm_read) > 100)
|
||||
{
|
||||
int adc_value = analogRead(PIN_BPM);
|
||||
// Map ADC (0-4095) zu BPM (40-240)
|
||||
current_bpm = map(adc_value, 0, 4095, 40, 240);
|
||||
last_bpm_read = now;
|
||||
}
|
||||
|
||||
// Metronome Button (Toggle)
|
||||
if(readButton(PIN_B_METRONOME, btn_metronome))
|
||||
{
|
||||
metronome_enabled = !metronome_enabled;
|
||||
Serial.printf("\n\r[METRONOME] %s (BPM: %d)",
|
||||
metronome_enabled ? "ON" : "OFF", current_bpm);
|
||||
|
||||
if(!metronome_enabled)
|
||||
{
|
||||
digitalWrite(PIN_L_METRONOME, HIGH); // Active-low: HIGH = OFF
|
||||
metronome_led_on = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!metronome_enabled) return;
|
||||
|
||||
// Berechne Beat-Intervall in ms
|
||||
unsigned long beat_interval = 60000UL / current_bpm;
|
||||
|
||||
// Neue Beat?
|
||||
if((now - last_beat_time) >= beat_interval)
|
||||
{
|
||||
digitalWrite(PIN_L_METRONOME, LOW); // Active-low: LOW = ON
|
||||
metronome_led_on = true;
|
||||
last_beat_time = now;
|
||||
last_pulse_end_time = now + 50; // 50ms Pulse
|
||||
}
|
||||
|
||||
// Pulse beenden?
|
||||
if(metronome_led_on && (now >= last_pulse_end_time))
|
||||
{
|
||||
digitalWrite(PIN_L_METRONOME, HIGH); // Active-low: HIGH = OFF
|
||||
metronome_led_on = false;
|
||||
}
|
||||
}
|
||||
|
||||
void updateVCOGates(bool cv1_active, bool cv2_active)
|
||||
{
|
||||
// PIN_VCO1_EN: HIGH wenn CV1 aktiv (Key mapped to CV-Gate 1)
|
||||
digitalWrite(PIN_VCO1_EN, cv1_active ? HIGH : LOW);
|
||||
|
||||
// PIN_VCO2_EN: HIGH wenn CV2 aktiv (Key mapped to CV-Gate 2)
|
||||
digitalWrite(PIN_VCO2_EN, cv2_active ? HIGH : LOW);
|
||||
}
|
||||
|
||||
void updateRecordingLED()
|
||||
{
|
||||
// PIN_REC: Active-low (LOW = LED ON)
|
||||
bool any_recording = sb1.isRecording() || sb2.isRecording();
|
||||
digitalWrite(PIN_REC, any_recording ? LOW : HIGH);
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUDRATE);
|
||||
delay(2000);
|
||||
Serial.printf("\n\r=== FIXED VERSION v2 ===");
|
||||
Serial.printf("\n\r=== COMPLETE VERSION with TODOs ===");
|
||||
Serial.printf("\n\rSerial OK!");
|
||||
|
||||
keyboard.begin();
|
||||
|
||||
// Fehlerbehandlung für CV-Initialisierung
|
||||
unsigned long timeout = millis() + 5000;
|
||||
while(!cv.begin(PIN_SDA, PIN_SCL))
|
||||
{
|
||||
@@ -219,25 +311,16 @@ void setup()
|
||||
Serial.printf("\n\r[OK] CV initialized");
|
||||
|
||||
initButtons();
|
||||
initOutputs();
|
||||
|
||||
sb1.setLoop(false);
|
||||
sb2.setLoop(false);
|
||||
|
||||
Serial.printf("\n\r=== Dual-Channel Sequencer System Started ===");
|
||||
Serial.printf("\n\rControls:");
|
||||
Serial.printf("\n\r PIN_SB_1_REC: SEQ1 Record Start/Stop (CH1+CH2)");
|
||||
Serial.printf("\n\r PIN_SB_1_PLAY: SEQ1 Play Mode Toggle:");
|
||||
Serial.printf("\n\r 1st click: Play once");
|
||||
Serial.printf("\n\r 2nd click: Loop mode");
|
||||
Serial.printf("\n\r 3rd click: Stop");
|
||||
Serial.printf("\n\r PIN_SB_2_REC: SEQ2 Record Start/Stop (CH1+CH2)");
|
||||
Serial.printf("\n\r PIN_SB_2_PLAY: SEQ2 Play Mode (same as SEQ1)");
|
||||
Serial.printf("\n\r");
|
||||
Serial.printf("\n\rFIXES:");
|
||||
Serial.printf("\n\r - Bounds checks in all array accesses");
|
||||
Serial.printf("\n\r - Rate limiting (5ms) for addStep()");
|
||||
Serial.printf("\n\r - Only call addStep() on voltage change");
|
||||
Serial.printf("\n\r - Stack overflow prevention");
|
||||
Serial.printf("\n\rFeatures:");
|
||||
Serial.printf("\n\r - VCO1/VCO2 Gate Outputs");
|
||||
Serial.printf("\n\r - Recording LED Indicator");
|
||||
Serial.printf("\n\r - BPM Metronome (40-240 BPM)");
|
||||
Serial.printf("\n\r==============================================\n\r");
|
||||
}
|
||||
|
||||
@@ -249,42 +332,44 @@ void loop()
|
||||
|
||||
loopCounter++;
|
||||
|
||||
// Debug-Ausgabe alle 5 Sekunden
|
||||
if(millis() - lastDebugPrint > 5000)
|
||||
{
|
||||
Serial.printf("\n\r[HEARTBEAT] Loop count: %lu", loopCounter);
|
||||
Serial.printf("\n\r[HEARTBEAT] Loop: %lu | BPM: %d | Metro: %s",
|
||||
loopCounter, current_bpm, metronome_enabled ? "ON" : "OFF");
|
||||
Serial.printf("\n\r[DEBUG] SB1: Rec=%d, Play=%d, Steps=%d",
|
||||
sb1.isRecording(), sb1.isPlaying(), sb1.getStepCount());
|
||||
Serial.printf("\n\r[DEBUG] SB2: Rec=%d, Play=%d, Steps=%d",
|
||||
sb2.isRecording(), sb2.isPlaying(), sb2.getStepCount());
|
||||
Serial.printf("\n\r[DEBUG] Free heap: %lu bytes", ESP.getFreeHeap());
|
||||
lastDebugPrint = millis();
|
||||
}
|
||||
|
||||
// ===== NON-BLOCKING TIMING SYSTEM =====
|
||||
// ===== NON-BLOCKING TIMING =====
|
||||
static unsigned long lastLoopTime = 0;
|
||||
unsigned long now = millis();
|
||||
const unsigned long LOOP_INTERVAL = 10; // 10ms
|
||||
const unsigned long LOOP_INTERVAL = 10;
|
||||
|
||||
if((now - lastLoopTime) < LOOP_INTERVAL)
|
||||
{
|
||||
return; // Nicht blockierend
|
||||
return;
|
||||
}
|
||||
lastLoopTime = now;
|
||||
|
||||
// ===== NORMALE UPDATE-FUNKTIONEN =====
|
||||
// ===== UPDATE FUNCTIONS =====
|
||||
keyboard.update();
|
||||
handleSequencerButtons();
|
||||
updateMetronome();
|
||||
updateRecordingLED();
|
||||
|
||||
// Sequencer Update (für Wiedergabe)
|
||||
sb1.update();
|
||||
sb2.update();
|
||||
|
||||
int n = keyboard.getQueueLength();
|
||||
|
||||
// Aktuelle Spannungen für beide Kanäle ermitteln
|
||||
// Aktuelle Spannungen ermitteln
|
||||
uint16_t voltage_ch1 = 0;
|
||||
uint16_t voltage_ch2 = 0;
|
||||
bool cv1_active = false;
|
||||
bool cv2_active = false;
|
||||
|
||||
if(n > 0)
|
||||
{
|
||||
@@ -292,6 +377,7 @@ void loop()
|
||||
if(!isNotKey(k1))
|
||||
{
|
||||
voltage_ch1 = keyToVoltage[k1.row * N_KEYBOARD_COL + k1.col];
|
||||
cv1_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,51 +387,59 @@ void loop()
|
||||
if(!isNotKey(k2))
|
||||
{
|
||||
voltage_ch2 = keyToVoltage[k2.row * N_KEYBOARD_COL + k2.col];
|
||||
cv2_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Bei Recording: Beide Kanäle aufnehmen - NUR bei Änderung!
|
||||
// Recording
|
||||
bool voltageChanged = (voltage_ch1 != last_voltage_ch1) || (voltage_ch2 != last_voltage_ch2);
|
||||
|
||||
if(sb1.isRecording())
|
||||
if(sb1.isRecording() && voltageChanged)
|
||||
{
|
||||
if(voltageChanged)
|
||||
{
|
||||
sb1.addStep(voltage_ch1, voltage_ch2);
|
||||
last_voltage_ch1 = voltage_ch1;
|
||||
last_voltage_ch2 = voltage_ch2;
|
||||
}
|
||||
sb1.addStep(voltage_ch1, voltage_ch2);
|
||||
last_voltage_ch1 = voltage_ch1;
|
||||
last_voltage_ch2 = voltage_ch2;
|
||||
}
|
||||
|
||||
if(sb2.isRecording())
|
||||
if(sb2.isRecording() && voltageChanged)
|
||||
{
|
||||
if(voltageChanged)
|
||||
{
|
||||
sb2.addStep(voltage_ch1, voltage_ch2);
|
||||
last_voltage_ch1 = voltage_ch1;
|
||||
last_voltage_ch2 = voltage_ch2;
|
||||
}
|
||||
sb2.addStep(voltage_ch1, voltage_ch2);
|
||||
last_voltage_ch1 = voltage_ch1;
|
||||
last_voltage_ch2 = voltage_ch2;
|
||||
}
|
||||
|
||||
// CV-Ausgabe: Priorität hat Sequencer-Wiedergabe
|
||||
// CV-Ausgabe & VCO Gates
|
||||
if(sb1.isPlaying())
|
||||
{
|
||||
cv.setVoltage(0, sb1.getCurrentVoltageCh1());
|
||||
cv.setVoltage(1, sb1.getCurrentVoltageCh2());
|
||||
uint16_t seq_v1 = sb1.getCurrentVoltageCh1();
|
||||
uint16_t seq_v2 = sb1.getCurrentVoltageCh2();
|
||||
cv.setVoltage(0, seq_v1);
|
||||
cv.setVoltage(1, seq_v2);
|
||||
|
||||
// KORREKT: Nutze isCurrentStepActive() statt Spannung > 0
|
||||
// Da 0V eine gültige Note sein kann!
|
||||
bool gate_active = sb1.isCurrentStepActive();
|
||||
updateVCOGates(gate_active, gate_active);
|
||||
}
|
||||
else if(sb2.isPlaying())
|
||||
{
|
||||
cv.setVoltage(0, sb2.getCurrentVoltageCh1());
|
||||
cv.setVoltage(1, sb2.getCurrentVoltageCh2());
|
||||
uint16_t seq_v1 = sb2.getCurrentVoltageCh1();
|
||||
uint16_t seq_v2 = sb2.getCurrentVoltageCh2();
|
||||
cv.setVoltage(0, seq_v1);
|
||||
cv.setVoltage(1, seq_v2);
|
||||
|
||||
bool gate_active = sb2.isCurrentStepActive();
|
||||
updateVCOGates(gate_active, gate_active);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Live-Ausgabe wenn kein Sequencer spielt
|
||||
// Live-Modus: cv1_active/cv2_active basieren auf tatsächlich gedrückten Tasten
|
||||
cv.setVoltage(0, voltage_ch1);
|
||||
cv.setVoltage(1, voltage_ch2);
|
||||
updateVCOGates(cv1_active, cv2_active);
|
||||
}
|
||||
|
||||
// Time-Limit Warnung
|
||||
// Time-Limit Check
|
||||
if(sb1.isRecording() && sb1.timeLimitReached())
|
||||
{
|
||||
sb1.stopRecord();
|
||||
|
||||
Reference in New Issue
Block a user