Remove braindead Parameter inheritance abuse.
[ardour.git] / libs / ardour / event_type_map.cc
1 /*
2     Copyright (C) 2008 Paul Davis
3     Author: David Robillard
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 <ctype.h>
22 #include <cstdio>
23 #include "ardour/types.h"
24 #include "ardour/event_type_map.h"
25 #include "ardour/parameter_types.h"
26 #include "ardour/uri_map.h"
27 #include "evoral/Parameter.hpp"
28 #include "evoral/midi_events.h"
29 #include "pbd/error.h"
30 #include "pbd/compose.h"
31
32 using namespace std;
33
34 namespace ARDOUR {
35
36 EventTypeMap* EventTypeMap::event_type_map;
37
38 EventTypeMap&
39 EventTypeMap::instance()
40 {
41         if (!EventTypeMap::event_type_map) {
42                 EventTypeMap::event_type_map = new EventTypeMap(URIMap::instance());
43
44                 // Initialize parameter metadata
45                 EventTypeMap::event_type_map->new_parameter(NullAutomation);
46                 EventTypeMap::event_type_map->new_parameter(GainAutomation);
47                 EventTypeMap::event_type_map->new_parameter(PanAzimuthAutomation);
48                 EventTypeMap::event_type_map->new_parameter(PanElevationAutomation);
49                 EventTypeMap::event_type_map->new_parameter(PanWidthAutomation);
50                 EventTypeMap::event_type_map->new_parameter(PluginAutomation);
51                 EventTypeMap::event_type_map->new_parameter(PluginPropertyAutomation);
52                 EventTypeMap::event_type_map->new_parameter(SoloAutomation);
53                 EventTypeMap::event_type_map->new_parameter(MuteAutomation);
54                 EventTypeMap::event_type_map->new_parameter(MidiCCAutomation);
55                 EventTypeMap::event_type_map->new_parameter(MidiPgmChangeAutomation);
56                 EventTypeMap::event_type_map->new_parameter(MidiPitchBenderAutomation);
57                 EventTypeMap::event_type_map->new_parameter(MidiChannelPressureAutomation);
58                 EventTypeMap::event_type_map->new_parameter(FadeInAutomation);
59                 EventTypeMap::event_type_map->new_parameter(FadeOutAutomation);
60                 EventTypeMap::event_type_map->new_parameter(EnvelopeAutomation);
61                 EventTypeMap::event_type_map->new_parameter(MidiCCAutomation);
62         }
63         return *EventTypeMap::event_type_map;
64 }
65
66 bool
67 EventTypeMap::type_is_midi(uint32_t type) const
68 {
69         return ARDOUR::parameter_is_midi((AutomationType)type);
70 }
71
72 bool
73 EventTypeMap::is_midi_parameter(const Evoral::Parameter& param)
74 {
75         return type_is_midi(param.type());
76 }
77
78 uint8_t
79 EventTypeMap::parameter_midi_type(const Evoral::Parameter& param) const
80 {
81         return ARDOUR::parameter_midi_type((AutomationType)param.type());
82 }
83
84 uint32_t
85 EventTypeMap::midi_event_type(uint8_t status) const
86 {
87         return (uint32_t)ARDOUR::midi_parameter_type(status);
88 }
89
90 bool
91 EventTypeMap::is_integer(const Evoral::Parameter& param) const
92 {
93         return (   param.type() >= MidiCCAutomation
94                         && param.type() <= MidiChannelPressureAutomation);
95 }
96
97 Evoral::ControlList::InterpolationStyle
98 EventTypeMap::interpolation_of(const Evoral::Parameter& param)
99 {
100         switch (param.type()) {
101         case MidiCCAutomation:
102                 switch (param.id()) {
103                 case MIDI_CTL_LSB_BANK:
104                 case MIDI_CTL_MSB_BANK:
105                 case MIDI_CTL_LSB_EFFECT1:
106                 case MIDI_CTL_LSB_EFFECT2:
107                 case MIDI_CTL_MSB_EFFECT1:
108                 case MIDI_CTL_MSB_EFFECT2:
109                 case MIDI_CTL_MSB_GENERAL_PURPOSE1:
110                 case MIDI_CTL_MSB_GENERAL_PURPOSE2:
111                 case MIDI_CTL_MSB_GENERAL_PURPOSE3:
112                 case MIDI_CTL_MSB_GENERAL_PURPOSE4:
113                 case MIDI_CTL_SUSTAIN:
114                 case MIDI_CTL_PORTAMENTO:
115                 case MIDI_CTL_SOSTENUTO:
116                 case MIDI_CTL_SOFT_PEDAL:
117                 case MIDI_CTL_LEGATO_FOOTSWITCH:
118                 case MIDI_CTL_HOLD2:
119                 case MIDI_CTL_GENERAL_PURPOSE5:
120                 case MIDI_CTL_GENERAL_PURPOSE6:
121                 case MIDI_CTL_GENERAL_PURPOSE7:
122                 case MIDI_CTL_GENERAL_PURPOSE8:
123                 case MIDI_CTL_DATA_INCREMENT:
124                 case MIDI_CTL_DATA_DECREMENT:
125                 case MIDI_CTL_NONREG_PARM_NUM_LSB:
126                 case MIDI_CTL_NONREG_PARM_NUM_MSB:
127                 case MIDI_CTL_REGIST_PARM_NUM_LSB:
128                 case MIDI_CTL_REGIST_PARM_NUM_MSB:
129                 case MIDI_CTL_ALL_SOUNDS_OFF:
130                 case MIDI_CTL_RESET_CONTROLLERS:
131                 case MIDI_CTL_LOCAL_CONTROL_SWITCH:
132                 case MIDI_CTL_ALL_NOTES_OFF:
133                 case MIDI_CTL_OMNI_OFF:
134                 case MIDI_CTL_OMNI_ON:
135                 case MIDI_CTL_MONO:
136                 case MIDI_CTL_POLY:
137                         return Evoral::ControlList::Discrete; break;
138                 default:
139                         return Evoral::ControlList::Linear; break;
140                 }
141                 break;
142         case MidiPgmChangeAutomation:       return Evoral::ControlList::Discrete; break;
143         case MidiChannelPressureAutomation: return Evoral::ControlList::Linear; break;
144         case MidiPitchBenderAutomation:     return Evoral::ControlList::Linear; break;
145         default: assert(false);
146         }
147         return Evoral::ControlList::Linear; // Not reached, suppress warnings
148 }
149
150
151 Evoral::Parameter
152 EventTypeMap::new_parameter(uint32_t type, uint8_t channel, uint32_t id) const
153 {
154         Evoral::Parameter p(type, channel, id);
155
156         double min     = 0.0f;
157         double max     = 1.0f;
158         double normal  = 0.0f;
159         bool   toggled = false;
160
161         switch((AutomationType)type) {
162         case NullAutomation:
163         case GainAutomation:
164                 max = 2.0f;
165                 normal = 1.0f;
166                 break;
167         case PanAzimuthAutomation:
168                 normal = 0.5f; // there really is no normal but this works for stereo, sort of
169                 break;
170         case PanWidthAutomation:
171                 min = -1.0;
172                 max = 1.0;
173                 normal = 0.0f;
174                 break;
175         case PanElevationAutomation:
176         case PanFrontBackAutomation:
177         case PanLFEAutomation:
178                 break;
179         case RecEnableAutomation:
180                 /* default 0.0 - 1.0 is fine */
181                 toggled = true;
182                 break;
183         case PluginAutomation:
184         case FadeInAutomation:
185         case FadeOutAutomation:
186         case EnvelopeAutomation:
187                 max = 2.0f;
188                 normal = 1.0f;
189                 break;
190         case SoloAutomation:
191         case MuteAutomation:
192                 max = 1.0f;
193                 normal = 0.0f;
194                 toggled = true;
195                 break;
196         case MidiCCAutomation:
197         case MidiPgmChangeAutomation:
198         case MidiChannelPressureAutomation:
199                 min = 0.0;
200                 normal = 0.0;
201                 max = 127.0;
202                 break;
203         case MidiPitchBenderAutomation:
204                 min = 0.0;
205                 normal = 8192.0;
206                 max = 16383.0;
207         case MidiSystemExclusiveAutomation:
208                 return p;
209         case PluginPropertyAutomation:
210                 return p;
211         }
212
213         p.set_range(type, min, max, normal, toggled);
214         return p;
215 }
216
217 Evoral::Parameter
218 EventTypeMap::new_parameter(const string& str) const
219 {
220         AutomationType p_type    = NullAutomation;
221         uint8_t        p_channel = 0;
222         uint32_t       p_id      = 0;
223
224         if (str == "gain") {
225                 p_type = GainAutomation;
226         } else if (str == "solo") {
227                 p_type = SoloAutomation;
228         } else if (str == "mute") {
229                 p_type = MuteAutomation;
230         } else if (str == "fadein") {
231                 p_type = FadeInAutomation;
232         } else if (str == "fadeout") {
233                 p_type = FadeOutAutomation;
234         } else if (str == "envelope") {
235                 p_type = EnvelopeAutomation;
236         } else if (str == "pan-azimuth") {
237                 p_type = PanAzimuthAutomation;
238         } else if (str == "pan-width") {
239                 p_type = PanWidthAutomation;
240         } else if (str == "pan-elevation") {
241                 p_type = PanElevationAutomation;
242         } else if (str == "pan-frontback") {
243                 p_type = PanFrontBackAutomation;
244         } else if (str == "pan-lfe") {
245                 p_type = PanLFEAutomation;
246         } else if (str.length() > 10 && str.substr(0, 10) == "parameter-") {
247                 p_type = PluginAutomation;
248                 p_id = atoi(str.c_str()+10);
249         } else if (str.length() > 9 && str.substr(0, 9) == "property-") {
250                 p_type = PluginPropertyAutomation;
251                 const char* name = str.c_str() + 9;
252                 if (isdigit(str.c_str()[0])) {
253                         p_id = atoi(name);
254                 } else {
255                         p_id = _uri_map.uri_to_id(name);
256                 }
257         } else if (str.length() > 7 && str.substr(0, 7) == "midicc-") {
258                 p_type = MidiCCAutomation;
259                 uint32_t channel = 0;
260                 sscanf(str.c_str(), "midicc-%d-%d", &channel, &p_id);
261                 assert(channel < 16);
262                 p_channel = channel;
263         } else if (str.length() > 16 && str.substr(0, 16) == "midi-pgm-change-") {
264                 p_type = MidiPgmChangeAutomation;
265                 uint32_t channel = 0;
266                 sscanf(str.c_str(), "midi-pgm-change-%d", &channel);
267                 assert(channel < 16);
268                 p_id = 0;
269                 p_channel = channel;
270         } else if (str.length() > 18 && str.substr(0, 18) == "midi-pitch-bender-") {
271                 p_type = MidiPitchBenderAutomation;
272                 uint32_t channel = 0;
273                 sscanf(str.c_str(), "midi-pitch-bender-%d", &channel);
274                 assert(channel < 16);
275                 p_id = 0;
276                 p_channel = channel;
277         } else if (str.length() > 22 && str.substr(0, 22) == "midi-channel-pressure-") {
278                 p_type = MidiChannelPressureAutomation;
279                 uint32_t channel = 0;
280                 sscanf(str.c_str(), "midi-channel-pressure-%d", &channel);
281                 assert(channel < 16);
282                 p_id = 0;
283                 p_channel = channel;
284         } else {
285                 PBD::warning << "Unknown Parameter '" << str << "'" << endmsg;
286         }
287         
288         return new_parameter(p_type, p_channel, p_id);
289 }
290
291 /** Unique string representation, suitable as an XML property value.
292  * e.g. <AutomationList automation-id="whatthisreturns">
293  */
294 std::string
295 EventTypeMap::to_symbol(const Evoral::Parameter& param) const
296 {
297         AutomationType t = (AutomationType)param.type();
298
299         if (t == GainAutomation) {
300                 return "gain";
301         } else if (t == PanAzimuthAutomation) {
302                 return "pan-azimuth";
303         } else if (t == PanElevationAutomation) {
304                 return "pan-elevation";
305         } else if (t == PanWidthAutomation) {
306                 return "pan-width";
307         } else if (t == PanFrontBackAutomation) {
308                 return "pan-frontback";
309         } else if (t == PanLFEAutomation) {
310                 return "pan-lfe";
311         } else if (t == SoloAutomation) {
312                 return "solo";
313         } else if (t == MuteAutomation) {
314                 return "mute";
315         } else if (t == FadeInAutomation) {
316                 return "fadein";
317         } else if (t == FadeOutAutomation) {
318                 return "fadeout";
319         } else if (t == EnvelopeAutomation) {
320                 return "envelope";
321         } else if (t == PluginAutomation) {
322                 return string_compose("parameter-%1", param.id());
323         } else if (t == PluginPropertyAutomation) {
324                 const char* uri = _uri_map.id_to_uri(param.id());
325                 if (uri) {
326                         return string_compose("property-%1", uri);
327                 } else {
328                         return string_compose("property-%1", param.id());
329                 }
330         } else if (t == MidiCCAutomation) {
331                 return string_compose("midicc-%1-%2", int(param.channel()), param.id());
332         } else if (t == MidiPgmChangeAutomation) {
333                 return string_compose("midi-pgm-change-%1", int(param.channel()));
334         } else if (t == MidiPitchBenderAutomation) {
335                 return string_compose("midi-pitch-bender-%1", int(param.channel()));
336         } else if (t == MidiChannelPressureAutomation) {
337                 return string_compose("midi-channel-pressure-%1", int(param.channel()));
338         } else {
339                 PBD::warning << "Uninitialized Parameter symbol() called." << endmsg;
340                 return "";
341         }
342 }
343
344 } // namespace ARDOUR
345