mirror of
https://github.com/erik-toth/audio-synth.git
synced 2025-12-06 12:00:02 +00:00
Firmware MCU: Sequencer, erfassen und widergabe im Sequencerblock von beiden Channel, playback im single und loop modus, test OK
This commit is contained in:
@@ -177,15 +177,6 @@ void Keyboard::_removeActiveKey(uint8_t row, uint8_t col)
|
||||
|
||||
// ==================== CV ====================
|
||||
|
||||
/*!
|
||||
* @param dac Adafruit_MCP4728 object
|
||||
* @param wire TwoWire object
|
||||
* @param nCV Number of CV-Gates
|
||||
* @param cvChannelMap Maps CV-Gate-Index to a MCP4728 output-channel
|
||||
* @param keyToVoltage One dimensional array of size row times col
|
||||
* @param row Keyboard matrix rows
|
||||
* @param col Keyboard matrix cols
|
||||
*/
|
||||
CV::CV(Adafruit_MCP4728 *dac, TwoWire *wire, uint8_t nCV, MCP4728_channel_t *cvChannelMap, uint16_t *keyToVoltage, uint8_t row, uint8_t col)
|
||||
{
|
||||
_dac = dac;
|
||||
@@ -242,31 +233,27 @@ uint8_t CV::_getKeyToVoltageIndex(Key k)
|
||||
|
||||
// ==================== SequencerBlock ====================
|
||||
|
||||
|
||||
/*!
|
||||
* @param maxDurationMS maximum loop duration of recording in milliseconds
|
||||
* @param timeoutMS stops recording after timeout in milliseconds
|
||||
* @brief TODO
|
||||
* @param minStepDurationMS minimum duration for a step to be recorded (prevents ultra-short steps)
|
||||
*/
|
||||
SequencerBlock::SequencerBlock(uint16_t maxDurationMS, uint16_t timeoutMS)
|
||||
SequencerBlock::SequencerBlock(uint16_t maxDurationMS, uint16_t minStepDurationMS)
|
||||
{
|
||||
_maxDurationMS = maxDurationMS;
|
||||
_timeoutMS = timeoutMS;
|
||||
_minStepDurationMS = minStepDurationMS;
|
||||
_stepCount = 0;
|
||||
_currentStep = 0;
|
||||
_isRecording = false;
|
||||
_isPlaying = false;
|
||||
_loop = false;
|
||||
_lastVoltage = 0;
|
||||
_lastVoltageCh1 = 0;
|
||||
_lastVoltageCh2 = 0;
|
||||
_recordStartTime = 0;
|
||||
_lastStepTime = 0;
|
||||
_playStartTime = 0;
|
||||
_stepStartTime = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief starts sequence block recording
|
||||
*/
|
||||
void SequencerBlock::startRecord()
|
||||
{
|
||||
if(_isPlaying) stopPlay();
|
||||
@@ -275,12 +262,10 @@ void SequencerBlock::startRecord()
|
||||
_isRecording = true;
|
||||
_recordStartTime = millis();
|
||||
_lastStepTime = _recordStartTime;
|
||||
_lastVoltage = 0;
|
||||
_lastVoltageCh1 = 0xFFFF; // Ungültiger Wert zum Triggern des ersten Steps
|
||||
_lastVoltageCh2 = 0xFFFF;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief stops sequence block recording and saves it
|
||||
*/
|
||||
void SequencerBlock::stopRecord()
|
||||
{
|
||||
if(!_isRecording) return;
|
||||
@@ -289,36 +274,44 @@ void SequencerBlock::stopRecord()
|
||||
_isRecording = false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief adds step to sequencer block
|
||||
* @param voltage voltage step for CV-Gate in millivolts
|
||||
*/
|
||||
void SequencerBlock::addStep(uint16_t voltage)
|
||||
void SequencerBlock::addStep(uint16_t voltage_ch1, uint16_t voltage_ch2)
|
||||
{
|
||||
if(!_isRecording) return;
|
||||
if(!_canAddStep()) return;
|
||||
if(timeLimitReached())
|
||||
{
|
||||
stopRecord();
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
// Wenn sich die Spannung geändert hat, vorherigen Schritt abschließen
|
||||
if(voltage != _lastVoltage && _stepCount > 0)
|
||||
{
|
||||
_finishCurrentStep();
|
||||
}
|
||||
// Hat sich die Spannung geändert?
|
||||
bool voltageChanged = (voltage_ch1 != _lastVoltageCh1) || (voltage_ch2 != _lastVoltageCh2);
|
||||
|
||||
// Neuen Schritt beginnen oder vorhandenen aktualisieren
|
||||
if(voltage != _lastVoltage || _stepCount == 0)
|
||||
if(voltageChanged)
|
||||
{
|
||||
// Vorherigen Step abschließen (wenn vorhanden)
|
||||
if(_stepCount > 0)
|
||||
{
|
||||
_finishCurrentStep();
|
||||
}
|
||||
|
||||
// Neuen Step beginnen
|
||||
if(_canAddStep())
|
||||
{
|
||||
_sequence[_stepCount].voltage = voltage;
|
||||
_sequence[_stepCount].voltage_ch1 = voltage_ch1;
|
||||
_sequence[_stepCount].voltage_ch2 = voltage_ch2;
|
||||
_sequence[_stepCount].duration = 0;
|
||||
_stepCount++;
|
||||
|
||||
_lastStepTime = now;
|
||||
_lastVoltage = voltage;
|
||||
_lastVoltageCh1 = voltage_ch1;
|
||||
_lastVoltageCh2 = voltage_ch2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Gleiche Spannung - Duration des aktuellen Steps aktualisieren
|
||||
if(_stepCount > 0)
|
||||
{
|
||||
_sequence[_stepCount - 1].duration = now - _lastStepTime;
|
||||
@@ -326,18 +319,11 @@ void SequencerBlock::addStep(uint16_t voltage)
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief checks if sequencer block is recording
|
||||
* @return true or false
|
||||
*/
|
||||
bool SequencerBlock::isRecording()
|
||||
{
|
||||
return _isRecording;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief starts playing sequencer block
|
||||
*/
|
||||
void SequencerBlock::startPlay()
|
||||
{
|
||||
if(_stepCount == 0) return;
|
||||
@@ -349,19 +335,12 @@ void SequencerBlock::startPlay()
|
||||
_stepStartTime = _playStartTime;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief stops playing sequencer block
|
||||
*/
|
||||
void SequencerBlock::stopPlay()
|
||||
{
|
||||
_isPlaying = false;
|
||||
_currentStep = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief updates sequencer block
|
||||
* @attention Has to be called every cycle!
|
||||
*/
|
||||
void SequencerBlock::update()
|
||||
{
|
||||
if(!_isPlaying || _stepCount == 0) return;
|
||||
@@ -395,44 +374,31 @@ void SequencerBlock::update()
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief checks if sequencer block is playing
|
||||
* @return true or false
|
||||
*/
|
||||
bool SequencerBlock::isPlaying()
|
||||
{
|
||||
return _isPlaying;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief clears recording of sequencer block
|
||||
*/
|
||||
void SequencerBlock::clear()
|
||||
{
|
||||
_stepCount = 0;
|
||||
_currentStep = 0;
|
||||
_lastVoltage = 0;
|
||||
_lastVoltageCh1 = 0;
|
||||
_lastVoltageCh2 = 0;
|
||||
|
||||
for(uint8_t i = 0; i < N_MAX_SEQUENCE_STEPS; i++)
|
||||
{
|
||||
_sequence[i].voltage = 0;
|
||||
_sequence[i].voltage_ch1 = 0;
|
||||
_sequence[i].voltage_ch2 = 0;
|
||||
_sequence[i].duration = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief sets configuation for looping over the recording
|
||||
* @param loop if set to true, saved recording gets played in a loop
|
||||
*/
|
||||
void SequencerBlock::setLoop(bool loop)
|
||||
{
|
||||
_loop = loop;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief checks if the recording time limit has been reached
|
||||
* @return true of false
|
||||
*/
|
||||
bool SequencerBlock::timeLimitReached()
|
||||
{
|
||||
if(!_isRecording) return false;
|
||||
@@ -443,31 +409,27 @@ bool SequencerBlock::timeLimitReached()
|
||||
return (elapsed >= _maxDurationMS);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief returns the currently recoreded steps
|
||||
* @return uint8_t between 0 and 128
|
||||
*/
|
||||
uint8_t SequencerBlock::getStepCount()
|
||||
{
|
||||
return _stepCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief if sequencer is playing, returns the current voltage level
|
||||
* @return uint16_t voltage range for CV
|
||||
*/
|
||||
uint16_t SequencerBlock::getCurrentVoltage()
|
||||
uint16_t SequencerBlock::getCurrentVoltageCh1()
|
||||
{
|
||||
if(!_isPlaying || _stepCount == 0) return 0;
|
||||
if(_currentStep >= _stepCount) return 0;
|
||||
|
||||
return _sequence[_currentStep].voltage;
|
||||
return _sequence[_currentStep].voltage_ch1;
|
||||
}
|
||||
|
||||
uint16_t SequencerBlock::getCurrentVoltageCh2()
|
||||
{
|
||||
if(!_isPlaying || _stepCount == 0) return 0;
|
||||
if(_currentStep >= _stepCount) return 0;
|
||||
|
||||
return _sequence[_currentStep].voltage_ch2;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief gets the length of the recording in the block
|
||||
* @return uint16_t time in milliseconds
|
||||
*/
|
||||
uint16_t SequencerBlock::getTotalDuration()
|
||||
{
|
||||
uint16_t total = 0;
|
||||
@@ -483,12 +445,17 @@ void SequencerBlock::_finishCurrentStep()
|
||||
if(_stepCount == 0) return;
|
||||
|
||||
unsigned long now = millis();
|
||||
_sequence[_stepCount - 1].duration = now - _lastStepTime;
|
||||
uint16_t duration = now - _lastStepTime;
|
||||
|
||||
// Timeout prüfen - wenn zu lange keine Änderung, Schritt nicht hinzufügen
|
||||
if(_sequence[_stepCount - 1].duration < _timeoutMS)
|
||||
// Nur Steps mit ausreichender Dauer speichern
|
||||
if(duration >= _minStepDurationMS)
|
||||
{
|
||||
_stepCount++;
|
||||
_sequence[_stepCount - 1].duration = duration;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Step war zu kurz, verwerfen
|
||||
_stepCount--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user