mirror of
https://github.com/erik-toth/audio-synth.git
synced 2026-03-12 00:47:42 +00:00
Firmware Update
Changed mapping behaveiour of seqeuncer blocks.
This commit is contained in:
Binary file not shown.
@@ -3,7 +3,7 @@
|
|||||||
@author: Erik Tóth
|
@author: Erik Tóth
|
||||||
@contact: etoth@tsn.at
|
@contact: etoth@tsn.at
|
||||||
@date: 2025-10-26
|
@date: 2025-10-26
|
||||||
@updated: 2025-12-06
|
@updated: 2026-03-08
|
||||||
@brief: Header for constant definitions
|
@brief: Header for constant definitions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -12,38 +12,38 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
// CONSTANTS DEFINITONS
|
// CONSTANTS DEFINITONS
|
||||||
#define N_KEYBOARD_ROW 5 // for PROD. change to 5
|
#define N_KEYBOARD_ROW 5
|
||||||
#define N_KEYBOARD_COL 5 // for PROD. change to 5
|
#define N_KEYBOARD_COL 5
|
||||||
#define N_CV_GATES 2 // PROD. OK
|
#define N_CV_GATES 2
|
||||||
#define N_SB 2 // PROD. OK
|
#define N_SB 2
|
||||||
#define BAUDRATE 115200
|
#define BAUDRATE 115200
|
||||||
#define N_MAX_SEQ_STEPS 512
|
#define N_MAX_SEQ_STEPS 512
|
||||||
// PIN DEFENTITIONS
|
// PIN DEFENTITIONS
|
||||||
// I2C PINS
|
// I2C PINS
|
||||||
#define PIN_SDA 15 // PROD. pin OK
|
#define PIN_SDA 15
|
||||||
#define PIN_SCL 16 // PROD. pin OK
|
#define PIN_SCL 16
|
||||||
// KEYBOARD PINS
|
// KEYBOARD PINS
|
||||||
#define PIN_K_R0 7 // PROD. pin OK
|
#define PIN_K_R0 7
|
||||||
#define PIN_K_R1 8 // PROD. pin OK
|
#define PIN_K_R1 8
|
||||||
#define PIN_K_R2 9 // PROD. pin OK
|
#define PIN_K_R2 9
|
||||||
#define PIN_K_R3 10 // PROD. pin OK
|
#define PIN_K_R3 10
|
||||||
#define PIN_K_R4 11 // DEV. not in use - PROD. pin OK
|
#define PIN_K_R4 11
|
||||||
#define PIN_K_C0 1 // PROD. pin OK
|
#define PIN_K_C0 1
|
||||||
#define PIN_K_C1 2 // PROD. pin OK
|
#define PIN_K_C1 2
|
||||||
#define PIN_K_C2 4 // PROD. pin OK
|
#define PIN_K_C2 4
|
||||||
#define PIN_K_C3 5 // DEV. not in use - PROD. pin OK
|
#define PIN_K_C3 5
|
||||||
#define PIN_K_C4 6 // DEV. not in use - PROD. pin OK
|
#define PIN_K_C4 6
|
||||||
// SEQUENCER BUTTON PINS
|
// SEQUENCER BUTTON PINS
|
||||||
#define PIN_SB_1_REC 33 // for PROD. change to 33 / not available on dev board
|
#define PIN_SB_1_REC 33
|
||||||
#define PIN_SB_1_PLAY 34 // for PROD. change to 34 / not available on dev board
|
#define PIN_SB_1_PLAY 34
|
||||||
#define PIN_SB_2_REC 35 // 35
|
#define PIN_SB_2_REC 35
|
||||||
#define PIN_SB_2_PLAY 36 // 36
|
#define PIN_SB_2_PLAY 36
|
||||||
// MISC/INFO PINS
|
// MISC/INFO PINS
|
||||||
#define PIN_VCO1_EN 38 // PROD. pin 38 TODO: if there is an active key mapped to CV-Gate 1 --> HIGH
|
#define PIN_VCO1_EN 38
|
||||||
#define PIN_VCO2_EN 39 // PROD. pin 39 TODO: if there is an active key mapped to CV-Gate 2 --> HIGH
|
#define PIN_VCO2_EN 39
|
||||||
#define PIN_REC 37 // PROD. pin 37 TODO: if any sb is recording LED on (active-low)
|
#define PIN_REC 37
|
||||||
#define PIN_BPM 12 // PROD. pin 12 TODO: get bpm through potentiometer analog value -> ADC-Pin
|
#define PIN_BPM 12
|
||||||
#define PIN_B_METRONOME 14 // PROD. pin 13 TODO: button activates/deactivates bpm led output (pull-up)
|
#define PIN_B_METRONOME 14
|
||||||
#define PIN_L_METRONOME 13 // PROD. pin 14 TODO: led blinks according to bpm value (active-low)
|
#define PIN_L_METRONOME 13
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -3,13 +3,13 @@
|
|||||||
@author: Erik Tóth
|
@author: Erik Tóth
|
||||||
@contact: etoth@tsn.at
|
@contact: etoth@tsn.at
|
||||||
@date: 2025-10-26
|
@date: 2025-10-26
|
||||||
@updated: 2025-12-06
|
@updated: 2026-03-08
|
||||||
@brief: Firmware für MCU - FIXED VERSION mit Bounds Checks
|
@brief: Firmware für MCU
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FIRMWARE.h"
|
#include "FIRMWARE.h"
|
||||||
|
|
||||||
// ==================== Helper-Functions ====================
|
// Helper-Functions
|
||||||
|
|
||||||
bool isNotKey(Key k)
|
bool isNotKey(Key k)
|
||||||
{
|
{
|
||||||
@@ -23,7 +23,7 @@ bool isEqualKey(Key k1, Key k2)
|
|||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== Keyboard ====================
|
// Keyboard
|
||||||
|
|
||||||
Keyboard::Keyboard(uint8_t nRows, uint8_t nCols, uint8_t *pinsRow, uint8_t *pinsCol)
|
Keyboard::Keyboard(uint8_t nRows, uint8_t nCols, uint8_t *pinsRow, uint8_t *pinsCol)
|
||||||
{
|
{
|
||||||
@@ -178,7 +178,7 @@ void Keyboard::_removeActiveKey(uint8_t row, uint8_t col)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== CV ====================
|
// CV
|
||||||
|
|
||||||
CV::CV(Adafruit_MCP4728 *dac, TwoWire *wire, uint8_t nCV, MCP4728_channel_t *cvChannelMap, uint16_t *keyToVoltage, uint8_t row, uint8_t col)
|
CV::CV(Adafruit_MCP4728 *dac, TwoWire *wire, uint8_t nCV, MCP4728_channel_t *cvChannelMap, uint16_t *keyToVoltage, uint8_t row, uint8_t col)
|
||||||
{
|
{
|
||||||
@@ -209,7 +209,7 @@ void CV::setVoltage(uint8_t cvIndex, uint16_t mV)
|
|||||||
{
|
{
|
||||||
if(cvIndex >= _nCV) return;
|
if(cvIndex >= _nCV) return;
|
||||||
MCP4728_channel_t ch = _cvChannelMap[cvIndex];
|
MCP4728_channel_t ch = _cvChannelMap[cvIndex];
|
||||||
_dac->setChannelValue(ch, map(mV, 0, 1992, 0, 2048), MCP4728_VREF_INTERNAL);
|
_dac->setChannelValue(ch, map(mV, 0, 2048, 0, 4095), MCP4728_VREF_INTERNAL, MCP4728_GAIN_1X);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CV::setVoltage(uint8_t cvIndex, Key k)
|
void CV::setVoltage(uint8_t cvIndex, Key k)
|
||||||
@@ -234,7 +234,7 @@ uint8_t CV::_getKeyToVoltageIndex(Key k)
|
|||||||
return (k.row*_col + k.col);
|
return (k.row*_col + k.col);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== SequencerBlock (FIXED) ====================
|
// SequencerBlock
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @param maxDurationMS maximum loop duration of recording in milliseconds
|
* @param maxDurationMS maximum loop duration of recording in milliseconds
|
||||||
@@ -255,7 +255,7 @@ SequencerBlock::SequencerBlock(uint16_t maxDurationMS, uint16_t maxStepCount)
|
|||||||
_lastStepTime = 0;
|
_lastStepTime = 0;
|
||||||
_playStartTime = 0;
|
_playStartTime = 0;
|
||||||
_stepStartTime = 0;
|
_stepStartTime = 0;
|
||||||
_lastAddStepTime = 0; // NEU: Rate-Limiting
|
_lastAddStepTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SequencerBlock::startRecord()
|
void SequencerBlock::startRecord()
|
||||||
@@ -266,7 +266,7 @@ void SequencerBlock::startRecord()
|
|||||||
_isRecording = true;
|
_isRecording = true;
|
||||||
_recordStartTime = millis();
|
_recordStartTime = millis();
|
||||||
_lastStepTime = _recordStartTime;
|
_lastStepTime = _recordStartTime;
|
||||||
_lastAddStepTime = _recordStartTime; // NEU
|
_lastAddStepTime = _recordStartTime;
|
||||||
_lastVoltageCh1 = 0xFFFF;
|
_lastVoltageCh1 = 0xFFFF;
|
||||||
_lastVoltageCh2 = 0xFFFF;
|
_lastVoltageCh2 = 0xFFFF;
|
||||||
}
|
}
|
||||||
@@ -281,10 +281,8 @@ void SequencerBlock::stopRecord()
|
|||||||
|
|
||||||
void SequencerBlock::addStep(uint16_t voltage_ch1, uint16_t voltage_ch2)
|
void SequencerBlock::addStep(uint16_t voltage_ch1, uint16_t voltage_ch2)
|
||||||
{
|
{
|
||||||
// KRITISCHE SICHERHEITSPRÜFUNGEN ZUERST
|
|
||||||
if(!_isRecording) return;
|
if(!_isRecording) return;
|
||||||
|
|
||||||
// Prüfe ob wir überhaupt noch Platz haben (mit Sicherheitsabstand!)
|
|
||||||
if(_stepCount >= _MAX_SEQUENCE_STEPS - 1)
|
if(_stepCount >= _MAX_SEQUENCE_STEPS - 1)
|
||||||
{
|
{
|
||||||
Serial.println("\n\r[ERROR] Step limit reached! Stopping recording.");
|
Serial.println("\n\r[ERROR] Step limit reached! Stopping recording.");
|
||||||
@@ -301,19 +299,16 @@ void SequencerBlock::addStep(uint16_t voltage_ch1, uint16_t voltage_ch2)
|
|||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
// NEU: Rate-Limiting - ignoriere zu häufige Aufrufe
|
|
||||||
if((unsigned long)(now - _lastAddStepTime) < 5)
|
if((unsigned long)(now - _lastAddStepTime) < 5)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_lastAddStepTime = now;
|
_lastAddStepTime = now;
|
||||||
|
|
||||||
// Hat sich die Spannung geändert?
|
|
||||||
bool voltageChanged = (voltage_ch1 != _lastVoltageCh1) || (voltage_ch2 != _lastVoltageCh2);
|
bool voltageChanged = (voltage_ch1 != _lastVoltageCh1) || (voltage_ch2 != _lastVoltageCh2);
|
||||||
|
|
||||||
if(voltageChanged)
|
if(voltageChanged)
|
||||||
{
|
{
|
||||||
// WICHTIG: Prüfe nochmal ob wir Platz haben BEVOR wir schreiben!
|
|
||||||
if(_stepCount >= _MAX_SEQUENCE_STEPS - 1)
|
if(_stepCount >= _MAX_SEQUENCE_STEPS - 1)
|
||||||
{
|
{
|
||||||
Serial.println("\n\r[ERROR] Array full! Stopping recording.");
|
Serial.println("\n\r[ERROR] Array full! Stopping recording.");
|
||||||
@@ -321,19 +316,17 @@ void SequencerBlock::addStep(uint16_t voltage_ch1, uint16_t voltage_ch2)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vorherigen Step abschließen (wenn vorhanden)
|
|
||||||
if(_stepCount > 0 && _stepCount <= _MAX_SEQUENCE_STEPS)
|
if(_stepCount > 0 && _stepCount <= _MAX_SEQUENCE_STEPS)
|
||||||
{
|
{
|
||||||
_finishCurrentStep();
|
_finishCurrentStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neuen Step beginnen - mit Bounds Check!
|
|
||||||
if(_stepCount < _MAX_SEQUENCE_STEPS)
|
if(_stepCount < _MAX_SEQUENCE_STEPS)
|
||||||
{
|
{
|
||||||
_sequence[_stepCount].voltage_ch1 = voltage_ch1;
|
_sequence[_stepCount].voltage_ch1 = voltage_ch1;
|
||||||
_sequence[_stepCount].voltage_ch2 = voltage_ch2;
|
_sequence[_stepCount].voltage_ch2 = voltage_ch2;
|
||||||
_sequence[_stepCount].duration = 0;
|
_sequence[_stepCount].duration = 0;
|
||||||
_sequence[_stepCount].active = (voltage_ch1 > 0 || voltage_ch2 > 0); // NEU: Prüfe ob Note aktiv
|
_sequence[_stepCount].active = (voltage_ch1 > 0 || voltage_ch2 > 0);
|
||||||
_stepCount++;
|
_stepCount++;
|
||||||
|
|
||||||
_lastStepTime = now;
|
_lastStepTime = now;
|
||||||
@@ -343,8 +336,6 @@ void SequencerBlock::addStep(uint16_t voltage_ch1, uint16_t voltage_ch2)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Gleiche Spannung - Duration des aktuellen Steps aktualisieren
|
|
||||||
// WICHTIG: Bounds Check!
|
|
||||||
if(_stepCount > 0 && _stepCount <= _MAX_SEQUENCE_STEPS)
|
if(_stepCount > 0 && _stepCount <= _MAX_SEQUENCE_STEPS)
|
||||||
{
|
{
|
||||||
_sequence[_stepCount - 1].duration = now - _lastStepTime;
|
_sequence[_stepCount - 1].duration = now - _lastStepTime;
|
||||||
@@ -378,7 +369,6 @@ void SequencerBlock::update()
|
|||||||
{
|
{
|
||||||
if(!_isPlaying || _stepCount == 0) return;
|
if(!_isPlaying || _stepCount == 0) return;
|
||||||
|
|
||||||
// WICHTIG: Bounds Check BEVOR wir auf Array zugreifen!
|
|
||||||
if(_currentStep >= _stepCount || _currentStep >= _MAX_SEQUENCE_STEPS)
|
if(_currentStep >= _stepCount || _currentStep >= _MAX_SEQUENCE_STEPS)
|
||||||
{
|
{
|
||||||
Serial.println("\n\r[ERROR] Invalid step index in update()!");
|
Serial.println("\n\r[ERROR] Invalid step index in update()!");
|
||||||
@@ -389,7 +379,6 @@ void SequencerBlock::update()
|
|||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
unsigned long elapsed = now - _stepStartTime;
|
unsigned long elapsed = now - _stepStartTime;
|
||||||
|
|
||||||
// Sicherung gegen Division durch Null / Endlosschleife
|
|
||||||
if(_sequence[_currentStep].duration == 0)
|
if(_sequence[_currentStep].duration == 0)
|
||||||
{
|
{
|
||||||
_currentStep++;
|
_currentStep++;
|
||||||
@@ -409,12 +398,10 @@ void SequencerBlock::update()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfen ob aktueller Schritt abgelaufen ist
|
|
||||||
if(elapsed >= _sequence[_currentStep].duration)
|
if(elapsed >= _sequence[_currentStep].duration)
|
||||||
{
|
{
|
||||||
_currentStep++;
|
_currentStep++;
|
||||||
|
|
||||||
// Sequenz-Ende erreicht?
|
|
||||||
if(_currentStep >= _stepCount)
|
if(_currentStep >= _stepCount)
|
||||||
{
|
{
|
||||||
if(_loop)
|
if(_loop)
|
||||||
@@ -447,7 +434,6 @@ void SequencerBlock::clear()
|
|||||||
_lastVoltageCh1 = 0;
|
_lastVoltageCh1 = 0;
|
||||||
_lastVoltageCh2 = 0;
|
_lastVoltageCh2 = 0;
|
||||||
|
|
||||||
// Optional: Array löschen (kann je nach Use-Case weggelassen werden)
|
|
||||||
for(uint16_t i = 0; i < _MAX_SEQUENCE_STEPS; i++)
|
for(uint16_t i = 0; i < _MAX_SEQUENCE_STEPS; i++)
|
||||||
{
|
{
|
||||||
_sequence[i].voltage_ch1 = 0;
|
_sequence[i].voltage_ch1 = 0;
|
||||||
@@ -500,7 +486,7 @@ uint16_t SequencerBlock::getCurrentVoltageCh2()
|
|||||||
|
|
||||||
uint16_t SequencerBlock::getTotalDuration()
|
uint16_t SequencerBlock::getTotalDuration()
|
||||||
{
|
{
|
||||||
uint32_t total = 0; // uint32 um Overflow zu vermeiden
|
uint32_t total = 0;
|
||||||
for(uint16_t i = 0; i < _stepCount && i < _MAX_SEQUENCE_STEPS; i++)
|
for(uint16_t i = 0; i < _stepCount && i < _MAX_SEQUENCE_STEPS; i++)
|
||||||
{
|
{
|
||||||
total += _sequence[i].duration;
|
total += _sequence[i].duration;
|
||||||
@@ -519,7 +505,7 @@ bool SequencerBlock::isCurrentStepActive()
|
|||||||
void SequencerBlock::_finishCurrentStep()
|
void SequencerBlock::_finishCurrentStep()
|
||||||
{
|
{
|
||||||
if(_stepCount == 0) return;
|
if(_stepCount == 0) return;
|
||||||
if(_stepCount > _MAX_SEQUENCE_STEPS) return; // Sicherheitsprüfung
|
if(_stepCount > _MAX_SEQUENCE_STEPS) return;
|
||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
uint16_t duration = now - _lastStepTime;
|
uint16_t duration = now - _lastStepTime;
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Example Code Three - Dual Channel Sequencer (COMPLETE)
|
* Analoger Audiosynthesizer mit digitaler Steuereinheit
|
||||||
* - Alle TODOs implementiert
|
* Firmware-Code für die digitale Einheit
|
||||||
* - VCO Gates, Recording LED, Metronome
|
* Autor: Erik Tóth
|
||||||
*/
|
*/
|
||||||
#include "FIRMWARE_DEF.h"
|
#include "FIRMWARE_DEF.h"
|
||||||
#include "FIRMWARE.h"
|
#include "FIRMWARE.h"
|
||||||
|
|
||||||
|
// Calibration table for optimal note accurarcy
|
||||||
|
const uint16_t NOTE_MV[25] = {
|
||||||
|
64, 140, 216, 293, 369,
|
||||||
|
445, 521, 597, 673, 750,
|
||||||
|
826, 902, 978, 1054, 1131,
|
||||||
|
1207, 1283, 1359, 1435, 1511,
|
||||||
|
1588, 1664, 1740, 1816, 1892,
|
||||||
|
};
|
||||||
|
#define HLFSTEP(n) NOTE_MV[n]
|
||||||
|
|
||||||
byte pins_keyboard_row[N_KEYBOARD_ROW] = {PIN_K_R0, PIN_K_R1, PIN_K_R2, PIN_K_R3, PIN_K_R4};
|
byte pins_keyboard_row[N_KEYBOARD_ROW] = {PIN_K_R0, PIN_K_R1, PIN_K_R2, PIN_K_R3, PIN_K_R4};
|
||||||
byte pins_keyboard_col[N_KEYBOARD_COL] = {PIN_K_C0, PIN_K_C1, PIN_K_C2, PIN_K_C3, PIN_K_C4};
|
byte pins_keyboard_col[N_KEYBOARD_COL] = {PIN_K_C0, PIN_K_C1, PIN_K_C2, PIN_K_C3, PIN_K_C4};
|
||||||
|
|
||||||
@@ -14,15 +24,16 @@ Keyboard keyboard(N_KEYBOARD_ROW, N_KEYBOARD_COL, pins_keyboard_row, pins_keyboa
|
|||||||
Adafruit_MCP4728 MCP4728;
|
Adafruit_MCP4728 MCP4728;
|
||||||
MCP4728_channel_t cvMap[N_CV_GATES] = {MCP4728_CHANNEL_A, MCP4728_CHANNEL_B};
|
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] = {
|
||||||
0*83, 1*83, 2*83, 3*83, 4*83,
|
HLFSTEP(0), HLFSTEP(1), HLFSTEP(2), HLFSTEP(3), HLFSTEP(4),
|
||||||
5*83, 6*83, 7*83, 8*83, 9*83,
|
HLFSTEP(5), HLFSTEP(6), HLFSTEP(7), HLFSTEP(8), HLFSTEP(9),
|
||||||
10*83, 11*83, 12*83, 13*83, 14*83,
|
HLFSTEP(10), HLFSTEP(11), HLFSTEP(12), HLFSTEP(13), HLFSTEP(14),
|
||||||
15*83, 16*83, 17*83, 18*83, 19*83,
|
HLFSTEP(15), HLFSTEP(16), HLFSTEP(17), HLFSTEP(18), HLFSTEP(19),
|
||||||
20*83, 21*83, 22*83, 23*83, 24*83
|
HLFSTEP(20), HLFSTEP(21), HLFSTEP(22), HLFSTEP(23), HLFSTEP(24)
|
||||||
};
|
};
|
||||||
|
|
||||||
CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL);
|
CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL);
|
||||||
|
|
||||||
|
// SB1 -> VCO1 (CV-Channel 0), SB2 -> VCO2 (CV-Channel 1)
|
||||||
SequencerBlock sb1(30000, N_MAX_SEQ_STEPS);
|
SequencerBlock sb1(30000, N_MAX_SEQ_STEPS);
|
||||||
SequencerBlock sb2(30000, N_MAX_SEQ_STEPS);
|
SequencerBlock sb2(30000, N_MAX_SEQ_STEPS);
|
||||||
|
|
||||||
@@ -43,8 +54,12 @@ const unsigned long DEBOUNCE_DELAY = 50;
|
|||||||
|
|
||||||
static bool seq1_loop_active = false;
|
static bool seq1_loop_active = false;
|
||||||
static bool seq2_loop_active = false;
|
static bool seq2_loop_active = false;
|
||||||
static uint16_t last_voltage_ch1 = 0xFFFF;
|
|
||||||
static uint16_t last_voltage_ch2 = 0xFFFF;
|
// Separate last-voltage tracking per sequencer
|
||||||
|
static uint16_t sb1_last_voltage_ch1 = 0xFFFF;
|
||||||
|
static uint16_t sb1_last_voltage_ch2 = 0xFFFF;
|
||||||
|
static uint16_t sb2_last_voltage_ch1 = 0xFFFF;
|
||||||
|
static uint16_t sb2_last_voltage_ch2 = 0xFFFF;
|
||||||
|
|
||||||
bool readButton(byte pin, ButtonState &state)
|
bool readButton(byte pin, ButtonState &state)
|
||||||
{
|
{
|
||||||
@@ -123,26 +138,24 @@ void initOutputs()
|
|||||||
|
|
||||||
void handleSequencerButtons()
|
void handleSequencerButtons()
|
||||||
{
|
{
|
||||||
// ===== Sequencer 1 Record Button =====
|
|
||||||
if(readButton(PIN_SB_1_REC, btn_sb1_rec))
|
if(readButton(PIN_SB_1_REC, btn_sb1_rec))
|
||||||
{
|
{
|
||||||
if(sb1.isRecording())
|
if(sb1.isRecording())
|
||||||
{
|
{
|
||||||
sb1.stopRecord();
|
sb1.stopRecord();
|
||||||
Serial.printf("\n\r[SEQ1] Recording stopped. Steps: %i, Duration: %ims",
|
Serial.printf("\n\r[SEQ1->VCO1] Recording stopped. Steps: %i, Duration: %ims",
|
||||||
sb1.getStepCount(), sb1.getTotalDuration());
|
sb1.getStepCount(), sb1.getTotalDuration());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(sb1.isPlaying()) sb1.stopPlay();
|
if(sb1.isPlaying()) sb1.stopPlay();
|
||||||
sb1.startRecord();
|
sb1.startRecord();
|
||||||
last_voltage_ch1 = 0xFFFF;
|
sb1_last_voltage_ch1 = 0xFFFF;
|
||||||
last_voltage_ch2 = 0xFFFF;
|
sb1_last_voltage_ch2 = 0xFFFF;
|
||||||
Serial.printf("\n\r[SEQ1] Recording started (2 channels)...");
|
Serial.printf("\n\r[SEQ1->VCO1] Recording started...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Sequencer 1 Play Button =====
|
|
||||||
if(readButton(PIN_SB_1_PLAY, btn_sb1_play))
|
if(readButton(PIN_SB_1_PLAY, btn_sb1_play))
|
||||||
{
|
{
|
||||||
if(!sb1.isPlaying())
|
if(!sb1.isPlaying())
|
||||||
@@ -151,43 +164,41 @@ void handleSequencerButtons()
|
|||||||
sb1.setLoop(false);
|
sb1.setLoop(false);
|
||||||
seq1_loop_active = false;
|
seq1_loop_active = false;
|
||||||
sb1.startPlay();
|
sb1.startPlay();
|
||||||
Serial.printf("\n\r[SEQ1] Playback started (single)\n\r\tSteps: %i, Duration: %ims",
|
Serial.printf("\n\r[SEQ1->VCO1] Playback started (single)\n\r\tSteps: %i, Duration: %ims",
|
||||||
sb1.getStepCount(), sb1.getTotalDuration());
|
sb1.getStepCount(), sb1.getTotalDuration());
|
||||||
}
|
}
|
||||||
else if(!seq1_loop_active)
|
else if(!seq1_loop_active)
|
||||||
{
|
{
|
||||||
sb1.setLoop(true);
|
sb1.setLoop(true);
|
||||||
seq1_loop_active = true;
|
seq1_loop_active = true;
|
||||||
Serial.printf("\n\r[SEQ1] Loop activated");
|
Serial.printf("\n\r[SEQ1->VCO1] Loop activated");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sb1.stopPlay();
|
sb1.stopPlay();
|
||||||
seq1_loop_active = false;
|
seq1_loop_active = false;
|
||||||
Serial.printf("\n\r[SEQ1] Playback stopped");
|
Serial.printf("\n\r[SEQ1->VCO1] Playback stopped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Sequencer 2 Record Button =====
|
|
||||||
if(readButton(PIN_SB_2_REC, btn_sb2_rec))
|
if(readButton(PIN_SB_2_REC, btn_sb2_rec))
|
||||||
{
|
{
|
||||||
if(sb2.isRecording())
|
if(sb2.isRecording())
|
||||||
{
|
{
|
||||||
sb2.stopRecord();
|
sb2.stopRecord();
|
||||||
Serial.printf("\n\r[SEQ2] Recording stopped. Steps: %i, Duration: %ims",
|
Serial.printf("\n\r[SEQ2->VCO2] Recording stopped. Steps: %i, Duration: %ims",
|
||||||
sb2.getStepCount(), sb2.getTotalDuration());
|
sb2.getStepCount(), sb2.getTotalDuration());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(sb2.isPlaying()) sb2.stopPlay();
|
if(sb2.isPlaying()) sb2.stopPlay();
|
||||||
sb2.startRecord();
|
sb2.startRecord();
|
||||||
last_voltage_ch1 = 0xFFFF;
|
sb2_last_voltage_ch1 = 0xFFFF;
|
||||||
last_voltage_ch2 = 0xFFFF;
|
sb2_last_voltage_ch2 = 0xFFFF;
|
||||||
Serial.printf("\n\r[SEQ2] Recording started (2 channels)...");
|
Serial.printf("\n\r[SEQ2->VCO2] Recording started...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Sequencer 2 Play Button =====
|
|
||||||
if(readButton(PIN_SB_2_PLAY, btn_sb2_play))
|
if(readButton(PIN_SB_2_PLAY, btn_sb2_play))
|
||||||
{
|
{
|
||||||
if(!sb2.isPlaying())
|
if(!sb2.isPlaying())
|
||||||
@@ -196,20 +207,20 @@ void handleSequencerButtons()
|
|||||||
sb2.setLoop(false);
|
sb2.setLoop(false);
|
||||||
seq2_loop_active = false;
|
seq2_loop_active = false;
|
||||||
sb2.startPlay();
|
sb2.startPlay();
|
||||||
Serial.printf("\n\r[SEQ2] Playback started (single)\n\r\tSteps: %i, Duration: %ims",
|
Serial.printf("\n\r[SEQ2->VCO2] Playback started (single)\n\r\tSteps: %i, Duration: %ims",
|
||||||
sb2.getStepCount(), sb2.getTotalDuration());
|
sb2.getStepCount(), sb2.getTotalDuration());
|
||||||
}
|
}
|
||||||
else if(!seq2_loop_active)
|
else if(!seq2_loop_active)
|
||||||
{
|
{
|
||||||
sb2.setLoop(true);
|
sb2.setLoop(true);
|
||||||
seq2_loop_active = true;
|
seq2_loop_active = true;
|
||||||
Serial.printf("\n\r[SEQ2] Loop activated");
|
Serial.printf("\n\r[SEQ2->VCO2] Loop activated");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sb2.stopPlay();
|
sb2.stopPlay();
|
||||||
seq2_loop_active = false;
|
seq2_loop_active = false;
|
||||||
Serial.printf("\n\r[SEQ2] Playback stopped");
|
Serial.printf("\n\r[SEQ2->VCO2] Playback stopped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,17 +235,14 @@ void updateMetronome()
|
|||||||
{
|
{
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
// BPM von Potentiometer lesen (alle 100ms)
|
|
||||||
static unsigned long last_bpm_read = 0;
|
static unsigned long last_bpm_read = 0;
|
||||||
if((now - last_bpm_read) > 100)
|
if((now - last_bpm_read) > 100)
|
||||||
{
|
{
|
||||||
int adc_value = analogRead(PIN_BPM);
|
int adc_value = analogRead(PIN_BPM);
|
||||||
// Map ADC (0-4095) zu BPM (40-240)
|
|
||||||
current_bpm = map(adc_value, 0, 4095, 40, 240);
|
current_bpm = map(adc_value, 0, 4095, 40, 240);
|
||||||
last_bpm_read = now;
|
last_bpm_read = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metronome Button (Toggle)
|
|
||||||
if(readButton(PIN_B_METRONOME, btn_metronome))
|
if(readButton(PIN_B_METRONOME, btn_metronome))
|
||||||
{
|
{
|
||||||
metronome_enabled = !metronome_enabled;
|
metronome_enabled = !metronome_enabled;
|
||||||
@@ -243,55 +251,41 @@ void updateMetronome()
|
|||||||
|
|
||||||
if(!metronome_enabled)
|
if(!metronome_enabled)
|
||||||
{
|
{
|
||||||
digitalWrite(PIN_L_METRONOME, HIGH); // Active-low: HIGH = OFF
|
digitalWrite(PIN_L_METRONOME, HIGH);
|
||||||
metronome_led_on = false;
|
metronome_led_on = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!metronome_enabled) return;
|
if(!metronome_enabled) return;
|
||||||
|
|
||||||
// Berechne Beat-Intervall in ms
|
|
||||||
unsigned long beat_interval = 60000UL / current_bpm;
|
unsigned long beat_interval = 60000UL / current_bpm;
|
||||||
|
|
||||||
// Neue Beat?
|
|
||||||
if((now - last_beat_time) >= beat_interval)
|
if((now - last_beat_time) >= beat_interval)
|
||||||
{
|
{
|
||||||
digitalWrite(PIN_L_METRONOME, LOW); // Active-low: LOW = ON
|
digitalWrite(PIN_L_METRONOME, LOW);
|
||||||
metronome_led_on = true;
|
metronome_led_on = true;
|
||||||
last_beat_time = now;
|
last_beat_time = now;
|
||||||
last_pulse_end_time = now + 50; // 50ms Pulse
|
last_pulse_end_time = now + 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pulse beenden?
|
|
||||||
if(metronome_led_on && (now >= last_pulse_end_time))
|
if(metronome_led_on && (now >= last_pulse_end_time))
|
||||||
{
|
{
|
||||||
digitalWrite(PIN_L_METRONOME, HIGH); // Active-low: HIGH = OFF
|
digitalWrite(PIN_L_METRONOME, HIGH);
|
||||||
metronome_led_on = false;
|
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()
|
void updateRecordingLED()
|
||||||
{
|
{
|
||||||
// PIN_REC: Active-low (LOW = LED ON)
|
|
||||||
bool any_recording = sb1.isRecording() || sb2.isRecording();
|
bool any_recording = sb1.isRecording() || sb2.isRecording();
|
||||||
digitalWrite(PIN_REC, any_recording ? LOW : HIGH);
|
digitalWrite(PIN_REC, any_recording ? LOW : HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(BAUDRATE);
|
Serial.begin(BAUDRATE);
|
||||||
delay(2000);
|
delay(2000);
|
||||||
Serial.printf("\n\r=== COMPLETE VERSION with TODOs ===");
|
Serial.printf("\n\r=== DUAL SEQUENCER: SB1->VCO1 | SB2->VCO2 ===");
|
||||||
Serial.printf("\n\rSerial OK!");
|
Serial.printf("\n\rSerial OK!");
|
||||||
|
|
||||||
keyboard.begin();
|
keyboard.begin();
|
||||||
@@ -317,45 +311,43 @@ void setup()
|
|||||||
sb1.setLoop(false);
|
sb1.setLoop(false);
|
||||||
sb2.setLoop(false);
|
sb2.setLoop(false);
|
||||||
|
|
||||||
Serial.printf("\n\r=== Dual-Channel Sequencer System Started ===");
|
Serial.printf("\n\r=== System Started ===");
|
||||||
Serial.printf("\n\rFeatures:");
|
Serial.printf("\n\rMapping:");
|
||||||
Serial.printf("\n\r - VCO1/VCO2 Gate Outputs");
|
Serial.printf("\n\r SB1 -> VCO1 (CV-Ch 0) | SB2 -> VCO2 (CV-Ch 1)");
|
||||||
Serial.printf("\n\r - Recording LED Indicator");
|
Serial.printf("\n\rManual fallback:");
|
||||||
Serial.printf("\n\r - BPM Metronome (40-240 BPM)");
|
Serial.printf("\n\r SB1 playing, SB2 idle -> VCO2 manual (Queue[0])");
|
||||||
Serial.printf("\n\r==============================================\n\r");
|
Serial.printf("\n\r SB2 playing, SB1 idle -> VCO1 manual (Queue[0])");
|
||||||
|
Serial.printf("\n\r Both idle -> VCO1=Queue[0], VCO2=Queue[1]");
|
||||||
|
Serial.printf("\n\r=====================================\n\r");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
// ===== DEBUG HEARTBEAT =====
|
// DEBUG HEARTBEAT
|
||||||
static unsigned long lastDebugPrint = 0;
|
static unsigned long lastDebugPrint = 0;
|
||||||
static unsigned long loopCounter = 0;
|
static unsigned long loopCounter = 0;
|
||||||
|
|
||||||
loopCounter++;
|
loopCounter++;
|
||||||
|
|
||||||
if(millis() - lastDebugPrint > 5000)
|
if(millis() - lastDebugPrint > 5000)
|
||||||
{
|
{
|
||||||
Serial.printf("\n\r[HEARTBEAT] Loop: %lu | BPM: %d | Metro: %s",
|
Serial.printf("\n\r[HEARTBEAT] Loop: %lu | BPM: %d | Metro: %s",
|
||||||
loopCounter, current_bpm, metronome_enabled ? "ON" : "OFF");
|
loopCounter, current_bpm, metronome_enabled ? "ON" : "OFF");
|
||||||
Serial.printf("\n\r[DEBUG] SB1: Rec=%d, Play=%d, Steps=%d",
|
Serial.printf("\n\r[DEBUG] SB1->VCO1: Rec=%d, Play=%d, Steps=%d",
|
||||||
sb1.isRecording(), sb1.isPlaying(), sb1.getStepCount());
|
sb1.isRecording(), sb1.isPlaying(), sb1.getStepCount());
|
||||||
Serial.printf("\n\r[DEBUG] SB2: Rec=%d, Play=%d, Steps=%d",
|
Serial.printf("\n\r[DEBUG] SB2->VCO2: Rec=%d, Play=%d, Steps=%d",
|
||||||
sb2.isRecording(), sb2.isPlaying(), sb2.getStepCount());
|
sb2.isRecording(), sb2.isPlaying(), sb2.getStepCount());
|
||||||
lastDebugPrint = millis();
|
lastDebugPrint = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== NON-BLOCKING TIMING =====
|
// NON-BLOCKING TIMING
|
||||||
static unsigned long lastLoopTime = 0;
|
static unsigned long lastLoopTime = 0;
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
const unsigned long LOOP_INTERVAL = 10;
|
const unsigned long LOOP_INTERVAL = 10;
|
||||||
|
|
||||||
if((now - lastLoopTime) < LOOP_INTERVAL)
|
if((now - lastLoopTime) < LOOP_INTERVAL) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastLoopTime = now;
|
lastLoopTime = now;
|
||||||
|
|
||||||
// ===== UPDATE FUNCTIONS =====
|
// UPDATE
|
||||||
keyboard.update();
|
keyboard.update();
|
||||||
handleSequencerButtons();
|
handleSequencerButtons();
|
||||||
updateMetronome();
|
updateMetronome();
|
||||||
@@ -364,97 +356,150 @@ void loop()
|
|||||||
sb1.update();
|
sb1.update();
|
||||||
sb2.update();
|
sb2.update();
|
||||||
|
|
||||||
|
// KEYBOARD INPUT
|
||||||
int n = keyboard.getQueueLength();
|
int n = keyboard.getQueueLength();
|
||||||
|
|
||||||
// Aktuelle Spannungen ermitteln
|
// Key 0 -> wird als manueller Eingang für den jeweils freien VCO genutzt
|
||||||
uint16_t voltage_ch1 = 0;
|
uint16_t manual_voltage_0 = 0;
|
||||||
uint16_t voltage_ch2 = 0;
|
uint16_t manual_voltage_1 = 0;
|
||||||
bool cv1_active = false;
|
bool manual_active_0 = false;
|
||||||
bool cv2_active = false;
|
bool manual_active_1 = false;
|
||||||
|
|
||||||
if(n > 0)
|
if(n > 0)
|
||||||
{
|
{
|
||||||
Key k1 = keyboard.getQueue(0);
|
Key k = keyboard.getQueue(0);
|
||||||
if(!isNotKey(k1))
|
if(!isNotKey(k))
|
||||||
{
|
{
|
||||||
Serial.printf("\n\r[DEBUG] K1: R%iC%i", k1.row, k1.col);
|
manual_voltage_0 = keyToVoltage[k.row * N_KEYBOARD_COL + k.col];
|
||||||
voltage_ch1 = keyToVoltage[k1.row * N_KEYBOARD_COL + k1.col];
|
manual_active_0 = true;
|
||||||
cv1_active = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(n > 1)
|
if(n > 1)
|
||||||
{
|
{
|
||||||
Key k2 = keyboard.getQueue(1);
|
Key k = keyboard.getQueue(1);
|
||||||
if(!isNotKey(k2))
|
if(!isNotKey(k))
|
||||||
{
|
{
|
||||||
Serial.printf("\n\r[DEBUG] K2: R%iC%i", k2.row, k2.col);
|
manual_voltage_1 = keyToVoltage[k.row * N_KEYBOARD_COL + k.col];
|
||||||
voltage_ch2 = keyToVoltage[k2.row * N_KEYBOARD_COL + k2.col];
|
manual_active_1 = true;
|
||||||
cv2_active = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recording
|
// ===== RECORDING =====
|
||||||
bool voltageChanged = (voltage_ch1 != last_voltage_ch1) || (voltage_ch2 != last_voltage_ch2);
|
// SB1 nimmt immer ch1=manual_voltage_0 / ch2=manual_voltage_1 auf
|
||||||
|
// (SB1 ist für VCO1 zuständig, nutzt den vollen Keyboard-Input)
|
||||||
if(sb1.isRecording() && voltageChanged)
|
if(sb1.isRecording())
|
||||||
{
|
{
|
||||||
sb1.addStep(voltage_ch1, voltage_ch2);
|
bool changed = (manual_voltage_0 != sb1_last_voltage_ch1) ||
|
||||||
last_voltage_ch1 = voltage_ch1;
|
(manual_voltage_1 != sb1_last_voltage_ch2);
|
||||||
last_voltage_ch2 = voltage_ch2;
|
if(changed)
|
||||||
|
{
|
||||||
|
sb1.addStep(manual_voltage_0, manual_voltage_1);
|
||||||
|
sb1_last_voltage_ch1 = manual_voltage_0;
|
||||||
|
sb1_last_voltage_ch2 = manual_voltage_1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sb2.isRecording() && voltageChanged)
|
// SB2 nimmt ebenfalls den vollen Keyboard-Input auf
|
||||||
|
if(sb2.isRecording())
|
||||||
{
|
{
|
||||||
sb2.addStep(voltage_ch1, voltage_ch2);
|
bool changed = (manual_voltage_0 != sb2_last_voltage_ch1) ||
|
||||||
last_voltage_ch1 = voltage_ch1;
|
(manual_voltage_1 != sb2_last_voltage_ch2);
|
||||||
last_voltage_ch2 = voltage_ch2;
|
if(changed)
|
||||||
|
{
|
||||||
|
sb2.addStep(manual_voltage_0, manual_voltage_1);
|
||||||
|
sb2_last_voltage_ch1 = manual_voltage_0;
|
||||||
|
sb2_last_voltage_ch2 = manual_voltage_1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CV-Ausgabe & VCO Gates
|
// ===== CV OUTPUT & VCO GATES =====
|
||||||
if(sb1.isPlaying())
|
//
|
||||||
{
|
// SB1 state | SB2 state | VCO1 (ch 0) | VCO2 (ch 1)
|
||||||
uint16_t seq_v1 = sb1.getCurrentVoltageCh1();
|
// ------------|-------------|---------------------|----------------------
|
||||||
uint16_t seq_v2 = sb1.getCurrentVoltageCh2();
|
// playing | playing | SB1 seq voltage | SB2 seq voltage
|
||||||
cv.setVoltage(0, seq_v1);
|
// playing | recording | SB1 seq voltage | live manual Queue[0]
|
||||||
cv.setVoltage(1, seq_v2);
|
// playing | idle | SB1 seq voltage | live manual Queue[0]
|
||||||
|
// idle | playing | live manual Queue[0]| SB2 seq voltage
|
||||||
|
// idle | recording | live manual Queue[0]| live manual Queue[0]
|
||||||
|
// idle | idle | live manual Queue[0]| live manual Queue[1]
|
||||||
|
|
||||||
// KORREKT: Nutze isCurrentStepActive() statt Spannung > 0
|
bool sb1_playing = sb1.isPlaying();
|
||||||
// Da 0V eine gültige Note sein kann!
|
bool sb1_recording = sb1.isRecording();
|
||||||
bool gate_active = sb1.isCurrentStepActive();
|
bool sb2_playing = sb2.isPlaying();
|
||||||
updateVCOGates(gate_active, gate_active);
|
bool sb2_recording = sb2.isRecording();
|
||||||
|
|
||||||
|
uint16_t out_vco1 = 0;
|
||||||
|
uint16_t out_vco2 = 0;
|
||||||
|
bool gate_vco1 = false;
|
||||||
|
bool gate_vco2 = false;
|
||||||
|
|
||||||
|
// VCO1
|
||||||
|
if(sb1_playing)
|
||||||
|
{
|
||||||
|
// SB1 Sequenz läuft -> Sequenz-Ausgabe
|
||||||
|
out_vco1 = sb1.getCurrentVoltageCh1();
|
||||||
|
gate_vco1 = sb1.isCurrentStepActive();
|
||||||
}
|
}
|
||||||
else if(sb2.isPlaying())
|
else if(sb1_recording)
|
||||||
{
|
{
|
||||||
uint16_t seq_v1 = sb2.getCurrentVoltageCh1();
|
// SB1 nimmt auf -> Live-Ausgabe damit man hört was man spielt
|
||||||
uint16_t seq_v2 = sb2.getCurrentVoltageCh2();
|
out_vco1 = manual_voltage_0;
|
||||||
cv.setVoltage(0, seq_v1);
|
gate_vco1 = manual_active_0;
|
||||||
cv.setVoltage(1, seq_v2);
|
|
||||||
|
|
||||||
bool gate_active = sb2.isCurrentStepActive();
|
|
||||||
updateVCOGates(gate_active, gate_active);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Live-Modus: cv1_active/cv2_active basieren auf tatsächlich gedrückten Tasten
|
// SB1 idle -> manuell
|
||||||
cv.setVoltage(0, voltage_ch1);
|
out_vco1 = manual_voltage_0;
|
||||||
cv.setVoltage(1, voltage_ch2);
|
gate_vco1 = manual_active_0;
|
||||||
updateVCOGates(cv1_active, cv2_active);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time-Limit Check
|
// VCO2
|
||||||
|
if(sb2_playing)
|
||||||
|
{
|
||||||
|
// SB2 Sequenz läuft -> Sequenz-Ausgabe
|
||||||
|
out_vco2 = sb2.getCurrentVoltageCh1();
|
||||||
|
gate_vco2 = sb2.isCurrentStepActive();
|
||||||
|
}
|
||||||
|
else if(sb2_recording)
|
||||||
|
{
|
||||||
|
// SB2 nimmt auf -> Live-Ausgabe damit man hört was man spielt
|
||||||
|
out_vco2 = manual_voltage_0;
|
||||||
|
gate_vco2 = manual_active_0;
|
||||||
|
gate_vco1 = false;
|
||||||
|
}
|
||||||
|
else if(sb1_playing)
|
||||||
|
{
|
||||||
|
// SB1 läuft, SB2 idle -> VCO2 manuell mit Queue[0]
|
||||||
|
out_vco2 = manual_voltage_0;
|
||||||
|
gate_vco2 = manual_active_0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Beide idle -> VCO2 bekommt Queue[1]
|
||||||
|
out_vco2 = manual_voltage_1;
|
||||||
|
gate_vco2 = manual_active_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv.setVoltage(0, out_vco1); // CH_A -> VCO1
|
||||||
|
cv.setVoltage(1, out_vco2); // CH_B -> VCO2
|
||||||
|
|
||||||
|
digitalWrite(PIN_VCO1_EN, gate_vco1 ? HIGH : LOW);
|
||||||
|
digitalWrite(PIN_VCO2_EN, gate_vco2 ? HIGH : LOW);
|
||||||
|
|
||||||
|
// TIME-LIMIT CHECK
|
||||||
if(sb1.isRecording() && sb1.timeLimitReached())
|
if(sb1.isRecording() && sb1.timeLimitReached())
|
||||||
{
|
{
|
||||||
sb1.stopRecord();
|
sb1.stopRecord();
|
||||||
Serial.printf("\n\r[SEQ1] Time limit reached! Recording stopped.");
|
Serial.printf("\n\r[SEQ1->VCO1] Time limit reached! Recording stopped.");
|
||||||
Serial.printf("\n\r[SEQ1] Final: Steps: %i, Duration: %ims",
|
Serial.printf("\n\r[SEQ1->VCO1] Final: Steps: %i, Duration: %ims",
|
||||||
sb1.getStepCount(), sb1.getTotalDuration());
|
sb1.getStepCount(), sb1.getTotalDuration());
|
||||||
}
|
}
|
||||||
if(sb2.isRecording() && sb2.timeLimitReached())
|
if(sb2.isRecording() && sb2.timeLimitReached())
|
||||||
{
|
{
|
||||||
sb2.stopRecord();
|
sb2.stopRecord();
|
||||||
Serial.printf("\n\r[SEQ2] Time limit reached! Recording stopped.");
|
Serial.printf("\n\r[SEQ2->VCO2] Time limit reached! Recording stopped.");
|
||||||
Serial.printf("\n\r[SEQ2] Final: Steps: %i, Duration: %ims",
|
Serial.printf("\n\r[SEQ2->VCO2] Final: Steps: %i, Duration: %ims",
|
||||||
sb2.getStepCount(), sb2.getTotalDuration());
|
sb2.getStepCount(), sb2.getTotalDuration());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
dev/print/2_gehaeuse/OldVersions/connection.0007.ipt
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/connection.0007.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/connection_text.0002.ipt
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/connection_text.0002.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/housing.0039.iam
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/housing.0039.iam
Normal file
Binary file not shown.
61185
dev/print/test/connection.stp
Normal file
61185
dev/print/test/connection.stp
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
BIN
lit/USB-PD-ELKO.pdf
Normal file
BIN
lit/USB-PD-ELKO.pdf
Normal file
Binary file not shown.
BIN
lit/ds1117.pdf
Normal file
BIN
lit/ds1117.pdf
Normal file
Binary file not shown.
BIN
lit/lm2940c.pdf
Normal file
BIN
lit/lm2940c.pdf
Normal file
Binary file not shown.
Reference in New Issue
Block a user