1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2 
3 #ifndef SPECTMORPH_INST_EDIT_PARAMS_HH
4 #define SPECTMORPH_INST_EDIT_PARAMS_HH
5 
6 #include "smcheckbox.hh"
7 #include "smparamlabel.hh"
8 #include "smbutton.hh"
9 #include "smshortcut.hh"
10 #include "smtoolbutton.hh"
11 #include "smcombobox.hh"
12 #include "smfixedgrid.hh"
13 #include "smscrollview.hh"
14 #include "smsamplewidget.hh"
15 
16 namespace SpectMorph
17 {
18 
19 class InstEditParams : public Window
20 {
21   Instrument *instrument = nullptr;
22   SampleWidget *sample_widget = nullptr;
23 
24   CheckBox   *auto_volume_checkbox = nullptr;
25   ComboBox   *auto_volume_method_combobox = nullptr;
26   Label      *auto_volume_method_label = nullptr;
27   Label      *auto_volume_gain_label = nullptr;
28   ParamLabel *auto_volume_gain_param_label = nullptr;
29 
30   CheckBox   *auto_tune_checkbox = nullptr;
31   ComboBox   *auto_tune_method_combobox = nullptr;
32   Label      *auto_tune_method_label = nullptr;
33 
34   Label      *auto_tune_partials_label = nullptr;
35   ParamLabel *auto_tune_partials_param_label = nullptr;
36 
37   Label      *auto_tune_time_label = nullptr;
38   ParamLabel *auto_tune_time_param_label = nullptr;
39 
40   Label      *auto_tune_amount_label = nullptr;
41   ParamLabel *auto_tune_amount_param_label = nullptr;
42 
43   CheckBox   *display_tuning_checkbox = nullptr;
44 
45   Label      *display_tuning_partials_label = nullptr;
46   ParamLabel *display_tuning_partials_param_label = nullptr;
47 
48   Label      *display_tuning_range_label = nullptr;
49   ParamLabel *display_tuning_range_param_label = nullptr;
50 
51   CheckBox   *enc_cfg_checkbox = nullptr;
52   std::vector<Widget *> enc_widgets;
53 
54   ScrollView *scroll_view = nullptr;
55   Widget     *scroll_widget = nullptr;
56 public:
57   InstEditParams (Window *window, Instrument *instrument, SampleWidget *sample_widget) :
58     Window (*window->event_loop(), "SpectMorph - Instrument Parameters", 320, 320, 0, false, window->native_window()),
59     instrument (instrument),
60     sample_widget (sample_widget)
61   {
62     set_close_callback ([this]() {
63       signal_closed();
64       delete_later();
65      });
66 
67     Shortcut *play_shortcut = new Shortcut (this, ' ');
68     connect (play_shortcut->signal_activated, [this]() { signal_toggle_play(); });
69 
70     FixedGrid grid;
71     grid.add_widget (scroll_view = new ScrollView (this), 1, 1, width() / 8 - 2, height() / 8 - 2);
72     scroll_widget = new Widget (scroll_view);
73     scroll_view->set_scroll_widget (scroll_widget, false, true);
74 
75     auto_volume_checkbox = new CheckBox (scroll_widget, "Auto Volume");
76     connect (auto_volume_checkbox->signal_toggled, this, &InstEditParams::on_auto_volume_changed);
77 
78     /*--- auto volume method ---*/
79     auto_volume_method_combobox = new ComboBox (scroll_widget);
80     auto_volume_method_label = new Label (scroll_widget, "Method");
81 
82     connect (auto_volume_method_combobox->signal_item_changed, this, &InstEditParams::on_auto_volume_method_changed);
83     auto_volume_method_combobox->add_item ("From Loop"); // default
84     auto_volume_method_combobox->add_item ("Global");
85 
86     /*--- auto volume gain ---*/
87     auto_volume_gain_label = new Label (scroll_widget, "Gain");
88 
89     auto gain_mod = new ParamLabelModelDouble (instrument->auto_volume().gain, -48.0, 48.0, "%.2f", "%.2f dB");
90     auto_volume_gain_param_label = new ParamLabel (scroll_widget, gain_mod);
91 
92     connect (gain_mod->signal_value_changed, this, &InstEditParams::on_auto_volume_gain_changed);
93 
94     auto_tune_checkbox = new CheckBox (scroll_widget, "Auto Tune");
95     connect (auto_tune_checkbox->signal_toggled, this, &InstEditParams::on_auto_tune_changed);
96 
97     /*--- auto tune method ---*/
98     auto_tune_method_combobox = new ComboBox (scroll_widget);
99     auto_tune_method_label = new Label (scroll_widget, "Method");
100 
101     connect (auto_tune_method_combobox->signal_item_changed, this, &InstEditParams::on_auto_tune_method_changed);
102     auto_tune_method_combobox->add_item ("Simple"); // default
103     auto_tune_method_combobox->add_item ("All Frames");
104     auto_tune_method_combobox->add_item ("Smooth");
105 
106     /*--- auto tune partials ---*/
107     auto_tune_partials_label = new Label (scroll_widget, "Partials");
108 
109     auto partials_mod = new ParamLabelModelInt (instrument->auto_tune().partials, 1, 3);
110     auto_tune_partials_param_label = new ParamLabel (scroll_widget, partials_mod);
111 
112     connect (partials_mod->signal_value_changed, this, &InstEditParams::on_auto_tune_partials_changed);
113 
114     /*--- auto tune time ---*/
115     auto_tune_time_label = new Label (scroll_widget, "Time");
116 
117     auto time_mod = new ParamLabelModelDouble (instrument->auto_tune().time, 1, 2000, "%.2f", "%.2f ms");
118     auto_tune_time_param_label = new ParamLabel (scroll_widget, time_mod);
119 
120     connect (time_mod->signal_value_changed, this, &InstEditParams::on_auto_tune_time_changed);
121 
122     /*--- auto tune amount ---*/
123     auto_tune_amount_label = new Label (scroll_widget, "Amount");
124 
125     auto amount_mod = new ParamLabelModelDouble (instrument->auto_tune().amount, 0, 100, "%.1f", "%.1f %%");
126     auto_tune_amount_param_label = new ParamLabel (scroll_widget, amount_mod);
127 
128     connect (amount_mod->signal_value_changed, this, &InstEditParams::on_auto_tune_amount_changed);
129 
130     /*--- display tuning ---*/
131     display_tuning_checkbox = new CheckBox (scroll_widget, "Display Tuning");
132     connect (display_tuning_checkbox->signal_toggled, this, &InstEditParams::on_display_tuning_changed);
133 
134     /*--- display tuning partials ---*/
135     display_tuning_partials_label = new Label (scroll_widget, "Partials");
136 
137     auto display_partials_mod = new ParamLabelModelInt (sample_widget->display_tuning().partials, 1, 3);
138     display_tuning_partials_param_label = new ParamLabel (scroll_widget, display_partials_mod);
139 
140     connect (display_partials_mod->signal_value_changed, this, &InstEditParams::on_display_tuning_partials_changed);
141 
142     /*--- display tuning range ---*/
143     display_tuning_range_label = new Label (scroll_widget, "Range");
144 
145     auto display_range_mod = new ParamLabelModelInt (sample_widget->display_tuning().range, 1, 400, "%d Cent");
146     display_tuning_range_param_label = new ParamLabel (scroll_widget, display_range_mod);
147 
148     connect (display_range_mod->signal_value_changed, this, &InstEditParams::on_display_tuning_range_changed);
149 
150     /*--- encoder config ---*/
151     enc_cfg_checkbox = new CheckBox (scroll_widget, "Custom Analysis Parameters");
152     connect (enc_cfg_checkbox->signal_toggled, this, &InstEditParams::on_enc_cfg_changed);
153 
154     connect (instrument->signal_global_changed, this, &InstEditParams::on_global_changed);
155     on_global_changed();
156     show();
157   }
158   void
159   on_global_changed()
160   {
161     FixedGrid grid;
162 
163     const auto auto_volume = instrument->auto_volume();
164     auto_volume_checkbox->set_checked (auto_volume.enabled);
165     auto_volume_method_label->set_visible (auto_volume.enabled);
166     auto_volume_method_combobox->set_visible (auto_volume.enabled);
167     auto_volume_gain_label->set_visible (auto_volume.enabled && auto_volume.method == Instrument::AutoVolume::GLOBAL);
168     auto_volume_gain_param_label->set_visible (auto_volume.enabled && auto_volume.method == Instrument::AutoVolume::GLOBAL);
169 
170     double y = 0;
171     grid.add_widget (auto_volume_checkbox, 0, y, 20, 2);
172     y += 2;
173     if (auto_volume.enabled)
174       {
175         grid.add_widget (auto_volume_method_label, 2, y, 10, 3);
176         grid.add_widget (auto_volume_method_combobox, 11, y, 23, 3);
177         y += 3;
178         if (auto_volume.method == Instrument::AutoVolume::GLOBAL)
179           {
180             grid.add_widget (auto_volume_gain_label, 2, y, 10, 3);
181             grid.add_widget (auto_volume_gain_param_label, 11, y, 10, 3);
182             y += 3;
183           }
184       }
185     const auto auto_tune = instrument->auto_tune();
186     auto_tune_method_label->set_visible (auto_tune.enabled);
187     auto_tune_method_combobox->set_visible (auto_tune.enabled);
188 
189     auto_tune_partials_label->set_visible (auto_tune.enabled &&
190       (auto_tune.method == Instrument::AutoTune::ALL_FRAMES || auto_tune.method == Instrument::AutoTune::SMOOTH));
191     auto_tune_partials_param_label->set_visible (auto_tune_partials_label->visible());
192 
193     auto_tune_time_label->set_visible (auto_tune.enabled && auto_tune.method == Instrument::AutoTune::SMOOTH);
194     auto_tune_time_param_label->set_visible (auto_tune_time_label->visible());
195 
196     auto_tune_amount_label->set_visible (auto_tune.enabled && auto_tune.method == Instrument::AutoTune::SMOOTH);
197     auto_tune_amount_param_label->set_visible (auto_tune_amount_label->visible());
198 
199     grid.add_widget (auto_tune_checkbox, 0, y, 20, 2);
200     y += 2;
201     if (auto_tune.enabled)
202       {
203         grid.add_widget (auto_tune_method_label, 2, y, 10, 3);
204         grid.add_widget (auto_tune_method_combobox, 11, y, 23, 3);
205         y += 3;
206         if (auto_tune_partials_label->visible())
207           {
208             grid.add_widget (auto_tune_partials_label, 2, y, 10, 3);
209             grid.add_widget (auto_tune_partials_param_label, 11, y, 10, 3);
210             y += 3;
211           }
212         if (auto_tune_time_label->visible())
213           {
214             grid.add_widget (auto_tune_time_label, 2, y, 10, 3);
215             grid.add_widget (auto_tune_time_param_label, 11, y, 10, 3);
216             y += 3;
217           }
218         if (auto_tune_amount_label->visible())
219           {
220             grid.add_widget (auto_tune_amount_label, 2, y, 10, 3);
221             grid.add_widget (auto_tune_amount_param_label, 11, y, 10, 3);
222             y += 3;
223           }
224       }
225 
226     const auto display_tuning = sample_widget->display_tuning();
227     display_tuning_partials_label->set_visible (display_tuning.enabled);
228     display_tuning_partials_param_label->set_visible (display_tuning.enabled);
229     display_tuning_range_label->set_visible (display_tuning.enabled);
230     display_tuning_range_param_label->set_visible (display_tuning.enabled);
231     grid.add_widget (display_tuning_checkbox, 0, y, 30, 2);
232     y += 2;
233     if (display_tuning.enabled)
234       {
235         grid.add_widget (display_tuning_partials_label, 2, y, 10, 3);
236         grid.add_widget (display_tuning_partials_param_label, 11, y, 23, 3);
237         y += 3;
238         grid.add_widget (display_tuning_range_label, 2, y, 10, 3);
239         grid.add_widget (display_tuning_range_param_label, 11, y, 23, 3);
240         y += 3;
241       }
242 
243     grid.add_widget (enc_cfg_checkbox, 0, y, 30, 2);
244     y += 2;
245 
246     switch (auto_tune.method)
247     {
248       case Instrument::AutoTune::SIMPLE:
249         auto_tune_method_combobox->set_text ("Simple");
250         break;
251       case Instrument::AutoTune::ALL_FRAMES:
252         auto_tune_method_combobox->set_text ("All Frames");
253         break;
254       case Instrument::AutoTune::SMOOTH:
255         auto_tune_method_combobox->set_text ("Smooth");
256         break;
257     }
258 
259     auto_tune_checkbox->set_checked (instrument->auto_tune().enabled);
260     display_tuning_checkbox->set_checked (display_tuning.enabled);
261     enc_cfg_checkbox->set_checked (instrument->encoder_config().enabled);
262 
263     if (instrument->auto_volume().method == Instrument::AutoVolume::GLOBAL)
264       auto_volume_method_combobox->set_text ("Global");
265     else
266       auto_volume_method_combobox->set_text ("From Loop");
267 
268     auto encoder_config = instrument->encoder_config();
269 
270     for (auto w : enc_widgets) /* delete old enc widgets */
271       w->delete_later();
272     enc_widgets.clear();
273 
274     if (encoder_config.enabled)
275       {
276         for (size_t i = 0; i < encoder_config.entries.size(); i++)
277           {
278             auto param_mod = new ParamLabelModelString (encoder_config.entries[i].param);
279             connect (param_mod->signal_value_changed, [this,i] (const std::string& s) { on_change_enc_entry (i, s.c_str(), nullptr); });
280 
281             auto value_mod = new ParamLabelModelString (encoder_config.entries[i].value);
282             connect (value_mod->signal_value_changed, [this,i] (const std::string& s) { on_change_enc_entry (i, nullptr, s.c_str()); });
283 
284             ParamLabel *plabel = new ParamLabel (scroll_widget, param_mod);
285             ParamLabel *vlabel = new ParamLabel (scroll_widget, value_mod);
286             ToolButton *tbutton = new ToolButton (scroll_widget, 'x');
287 
288             grid.add_widget (plabel, 2, y, 18, 3);
289             grid.add_widget (vlabel, 21, y, 11, 3);
290             grid.add_widget (tbutton, 32.5, y + 0.5, 2, 2);
291             y += 3;
292             enc_widgets.push_back (plabel);
293             enc_widgets.push_back (vlabel);
294             enc_widgets.push_back (tbutton);
295 
296             connect (tbutton->signal_clicked, [this,i]() { on_remove_enc_entry (i); });
297           }
298         Button *add_button = new Button (scroll_widget, "Add Entry");
299         grid.add_widget (add_button, 2, y, 12, 3);
300         connect (add_button->signal_clicked, this, &InstEditParams::on_add_enc_entry);
301         enc_widgets.push_back (add_button);
302         y += 3;
303       }
304 
305     scroll_widget->set_height (y * 8);
306     scroll_widget->set_width (32 * 8);
307     scroll_view->on_widget_size_changed();
308   }
309   void
310   on_auto_volume_changed (bool new_value)
311   {
312     Instrument::AutoVolume av = instrument->auto_volume();
313     av.enabled = new_value;
314 
315     instrument->set_auto_volume (av);
316   }
317   void
318   on_auto_volume_method_changed()
319   {
320     Instrument::AutoVolume av = instrument->auto_volume();
321 
322     int idx = auto_volume_method_combobox->current_index();
323     if (idx == 0)
324       av.method = Instrument::AutoVolume::FROM_LOOP;
325     else
326       av.method = Instrument::AutoVolume::GLOBAL;
327 
328     instrument->set_auto_volume (av);
329   }
330   void
331   on_auto_volume_gain_changed (double gain)
332   {
333     Instrument::AutoVolume av = instrument->auto_volume();
334     av.gain = gain;
335 
336     instrument->set_auto_volume (av);
337   }
338   void
339   on_auto_tune_changed (bool new_value)
340   {
341     auto at = instrument->auto_tune();
342     at.enabled = new_value;
343 
344     instrument->set_auto_tune (at);
345   }
346   void
347   on_auto_tune_method_changed()
348   {
349     auto at = instrument->auto_tune();
350 
351     int idx = auto_tune_method_combobox->current_index();
352     if (idx == 0)
353       at.method = Instrument::AutoTune::SIMPLE;
354     if (idx == 1)
355       at.method = Instrument::AutoTune::ALL_FRAMES;
356     if (idx == 2)
357       at.method = Instrument::AutoTune::SMOOTH;
358 
359     instrument->set_auto_tune (at);
360   }
361   void
362   on_auto_tune_partials_changed (int p)
363   {
364     auto at = instrument->auto_tune();
365     at.partials = p;
366 
367     instrument->set_auto_tune (at);
368   }
369   void
370   on_auto_tune_time_changed (double t)
371   {
372     auto at = instrument->auto_tune();
373     at.time = t;
374 
375     instrument->set_auto_tune (at);
376   }
377   void
378   on_auto_tune_amount_changed (double a)
379   {
380     auto at = instrument->auto_tune();
381     at.amount = a;
382 
383     instrument->set_auto_tune (at);
384   }
385   void
386   on_enc_cfg_changed (bool new_value)
387   {
388     auto enc_cfg = instrument->encoder_config();
389     enc_cfg.enabled = new_value;
390 
391     instrument->set_encoder_config (enc_cfg);
392   }
393   void
394   on_remove_enc_entry (size_t i)
395   {
396     auto enc_cfg = instrument->encoder_config();
397 
398     if (i < enc_cfg.entries.size())
399       enc_cfg.entries.erase (enc_cfg.entries.begin() + i);
400 
401     instrument->set_encoder_config (enc_cfg);
402   }
403   void
404   on_add_enc_entry()
405   {
406     auto enc_cfg = instrument->encoder_config();
407 
408     Instrument::EncoderEntry entry {"key", "value" };
409     enc_cfg.entries.push_back (entry);
410 
411     instrument->set_encoder_config (enc_cfg);
412   }
413   void
414   on_change_enc_entry (size_t i, const char *k, const char *v)
415   {
416     auto enc_cfg = instrument->encoder_config();
417 
418     if (i < enc_cfg.entries.size())
419       {
420         if (k)
421           enc_cfg.entries[i].param = k;
422         if (v)
423           enc_cfg.entries[i].value = v;
424       }
425 
426     instrument->set_encoder_config (enc_cfg);
427   }
428   void
429   on_display_tuning_changed (bool new_value)
430   {
431     auto dt = sample_widget->display_tuning();
432     dt.enabled = new_value;
433     sample_widget->set_display_tuning (dt);
434     on_global_changed(); // DisplayTuning is not part of Instrument
435   }
436   void
437   on_display_tuning_partials_changed (int p)
438   {
439     auto dt = sample_widget->display_tuning();
440     dt.partials = p;
441     sample_widget->set_display_tuning (dt);
442     on_global_changed(); // DisplayTuning is not part of Instrument
443   }
444   void
445   on_display_tuning_range_changed (int r)
446   {
447     auto dt = sample_widget->display_tuning();
448     dt.range = r;
449     sample_widget->set_display_tuning (dt);
450     on_global_changed(); // DisplayTuning is not part of Instrument
451   }
452   Signal<> signal_toggle_play;
453   Signal<> signal_closed;
454 };
455 
456 }
457 
458 #endif
459