Vorbis Quality Config GUI
[ardour.git] / gtk2_ardour / patch_change_dialog.cc
1 /*
2     Copyright (C) 2010 Paul Davis
3     Author: Carl Hetherington <cth@carlh.net>
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 <gtkmm/stock.h>
22 #include <gtkmm/table.h>
23
24 #include <boost/algorithm/string.hpp>
25
26 #include "gtkmm2ext/utils.h"
27
28 #include "midi++/midnam_patch.h"
29
30 #include "ardour/beats_samples_converter.h"
31 #include "ardour/instrument_info.h"
32
33 #include "patch_change_dialog.h"
34 #include "gui_thread.h"
35
36 #include "pbd/i18n.h"
37
38 using namespace std;
39 using namespace Gtk;
40 using namespace Gtkmm2ext;
41
42 /** @param tc If non-0, a time converter for this patch change.  If 0, time control will be desensitized */
43 PatchChangeDialog::PatchChangeDialog (
44         const ARDOUR::BeatsSamplesConverter*        tc,
45         ARDOUR::Session*                           session,
46         Evoral::PatchChange<Temporal::Beats> const & patch,
47         ARDOUR::InstrumentInfo&                    info,
48         const Gtk::BuiltinStockID&                 ok,
49         bool                                       allow_delete,
50         bool                                       modal)
51         : ArdourDialog (_("Patch Change"), modal)
52         , _time_converter (tc)
53         , _info (info)
54         , _time (X_("patchchangetime"), true, "", true, false)
55         , _channel (*manage (new Adjustment (1, 1, 16, 1, 4)))
56         , _program (*manage (new Adjustment (1, 1, 128, 1, 16)))
57         , _bank_msb (*manage (new Adjustment (0, 0, 127, 1, 16)))
58         , _bank_lsb (*manage (new Adjustment (0, 0, 127, 1, 16)))
59         , _ignore_signals (false)
60         , _keep_open (!modal)
61 {
62         Table* t = manage (new Table (4, 2));
63         Label* l;
64         t->set_spacings (6);
65         int r = 0;
66
67         if (_time_converter) {
68
69                 l = manage (left_aligned_label (_("Time")));
70                 t->attach (*l, 0, 1, r, r + 1);
71                 t->attach (_time, 1, 2, r, r + 1);
72                 ++r;
73
74                 _time.set_session (session);
75                 _time.set_mode (AudioClock::BBT);
76                 _time.set (_time_converter->to (patch.time ()), true);
77         }
78
79         l = manage (left_aligned_label (_("Patch Bank")));
80         t->attach (*l, 0, 1, r, r + 1);
81         t->attach (_bank_combo, 1, 2, r, r + 1);
82         ++r;
83
84         _bank_combo.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::bank_combo_changed));
85
86         l = manage (left_aligned_label (_("Patch")));
87         t->attach (*l, 0, 1, r, r + 1);
88         t->attach (_patch_combo, 1, 2, r, r + 1);
89         ++r;
90
91         _patch_combo.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::patch_combo_changed));
92
93         l = manage (left_aligned_label (_("Channel")));
94         t->attach (*l, 0, 1, r, r + 1);
95         t->attach (_channel, 1, 2, r, r + 1);
96         ++r;
97
98         _channel.set_value (patch.channel() + 1);
99         _channel.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::channel_changed));
100
101         l = manage (left_aligned_label (_("Program")));
102         t->attach (*l, 0, 1, r, r + 1);
103         t->attach (_program, 1, 2, r, r + 1);
104         ++r;
105
106         _program.set_value (patch.program () + 1);
107         _program.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::program_changed));
108
109         l = manage (left_aligned_label (_("Bank MSB")));
110         t->attach (*l, 0, 1, r, r + 1);
111         t->attach (_bank_msb, 1, 2, r, r + 1);
112         ++r;
113
114         l = manage (left_aligned_label (_("Bank LSB")));
115         t->attach (*l, 0, 1, r, r + 1);
116         t->attach (_bank_lsb, 1, 2, r, r + 1);
117         ++r;
118
119         assert (patch.bank() != UINT16_MAX);
120
121         _bank_msb.set_value ((patch.bank() >> 7));
122         _bank_msb.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::bank_changed));
123         _bank_lsb.set_value ((patch.bank() & 127));
124         _bank_lsb.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::bank_changed));
125
126         get_vbox()->add (*t);
127
128         if (modal) {
129                 add_button (Stock::CANCEL, RESPONSE_CANCEL);
130         }
131         add_button (ok, RESPONSE_ACCEPT);
132         if (allow_delete) {
133                 add_button (Gtk::StockID(GTK_STOCK_DELETE), RESPONSE_REJECT);
134         }
135         set_default_response (RESPONSE_ACCEPT);
136
137         fill_bank_combo ();
138         set_active_bank_combo ();
139         bank_combo_changed ();
140
141         _info.Changed.connect (_info_changed_connection, invalidator (*this),
142                                boost::bind (&PatchChangeDialog::instrument_info_changed, this), gui_context());
143
144         show_all ();
145 }
146
147 void
148 PatchChangeDialog::on_response (int response_id)
149 {
150         if (_keep_open) {
151                 Gtk::Dialog::on_response (response_id);
152         } else {
153                 ArdourDialog::on_response (response_id);
154         }
155 }
156
157 int
158 PatchChangeDialog::get_14bit_bank () const
159 {
160         return (_bank_msb.get_value_as_int() << 7) + _bank_lsb.get_value_as_int();
161 }
162
163 void
164 PatchChangeDialog::instrument_info_changed ()
165 {
166         _bank_combo.clear ();
167         _patch_combo.clear ();
168         fill_bank_combo ();
169         fill_patch_combo ();
170 }
171
172 Evoral::PatchChange<Temporal::Beats>
173 PatchChangeDialog::patch () const
174 {
175         Temporal::Beats t = Temporal::Beats();
176
177         if (_time_converter) {
178                 t = _time_converter->from (_time.current_time ());
179         }
180
181         return Evoral::PatchChange<Temporal::Beats> (
182                 t,
183                 _channel.get_value_as_int() - 1,
184                 _program.get_value_as_int() - 1,
185                 get_14bit_bank ()
186                 );
187 }
188
189 /** Fill the bank_combo according to the current _channel */
190 void
191 PatchChangeDialog::fill_bank_combo ()
192 {
193         _bank_combo.clear ();
194
195         boost::shared_ptr<MIDI::Name::ChannelNameSet> cns = _info.get_patches (_channel.get_value_as_int() - 1);
196
197         if (!cns) {
198                 return;
199         }
200
201         for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = cns->patch_banks().begin(); i != cns->patch_banks().end(); ++i) {
202                 string n = (*i)->name ();
203                 boost::replace_all (n, "_", " ");
204                 _bank_combo.append_text (n);
205         }
206 }
207
208 /** Set the active value of the bank_combo, and _current_patch_bank, from the contents of _bank */
209 void
210 PatchChangeDialog::set_active_bank_combo ()
211 {
212         _current_patch_bank.reset ();
213
214         boost::shared_ptr<MIDI::Name::ChannelNameSet> cns = _info.get_patches (_channel.get_value_as_int() - 1);
215
216         if (!cns) {
217                 return;
218         }
219
220         for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = cns->patch_banks().begin(); i != cns->patch_banks().end(); ++i) {
221
222                 string n = (*i)->name ();
223                 boost::replace_all (n, "_", " ");
224
225                 if ((*i)->number() == get_14bit_bank()) {
226                         _current_patch_bank = *i;
227                         _ignore_signals = true;
228                         _bank_combo.set_active_text (n);
229                         _ignore_signals = false;
230                         return;
231                 }
232         }
233
234         _ignore_signals = true;
235         _bank_combo.set_active (-1);
236         _ignore_signals = false;
237 }
238
239 /** Update _current_patch_bank and reflect the current value of
240  *  bank_combo in the rest of the dialog.
241  */
242 void
243 PatchChangeDialog::bank_combo_changed ()
244 {
245         if (_ignore_signals) {
246                 return;
247         }
248
249         _current_patch_bank.reset ();
250
251         boost::shared_ptr<MIDI::Name::ChannelNameSet> cns = _info.get_patches (_channel.get_value_as_int() - 1);
252
253         if (!cns) {
254                 return;
255         }
256
257         for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = cns->patch_banks().begin(); i != cns->patch_banks().end(); ++i) {
258                 string n = (*i)->name ();
259                 boost::replace_all (n, "_", " ");
260                 if (n == _bank_combo.get_active_text()) {
261                         _current_patch_bank = *i;
262                 }
263         }
264
265         if (_current_patch_bank == 0) {
266                 return;
267         }
268
269         /* Reflect */
270
271         fill_patch_combo ();
272         set_active_patch_combo ();
273
274         if (_current_patch_bank->number() != UINT16_MAX) {
275                 _ignore_signals = true;
276                 _bank_msb.set_value (_current_patch_bank->number() >> 7);
277                 _bank_lsb.set_value (_current_patch_bank->number() & 127);
278                 _ignore_signals = false;
279         }
280 }
281
282 /** Fill the contents of the patch combo */
283 void
284 PatchChangeDialog::fill_patch_combo ()
285 {
286         _patch_combo.clear ();
287
288         if (_current_patch_bank == 0) {
289                 return;
290         }
291
292         const MIDI::Name::PatchNameList& patches = _current_patch_bank->patch_name_list ();
293         for (MIDI::Name::PatchNameList::const_iterator j = patches.begin(); j != patches.end(); ++j) {
294                 string n = (*j)->name ();
295                 boost::replace_all (n, "_", " ");
296                 _patch_combo.append_text (n);
297         }
298 }
299
300 /** Set the active value of the patch combo from the value of the _program entry */
301 void
302 PatchChangeDialog::set_active_patch_combo ()
303 {
304         if (_ignore_signals) {
305                 return;
306         }
307
308         if (_current_patch_bank == 0) {
309                 _ignore_signals = true;
310                 _patch_combo.set_active (-1);
311                 _ignore_signals = false;
312                 return;
313         }
314
315         const MIDI::Name::PatchNameList& patches = _current_patch_bank->patch_name_list ();
316         for (MIDI::Name::PatchNameList::const_iterator j = patches.begin(); j != patches.end(); ++j) {
317                 string n = (*j)->name ();
318                 boost::replace_all (n, "_", " ");
319
320                 MIDI::Name::PatchPrimaryKey const & key = (*j)->patch_primary_key ();
321                 if (key.program() == _program.get_value() - 1) {
322                         _ignore_signals = true;
323                         _patch_combo.set_active_text (n);
324                         _ignore_signals = false;
325                         return;
326                 }
327         }
328
329         _ignore_signals = true;
330         _patch_combo.set_active (-1);
331         _ignore_signals = false;
332 }
333
334 /** Set _program from the current state of _patch_combo */
335 void
336 PatchChangeDialog::patch_combo_changed ()
337 {
338         if (_ignore_signals || _current_patch_bank == 0) {
339                 return;
340         }
341
342         const MIDI::Name::PatchNameList& patches = _current_patch_bank->patch_name_list ();
343
344         for (MIDI::Name::PatchNameList::const_iterator j = patches.begin(); j != patches.end(); ++j) {
345                 string n = (*j)->name ();
346                 boost::replace_all (n, "_", " ");
347
348                 if (n == _patch_combo.get_active_text ()) {
349                         _ignore_signals = true;
350                         _program.set_value ((*j)->program_number() + 1);
351                         _bank_msb.set_value ((*j)->bank_number() >> 7);
352                         _bank_lsb.set_value ((*j)->bank_number() & 127);
353                         _ignore_signals = false;
354                         break;
355                 }
356         }
357 }
358
359 void
360 PatchChangeDialog::channel_changed ()
361 {
362         fill_bank_combo ();
363         set_active_bank_combo ();
364         fill_patch_combo ();
365         set_active_patch_combo ();
366 }
367
368 void
369 PatchChangeDialog::program_changed ()
370 {
371         if (_ignore_signals) {
372                 return;
373         }
374
375         set_active_patch_combo ();
376 }
377
378 void
379 PatchChangeDialog::bank_changed ()
380 {
381         if (_ignore_signals) {
382                 return;
383         }
384
385         set_active_bank_combo ();
386         fill_patch_combo ();
387         set_active_patch_combo ();
388 }
389