OSC: Add preset loading to OSC GUI
[ardour.git] / libs / surfaces / osc / osc_gui.cc
1 /*
2     Copyright (C) 2016 Robin Gareus <robin@gareus.org
3     Copyright (C) 2009-2012 Paul Davis
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include <iostream>
22 #include <list>
23 #include <string>
24 #include <vector>
25 //#include <glibmm/miscutils.h>
26
27 #include "pbd/file_utils.h"
28
29 #include <gtkmm/box.h>
30 #include <gtkmm/notebook.h>
31 #include <gtkmm/table.h>
32 #include <gtkmm/label.h>
33 #include <gtkmm/button.h>
34 #include <gtkmm/spinbutton.h>
35 #include <gtkmm/comboboxtext.h>
36
37 #include "gtkmm2ext/gtk_ui.h"
38 #include "gtkmm2ext/gui_thread.h"
39 #include "gtkmm2ext/utils.h"
40
41 #include "ardour/filesystem_paths.h"
42
43 #include "osc.h"
44 #include "osc_gui.h"
45
46 #include "pbd/i18n.h"
47
48 using namespace PBD;
49 using namespace ARDOUR;
50 using namespace Gtk;
51 using namespace Gtkmm2ext;
52 using namespace ArdourSurface;
53
54 OSC_GUI::OSC_GUI (OSC& p)
55         : cp (p)
56 {
57         int n = 0; // table row
58         Table* table = manage (new Table);
59         Label* label;
60         Button* button;
61         table->set_row_spacings (10);
62         table->set_col_spacings (6);
63         table->set_border_width (12);
64         get_session ();
65         preset_busy = true;
66
67         // show our url
68         label = manage (new Gtk::Label(_("Connection:")));
69         label->set_alignment(1, .5);
70         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
71         label = manage (new Gtk::Label(cp.get_server_url()));
72         table->attach (*label, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
73         ++n;
74
75         // show and set port to auto (default) or manual (one surface only)
76         label = manage (new Gtk::Label(_("Port Mode:")));
77         label->set_alignment(1, .5);
78         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
79         table->attach (portmode_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
80         std::vector<std::string> portmode_options;
81         portmode_options.push_back (_("Auto"));
82         portmode_options.push_back (_("Manual"));
83
84         set_popdown_strings (portmode_combo, portmode_options);
85         portmode_combo.set_active ((int)cp.get_portmode());
86         ++n;
87
88         // port entry box
89         label = manage (new Gtk::Label(_("Manual Port:")));
90         label->set_alignment(1, .5);
91         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
92         table->attach (port_entry, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
93         port_entry.set_range(1024, 0xffff);
94         port_entry.set_increments (1, 100);
95         port_entry.set_text(cp.get_remote_port().c_str());
96         if (!cp.get_portmode()) {
97                 port_entry.set_sensitive (false);
98         }
99         ++n;
100
101         // default banksize setting
102         label = manage (new Gtk::Label(_("Bank Size:")));
103         label->set_alignment(1, .5);
104         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
105         table->attach (bank_entry, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
106         bank_entry.set_range (0, 0xffff);
107         bank_entry.set_increments (1, 8);
108         bank_entry.set_value (cp.get_banksize());
109
110         ++n;
111
112         // Gain Mode
113         label = manage (new Gtk::Label(_("Gain Mode:")));
114         label->set_alignment(1, .5);
115         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
116         table->attach (gainmode_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
117         std::vector<std::string> gainmode_options;
118         gainmode_options.push_back (_("dB"));
119         gainmode_options.push_back (_("Position"));
120
121         set_popdown_strings (gainmode_combo, gainmode_options);
122         gainmode_combo.set_active ((int)cp.get_gainmode());
123         ++n;
124
125         // debug setting
126         label = manage (new Gtk::Label(_("Debug:")));
127         label->set_alignment(1, .5);
128         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
129         table->attach (debug_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
130
131         std::vector<std::string> debug_options;
132         debug_options.push_back (_("Off"));
133         debug_options.push_back (_("Log invalid messages"));
134         debug_options.push_back (_("Log all messages"));
135
136         set_popdown_strings (debug_combo, debug_options);
137         debug_combo.set_active ((int)cp.get_debug_mode());
138         ++n;
139
140         // Preset loader combo
141         label = manage (new Gtk::Label(_("Preset:")));
142         label->set_alignment(1, .5);
143         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
144         table->attach (preset_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
145
146         preset_files.clear();
147         // no files for these two
148         preset_options.push_back (_("Last Loaded Session"));
149         preset_options.push_back (_("Ardour Factory Setting"));
150         // user is special it appears in menu even if no file is present
151         preset_options.push_back ("User");
152         preset_files["User"] = "";
153         // scan for OSC .preset files
154         scan_preset_files ();
155
156         set_popdown_strings (preset_combo, preset_options);
157         preset_combo.set_active (0);
158         preset_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::preset_changed));
159         ++n;
160
161         // refresh button
162         button = manage (new Gtk::Button(_("Clear OSC Devices")));
163         table->attach (*button, 0, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 10);
164
165         table->show_all ();
166         append_page (*table, _("OSC Setup"));
167
168         debug_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::debug_changed));
169         portmode_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::portmode_changed));
170         gainmode_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::gainmode_changed));
171         button->signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::clear_device));
172         port_entry.signal_activate().connect (sigc::mem_fun (*this, &OSC_GUI::port_changed));
173         bank_entry.signal_activate().connect (sigc::mem_fun (*this, &OSC_GUI::bank_changed));
174
175         // Strip Types Calculate Page
176         int stn = 0; // table row
177         Table* sttable = manage (new Table);
178         sttable->set_row_spacings (8);
179         sttable->set_col_spacings (6);
180         sttable->set_border_width (25);
181
182         // show our url
183         label = manage (new Gtk::Label(_("Select Desired Types of Tracks")));
184         sttable->attach (*label, 0, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
185         ++stn;
186
187         label = manage (new Gtk::Label(_("Strip Types Value:")));
188         label->set_alignment(1, .5);
189         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 15);
190         calculate_strip_types ();
191         current_strip_types.set_width_chars(10);
192         sttable->attach (current_strip_types, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 15);
193         ++stn;
194
195         label = manage (new Gtk::Label(_("Audio Tracks:")));
196         label->set_alignment(1, .5);
197         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
198         sttable->attach (audio_tracks, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
199         ++stn;
200
201         label = manage (new Gtk::Label(_("Midi Tracks:")));
202         label->set_alignment(1, .5);
203         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
204         sttable->attach (midi_tracks, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
205         ++stn;
206
207         label = manage (new Gtk::Label(_("Audio Buses:")));
208         label->set_alignment(1, .5);
209         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
210         sttable->attach (audio_buses, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
211         ++stn;
212
213         label = manage (new Gtk::Label(_("Midi Buses:")));
214         label->set_alignment(1, .5);
215         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
216         sttable->attach (midi_buses, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
217         ++stn;
218
219         label = manage (new Gtk::Label(_("Control Masters:")));
220         label->set_alignment(1, .5);
221         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
222         sttable->attach (control_masters, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
223         ++stn;
224
225         label = manage (new Gtk::Label(_("Master (use /master instead):")));
226         label->set_alignment(1, .5);
227         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
228         sttable->attach (master_type, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
229         ++stn;
230
231         label = manage (new Gtk::Label(_("Monitor (use /monitor instead):")));
232         label->set_alignment(1, .5);
233         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
234         sttable->attach (monitor_type, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
235         ++stn;
236
237         label = manage (new Gtk::Label(_("Selected Tracks (use for selected tracks only):")));
238         label->set_alignment(1, .5);
239         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
240         sttable->attach (selected_tracks, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
241         ++stn;
242
243         label = manage (new Gtk::Label(_("Hidden Tracks:")));
244         label->set_alignment(1, .5);
245         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
246         sttable->attach (hidden_tracks, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
247         ++stn;
248
249
250         sttable->show_all ();
251         append_page (*sttable, _("Default Strip Types"));
252
253
254         // Feedback Calculate Page
255         int fn = 0; // table row
256         Table* fbtable = manage (new Table);
257         fbtable->set_row_spacings (4);
258         fbtable->set_col_spacings (6);
259         fbtable->set_border_width (12);
260
261         // show our url
262         label = manage (new Gtk::Label(_("Select Desired Types of Feedback")));
263         fbtable->attach (*label, 0, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
264         ++fn;
265
266         label = manage (new Gtk::Label(_("Feedback Value:")));
267         label->set_alignment(1, .5);
268         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 15);
269         calculate_feedback ();
270         current_feedback.set_width_chars(10);
271         fbtable->attach (current_feedback, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 15);
272         ++fn;
273
274         label = manage (new Gtk::Label(_("Strip Buttons:")));
275         label->set_alignment(1, .5);
276         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
277         fbtable->attach (strip_buttons_button, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
278         ++fn;
279
280         label = manage (new Gtk::Label(_("Strip Controls:")));
281         label->set_alignment(1, .5);
282         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
283         fbtable->attach (strip_control_button, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
284         ++fn;
285
286         label = manage (new Gtk::Label(_("Use SSID as Path Extension:")));
287         label->set_alignment(1, .5);
288         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
289         fbtable->attach (ssid_as_path, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
290         ++fn;
291
292         label = manage (new Gtk::Label(_("Use Heart Beat:")));
293         label->set_alignment(1, .5);
294         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
295         fbtable->attach (heart_beat, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
296         ++fn;
297
298         label = manage (new Gtk::Label(_("Master Section:")));
299         label->set_alignment(1, .5);
300         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
301         fbtable->attach (master_fb, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
302         ++fn;
303
304         label = manage (new Gtk::Label(_("Play Head Position as Bar and Beat:")));
305         label->set_alignment(1, .5);
306         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
307         fbtable->attach (bar_and_beat, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
308         ++fn;
309
310         label = manage (new Gtk::Label(_("Play Head Position as SMPTE Time:")));
311         label->set_alignment(1, .5);
312         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
313         fbtable->attach (smpte, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
314         ++fn;
315
316         label = manage (new Gtk::Label(_("Metering as a Float:")));
317         label->set_alignment(1, .5);
318         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
319         fbtable->attach (meter_float, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
320         ++fn;
321
322         label = manage (new Gtk::Label(_("Metering as a LED Strip:")));
323         label->set_alignment(1, .5);
324         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
325         fbtable->attach (meter_led, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
326         ++fn;
327
328         label = manage (new Gtk::Label(_("Signal Present:")));
329         label->set_alignment(1, .5);
330         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
331         fbtable->attach (signal_present, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
332         ++fn;
333
334         label = manage (new Gtk::Label(_("Play Head Position as Samples:")));
335         label->set_alignment(1, .5);
336         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
337         fbtable->attach (hp_samples, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
338         ++fn;
339
340         label = manage (new Gtk::Label(_("Playhead Position as Minutes Seconds:")));
341         label->set_alignment(1, .5);
342         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
343         fbtable->attach (hp_min_sec, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
344         ++fn;
345
346         label = manage (new Gtk::Label(_("Playhead Position as per GUI Clock:")));
347         label->set_alignment(1, .5);
348         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
349         fbtable->attach (hp_gui, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
350         hp_gui.set_sensitive (false); // we don't have this yet (Mixbus wants)
351         ++fn;
352
353         label = manage (new Gtk::Label(_("Extra Select Only Feedback:")));
354         label->set_alignment(1, .5);
355         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
356         fbtable->attach (select_fb, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
357         ++fn;
358
359         fbtable->show_all ();
360         append_page (*fbtable, _("Default Feedback"));
361         // set strips and feedback from loaded default values
362         reshow_values ();
363         // connect signals
364         audio_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
365         midi_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
366         audio_buses.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
367         midi_buses.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
368         control_masters.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
369         master_type.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
370         monitor_type.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
371         selected_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
372         hidden_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
373         strip_buttons_button.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
374         strip_control_button.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
375         ssid_as_path.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
376         heart_beat.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
377         master_fb.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
378         bar_and_beat.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
379         smpte.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
380         meter_float.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
381         meter_led.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
382         signal_present.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
383         hp_samples.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
384         hp_min_sec.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
385         hp_gui.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
386         select_fb.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
387         preset_busy = false;
388
389 }
390
391 OSC_GUI::~OSC_GUI ()
392 {
393 }
394
395 // static directory and file handling stuff
396 static Searchpath
397 preset_search_path ()
398 {
399         bool preset_path_defined = false;
400         std::string spath_env (Glib::getenv (preset_env_variable_name, preset_path_defined));
401
402         if (preset_path_defined) {
403                 return spath_env;
404         }
405
406         Searchpath spath (ardour_data_search_path());
407         spath.add_subdirectory_to_paths(preset_dir_name);
408
409         return spath;
410 }
411
412 static std::string
413 user_preset_directory ()
414 {
415         return Glib::build_filename (user_config_directory(), preset_dir_name);
416 }
417
418 static bool
419 preset_filter (const std::string &str, void* /*arg*/)
420 {
421         return (str.length() > strlen(preset_suffix) &&
422                 str.find (preset_suffix) == (str.length() - strlen (preset_suffix)));
423 }
424
425 static std::string
426 legalize_for_path (const std::string& str)
427 {
428         std::string::size_type pos;
429         std::string illegal_chars = "/\\"; /* DOS, POSIX. Yes, we're going to ignore HFS */
430         std::string legal;
431
432         legal = str;
433         pos = 0;
434
435         while ((pos = legal.find_first_of (illegal_chars, pos)) != std::string::npos) {
436                 legal.replace (pos, 1, "_");
437                 pos += 1;
438         }
439
440         return std::string (legal);
441 }
442
443 // end of static functions
444
445 void
446 OSC_GUI::debug_changed ()
447 {
448         std::string str = debug_combo.get_active_text ();
449         if (str == _("Off")) {
450                 cp.set_debug_mode (OSC::Off);
451         }
452         else if (str == _("Log invalid messages")) {
453                 cp.set_debug_mode (OSC::Unhandled);
454         }
455         else if (str == _("Log all messages")) {
456                 cp.set_debug_mode (OSC::All);
457         }
458         else {
459                 std::cerr << "Invalid OSC Debug Mode\n";
460                 assert (0);
461         }
462 }
463
464 void
465 OSC_GUI::portmode_changed ()
466 {
467         std::string str = portmode_combo.get_active_text ();
468         if (str == _("Auto")) {
469                 cp.set_portmode (0);
470                 port_entry.set_sensitive (false);
471         }
472         else if (str == _("Manual")) {
473                 cp.set_portmode (1);
474                 port_entry.set_sensitive (true);
475         }
476         else {
477                 std::cerr << "Invalid OSC Port Mode\n";
478                 assert (0);
479         }
480         save_user ();
481 }
482
483 void
484 OSC_GUI::port_changed ()
485 {
486         std::string str = port_entry.get_text ();
487         if (port_entry.get_value() == 3819) {
488                 str = "8000";
489                 port_entry.set_value (8000);
490         }
491         cp.set_remote_port (str);
492         save_user ();
493 }
494
495 void
496 OSC_GUI::bank_changed ()
497 {
498         uint32_t bsize = bank_entry.get_value ();
499         cp.set_banksize (bsize);
500         save_user ();
501
502 }
503
504 void
505 OSC_GUI::gainmode_changed ()
506 {
507         std::string str = gainmode_combo.get_active_text ();
508         if (str == _("dB")) {
509                 cp.set_gainmode (0);
510         }
511         else if (str == _("Position")) {
512                 cp.set_gainmode (1);
513         }
514         else {
515                 std::cerr << "Invalid OSC Gain Mode\n";
516                 assert (0);
517         }
518         save_user ();
519 }
520
521 void
522 OSC_GUI::clear_device ()
523 {
524         cp.clear_devices();
525 }
526
527 void
528 OSC_GUI::preset_changed ()
529 {
530         preset_busy = true;
531         std::string str = preset_combo.get_active_text ();
532         if (str == "Last Loaded Session") {
533                 restore_sesn_values ();
534         }
535         else if (str == "Ardour Factory Setting") {
536                 factory_reset ();
537         }
538         else if (str == "User") {
539                 load_preset ("User");
540         }
541         else {
542                 load_preset (str);
543         }
544         preset_busy = false;
545 }
546
547 void
548 OSC_GUI::factory_reset ()
549 {
550         cp.set_banksize (0);
551         bank_entry.set_value (0);
552         cp.set_defaultstrip (31);
553         cp.set_defaultfeedback (0);
554         reshow_values ();
555         cp.set_gainmode (0);
556         gainmode_combo.set_active (0);
557         cp.set_portmode (0);
558         portmode_combo.set_active (0);
559         cp.set_remote_port ("8000");
560         port_entry.set_value (8000);
561         cp.clear_devices();
562 }
563
564 void
565 OSC_GUI::reshow_values ()
566 {
567         def_strip = cp.get_defaultstrip();
568         audio_tracks.set_active(def_strip & 1);
569         midi_tracks.set_active(def_strip & 2);
570         audio_buses.set_active(def_strip & 4);
571         midi_buses.set_active(def_strip & 8);
572         control_masters.set_active(def_strip & 16);
573         master_type.set_active(def_strip & 32);
574         monitor_type.set_active(def_strip & 64);
575         selected_tracks.set_active(def_strip & 256);
576         hidden_tracks.set_active(def_strip & 512);
577         def_feedback = cp.get_defaultfeedback();
578         strip_buttons_button.set_active(def_feedback & 1);
579         strip_control_button.set_active(def_feedback & 2);
580         ssid_as_path.set_active(def_feedback & 4);
581         heart_beat.set_active(def_feedback & 8);
582         master_fb.set_active(def_feedback & 16);
583         bar_and_beat.set_active(def_feedback & 32);
584         smpte.set_active(def_feedback & 64);
585         meter_float.set_active(def_feedback & 128);
586         meter_led.set_active(def_feedback & 256);
587         signal_present.set_active(def_feedback & 512);
588         hp_samples.set_active(def_feedback & 1024);
589         hp_min_sec.set_active (def_feedback & 2048);
590         //hp_gui.set_active (false); // we don't have this yet (Mixbus wants)
591         select_fb.set_active(def_feedback & 8192);
592
593         calculate_strip_types ();
594         calculate_feedback ();
595 }
596
597 void
598 OSC_GUI::calculate_feedback ()
599 {
600         fbvalue = 0;
601         if (strip_buttons_button.get_active()) {
602                 fbvalue += 1;
603         }
604         if (strip_control_button.get_active()) {
605                 fbvalue += 2;
606         }
607         if (ssid_as_path.get_active()) {
608                 fbvalue += 4;
609         }
610         if (heart_beat.get_active()) {
611                 fbvalue += 8;
612         }
613         if (master_fb.get_active()) {
614                 fbvalue += 16;
615         }
616         if (bar_and_beat.get_active()) {
617                 fbvalue += 32;
618         }
619         if (smpte.get_active()) {
620                 fbvalue += 64;
621         }
622         if (meter_float.get_active()) {
623                 fbvalue += 128;
624         }
625         if (meter_led.get_active()) {
626                 fbvalue += 256;
627         }
628         if (signal_present.get_active()) {
629                 fbvalue += 512;
630         }
631         if (hp_samples.get_active()) {
632                 fbvalue += 1024;
633         }
634         if (hp_min_sec.get_active()) {
635                 fbvalue += 2048;
636         }
637         if (hp_gui.get_active()) {
638                 fbvalue += 4096;
639         }
640         if (select_fb.get_active()) {
641                 fbvalue += 8192;
642         }
643
644         current_feedback.set_text(string_compose("%1", fbvalue));
645 }
646
647 void
648 OSC_GUI::push_feedback ()
649 {
650         cp.set_defaultfeedback (fbvalue);
651         save_user ();
652 }
653
654 void
655 OSC_GUI::calculate_strip_types ()
656 {
657         stvalue = 0;
658         if (audio_tracks.get_active()) {
659                 stvalue += 1;
660         }
661         if (midi_tracks.get_active()) {
662                 stvalue += 2;
663         }
664         if (audio_buses.get_active()) {
665                 stvalue += 4;
666         }
667         if (midi_buses.get_active()) {
668                 stvalue += 8;
669         }
670         if (control_masters.get_active()) {
671                 stvalue += 16;
672         }
673         if (master_type.get_active()) {
674                 stvalue += 32;
675         }
676         if (monitor_type.get_active()) {
677                 stvalue += 64;
678         }
679         /*if (Auditioner_type.get_active()) {
680                 stvalue += 128; // this one has no user accessable controls
681         }*/
682         if (selected_tracks.get_active()) {
683                 stvalue += 256;
684         }
685         if (hidden_tracks.get_active()) {
686                 stvalue += 512;
687         }
688
689         current_strip_types.set_text(string_compose("%1", stvalue));
690 }
691
692 void
693 OSC_GUI::push_strip_types ()
694 {
695         cp.set_defaultstrip (stvalue);
696         save_user ();
697 }
698
699 void
700 OSC_GUI::set_bitsets ()
701 {
702         if (preset_busy) {
703                 return;
704         }
705         calculate_strip_types ();
706         calculate_feedback ();
707         push_strip_types ();
708         push_feedback ();
709 }
710
711 void
712 OSC_GUI::scan_preset_files ()
713 {
714         std::vector<std::string> presets;
715         Searchpath spath (preset_search_path());
716
717         find_files_matching_filter (presets, spath, preset_filter, 0, false, true);
718         //device_profiles.clear ();preset_list.clear // first two entries already there
719
720         if (presets.empty()) {
721                 error << "No OSC preset files found using " << spath.to_string() << endmsg;
722                 return;
723         }
724
725         for (std::vector<std::string>::iterator i = presets.begin(); i != presets.end(); ++i) {
726                 std::string fullpath = *i;
727                 //DeviceProfile dp; // has to be initial every loop or info from last added.
728
729                 XMLTree tree;
730
731                 if (!tree.read (fullpath.c_str())) {
732                         continue;
733                 }
734
735                 XMLNode* root = tree.root ();
736                 if (!root) {
737                         continue;
738                 }
739                 const XMLProperty* prop;
740                 const XMLNode* child;
741
742                 if (root->name() != "OSCPreset") {
743                         continue;
744                 }
745
746                 if ((child = root->child ("Name")) == 0 || (prop = child->property ("value")) == 0) {
747                         continue;
748                 } else {
749                         if (prop->value() == "User") {
750                                 // We already added user but no file name
751                                 preset_files[prop->value()] = fullpath;
752                         } else if (preset_files.find(prop->value()) == preset_files.end()) {
753                                 preset_options.push_back (prop->value());
754                                 preset_files[prop->value()] = fullpath;
755                         }
756                 }
757
758         }
759 }
760
761 void
762 OSC_GUI::save_user ()
763 {
764         if (preset_busy) {
765                 return;
766         }
767         preset_combo.set_active (2);
768         std::string fullpath = user_preset_directory();
769
770         if (g_mkdir_with_parents (fullpath.c_str(), 0755) < 0) {
771                 error << string_compose(_("Session: cannot create user MCP profile folder \"%1\" (%2)"), fullpath, strerror (errno)) << endmsg;
772                 return;
773         }
774
775         fullpath = Glib::build_filename (fullpath, string_compose ("%1%2", legalize_for_path ("user"), preset_suffix));
776
777         XMLNode* node = new XMLNode ("OSCPreset");
778         XMLNode* child = new XMLNode ("Name");
779
780         child->add_property ("value", "User");
781         node->add_child_nocopy (*child);
782
783         child = new XMLNode ("PortMode");
784         child->add_property ("value", cp.get_portmode());
785         node->add_child_nocopy (*child);
786
787         child = new XMLNode ("Remote-Port");
788         child->add_property ("value", cp.get_remote_port());
789         node->add_child_nocopy (*child);
790
791         child = new XMLNode ("Bank-Size");
792         child->add_property ("value", cp.get_banksize());
793         node->add_child_nocopy (*child);
794
795         child = new XMLNode ("Strip-Types");
796         child->add_property ("value", cp.get_defaultstrip());
797         node->add_child_nocopy (*child);
798
799         child = new XMLNode ("Feedback");
800         child->add_property ("value", cp.get_defaultfeedback());
801         node->add_child_nocopy (*child);
802
803         child = new XMLNode ("Gain-Mode");
804         child->add_property ("value", cp.get_gainmode());
805         node->add_child_nocopy (*child);
806
807         XMLTree tree;
808         tree.set_root (node);
809
810         if (!tree.write (fullpath)) {
811                 error << string_compose ("MCP profile not saved to %1", fullpath) << endmsg;
812         }
813
814 }
815
816 void
817 OSC_GUI::load_preset (std::string preset)
818 {
819         if (preset == "User" && preset_files["User"] == "") {
820                 restore_sesn_values ();
821         } else if (preset_files.find(preset) != preset_files.end()) {
822                 XMLTree tree;
823
824                 if (!tree.read (preset_files[preset])) {
825                         std::cerr << "preset file not found " << preset_files[preset] << "\n";
826                         return;
827                 }
828
829                 XMLNode* root = tree.root ();
830                 if (!root) {
831                         std::cerr << "invalid preset file " << preset_files[preset] << "\n";
832                         return;
833                 }
834                 const XMLProperty* prop;
835                 const XMLNode* child;
836
837                 if (root->name() != "OSCPreset") {
838                         std::cerr << "invalid preset file " << preset_files[preset] << "\n";
839                         return;
840                 }
841
842                 if ((child = root->child ("Name")) == 0 || (prop = child->property ("value")) == 0) {
843                         std::cerr << "preset file missing Name " << preset_files[preset] << "\n";
844                         return;
845                 }
846                 if ((child = root->child ("PortMode")) == 0 || (prop = child->property ("value")) == 0) {
847                         cp.set_portmode (sesn_portmode);
848                         portmode_combo.set_active (sesn_portmode);
849                 } else {
850                         cp.set_portmode (atoi (prop->value().c_str()));
851                         portmode_combo.set_active (atoi (prop->value().c_str()));
852                 }
853                 if ((child = root->child ("Remote-Port")) == 0 || (prop = child->property ("value")) == 0) {
854                         cp.set_remote_port (sesn_port);
855                         port_entry.set_text (sesn_port);
856                 } else {
857                         cp.set_remote_port (prop->value());
858                         port_entry.set_text (prop->value());
859                 }
860                 if ((child = root->child ("Bank-Size")) == 0 || (prop = child->property ("value")) == 0) {
861                         cp.set_banksize (sesn_bank);
862                         bank_entry.set_value (sesn_bank);
863                 } else {
864                         cp.set_banksize (atoi (prop->value().c_str()));
865                         bank_entry.set_value (atoi (prop->value().c_str()));
866                 }
867                 if ((child = root->child ("Strip-Types")) == 0 || (prop = child->property ("value")) == 0) {
868                         cp.set_defaultstrip (sesn_strips);
869                 } else {
870                         cp.set_defaultstrip (atoi (prop->value().c_str()));
871                 }
872                 if ((child = root->child ("Feedback")) == 0 || (prop = child->property ("value")) == 0) {
873                         cp.set_defaultfeedback (sesn_feedback);
874                 } else {
875                         cp.set_defaultfeedback (atoi (prop->value().c_str()));
876                 }
877                 reshow_values (); // show strip types and feed back in GUI
878
879                 if ((child = root->child ("Gain-Mode")) == 0 || (prop = child->property ("value")) == 0) {
880                         cp.set_gainmode (sesn_gainmode);
881                         gainmode_combo.set_active (sesn_gainmode);
882                 } else {
883                         cp.set_gainmode (atoi (prop->value().c_str()));
884                         gainmode_combo.set_active (atoi (prop->value().c_str()));
885                 }
886
887         }
888 }
889
890 void
891 OSC_GUI::get_session ()
892 {
893         sesn_portmode = cp.get_portmode ();
894         sesn_port = cp.get_remote_port ();
895         sesn_bank = cp.get_banksize ();
896         sesn_strips = cp.get_defaultstrip ();
897         sesn_feedback = cp.get_defaultfeedback ();
898         sesn_gainmode = cp.get_gainmode ();
899 }
900
901 void
902 OSC_GUI::restore_sesn_values ()
903 {
904         cp.set_portmode (sesn_portmode);
905         portmode_combo.set_active (sesn_portmode);
906         cp.set_remote_port (sesn_port);
907         port_entry.set_text (sesn_port);
908         cp.set_banksize (sesn_bank);
909         bank_entry.set_value (sesn_bank);
910         cp.set_defaultstrip (sesn_strips);
911         cp.set_defaultfeedback (sesn_feedback);
912         reshow_values ();
913         cp.set_gainmode (sesn_gainmode);
914         gainmode_combo.set_active (sesn_gainmode);
915 }