16c618dec62c2c1fede78f5c02e23a94ac609d5d
[ardour.git] / libs / ardour / parameter_descriptor.cc
1 /*
2     Copyright (C) 2014 Paul Davis
3     Author: David Robillard
4
5     This program is free software; you can redistribute it and/or modify it
6     under the terms of the GNU General Public License as published by the Free
7     Software Foundation; either version 2 of the License, or (at your option)
8     any later version.
9
10     This program is distributed in the hope that it will be useful, but WITHOUT
11     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13     for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <boost/algorithm/string.hpp>
21
22 #include "ardour/amp.h"
23 #include "ardour/dB.h"
24 #include "ardour/parameter_descriptor.h"
25 #include "ardour/rc_configuration.h"
26 #include "ardour/types.h"
27 #include "ardour/utils.h"
28
29 #include "pbd/i18n.h"
30
31 namespace ARDOUR {
32
33 ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter)
34         : Evoral::ParameterDescriptor()
35         , key((uint32_t)-1)
36         , datatype(Variant::NOTHING)
37         , type((AutomationType)parameter.type())
38         , unit(NONE)
39         , step(0)
40         , smallstep(0)
41         , largestep(0)
42         , integer_step(parameter.type() >= MidiCCAutomation &&
43                        parameter.type() <= MidiChannelPressureAutomation)
44         , logarithmic(false)
45         , sr_dependent(false)
46         , min_unbound(0)
47         , max_unbound(0)
48         , enumeration(false)
49 {
50         ScalePoints sp;
51
52         switch((AutomationType)parameter.type()) {
53         case GainAutomation:
54                 upper  = Config->get_max_gain();
55                 normal = 1.0f;
56                 break;
57         case BusSendLevel:
58                 upper = Config->get_max_gain ();
59                 normal = 1.0f;
60                 break;
61         case BusSendEnable:
62                 normal = 1.0f;
63                 toggled = true;
64                 break;
65         case TrimAutomation:
66                 upper  = 10; // +20dB
67                 lower  = .1; // -20dB
68                 normal = 1.0f;
69                 break;
70         case PanAzimuthAutomation:
71                 normal = 0.5f; // there really is no _normal but this works for stereo, sort of
72                 upper  = 1.0f;
73                 break;
74         case PanWidthAutomation:
75                 lower  = -1.0;
76                 upper  = 1.0;
77                 normal = 0.0f;
78                 break;
79         case RecEnableAutomation:
80         case RecSafeAutomation:
81                 lower  = 0.0;
82                 upper  = 1.0;
83                 toggled = true;
84                 break;
85         case PluginAutomation:
86         case FadeInAutomation:
87         case FadeOutAutomation:
88         case EnvelopeAutomation:
89                 upper  = 2.0f;
90                 normal = 1.0f;
91                 break;
92         case SoloAutomation:
93         case MuteAutomation:
94                 upper  = 1.0f;
95                 normal = 0.0f;
96                 toggled = true;
97                 break;
98         case MidiCCAutomation:
99         case MidiPgmChangeAutomation:
100         case MidiChannelPressureAutomation:
101         case MidiNotePressureAutomation:
102                 lower  = 0.0;
103                 normal = 0.0;
104                 upper  = 127.0;
105                 break;
106         case MidiPitchBenderAutomation:
107                 lower  = 0.0;
108                 normal = 8192.0;
109                 upper  = 16383.0;
110                 break;
111         case PhaseAutomation:
112                 toggled = true;
113                 break;
114         case MonitoringAutomation:
115                 enumeration = true;
116                 integer_step = true;
117                 lower = MonitorAuto;
118                 upper = MonitorDisk; /* XXX bump when we add MonitorCue */
119                 break;
120         case SoloIsolateAutomation:
121                 toggled = true;
122                 break;
123         case SoloSafeAutomation:
124                 toggled = true;
125                 break;
126         default:
127                 break;
128         }
129
130         update_steps();
131 }
132
133 ParameterDescriptor::ParameterDescriptor()
134         : Evoral::ParameterDescriptor()
135         , key((uint32_t)-1)
136         , datatype(Variant::NOTHING)
137         , type(NullAutomation)
138         , unit(NONE)
139         , step(0)
140         , smallstep(0)
141         , largestep(0)
142         , integer_step(false)
143         , logarithmic(false)
144         , sr_dependent(false)
145         , min_unbound(0)
146         , max_unbound(0)
147         , enumeration(false)
148 {}
149
150 void
151 ParameterDescriptor::update_steps()
152 {
153         if (unit == ParameterDescriptor::MIDI_NOTE) {
154                 step      = smallstep = 1;  // semitone
155                 largestep = 12;             // octave
156         } else if (type == GainAutomation || type == TrimAutomation) {
157                 /* dB_coeff_step gives a step normalized for [0, max_gain].  This is
158                    like "slider position", so we convert from "slider position" to gain
159                    to have the correct unit here. */
160                 largestep = slider_position_to_gain(dB_coeff_step(upper));
161                 step      = slider_position_to_gain(largestep / 10.0);
162                 smallstep = step;
163         } else {
164                 /* note that LV2Plugin::get_parameter_descriptor ()
165                  * overrides this is lv2:rangeStep is set for a port.
166                  */
167                 const float delta = upper - lower;
168
169                 /* 30 happens to be the total number of steps for a fader with default
170                    max gain of 2.0 (6 dB), so we use 30 here too for consistency. */
171                 step      = smallstep = (delta / 300.0f);
172                 largestep = (delta / 30.0f);
173
174                 if (logarithmic) {
175                         /* Steps are linear, but we map them with pow like values (in
176                            internal_to_interface).  Thus, they are applied exponentially,
177                            which means too few steps.  So, divide to get roughly the
178                            desired number of steps (30).  This is not mathematically
179                            precise but seems to be about right for the controls I tried.
180                            If you're reading this, you've probably found a case where that
181                            isn't true, and somebody needs to sit down with a piece of paper
182                            and actually do the math. */
183                         smallstep = smallstep / logf(30.0f);
184                         step      = step      / logf(30.0f);
185                         largestep = largestep / logf(30.0f);
186                 } else if (integer_step) {
187                         smallstep = 1.0;
188                         step      = std::max(1.f, rintf (step));
189                         largestep = std::max(1.f, rintf (largestep));
190                 }
191         }
192 }
193
194 std::string
195 ParameterDescriptor::midi_note_name (const uint8_t b, bool translate)
196 {
197         char buf[16];
198         if (b > 127) {
199                 snprintf(buf, sizeof(buf), "%d", b);
200                 return buf;
201         }
202
203         static const char* en_notes[] = {
204                 "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
205         };
206
207         static const char* notes[] = {
208                 S_("Note|C"),
209                 S_("Note|C#"),
210                 S_("Note|D"),
211                 S_("Note|D#"),
212                 S_("Note|E"),
213                 S_("Note|F"),
214                 S_("Note|F#"),
215                 S_("Note|G"),
216                 S_("Note|G#"),
217                 S_("Note|A"),
218                 S_("Note|A#"),
219                 S_("Note|B")
220         };
221
222         /* MIDI note 0 is in octave -1 (in scientific pitch notation) */
223         const int octave = b / 12 - 1;
224         const size_t p = b % 12;
225         snprintf (buf, sizeof (buf), "%s%d", translate ? notes[p] : en_notes[p], octave);
226         return buf;
227 }
228
229 std::string
230 ParameterDescriptor::normalize_note_name(const std::string& name)
231 {
232         // Remove whitespaces and convert to lower case for a more resilient parser
233         return boost::to_lower_copy(boost::erase_all_copy(name, " "));
234 };
235
236 ParameterDescriptor::NameNumMap
237 ParameterDescriptor::build_midi_name2num()
238 {
239         NameNumMap name2num;
240         for (uint8_t num = 0; num < 128; num++) {
241                 name2num[normalize_note_name(midi_note_name(num))] = num;
242         }
243         return name2num;
244 }
245
246 uint8_t
247 ParameterDescriptor::midi_note_num (const std::string& name)
248 {
249         static NameNumMap name2num = build_midi_name2num();
250
251         uint8_t num = -1;                       // -1 (or 255) is returned in case of failure
252
253         NameNumMap::const_iterator it = name2num.find(normalize_note_name(name));
254         if (it != name2num.end())
255                 num = it->second;
256
257         return num;
258 }
259
260 } // namespace ARDOUR