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: 10 сент. 2019 г.
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/plugins/para_equalizer_ui.h>
23 #include <core/files/RoomEQWizard.h>
24 
25 #include <metadata/plugins.h>
26 
27 namespace lsp
28 {
29     static const char *fmt_strings[] =
30     {
31         "%s_%d",
32         NULL
33     };
34 
35     static const char *fmt_strings_lr[] =
36     {
37         "%sl_%d",
38         "%sr_%d",
39         NULL
40     };
41 
42     static const char *fmt_strings_ms[] =
43     {
44         "%sm_%d",
45         "%ss_%d",
46         NULL
47     };
48 
para_equalizer_ui(const plugin_metadata_t * mdata,void * root_widget)49     para_equalizer_ui::para_equalizer_ui(const plugin_metadata_t *mdata, void *root_widget):
50         plugin_ui(mdata, root_widget)
51     {
52         pRewImport  = NULL;
53         pRewPath    = NULL;
54         fmtStrings  = fmt_strings;
55 
56         if (::strstr(mdata->lv2_uid, "_lr") != NULL)
57             fmtStrings      = fmt_strings_lr;
58         else if (::strstr(mdata->lv2_uid, "_ms") != NULL)
59             fmtStrings      = fmt_strings_ms;
60     }
61 
~para_equalizer_ui()62     para_equalizer_ui::~para_equalizer_ui()
63     {
64         pRewImport = NULL;      // Will be automatically destroyed from list of widgets
65     }
66 
slot_start_import_rew_file(LSPWidget * sender,void * ptr,void * data)67     status_t para_equalizer_ui::slot_start_import_rew_file(LSPWidget *sender, void *ptr, void *data)
68     {
69         para_equalizer_ui *_this = static_cast<para_equalizer_ui *>(ptr);
70 
71         LSPFileDialog *dlg = _this->pRewImport;
72         if (dlg == NULL)
73         {
74             dlg = new LSPFileDialog(&_this->sDisplay);
75             _this->vWidgets.add(dlg);
76             _this->pRewImport  = dlg;
77 
78             dlg->init();
79             dlg->set_mode(FDM_OPEN_FILE);
80             dlg->title()->set("titles.import_rew_filter_settings");
81             dlg->action_title()->set("actions.import");
82 
83             LSPFileFilter *f = dlg->filter();
84             {
85                 LSPFileFilterItem ffi;
86 
87                 ffi.pattern()->set("*.req|*.txt");
88                 ffi.title()->set("files.roomeqwizard.all");
89                 ffi.set_extension("");
90                 f->add(&ffi);
91 
92                 ffi.pattern()->set("*.req");
93                 ffi.title()->set("files.roomeqwizard.req");
94                 ffi.set_extension("");
95                 f->add(&ffi);
96 
97                 ffi.pattern()->set("*.txt");
98                 ffi.title()->set("files.roomeqwizard.txt");
99                 ffi.set_extension("");
100                 f->add(&ffi);
101 
102                 ffi.pattern()->set("*");
103                 ffi.title()->set("files.all");
104                 ffi.set_extension("");
105                 f->add(&ffi);
106             }
107             dlg->bind_action(slot_call_import_rew_file, ptr);
108             dlg->slots()->bind(LSPSLOT_SHOW, slot_fetch_rew_path, _this);
109             dlg->slots()->bind(LSPSLOT_HIDE, slot_commit_rew_path, _this);
110         }
111 
112         return dlg->show(_this->pRoot);
113     }
114 
slot_call_import_rew_file(LSPWidget * sender,void * ptr,void * data)115     status_t para_equalizer_ui::slot_call_import_rew_file(LSPWidget *sender, void *ptr, void *data)
116     {
117         para_equalizer_ui *_this = static_cast<para_equalizer_ui *>(ptr);
118         LSPString path;
119         status_t res = _this->pRewImport->get_selected_file(&path);
120         if (res == STATUS_OK)
121             res = _this->import_rew_file(&path);
122         return STATUS_OK;
123     }
124 
slot_fetch_rew_path(LSPWidget * sender,void * ptr,void * data)125     status_t para_equalizer_ui::slot_fetch_rew_path(LSPWidget *sender, void *ptr, void *data)
126     {
127         para_equalizer_ui *_this = static_cast<para_equalizer_ui *>(ptr);
128         if ((_this == NULL) || (_this->pRewPath == NULL))
129             return STATUS_BAD_STATE;
130 
131         LSPFileDialog *dlg = widget_cast<LSPFileDialog>(sender);
132         if (dlg == NULL)
133             return STATUS_OK;
134 
135         dlg->set_path(_this->pRewPath->get_buffer<char>());
136         return STATUS_OK;
137     }
138 
slot_commit_rew_path(LSPWidget * sender,void * ptr,void * data)139     status_t para_equalizer_ui::slot_commit_rew_path(LSPWidget *sender, void *ptr, void *data)
140     {
141         para_equalizer_ui *_this = static_cast<para_equalizer_ui *>(ptr);
142         if ((_this == NULL) || (_this->pRewPath == NULL))
143             return STATUS_BAD_STATE;
144 
145         LSPFileDialog *dlg = widget_cast<LSPFileDialog>(sender);
146         if (dlg == NULL)
147             return STATUS_OK;
148 
149         const char *path = dlg->path();
150         if (path != NULL)
151         {
152             _this->pRewPath->write(path, ::strlen(path));
153             _this->pRewPath->notify_all();
154         }
155 
156         return STATUS_OK;
157     }
158 
build()159     status_t para_equalizer_ui::build()
160     {
161         status_t res = plugin_ui::build();
162         if (res != STATUS_OK)
163             return res;
164 
165         // Find REW port
166         pRewPath        =  port(UI_CONFIG_PORT_PREFIX UI_DLG_REW_PATH_ID);
167 
168         // Add subwidgets
169         LSPMenu *menu       = widget_cast<LSPMenu>(resolve(WUID_IMPORT_MENU));
170         if (menu != NULL)
171         {
172             LSPMenuItem *child = new LSPMenuItem(&sDisplay);
173             vWidgets.add(child);
174             child->init();
175             child->text()->set("actions.import_rew_filter_file");
176             child->slots()->bind(LSPSLOT_SUBMIT, slot_start_import_rew_file, this);
177             menu->add(child);
178         }
179 
180         return STATUS_OK;
181     }
182 
set_port_value(const char * base,size_t id,float value)183     void para_equalizer_ui::set_port_value(const char *base, size_t id, float value)
184     {
185         char port_id[32];
186 
187         for (const char **fmt = fmtStrings; *fmt != NULL; ++fmt)
188         {
189             ::snprintf(port_id, sizeof(port_id)/sizeof(char), *fmt, base, int(id));
190             CtlPort *p = port(port_id);
191             if (p != NULL)
192             {
193                 p->set_value(value);
194                 p->notify_all();
195             }
196         }
197     }
198 
set_filter_mode(size_t id,size_t value)199     void para_equalizer_ui::set_filter_mode(size_t id, size_t value)
200     {
201         set_port_value("fm", id, value);
202     }
203 
set_filter_type(size_t id,size_t value)204     void para_equalizer_ui::set_filter_type(size_t id, size_t value)
205     {
206         set_port_value("ft", id, value);
207     }
208 
set_filter_frequency(size_t id,double value)209     void para_equalizer_ui::set_filter_frequency(size_t id, double value)
210     {
211         set_port_value("f", id, value);
212     }
213 
set_filter_quality(size_t id,double value)214     void para_equalizer_ui::set_filter_quality(size_t id, double value)
215     {
216         set_port_value("q", id, value);
217     }
218 
set_filter_gain(size_t id,double value)219     void para_equalizer_ui::set_filter_gain(size_t id, double value)
220     {
221         double gain = expf(0.05 * value * M_LN10);
222         set_port_value("g", id, gain);
223     }
224 
set_filter_slope(size_t id,size_t slope)225     void para_equalizer_ui::set_filter_slope(size_t id, size_t slope)
226     {
227         set_port_value("s", id, slope - 1);
228     }
229 
set_filter_enabled(size_t id,bool enabled)230     void para_equalizer_ui::set_filter_enabled(size_t id, bool enabled)
231     {
232         set_port_value("xm", id, (enabled) ? 0.0f : 1.0f);
233     }
234 
set_filter_solo(size_t id,bool solo)235     void para_equalizer_ui::set_filter_solo(size_t id, bool solo)
236     {
237         set_port_value("xs", id, (solo) ? 1.0f : 0.0f);
238     }
239 
import_rew_file(const LSPString * path)240     status_t para_equalizer_ui::import_rew_file(const LSPString *path)
241     {
242         // Load settings
243         room_ew::config_t *cfg = NULL;
244         status_t res = room_ew::load(path, &cfg);
245         if (res != STATUS_OK)
246             return res;
247 
248         // Apply settings
249         size_t fid = 0;
250         for (size_t i=0; i<cfg->nFilters; ++i)
251         {
252             const room_ew::filter_t *f = &cfg->vFilters[i];
253 
254             // Perform parameter translation
255             size_t mode     = para_equalizer_base_metadata::EFM_APO_DR;
256             ssize_t type    = -1;
257             double gain     = 0.0;
258             double quality  = M_SQRT1_2;
259             double freq     = f->fc;
260 
261             switch (f->filterType)
262             {
263                 case room_ew::PK:
264                     type    = para_equalizer_base_metadata::EQF_BELL;
265                     gain    = f->gain;
266                     quality = f->Q;
267                     break;
268                 case room_ew::LS:
269                     type    = para_equalizer_base_metadata::EQF_LOSHELF;
270                     gain    = f->gain;
271                     quality = 2.0/3.0;
272                     break;
273                 case room_ew::HS:
274                     type    = para_equalizer_base_metadata::EQF_HISHELF;
275                     gain    = f->gain;
276                     quality = 2.0/3.0;
277                     break;
278                 case room_ew::LP:
279                     type    = para_equalizer_base_metadata::EQF_LOPASS;
280                     break;
281                 case room_ew::HP:
282                     type    = para_equalizer_base_metadata::EQF_HIPASS;
283                     break;
284                 case room_ew::LPQ:
285                     type    = para_equalizer_base_metadata::EQF_LOPASS;
286                     quality = f->Q;
287                     break;
288                 case room_ew::HPQ:
289                     type    = para_equalizer_base_metadata::EQF_HIPASS;
290                     quality = f->Q;
291                     break;
292                 case room_ew::LS6:
293                     type    = para_equalizer_base_metadata::EQF_LOSHELF;
294                     gain    = f->gain;
295                     quality = M_SQRT2 / 3.0;
296                     freq    = freq * 2.0 / 3.0;
297                     break;
298                 case room_ew::HS6:
299                     type    = para_equalizer_base_metadata::EQF_HISHELF;
300                     gain    = f->gain;
301                     quality = M_SQRT2 / 3.0;
302                     freq    = freq / M_SQRT1_2;
303                     break;
304                 case room_ew::LS12:
305                     type    = para_equalizer_base_metadata::EQF_LOSHELF;
306                     gain    = f->gain;
307                     freq    = freq * 3.0 / 2.0;
308                     break;
309                 case room_ew::HS12:
310                     type    = para_equalizer_base_metadata::EQF_HISHELF;
311                     gain    = f->gain;
312                     freq    = freq * M_SQRT1_2;
313                     break;
314                 case room_ew::NO:
315                     type    = para_equalizer_base_metadata::EQF_NOTCH;
316                     quality = 100.0 / 3.0;
317                     break;
318                 case room_ew::AP:
319                     type    = para_equalizer_base_metadata::EQF_ALLPASS;
320                     quality = 0.0;
321                     break;
322                 default: // Skip other filter types
323                     break;
324             }
325 
326             if (type < 0)
327                 continue;
328 
329             // Set-up parameters
330             set_filter_mode(fid, mode);
331             set_filter_type(fid, type);
332             set_filter_slope(fid, 1);
333             set_filter_frequency(fid, freq);
334             set_filter_gain(fid, gain);
335             set_filter_quality(fid, quality);
336             set_filter_enabled(fid, f->enabled);
337             set_filter_solo(fid, false);
338 
339             // Increment imported filter number
340             ++fid;
341         }
342 
343         // Reset state of all other filters
344         for (; fid < 32; ++fid)
345         {
346             set_filter_type(fid, para_equalizer_base_metadata::EQF_OFF);
347             set_filter_slope(fid, 1);
348             set_filter_gain(fid, 1.0f);
349             set_filter_quality(fid, 0.0f);
350             set_filter_enabled(fid, true);
351             set_filter_solo(fid, false);
352         }
353 
354         return STATUS_OK;
355     }
356 
357 } /* namespace lsp */
358