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