Skip to content

Commit b283006

Browse files
committed
misc
1 parent e064bae commit b283006

File tree

3 files changed

+114
-15
lines changed

3 files changed

+114
-15
lines changed

src/gui.cpp

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ void gui_draw(Synth *synth, SDL_Window *window, SDL_GLContext gl_context,
199199

200200
// Oscillators
201201
if (ImGui::CollapsingHeader("Oscillators", ImGuiTreeNodeFlags_DefaultOpen)) {
202-
ImGui::Columns(2, "osc_columns", true);
202+
ImGui::Columns(3, "osc_columns", true);
203203
for (int i = 0; i < 6; ++i) {
204204
ImGui::PushID(i);
205205
char title[32];
@@ -270,11 +270,7 @@ void gui_draw(Synth *synth, SDL_Window *window, SDL_GLContext gl_context,
270270

271271
// ADSR Envelope
272272
if (ImGui::CollapsingHeader("ADSR Envelope", ImGuiTreeNodeFlags_DefaultOpen)) {
273-
ImGui::Columns(2, "adsr_columns", true);
274-
ImGui::SetColumnWidth(0, (float)window_width / 3.0f);
275-
ImGui::SetColumnWidth(1, (float)window_width / 3.0f);
276-
277-
// Left column - Attack and Decay
273+
// Single column layout - Attack, Decay, Sustain, Release stacked vertically
278274
ImGui::Text("Attack");
279275
if (ImGui::SliderFloat("##adsrattack", &synth->adsr.attack, 0.001f, 5.0f, "%.3f s", 0)) {
280276
synth_set_param(synth, "adsr.attack", synth->adsr.attack);
@@ -285,9 +281,6 @@ void gui_draw(Synth *synth, SDL_Window *window, SDL_GLContext gl_context,
285281
synth_set_param(synth, "adsr.decay", synth->adsr.decay);
286282
}
287283

288-
ImGui::NextColumn();
289-
290-
// Right column - Sustain and Release
291284
ImGui::Text("Sustain");
292285
if (ImGui::SliderFloat("##adsrsustain", &synth->adsr.sustain, 0.0f, 1.0f, "%.2f", 0)) {
293286
synth_set_param(synth, "adsr.sustain", synth->adsr.sustain);
@@ -298,12 +291,9 @@ void gui_draw(Synth *synth, SDL_Window *window, SDL_GLContext gl_context,
298291
synth_set_param(synth, "adsr.release", synth->adsr.release);
299292
}
300293

301-
ImGui::Columns(1, "", false);
302-
303294
// Preset buttons
304295
ImGui::Separator();
305-
ImGui::Text("Presets:");
306-
ImGui::Columns(8, "adsr_presets", true);
296+
ImGui::Columns(7, "adsr_presets", true);
307297

308298
if (ImGui::Button("Pad")) {
309299
synth_set_param(synth, "adsr.attack", 1.5f);
@@ -359,6 +349,63 @@ void gui_draw(Synth *synth, SDL_Window *window, SDL_GLContext gl_context,
359349
synth_set_param(synth, "adsr.sustain", 0.8f);
360350
synth_set_param(synth, "adsr.release", 1.2f);
361351
}
352+
ImGui::NextColumn();
353+
354+
// Row 2 - New presets
355+
if (ImGui::Button("Piano")) {
356+
synth_set_param(synth, "adsr.attack", 0.005f);
357+
synth_set_param(synth, "adsr.decay", 0.3f);
358+
synth_set_param(synth, "adsr.sustain", 0.4f);
359+
synth_set_param(synth, "adsr.release", 1.0f);
360+
}
361+
ImGui::NextColumn();
362+
363+
if (ImGui::Button("Organ")) {
364+
synth_set_param(synth, "adsr.attack", 0.01f);
365+
synth_set_param(synth, "adsr.decay", 0.1f);
366+
synth_set_param(synth, "adsr.sustain", 0.9f);
367+
synth_set_param(synth, "adsr.release", 0.3f);
368+
}
369+
ImGui::NextColumn();
370+
371+
if (ImGui::Button("Brass")) {
372+
synth_set_param(synth, "adsr.attack", 0.1f);
373+
synth_set_param(synth, "adsr.decay", 0.2f);
374+
synth_set_param(synth, "adsr.sustain", 0.8f);
375+
synth_set_param(synth, "adsr.release", 0.4f);
376+
}
377+
ImGui::NextColumn();
378+
379+
if (ImGui::Button("Guitar")) {
380+
synth_set_param(synth, "adsr.attack", 0.002f);
381+
synth_set_param(synth, "adsr.decay", 0.4f);
382+
synth_set_param(synth, "adsr.sustain", 0.6f);
383+
synth_set_param(synth, "adsr.release", 0.8f);
384+
}
385+
ImGui::NextColumn();
386+
387+
if (ImGui::Button("Synth")) {
388+
synth_set_param(synth, "adsr.attack", 0.02f);
389+
synth_set_param(synth, "adsr.decay", 0.3f);
390+
synth_set_param(synth, "adsr.sustain", 0.7f);
391+
synth_set_param(synth, "adsr.release", 0.5f);
392+
}
393+
ImGui::NextColumn();
394+
395+
if (ImGui::Button("Percussion")) {
396+
synth_set_param(synth, "adsr.attack", 0.001f);
397+
synth_set_param(synth, "adsr.decay", 0.02f);
398+
synth_set_param(synth, "adsr.sustain", 0.0f);
399+
synth_set_param(synth, "adsr.release", 0.05f);
400+
}
401+
ImGui::NextColumn();
402+
403+
if (ImGui::Button("Fade In")) {
404+
synth_set_param(synth, "adsr.attack", 2.0f);
405+
synth_set_param(synth, "adsr.decay", 0.5f);
406+
synth_set_param(synth, "adsr.sustain", 0.8f);
407+
synth_set_param(synth, "adsr.release", 3.0f);
408+
}
362409

363410
ImGui::Columns(1, "", false);
364411
}

src/oscilloscope.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,61 @@ void oscilloscope_draw(SDL_Renderer *renderer, const struct Synth *synth,
9696
SDL_RenderDrawLine(renderer, right_x, y + waveform_h/2, right_x + channel_width, y + waveform_h/2);
9797

9898
if (buffer_ready) {
99-
// Find a stable trigger point (zero crossing)
99+
// Find a stable trigger point on rising edge zero crossing
100100
int trigger_pos = waveform_write_pos;
101101
int samples_to_display = channel_width > WAVEFORM_BUFFER_SIZE ? WAVEFORM_BUFFER_SIZE : channel_width;
102+
103+
// Search backwards from write position for stable trigger
104+
// We'll look for a zero crossing where signal goes from negative to positive
105+
int search_range = WAVEFORM_BUFFER_SIZE / 4; // Search through 1/4 of buffer
106+
int stable_trigger = -1;
107+
int best_trigger = trigger_pos;
108+
float min_crossing_diff = 1.0f; // Track smallest crossing amplitude difference
109+
110+
for (int offset = 0; offset < search_range; offset++) {
111+
int idx1 = (trigger_pos - offset - 1 + WAVEFORM_BUFFER_SIZE) % WAVEFORM_BUFFER_SIZE;
112+
int idx2 = (trigger_pos - offset + WAVEFORM_BUFFER_SIZE) % WAVEFORM_BUFFER_SIZE;
113+
114+
float sample1 = waveform_buffer[idx1];
115+
float sample2 = waveform_buffer[idx2];
116+
117+
// Check for rising edge zero crossing (negative to positive)
118+
if (sample1 < 0.0f && sample2 >= 0.0f) {
119+
// Calculate how close to zero this crossing is
120+
float crossing_diff = fabsf(sample1) + fabsf(sample2);
121+
122+
// Prefer crossings with smaller amplitude difference (closer to true zero crossing)
123+
if (crossing_diff < min_crossing_diff) {
124+
min_crossing_diff = crossing_diff;
125+
best_trigger = idx2;
126+
127+
// Additional stability check: ensure signal has some amplitude after crossing
128+
// Check a few samples ahead to make sure this isn't noise
129+
int stable_count = 0;
130+
float amplitude_sum = 0.0f;
131+
for (int check = 0; check < 8 && check < samples_to_display; check++) {
132+
int check_idx = (idx2 + check) % WAVEFORM_BUFFER_SIZE;
133+
float check_sample = waveform_buffer[check_idx];
134+
amplitude_sum += fabsf(check_sample);
135+
if (fabsf(check_sample) > 0.01f) { // Small threshold to avoid noise
136+
stable_count++;
137+
}
138+
}
139+
140+
// Consider it stable if at least half the samples have measurable amplitude
141+
if (stable_count >= 4 && amplitude_sum / 8.0f > 0.02f) {
142+
stable_trigger = idx2;
143+
}
144+
}
145+
}
146+
}
147+
148+
// Use stable trigger if found, otherwise use best zero crossing
149+
if (stable_trigger >= 0) {
150+
trigger_pos = stable_trigger;
151+
} else if (best_trigger != trigger_pos) {
152+
trigger_pos = best_trigger;
153+
}
102154

103155
// Find the actual signal range for auto-scaling
104156
float min_sample = 0.0f, max_sample = 0.0f;

src/synth.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ char* synth_save_preset_json(const Synth *synth) {
446446

447447
// Save Oscillator parameters
448448
cJSON *oscillators = cJSON_CreateArray();
449-
for (int i = 0; i < 4; ++i) {
449+
for (int i = 0; i < 6; ++i) {
450450
cJSON *osc = cJSON_CreateObject();
451451
cJSON_AddNumberToObject(osc, "waveform", synth->osc[i].waveform);
452452
cJSON_AddNumberToObject(osc, "pitch", synth->osc[i].pitch);

0 commit comments

Comments
 (0)