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