better comments
[ardour.git] / libs / ardour / instrument_info.cc
1 /*
2  * Copyright (C) 2012-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2013-2014 David Robillard <d@drobilla.net>
4  * Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include <algorithm>
22
23 #include "pbd/compose.h"
24
25 #include "midi++/midnam_patch.h"
26
27 #include "ardour/instrument_info.h"
28 #include "ardour/midi_patch_manager.h"
29 #include "ardour/processor.h"
30 #include "ardour/plugin.h"
31 #include "ardour/plugin_insert.h"
32 #include "ardour/rc_configuration.h"
33
34 #include "pbd/i18n.h"
35
36 using namespace ARDOUR;
37 using namespace MIDI::Name;
38 using std::string;
39
40 MIDI::Name::PatchNameList InstrumentInfo::_gm_patches;
41
42 InstrumentInfo::InstrumentInfo ()
43         : external_instrument_model (_("Unknown"))
44 {
45 }
46
47 InstrumentInfo::~InstrumentInfo ()
48 {
49 }
50
51 void
52 InstrumentInfo::set_external_instrument (const string& model, const string& mode)
53 {
54         if (external_instrument_model == model && external_instrument_mode == mode && internal_instrument.expired ()) {
55                 return;
56         }
57         external_instrument_model = model;
58         external_instrument_mode = mode;
59         internal_instrument.reset ();
60         Changed(); /* EMIT SIGNAL */
61 }
62
63 void
64 InstrumentInfo::set_internal_instrument (boost::shared_ptr<Processor> p)
65 {
66         bool changed = !external_instrument_mode.empty ();
67         external_instrument_mode = "";
68
69         boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(p);
70         if (pi && pi->plugin ()->has_midnam ()) {
71                 /* really back hack, following MidiTimeAxisView::model_changed()
72                  *
73                  * InstrumentInfo::get_plugin_patch_name() needs to be overhauled,
74                  * it limits all PluginInsert to generic-midi or only numbers.
75                  */
76                 changed |= !internal_instrument.expired ();
77                 changed |= external_instrument_model != pi->plugin ()->midnam_model ();
78
79                 internal_instrument.reset ();
80                 external_instrument_model = pi->plugin ()->midnam_model ();
81                 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance().custom_device_mode_names_by_model (external_instrument_model);
82                 if (device_modes.size() > 0) {
83                         changed |= external_instrument_mode != device_modes.front();
84                         external_instrument_mode = device_modes.front();
85                 }
86         } else {
87                 changed |= internal_instrument.lock () != p || external_instrument_model != _("Unknown");
88                 internal_instrument = p;
89                 external_instrument_model = _("Unknown");
90         }
91         if (changed) {
92                 Changed(); /* EMIT SIGNAL */
93         }
94 }
95
96 string
97 InstrumentInfo::get_instrument_name () const
98 {
99         boost::shared_ptr<Processor> p = internal_instrument.lock();
100         if (p) {
101                 return p->name();
102         }
103
104         if (external_instrument_mode.empty()) {
105                 return external_instrument_model;
106         } else {
107                 return string_compose ("%1 (%2)", external_instrument_model, external_instrument_mode);
108         }
109 }
110
111 string
112 InstrumentInfo::get_patch_name (uint16_t bank, uint8_t program, uint8_t channel) const
113 {
114         return get_patch_name (bank, program, channel, true);
115 }
116
117 string
118 InstrumentInfo::get_patch_name_without (uint16_t bank, uint8_t program, uint8_t channel) const
119 {
120         return get_patch_name (bank, program, channel, false);
121 }
122
123 string
124 InstrumentInfo::get_patch_name (uint16_t bank, uint8_t program, uint8_t channel, bool with_extra) const
125 {
126         boost::shared_ptr<Processor> p = internal_instrument.lock();
127         if (p) {
128                 return get_plugin_patch_name (p, bank, program, channel);
129         }
130
131         MIDI::Name::PatchPrimaryKey patch_key (program, bank);
132
133         boost::shared_ptr<MIDI::Name::Patch> patch =
134                 MIDI::Name::MidiPatchManager::instance().find_patch (external_instrument_model,
135                                                                      external_instrument_mode, channel, patch_key);
136
137         if (patch) {
138                 return patch->name();
139         } else {
140                 /* program and bank numbers are zero-based: convert to one-based: MIDI_BP_ZERO */
141
142 #define MIDI_BP_ZERO ((Config->get_first_midi_bank_is_zero())?0:1)
143
144                 if (with_extra) {
145                         return string_compose ("prg %1 bnk %2",program + MIDI_BP_ZERO , bank + MIDI_BP_ZERO);
146                 } else {
147                         return string_compose ("%1", program + MIDI_BP_ZERO);
148                 }
149         }
150 }
151
152 string
153 InstrumentInfo::get_controller_name (Evoral::Parameter param) const
154 {
155         boost::shared_ptr<Processor> p = internal_instrument.lock();
156         if (param.type() != MidiCCAutomation) {
157                 return "";
158         }
159         if (p) {
160                 return get_plugin_controller_name (p, param);
161         }
162
163         boost::shared_ptr<MIDI::Name::MasterDeviceNames> dev_names(
164                 MIDI::Name::MidiPatchManager::instance().master_device_by_model(
165                         external_instrument_model));
166         if (!dev_names) {
167                 return "";
168         }
169
170         boost::shared_ptr<ChannelNameSet> chan_names(
171                 dev_names->channel_name_set_by_channel(
172                         external_instrument_mode, param.channel()));
173         if (!chan_names) {
174                 return "";
175         }
176
177         boost::shared_ptr<ControlNameList> control_names(
178                 dev_names->control_name_list(chan_names->control_list_name()));
179         if (!control_names) {
180                 return "";
181         }
182         boost::shared_ptr<const Control> c = control_names->control(param.id());
183
184         if (c) {
185                 return string_compose(c->name() + " [%1]", int(param.channel()) + 1);
186         }
187
188         return "";
189 }
190
191 boost::shared_ptr<MIDI::Name::ChannelNameSet>
192 InstrumentInfo::get_patches (uint8_t channel)
193 {
194         boost::shared_ptr<Processor> p = internal_instrument.lock();
195         if (p) {
196                 return plugin_programs_to_channel_name_set (p);
197         }
198
199         boost::shared_ptr<MIDI::Name::ChannelNameSet> channel_name_set =
200                 MidiPatchManager::instance().find_channel_name_set (external_instrument_model,
201                                                                                                                     external_instrument_mode,
202                                                                                                                     channel);
203
204         //std::cerr << "got channel name set with name '" << channel_name_set->name() << std::endl;
205
206         return channel_name_set;
207 }
208
209 boost::shared_ptr<MIDI::Name::ChannelNameSet>
210 InstrumentInfo::plugin_programs_to_channel_name_set (boost::shared_ptr<Processor> p)
211 {
212         PatchNameList patch_list;
213
214         boost::shared_ptr<PluginInsert> insert = boost::dynamic_pointer_cast<PluginInsert> (p);
215         if (!insert) {
216                 return boost::shared_ptr<ChannelNameSet>();
217         }
218
219         boost::shared_ptr<Plugin> pp = insert->plugin();
220
221         if (pp->current_preset_uses_general_midi()) {
222
223                 patch_list = InstrumentInfo::general_midi_patches ();
224
225         } else if (pp->presets_are_MIDI_programs()) {
226
227                 std::vector<Plugin::PresetRecord> presets = pp->get_presets ();
228                 std::vector<Plugin::PresetRecord>::iterator i;
229                 int n;
230
231                 for (n = 0, i = presets.begin(); i != presets.end(); ++i, ++n) {
232                         if ((*i).valid) {
233                                 patch_list.push_back (boost::shared_ptr<Patch> (new Patch ((*i).label, n)));
234                         } else {
235                                 patch_list.push_back (boost::shared_ptr<Patch> (new Patch (string_compose ("program %1", n), n)));
236                         }
237                 }
238         } else {
239                 for (int n = 0; n < 127; ++n) {
240                         patch_list.push_back (boost::shared_ptr<Patch> (new Patch (string_compose ("program %1", n), n)));
241                 }
242         }
243
244         boost::shared_ptr<PatchBank> pb (new PatchBank (0, p->name()));
245         pb->set_patch_name_list (patch_list);
246
247         ChannelNameSet::PatchBanks patch_banks;
248         patch_banks.push_back (pb);
249
250         boost::shared_ptr<MIDI::Name::ChannelNameSet> cns (new ChannelNameSet);
251         cns->set_patch_banks (patch_banks);
252
253         return cns;
254 }
255
256 const MIDI::Name::PatchNameList&
257 InstrumentInfo::general_midi_patches()
258 {
259         if (_gm_patches.empty()) {
260                 for (int n = 0; n < 128; n++) {
261                         _gm_patches.push_back (boost::shared_ptr<Patch> (new Patch (general_midi_program_names[n], n)));
262                 }
263         }
264
265         return _gm_patches;
266 }
267
268 string
269 InstrumentInfo::get_plugin_controller_name (boost::shared_ptr<ARDOUR::Processor>, Evoral::Parameter param) const
270 {
271         return "";
272 }
273
274 string
275 InstrumentInfo::get_plugin_patch_name (boost::shared_ptr<Processor> p, uint16_t bank, uint8_t program, uint8_t /*channel*/) const
276 {
277         boost::shared_ptr<PluginInsert> insert = boost::dynamic_pointer_cast<PluginInsert> (p);
278         if (insert) {
279                 boost::shared_ptr<Plugin> pp = insert->plugin();
280
281                 if (pp->current_preset_uses_general_midi()) {
282                         return MIDI::Name::general_midi_program_names[std::min((uint8_t) 127,program)];
283                 }
284         }
285
286         return string_compose (_("preset %1 (bank %2)"), (int) program, (int) bank);
287 }