Remove locale_guard.h from ardour/ardour.h header
[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 "pbd/control_math.h"
23
24 #include "ardour/amp.h"
25 #include "ardour/dB.h"
26 #include "ardour/parameter_descriptor.h"
27 #include "ardour/rc_configuration.h"
28 #include "ardour/types.h"
29 #include "ardour/utils.h"
30
31 #include "pbd/i18n.h"
32
33 namespace ARDOUR {
34
35 ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter)
36         : Evoral::ParameterDescriptor()
37         , key((uint32_t)-1)
38         , datatype(Variant::NOTHING)
39         , type((AutomationType)parameter.type())
40         , unit(NONE)
41         , step(0)
42         , smallstep(0)
43         , largestep(0)
44         , integer_step(parameter.type() >= MidiCCAutomation &&
45                        parameter.type() <= MidiChannelPressureAutomation)
46         , sr_dependent(false)
47         , enumeration(false)
48 {
49         ScalePoints sp;
50
51         /* Note: defaults in Evoral::ParameterDescriptor */
52
53         switch((AutomationType)parameter.type()) {
54         case GainAutomation:
55         case BusSendLevel:
56                 upper  = Config->get_max_gain();
57                 normal = 1.0f;
58                 break;
59         case BusSendEnable:
60                 normal = 1.0f;
61                 toggled = true;
62                 break;
63         case TrimAutomation:
64                 upper  = 10; // +20dB
65                 lower  = .1; // -20dB
66                 normal = 1.0f;
67                 logarithmic = true;
68                 break;
69         case PanAzimuthAutomation:
70                 normal = 0.5f; // there really is no _normal but this works for stereo, sort of
71                 upper  = 1.0f;
72                 break;
73         case PanWidthAutomation:
74                 lower  = -1.0;
75                 upper  = 1.0;
76                 normal = 0.0f;
77                 break;
78         case RecEnableAutomation:
79         case RecSafeAutomation:
80                 lower  = 0.0;
81                 upper  = 1.0;
82                 toggled = true;
83                 break;
84         case FadeInAutomation:
85         case FadeOutAutomation:
86         case EnvelopeAutomation:
87                 upper  = 2.0f;
88                 normal = 1.0f;
89                 break;
90         case SoloAutomation:
91         case MuteAutomation:
92                 upper  = 1.0f;
93                 normal = 0.0f;
94                 toggled = true;
95                 break;
96         case MidiCCAutomation:
97         case MidiPgmChangeAutomation:
98         case MidiChannelPressureAutomation:
99         case MidiNotePressureAutomation:
100                 lower  = 0.0;
101                 normal = 0.0;
102                 upper  = 127.0;
103                 break;
104         case MidiPitchBenderAutomation:
105                 lower  = 0.0;
106                 normal = 8192.0;
107                 upper  = 16383.0;
108                 break;
109         case PhaseAutomation:
110                 toggled = true;
111                 break;
112         case MonitoringAutomation:
113                 enumeration = true;
114                 integer_step = true;
115                 lower = MonitorAuto;
116                 upper = MonitorDisk; /* XXX bump when we add MonitorCue */
117                 break;
118         case SoloIsolateAutomation:
119         case SoloSafeAutomation:
120                 toggled = true;
121                 break;
122         default:
123                 break;
124         }
125
126         update_steps();
127 }
128
129 ParameterDescriptor::ParameterDescriptor()
130         : Evoral::ParameterDescriptor()
131         , key((uint32_t)-1)
132         , datatype(Variant::NOTHING)
133         , type(NullAutomation)
134         , unit(NONE)
135         , step(0)
136         , smallstep(0)
137         , largestep(0)
138         , integer_step(false)
139         , sr_dependent(false)
140         , enumeration(false)
141 {}
142
143 void
144 ParameterDescriptor::update_steps()
145 {
146         /* sanitize flags */
147         if (toggled || enumeration) {
148                 logarithmic = false;
149         }
150         if (logarithmic && (upper <= lower || lower * upper <= 0)) {
151                 logarithmic = false;
152         }
153         if (rangesteps < 2) {
154                 rangesteps = 0;
155         }
156
157         if (unit == ParameterDescriptor::MIDI_NOTE) {
158                 step      = smallstep = 1;  // semitone
159                 largestep = 12;             // octave
160         } else if (type == GainAutomation || type == TrimAutomation) {
161                 /* dB_coeff_step gives a step normalized for [0, max_gain].  This is
162                    like "slider position", so we convert from "slider position" to gain
163                    to have the correct unit here. */
164                 largestep = position_to_gain (dB_coeff_step(upper));
165                 step      = position_to_gain (largestep / 10.0);
166                 smallstep = step;
167         } else if (rangesteps > 1) {
168                 const float delta = upper - lower;
169
170                 step = smallstep = (delta / (rangesteps - 1)); // XXX
171                 largestep = std::min ((delta / 5.0f), 10.f * smallstep); // XXX
172
173                 if (logarithmic) {
174                         smallstep = smallstep / logf (rangesteps); // XXX
175                         step      = step      / logf (rangesteps);
176                         largestep = largestep / logf (rangesteps);
177                 } else if (integer_step) {
178                         smallstep = 1.0;
179                         step      = std::max(1.f, rintf (rangesteps));
180                         largestep = std::max(1.f, rintf (largestep));
181                 }
182         } else {
183                 const float delta = upper - lower;
184
185                 /* 30 happens to be the total number of steps for a fader with default
186                    max gain of 2.0 (6 dB), so we use 30 here too for consistency. */
187                 step      = smallstep = (delta / 300.0f);
188                 largestep = (delta / 30.0f);
189
190                 if (logarithmic) {
191                         /* Steps are linear, but we map them with pow like values (in
192                            internal_to_interface).  Thus, they are applied exponentially,
193                            which means too few steps.  So, divide to get roughly the
194                            desired number of steps (30).  This is not mathematically
195                            precise but seems to be about right for the controls I tried.
196                            If you're reading this, you've probably found a case where that
197                            isn't true, and somebody needs to sit down with a piece of paper
198                            and actually do the math. */
199                         smallstep = smallstep / logf(30.0f);
200                         step      = step      / logf(30.0f);
201                         largestep = largestep / logf(30.0f);
202                 } else if (integer_step) {
203                         smallstep = 1.0;
204                         step      = std::max(1.f, rintf (step));
205                         largestep = std::max(1.f, rintf (largestep));
206                 }
207         }
208 }
209
210 std::string
211 ParameterDescriptor::midi_note_name (const uint8_t b, bool translate)
212 {
213         char buf[16];
214         if (b > 127) {
215                 snprintf(buf, sizeof(buf), "%d", b);
216                 return buf;
217         }
218
219         static const char* en_notes[] = {
220                 "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
221         };
222
223         static const char* notes[] = {
224                 S_("Note|C"),
225                 S_("Note|C#"),
226                 S_("Note|D"),
227                 S_("Note|D#"),
228                 S_("Note|E"),
229                 S_("Note|F"),
230                 S_("Note|F#"),
231                 S_("Note|G"),
232                 S_("Note|G#"),
233                 S_("Note|A"),
234                 S_("Note|A#"),
235                 S_("Note|B")
236         };
237
238         /* MIDI note 0 is in octave -1 (in scientific pitch notation) */
239         const int octave = b / 12 - 1;
240         const size_t p = b % 12;
241         snprintf (buf, sizeof (buf), "%s%d", translate ? notes[p] : en_notes[p], octave);
242         return buf;
243 }
244
245 std::string
246 ParameterDescriptor::normalize_note_name(const std::string& name)
247 {
248         // Remove whitespaces and convert to lower case for a more resilient parser
249         return boost::to_lower_copy(boost::erase_all_copy(name, " "));
250 };
251
252 ParameterDescriptor::NameNumMap
253 ParameterDescriptor::build_midi_name2num()
254 {
255         NameNumMap name2num;
256         for (uint8_t num = 0; num < 128; num++) {
257                 name2num[normalize_note_name(midi_note_name(num))] = num;
258         }
259         return name2num;
260 }
261
262 uint8_t
263 ParameterDescriptor::midi_note_num (const std::string& name)
264 {
265         static NameNumMap name2num = build_midi_name2num();
266
267         uint8_t num = -1;                       // -1 (or 255) is returned in case of failure
268
269         NameNumMap::const_iterator it = name2num.find(normalize_note_name(name));
270         if (it != name2num.end())
271                 num = it->second;
272
273         return num;
274 }
275
276 float
277 ParameterDescriptor::to_interface (float val) const
278 {
279         val = std::min (upper, std::max (lower, val));
280         switch(type) {
281                 case GainAutomation:
282                 case BusSendLevel:
283                 case EnvelopeAutomation:
284                         val = gain_to_slider_position_with_max (val, upper);
285                         break;
286                 case TrimAutomation:
287                         {
288                                 const float lower_db = accurate_coefficient_to_dB (lower);
289                                 const float range_db = accurate_coefficient_to_dB (upper) - lower_db;
290                                 val = (accurate_coefficient_to_dB (val) - lower_db) / range_db;
291                         }
292                         break;
293                 case PanAzimuthAutomation:
294                 case PanElevationAutomation:
295                         val = 1.f - val;
296                         break;
297                 case PanWidthAutomation:
298                         val = .5f + val * .5f;
299                         break;
300                 default:
301                         if (logarithmic) {
302                                 if (rangesteps > 1) {
303                                         val = logscale_to_position_with_steps (val, lower, upper, rangesteps);
304                                 } else {
305                                         val = logscale_to_position (val, lower, upper);
306                                 }
307                         } else if (toggled) {
308                                 return (val - lower) / (upper - lower) >= 0.5f ? 1.f : 0.f;
309                         } else if (integer_step) {
310                                 /* evenly-divide steps. lower,upper inclusive
311                                  * e.g. 5 integers 0,1,2,3,4 are mapped to a fader
312                                  * [0.0 ... 0.2 | 0.2 ... 0.4 | 0.4 ... 0.6 | 0.6 ... 0.8 | 0.8 ... 1.0]
313                                  *       0             1             2             3             4
314                                  *      0.1           0.3           0.5           0.7           0.9
315                                  */
316                                 val = (val + .5f - lower) / (1.f + upper - lower);
317                         } else {
318                                 val = (val - lower) / (upper - lower);
319                         }
320                         break;
321         }
322         val = std::max (0.f, std::min (1.f, val));
323         return val;
324 }
325
326 float
327 ParameterDescriptor::from_interface (float val) const
328 {
329         val = std::max (0.f, std::min (1.f, val));
330
331         switch(type) {
332                 case GainAutomation:
333                 case EnvelopeAutomation:
334                 case BusSendLevel:
335                         val = slider_position_to_gain_with_max (val, upper);
336                         break;
337                 case TrimAutomation:
338                         {
339                                 const float lower_db = accurate_coefficient_to_dB (lower);
340                                 const float range_db = accurate_coefficient_to_dB (upper) - lower_db;
341                                 val = dB_to_coefficient (lower_db + val * range_db);
342                         }
343                         break;
344                 case PanAzimuthAutomation:
345                 case PanElevationAutomation:
346                          val = 1.f - val;
347                         break;
348                 case PanWidthAutomation:
349                         val = 2.f * val - 1.f;
350                         break;
351                 default:
352                         if (logarithmic) {
353                                 assert (!toggled && !integer_step); // update_steps() should prevent that.
354                                 if (rangesteps > 1) {
355                                         val = position_to_logscale_with_steps (val, lower, upper, rangesteps);
356                                 } else {
357                                         val = position_to_logscale (val, lower, upper);
358                                 }
359                         } else if (toggled) {
360                                 val = val > 0 ? upper : lower;
361                         } else if (integer_step) {
362                                 /* upper and lower are inclusive. use evenly-divided steps
363                                  * e.g. 5 integers 0,1,2,3,4 are mapped to a fader
364                                  * [0.0 .. 0.2 | 0.2 .. 0.4 | 0.4 .. 0.6 | 0.6 .. 0.8 | 0.8 .. 1.0]
365                                  */
366                                 val =  round (lower + val * (1.f + upper - lower) - .5f);
367                         } else if (rangesteps > 1) {
368                                 /* similar to above, but for float controls */
369                                 val = floor (val * (rangesteps - 1.f)) / (rangesteps - 1.f); // XXX
370                                 val = val * (upper - lower) + lower;
371                         } else {
372                                 val = val * (upper - lower) + lower;
373                         }
374                         break;
375         }
376         val = std::min (upper, std::max (lower, val));
377         return val;
378 }
379
380 bool
381 ParameterDescriptor::is_linear () const
382 {
383         if (logarithmic) {
384                 return false;
385         }
386         switch(type) {
387                 case GainAutomation:
388                 case EnvelopeAutomation:
389                 case BusSendLevel:
390                         return false;
391                 default:
392                         break;
393         }
394         return true;
395 }
396
397 float
398 ParameterDescriptor::compute_delta (float from, float to) const
399 {
400         if (is_linear ()) {
401                 return to - from;
402         }
403         if (from == 0) {
404                 return 0;
405         }
406         return to / from;
407 }
408
409 float
410 ParameterDescriptor::apply_delta (float val, float delta) const
411 {
412         if (is_linear ()) {
413                 return val + delta;
414         } else {
415                 return val * delta;
416         }
417 }
418
419 } // namespace ARDOUR