1 /*
2 Converter UI for DeaDBeeF 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 #ifdef HAVE_CONFIG_H
25 # include "../../config.h"
26 #endif
27 #if HAVE_SYS_CDEFS_H
28 #include <sys/cdefs.h>
29 #endif
30 #include <limits.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <assert.h>
34 #include <dirent.h>
35 #include <unistd.h>
36 #include "converter.h"
37 #include "support.h"
38 #include "interface.h"
39 #include "../gtkui/gtkui_api.h"
40
41 DB_functions_t *deadbeef;
42
43 ddb_converter_t *converter_plugin;
44 ddb_gtkui_t *gtkui_plugin;
45
46 static int converter_active;
47
48 typedef struct {
49 GtkWidget *converter;
50 ddb_encoder_preset_t *current_encoder_preset;
51 ddb_dsp_preset_t *current_dsp_preset;
52
53 DB_playItem_t **convert_items;
54 ddb_playlist_t *convert_playlist;
55
56 int convert_items_count;
57 char *outfolder;
58 char *outfile;
59 int preserve_folder_structure;
60 int write_to_source_folder;
61 int output_bps;
62 int output_is_float;
63 int overwrite_action;
64 ddb_encoder_preset_t *encoder_preset;
65 ddb_dsp_preset_t *dsp_preset;
66 GtkWidget *progress;
67 GtkWidget *progress_entry;
68 int cancelled;
69 } converter_ctx_t;
70
71 converter_ctx_t *current_ctx;
72
73 enum {
74 PRESET_TYPE_ENCODER,
75 PRESET_TYPE_DSP
76 };
77
78 static void
fill_presets(GtkListStore * mdl,ddb_preset_t * head,int type)79 fill_presets (GtkListStore *mdl, ddb_preset_t *head, int type) {
80 ddb_preset_t *p = head;
81 while (p) {
82 GtkTreeIter iter;
83 gtk_list_store_append (mdl, &iter);
84 const char *s = p->title;
85 if (type == PRESET_TYPE_ENCODER && ((ddb_encoder_preset_t *)p)->readonly) {
86 char stock[1000];
87 snprintf (stock, sizeof (stock), _("[Built-in] %s"), p->title);
88 s = stock;
89 }
90 gtk_list_store_set (mdl, &iter, 0, s, -1);
91 p = p->next;
92 }
93 }
94
95 void
on_converter_progress_cancel(GtkDialog * dialog,gint response_id,gpointer user_data)96 on_converter_progress_cancel (GtkDialog *dialog, gint response_id, gpointer user_data) {
97 converter_ctx_t *ctx = user_data;
98 ctx->cancelled = 1;
99 }
100
101 typedef struct {
102 GtkWidget *entry;
103 char *text;
104 } update_progress_info_t;
105
106 static gboolean
update_progress_cb(gpointer ctx)107 update_progress_cb (gpointer ctx) {
108 update_progress_info_t *info = ctx;
109 gtk_entry_set_text (GTK_ENTRY (info->entry), info->text);
110 free (info->text);
111 g_object_unref (info->entry);
112 free (info);
113 return FALSE;
114 }
115
116 static gboolean
destroy_progress_cb(gpointer ctx)117 destroy_progress_cb (gpointer ctx) {
118 gtk_widget_destroy (ctx);
119 return FALSE;
120 }
121
122 struct overwrite_prompt_ctx {
123 const char *fname;
124 uintptr_t mutex;
125 uintptr_t cond;
126 int result;
127 };
128
129 static gboolean
overwrite_prompt_cb(void * ctx)130 overwrite_prompt_cb (void *ctx) {
131 struct overwrite_prompt_ctx *ctl = ctx;
132 GtkWidget *mainwin = gtkui_plugin->get_mainwin ();
133 GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (mainwin), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("The file already exists. Overwrite?"));
134 gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (mainwin));
135 gtk_window_set_title (GTK_WINDOW (dlg), _("Converter warning"));
136 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), "%s", ctl->fname);
137
138 int response = gtk_dialog_run (GTK_DIALOG (dlg));
139 gtk_widget_destroy (dlg);
140 ctl->result = response == GTK_RESPONSE_YES ? 1 : 0;
141 deadbeef->cond_signal (ctl->cond);
142 return FALSE;
143 }
144
145 static int
overwrite_prompt(const char * outpath)146 overwrite_prompt (const char *outpath) {
147 struct overwrite_prompt_ctx ctl;
148 ctl.mutex = deadbeef->mutex_create ();
149 ctl.cond = deadbeef->cond_create ();
150 ctl.fname = outpath;
151 ctl.result = 0;
152 gdk_threads_add_idle (overwrite_prompt_cb, &ctl);
153 deadbeef->cond_wait (ctl.cond, ctl.mutex);
154 deadbeef->cond_free (ctl.cond);
155 deadbeef->mutex_free (ctl.mutex);
156 return ctl.result;
157 }
158
159 static void
converter_worker(void * ctx)160 converter_worker (void *ctx) {
161 deadbeef->background_job_increment ();
162 converter_ctx_t *conv = ctx;
163
164 char root[2000] = "";
165 int rootlen = 0;
166 // prepare for preserving folder struct
167 if (conv->preserve_folder_structure && conv->convert_items_count >= 1) {
168 // start with the 1st track path
169 deadbeef->pl_get_meta (conv->convert_items[0], ":URI", root, sizeof (root));
170 char *sep = strrchr (root, '/');
171 if (sep) {
172 *sep = 0;
173 }
174 // reduce
175 rootlen = strlen (root);
176 for (int n = 1; n < conv->convert_items_count; n++) {
177 deadbeef->pl_lock ();
178 const char *path = deadbeef->pl_find_meta (conv->convert_items[n], ":URI");
179 if (strncmp (path, root, rootlen)) {
180 // find where path splits
181 char *r = root;
182 while (*path && *r) {
183 if (*path != *r) {
184 // find new separator
185 while (r > root && *r != '/') {
186 r--;
187 }
188 *r = 0;
189 rootlen = r-root;
190 break;
191 }
192 path++;
193 r++;
194 }
195 }
196 deadbeef->pl_unlock ();
197 }
198 }
199
200 for (int n = 0; n < conv->convert_items_count; n++) {
201 update_progress_info_t *info = malloc (sizeof (update_progress_info_t));
202 info->entry = conv->progress_entry;
203 g_object_ref (info->entry);
204 deadbeef->pl_lock ();
205 info->text = strdup (deadbeef->pl_find_meta (conv->convert_items[n], ":URI"));
206 deadbeef->pl_unlock ();
207 g_idle_add (update_progress_cb, info);
208
209 char outpath[2000];
210 converter_plugin->get_output_path2 (conv->convert_items[n], conv->convert_playlist, conv->outfolder, conv->outfile, conv->encoder_preset, conv->preserve_folder_structure, root, conv->write_to_source_folder, outpath, sizeof (outpath));
211
212 int skip = 0;
213 char *real_out = realpath(outpath, NULL);
214 if (real_out) {
215 skip = 1;
216 deadbeef->pl_lock();
217 char *real_in = realpath(deadbeef->pl_find_meta(conv->convert_items[n], ":URI"), NULL);
218 deadbeef->pl_unlock();
219 const int paths_match = real_in && !strcmp(real_in, real_out);
220 free(real_in);
221 free(real_out);
222 if (paths_match) {
223 fprintf (stderr, "converter: destination file is the same as source file, skipping\n");
224 }
225 else if (conv->overwrite_action == 2 || (conv->overwrite_action == 1 && overwrite_prompt(outpath))) {
226 unlink (outpath);
227 skip = 0;
228 }
229 }
230
231 if (!skip) {
232 converter_plugin->convert (conv->convert_items[n], outpath, conv->output_bps, conv->output_is_float, conv->encoder_preset, conv->dsp_preset, &conv->cancelled);
233 }
234 if (conv->cancelled) {
235 for (; n < conv->convert_items_count; n++) {
236 deadbeef->pl_item_unref (conv->convert_items[n]);
237 }
238 break;
239 }
240 deadbeef->pl_item_unref (conv->convert_items[n]);
241 }
242 g_idle_add (destroy_progress_cb, conv->progress);
243 if (conv->convert_items) {
244 free (conv->convert_items);
245 }
246 if (conv->convert_playlist) {
247 deadbeef->plt_unref (conv->convert_playlist);
248 }
249 if (conv->outfolder) {
250 free (conv->outfolder);
251 }
252 if (conv->outfile) {
253 free (conv->outfile);
254 }
255 converter_plugin->encoder_preset_free (conv->encoder_preset);
256 converter_plugin->dsp_preset_free (conv->dsp_preset);
257 free (conv);
258 deadbeef->background_job_decrement ();
259 }
260
261 int
converter_process(converter_ctx_t * conv)262 converter_process (converter_ctx_t *conv)
263 {
264 conv->outfolder = strdup (gtk_entry_get_text (GTK_ENTRY (lookup_widget (conv->converter, "output_folder"))));
265 const char *outfile = gtk_entry_get_text (GTK_ENTRY (lookup_widget (conv->converter, "output_file")));
266 if (outfile[0] == 0) {
267 outfile = "%artist% - %title%";
268 }
269 conv->outfile = strdup (outfile);
270 conv->preserve_folder_structure = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (conv->converter, "preserve_folders")));
271 conv->write_to_source_folder = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (conv->converter, "write_to_source_folder")));
272 conv->overwrite_action = gtk_combo_box_get_active (GTK_COMBO_BOX (lookup_widget (conv->converter, "overwrite_action")));
273
274 GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "output_format"));
275 int selected_format = gtk_combo_box_get_active (combo);
276 switch (selected_format) {
277 case 1 ... 4:
278 conv->output_bps = selected_format * 8;
279 conv->output_is_float = 0;
280 break;
281 case 5:
282 conv->output_bps = 32;
283 conv->output_is_float = 1;
284 break;
285 default:
286 conv->output_bps = -1; // same as input, or encoder default
287 break;
288 }
289
290 combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "encoder"));
291 int enc_preset = gtk_combo_box_get_active (combo);
292 ddb_encoder_preset_t *encoder_preset = NULL;
293
294 if (enc_preset >= 0) {
295 encoder_preset = converter_plugin->encoder_preset_get_for_idx (enc_preset);
296 }
297 if (!encoder_preset) {
298 GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (conv->converter), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Please select encoder"));
299 gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (conv->converter));
300 gtk_window_set_title (GTK_WINDOW (dlg), _("Converter error"));
301
302 gtk_dialog_run (GTK_DIALOG (dlg));
303 gtk_widget_destroy (dlg);
304 return -1;
305 }
306
307 combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "dsp_preset"));
308 int dsp_idx = gtk_combo_box_get_active (combo) - 1;
309
310 ddb_dsp_preset_t *dsp_preset = NULL;
311 if (dsp_idx >= 0) {
312 dsp_preset = converter_plugin->dsp_preset_get_for_idx (dsp_idx);
313 }
314
315 if (encoder_preset) {
316 conv->encoder_preset = converter_plugin->encoder_preset_alloc ();
317 converter_plugin->encoder_preset_copy (conv->encoder_preset, encoder_preset);
318 }
319 if (dsp_preset) {
320 conv->dsp_preset = converter_plugin->dsp_preset_alloc ();
321 converter_plugin->dsp_preset_copy (conv->dsp_preset, dsp_preset);
322 }
323
324 GtkWidget *progress = gtk_dialog_new_with_buttons (_("Converting..."), GTK_WINDOW (gtkui_plugin->get_mainwin ()), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
325 GtkWidget *vbox = gtk_dialog_get_content_area (GTK_DIALOG (progress));
326 GtkWidget *entry = gtk_entry_new ();
327 gtk_widget_set_size_request (entry, 400, -1);
328 gtk_editable_set_editable (GTK_EDITABLE (entry), FALSE);
329 gtk_widget_show (entry);
330 gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 12);
331
332 g_signal_connect ((gpointer)progress, "response", G_CALLBACK (on_converter_progress_cancel), conv);
333
334 gtk_widget_show (progress);
335
336 conv->progress = progress;
337 conv->progress_entry = entry;
338 intptr_t tid = deadbeef->thread_start (converter_worker, conv);
339 deadbeef->thread_detach (tid);
340 return 0;
341 }
342
343 void
344 on_write_to_source_folder_toggled (GtkToggleButton *togglebutton,
345 gpointer user_data);
346
347 static gboolean
converter_show_cb(void * data)348 converter_show_cb (void *data) {
349 int ctx = (intptr_t)data;
350 converter_ctx_t *conv = malloc (sizeof (converter_ctx_t));
351 current_ctx = conv;
352 memset (conv, 0, sizeof (converter_ctx_t));
353
354 deadbeef->pl_lock ();
355 switch (ctx) {
356 case DDB_ACTION_CTX_MAIN:
357 case DDB_ACTION_CTX_SELECTION:
358 {
359 // copy list
360 ddb_playlist_t *plt = deadbeef->plt_get_curr ();
361 if (plt) {
362 conv->convert_playlist = plt;
363 conv->convert_items_count = deadbeef->plt_getselcount (plt);
364 if (0 < conv->convert_items_count) {
365 conv->convert_items = malloc (sizeof (DB_playItem_t *) * conv->convert_items_count);
366 if (conv->convert_items) {
367 int n = 0;
368 DB_playItem_t *it = deadbeef->pl_get_first (PL_MAIN);
369 while (it) {
370 if (deadbeef->pl_is_selected (it)) {
371 assert (n < conv->convert_items_count);
372 deadbeef->pl_item_ref (it);
373 conv->convert_items[n++] = it;
374 }
375 DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
376 deadbeef->pl_item_unref (it);
377 it = next;
378 }
379 }
380 }
381 }
382 break;
383 }
384 case DDB_ACTION_CTX_PLAYLIST:
385 {
386 // copy list
387 ddb_playlist_t *plt = deadbeef->action_get_playlist ();
388 if (plt) {
389 conv->convert_playlist = plt;
390 conv->convert_items_count = deadbeef->plt_get_item_count (plt, PL_MAIN);
391 if (0 < conv->convert_items_count) {
392 conv->convert_items = malloc (sizeof (DB_playItem_t *) * conv->convert_items_count);
393 if (conv->convert_items) {
394 int n = 0;
395 DB_playItem_t *it = deadbeef->pl_get_first (PL_MAIN);
396 while (it) {
397 conv->convert_items[n++] = it;
398 it = deadbeef->pl_get_next (it, PL_MAIN);
399 }
400 }
401 }
402 }
403 break;
404 }
405 case DDB_ACTION_CTX_NOWPLAYING:
406 {
407 DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
408 if (it) {
409 conv->convert_playlist = deadbeef->pl_get_playlist (it);
410 conv->convert_items_count = 1;
411 conv->convert_items = malloc (sizeof (DB_playItem_t *) * conv->convert_items_count);
412 if (conv->convert_items) {
413 conv->convert_items[0] = it;
414 }
415 }
416 }
417 break;
418 }
419 deadbeef->pl_unlock ();
420
421 conv->converter = create_converterdlg ();
422 deadbeef->conf_lock ();
423 const char *out_folder = deadbeef->conf_get_str_fast ("converter.output_folder", "");
424 if (!out_folder[0]) {
425 out_folder = getenv("HOME");
426 }
427 gtk_entry_set_text (GTK_ENTRY (lookup_widget (conv->converter, "output_folder")), out_folder);
428 gtk_entry_set_text (GTK_ENTRY (lookup_widget (conv->converter, "output_file")), deadbeef->conf_get_str_fast ("converter.output_file_tf", ""));
429 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (conv->converter, "preserve_folders")), deadbeef->conf_get_int ("converter.preserve_folder_structure", 0));
430 int write_to_source_folder = deadbeef->conf_get_int ("converter.write_to_source_folder", 0);
431 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (conv->converter, "write_to_source_folder")), write_to_source_folder);
432
433 g_signal_connect ((gpointer) lookup_widget (conv->converter, "write_to_source_folder"), "toggled",
434 G_CALLBACK (on_write_to_source_folder_toggled),
435 conv);
436
437 gtk_widget_set_sensitive (lookup_widget (conv->converter, "output_folder"), !write_to_source_folder);
438 gtk_widget_set_sensitive (lookup_widget (conv->converter, "preserve_folders"), !write_to_source_folder);
439 gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (conv->converter, "overwrite_action")), deadbeef->conf_get_int ("converter.overwrite_action", 0));
440 deadbeef->conf_unlock ();
441
442 GtkComboBox *combo;
443 // fill encoder presets
444 combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "encoder"));
445 GtkListStore *mdl = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
446 fill_presets (mdl, (ddb_preset_t *)converter_plugin->encoder_preset_get_list (), PRESET_TYPE_ENCODER);
447 gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("converter.encoder_preset", 0));
448
449 // fill dsp presets
450 combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "dsp_preset"));
451 mdl = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
452 GtkTreeIter iter;
453 gtk_list_store_append (mdl, &iter);
454 gtk_list_store_set (mdl, &iter, 0, "Pass through", -1);
455 fill_presets (mdl, (ddb_preset_t *)converter_plugin->dsp_preset_get_list (), PRESET_TYPE_DSP);
456
457 gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("converter.dsp_preset", -1) + 1);
458
459 // select output format
460 combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "output_format"));
461 gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("converter.output_format", 0));
462
463 // overwrite action
464 combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "overwrite_action"));
465 gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("converter.overwrite_action", 0));
466
467 for (;;) {
468 int response = gtk_dialog_run (GTK_DIALOG (conv->converter));
469 if (response == GTK_RESPONSE_OK) {
470 int err = converter_process (conv);
471 if (err != 0) {
472 continue;
473 }
474 gtk_widget_destroy (conv->converter);
475 }
476 else {
477 // FIXME: clean up properly
478 gtk_widget_destroy (conv->converter);
479 if (conv->convert_items) {
480 for (int n = 0; n < conv->convert_items_count; n++) {
481 deadbeef->pl_item_unref (conv->convert_items[n]);
482 }
483 free (conv->convert_items);
484 }
485 free (conv);
486 }
487 current_ctx = NULL;
488 break;
489 }
490 converter_active = 0;
491 return FALSE;
492 }
493
494 static int
converter_show(DB_plugin_action_t * act,int ctx)495 converter_show (DB_plugin_action_t *act, int ctx) {
496 if (converter_active) {
497 return -1;
498 }
499 converter_active = 1;
500 if (converter_plugin->misc.plugin.version_minor >= 1) {
501 // reload all presets
502 converter_plugin->free_encoder_presets ();
503 converter_plugin->load_encoder_presets ();
504 converter_plugin->free_dsp_presets ();
505 converter_plugin->load_dsp_presets ();
506 }
507 // this can be called from non-gtk thread
508 gdk_threads_add_idle (converter_show_cb, (void *)(intptr_t)ctx);
509 return 0;
510 }
511
512 void
on_converter_encoder_changed(GtkComboBox * combobox,gpointer user_data)513 on_converter_encoder_changed (GtkComboBox *combobox,
514 gpointer user_data)
515 {
516 GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "encoder"));
517 int act = gtk_combo_box_get_active (combo);
518 deadbeef->conf_set_int ("converter.encoder_preset", act);
519 deadbeef->conf_save ();
520 }
521
522 void
on_converter_dsp_preset_changed(GtkComboBox * combobox,gpointer user_data)523 on_converter_dsp_preset_changed (GtkComboBox *combobox,
524 gpointer user_data)
525 {
526 GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "dsp_preset"));
527 int act = gtk_combo_box_get_active (combo);
528 deadbeef->conf_set_int ("converter.dsp_preset", act-1);
529 deadbeef->conf_save ();
530 }
531
532 void
on_converter_output_browse_clicked(GtkButton * button,gpointer user_data)533 on_converter_output_browse_clicked (GtkButton *button,
534 gpointer user_data)
535 {
536 GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Select folder..."), GTK_WINDOW (current_ctx->converter), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
537 gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (current_ctx->converter));
538
539 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), FALSE);
540 // restore folder
541 deadbeef->conf_lock ();
542 char dir[2000];
543 deadbeef->conf_get_str ("converter.lastdir", "", dir, sizeof (dir));
544 if (!dir[0]) {
545 const char *out_folder = deadbeef->conf_get_str_fast ("converter.output_folder", "");
546 if (!out_folder[0]) {
547 out_folder = getenv("HOME");
548 }
549 snprintf (dir, sizeof (dir), "file://%s", out_folder);
550 }
551
552 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), dir);
553 deadbeef->conf_unlock ();
554 int response = gtk_dialog_run (GTK_DIALOG (dlg));
555 // store folder
556 gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
557 if (folder) {
558 deadbeef->conf_set_str ("converter.lastdir", folder);
559 g_free (folder);
560 }
561 if (response == GTK_RESPONSE_OK) {
562 folder = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
563 gtk_widget_destroy (dlg);
564 if (folder) {
565 GtkWidget *entry = lookup_widget (current_ctx->converter, "output_folder");
566 gtk_entry_set_text (GTK_ENTRY (entry), folder);
567 g_free (folder);
568 }
569 }
570 else {
571 gtk_widget_destroy (dlg);
572 }
573 }
574
575
576 void
on_output_folder_changed(GtkEntry * entry,gpointer user_data)577 on_output_folder_changed (GtkEntry *entry,
578 gpointer user_data)
579 {
580 deadbeef->conf_set_str ("converter.output_folder", gtk_entry_get_text (entry));
581 deadbeef->conf_save ();
582 }
583
584
585 void
on_numthreads_changed(GtkEditable * editable,gpointer user_data)586 on_numthreads_changed (GtkEditable *editable,
587 gpointer user_data)
588 {
589 deadbeef->conf_set_int ("converter.threads", gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editable)));
590 deadbeef->conf_save ();
591 }
592
593 void
on_overwrite_action_changed(GtkComboBox * combobox,gpointer user_data)594 on_overwrite_action_changed (GtkComboBox *combobox,
595 gpointer user_data)
596 {
597 deadbeef->conf_set_int ("converter.overwrite_action", gtk_combo_box_get_active (combobox));
598 deadbeef->conf_save ();
599 }
600
601 void
on_encoder_changed(GtkEditable * editable,gpointer user_data)602 on_encoder_changed (GtkEditable *editable,
603 gpointer user_data)
604 {
605 gtk_widget_set_has_tooltip (GTK_WIDGET (editable), TRUE);
606
607 char enc[2000];
608 const char *e = gtk_entry_get_text (GTK_ENTRY (editable));
609 char *o = enc;
610 *o = 0;
611 int len = sizeof (enc);
612 while (e && *e) {
613 if (len <= 0) {
614 break;
615 }
616 if (e[0] == '%' && e[1]) {
617 if (e[1] == 'o') {
618 int l = snprintf (o, len, "\"OUTPUT_FILE_NAME\"");
619 o += l;
620 len -= l;
621 }
622 else if (e[1] == 'i') {
623 int l = snprintf (o, len, "\"TEMP_FILE_NAME\"");
624 o += l;
625 len -= l;
626 }
627 else {
628 strncpy (o, e, 2);
629 o += 2;
630 len -= 2;
631 }
632 e += 2;
633 }
634 else {
635 *o++ = *e++;
636 *o = 0;
637 len--;
638 }
639 }
640
641 gtk_widget_set_tooltip_text (GTK_WIDGET (editable), enc);
642 }
643
644 void
on_output_file_changed(GtkEntry * entry,gpointer user_data)645 on_output_file_changed (GtkEntry *entry,
646 gpointer user_data)
647 {
648 deadbeef->conf_set_str ("converter.output_file_tf", gtk_entry_get_text (entry));
649 deadbeef->conf_save ();
650 }
651
652 void
on_preserve_folders_toggled(GtkToggleButton * togglebutton,gpointer user_data)653 on_preserve_folders_toggled (GtkToggleButton *togglebutton,
654 gpointer user_data)
655 {
656 deadbeef->conf_set_int ("converter.preserve_folder_structure", gtk_toggle_button_get_active (togglebutton));
657 deadbeef->conf_save ();
658 }
659
660 void
on_write_to_source_folder_toggled(GtkToggleButton * togglebutton,gpointer user_data)661 on_write_to_source_folder_toggled (GtkToggleButton *togglebutton,
662 gpointer user_data)
663 {
664 int active = gtk_toggle_button_get_active (togglebutton);
665 converter_ctx_t *conv = user_data;
666 deadbeef->conf_set_int ("converter.write_to_source_folder", active);
667 gtk_widget_set_sensitive (lookup_widget (conv->converter, "output_folder"), !active);
668 gtk_widget_set_sensitive (lookup_widget (conv->converter, "preserve_folders"), !active);
669 }
670
671
672 DB_decoder_t *
plug_get_decoder_for_id(const char * id)673 plug_get_decoder_for_id (const char *id) {
674 DB_decoder_t **plugins = deadbeef->plug_get_decoder_list ();
675 for (int c = 0; plugins[c]; c++) {
676 if (!strcmp (id, plugins[c]->plugin.id)) {
677 return plugins[c];
678 }
679 }
680 return NULL;
681 }
682
683 void
init_encoder_preset_from_dlg(GtkWidget * dlg,ddb_encoder_preset_t * p)684 init_encoder_preset_from_dlg (GtkWidget *dlg, ddb_encoder_preset_t *p) {
685 p->title = strdup (gtk_entry_get_text (GTK_ENTRY (lookup_widget (dlg, "title"))));
686 p->ext = strdup (gtk_entry_get_text (GTK_ENTRY (lookup_widget (dlg, "ext"))));
687 p->encoder = strdup (gtk_entry_get_text (GTK_ENTRY (lookup_widget (dlg, "encoder"))));
688 int method_idx = gtk_combo_box_get_active (GTK_COMBO_BOX (lookup_widget (dlg, "method")));
689 switch (method_idx) {
690 case 0:
691 p->method = DDB_ENCODER_METHOD_PIPE;
692 break;
693 case 1:
694 p->method = DDB_ENCODER_METHOD_FILE;
695 break;
696 }
697
698 p->id3v2_version = gtk_combo_box_get_active (GTK_COMBO_BOX (lookup_widget (dlg, "id3v2_version")));
699 p->tag_id3v2 = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "id3v2")));
700 p->tag_id3v1 = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "id3v1")));
701 p->tag_apev2 = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "apev2")));
702 p->tag_flac = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "flac")));
703 p->tag_oggvorbis = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "oggvorbis")));
704 }
705
706 int
edit_encoder_preset(char * title,GtkWidget * toplevel)707 edit_encoder_preset (char *title, GtkWidget *toplevel) {
708 GtkWidget *dlg = create_convpreset_editor ();
709 gtk_window_set_title (GTK_WINDOW (dlg), title);
710 gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
711
712 gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (toplevel));
713 ddb_encoder_preset_t *p = current_ctx->current_encoder_preset;
714
715 if (p->title) {
716 gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "title")), p->title);
717 }
718 if (p->ext) {
719 gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "ext")), p->ext);
720 }
721 if (p->encoder) {
722 gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "encoder")), p->encoder);
723 }
724 gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (dlg, "method")), p->method);
725
726 gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (dlg, "id3v2_version")), p->id3v2_version);
727 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "id3v2")), p->tag_id3v2);
728 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "id3v1")), p->tag_id3v1);
729 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "apev2")), p->tag_apev2);
730 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "flac")), p->tag_flac);
731 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "oggvorbis")), p->tag_oggvorbis);
732
733 ddb_encoder_preset_t *old = p;
734 int r = GTK_RESPONSE_CANCEL;
735 for (;;) {
736 r = gtk_dialog_run (GTK_DIALOG (dlg));
737 if (r == GTK_RESPONSE_OK) {
738 ddb_encoder_preset_t *p = converter_plugin->encoder_preset_alloc ();
739 if (p) {
740 init_encoder_preset_from_dlg (dlg, p);
741 int err = 0;
742
743 ddb_encoder_preset_t *pp = converter_plugin->encoder_preset_get_list ();
744 for (; pp; pp = pp->next) {
745 if (pp != old && !strcmp (pp->title, p->title)) {
746 err = -2;
747 break;
748 }
749 }
750
751 if (!err) {
752 err = converter_plugin->encoder_preset_save (p, 1);
753 }
754 if (!err) {
755 if (old->title && strcmp (p->title, old->title)) {
756 char path[1024];
757 if (snprintf (path, sizeof (path), "%s/presets/encoders/%s.txt", deadbeef->get_config_dir (), old->title) > 0) {
758 unlink (path);
759 }
760 }
761 free (old->title);
762 free (old->ext);
763 free (old->encoder);
764
765 converter_plugin->encoder_preset_copy (old, p);
766 converter_plugin->encoder_preset_free (p);
767 }
768 else {
769 GtkWidget *warndlg = gtk_message_dialog_new (GTK_WINDOW (gtkui_plugin->get_mainwin ()), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Failed to save encoder preset"));
770 gtk_window_set_transient_for (GTK_WINDOW (warndlg), GTK_WINDOW (dlg));
771 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (warndlg), err == -1 ? _("Check preset folder permissions, try to pick different title, or free up some disk space") : _("Preset with the same name already exists. Try to pick another title."));
772 gtk_window_set_title (GTK_WINDOW (warndlg), _("Error"));
773
774 /*int response = */gtk_dialog_run (GTK_DIALOG (warndlg));
775 gtk_widget_destroy (warndlg);
776 continue;
777 }
778 }
779 }
780 break;
781 }
782
783 gtk_widget_destroy (dlg);
784 return r;
785 }
786
787 void
refresh_encoder_lists(GtkComboBox * combo,GtkTreeView * list)788 refresh_encoder_lists (GtkComboBox *combo, GtkTreeView *list) {
789 // presets list view
790 GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (list)));
791
792 GtkTreePath *path;
793 GtkTreeViewColumn *col;
794 gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
795 int idx = -1;
796 if (path && col) {
797 int *indices = gtk_tree_path_get_indices (path);
798 idx = *indices;
799 g_free (indices);
800 }
801
802 gtk_list_store_clear (mdl);
803 fill_presets (mdl, (ddb_preset_t *)converter_plugin->encoder_preset_get_list (), PRESET_TYPE_ENCODER);
804 if (idx != -1) {
805 path = gtk_tree_path_new_from_indices (idx, -1);
806 gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
807 gtk_tree_path_free (path);
808 }
809
810 // presets combo box
811 int act = gtk_combo_box_get_active (combo);
812 mdl = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
813 gtk_list_store_clear (mdl);
814 fill_presets (mdl, (ddb_preset_t *)converter_plugin->encoder_preset_get_list (), PRESET_TYPE_ENCODER);
815 gtk_combo_box_set_active (combo, act);
816 }
817
818 void
on_encoder_preset_add(GtkButton * button,gpointer user_data)819 on_encoder_preset_add (GtkButton *button,
820 gpointer user_data)
821 {
822 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
823
824 current_ctx->current_encoder_preset = converter_plugin->encoder_preset_alloc ();
825
826 if (GTK_RESPONSE_OK == edit_encoder_preset (_("Add new encoder"), toplevel)) {
827 converter_plugin->encoder_preset_append (current_ctx->current_encoder_preset);
828 GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "encoder"));
829 GtkWidget *list = lookup_widget (toplevel, "presets");
830 refresh_encoder_lists (combo, GTK_TREE_VIEW (list));
831 }
832
833 current_ctx->current_encoder_preset = NULL;
834 }
835
836 void
on_encoder_preset_edit(GtkButton * button,gpointer user_data)837 on_encoder_preset_edit (GtkButton *button,
838 gpointer user_data)
839 {
840 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
841 GtkWidget *list = lookup_widget (toplevel, "presets");
842 GtkTreePath *path;
843 GtkTreeViewColumn *col;
844 gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
845 if (!path || !col) {
846 // nothing selected
847 return;
848 }
849 int *indices = gtk_tree_path_get_indices (path);
850 int idx = *indices;
851 g_free (indices);
852
853 ddb_encoder_preset_t *p = converter_plugin->encoder_preset_get_for_idx (idx);
854 current_ctx->current_encoder_preset = p;
855
856 int r = edit_encoder_preset (_("Edit encoder"), toplevel);
857 if (r == GTK_RESPONSE_OK) {
858 GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "encoder"));
859 refresh_encoder_lists (combo, GTK_TREE_VIEW (list));
860 }
861
862 current_ctx->current_encoder_preset = NULL;
863 }
864
865 void
on_encoder_preset_remove(GtkButton * button,gpointer user_data)866 on_encoder_preset_remove (GtkButton *button,
867 gpointer user_data)
868 {
869
870 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
871 GtkWidget *list = lookup_widget (toplevel, "presets");
872 GtkTreePath *path;
873 GtkTreeViewColumn *col;
874 gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
875 if (!path || !col) {
876 // nothing selected
877 return;
878 }
879 int *indices = gtk_tree_path_get_indices (path);
880 int idx = *indices;
881 g_free (indices);
882
883 ddb_encoder_preset_t *p = converter_plugin->encoder_preset_get_for_idx (idx);
884 if (!p) {
885 return;
886 }
887
888 GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (gtkui_plugin->get_mainwin ()), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Remove preset"));
889 gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (toplevel));
890 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), _("This action will delete the selected preset. Are you sure?"));
891 gtk_window_set_title (GTK_WINDOW (dlg), _("Warning"));
892
893 int response = gtk_dialog_run (GTK_DIALOG (dlg));
894 gtk_widget_destroy (dlg);
895 if (response == GTK_RESPONSE_YES) {
896 char path[1024];
897 if (snprintf (path, sizeof (path), "%s/presets/encoders/%s.txt", deadbeef->get_config_dir (), p->title) > 0) {
898 unlink (path);
899 }
900
901 converter_plugin->encoder_preset_remove (p);
902 converter_plugin->encoder_preset_free (p);
903
904 GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "encoder"));
905 refresh_encoder_lists (combo, GTK_TREE_VIEW (list));
906 }
907 }
908
909 static GtkWidget *encpreset_dialog;
910
911 static void
on_encoder_preset_cursor_changed(GtkTreeView * treeview,gpointer user_data)912 on_encoder_preset_cursor_changed (GtkTreeView *treeview,
913 gpointer user_data) {
914 if (!encpreset_dialog) {
915 return;
916 }
917 GtkWidget *edit = lookup_widget (encpreset_dialog, "edit");
918 GtkWidget *remove = lookup_widget (encpreset_dialog, "remove");
919
920 GtkTreePath *path;
921 GtkTreeViewColumn *col;
922 gtk_tree_view_get_cursor (treeview, &path, &col);
923 if (!path || !col) {
924 // nothing selected
925 gtk_widget_set_sensitive (edit, FALSE);
926 gtk_widget_set_sensitive (remove, FALSE);
927 return;
928 }
929 int *indices = gtk_tree_path_get_indices (path);
930 int idx = *indices;
931 g_free (indices);
932
933 ddb_encoder_preset_t *p = converter_plugin->encoder_preset_get_for_idx (idx);
934 gtk_widget_set_sensitive (edit, !p->readonly);
935 gtk_widget_set_sensitive (remove, !p->readonly);
936 }
937
938
939 void
on_encoder_preset_copy(GtkButton * button,gpointer user_data)940 on_encoder_preset_copy (GtkButton *button, gpointer user_data)
941 {
942 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
943
944 GtkTreeView *treeview = GTK_TREE_VIEW (lookup_widget (toplevel, "presets"));
945
946 GtkTreePath *path;
947 GtkTreeViewColumn *col;
948 gtk_tree_view_get_cursor (treeview, &path, &col);
949 if (!path || !col) {
950 return;
951 }
952 int *indices = gtk_tree_path_get_indices (path);
953 int idx = *indices;
954 g_free (indices);
955
956 ddb_encoder_preset_t *p = converter_plugin->encoder_preset_get_for_idx (idx);
957
958 current_ctx->current_encoder_preset = converter_plugin->encoder_preset_alloc ();
959 if (!current_ctx->current_encoder_preset) {
960 return;
961 }
962 converter_plugin->encoder_preset_copy (current_ctx->current_encoder_preset, p);
963
964 if (GTK_RESPONSE_OK == edit_encoder_preset (_("Add new encoder"), toplevel)) {
965 converter_plugin->encoder_preset_append (current_ctx->current_encoder_preset);
966 GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "encoder"));
967 refresh_encoder_lists (combo, treeview);
968 }
969
970 current_ctx->current_encoder_preset = NULL;
971 }
972
973 void
on_edit_encoder_presets_clicked(GtkButton * button,gpointer user_data)974 on_edit_encoder_presets_clicked (GtkButton *button,
975 gpointer user_data)
976 {
977 GtkWidget *dlg = create_preset_list ();
978 encpreset_dialog = dlg;
979 gtk_window_set_title (GTK_WINDOW (dlg), _("Encoders"));
980 gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (current_ctx->converter));
981 g_signal_connect ((gpointer)lookup_widget (dlg, "add"), "clicked", G_CALLBACK (on_encoder_preset_add), NULL);
982 g_signal_connect ((gpointer)lookup_widget (dlg, "remove"), "clicked", G_CALLBACK (on_encoder_preset_remove), NULL);
983 g_signal_connect ((gpointer)lookup_widget (dlg, "edit"), "clicked", G_CALLBACK (on_encoder_preset_edit), NULL);
984 g_signal_connect ((gpointer)lookup_widget (dlg, "copy"), "clicked", G_CALLBACK (on_encoder_preset_copy), NULL);
985
986 GtkWidget *list = lookup_widget (dlg, "presets");
987 g_signal_connect ((gpointer)list, "cursor-changed", G_CALLBACK (on_encoder_preset_cursor_changed), NULL);
988 GtkCellRenderer *title_cell = gtk_cell_renderer_text_new ();
989 GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("Title"), title_cell, "text", 0, NULL);
990 gtk_tree_view_append_column (GTK_TREE_VIEW (list), GTK_TREE_VIEW_COLUMN (col));
991 GtkListStore *mdl = gtk_list_store_new (1, G_TYPE_STRING);
992 gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (mdl));
993 fill_presets (mdl, (ddb_preset_t *)converter_plugin->encoder_preset_get_list (), PRESET_TYPE_ENCODER);
994 int curr = deadbeef->conf_get_int ("converter.encoder_preset", -1);
995 if (curr != -1) {
996 GtkTreePath *path = gtk_tree_path_new_from_indices (curr, -1);
997 if (path && gtk_tree_path_get_depth (path) > 0) {
998 gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
999 gtk_tree_path_free (path);
1000 }
1001 }
1002 on_encoder_preset_cursor_changed (GTK_TREE_VIEW (list), NULL);
1003 gtk_dialog_run (GTK_DIALOG (dlg));
1004 gtk_widget_destroy (dlg);
1005 encpreset_dialog = NULL;
1006 }
1007
1008 ///// dsp preset gui
1009
1010 void
fill_dsp_plugin_list(GtkListStore * mdl)1011 fill_dsp_plugin_list (GtkListStore *mdl) {
1012 struct DB_dsp_s **dsp = deadbeef->plug_get_dsp_list ();
1013 int i;
1014 for (i = 0; dsp[i]; i++) {
1015 GtkTreeIter iter;
1016 gtk_list_store_append (mdl, &iter);
1017 gtk_list_store_set (mdl, &iter, 0, dsp[i]->plugin.name, -1);
1018 }
1019 }
1020
1021 void
fill_dsp_preset_chain(GtkListStore * mdl)1022 fill_dsp_preset_chain (GtkListStore *mdl) {
1023 ddb_dsp_context_t *dsp = current_ctx->current_dsp_preset->chain;
1024 while (dsp) {
1025 GtkTreeIter iter;
1026 gtk_list_store_append (mdl, &iter);
1027 gtk_list_store_set (mdl, &iter, 0, dsp->plugin->plugin.name, -1);
1028 dsp = dsp->next;
1029 }
1030 }
1031
1032 static int
listview_get_index(GtkWidget * list)1033 listview_get_index (GtkWidget *list) {
1034 GtkTreePath *path;
1035 GtkTreeViewColumn *col;
1036 gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
1037 if (!path) {
1038 // nothing selected
1039 return -1;
1040 }
1041 int *indices = gtk_tree_path_get_indices (path);
1042 int idx = *indices;
1043 g_free (indices);
1044 return idx;
1045 }
1046
1047 void
on_dsp_preset_add_plugin_clicked(GtkButton * button,gpointer user_data)1048 on_dsp_preset_add_plugin_clicked (GtkButton *button,
1049 gpointer user_data)
1050 {
1051 GtkWidget *dlg = create_select_dsp_plugin ();
1052 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
1053 gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (toplevel));
1054 gtk_window_set_title (GTK_WINDOW (dlg), _("Add plugin to DSP chain"));
1055
1056 GtkComboBox *combo;
1057 // fill encoder presets
1058 combo = GTK_COMBO_BOX (lookup_widget (dlg, "plugin"));
1059 GtkListStore *mdl = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
1060 fill_dsp_plugin_list (mdl);
1061 gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("converter.last_selected_dsp", 0));
1062
1063 int r = gtk_dialog_run (GTK_DIALOG (dlg));
1064 if (r == GTK_RESPONSE_OK) {
1065 // create new instance of the selected plugin
1066 int idx = gtk_combo_box_get_active (combo);
1067 struct DB_dsp_s **dsp = deadbeef->plug_get_dsp_list ();
1068 int i;
1069 ddb_dsp_context_t *inst = NULL;
1070 for (i = 0; dsp[i]; i++) {
1071 if (i == idx) {
1072 inst = dsp[i]->open ();
1073 break;
1074 }
1075 }
1076 if (inst) {
1077 // append to DSP chain
1078 ddb_dsp_context_t *tail = current_ctx->current_dsp_preset->chain;
1079 while (tail && tail->next) {
1080 tail = tail->next;
1081 }
1082 if (tail) {
1083 tail->next = inst;
1084 }
1085 else {
1086 current_ctx->current_dsp_preset->chain = inst;
1087 }
1088
1089 // reinit list of instances
1090 GtkWidget *list = lookup_widget (toplevel, "plugins");
1091 GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW(list)));
1092 int idx = listview_get_index (list);
1093 gtk_list_store_clear (mdl);
1094 fill_dsp_preset_chain (mdl);
1095 GtkTreePath *path = gtk_tree_path_new_from_indices (idx, -1);
1096 gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, NULL, FALSE);
1097 gtk_tree_path_free (path);
1098 }
1099 else {
1100 fprintf (stderr, "converter: failed to add DSP plugin to chain\n");
1101 }
1102 }
1103 gtk_widget_destroy (dlg);
1104 }
1105
1106
1107 void
on_dsp_preset_remove_plugin_clicked(GtkButton * button,gpointer user_data)1108 on_dsp_preset_remove_plugin_clicked (GtkButton *button,
1109 gpointer user_data)
1110 {
1111 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
1112 GtkWidget *list = lookup_widget (toplevel, "plugins");
1113 GtkTreePath *path;
1114 GtkTreeViewColumn *col;
1115 gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
1116 if (!path || !col) {
1117 // nothing selected
1118 return;
1119 }
1120 int *indices = gtk_tree_path_get_indices (path);
1121 int idx = *indices;
1122 g_free (indices);
1123 if (idx == -1) {
1124 return;
1125 }
1126
1127 ddb_dsp_context_t *p = current_ctx->current_dsp_preset->chain;
1128 ddb_dsp_context_t *prev = NULL;
1129 int i = idx;
1130 while (p && i--) {
1131 prev = p;
1132 p = p->next;
1133 }
1134 if (p) {
1135 if (prev) {
1136 prev->next = p->next;
1137 }
1138 else {
1139 current_ctx->current_dsp_preset->chain = p->next;
1140 }
1141 p->plugin->close (p);
1142 GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW(list)));
1143 gtk_list_store_clear (mdl);
1144 fill_dsp_preset_chain (mdl);
1145 path = gtk_tree_path_new_from_indices (idx, -1);
1146 gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
1147 gtk_tree_path_free (path);
1148 }
1149 }
1150
1151 static ddb_dsp_context_t *current_dsp_context = NULL;
1152
1153 void
dsp_ctx_set_param(const char * key,const char * value)1154 dsp_ctx_set_param (const char *key, const char *value) {
1155 current_dsp_context->plugin->set_param (current_dsp_context, atoi (key), value);
1156 }
1157
1158 void
dsp_ctx_get_param(const char * key,char * value,int len,const char * def)1159 dsp_ctx_get_param (const char *key, char *value, int len, const char *def) {
1160 strncpy (value, def, len);
1161 current_dsp_context->plugin->get_param (current_dsp_context, atoi (key), value, len);
1162 }
1163
1164 void
on_dsp_preset_plugin_configure_clicked(GtkButton * button,gpointer user_data)1165 on_dsp_preset_plugin_configure_clicked (GtkButton *button,
1166 gpointer user_data)
1167 {
1168 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
1169 GtkWidget *list = lookup_widget (toplevel, "plugins");
1170 int idx = listview_get_index (list);
1171 if (idx == -1) {
1172 return;
1173 }
1174 ddb_dsp_context_t *p = current_ctx->current_dsp_preset->chain;
1175 int i = idx;
1176 while (p && i--) {
1177 p = p->next;
1178 }
1179 if (!p || !p->plugin->configdialog) {
1180 return;
1181 }
1182 current_dsp_context = p;
1183 ddb_dialog_t conf = {
1184 .title = p->plugin->plugin.name,
1185 .layout = p->plugin->configdialog,
1186 .set_param = dsp_ctx_set_param,
1187 .get_param = dsp_ctx_get_param,
1188 .parent = toplevel
1189 };
1190 gtkui_plugin->gui.run_dialog (&conf, 0, NULL, NULL);
1191 current_dsp_context = NULL;
1192 }
1193
1194 static int
swap_items(GtkWidget * list,int idx)1195 swap_items (GtkWidget *list, int idx) {
1196 ddb_dsp_context_t *prev = NULL;
1197 ddb_dsp_context_t *p = current_ctx->current_dsp_preset->chain;
1198
1199 int n = idx;
1200 while (n > 0 && p) {
1201 prev = p;
1202 p = p->next;
1203 n--;
1204 }
1205
1206 if (!p || !p->next) {
1207 return -1;
1208 }
1209
1210 ddb_dsp_context_t *moved = p->next;
1211
1212 if (!moved) {
1213 return -1;
1214 }
1215
1216 ddb_dsp_context_t *last = moved ? moved->next : NULL;
1217
1218 if (prev) {
1219 p->next = last;
1220 prev->next = moved;
1221 moved->next = p;
1222 }
1223 else {
1224 p->next = last;
1225 current_ctx->current_dsp_preset->chain = moved;
1226 moved->next = p;
1227 }
1228 GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW(list)));
1229 gtk_list_store_clear (mdl);
1230 fill_dsp_preset_chain (mdl);
1231 return 0;
1232 }
1233
1234 void
on_dsp_preset_plugin_up_clicked(GtkButton * button,gpointer user_data)1235 on_dsp_preset_plugin_up_clicked (GtkButton *button,
1236 gpointer user_data)
1237 {
1238 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
1239 GtkWidget *list = lookup_widget (toplevel, "plugins");
1240 int idx = listview_get_index (list);
1241 if (idx <= 0) {
1242 return;
1243 }
1244
1245 if (-1 == swap_items (list, idx-1)) {
1246 return;
1247 }
1248 GtkTreePath *path = gtk_tree_path_new_from_indices (idx-1, -1);
1249 gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, NULL, FALSE);
1250 gtk_tree_path_free (path);
1251 }
1252
1253
1254 void
on_dsp_preset_plugin_down_clicked(GtkButton * button,gpointer user_data)1255 on_dsp_preset_plugin_down_clicked (GtkButton *button,
1256 gpointer user_data)
1257 {
1258 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
1259 GtkWidget *list = lookup_widget (toplevel, "plugins");
1260 int idx = listview_get_index (list);
1261 if (idx == -1) {
1262 return;
1263 }
1264
1265 if (-1 == swap_items (list, idx)) {
1266 return;
1267 }
1268 GtkTreePath *path = gtk_tree_path_new_from_indices (idx+1, -1);
1269 gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, NULL, FALSE);
1270 gtk_tree_path_free (path);
1271 }
1272
1273
1274 int
edit_dsp_preset(const char * title,GtkWidget * toplevel,ddb_dsp_preset_t * orig)1275 edit_dsp_preset (const char *title, GtkWidget *toplevel, ddb_dsp_preset_t *orig) {
1276 int r = GTK_RESPONSE_CANCEL;
1277
1278 GtkWidget *dlg = create_dsppreset_editor ();
1279 gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
1280 gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (toplevel));
1281 gtk_window_set_title (GTK_WINDOW (dlg), title);
1282
1283 ddb_dsp_preset_t *p = current_ctx->current_dsp_preset;
1284
1285 // title
1286 if (p->title) {
1287 gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "title")), p->title);
1288 }
1289
1290 {
1291 GtkWidget *list = lookup_widget (dlg, "plugins");
1292 GtkCellRenderer *title_cell = gtk_cell_renderer_text_new ();
1293 GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("Plugin"), title_cell, "text", 0, NULL);
1294 gtk_tree_view_append_column (GTK_TREE_VIEW (list), GTK_TREE_VIEW_COLUMN (col));
1295 GtkListStore *mdl = gtk_list_store_new (1, G_TYPE_STRING);
1296 gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (mdl));
1297
1298 fill_dsp_preset_chain (mdl);
1299 GtkTreePath *path = gtk_tree_path_new_from_indices (0, -1);
1300 gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, NULL, FALSE);
1301 gtk_tree_path_free (path);
1302 }
1303
1304 for (;;) {
1305 r = gtk_dialog_run (GTK_DIALOG (dlg));
1306
1307 if (r == GTK_RESPONSE_OK) {
1308 const char *title = gtk_entry_get_text (GTK_ENTRY (lookup_widget (dlg, "title")));
1309 int err = 0;
1310
1311 // don't allow duplicate title with existing presets
1312 ddb_dsp_preset_t *pp = converter_plugin->dsp_preset_get_list ();
1313 for (; pp; pp = pp->next) {
1314 if (pp != orig && !strcmp (pp->title, title)) {
1315 err = -2;
1316 break;
1317 }
1318 }
1319
1320 if (!err) {
1321 if (current_ctx->current_dsp_preset->title) {
1322 free (current_ctx->current_dsp_preset->title);
1323 }
1324 current_ctx->current_dsp_preset->title = strdup (title);
1325 err = converter_plugin->dsp_preset_save (current_ctx->current_dsp_preset, 1);
1326 }
1327
1328 if (err < 0) {
1329 GtkWidget *warndlg = gtk_message_dialog_new (GTK_WINDOW (gtkui_plugin->get_mainwin ()), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Failed to save DSP preset"));
1330 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (warndlg), err == -1 ? _("Check preset folder permissions, try to pick different title, or free up some disk space") : _("Preset with the same name already exists. Try to pick another title."));
1331 gtk_window_set_title (GTK_WINDOW (warndlg), _("Error"));
1332
1333 gtk_window_set_transient_for (GTK_WINDOW (warndlg), GTK_WINDOW (dlg));
1334 /*int response = */gtk_dialog_run (GTK_DIALOG (warndlg));
1335 gtk_widget_destroy (warndlg);
1336 continue;
1337 }
1338
1339 }
1340
1341 break;
1342 }
1343
1344 gtk_widget_destroy (dlg);
1345 return r;
1346 }
1347
1348 void
refresh_dsp_lists(GtkComboBox * combo,GtkTreeView * list)1349 refresh_dsp_lists (GtkComboBox *combo, GtkTreeView *list) {
1350 // presets list view
1351 GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (list)));
1352
1353 GtkTreePath *path;
1354 GtkTreeViewColumn *col;
1355 int idx = -1;
1356
1357 gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
1358 if (path && col) {
1359 int *indices = gtk_tree_path_get_indices (path);
1360 idx = *indices;
1361 g_free (indices);
1362 }
1363
1364 gtk_list_store_clear (mdl);
1365 fill_presets (mdl, (ddb_preset_t *)converter_plugin->dsp_preset_get_list (), PRESET_TYPE_DSP);
1366 if (idx != -1) {
1367 path = gtk_tree_path_new_from_indices (idx, -1);
1368 gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
1369 gtk_tree_path_free (path);
1370 }
1371
1372 // presets combo box
1373 int act = gtk_combo_box_get_active (combo);
1374 mdl = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
1375 gtk_list_store_clear (mdl);
1376 GtkTreeIter iter;
1377 gtk_list_store_append (mdl, &iter);
1378 gtk_list_store_set (mdl, &iter, 0, "Pass through", -1);
1379 fill_presets (mdl, (ddb_preset_t *)converter_plugin->dsp_preset_get_list (), PRESET_TYPE_DSP);
1380 gtk_combo_box_set_active (combo, act);
1381 }
1382
1383
1384 void
on_dsp_preset_add(GtkButton * button,gpointer user_data)1385 on_dsp_preset_add (GtkButton *button,
1386 gpointer user_data)
1387 {
1388
1389 current_ctx->current_dsp_preset = converter_plugin->dsp_preset_alloc ();
1390
1391 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
1392
1393 if (GTK_RESPONSE_OK == edit_dsp_preset (_("New DSP Preset"), toplevel, NULL)) {
1394 converter_plugin->dsp_preset_append (current_ctx->current_dsp_preset);
1395 GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "dsp_preset"));
1396 GtkWidget *list = lookup_widget (toplevel, "presets");
1397 refresh_dsp_lists (combo, GTK_TREE_VIEW (list));
1398 }
1399 else {
1400 converter_plugin->dsp_preset_free (current_ctx->current_dsp_preset);
1401 }
1402
1403 current_ctx->current_dsp_preset = NULL;
1404 }
1405
1406 void
on_dsp_preset_copy(GtkButton * button,gpointer user_data)1407 on_dsp_preset_copy (GtkButton *button, gpointer user_data)
1408 {
1409 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
1410
1411 GtkTreeView *treeview = GTK_TREE_VIEW (lookup_widget (toplevel, "presets"));
1412
1413 GtkTreePath *path;
1414 GtkTreeViewColumn *col;
1415 gtk_tree_view_get_cursor (treeview, &path, &col);
1416 if (!path || !col) {
1417 return;
1418 }
1419 int *indices = gtk_tree_path_get_indices (path);
1420 int idx = *indices;
1421 g_free (indices);
1422
1423 ddb_dsp_preset_t *p = converter_plugin->dsp_preset_get_for_idx (idx);
1424
1425 current_ctx->current_dsp_preset = converter_plugin->dsp_preset_alloc ();
1426 if (!current_ctx->current_dsp_preset) {
1427 return;
1428 }
1429 converter_plugin->dsp_preset_copy (current_ctx->current_dsp_preset, p);
1430
1431 if (GTK_RESPONSE_OK == edit_dsp_preset (_("New DSP Preset"), toplevel, NULL)) {
1432 converter_plugin->dsp_preset_append (current_ctx->current_dsp_preset);
1433 GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "dsp_preset"));
1434 refresh_dsp_lists (combo, treeview);
1435 }
1436 else {
1437 converter_plugin->dsp_preset_free (current_ctx->current_dsp_preset);
1438 }
1439
1440 current_ctx->current_dsp_preset = NULL;
1441 }
1442
1443 void
on_dsp_preset_remove(GtkButton * button,gpointer user_data)1444 on_dsp_preset_remove (GtkButton *button,
1445 gpointer user_data)
1446 {
1447 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
1448 GtkWidget *list = lookup_widget (toplevel, "presets");
1449 GtkTreePath *path;
1450 GtkTreeViewColumn *col;
1451 gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
1452 if (!path || !col) {
1453 // nothing selected
1454 return;
1455 }
1456 int *indices = gtk_tree_path_get_indices (path);
1457 int idx = *indices;
1458 g_free (indices);
1459
1460 ddb_dsp_preset_t *p = converter_plugin->dsp_preset_get_for_idx (idx);
1461 if (!p) {
1462 return;
1463 }
1464
1465 GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (gtkui_plugin->get_mainwin ()), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Remove preset"));
1466 gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (toplevel));
1467 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), _("This action will delete the selected preset. Are you sure?"));
1468 gtk_window_set_title (GTK_WINDOW (dlg), _("Warning"));
1469
1470 int response = gtk_dialog_run (GTK_DIALOG (dlg));
1471 gtk_widget_destroy (dlg);
1472 if (response == GTK_RESPONSE_YES) {
1473 char path[1024];
1474 if (snprintf (path, sizeof (path), "%s/presets/dsp/%s.txt", deadbeef->get_config_dir (), p->title) > 0) {
1475 unlink (path);
1476 }
1477
1478 converter_plugin->dsp_preset_remove (p);
1479 converter_plugin->dsp_preset_free (p);
1480
1481 GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "dsp_preset"));
1482 refresh_dsp_lists (combo, GTK_TREE_VIEW (list));
1483 }
1484 }
1485
1486 void
on_dsp_preset_edit(GtkButton * button,gpointer user_data)1487 on_dsp_preset_edit (GtkButton *button,
1488 gpointer user_data)
1489 {
1490 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
1491
1492 GtkWidget *list = lookup_widget (toplevel, "presets");
1493 GtkTreePath *path;
1494 GtkTreeViewColumn *col;
1495 gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
1496 if (!path || !col) {
1497 // nothing selected
1498 return;
1499 }
1500 int *indices = gtk_tree_path_get_indices (path);
1501 int idx = *indices;
1502 g_free (indices);
1503 if (idx == -1) {
1504 return;
1505 }
1506
1507 ddb_dsp_preset_t *p = converter_plugin->dsp_preset_get_for_idx (idx);
1508 if (!p) {
1509 return;
1510 }
1511
1512 current_ctx->current_dsp_preset = converter_plugin->dsp_preset_alloc ();
1513 converter_plugin->dsp_preset_copy (current_ctx->current_dsp_preset, p);
1514
1515 int r = edit_dsp_preset (_("Edit DSP Preset"), toplevel, p);
1516 if (r == GTK_RESPONSE_OK) {
1517 // replace preset
1518 converter_plugin->dsp_preset_replace (p, current_ctx->current_dsp_preset);
1519 converter_plugin->dsp_preset_free (p);
1520 GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "dsp_preset"));
1521 refresh_dsp_lists (combo, GTK_TREE_VIEW (list));
1522 }
1523 else {
1524 converter_plugin->dsp_preset_free (current_ctx->current_dsp_preset);
1525 }
1526
1527 current_ctx->current_dsp_preset = NULL;
1528 }
1529
1530 void
on_edit_dsp_presets_clicked(GtkButton * button,gpointer user_data)1531 on_edit_dsp_presets_clicked (GtkButton *button,
1532 gpointer user_data)
1533 {
1534 GtkWidget *dlg = create_preset_list ();
1535 gtk_window_set_title (GTK_WINDOW (dlg), _("DSP Presets"));
1536 gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (current_ctx->converter));
1537 g_signal_connect ((gpointer)lookup_widget (dlg, "add"), "clicked", G_CALLBACK (on_dsp_preset_add), NULL);
1538 g_signal_connect ((gpointer)lookup_widget (dlg, "remove"), "clicked", G_CALLBACK (on_dsp_preset_remove), NULL);
1539 g_signal_connect ((gpointer)lookup_widget (dlg, "edit"), "clicked", G_CALLBACK (on_dsp_preset_edit), NULL);
1540 g_signal_connect ((gpointer)lookup_widget (dlg, "copy"), "clicked", G_CALLBACK (on_dsp_preset_copy), NULL);
1541
1542 GtkWidget *list = lookup_widget (dlg, "presets");
1543 GtkCellRenderer *title_cell = gtk_cell_renderer_text_new ();
1544 GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("Title"), title_cell, "text", 0, NULL);
1545 gtk_tree_view_append_column (GTK_TREE_VIEW (list), GTK_TREE_VIEW_COLUMN (col));
1546 GtkListStore *mdl = gtk_list_store_new (1, G_TYPE_STRING);
1547 gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (mdl));
1548 fill_presets (mdl, (ddb_preset_t *)converter_plugin->dsp_preset_get_list (), PRESET_TYPE_DSP);
1549 int curr = deadbeef->conf_get_int ("converter.dsp_preset", -1);
1550 if (curr >= 0) {
1551 GtkTreePath *path = gtk_tree_path_new_from_indices (curr, -1);
1552 gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
1553 gtk_tree_path_free (path);
1554 }
1555 gtk_dialog_run (GTK_DIALOG (dlg));
1556 gtk_widget_destroy (dlg);
1557 }
1558
1559
1560 void
on_converter_output_format_changed(GtkComboBox * combobox,gpointer user_data)1561 on_converter_output_format_changed (GtkComboBox *combobox,
1562 gpointer user_data)
1563 {
1564 int idx = gtk_combo_box_get_active (combobox);
1565 deadbeef->conf_set_int ("converter.output_format", idx);
1566 deadbeef->conf_save ();
1567 }
1568
1569 GtkWidget*
title_formatting_help_link_create(gchar * widget_name,gchar * string1,gchar * string2,gint int1,gint int2)1570 title_formatting_help_link_create (gchar *widget_name, gchar *string1, gchar *string2,
1571 gint int1, gint int2)
1572 {
1573 GtkWidget *link = gtk_link_button_new_with_label ("http://github.com/Alexey-Yakovenko/deadbeef/wiki/Title-formatting-2.0", _("Help"));
1574 return link;
1575 }
1576
1577 GtkWidget*
encoder_cmdline_help_link_create(gchar * widget_name,gchar * string1,gchar * string2,gint int1,gint int2)1578 encoder_cmdline_help_link_create (gchar *widget_name, gchar *string1, gchar *string2,
1579 gint int1, gint int2)
1580 {
1581 GtkWidget *link = gtk_link_button_new_with_label ("http://github.com/Alexey-Yakovenko/deadbeef/wiki/Encoder-Command-Line", _("Help"));
1582 return link;
1583 }
1584
1585 static DB_plugin_action_t convert_action = {
1586 .title = "Convert",
1587 .name = "convert",
1588 .flags = DB_ACTION_MULTIPLE_TRACKS | DB_ACTION_SINGLE_TRACK | DB_ACTION_ADD_MENU,
1589 .callback2 = converter_show,
1590 .next = NULL
1591 };
1592
1593 static DB_plugin_action_t *
convgui_get_actions(DB_playItem_t * it)1594 convgui_get_actions (DB_playItem_t *it)
1595 {
1596 return &convert_action;
1597 }
1598
1599 static int
convgui_connect(void)1600 convgui_connect (void) {
1601 gtkui_plugin = (ddb_gtkui_t *)deadbeef->plug_get_for_id (DDB_GTKUI_PLUGIN_ID);
1602 converter_plugin = (ddb_converter_t *)deadbeef->plug_get_for_id ("converter");
1603 if (!gtkui_plugin) {
1604 fprintf (stderr, "convgui: gtkui plugin not found\n");
1605 return -1;
1606 }
1607 if (!converter_plugin) {
1608 fprintf (stderr, "convgui: converter plugin not found\n");
1609 return -1;
1610 }
1611 #define REQ_CONV_VERSION 4
1612 if (!PLUG_TEST_COMPAT(&converter_plugin->misc.plugin, 1, REQ_CONV_VERSION)) {
1613 fprintf (stderr, "convgui: need converter>=1.%d, but found %d.%d\n", REQ_CONV_VERSION, converter_plugin->misc.plugin.version_major, converter_plugin->misc.plugin.version_minor);
1614 return -1;
1615 }
1616 return 0;
1617 }
1618
1619 static void
import_legacy_tf(const char * key_from,const char * key_to)1620 import_legacy_tf (const char *key_from, const char *key_to) {
1621 deadbeef->conf_lock ();
1622 if (!deadbeef->conf_get_str_fast (key_to, NULL)
1623 && deadbeef->conf_get_str_fast (key_from, NULL)) {
1624 char old[200], new[200];
1625 deadbeef->conf_get_str (key_from, "", old, sizeof (old));
1626 deadbeef->tf_import_legacy (old, new, sizeof (new));
1627 deadbeef->conf_set_str (key_to, new);
1628 }
1629 deadbeef->conf_unlock ();
1630 }
1631
1632 static int
convgui_start(void)1633 convgui_start (void) {
1634 import_legacy_tf ("converter.output_file", "converter.output_file_tf");
1635 return 0;
1636 }
1637
1638 DB_misc_t plugin = {
1639 .plugin.api_vmajor = 1,
1640 .plugin.api_vminor = 5,
1641 .plugin.version_major = 1,
1642 .plugin.version_minor = 2,
1643 .plugin.type = DB_PLUGIN_MISC,
1644 #if GTK_CHECK_VERSION(3,0,0)
1645 .plugin.name = "Converter GTK3 UI",
1646 #else
1647 .plugin.name = "Converter GTK2 UI",
1648 #endif
1649 .plugin.descr = "GTK User interface for the Converter plugin\n"
1650 "Usage:\n"
1651 "· select some tracks in playlist\n"
1652 "· right click\n"
1653 "· select «Convert»\n",
1654 .plugin.copyright =
1655 "Converter UI for DeaDBeeF Player\n"
1656 "Copyright (C) 2009-2015 Alexey Yakovenko and other contributors\n"
1657 "\n"
1658 "This software is provided 'as-is', without any express or implied\n"
1659 "warranty. In no event will the authors be held liable for any damages\n"
1660 "arising from the use of this software.\n"
1661 "\n"
1662 "Permission is granted to anyone to use this software for any purpose,\n"
1663 "including commercial applications, and to alter it and redistribute it\n"
1664 "freely, subject to the following restrictions:\n"
1665 "\n"
1666 "1. The origin of this software must not be misrepresented; you must not\n"
1667 " claim that you wrote the original software. If you use this software\n"
1668 " in a product, an acknowledgment in the product documentation would be\n"
1669 " appreciated but is not required.\n"
1670 "\n"
1671 "2. Altered source versions must be plainly marked as such, and must not be\n"
1672 " misrepresented as being the original software.\n"
1673 "\n"
1674 "3. This notice may not be removed or altered from any source distribution.\n"
1675 ,
1676 .plugin.website = "http://deadbeef.sf.net",
1677 .plugin.get_actions = convgui_get_actions,
1678 .plugin.connect = convgui_connect,
1679 .plugin.start = convgui_start,
1680 };
1681
1682 DB_plugin_t *
1683 #if GTK_CHECK_VERSION(3,0,0)
converter_gtk3_load(DB_functions_t * api)1684 converter_gtk3_load (DB_functions_t *api) {
1685 #else
1686 converter_gtk2_load (DB_functions_t *api) {
1687 #endif
1688 deadbeef = api;
1689 return DB_PLUGIN (&plugin);
1690 }
1691
1692