You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
3.0 KiB
125 lines
3.0 KiB
#pragma once |
|
#include <SDL2/SDL.h> |
|
#include <mutex> |
|
#include <vector> |
|
|
|
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<float> 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); |
|
};
|
|
|