/* @file: FIRMARE.h @author: Erik Tóth @contact: etoth@tsn.at @date: 2025-10-26 @updated: 2025-12-06 @brief: Header for FIRMWARE.cpp (FIXED VERSION) */ #include #include #include #ifndef FIRMWARE_H #define FIRMWARE_H #define N_MAX_QUEUE 10 #define N_MAX_ROWS 8 #define N_MAX_COLS 8 #define MS_DEBOUNCE 20 #define N_MAX_DAC_CH 4 struct Key { int row; int col; }; struct DualVoltageDurationPair { uint16_t voltage_ch1; uint16_t voltage_ch2; uint16_t duration; bool active; // NEU: true wenn Step aktive Noten hat, false für Pausen }; const Key NOT_A_KEY = {-1, -1}; bool isNotKey(Key k); bool isEqualKey(Key k1, Key k2); class Keyboard { public: Keyboard(uint8_t nRows, uint8_t nCols, uint8_t *pinsRow, uint8_t *pinsCol); void begin(); void update(); int getQueueLength(); Key getQueue(uint8_t index); private: uint8_t _nRows; uint8_t _nCols; uint8_t *_pinsRow; uint8_t *_pinsCol; bool _keyState[N_MAX_COLS][N_MAX_ROWS]; bool _keyStateLatest[N_MAX_COLS][N_MAX_ROWS]; unsigned long _lastChangeTime[N_MAX_COLS][N_MAX_ROWS]; Key _activeKeys[N_MAX_QUEUE]; uint8_t _nActiveKeys; uint8_t _nSticky; void _addActiveKey(uint8_t row, uint8_t col); void _removeActiveKey(uint8_t row, uint8_t col); bool _inQueue(uint8_t row, uint8_t col); bool _inQueue(Key k); bool _isNotKey(Key k); bool _isEqualKey(Key k1, Key k2); }; class CV { public: CV(Adafruit_MCP4728 *dac, TwoWire *wire, uint8_t nCV, MCP4728_channel_t *cvChannelMap, uint16_t *keyToVoltage, uint8_t row, uint8_t col); bool begin(uint8_t pinSDA, uint8_t pinSCL); void setVoltage(uint8_t cvIndex, Key k); void setVoltage(uint8_t cvIndex, uint16_t mV); void clearAll(); private: Adafruit_MCP4728 *_dac; TwoWire *_wire; uint8_t _nCV; uint8_t _row; uint8_t _col; MCP4728_channel_t _cvChannelMap[N_MAX_DAC_CH]; uint16_t *_keyToVoltage; uint8_t _getKeyToVoltageIndex(uint8_t row, uint8_t col); uint8_t _getKeyToVoltageIndex(Key k); }; class SequencerBlock { public: SequencerBlock(uint16_t maxDurationMS, uint16_t maxStepCount); // Aufnahme-Funktionen void startRecord(); void stopRecord(); void addStep(uint16_t voltage_ch1, uint16_t voltage_ch2); bool isRecording(); // Wiedergabe-Funktionen void startPlay(); void stopPlay(); void update(); bool isPlaying(); // Sequenz-Verwaltung void clear(); void setLoop(bool loop); // Status-Abfragen bool timeLimitReached(); bool stepLimitReached(); uint16_t getStepCount(); uint16_t getCurrentVoltageCh1(); uint16_t getCurrentVoltageCh2(); bool isCurrentStepActive(); // NEU: Prüft ob aktueller Step aktive Noten hat uint16_t getTotalDuration(); private: /*! * @brief Memory limiting * @return (uint16_t) 1024 * @attention Increasing the value might lead to an overflow * @note sizeOf(DualVoltageDurationPair) = 8 Byte ==> 8 Byte * 1024 = 8192 Byte */ const static uint16_t _MAX_SEQUENCE_STEPS = 1024; // Sequenz memory DualVoltageDurationPair _sequence[_MAX_SEQUENCE_STEPS]; uint16_t _stepCount; uint16_t _currentStep; // Time management uint16_t _maxDurationMS; uint16_t _maxStepCount; unsigned long _recordStartTime; unsigned long _lastStepTime; unsigned long _playStartTime; unsigned long _stepStartTime; unsigned long _lastAddStepTime; // NEU: Rate-Limiting // Status flags bool _isRecording; bool _isPlaying; bool _loop; // Last recorded Voltage: at n-th step minus one uint16_t _lastVoltageCh1; uint16_t _lastVoltageCh2; // helper functions void _finishCurrentStep(); bool _canAddStep(); }; #endif