1 /*
2 DeaDBeeF -- the music player
3 Copyright (C) 2009-2015 Alexey Yakovenko and other contributors
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17
18 2. Altered source versions must be plainly marked as such, and must not be
19 misrepresented as being the original software.
20
21 3. This notice may not be removed or altered from any source distribution.
22 */
23
24 #include <gtk/gtk.h>
25 #include <string.h>
26 #include <math.h>
27 #include <stdlib.h>
28 #include "gtkui.h"
29 #include "support.h"
30 #include "ddbequalizer.h"
31
32 static GtkWidget *eqcont;
33 static GtkWidget *eqwin;
34 static GtkWidget *eqenablebtn;
35
36 static inline float
db_to_amp(float dB)37 db_to_amp (float dB) {
38 const float ln10=2.3025850929940002f;
39 return exp(ln10*dB/20.f);
40 }
41
42 static inline float
amp_to_db(float amp)43 amp_to_db (float amp) {
44 return 20*log10 (amp);
45 }
46
47 ddb_dsp_context_t *
get_supereq(void)48 get_supereq (void) {
49 ddb_dsp_context_t *dsp = deadbeef->streamer_get_dsp_chain ();
50 while (dsp) {
51 if (!strcmp (dsp->plugin->plugin.id, "supereq")) {
52 return dsp;
53 }
54 dsp = dsp->next;
55 }
56
57 return NULL;
58 }
59
60 static void
set_param(ddb_dsp_context_t * eq,int i,float v)61 set_param (ddb_dsp_context_t *eq, int i, float v) {
62 char fv[100];
63 snprintf (fv, sizeof (fv), "%f", v);
64 eq->plugin->set_param (eq, i, fv);
65 }
66
67 void
eq_value_changed(DdbEqualizer * widget)68 eq_value_changed (DdbEqualizer *widget)
69 {
70 ddb_dsp_context_t *eq = get_supereq ();
71 if (eq) {
72 for (int i = 0; i < 18; i++) {
73 set_param (eq, i+1, ddb_equalizer_get_band (widget, i));
74 }
75 set_param (eq, 0, ddb_equalizer_get_preamp (widget));
76 deadbeef->streamer_dsp_chain_save ();
77 }
78 }
79
80 void
on_enable_toggled(GtkToggleButton * togglebutton,gpointer user_data)81 on_enable_toggled (GtkToggleButton *togglebutton,
82 gpointer user_data) {
83 ddb_dsp_context_t *eq = get_supereq ();
84 if (eq) {
85 int enabled = gtk_toggle_button_get_active (togglebutton) ? 1 : 0;
86 eq->enabled = enabled;
87 deadbeef->streamer_dsp_refresh ();
88 deadbeef->streamer_dsp_chain_save ();
89 }
90 }
91
92 void
on_zero_all_clicked(GtkButton * button,gpointer user_data)93 on_zero_all_clicked (GtkButton *button,
94 gpointer user_data) {
95 if (eqwin) {
96 ddb_dsp_context_t *eq = get_supereq ();
97 if (eq) {
98 ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), 0);
99 set_param (eq, 0, 0);
100 for (int i = 0; i < 18; i++) {
101 // set gui
102 ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, 0);
103
104 // set dsp
105 set_param (eq, i+1, 0);
106 }
107 gtk_widget_queue_draw (eqwin);
108 deadbeef->streamer_dsp_chain_save ();
109 }
110 }
111 }
112
113 void
on_zero_preamp_clicked(GtkButton * button,gpointer user_data)114 on_zero_preamp_clicked (GtkButton *button,
115 gpointer user_data) {
116 if (eqwin) {
117 ddb_dsp_context_t *eq = get_supereq ();
118 if (eq) {
119 set_param (eq, 0, 0);
120 ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), 0);
121 gtk_widget_queue_draw (eqwin);
122 deadbeef->streamer_dsp_chain_save ();
123 }
124 }
125 }
126
127 void
on_zero_bands_clicked(GtkButton * button,gpointer user_data)128 on_zero_bands_clicked (GtkButton *button,
129 gpointer user_data) {
130 if (eqwin) {
131 ddb_dsp_context_t *eq = get_supereq ();
132 if (eq) {
133 for (int i = 0; i < 18; i++) {
134 ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, 0);
135 set_param (eq, i+1, 0);
136 }
137 gtk_widget_queue_draw (eqwin);
138 deadbeef->streamer_dsp_chain_save ();
139 }
140 }
141 }
142
143 void
on_save_preset_clicked(GtkMenuItem * menuitem,gpointer user_data)144 on_save_preset_clicked (GtkMenuItem *menuitem,
145 gpointer user_data) {
146 GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Save DeaDBeeF EQ Preset"), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL);
147
148 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dlg), TRUE);
149 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dlg), "untitled.ddbeq");
150
151 GtkFileFilter* flt;
152 flt = gtk_file_filter_new ();
153 gtk_file_filter_set_name (flt, _("DeaDBeeF EQ preset files (*.ddbeq)"));
154 gtk_file_filter_add_pattern (flt, "*.ddbeq");
155
156 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
157
158 if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_OK)
159 {
160 gchar *fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
161 gtk_widget_destroy (dlg);
162
163 if (fname) {
164 FILE *fp = fopen (fname, "w+b");
165 if (fp) {
166 ddb_dsp_context_t *eq = get_supereq ();
167 if (eq) {
168 char fv[100];
169 float v;
170 for (int i = 0; i < 18; i++) {
171 eq->plugin->get_param (eq, i+1, fv, sizeof (fv));
172 v = atof (fv);
173 fprintf (fp, "%f\n", v);
174 }
175 eq->plugin->get_param (eq, 0, fv, sizeof (fv));
176 v = atof (fv);
177 fprintf (fp, "%f\n", v);
178 }
179 fclose (fp);
180 }
181 g_free (fname);
182 }
183 }
184 else {
185 gtk_widget_destroy (dlg);
186 }
187 }
188
189 void
on_load_preset_clicked(GtkMenuItem * menuitem,gpointer user_data)190 on_load_preset_clicked (GtkMenuItem *menuitem,
191 gpointer user_data) {
192 GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Load DeaDBeeF EQ Preset..."), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
193
194 GtkFileFilter* flt;
195 flt = gtk_file_filter_new ();
196 gtk_file_filter_set_name (flt, _("DeaDBeeF EQ presets (*.ddbeq)"));
197 gtk_file_filter_add_pattern (flt, "*.ddbeq");
198 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
199
200 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), FALSE);
201 // restore folder
202 deadbeef->conf_lock ();
203 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
204 deadbeef->conf_unlock ();
205 int response = gtk_dialog_run (GTK_DIALOG (dlg));
206 // store folder
207 gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
208 if (folder) {
209 deadbeef->conf_set_str ("filechooser.lastdir", folder);
210 g_free (folder);
211 }
212 if (response == GTK_RESPONSE_OK)
213 {
214 gchar *fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
215 if (fname) {
216 FILE *fp = fopen (fname, "rt");
217 if (fp) {
218 float vals[19]; // float dBs
219 int i = 0;
220 while (i < 19) {
221 char tmp[20];
222 char *out = fgets (tmp, sizeof (tmp), fp);
223 if (!out) {
224 break;
225 }
226 vals[i] = atof (tmp);
227 i++;
228 }
229 fclose (fp);
230 if (i == 19) {
231 // apply and save config
232 ddb_dsp_context_t *eq = get_supereq ();
233 if (eq) {
234 set_param (eq, 0, vals[18]);
235 ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), vals[18]);
236 for (int i = 0; i < 18; i++) {
237 ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, vals[i]);
238 set_param (eq, i+1, vals[i]);
239 }
240 gtk_widget_queue_draw (eqwin);
241 deadbeef->streamer_dsp_chain_save ();
242 }
243 }
244 else {
245 fprintf (stderr, "[eq] corrupted DeaDBeeF preset file, discarded\n");
246 }
247 }
248 g_free (fname);
249 }
250 }
251 gtk_widget_destroy (dlg);
252 }
253
254 void
on_import_fb2k_preset_clicked(GtkButton * button,gpointer user_data)255 on_import_fb2k_preset_clicked (GtkButton *button,
256 gpointer user_data) {
257 GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Import Foobar2000 EQ Preset..."), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
258
259 GtkFileFilter* flt;
260 flt = gtk_file_filter_new ();
261 gtk_file_filter_set_name (flt, _("Foobar2000 EQ presets (*.feq)"));
262 gtk_file_filter_add_pattern (flt, "*.feq");
263 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
264
265 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), FALSE);
266 // restore folder
267 deadbeef->conf_lock ();
268 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
269 deadbeef->conf_unlock ();
270
271 int response = gtk_dialog_run (GTK_DIALOG (dlg));
272 // store folder
273 gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
274 if (folder) {
275 deadbeef->conf_set_str ("filechooser.lastdir", folder);
276 g_free (folder);
277 }
278 if (response == GTK_RESPONSE_OK)
279 {
280 gchar *fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
281 if (fname) {
282 FILE *fp = fopen (fname, "rt");
283 if (fp) {
284 int vals[18]; // integer dBs
285 int i = 0;
286 while (i < 18) {
287 char tmp[20];
288 char *out = fgets (tmp, sizeof (tmp), fp);
289 if (!out) {
290 break;
291 }
292 vals[i] = atoi (tmp);
293 i++;
294 }
295 fclose (fp);
296 if (i == 18) {
297 // apply and save config
298 ddb_dsp_context_t *eq = get_supereq ();
299 if (eq) {
300 set_param (eq, 0, 0);
301 ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), 0);
302 for (int i = 0; i < 18; i++) {
303 ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, vals[i]);
304 set_param (eq, i+1, vals[i]);
305 }
306 gtk_widget_queue_draw (eqwin);
307 deadbeef->streamer_dsp_chain_save ();
308 }
309 }
310 else {
311 fprintf (stderr, "[eq] corrupted Foobar2000 preset file, discarded\n");
312 }
313 }
314 g_free (fname);
315 }
316 }
317 gtk_widget_destroy (dlg);
318 }
319
320 void
on_presets_clicked(GtkButton * button,gpointer user_data)321 on_presets_clicked (GtkButton *button,
322 gpointer user_data) {
323 GtkWidget *menu = gtk_menu_new ();
324 GtkWidget *menuitem;
325
326 menuitem = gtk_menu_item_new_with_mnemonic (_("Save Preset"));
327 gtk_widget_show (menuitem);
328 gtk_container_add (GTK_CONTAINER (menu), menuitem);
329
330 g_signal_connect ((gpointer) menuitem, "activate",
331 G_CALLBACK (on_save_preset_clicked),
332 NULL);
333
334 menuitem = gtk_menu_item_new_with_mnemonic (_("Load Preset"));
335 gtk_widget_show (menuitem);
336 gtk_container_add (GTK_CONTAINER (menu), menuitem);
337
338 g_signal_connect ((gpointer) menuitem, "activate",
339 G_CALLBACK (on_load_preset_clicked),
340 NULL);
341
342 menuitem = gtk_menu_item_new_with_mnemonic (_("Import Foobar2000 Preset"));
343 gtk_widget_show (menuitem);
344 gtk_container_add (GTK_CONTAINER (menu), menuitem);
345
346 g_signal_connect ((gpointer) menuitem, "activate",
347 G_CALLBACK (on_import_fb2k_preset_clicked),
348 NULL);
349
350 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
351 }
352
353 void
eq_window_show(void)354 eq_window_show (void) {
355 if (!eqcont) {
356 eqcont = gtk_vbox_new (FALSE, 8);
357 GtkWidget *parent= lookup_widget (mainwin, "plugins_bottom_vbox");
358 gtk_box_pack_start (GTK_BOX (parent), eqcont, FALSE, FALSE, 0);
359
360 GtkWidget *buttons = gtk_hbox_new (FALSE, 8);
361 gtk_container_set_border_width (GTK_CONTAINER (buttons), 3);
362 gtk_widget_show (buttons);
363 gtk_box_pack_start (GTK_BOX (eqcont), buttons, FALSE, FALSE, 0);
364
365 GtkWidget *button;
366
367 eqenablebtn = button = gtk_check_button_new_with_label (_("Enable"));
368 gtk_widget_show (button);
369 gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, FALSE, 0);
370 ddb_dsp_context_t *eq = get_supereq ();
371 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (eqenablebtn), eq ? eq->enabled : 0);
372 g_signal_connect ((gpointer) button, "toggled",
373 G_CALLBACK (on_enable_toggled),
374 NULL);
375
376 button = gtk_button_new_with_label (_("Zero All"));
377 gtk_widget_show (button);
378 gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, FALSE, 0);
379 g_signal_connect ((gpointer) button, "clicked",
380 G_CALLBACK (on_zero_all_clicked),
381 NULL);
382
383 button = gtk_button_new_with_label (_("Zero Preamp"));
384 gtk_widget_show (button);
385 gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, FALSE, 0);
386 g_signal_connect ((gpointer) button, "clicked",
387 G_CALLBACK (on_zero_preamp_clicked),
388 NULL);
389
390 button = gtk_button_new_with_label (_("Zero Bands"));
391 gtk_widget_show (button);
392 gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, FALSE, 0);
393 g_signal_connect ((gpointer) button, "clicked",
394 G_CALLBACK (on_zero_bands_clicked),
395 NULL);
396
397 button = gtk_button_new_with_label (_("Presets"));
398 gtk_widget_show (button);
399 gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, FALSE, 0);
400 g_signal_connect ((gpointer) button, "clicked",
401 G_CALLBACK (on_presets_clicked),
402 NULL);
403
404 eqwin = GTK_WIDGET (ddb_equalizer_new());
405 g_signal_connect (eqwin, "on_changed", G_CALLBACK (eq_value_changed), 0);
406 gtk_widget_set_size_request (eqwin, -1, 200);
407
408 if (eq) {
409 char fv[100];
410 float v;
411 eq->plugin->get_param (eq, 0, fv, sizeof (fv));
412 v = atof (fv);
413 ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), v);
414 for (int i = 0; i < 18; i++) {
415 if (eq) {
416 eq->plugin->get_param (eq, i+1, fv, sizeof (fv));
417 v = atof (fv);
418 ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, v);
419 }
420 }
421 }
422
423 gtk_widget_show (eqwin);
424 gtk_box_pack_start (GTK_BOX (eqcont), eqwin, TRUE, TRUE, 0);
425 }
426 gtk_widget_show (eqcont);
427 }
428
429 void
eq_window_hide(void)430 eq_window_hide (void) {
431 if (eqcont) {
432 gtk_widget_hide (eqcont);
433 }
434 }
435
436 void
eq_window_destroy(void)437 eq_window_destroy (void) {
438 if (eqwin) {
439 gtk_widget_destroy (eqwin);
440 eqwin = NULL;
441 }
442 }
443
444 void
eq_redraw(void)445 eq_redraw (void) {
446 if (eqwin) {
447 gtk_widget_queue_draw (eqwin);
448 }
449 }
450
451 void
eq_refresh(void)452 eq_refresh (void) {
453 ddb_dsp_context_t *eq = get_supereq ();
454 if (eq && eqwin) {
455 char s[20];
456 eq->plugin->get_param (eq, 0, s, sizeof (s));
457 ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), atof(s));
458 for (int i = 0; i < 18; i++) {
459 eq->plugin->get_param (eq, i+1, s, sizeof (s));
460 ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, atoi(s));
461 }
462 eq_redraw ();
463 }
464 }
465