ADSR and filters

This commit is contained in:
Dejvino
2026-02-27 22:23:59 +01:00
parent c8bdf3ee13
commit f80daed222
3 changed files with 199 additions and 27 deletions
+87 -11
View File
@@ -28,6 +28,10 @@ float knob_vol_val = 0.5f;
SynthEngine::Waveform current_waveform = SynthEngine::SAWTOOTH;
const char* waveform_names[] = {"Saw", "Square", "Sine"};
// ADSR (A, D, R in seconds, S in 0-1)
float adsr_vals[4] = {0.05f, 0.2f, 0.6f, 0.5f};
float filter_vals[2] = {1.0f, 0.0f}; // LP (1.0=Open), HP (0.0=Open)
// --- MIDI / Keyboard Input State ---
std::map<SDL_Scancode, int> key_to_note_map;
int current_key_scancode = 0; // 0 for none
@@ -174,6 +178,21 @@ void drawToggle(SDL_Renderer* renderer, int x, int y, int size, bool active) {
SDL_RenderDrawLine(renderer, m_x + m_w, m_y, m_x + m_w, m_y + m_h); // Right leg
}
void drawSlider(SDL_Renderer* renderer, int x, int y, int w, int h, float val, const char* label) {
// Track
SDL_SetRenderDrawColor(renderer, 80, 80, 80, 255);
SDL_Rect track = {x + w/2 - 2, y, 4, h};
SDL_RenderFillRect(renderer, &track);
// Handle
int handleH = 10;
int handleY = y + h - (int)(val * h) - handleH/2;
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255);
SDL_Rect handle = {x, handleY, w, handleH};
SDL_RenderFillRect(renderer, &handle);
SDL_RenderDrawRect(renderer, &handle);
}
int main(int argc, char* argv[]) {
(void)argc; (void)argv;
@@ -232,6 +251,10 @@ int main(int argc, char* argv[]) {
engine.setVolume(knob_vol_val);
engine.setGate(false); // Start with silence
// Init engine with default UI values
engine.setADSR(adsr_vals[0]*2.0f, adsr_vals[1]*2.0f, adsr_vals[2], adsr_vals[3]*2.0f);
engine.setFilter(20.0f + filter_vals[0]*19980.0f, 20.0f + filter_vals[1]*19980.0f);
// --- Main Loop ---
bool quit = false;
@@ -285,9 +308,9 @@ int main(int argc, char* argv[]) {
SDL_GetMouseState(&mouseX, &mouseY);
// Check Toggle Click
int toggleX = WINDOW_WIDTH / 2;
int toggleY = WINDOW_HEIGHT * 3 / 4;
int toggleSize = 40;
int toggleX = 580;
int toggleY = 450;
int toggleSize = 30;
if (mouseX >= toggleX - toggleSize/2 && mouseX <= toggleX + toggleSize/2 &&
mouseY >= toggleY - toggleSize/2 && mouseY <= toggleY + toggleSize/2) {
@@ -298,10 +321,52 @@ int main(int argc, char* argv[]) {
if (auto_melody_enabled) {
auto_melody_next_event_time = SDL_GetTicks(); // Start immediately
}
} else if (e.button.button == SDL_BUTTON_LEFT && mouseX < WINDOW_WIDTH / 2) {
// Left knob click emulates encoder switch: cycle waveform
current_waveform = (SynthEngine::Waveform)(((int)current_waveform + 1) % 3);
engine.setWaveform(current_waveform);
} else if (e.button.button == SDL_BUTTON_LEFT) {
// Check Left Knob (Octave) or Waveform Icon
// Knob: 100, 450, r=40. Waveform: 75, 500, 50x20
bool clickedKnob = (pow(mouseX - 100, 2) + pow(mouseY - 450, 2)) <= pow(40, 2);
bool clickedWave = (mouseX >= 75 && mouseX <= 125 && mouseY >= 500 && mouseY <= 520);
if (clickedKnob || clickedWave) {
// Left knob click emulates encoder switch: cycle waveform
current_waveform = (SynthEngine::Waveform)(((int)current_waveform + 1) % 3);
engine.setWaveform(current_waveform);
}
}
} else if (e.type == SDL_MOUSEMOTION) {
if (e.motion.state & SDL_BUTTON_LMASK) {
int mouseX = e.motion.x;
int mouseY = e.motion.y;
// Handle Sliders
// ADSR: x=200, 250, 300, 350. y=380, h=150
// Filters: x=450, 500.
int sliderY = 380;
int sliderH = 150;
int sliderW = 30;
auto checkSlider = [&](int idx, int sx, float* val) {
if (mouseX >= sx && mouseX <= sx + sliderW && mouseY >= sliderY - 20 && mouseY <= sliderY + sliderH + 20) {
*val = 1.0f - (float)(mouseY - sliderY) / (float)sliderH;
if (*val < 0.0f) *val = 0.0f;
if (*val > 1.0f) *val = 1.0f;
return true;
}
return false;
};
bool changed = false;
if (checkSlider(0, 200, &adsr_vals[0])) changed = true;
if (checkSlider(1, 250, &adsr_vals[1])) changed = true;
if (checkSlider(2, 300, &adsr_vals[2])) changed = true;
if (checkSlider(3, 350, &adsr_vals[3])) changed = true;
if (changed) engine.setADSR(adsr_vals[0]*2.0f, adsr_vals[1]*2.0f, adsr_vals[2], adsr_vals[3]*2.0f);
if (checkSlider(0, 450, &filter_vals[0]) || checkSlider(1, 500, &filter_vals[1])) {
// Map 0-1 to 20Hz-20kHz
float lpFreq = 20.0f + pow(filter_vals[0], 2.0f) * 19980.0f; // Exponential feel
float hpFreq = 20.0f + pow(filter_vals[1], 2.0f) * 19980.0f;
engine.setFilter(lpFreq, hpFreq);
}
}
} else if (e.type == SDL_KEYDOWN) {
if (e.key.repeat == 0) { // Ignore key repeats
@@ -390,11 +455,22 @@ int main(int argc, char* argv[]) {
// --- Draw Controls ---
// Draw in the bottom half of the window
// Knobs moved to edges
float normalized_octave = (float)current_octave / 8.0f; // Max octave 8
drawKnob(renderer, WINDOW_WIDTH / 4, WINDOW_HEIGHT * 3 / 4, 50, normalized_octave);
drawWaveformIcon(renderer, WINDOW_WIDTH / 4 - 25, WINDOW_HEIGHT * 3 / 4 + 60, 50, 20, current_waveform);
drawToggle(renderer, WINDOW_WIDTH / 2, WINDOW_HEIGHT * 3 / 4, 40, auto_melody_enabled);
drawKnob(renderer, WINDOW_WIDTH * 3 / 4, WINDOW_HEIGHT * 3 / 4, 50, knob_vol_val);
drawKnob(renderer, 100, 450, 40, normalized_octave);
drawWaveformIcon(renderer, 100 - 25, 450 + 50, 50, 20, current_waveform);
drawKnob(renderer, 700, 450, 40, knob_vol_val);
drawToggle(renderer, 580, 450, 30, auto_melody_enabled);
drawSlider(renderer, 200, 380, 30, 150, adsr_vals[0], "A");
drawSlider(renderer, 250, 380, 30, 150, adsr_vals[1], "D");
drawSlider(renderer, 300, 380, 30, 150, adsr_vals[2], "S");
drawSlider(renderer, 350, 380, 30, 150, adsr_vals[3], "R");
drawSlider(renderer, 450, 380, 30, 150, filter_vals[0], "LP");
drawSlider(renderer, 500, 380, 30, 150, filter_vals[1], "HP");
SDL_RenderPresent(renderer);
}