21e1ba5f85c77e100c39f0f45b9b11fb2e183637
[ardour.git] / libs / ardour / gain_control.cc
1 /*
2     Copyright (C) 2006-2016 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify it
5     under the terms of the GNU General Public License as published by the Free
6     Software Foundation; either version 2 of the License, or (at your option)
7     any later version.
8
9     This program is distributed in the hope that it will be useful, but WITHOUT
10     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12     for more details.
13
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <cmath>
20
21 #include "pbd/convert.h"
22 #include "pbd/strsplit.h"
23
24 #include "ardour/dB.h"
25 #include "ardour/gain_control.h"
26 #include "ardour/session.h"
27 #include "ardour/vca.h"
28 #include "ardour/vca_manager.h"
29
30 #include "pbd/i18n.h"
31
32 using namespace ARDOUR;
33 using namespace std;
34
35 GainControl::GainControl (Session& session, const Evoral::Parameter &param, boost::shared_ptr<AutomationList> al)
36         : SlavableAutomationControl (session, param, ParameterDescriptor(param),
37                                      al ? al : boost::shared_ptr<AutomationList> (new AutomationList (param)),
38                                      param.type() == GainAutomation ? X_("gaincontrol") : X_("trimcontrol"),
39                                      Controllable::GainLike)
40 {
41         alist()->reset_default (1.0);
42
43         lower_db = accurate_coefficient_to_dB (_desc.lower);
44         range_db = accurate_coefficient_to_dB (_desc.upper) - lower_db;
45 }
46
47 double
48 GainControl::internal_to_interface (double v) const
49 {
50         if (_desc.type == GainAutomation) {
51                 return gain_to_slider_position (v);
52         } else {
53                 return (accurate_coefficient_to_dB (v) - lower_db) / range_db;
54         }
55 }
56
57 double
58 GainControl::interface_to_internal (double v) const
59 {
60         if (_desc.type == GainAutomation) {
61                 return slider_position_to_gain (v);
62         } else {
63                 return dB_to_coefficient (lower_db + v * range_db);
64         }
65 }
66
67 double
68 GainControl::internal_to_user (double v) const
69 {
70         return accurate_coefficient_to_dB (v);
71 }
72
73 double
74 GainControl::user_to_internal (double u) const
75 {
76         return dB_to_coefficient (u);
77 }
78
79 std::string
80 GainControl::get_user_string () const
81 {
82         char theBuf[32]; sprintf( theBuf, _("%3.1f dB"), accurate_coefficient_to_dB (get_value()));
83         return std::string(theBuf);
84 }
85
86 void
87 GainControl::inc_gain (gain_t factor)
88 {
89         /* To be used ONLY when doing group-relative gain adjustment, from
90          * ControlGroup::set_group_values().
91          */
92
93         const float desired_gain = user_double();
94
95         if (fabsf (desired_gain) < GAIN_COEFF_SMALL) {
96                 // really?! what's the idea here?
97                 actually_set_value (0.000001f + (0.000001f * factor), Controllable::ForGroup);
98         } else {
99                 actually_set_value (desired_gain + (desired_gain * factor), Controllable::ForGroup);
100         }
101 }
102
103 void
104 GainControl::recompute_masters_ratios (double val)
105 {
106         /* Master WRITE lock must be held */
107
108         /* V' is the new gain value for this
109
110            Mv(n) is the return value of ::get_value() for the n-th master
111            Mr(n) is the return value of ::ratio() for the n-th master record
112
113            the slave should return V' on the next call to ::get_value().
114
115            but the value is determined by the masters, so we know:
116
117            V' = (Mv(1) * Mr(1)) * (Mv(2) * Mr(2)) * ... * (Mv(n) * Mr(n))
118
119            hence:
120
121            Mr(1) * Mr(2) * ... * (Mr(n) = V' / (Mv(1) * Mv(2) * ... * Mv(n))
122
123            if we make all ratios equal (i.e. each master contributes the same
124            fraction of its own gain level to make the final slave gain), then we
125            have:
126
127            pow (Mr(n), n) = V' / (Mv(1) * Mv(2) * ... * Mv(n))
128
129            which gives
130
131            Mr(n) = pow ((V' / (Mv(1) * Mv(2) * ... * Mv(n))), 1/n)
132
133            Mr(n) is the new ratio number for the slaves
134         */
135
136         const double nmasters = _masters.size();
137         double masters_total_gain_coefficient = 1.0;
138
139         for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
140                 masters_total_gain_coefficient *= mr->second.master()->get_value();
141         }
142
143         const double new_universal_ratio = pow ((val / masters_total_gain_coefficient), (1.0/nmasters));
144
145         for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
146                 mr->second.reset_ratio (new_universal_ratio);
147         }
148 }
149