couple of fixes to enable building, and building with gtkmm 2.2(<4)
[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 #include <boost/algorithm/string.hpp>
24 #include "ardour/midi_patch_manager.h"
25 #include "ardour/beats_frames_converter.h"
26 #include "patch_change_dialog.h"
27 #include "i18n.h"
28
29 using namespace std;
30 using namespace Gtk;
31
32 /** @param tc If non-0, a time converter for this patch change.  If 0, time control will be desensitized */
33 PatchChangeDialog::PatchChangeDialog (
34         const ARDOUR::BeatsFramesConverter* tc,
35         ARDOUR::Session* session,
36         Evoral::PatchChange<Evoral::MusicalTime> const & patch,
37         string const & model_name,
38         string const & custom_device_node,
39         const Gtk::BuiltinStockID& ok
40         )
41         : ArdourDialog (_("Patch Change"), true)
42         , _time_converter (tc)
43         , _model_name (model_name)
44         , _custom_device_mode (custom_device_node)
45         , _time (X_("patchchangetime"), true, "", true, false)
46         , _channel (*manage (new Adjustment (1, 1, 16, 1, 4)))
47         , _program (*manage (new Adjustment (1, 1, 128, 1, 16)))
48         , _bank (*manage (new Adjustment (1, 1, 16384, 1, 64)))
49         , _ignore_signals (false)
50 {
51         Table* t = manage (new Table (4, 2));
52         Label* l;
53         t->set_spacings (6);
54         int r = 0;
55
56         if (_time_converter) {
57                 
58                 l = manage (new Label (_("Time")));
59                 l->set_alignment (0, 0.5);
60                 t->attach (*l, 0, 1, r, r + 1);
61                 t->attach (_time, 1, 2, r, r + 1);
62                 ++r;
63
64                 _time.set_session (session);
65                 _time.set_mode (AudioClock::BBT);
66                 _time.set (_time_converter->to (patch.time ()), true);
67         }
68
69         l = manage (new Label (_("Patch Bank")));
70         l->set_alignment (0, 0.5);
71         t->attach (*l, 0, 1, r, r + 1);
72         t->attach (_bank_combo, 1, 2, r, r + 1);
73         ++r;
74
75         _bank_combo.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::bank_combo_changed));
76
77         l = manage (new Label (_("Patch")));
78         l->set_alignment (0, 0.5);
79         t->attach (*l, 0, 1, r, r + 1);
80         t->attach (_patch_combo, 1, 2, r, r + 1);
81         ++r;
82         
83         _patch_combo.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::patch_combo_changed));
84
85         l = manage (new Label (_("Channel")));
86         l->set_alignment (0, 0.5);
87         t->attach (*l, 0, 1, r, r + 1);
88         t->attach (_channel, 1, 2, r, r + 1);
89         ++r;
90
91         _channel.set_value (patch.channel() + 1);
92         _channel.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::channel_changed));
93
94         l = manage (new Label (_("Program")));
95         l->set_alignment (0, 0.5);
96         t->attach (*l, 0, 1, r, r + 1);
97         t->attach (_program, 1, 2, r, r + 1);
98         ++r;
99
100         _program.set_value (patch.program () + 1);
101         _program.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::program_changed));
102
103         l = manage (new Label (_("Bank")));
104         l->set_alignment (0, 0.5);
105         t->attach (*l, 0, 1, r, r + 1);
106         t->attach (_bank, 1, 2, r, r + 1);
107         ++r;
108
109         _bank.set_value (patch.bank() + 1);
110         _bank.signal_changed().connect (sigc::mem_fun (*this, &PatchChangeDialog::bank_changed));
111
112         get_vbox()->add (*t);
113
114         add_button (Stock::CANCEL, RESPONSE_CANCEL);
115         add_button (ok, RESPONSE_ACCEPT);
116         set_default_response (RESPONSE_ACCEPT);
117
118         fill_bank_combo ();
119         set_active_bank_combo ();
120         bank_combo_changed ();
121
122         show_all ();
123 }
124
125 Evoral::PatchChange<Evoral::MusicalTime>
126 PatchChangeDialog::patch () const
127 {
128         Evoral::MusicalTime t = 0;
129
130         if (_time_converter) {
131                 t = _time_converter->from (_time.current_time ());
132         }
133
134         return Evoral::PatchChange<Evoral::MusicalTime> (
135                 t,
136                 _channel.get_value_as_int() - 1,
137                 _program.get_value_as_int() - 1,
138                 _bank.get_value_as_int() - 1
139                 );
140 }
141
142 /** Fill the bank_combo according to the current _channel */
143 void
144 PatchChangeDialog::fill_bank_combo ()
145 {
146         MIDI::Name::ChannelNameSet::PatchBanks const * banks = get_banks ();
147         if (banks == 0) {
148                 return;
149         }
150
151         for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = banks->begin(); i != banks->end(); ++i) {
152                 string n = (*i)->name ();
153                 boost::replace_all (n, "_", " ");
154                 _bank_combo.append_text (n);
155         }
156 }
157
158 /** Set the active value of the bank_combo, and _current_patch_bank, from the contents of _bank */
159 void
160 PatchChangeDialog::set_active_bank_combo ()
161 {
162         _current_patch_bank.reset ();
163         
164         MIDI::Name::ChannelNameSet::PatchBanks const * banks = get_banks ();
165         if (banks == 0) {
166                 return;
167         }
168
169         for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = banks->begin(); i != banks->end(); ++i) {
170                 string n = (*i)->name ();
171                 boost::replace_all (n, "_", " ");
172
173                 MIDI::Name::PatchPrimaryKey const * key = (*i)->patch_primary_key ();
174                 if (((key->msb << 7) | key->lsb) == _bank.get_value () - 1) {
175                         _current_patch_bank = *i;
176                         _ignore_signals = true;
177                         _bank_combo.set_active_text (n);
178                         _ignore_signals = false;
179                         return;
180                 }
181         }
182
183         _ignore_signals = true;
184         _bank_combo.set_active (-1);
185         _ignore_signals = false;
186 }
187
188 /** Update _current_patch_bank and reflect the current value of
189  *  bank_combo in the rest of the dialog.
190  */
191 void
192 PatchChangeDialog::bank_combo_changed ()
193 {
194         if (_ignore_signals) {
195                 return;
196         }
197         
198         _current_patch_bank.reset ();
199
200         MIDI::Name::ChannelNameSet::PatchBanks const * banks = get_banks ();
201         if (banks == 0) {
202                 return;
203         }
204
205         for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = banks->begin(); i != banks->end(); ++i) {
206                 string n = (*i)->name ();
207                 boost::replace_all (n, "_", " ");
208                 if (n == _bank_combo.get_active_text()) {
209                         _current_patch_bank = *i;
210                 }
211         }
212
213         /* Reflect */
214
215         fill_patch_combo ();
216         set_active_patch_combo ();
217
218         MIDI::Name::PatchPrimaryKey const * key = _current_patch_bank->patch_primary_key ();
219         _ignore_signals = true;
220         _bank.set_value (((key->msb << 7) | key->lsb) + 1);
221         _ignore_signals = false;
222 }
223
224 /** Fill the contents of the patch combo */
225 void
226 PatchChangeDialog::fill_patch_combo ()
227 {
228         _patch_combo.clear ();
229
230         if (_current_patch_bank == 0) {
231                 return;
232         }
233
234         const MIDI::Name::PatchBank::PatchNameList& patches = _current_patch_bank->patch_name_list ();
235         for (MIDI::Name::PatchBank::PatchNameList::const_iterator j = patches.begin(); j != patches.end(); ++j) {
236                 string n = (*j)->name ();
237                 boost::replace_all (n, "_", " ");
238                 _patch_combo.append_text (n);
239         }
240 }
241
242 /** Set the active value of the patch combo from the value of the _program entry */
243 void
244 PatchChangeDialog::set_active_patch_combo ()
245 {
246         if (_ignore_signals) {
247                 return;
248         }
249
250         if (_current_patch_bank == 0) {
251                 _ignore_signals = true;
252                 _patch_combo.set_active (-1);
253                 _ignore_signals = false;
254                 return;
255         }
256         
257         const MIDI::Name::PatchBank::PatchNameList& patches = _current_patch_bank->patch_name_list ();
258         for (MIDI::Name::PatchBank::PatchNameList::const_iterator j = patches.begin(); j != patches.end(); ++j) {
259                 string n = (*j)->name ();
260                 boost::replace_all (n, "_", " ");
261
262                 MIDI::Name::PatchPrimaryKey const & key = (*j)->patch_primary_key ();
263                 if (key.program_number == _program.get_value() - 1) {
264                         _ignore_signals = true;
265                         _patch_combo.set_active_text (n);
266                         _ignore_signals = false;
267                         return;
268                 }
269         }
270
271         _ignore_signals = true;
272         _patch_combo.set_active (-1);
273         _ignore_signals = false;
274 }       
275
276 /** Set _program from the current state of _patch_combo */
277 void
278 PatchChangeDialog::patch_combo_changed ()
279 {
280         if (_ignore_signals || _current_patch_bank == 0) {
281                 return;
282         }
283
284         const MIDI::Name::PatchBank::PatchNameList& patches = _current_patch_bank->patch_name_list ();
285         for (MIDI::Name::PatchBank::PatchNameList::const_iterator j = patches.begin(); j != patches.end(); ++j) {
286                 string n = (*j)->name ();
287                 boost::replace_all (n, "_", " ");
288                 if (n == _patch_combo.get_active_text ()) {
289                         MIDI::Name::PatchPrimaryKey const & key = (*j)->patch_primary_key ();
290                         _ignore_signals = true;
291                         _program.set_value (key.program_number + 1);
292                         _ignore_signals = false;
293                 }
294         }
295 }
296
297 void
298 PatchChangeDialog::channel_changed ()
299 {
300         fill_bank_combo ();
301         set_active_bank_combo ();
302         fill_patch_combo ();
303         set_active_patch_combo ();
304 }
305
306 void
307 PatchChangeDialog::program_changed ()
308 {
309         if (_ignore_signals) {
310                 return;
311         }
312
313         set_active_patch_combo ();
314 }
315
316 void
317 PatchChangeDialog::bank_changed ()
318 {
319         if (_ignore_signals) {
320                 return;
321         }
322
323         set_active_bank_combo ();
324         fill_patch_combo ();
325         set_active_patch_combo ();
326 }
327
328 MIDI::Name::ChannelNameSet::PatchBanks const *
329 PatchChangeDialog::get_banks ()
330 {
331         MIDI::Name::MidiPatchManager& mpm = MIDI::Name::MidiPatchManager::instance ();
332         boost::shared_ptr<MIDI::Name::ChannelNameSet> channel_name_set = mpm.find_channel_name_set (
333                 _model_name, _custom_device_mode, _channel.get_value_as_int() - 1
334                 );
335
336         if (!channel_name_set) {
337                 return 0;
338         }
339
340         return &channel_name_set->patch_banks ();
341 }