mp4chaps Lua script: don't clutter global environment
[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_frames_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::BeatsFramesConverter*        tc,
45         ARDOUR::Session*                           session,
46         Evoral::PatchChange<Evoral::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         _bank_msb.set_value ((patch.bank() >> 7));
120         _bank_msb.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::bank_changed));
121
122         _bank_lsb.set_value ((patch.bank() & 127));
123         _bank_lsb.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::bank_changed));
124
125         get_vbox()->add (*t);
126
127         if (modal) {
128                 add_button (Stock::CANCEL, RESPONSE_CANCEL);
129         }
130         add_button (ok, RESPONSE_ACCEPT);
131         if (allow_delete) {
132                 add_button (Gtk::StockID(GTK_STOCK_DELETE), RESPONSE_REJECT);
133         }
134         set_default_response (RESPONSE_ACCEPT);
135
136         fill_bank_combo ();
137         set_active_bank_combo ();
138         bank_combo_changed ();
139
140         _info.Changed.connect (_info_changed_connection, invalidator (*this),
141                                boost::bind (&PatchChangeDialog::instrument_info_changed, this), gui_context());
142
143         show_all ();
144 }
145
146 void
147 PatchChangeDialog::on_response (int response_id)
148 {
149         if (_keep_open) {
150                 Gtk::Dialog::on_response (response_id);
151         } else {
152                 ArdourDialog::on_response (response_id);
153         }
154 }
155
156 int
157 PatchChangeDialog::get_14bit_bank () const
158 {
159         return (_bank_msb.get_value_as_int() << 7) + _bank_lsb.get_value_as_int();
160 }
161
162 void
163 PatchChangeDialog::instrument_info_changed ()
164 {
165         _bank_combo.clear ();
166         _patch_combo.clear ();
167         fill_bank_combo ();
168         fill_patch_combo ();
169 }
170
171 Evoral::PatchChange<Evoral::Beats>
172 PatchChangeDialog::patch () const
173 {
174         Evoral::Beats t = Evoral::Beats();
175
176         if (_time_converter) {
177                 t = _time_converter->from (_time.current_time ());
178         }
179
180         return Evoral::PatchChange<Evoral::Beats> (
181                 t,
182                 _channel.get_value_as_int() - 1,
183                 _program.get_value_as_int() - 1,
184                 get_14bit_bank ()
185                 );
186 }
187
188 /** Fill the bank_combo according to the current _channel */
189 void
190 PatchChangeDialog::fill_bank_combo ()
191 {
192         _bank_combo.clear ();
193
194         boost::shared_ptr<MIDI::Name::ChannelNameSet> cns = _info.get_patches (_channel.get_value_as_int() - 1);
195
196         if (!cns) {
197                 return;
198         }
199
200         for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = cns->patch_banks().begin(); i != cns->patch_banks().end(); ++i) {
201                 string n = (*i)->name ();
202                 boost::replace_all (n, "_", " ");
203                 _bank_combo.append_text (n);
204         }
205 }
206
207 /** Set the active value of the bank_combo, and _current_patch_bank, from the contents of _bank */
208 void
209 PatchChangeDialog::set_active_bank_combo ()
210 {
211         _current_patch_bank.reset ();
212
213         boost::shared_ptr<MIDI::Name::ChannelNameSet> cns = _info.get_patches (_channel.get_value_as_int() - 1);
214
215         if (!cns) {
216                 return;
217         }
218
219         for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = cns->patch_banks().begin(); i != cns->patch_banks().end(); ++i) {
220
221                 string n = (*i)->name ();
222                 boost::replace_all (n, "_", " ");
223
224                 if ((*i)->number() == get_14bit_bank()) {
225                         _current_patch_bank = *i;
226                         _ignore_signals = true;
227                         _bank_combo.set_active_text (n);
228                         _ignore_signals = false;
229                         return;
230                 }
231         }
232
233         _ignore_signals = true;
234         _bank_combo.set_active (-1);
235         _ignore_signals = false;
236 }
237
238 /** Update _current_patch_bank and reflect the current value of
239  *  bank_combo in the rest of the dialog.
240  */
241 void
242 PatchChangeDialog::bank_combo_changed ()
243 {
244         if (_ignore_signals) {
245                 return;
246         }
247
248         _current_patch_bank.reset ();
249
250         boost::shared_ptr<MIDI::Name::ChannelNameSet> cns = _info.get_patches (_channel.get_value_as_int() - 1);
251
252         if (!cns) {
253                 return;
254         }
255
256         for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = cns->patch_banks().begin(); i != cns->patch_banks().end(); ++i) {
257                 string n = (*i)->name ();
258                 boost::replace_all (n, "_", " ");
259                 if (n == _bank_combo.get_active_text()) {
260                         _current_patch_bank = *i;
261                 }
262         }
263
264         if (_current_patch_bank == 0) {
265                 return;
266         }
267
268         /* Reflect */
269
270         fill_patch_combo ();
271         set_active_patch_combo ();
272
273         _ignore_signals = true;
274         _bank_msb.set_value (_current_patch_bank->number() >> 7);
275         _bank_lsb.set_value (_current_patch_bank->number() & 127);
276         _ignore_signals = false;
277 }
278
279 /** Fill the contents of the patch combo */
280 void
281 PatchChangeDialog::fill_patch_combo ()
282 {
283         _patch_combo.clear ();
284
285         if (_current_patch_bank == 0) {
286                 return;
287         }
288
289         const MIDI::Name::PatchNameList& patches = _current_patch_bank->patch_name_list ();
290         for (MIDI::Name::PatchNameList::const_iterator j = patches.begin(); j != patches.end(); ++j) {
291                 string n = (*j)->name ();
292                 boost::replace_all (n, "_", " ");
293                 _patch_combo.append_text (n);
294         }
295 }
296
297 /** Set the active value of the patch combo from the value of the _program entry */
298 void
299 PatchChangeDialog::set_active_patch_combo ()
300 {
301         if (_ignore_signals) {
302                 return;
303         }
304
305         if (_current_patch_bank == 0) {
306                 _ignore_signals = true;
307                 _patch_combo.set_active (-1);
308                 _ignore_signals = false;
309                 return;
310         }
311
312         const MIDI::Name::PatchNameList& patches = _current_patch_bank->patch_name_list ();
313         for (MIDI::Name::PatchNameList::const_iterator j = patches.begin(); j != patches.end(); ++j) {
314                 string n = (*j)->name ();
315                 boost::replace_all (n, "_", " ");
316
317                 MIDI::Name::PatchPrimaryKey const & key = (*j)->patch_primary_key ();
318                 if (key.program() == _program.get_value() - 1) {
319                         _ignore_signals = true;
320                         _patch_combo.set_active_text (n);
321                         _ignore_signals = false;
322                         return;
323                 }
324         }
325
326         _ignore_signals = true;
327         _patch_combo.set_active (-1);
328         _ignore_signals = false;
329 }
330
331 /** Set _program from the current state of _patch_combo */
332 void
333 PatchChangeDialog::patch_combo_changed ()
334 {
335         if (_ignore_signals || _current_patch_bank == 0) {
336                 return;
337         }
338
339         const MIDI::Name::PatchNameList& patches = _current_patch_bank->patch_name_list ();
340
341         for (MIDI::Name::PatchNameList::const_iterator j = patches.begin(); j != patches.end(); ++j) {
342                 string n = (*j)->name ();
343                 boost::replace_all (n, "_", " ");
344
345                 if (n == _patch_combo.get_active_text ()) {
346                         _ignore_signals = true;
347                         _program.set_value ((*j)->program_number() + 1);
348                         _ignore_signals = false;
349                         break;
350                 }
351         }
352 }
353
354 void
355 PatchChangeDialog::channel_changed ()
356 {
357         fill_bank_combo ();
358         set_active_bank_combo ();
359         fill_patch_combo ();
360         set_active_patch_combo ();
361 }
362
363 void
364 PatchChangeDialog::program_changed ()
365 {
366         if (_ignore_signals) {
367                 return;
368         }
369
370         set_active_patch_combo ();
371 }
372
373 void
374 PatchChangeDialog::bank_changed ()
375 {
376         if (_ignore_signals) {
377                 return;
378         }
379
380         set_active_bank_combo ();
381         fill_patch_combo ();
382         set_active_patch_combo ();
383 }
384