mirror of
https://github.com/erik-toth/audio-synth.git
synced 2026-03-12 04:57:41 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c953f17090 | |||
| 04884bc243 | |||
|
|
d9964ced3e | ||
| 2108552078 | |||
| a7e466932b | |||
|
|
1216ea923c | ||
|
|
f2becb78b7 | ||
| 9e4ef1c330 | |||
| ff0396bf5d | |||
|
|
412badd8d2 | ||
|
|
300edffe49 | ||
|
|
5b4f9c49da | ||
|
|
b55b648522 | ||
|
|
0c22514679 | ||
| ef93262ed7 | |||
| 11e4eebd73 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,4 +7,4 @@ From : Project [TRI-SQR-VCO_OTA_SS.PrjPcb]
|
||||
Files Generated : 1
|
||||
Documents Printed : 0
|
||||
|
||||
Finished Output Generation At 14:24:51 On 11.12.2025
|
||||
Finished Output Generation At 14:45:26 On 03.02.2026
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
TRI-SQR-VCO_OTA_SS
|
||||
*SPICE Netlist generated by Advanced Sim server on 12.12.2025 14:46:42
|
||||
*SPICE Netlist generated by Advanced Sim server on 03.02.2026 15:26:41
|
||||
.options MixedSimGenerated
|
||||
|
||||
*Schematic Netlist:
|
||||
@@ -22,38 +22,30 @@ XIC3B U_SAW NetIC3_6 VAP 0 NetIC3_7 TL074
|
||||
XIC3C VCM NetIC3_9 VAP 0 U_C TL074
|
||||
XIC3D VCM NetIC3_13 VAP 0 U_CV TL074
|
||||
XIC4A R.VMID NetIC4_1 VAP 0 NetIC4_1 TL074
|
||||
RPTC NetPTC_1 U_C 1k
|
||||
RR2 0 U_TRI 20k
|
||||
RR3 VAP NetIC1_1 15k
|
||||
RR4a NetIC3_2 U_TRI 200k
|
||||
RR4b U_in NetIC3_2 100k
|
||||
RR_Aa NetR_Aa_1 U_SQR_OTA 3.3k
|
||||
RR_Ab VCM NetR_Aa_1 330R
|
||||
RR_CV_a NetR_CV_a_1 U_CV 120k
|
||||
RR_CV_b NetR_CV_b_1 NetR_CV_a_1 6.8k
|
||||
RR_CV_c NetR_CV_b_1 NetIC3_9 820R
|
||||
RR_COARSEA 0 NetR_COARSE_2 {100k * {COARSE}}
|
||||
RR_COARSEB NetR_COARSE_2 VAP {100k - (100k * {COARSE})}
|
||||
RR_CV_a NetIC3_9 U_C 1k
|
||||
RR_CV_b NetR_COARSE_2 NetIC3_9 47k
|
||||
RR_CV_c U_CV NetIC3_9 47k
|
||||
RR_CV_d NetIC3_9 NetR_CV_d_2 1Meg
|
||||
RR_E NetC_an_2 NetR_E_2 10k
|
||||
RR_FINEA 0 NetR_CV_d_2 {100k * {FINE}}
|
||||
RR_FINEB NetR_CV_d_2 VAP {100k - (100k * {FINE})}
|
||||
RR_inv_a NetIC2_8 NetIC3_13 10k
|
||||
RR_inv_b NetIC3_13 U_CV 10k
|
||||
RR_lambda_T_a NetIC3_9 NetR_lambda_T_a_2 1.2k
|
||||
RR_lambda_T_b NetR_lambda_T_a_2 NetPTC_1 100R
|
||||
RR_off_b NetIC2_9 NetIC2_8 10k
|
||||
RR_off_c_+0 VAP NetR_off_c_+0_2 10k
|
||||
RR_off_c_+1A VAP NetR_off_c_+1_2 {8330R * 0.5}
|
||||
RR_off_c_+1B NetR_off_c_+1_2 NetR_off_c_+1_2 {8330R - (8330R * 0.5)}
|
||||
RR_off_c_+1_vor VAP NetR_off_c_+1_vor_2 10k
|
||||
RR_off_c_+2A VAP NetR_off_c_+2_2 {7150R * 0.5}
|
||||
RR_off_c_+2B NetR_off_c_+2_2 NetR_off_c_+2_2 {7150R - (7150R * 0.5)}
|
||||
RR_off_c_-1A NetR_off_c_+1_vor_2 NetR_off_c_-1_2 {2.5k * 0.5}
|
||||
RR_off_c_-1B NetR_off_c_-1_2 NetR_off_c_-1_2 {2.5k - (2.5k * 0.5)}
|
||||
RR_off_c_sim VAP NetIC2_9 10k
|
||||
RR_off_d NetR_off_d_1 NetIC2_9 10k
|
||||
RR_POT_refA 0 NetR_POT_ref_2 {100k * 0.5}
|
||||
RR_POT_refB NetR_POT_ref_2 NetR_POT_ref_2 {100k - (100k * 0.5)}
|
||||
RR_POT_SAWA 0 0 {10k * 0.5}
|
||||
RR_POT_SAWB 0 NetR_POT_SAW_3 {10k - (10k * 0.5)}
|
||||
RR_POT_uC_compA 0 NetR_POT_uC_comp_2 {100k * {Q}}
|
||||
RR_POT_uC_compB NetR_POT_uC_comp_2 VAP {100k - (100k * {Q})}
|
||||
RR_PWM_a1 NetR_POT_SAW_3 NetIC3_6 10k
|
||||
RR_PWM_a2 NetR_POT_SAW_3 NetIC3_6 10k
|
||||
RR_PWM_b NetIC3_6 VAP 10k
|
||||
@@ -67,7 +59,6 @@ RR_SAW_b NetIC2_12 U_in 10k
|
||||
RR_SAW_c U_SAW NetIC2_13 10k
|
||||
RR_SAW_e U_SQR fet_gate 33k
|
||||
RR_SAW_f 0 fet_gate 100k
|
||||
RR_uC_comp NetIC3_9 NetR_POT_uC_comp_2 1Meg
|
||||
RRoff_a NetIC3_2 0 1Meg
|
||||
RRoff_b NetIC3_2 0 1Meg
|
||||
XT1 VCM NetC_an_2 NetC_an_1 U_C NetC_an_2 NetT1_6 DMMT3906W
|
||||
@@ -96,7 +87,8 @@ SWEEP U_var LIST 0 1 2
|
||||
.ENDC
|
||||
|
||||
*Global Parameters:
|
||||
.PARAM Q=0.5
|
||||
.PARAM COARSE={0.50}
|
||||
.PARAM FINE={0.3}
|
||||
|
||||
*Models and Subcircuits:
|
||||
* A dual opamp ngspice model
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
Filter_Test
|
||||
*SPICE Netlist generated by Advanced Sim server on 21.12.2025 21:14:32
|
||||
*SPICE Netlist generated by Advanced Sim server on 06.02.2026 11:30:06
|
||||
.options MixedSimGenerated
|
||||
|
||||
*Schematic Netlist:
|
||||
@@ -50,22 +50,24 @@ RR_hilfe2 NetIC2_2 NetIC2_1 100k
|
||||
VU_mess_abc NetIC3_16 NetR_abc_2 0
|
||||
VU_mess_abc1 NetIC1_16 NetR_abc_2 0
|
||||
VU_mess_abc2 NetIC1_1 NetR_abc_2 0
|
||||
VUe Uin VCM DC 0 SIN(0 3V 440Hz 0 0 0) AC 1 0
|
||||
VUe Uin VCM DC 0 SIN(0 0 440Hz 0 0 0) AC 1 0
|
||||
VUneg VCM 0 +5V
|
||||
VUpos VAP VCM +5V
|
||||
|
||||
.PLOT AC {dB(v(BP))} =PLOT(1) =AXIS(1) =NAME(Au_Uout) =UNITS(dB)
|
||||
.PLOT AC {dB(v(LP))} =PLOT(2) =AXIS(1) =NAME(Au_Uout2) =UNITS(dB)
|
||||
.PLOT AC {dB(v(HP))} =PLOT(3) =AXIS(1) =NAME(Au_HP) =UNITS(dB)
|
||||
.PLOT TRAN {v(div)} =PLOT(2) =AXIS(1) =NAME(div) =UNITS(V)
|
||||
.PLOT TRAN {i(U_mess_abc1)} =PLOT(3) =AXIS(1) =NAME(I_ABC1) =UNITS(A)
|
||||
.PLOT TRAN {i(U_mess_abc2)} =PLOT(3) =AXIS(1) =NAME(I_ABC2) =UNITS(A)
|
||||
.PLOT TRAN {i(U_mess_abc3)} =PLOT(3) =AXIS(1) =NAME(I_ABC3) =UNITS(A)
|
||||
.PLOT TRAN {v(Uin)} =PLOT(1) =AXIS(1) =NAME(U_E) =UNITS(V)
|
||||
|
||||
*Selected Circuit Analyses:
|
||||
.AC DEC 50 20 20k
|
||||
.TRAN 90.91u 11.36m 0 90.91u
|
||||
.CONTROL
|
||||
SWEEP Q LIST 0.002 0.01 0.1 1
|
||||
.ENDC
|
||||
|
||||
*Global Parameters:
|
||||
.PARAM Q=0.1
|
||||
.PARAM Q={0.1}
|
||||
|
||||
*Models and Subcircuits:
|
||||
* A dual opamp ngspice model
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
Output: Mixed Sim
|
||||
Type : AdvSimNetlist
|
||||
From : Project [Filter_Test.PrjPcb]
|
||||
Generated File[Filter_Test.nsx]
|
||||
|
||||
|
||||
Files Generated : 1
|
||||
Documents Printed : 0
|
||||
|
||||
Finished Output Generation At 11:26:55 On 06.02.2026
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,4 +7,4 @@ From : Project [VCA_LM13700.PrjPcb]
|
||||
Files Generated : 1
|
||||
Documents Printed : 0
|
||||
|
||||
Finished Output Generation At 13:07:34 On 14.12.2025
|
||||
Finished Output Generation At 11:31:57 On 06.02.2026
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
VCA_LM13700
|
||||
*SPICE Netlist generated by Advanced Sim server on 14.12.2025 13:07:43
|
||||
*SPICE Netlist generated by Advanced Sim server on 06.02.2026 11:37:11
|
||||
.options MixedSimGenerated
|
||||
|
||||
*Schematic Netlist:
|
||||
@@ -13,16 +13,19 @@ XIC1E NetIC1_16 NetIC1_15 NetIC1_14 NetIC1_13 OUT 0 OUT Uout ExtraNet_XIC1E_9
|
||||
+ ExtraNet_XIC1E_10 VAP ExtraNet_XIC1E_12 ExtraNet_XIC1E_13 ExtraNet_XIC1E_14
|
||||
+ ExtraNet_XIC1E_15 ExtraNet_XIC1E_16 LM13700-DUAL
|
||||
RR1 NetIC1_14 IN 3.3k
|
||||
RR2 OUT VCM 27k
|
||||
RR2a OUT NetR2a_2 20k
|
||||
RR2b NetR2a_2 VCM 6.8k
|
||||
RR3 Uout 0 5.1k
|
||||
RR4 VCM NetIC1_14 1.2k
|
||||
RR5 VCM NetIC1_13 1.2k
|
||||
RR_B NetR_B_1 NetR_B_2 100k
|
||||
RR_BASE_GAIN NetIC1_16 NetR_BASE_GAIN_2 10k
|
||||
RR_D VAP NetIC1_15 5.1k
|
||||
QT VAP NetR_B_1 NetR_BASE_GAIN_2 QBC547B
|
||||
RR_GAINA NetR_BASE_GAIN_2 NetR_BASE_GAIN_2 {100k * {GAIN}}
|
||||
RR_GAINB NetR_BASE_GAIN_2 U_ABC {100k - (100k * {GAIN})}
|
||||
QT VAP NetR_B_1 U_ABC QBC547B
|
||||
VU_VCO_EN NetR_B_2 0 DC 0 PULSE(3.3 0 0 4u 1u 20m 40m) AC 1 0
|
||||
VUin IN VCM DC 0 SIN(0 2V 440Hz 0 0 0) AC 1 0
|
||||
VUin IN VCM DC 0 SIN(0 0 440Hz 0 0 0) AC 1 0
|
||||
VUneg VCM 0 +5V
|
||||
VUpos VAP VCM +5V
|
||||
|
||||
@@ -34,6 +37,7 @@ VUpos VAP VCM +5V
|
||||
.PLOT TRAN {i(R5)} =PLOT(6) =AXIS(1) =NAME(I_5) =UNITS(A)
|
||||
.PLOT TRAN {i(R4)} =PLOT(6) =AXIS(1) =NAME(I_4) =UNITS(A)
|
||||
.PLOT TRAN {2*(v(Uout)*0.663)} =PLOT(2) =AXIS(1) =NAME(Uout_buffer) =UNITS(V)
|
||||
.PLOT TRAN {v(U_ABC)} =PLOT(7) =AXIS(1) =NAME(U_ABC) =UNITS(V)
|
||||
|
||||
.OPTIONS METHOD=GEAR MAXORD=2
|
||||
*Selected Circuit Analyses:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
@author: Erik Tóth
|
||||
@contact: etoth@tsn.at
|
||||
@date: 2025-10-26
|
||||
@updated: 2025-12-06
|
||||
@updated: 2026-03-08
|
||||
@brief: Header for constant definitions
|
||||
*/
|
||||
|
||||
@@ -12,38 +12,38 @@
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
// CONSTANTS DEFINITONS
|
||||
#define N_KEYBOARD_ROW 5 // for PROD. change to 5
|
||||
#define N_KEYBOARD_COL 5 // for PROD. change to 5
|
||||
#define N_CV_GATES 2 // PROD. OK
|
||||
#define N_SB 2 // PROD. OK
|
||||
#define N_KEYBOARD_ROW 5
|
||||
#define N_KEYBOARD_COL 5
|
||||
#define N_CV_GATES 2
|
||||
#define N_SB 2
|
||||
#define BAUDRATE 115200
|
||||
#define N_MAX_SEQ_STEPS 512
|
||||
// PIN DEFENTITIONS
|
||||
// I2C PINS
|
||||
#define PIN_SDA 15 // PROD. pin OK
|
||||
#define PIN_SCL 16 // PROD. pin OK
|
||||
#define PIN_SDA 15
|
||||
#define PIN_SCL 16
|
||||
// KEYBOARD PINS
|
||||
#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
|
||||
#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
|
||||
#define PIN_K_C0 1
|
||||
#define PIN_K_C1 2
|
||||
#define PIN_K_C2 4
|
||||
#define PIN_K_C3 5
|
||||
#define PIN_K_C4 6
|
||||
// SEQUENCER BUTTON PINS
|
||||
#define PIN_SB_1_REC 33 // for PROD. change to 33 / not available on dev board
|
||||
#define PIN_SB_1_PLAY 34 // for PROD. change to 34 / not available on dev board
|
||||
#define PIN_SB_2_REC 35 // 35
|
||||
#define PIN_SB_2_PLAY 36 // 36
|
||||
#define PIN_SB_1_REC 33
|
||||
#define PIN_SB_1_PLAY 34
|
||||
#define PIN_SB_2_REC 35
|
||||
#define PIN_SB_2_PLAY 36
|
||||
// MISC/INFO PINS
|
||||
#define PIN_VCO1_EN 37 // PROD. pin 37 TODO: if there is an active key mapped to CV-Gate 1 --> HIGH
|
||||
#define PIN_VCO2_EN 38 // 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)
|
||||
#define PIN_VCO1_EN 38
|
||||
#define PIN_VCO2_EN 39
|
||||
#define PIN_REC 37
|
||||
#define PIN_BPM 12
|
||||
#define PIN_B_METRONOME 14
|
||||
#define PIN_L_METRONOME 13
|
||||
|
||||
#endif
|
||||
@@ -3,13 +3,13 @@
|
||||
@author: Erik Tóth
|
||||
@contact: etoth@tsn.at
|
||||
@date: 2025-10-26
|
||||
@updated: 2025-12-06
|
||||
@brief: Firmware für MCU - FIXED VERSION mit Bounds Checks
|
||||
@updated: 2026-03-08
|
||||
@brief: Firmware für MCU
|
||||
*/
|
||||
|
||||
#include "FIRMWARE.h"
|
||||
|
||||
// ==================== Helper-Functions ====================
|
||||
// Helper-Functions
|
||||
|
||||
bool isNotKey(Key k)
|
||||
{
|
||||
@@ -23,7 +23,7 @@ bool isEqualKey(Key k1, Key k2)
|
||||
else return false;
|
||||
}
|
||||
|
||||
// ==================== Keyboard ====================
|
||||
// Keyboard
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -209,7 +209,7 @@ void CV::setVoltage(uint8_t cvIndex, uint16_t mV)
|
||||
{
|
||||
if(cvIndex >= _nCV) return;
|
||||
MCP4728_channel_t ch = _cvChannelMap[cvIndex];
|
||||
_dac->setChannelValue(ch, map(mV, 0, 2048, 0, 4095), 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)
|
||||
@@ -234,7 +234,7 @@ uint8_t CV::_getKeyToVoltageIndex(Key k)
|
||||
return (k.row*_col + k.col);
|
||||
}
|
||||
|
||||
// ==================== SequencerBlock (FIXED) ====================
|
||||
// SequencerBlock
|
||||
|
||||
/*!
|
||||
* @param maxDurationMS maximum loop duration of recording in milliseconds
|
||||
@@ -255,7 +255,7 @@ SequencerBlock::SequencerBlock(uint16_t maxDurationMS, uint16_t maxStepCount)
|
||||
_lastStepTime = 0;
|
||||
_playStartTime = 0;
|
||||
_stepStartTime = 0;
|
||||
_lastAddStepTime = 0; // NEU: Rate-Limiting
|
||||
_lastAddStepTime = 0;
|
||||
}
|
||||
|
||||
void SequencerBlock::startRecord()
|
||||
@@ -266,7 +266,7 @@ void SequencerBlock::startRecord()
|
||||
_isRecording = true;
|
||||
_recordStartTime = millis();
|
||||
_lastStepTime = _recordStartTime;
|
||||
_lastAddStepTime = _recordStartTime; // NEU
|
||||
_lastAddStepTime = _recordStartTime;
|
||||
_lastVoltageCh1 = 0xFFFF;
|
||||
_lastVoltageCh2 = 0xFFFF;
|
||||
}
|
||||
@@ -281,10 +281,8 @@ void SequencerBlock::stopRecord()
|
||||
|
||||
void SequencerBlock::addStep(uint16_t voltage_ch1, uint16_t voltage_ch2)
|
||||
{
|
||||
// KRITISCHE SICHERHEITSPRÜFUNGEN ZUERST
|
||||
if(!_isRecording) return;
|
||||
|
||||
// Prüfe ob wir überhaupt noch Platz haben (mit Sicherheitsabstand!)
|
||||
if(_stepCount >= _MAX_SEQUENCE_STEPS - 1)
|
||||
{
|
||||
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();
|
||||
|
||||
// NEU: Rate-Limiting - ignoriere zu häufige Aufrufe
|
||||
if((unsigned long)(now - _lastAddStepTime) < 5)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_lastAddStepTime = now;
|
||||
|
||||
// Hat sich die Spannung geändert?
|
||||
bool voltageChanged = (voltage_ch1 != _lastVoltageCh1) || (voltage_ch2 != _lastVoltageCh2);
|
||||
|
||||
if(voltageChanged)
|
||||
{
|
||||
// WICHTIG: Prüfe nochmal ob wir Platz haben BEVOR wir schreiben!
|
||||
if(_stepCount >= _MAX_SEQUENCE_STEPS - 1)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// Vorherigen Step abschließen (wenn vorhanden)
|
||||
if(_stepCount > 0 && _stepCount <= _MAX_SEQUENCE_STEPS)
|
||||
{
|
||||
_finishCurrentStep();
|
||||
}
|
||||
|
||||
// Neuen Step beginnen - mit Bounds Check!
|
||||
if(_stepCount < _MAX_SEQUENCE_STEPS)
|
||||
{
|
||||
_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
|
||||
_sequence[_stepCount].active = (voltage_ch1 > 0 || voltage_ch2 > 0);
|
||||
_stepCount++;
|
||||
|
||||
_lastStepTime = now;
|
||||
@@ -343,8 +336,6 @@ void SequencerBlock::addStep(uint16_t voltage_ch1, uint16_t voltage_ch2)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Gleiche Spannung - Duration des aktuellen Steps aktualisieren
|
||||
// WICHTIG: Bounds Check!
|
||||
if(_stepCount > 0 && _stepCount <= _MAX_SEQUENCE_STEPS)
|
||||
{
|
||||
_sequence[_stepCount - 1].duration = now - _lastStepTime;
|
||||
@@ -378,7 +369,6 @@ void SequencerBlock::update()
|
||||
{
|
||||
if(!_isPlaying || _stepCount == 0) return;
|
||||
|
||||
// WICHTIG: Bounds Check BEVOR wir auf Array zugreifen!
|
||||
if(_currentStep >= _stepCount || _currentStep >= _MAX_SEQUENCE_STEPS)
|
||||
{
|
||||
Serial.println("\n\r[ERROR] Invalid step index in update()!");
|
||||
@@ -389,7 +379,6 @@ void SequencerBlock::update()
|
||||
unsigned long now = millis();
|
||||
unsigned long elapsed = now - _stepStartTime;
|
||||
|
||||
// Sicherung gegen Division durch Null / Endlosschleife
|
||||
if(_sequence[_currentStep].duration == 0)
|
||||
{
|
||||
_currentStep++;
|
||||
@@ -409,12 +398,10 @@ void SequencerBlock::update()
|
||||
return;
|
||||
}
|
||||
|
||||
// Prüfen ob aktueller Schritt abgelaufen ist
|
||||
if(elapsed >= _sequence[_currentStep].duration)
|
||||
{
|
||||
_currentStep++;
|
||||
|
||||
// Sequenz-Ende erreicht?
|
||||
if(_currentStep >= _stepCount)
|
||||
{
|
||||
if(_loop)
|
||||
@@ -447,7 +434,6 @@ void SequencerBlock::clear()
|
||||
_lastVoltageCh1 = 0;
|
||||
_lastVoltageCh2 = 0;
|
||||
|
||||
// Optional: Array löschen (kann je nach Use-Case weggelassen werden)
|
||||
for(uint16_t i = 0; i < _MAX_SEQUENCE_STEPS; i++)
|
||||
{
|
||||
_sequence[i].voltage_ch1 = 0;
|
||||
@@ -500,7 +486,7 @@ uint16_t SequencerBlock::getCurrentVoltageCh2()
|
||||
|
||||
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++)
|
||||
{
|
||||
total += _sequence[i].duration;
|
||||
@@ -519,7 +505,7 @@ bool SequencerBlock::isCurrentStepActive()
|
||||
void SequencerBlock::_finishCurrentStep()
|
||||
{
|
||||
if(_stepCount == 0) return;
|
||||
if(_stepCount > _MAX_SEQUENCE_STEPS) return; // Sicherheitsprüfung
|
||||
if(_stepCount > _MAX_SEQUENCE_STEPS) return;
|
||||
|
||||
unsigned long now = millis();
|
||||
uint16_t duration = now - _lastStepTime;
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
/*
|
||||
* Example Code Three - Dual Channel Sequencer (COMPLETE)
|
||||
* - Alle TODOs implementiert
|
||||
* - VCO Gates, Recording LED, Metronome
|
||||
* Analoger Audiosynthesizer mit digitaler Steuereinheit
|
||||
* Firmware-Code für die digitale Einheit
|
||||
* Autor: Erik Tóth
|
||||
*/
|
||||
#include "FIRMWARE_DEF.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_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;
|
||||
MCP4728_channel_t cvMap[N_CV_GATES] = {MCP4728_CHANNEL_A, MCP4728_CHANNEL_B};
|
||||
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = {
|
||||
1*83, 6*83, 11*83, 16*83, 21*83,
|
||||
2*83, 7*83, 12*83, 17*83, 22*83,
|
||||
3*83, 8*83, 13*83, 18*83, 23*83,
|
||||
4*83, 9*83, 14*83, 19*83, 24*83,
|
||||
5*83, 10*83, 15*83, 20*83, 25*83
|
||||
HLFSTEP(0), HLFSTEP(1), HLFSTEP(2), HLFSTEP(3), HLFSTEP(4),
|
||||
HLFSTEP(5), HLFSTEP(6), HLFSTEP(7), HLFSTEP(8), HLFSTEP(9),
|
||||
HLFSTEP(10), HLFSTEP(11), HLFSTEP(12), HLFSTEP(13), HLFSTEP(14),
|
||||
HLFSTEP(15), HLFSTEP(16), HLFSTEP(17), HLFSTEP(18), HLFSTEP(19),
|
||||
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);
|
||||
|
||||
// SB1 -> VCO1 (CV-Channel 0), SB2 -> VCO2 (CV-Channel 1)
|
||||
SequencerBlock sb1(30000, N_MAX_SEQ_STEPS);
|
||||
SequencerBlock sb2(30000, N_MAX_SEQ_STEPS);
|
||||
|
||||
@@ -43,12 +54,16 @@ const unsigned long DEBOUNCE_DELAY = 50;
|
||||
|
||||
static bool seq1_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 reading = digitalRead(pin) == LOW;
|
||||
bool reading = digitalRead(pin) == HIGH;
|
||||
bool buttonPressed = false;
|
||||
|
||||
if(reading != state.last)
|
||||
@@ -74,11 +89,11 @@ bool readButton(byte pin, ButtonState &state)
|
||||
|
||||
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);
|
||||
pinMode(PIN_B_METRONOME, INPUT_PULLUP);
|
||||
pinMode(PIN_SB_1_REC, INPUT_PULLDOWN);
|
||||
pinMode(PIN_SB_1_PLAY, INPUT_PULLDOWN);
|
||||
pinMode(PIN_SB_2_REC, INPUT_PULLDOWN);
|
||||
pinMode(PIN_SB_2_PLAY, INPUT_PULLDOWN);
|
||||
pinMode(PIN_B_METRONOME, INPUT_PULLDOWN);
|
||||
|
||||
btn_sb1_rec.current = false;
|
||||
btn_sb1_rec.last = false;
|
||||
@@ -123,26 +138,24 @@ void initOutputs()
|
||||
|
||||
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",
|
||||
Serial.printf("\n\r[SEQ1->VCO1] Recording stopped. Steps: %i, Duration: %ims",
|
||||
sb1.getStepCount(), sb1.getTotalDuration());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sb1.isPlaying()) sb1.stopPlay();
|
||||
sb1.startRecord();
|
||||
last_voltage_ch1 = 0xFFFF;
|
||||
last_voltage_ch2 = 0xFFFF;
|
||||
Serial.printf("\n\r[SEQ1] Recording started (2 channels)...");
|
||||
sb1_last_voltage_ch1 = 0xFFFF;
|
||||
sb1_last_voltage_ch2 = 0xFFFF;
|
||||
Serial.printf("\n\r[SEQ1->VCO1] Recording started...");
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Sequencer 1 Play Button =====
|
||||
if(readButton(PIN_SB_1_PLAY, btn_sb1_play))
|
||||
{
|
||||
if(!sb1.isPlaying())
|
||||
@@ -151,43 +164,41 @@ void handleSequencerButtons()
|
||||
sb1.setLoop(false);
|
||||
seq1_loop_active = false;
|
||||
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());
|
||||
}
|
||||
else if(!seq1_loop_active)
|
||||
{
|
||||
sb1.setLoop(true);
|
||||
seq1_loop_active = true;
|
||||
Serial.printf("\n\r[SEQ1] Loop activated");
|
||||
Serial.printf("\n\r[SEQ1->VCO1] Loop activated");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb1.stopPlay();
|
||||
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(sb2.isRecording())
|
||||
{
|
||||
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());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sb2.isPlaying()) sb2.stopPlay();
|
||||
sb2.startRecord();
|
||||
last_voltage_ch1 = 0xFFFF;
|
||||
last_voltage_ch2 = 0xFFFF;
|
||||
Serial.printf("\n\r[SEQ2] Recording started (2 channels)...");
|
||||
sb2_last_voltage_ch1 = 0xFFFF;
|
||||
sb2_last_voltage_ch2 = 0xFFFF;
|
||||
Serial.printf("\n\r[SEQ2->VCO2] Recording started...");
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Sequencer 2 Play Button =====
|
||||
if(readButton(PIN_SB_2_PLAY, btn_sb2_play))
|
||||
{
|
||||
if(!sb2.isPlaying())
|
||||
@@ -196,20 +207,20 @@ void handleSequencerButtons()
|
||||
sb2.setLoop(false);
|
||||
seq2_loop_active = false;
|
||||
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());
|
||||
}
|
||||
else if(!seq2_loop_active)
|
||||
{
|
||||
sb2.setLoop(true);
|
||||
seq2_loop_active = true;
|
||||
Serial.printf("\n\r[SEQ2] Loop activated");
|
||||
Serial.printf("\n\r[SEQ2->VCO2] Loop activated");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb2.stopPlay();
|
||||
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();
|
||||
|
||||
// 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;
|
||||
@@ -243,55 +251,41 @@ void updateMetronome()
|
||||
|
||||
if(!metronome_enabled)
|
||||
{
|
||||
digitalWrite(PIN_L_METRONOME, HIGH); // Active-low: HIGH = OFF
|
||||
digitalWrite(PIN_L_METRONOME, HIGH);
|
||||
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
|
||||
digitalWrite(PIN_L_METRONOME, LOW);
|
||||
metronome_led_on = true;
|
||||
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))
|
||||
{
|
||||
digitalWrite(PIN_L_METRONOME, HIGH); // Active-low: HIGH = OFF
|
||||
digitalWrite(PIN_L_METRONOME, HIGH);
|
||||
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=== COMPLETE VERSION with TODOs ===");
|
||||
Serial.printf("\n\r=== DUAL SEQUENCER: SB1->VCO1 | SB2->VCO2 ===");
|
||||
Serial.printf("\n\rSerial OK!");
|
||||
|
||||
keyboard.begin();
|
||||
@@ -317,45 +311,43 @@ void setup()
|
||||
sb1.setLoop(false);
|
||||
sb2.setLoop(false);
|
||||
|
||||
Serial.printf("\n\r=== Dual-Channel Sequencer System Started ===");
|
||||
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");
|
||||
Serial.printf("\n\r=== System Started ===");
|
||||
Serial.printf("\n\rMapping:");
|
||||
Serial.printf("\n\r SB1 -> VCO1 (CV-Ch 0) | SB2 -> VCO2 (CV-Ch 1)");
|
||||
Serial.printf("\n\rManual fallback:");
|
||||
Serial.printf("\n\r SB1 playing, SB2 idle -> VCO2 manual (Queue[0])");
|
||||
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()
|
||||
{
|
||||
// ===== DEBUG HEARTBEAT =====
|
||||
// DEBUG HEARTBEAT
|
||||
static unsigned long lastDebugPrint = 0;
|
||||
static unsigned long loopCounter = 0;
|
||||
|
||||
loopCounter++;
|
||||
|
||||
if(millis() - lastDebugPrint > 5000)
|
||||
{
|
||||
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",
|
||||
Serial.printf("\n\r[DEBUG] SB1->VCO1: Rec=%d, Play=%d, Steps=%d",
|
||||
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());
|
||||
lastDebugPrint = millis();
|
||||
}
|
||||
|
||||
// ===== NON-BLOCKING TIMING =====
|
||||
// NON-BLOCKING TIMING
|
||||
static unsigned long lastLoopTime = 0;
|
||||
unsigned long now = millis();
|
||||
const unsigned long LOOP_INTERVAL = 10;
|
||||
|
||||
if((now - lastLoopTime) < LOOP_INTERVAL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if((now - lastLoopTime) < LOOP_INTERVAL) return;
|
||||
lastLoopTime = now;
|
||||
|
||||
// ===== UPDATE FUNCTIONS =====
|
||||
// UPDATE
|
||||
keyboard.update();
|
||||
handleSequencerButtons();
|
||||
updateMetronome();
|
||||
@@ -364,97 +356,150 @@ void loop()
|
||||
sb1.update();
|
||||
sb2.update();
|
||||
|
||||
// KEYBOARD INPUT
|
||||
int n = keyboard.getQueueLength();
|
||||
|
||||
// Aktuelle Spannungen ermitteln
|
||||
uint16_t voltage_ch1 = 0;
|
||||
uint16_t voltage_ch2 = 0;
|
||||
bool cv1_active = false;
|
||||
bool cv2_active = false;
|
||||
// Key 0 -> wird als manueller Eingang für den jeweils freien VCO genutzt
|
||||
uint16_t manual_voltage_0 = 0;
|
||||
uint16_t manual_voltage_1 = 0;
|
||||
bool manual_active_0 = false;
|
||||
bool manual_active_1 = false;
|
||||
|
||||
if(n > 0)
|
||||
{
|
||||
Key k1 = keyboard.getQueue(0);
|
||||
if(!isNotKey(k1))
|
||||
Key k = keyboard.getQueue(0);
|
||||
if(!isNotKey(k))
|
||||
{
|
||||
Serial.printf("\n\r[DEBUG] K1: R%iC%i", k1.row, k1.col);
|
||||
voltage_ch1 = keyToVoltage[k1.row * N_KEYBOARD_COL + k1.col];
|
||||
cv1_active = true;
|
||||
manual_voltage_0 = keyToVoltage[k.row * N_KEYBOARD_COL + k.col];
|
||||
manual_active_0 = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(n > 1)
|
||||
{
|
||||
Key k2 = keyboard.getQueue(1);
|
||||
if(!isNotKey(k2))
|
||||
Key k = keyboard.getQueue(1);
|
||||
if(!isNotKey(k))
|
||||
{
|
||||
Serial.printf("\n\r[DEBUG] K2: R%iC%i", k2.row, k2.col);
|
||||
voltage_ch2 = keyToVoltage[k2.row * N_KEYBOARD_COL + k2.col];
|
||||
cv2_active = true;
|
||||
manual_voltage_1 = keyToVoltage[k.row * N_KEYBOARD_COL + k.col];
|
||||
manual_active_1 = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== RECORDING =====
|
||||
// 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())
|
||||
{
|
||||
bool changed = (manual_voltage_0 != sb1_last_voltage_ch1) ||
|
||||
(manual_voltage_1 != sb1_last_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;
|
||||
}
|
||||
}
|
||||
|
||||
// Recording
|
||||
bool voltageChanged = (voltage_ch1 != last_voltage_ch1) || (voltage_ch2 != last_voltage_ch2);
|
||||
|
||||
if(sb1.isRecording() && voltageChanged)
|
||||
// SB2 nimmt ebenfalls den vollen Keyboard-Input auf
|
||||
if(sb2.isRecording())
|
||||
{
|
||||
sb1.addStep(voltage_ch1, voltage_ch2);
|
||||
last_voltage_ch1 = voltage_ch1;
|
||||
last_voltage_ch2 = voltage_ch2;
|
||||
bool changed = (manual_voltage_0 != sb2_last_voltage_ch1) ||
|
||||
(manual_voltage_1 != sb2_last_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;
|
||||
}
|
||||
}
|
||||
|
||||
if(sb2.isRecording() && voltageChanged)
|
||||
|
||||
// ===== CV OUTPUT & VCO GATES =====
|
||||
//
|
||||
// SB1 state | SB2 state | VCO1 (ch 0) | VCO2 (ch 1)
|
||||
// ------------|-------------|---------------------|----------------------
|
||||
// playing | playing | SB1 seq voltage | SB2 seq voltage
|
||||
// playing | recording | SB1 seq voltage | live manual Queue[0]
|
||||
// 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]
|
||||
|
||||
bool sb1_playing = sb1.isPlaying();
|
||||
bool sb1_recording = sb1.isRecording();
|
||||
bool sb2_playing = sb2.isPlaying();
|
||||
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)
|
||||
{
|
||||
sb2.addStep(voltage_ch1, voltage_ch2);
|
||||
last_voltage_ch1 = voltage_ch1;
|
||||
last_voltage_ch2 = voltage_ch2;
|
||||
// SB1 Sequenz läuft -> Sequenz-Ausgabe
|
||||
out_vco1 = sb1.getCurrentVoltageCh1();
|
||||
gate_vco1 = sb1.isCurrentStepActive();
|
||||
}
|
||||
|
||||
// CV-Ausgabe & VCO Gates
|
||||
if(sb1.isPlaying())
|
||||
else if(sb1_recording)
|
||||
{
|
||||
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())
|
||||
{
|
||||
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);
|
||||
// SB1 nimmt auf -> Live-Ausgabe damit man hört was man spielt
|
||||
out_vco1 = manual_voltage_0;
|
||||
gate_vco1 = manual_active_0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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);
|
||||
// SB1 idle -> manuell
|
||||
out_vco1 = manual_voltage_0;
|
||||
gate_vco1 = manual_active_0;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Time-Limit Check
|
||||
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())
|
||||
{
|
||||
sb1.stopRecord();
|
||||
Serial.printf("\n\r[SEQ1] Time limit reached! Recording stopped.");
|
||||
Serial.printf("\n\r[SEQ1] Final: Steps: %i, Duration: %ims",
|
||||
Serial.printf("\n\r[SEQ1->VCO1] Time limit reached! Recording stopped.");
|
||||
Serial.printf("\n\r[SEQ1->VCO1] Final: Steps: %i, Duration: %ims",
|
||||
sb1.getStepCount(), sb1.getTotalDuration());
|
||||
}
|
||||
if(sb2.isRecording() && sb2.timeLimitReached())
|
||||
{
|
||||
sb2.stopRecord();
|
||||
Serial.printf("\n\r[SEQ2] Time limit reached! Recording stopped.");
|
||||
Serial.printf("\n\r[SEQ2] Final: Steps: %i, Duration: %ims",
|
||||
Serial.printf("\n\r[SEQ2->VCO2] Time limit reached! Recording stopped.");
|
||||
Serial.printf("\n\r[SEQ2->VCO2] Final: Steps: %i, Duration: %ims",
|
||||
sb2.getStepCount(), sb2.getTotalDuration());
|
||||
}
|
||||
}
|
||||
Binary file not shown.
BIN
dev/print/1_tasten/OldVersions/cut_left.0002.ipt
Normal file
BIN
dev/print/1_tasten/OldVersions/cut_left.0002.ipt
Normal file
Binary file not shown.
BIN
dev/print/1_tasten/OldVersions/cut_right.0004.ipt
Normal file
BIN
dev/print/1_tasten/OldVersions/cut_right.0004.ipt
Normal file
Binary file not shown.
BIN
dev/print/1_tasten/OldVersions/half_new.0003.ipt
Normal file
BIN
dev/print/1_tasten/OldVersions/half_new.0003.ipt
Normal file
Binary file not shown.
BIN
dev/print/1_tasten/OldVersions/mid_new.0002.ipt
Normal file
BIN
dev/print/1_tasten/OldVersions/mid_new.0002.ipt
Normal file
Binary file not shown.
BIN
dev/print/1_tasten/OldVersions/note.0006.ipt
Normal file
BIN
dev/print/1_tasten/OldVersions/note.0006.ipt
Normal file
Binary file not shown.
BIN
dev/print/1_tasten/OldVersions/notes.0008.iam
Normal file
BIN
dev/print/1_tasten/OldVersions/notes.0008.iam
Normal file
Binary file not shown.
BIN
dev/print/1_tasten/cut_left.ipt
Normal file
BIN
dev/print/1_tasten/cut_left.ipt
Normal file
Binary file not shown.
BIN
dev/print/1_tasten/cut_right.ipt
Normal file
BIN
dev/print/1_tasten/cut_right.ipt
Normal file
Binary file not shown.
BIN
dev/print/1_tasten/half_new.ipt
Normal file
BIN
dev/print/1_tasten/half_new.ipt
Normal file
Binary file not shown.
BIN
dev/print/1_tasten/mid_new.ipt
Normal file
BIN
dev/print/1_tasten/mid_new.ipt
Normal file
Binary file not shown.
Binary file not shown.
BIN
dev/print/1_tasten/notes.iam
Normal file
BIN
dev/print/1_tasten/notes.iam
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/Schneckel.0004.iam
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/Schneckel.0004.iam
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/button_mount_neu.0002.ipt
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/button_mount_neu.0002.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/connection.0004.iam
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/connection.0004.iam
Normal file
Binary file not shown.
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/frontplane_left.0005.iam
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/frontplane_left.0005.iam
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/frontplane_left.0006.iam
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/frontplane_left.0006.iam
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/frontplane_right.0001.iam
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/frontplane_right.0001.iam
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_left.0015.iam
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_left.0015.iam
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_left_base.0029.ipt
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_left_base.0029.ipt
Normal file
Binary file not shown.
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_left_text.0010.ipt
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_left_text.0010.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_right.0008.iam
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_right.0008.iam
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_right_base.0029.ipt
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_right_base.0029.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_right_text.0006.ipt
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/frontplate_right_text.0006.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/housing.0008.ipt
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/housing.0008.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.
BIN
dev/print/2_gehaeuse/OldVersions/housing.0052.iam
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/housing.0052.iam
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/housing_base.0030.ipt
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/housing_base.0030.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/OldVersions/schriftzug_neu.0001.ipt
Normal file
BIN
dev/print/2_gehaeuse/OldVersions/schriftzug_neu.0001.ipt
Normal file
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
dev/print/2_gehaeuse/connection.iam
Normal file
BIN
dev/print/2_gehaeuse/connection.iam
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/connection.ipt
Normal file
BIN
dev/print/2_gehaeuse/connection.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/connection_text.ipt
Normal file
BIN
dev/print/2_gehaeuse/connection_text.ipt
Normal file
Binary file not shown.
Binary file not shown.
BIN
dev/print/2_gehaeuse/frontplate_left.iam
Normal file
BIN
dev/print/2_gehaeuse/frontplate_left.iam
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/frontplate_left_base.ipt
Normal file
BIN
dev/print/2_gehaeuse/frontplate_left_base.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/frontplate_left_button_mount.ipt
Normal file
BIN
dev/print/2_gehaeuse/frontplate_left_button_mount.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/frontplate_left_text.ipt
Normal file
BIN
dev/print/2_gehaeuse/frontplate_left_text.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/frontplate_right.iam
Normal file
BIN
dev/print/2_gehaeuse/frontplate_right.iam
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/frontplate_right_base.ipt
Normal file
BIN
dev/print/2_gehaeuse/frontplate_right_base.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/frontplate_right_text.ipt
Normal file
BIN
dev/print/2_gehaeuse/frontplate_right_text.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/housing.iam
Normal file
BIN
dev/print/2_gehaeuse/housing.iam
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/housing_base.ipt
Normal file
BIN
dev/print/2_gehaeuse/housing_base.ipt
Normal file
Binary file not shown.
BIN
dev/print/2_gehaeuse/rod.ipt
Normal file
BIN
dev/print/2_gehaeuse/rod.ipt
Normal file
Binary file not shown.
BIN
dev/print/4_caps/OldVersions/caps.0004.iam
Normal file
BIN
dev/print/4_caps/OldVersions/caps.0004.iam
Normal file
Binary file not shown.
BIN
dev/print/4_caps/OldVersions/poti_cap.0003.ipt
Normal file
BIN
dev/print/4_caps/OldVersions/poti_cap.0003.ipt
Normal file
Binary file not shown.
BIN
dev/print/4_caps/OldVersions/rot_switch_cap.0001.ipt
Normal file
BIN
dev/print/4_caps/OldVersions/rot_switch_cap.0001.ipt
Normal file
Binary file not shown.
BIN
dev/print/4_caps/caps.iam
Normal file
BIN
dev/print/4_caps/caps.iam
Normal file
Binary file not shown.
BIN
dev/print/4_caps/poti_cap.ipt
Normal file
BIN
dev/print/4_caps/poti_cap.ipt
Normal file
Binary file not shown.
BIN
dev/print/4_caps/rot_switch_cap.ipt
Normal file
BIN
dev/print/4_caps/rot_switch_cap.ipt
Normal file
Binary file not shown.
BIN
dev/print/info_skizzen/drehschalter.jpeg
Normal file
BIN
dev/print/info_skizzen/drehschalter.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
dev/print/info_skizzen/potentiometer.gif
Normal file
BIN
dev/print/info_skizzen/potentiometer.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
55429
dev/print/prod/frontplate_left.step
Normal file
55429
dev/print/prod/frontplate_left.step
Normal file
File diff suppressed because it is too large
Load Diff
1894
dev/print/prod/frontplate_left_button_mount.step
Normal file
1894
dev/print/prod/frontplate_left_button_mount.step
Normal file
File diff suppressed because it is too large
Load Diff
32143
dev/print/prod/frontplate_right.step
Normal file
32143
dev/print/prod/frontplate_right.step
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user