#pragma once #include #include #include enum class WaveType { SINE, SQUARE, TRIANGLE, NOISE }; enum class ChordType { AM, E7, DM, F, G, C }; struct Envelope { float attackTime = 0.005f; // seconds float decayTime = 0.05f; // seconds float sustainLevel = 0.7f; // 0.0 to 1.0 float releaseTime = 0.12f; // seconds }; struct Voice { bool active = false; WaveType wave = WaveType::SQUARE; float frequency = 0.0f; float phase = 0.0f; float volume = 0.12f; float pan = 0.5f; // 0.0 (left) to 1.0 (right) // Envelope tracking Envelope adsr; float age = 0.0f; // duration active (seconds) float releaseAge = 0.0f; // duration in release phase (seconds) bool releasing = false; // Frequency sweeps (for sound effects) float startFreq = 0.0f; float targetFreq = 0.0f; float sweepDuration = 0.0f; float sweepAge = 0.0f; // Vibrato float vibratoFreq = 0.0f; // LFO speed (Hz) float vibratoDepth = 0.0f; // pitch variation depth }; enum class SFXType { MOVE, ROTATE, LAND, LINE_CLEAR, TETRIS_CLEAR, LEVEL_UP, GAME_OVER }; class Synth { public: Synth(); ~Synth(); bool init(); void playBGM(bool play); void triggerSFX(SFXType type); void stopAllSFX(); // Thread-safe copy of visualizer buffer for the GPU renderer std::vector getVisualizerBuffer(); // SDL Audio Callback void audioCallback(Uint8* stream, int len); private: static void audioCallbackWrapper(void* userdata, Uint8* stream, int len); SDL_AudioDeviceID mAudioDevice = 0; bool mBGMEnabled = false; std::mutex mMutex; // 8 Dedicated voices: // Voice 0: BGM Lead (Square) // Voice 1: BGM Harmony / Echo (Pulse) // Voice 2: BGM Bass (Triangle) // Voice 3: BGM Drums / Noise (Noise/Triangle) // Voice 4, 5, 6, 7: Dedicated SFX voices static constexpr int NUM_VOICES = 8; Voice mVoices[NUM_VOICES]; // Sequencer state int mBPM = 138; float mSecsPerTick = 0.0f; // Seconds per eighth note tick float mTickTimer = 0.0f; int mCurrentTick = 0; // Pattern-based Sequencer static constexpr int NUM_PATTERNS = 6; uint8_t mPatternLead[NUM_PATTERNS][64]; uint8_t mPatternBass[NUM_PATTERNS][64]; ChordType mPatternChords[NUM_PATTERNS][8]; // 8 bars per pattern // Dynamic Playlist (4 patterns per cycle) int mPlaylist[4]; void shufflePlaylist(); // Visualizer Oscilloscope Ring Buffer static constexpr int VIS_BUFFER_SIZE = 512; float mVisBuffer[VIS_BUFFER_SIZE]; int mVisWritePos = 0; void initSequencer(); void updateSequencer(float dt); void updateVoice(Voice& voice, float dt); float generateSample(Voice& voice); // Helper to start BGM notes void triggerMusicNote(int voiceIdx, uint8_t midiNote, WaveType wave, float duration, float pan = 0.5f, float volume = 0.1f); };