1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 11 июл. 2017 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <ui/ctl/ctl.h>
23 
24 namespace lsp
25 {
26     namespace ctl
27     {
28         const ctl_class_t CtlKnob::metadata = { "CtlKnob", &CtlWidget::metadata };
29 
CtlKnob(CtlRegistry * src,LSPKnob * widget)30         CtlKnob::CtlKnob(CtlRegistry *src, LSPKnob *widget): CtlWidget(src, widget)
31         {
32             pClass          = &metadata;
33             pPort           = NULL;
34             bLog            = false;
35             bLogSet         = false;
36             bCyclingSet     = false;
37             fDefaultValue   = 0.0f;
38             bBalanceSet     = false;
39             fBalance        = 0.0f;
40         }
41 
~CtlKnob()42         CtlKnob::~CtlKnob()
43         {
44         }
45 
slot_change(LSPWidget * sender,void * ptr,void * data)46         status_t CtlKnob::slot_change(LSPWidget *sender, void *ptr, void *data)
47         {
48             CtlKnob *_this      = static_cast<CtlKnob *>(ptr);
49             if (_this != NULL)
50                 _this->submit_value();
51             return STATUS_OK;
52         }
53 
slot_dbl_click(LSPWidget * sender,void * ptr,void * data)54         status_t CtlKnob::slot_dbl_click(LSPWidget *sender, void *ptr, void *data)
55         {
56             CtlKnob *_this      = static_cast<CtlKnob *>(ptr);
57             if (_this != NULL)
58                 _this->set_default_value();
59             return STATUS_OK;
60         }
61 
submit_value()62         void CtlKnob::submit_value()
63         {
64             if (pPort == NULL)
65                 return;
66             if (pWidget == NULL)
67                 return;
68 
69             LSPKnob *knob   = widget_cast<LSPKnob>(pWidget);
70             float value     = knob->value();
71 
72             const port_t *p = pPort->metadata();
73             if (p == NULL)
74             {
75                 pPort->set_value(value);
76                 pPort->notify_all();
77                 return;
78             }
79 
80             if (is_gain_unit(p->unit)) // Gain
81             {
82                 double base     = (p->unit == U_GAIN_AMP) ? M_LN10 * 0.05 : M_LN10 * 0.1;
83                 value           = exp(value * base);
84                 float min       = (p->flags & F_LOWER) ? p->min : 0.0f;
85                 if ((min <= 0.0f) && (value < GAIN_AMP_M_80_DB))
86                     value           = 0.0f;
87             }
88             else if (is_discrete_unit(p->unit)) // Integer type
89             {
90                  value          = truncf(value);
91             }
92             else if (bLog)  // Float and other values, logarithmic
93             {
94                 value           = exp(value);
95                 float min       = (p->flags & F_LOWER) ? p->min : 0.0f;
96                 if ((min <= 0.0f) && (value < log(GAIN_AMP_M_80_DB)))
97                     value           = 0.0f;
98             }
99 
100             pPort->set_value(value);
101             pPort->notify_all();
102         }
103 
set_default_value()104         void CtlKnob::set_default_value()
105         {
106             LSPKnob *knob = widget_cast<LSPKnob>(pWidget);
107             if (knob == NULL)
108                 return;
109 
110             const port_t *p = pPort->metadata();
111             float dfl   = (p != NULL) ? pPort->get_default_value() : fDefaultValue;
112             float value = dfl;
113 
114             if (p != NULL)
115             {
116                 if (is_gain_unit(p->unit)) // Decibels
117                 {
118                     double base = (p->unit == U_GAIN_AMP) ? 20.0 / M_LN10 : 10.0 / M_LN10;
119 
120                     if (value < GAIN_AMP_M_120_DB)
121                         value           = GAIN_AMP_M_120_DB;
122 
123                     value = base * log(value);
124                 }
125                 else if (bLog)
126                 {
127                     if (value < GAIN_AMP_M_120_DB)
128                         value           = GAIN_AMP_M_120_DB;
129                     value = log(value);
130                 }
131             }
132 
133             knob->set_value(value);
134             pPort->set_value(dfl);
135             pPort->notify_all();
136         }
137 
commit_value(float value)138         void CtlKnob::commit_value(float value)
139         {
140             if (pWidget == NULL)
141                 return;
142 
143             LSPKnob *knob = widget_cast<LSPKnob>(pWidget);
144             if (knob == NULL)
145                 return;
146 
147             const port_t *p = pPort->metadata();
148             if (p == NULL)
149                 return;
150 
151             if (is_gain_unit(p->unit)) // Decibels
152             {
153                 double base = (p->unit == U_GAIN_AMP) ? 20.0 / M_LN10 : 10.0 / M_LN10;
154 
155                 if (value < GAIN_AMP_M_120_DB)
156                     value           = GAIN_AMP_M_120_DB;
157 
158                 knob->set_value(base * log(value));
159             }
160             else if (is_discrete_unit(p->unit)) // Integer type
161                 knob->set_value(truncf(value));
162             else if (bLog)
163             {
164                 if (value < GAIN_AMP_M_120_DB)
165                     value           = GAIN_AMP_M_120_DB;
166                 knob->set_value(log(value));
167             }
168             else
169                 knob->set_value(value);
170         }
171 
init()172         void CtlKnob::init()
173         {
174             CtlWidget::init();
175 
176             LSPKnob *knob = widget_cast<LSPKnob>(pWidget);
177             if (knob == NULL)
178                 return;
179 
180             // Initialize color controllers
181             sColor.init_hsl(pRegistry, knob, knob->color(), A_COLOR, A_HUE_ID, A_SAT_ID, A_LIGHT_ID);
182             sScaleColor.init_hsl(pRegistry, knob, knob->scale_color(), A_SCALE_COLOR, A_SCALE_HUE_ID, A_SCALE_SAT_ID, A_SCALE_LIGHT_ID);
183             sScaleColor.map_static_hsl(A_SCALE_HUE, -1, -1);
184 
185             // Bind slots
186             knob->slots()->bind(LSPSLOT_CHANGE, slot_change, this);
187             knob->slots()->bind(LSPSLOT_MOUSE_DBL_CLICK, slot_dbl_click, this);
188         }
189 
set(widget_attribute_t att,const char * value)190         void CtlKnob::set(widget_attribute_t att, const char *value)
191         {
192             LSPKnob *knob = widget_cast<LSPKnob>(pWidget);
193 
194             switch (att)
195             {
196                 case A_ID:
197                     BIND_PORT(pRegistry, pPort, value);
198                     break;
199                 case A_SIZE:
200                     if (knob != NULL)
201                         PARSE_INT(value, knob->set_size(__));
202                     break;
203                 case A_VALUE:
204                     if (knob != NULL)
205                         PARSE_FLOAT(value, knob->set_value(__));
206                     break;
207                 case A_DEFAULT:
208                     if (knob != NULL)
209                         PARSE_FLOAT(value, fDefaultValue = __);
210                     break;
211                 case A_MIN:
212                     if (knob != NULL)
213                         PARSE_FLOAT(value, knob->set_min_value(__));
214                     break;
215                 case A_MAX:
216                     if (knob != NULL)
217                         PARSE_FLOAT(value, knob->set_max_value(__));
218                     break;
219                 case A_LOGARITHMIC:
220                     PARSE_BOOL(value, bLog = __);
221                     bLogSet     = true;
222                     break;
223                 case A_STEP:
224                     if (knob != NULL)
225                         PARSE_FLOAT(value, knob->set_step(__));
226                     break;
227                 case A_TINY_STEP:
228                     if (knob != NULL)
229                         PARSE_FLOAT(value, knob->set_tiny_step(__));
230                     break;
231                 case A_BALANCE:
232                     bBalanceSet = true;
233                     if (knob != NULL)
234                         PARSE_FLOAT(value, knob->set_balance(fBalance = __));
235                     break;
236                 case A_CYCLE:
237                     bCyclingSet = true;
238                     if (knob != NULL)
239                         PARSE_BOOL(value, knob->set_cycling(__); );
240                     break;
241                 default:
242                 {
243                     sColor.set(att, value);
244                     sScaleColor.set(att, value);
245                     CtlWidget::set(att, value);
246                     break;
247                 }
248             }
249         }
250 
notify(CtlPort * port)251         void CtlKnob::notify(CtlPort *port)
252         {
253             CtlWidget::notify(port);
254 
255             if (port == pPort)
256                 commit_value(pPort->get_value());
257         }
258 
limit(float v,float min,float max)259         static inline float limit(float v, float min, float max)
260         {
261             if (min < max)
262             {
263                 if (v < min)
264                     return min;
265                 return (v > max) ? max : v;
266             }
267             else
268             {
269                 if (v < max)
270                     return max;
271                 return (v > min) ? min : v;
272             }
273         }
274 
end()275         void CtlKnob::end()
276         {
277             // Call parent controller
278             CtlWidget::end();
279 
280             // Ensure that widget is set
281             if (pWidget == NULL)
282                 return;
283             LSPKnob *knob = widget_cast<LSPKnob>(pWidget);
284 
285             // Ensure that port is set
286             const port_t *p = (pPort != NULL) ? pPort->metadata() : NULL;
287             if (p == NULL)
288             {
289                 knob->set_value(fDefaultValue);
290                 return;
291             }
292 
293             // Update logarithmic flag
294             if (!bLogSet)
295                 bLog        = (p->flags & F_LOG);
296 
297             if (is_gain_unit(p->unit)) // Gain
298             {
299                 double base     = (p->unit == U_GAIN_AMP) ? 20.0 / M_LN10 : 10.0 / M_LN10;
300 
301                 float min       = (p->flags & F_LOWER) ? p->min : 0.0f;
302                 float max       = (p->flags & F_UPPER) ? p->max : GAIN_AMP_P_12_DB;
303                 float dfl       = (bBalanceSet) ? fBalance : min;
304 
305                 double step     = base * log((p->flags & F_STEP) ? p->step + 1.0f : 1.01f) * 0.1f;
306                 double thresh   = ((p->flags & F_EXT) ? GAIN_AMP_M_140_DB : GAIN_AMP_M_80_DB);
307 
308                 double db_min   = (fabs(min) < thresh) ? (base * log(thresh) - step) : (base * log(min));
309                 double db_max   = (fabs(max) < thresh) ? (base * log(thresh) - step) : (base * log(max));
310                 double db_dfl   = (fabs(max) < thresh) ? (base * log(thresh) - step) : (base * log(dfl));
311                 float balance   = limit(db_dfl, db_min, db_max);
312 
313                 knob->set_min_value(db_min);
314                 knob->set_max_value(db_max);
315                 knob->set_balance(balance);
316                 knob->set_step(step * 10.0f);
317                 knob->set_tiny_step(step);
318                 fDefaultValue   = base * log(p->start);
319             }
320             else if (is_discrete_unit(p->unit)) // Integer type
321             {
322                 float min       = (p->flags & F_LOWER) ? p->min : 0.0f;
323                 float max       = (p->unit == U_ENUM) ? min + list_size(p->items) - 1.0f :
324                                   (p->flags & F_UPPER) ? p->max : 1.0f;
325                 float dfl       = (bBalanceSet) ? fBalance : p->min;
326                 float balance   = limit(dfl, min, max);
327                 ssize_t step    = (p->flags & F_STEP) ? p->step : 1;
328                 step            = (step == 0) ? 1 : step;
329 
330                 knob->set_min_value(min);
331                 knob->set_max_value(max);
332                 knob->set_balance(balance);
333                 knob->set_step(step);
334                 knob->set_tiny_step(step);
335                 fDefaultValue   = p->start;
336                 if (!bCyclingSet)
337                     knob->set_cycling(p->flags & F_CYCLIC);
338             }
339             else if (bLog)  // Float and other values, logarithmic
340             {
341                 float min       = (p->flags & F_LOWER) ? p->min : 0.0f;
342                 float max       = (p->flags & F_UPPER) ? p->max : GAIN_AMP_P_12_DB;
343                 float dfl       = (bBalanceSet) ? fBalance : min;
344 
345                 double step     = log((p->flags & F_STEP) ? p->step + 1.0f : 1.01f);
346                 double l_min    = (fabs(min) < GAIN_AMP_M_80_DB) ? log(GAIN_AMP_M_80_DB) - step : log(min);
347                 double l_max    = (fabs(max) < GAIN_AMP_M_80_DB) ? log(GAIN_AMP_M_80_DB) - step : log(max);
348                 double l_dfl    = (fabs(dfl) < GAIN_AMP_M_80_DB) ? log(GAIN_AMP_M_80_DB) - step : log(dfl);
349                 float balance   = limit(l_dfl, l_min, l_max);
350 
351                 knob->set_min_value(l_min);
352                 knob->set_max_value(l_max);
353                 knob->set_balance(balance);
354                 knob->set_step(step * 10.0f);
355                 knob->set_tiny_step(step);
356                 fDefaultValue = log(p->start);
357             }
358             else // Float and other values, non-logarithmic
359             {
360                 float min       = (p->flags & F_LOWER) ? p->min : 0.0f;
361                 float max       = (p->flags & F_UPPER) ? p->max : 1.0f;
362                 float dfl       = (bBalanceSet) ? fBalance : min;
363                 float balance   = limit(dfl, min, max);
364 
365                 knob->set_min_value(min);
366                 knob->set_max_value(max);
367                 knob->set_balance(balance);
368                 knob->set_tiny_step((p->flags & F_STEP) ? p->step : (max - min) * 0.01f);
369                 knob->set_step(knob->tiny_step() * 10.0f);
370                 fDefaultValue   = p->start;
371                 if (!bCyclingSet)
372                     knob->set_cycling(p->flags & F_CYCLIC);
373             }
374 
375             // Set default value to the knob
376             knob->set_value(fDefaultValue);
377         }
378 
379     } /* namespace ctl */
380 } /* namespace lsp */
381