From 3a882b98d74c1d2b473080890ca534bf716797d2 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Fri, 12 Nov 2021 00:03:30 +0100 Subject: [PATCH 1/2] Updated options panel and random things in the UI --- plugins/editor/layout/main.fl | 237 +++++++++++++--------- plugins/editor/src/editor/Editor.cpp | 95 ++++++--- plugins/editor/src/editor/layout/main.hpp | 165 ++++++++------- 3 files changed, 304 insertions(+), 193 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index 63effffff..8457fa5c2 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -3,11 +3,11 @@ version 1.0304 header_name {.h} code_name {.cxx} widget_class mainView {open - xywh {108 91 800 475} type Double + xywh {607 439 800 475} type Double class LogicalGroup visible } { Fl_Box imageContainer_ { - image {../resources/background.png} xywh {5 110 790 285} + image {../resources/background.png} xywh {90 110 790 285} class Background } Fl_Group {} { @@ -15,7 +15,7 @@ widget_class mainView {open xywh {0 0 814 110} class LogicalGroup } { - Fl_Group {} {open + Fl_Group {} { xywh {5 4 175 101} box ROUNDED_BOX align 0 class RoundedGroup } { @@ -45,7 +45,7 @@ widget_class mainView {open class HomeButton } } - Fl_Group {} {open + Fl_Group {} { xywh {185 5 390 100} box ROUNDED_BOX class RoundedGroup } { @@ -126,7 +126,7 @@ widget_class mainView {open class ChevronValueDropDown } } - Fl_Group {} {open + Fl_Group {} { xywh {580 5 215 100} box ROUNDED_BOX class RoundedGroup } { @@ -155,17 +155,17 @@ widget_class mainView {open xywh {739 10 23 90} box BORDER_BOX class VMeter } - Fl_Box {meters_[1]} {selected + Fl_Box {meters_[1]} { xywh {763 10 23 90} box BORDER_BOX class VMeter } } } - Fl_Group {subPanels_[kPanelInfo]} { + Fl_Group {subPanels_[kPanelInfo]} {open xywh {5 110 790 285} hide class LogicalGroup } { - Fl_Group {} {open + Fl_Group {} { xywh {5 110 790 285} box ROUNDED_BOX class RoundedGroup } { @@ -225,7 +225,7 @@ widget_class mainView {open xywh {5 110 790 285} hide class LogicalGroup } { - Fl_Group {} {open + Fl_Group {} { xywh {5 110 790 285} box ROUNDED_BOX class RoundedGroup } { @@ -235,150 +235,205 @@ widget_class mainView {open } {} } } - Fl_Group {subPanels_[kPanelSettings]} { - xywh {5 110 790 285} + Fl_Group {subPanels_[kPanelSettings]} {open + xywh {0 110 825 360} class LogicalGroup } { - Fl_Group {} { - label Engine open - xywh {305 135 195 100} box ROUNDED_BOX labelsize 12 align 17 - class TitleGroup + Fl_Group {} {open + xywh {5 110 790 285} box ROUNDED_BOX + class RoundedGroup } { Fl_Spinner oversamplingSlider_ { comment {tag=kTagSetOversampling} - xywh {330 195 60 25} labelsize 12 textsize 12 + xywh {175 185 70 25} labelsize 12 textsize 12 class ValueMenu } Fl_Box {} { label Oversampling - xywh {320 155 80 25} labelsize 12 - class ValueLabel + xywh {20 185 85 25} labelsize 12 align 20 + class Label } Fl_Box {} { label {Preload size} - xywh {405 155 80 25} labelsize 12 - class ValueLabel + xywh {20 160 75 25} labelsize 12 align 20 + class Label } Fl_Spinner preloadSizeSlider_ { comment {tag=kTagSetPreloadSize} - xywh {415 195 60 25} labelsize 12 textsize 12 + xywh {175 160 70 25} labelsize 12 textsize 12 + class ValueMenu + } + Fl_Spinner sampleQualitySlider_ { + comment {tag=kTagSetSampleQuality} + xywh {435 145 80 25} labelsize 12 textsize 12 class ValueMenu } - } - Fl_Group {} { - label Tuning open - xywh {175 270 415 100} box ROUNDED_BOX labelsize 12 align 17 - class TitleGroup - } { Fl_Box {} { - label {Root key} - xywh {330 290 80 25} labelsize 12 - class ValueLabel + label Sample + xywh {290 145 50 25} labelsize 12 align 20 + class Label } - Fl_Spinner tuningFrequencySlider_ { - comment {tag=kTagSetTuningFrequency} - xywh {425 330 60 25} labelsize 12 textsize 12 + Fl_Box {} { + label Oscillator + xywh {290 170 60 25} labelsize 12 align 20 + class Label + } + Fl_Spinner oscillatorQualitySlider_ { + comment {tag=kTagSetOscillatorQuality} + xywh {435 170 80 25} labelsize 12 textsize 12 class ValueMenu } + Fl_Spinner themeMenu_ { + comment {tag=kTagThemeMenu} + xywh {680 145 100 25} labelsize 12 textsize 12 + class OptionMenu + } + Fl_Box {} { + label Theme + xywh {555 145 45 25} labelsize 12 align 20 + class Label + } + Fl_Box {} { + label {User SFZ folder} + xywh {555 170 95 25} labelsize 12 align 20 + class Label + } + Fl_Button userFilesDirButton_ { + label DefaultPath + comment {tag=kTagChooseUserFilesDir} + xywh {680 170 100 25} labelsize 12 + class ValueButton + } + Fl_Box {} { + label {Root key} + xywh {290 285 60 25} labelsize 12 align 20 + class Label + } Fl_Box {} { label Frequency - xywh {415 290 80 25} labelsize 12 - class ValueLabel + xywh {290 310 70 25} labelsize 12 align 20 + class Label } Fl_Dial stretchedTuningSlider_ { comment {tag=kTagSetStretchedTuning} - xywh {515 315 48 48} value 0.5 + xywh {455 337 48 48} value 0.5 class StyledKnob } Fl_Box {} { label Stretch - xywh {500 290 80 25} labelsize 12 - class ValueLabel + xywh {290 345 50 25} labelsize 12 align 20 + class Label } Fl_Box {} { label {Scala file} - xywh {195 290 100 25} labelsize 12 - class ValueLabel + xywh {290 260 60 25} labelsize 12 align 20 + class Label } Fl_Button scalaFileButton_ { label DefaultScale comment {tag=kTagLoadScalaFile} - xywh {195 330 100 25} labelsize 12 + xywh {390 260 100 25} labelsize 12 class ValueButton } Fl_Spinner scalaRootKeySlider_ { comment {tag=kTagSetScalaRootKey} - xywh {340 330 35 25} labelsize 12 textsize 12 + xywh {450 285 35 25} labelsize 12 textsize 12 class ValueMenu } Fl_Spinner scalaRootOctaveSlider_ { comment {tag=kTagSetScalaRootKey} - xywh {375 330 30 25} labelsize 12 textsize 12 + xywh {485 285 30 25} labelsize 12 textsize 12 class ValueMenu } Fl_Button scalaResetButton_ { comment {tag=kTagResetScalaFile} - xywh {295 330 25 25} labelsize 12 + xywh {490 260 25 25} labelsize 12 class ResetSomethingButton } - } - Fl_Group userFilesGroup_ { - label Files open - xywh {620 270 139 100} box ROUNDED_BOX labelsize 12 align 17 - class TitleGroup - } { Fl_Box {} { - label {User SFZ folder} - xywh {640 290 100 25} labelsize 12 - class ValueLabel - } - Fl_Button userFilesDirButton_ { - label DefaultPath - comment {tag=kTagChooseUserFilesDir} - xywh {640 330 100 25} labelsize 12 - class ValueButton + label Freewheeling + xywh {290 195 85 25} labelsize 12 align 20 + class Label } - } - Fl_Group {} { - label Quality open - xywh {530 135 195 100} box ROUNDED_BOX labelsize 12 align 17 - class TitleGroup - } { - Fl_Spinner sampleQualitySlider_ { - comment {tag=kTagSetSampleQuality} - xywh {545 195 80 25} labelsize 12 textsize 12 + Fl_Spinner freewheelingQualitySlider_ { + comment {tag=kTagSetOscillatorQuality} + xywh {435 195 80 25} labelsize 12 textsize 12 class ValueMenu } Fl_Box {} { - label Sample - xywh {545 155 80 25} labelsize 12 - class ValueLabel + label {Release cancels sustain} + xywh {20 210 145 25} labelsize 12 align 20 + class Label + } + Fl_Check_Button {} { + xywh {205 210 25 25} down_box DOWN_BOX + class Checkbox + } + Fl_Box sfizzVersionLabel_ { + label SFIZZ_VERSION + xywh {20 140 225 20} labelsize 10 + class Label } Fl_Box {} { - label Oscillator - xywh {630 155 80 25} labelsize 12 - class ValueLabel + label {Rendering quality} + xywh {290 115 110 25} labelsize 12 align 20 + class Label } - Fl_Spinner oscillatorQualitySlider_ { - comment {tag=kTagSetOscillatorQuality} - xywh {630 195 80 25} labelsize 12 textsize 12 - class ValueMenu + Fl_Box {} { + label {Separator 2} + xywh {20 135 225 5} box BORDER_BOX labeltype NO_LABEL + class HLine } - } - Fl_Group {} { - label Appearance open - xywh {40 270 105 100} box ROUNDED_BOX labelsize 12 align 17 - class TitleGroup - } { - Fl_Spinner themeMenu_ { - comment {tag=kTagThemeMenu} - xywh {60 330 65 25} labelsize 12 textsize 12 - class OptionMenu + Fl_Box {} { + label {Engine options} + xywh {20 115 95 25} labelsize 12 align 20 + class Label } Fl_Box {} { - label Theme - xywh {50 295 80 25} labelsize 12 - class ValueLabel + label {Separator 2} + xywh {580 135 185 5} box BORDER_BOX labeltype NO_LABEL + class HLine + } + Fl_Box {} { + label Other + xywh {555 115 40 25} labelsize 12 align 20 + class Label + } + Fl_Box {} { + label Tuning + xywh {290 230 225 25} labelsize 12 align 20 + class Label + } + Fl_Box {} { + label {Separator 2} + xywh {290 135 225 5} box BORDER_BOX labeltype NO_LABEL + class HLine + } + Fl_Box {} { + label {Separator 2} + xywh {555 135 225 5} box BORDER_BOX labeltype NO_LABEL + class HLine + } + Fl_Box {} { + label {Separator 2} + xywh {290 250 225 5} box BORDER_BOX labeltype NO_LABEL + class HLine + } + Fl_Button tuningFrequencyDropdown_ { + comment {tag=kTagSetTuningFrequency} + xywh {490 310 25 25} labelsize 24 + class ChevronValueDropDown + } + Fl_Text_Editor tuningFrequencyEdit_ { + comment {tag=kTagSetTuningFrequency} + xywh {430 310 60 25} labelsize 12 + class TextEdit + } + Fl_Button settingsAboutButton_ { + label {About sfizz} + comment {tag=kTagAbout} selected + xywh {610 205 115 25} labelsize 12 + class ValueButton } } } diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index a9e02003a..8b062aac0 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -10,6 +10,7 @@ #include "GUIComponents.h" #include "GUIHelpers.h" #include "GUIPiano.h" +#include "GitBuildId.h" #include "DlgAbout.h" #include "ImageHelpers.h" #include "NativeHelpers.h" @@ -20,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +98,8 @@ struct Editor::Impl : EditorController::Receiver, kTagSetStretchedTuning, kTagSetSampleQuality, kTagSetOscillatorQuality, + kTagSetFreewheelingQuality, + kTagSetReleaseCancelsSustain, kTagSetCCVolume, kTagSetCCPan, kTagChooseUserFilesDir, @@ -120,12 +124,15 @@ struct Editor::Impl : EditorController::Receiver, SValueMenu *scalaRootKeySlider_ = nullptr; SValueMenu *scalaRootOctaveSlider_ = nullptr; CTextLabel* scalaRootKeyLabel_ = nullptr; - SValueMenu *tuningFrequencySlider_ = nullptr; + SValueMenu* tuningFrequencyDropdown_ = nullptr; + CTextEdit* tuningFrequencyEdit_ = nullptr; + STextButton *settingsAboutButton_ = nullptr; CTextLabel* tuningFrequencyLabel_ = nullptr; CControl *stretchedTuningSlider_ = nullptr; CTextLabel* stretchedTuningLabel_ = nullptr; SValueMenu *sampleQualitySlider_ = nullptr; SValueMenu *oscillatorQualitySlider_ = nullptr; + SValueMenu *freewheelingQualitySlider_ = nullptr; CTextLabel* keyswitchLabel_ = nullptr; CTextLabel* keyswitchInactiveLabel_ = nullptr; CTextLabel* keyswitchBadge_ = nullptr; @@ -161,6 +168,8 @@ struct Editor::Impl : EditorController::Receiver, SharedPointer backgroundBitmap_; SharedPointer defaultBackgroundBitmap_; + CTextLabel* sfizzVersionLabel_ = nullptr; + SKnobCCBox* getSecondaryCCKnob(unsigned cc) { switch (cc) { @@ -219,7 +228,6 @@ struct Editor::Impl : EditorController::Receiver, void updateOversamplingLabel(int oversamplingLog2); void updatePreloadSizeLabel(int preloadSize); void updateScalaRootKeyLabel(int rootKey); - void updateTuningFrequencyLabel(float tuningFrequency); void updateStretchedTuningLabel(float stretchedTuning); absl::string_view getCurrentKeyswitchName() const; @@ -410,9 +418,8 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) case EditId::TuningFrequency: { const float value = v.to_float(); - if (tuningFrequencySlider_) - tuningFrequencySlider_->setValue(value); - updateTuningFrequencyLabel(value); + if (tuningFrequencyEdit_) + tuningFrequencyEdit_->setValue(value); } break; case EditId::StretchTuning: @@ -695,6 +702,7 @@ void Editor::Impl::createFrameContents() }); return box; }; +#if 0 auto createTitleGroup = [this, &palette](const CRect& bounds, int, const char* label, CHoriTxtAlign, int fontsize) { auto* box = new STitleContainer(bounds, label); box->setCornerRadius(10.0); @@ -707,6 +715,7 @@ void Editor::Impl::createFrameContents() box->setTitleFont(font); return box; }; +#endif auto createAboutButton = [this, &iconShaded](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int) { return new CKickButton(bounds, this, tag, 0.0f, iconShaded); }; @@ -734,11 +743,13 @@ void Editor::Impl::createFrameContents() lbl->setFont(font); return lbl; }; - auto createHLine = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { + auto createHLine = [this, &palette](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { int y = static_cast(0.5 * (bounds.top + bounds.bottom)); CRect lineBounds(bounds.left, y, bounds.right, y + 1); CViewContainer* hline = new CViewContainer(lineBounds); - hline->setBackgroundColor(CColor(0xff, 0xff, 0xff, 0xff)); + OnThemeChanged.push_back([hline, palette]() { + hline->setBackgroundColor(palette->text); + }); return hline; }; auto createValueLabel = [this, &palette](const CRect& bounds, int, const char* label, CHoriTxtAlign align, int fontsize) { @@ -767,15 +778,7 @@ void Editor::Impl::createFrameContents() lbl->setFont(font); return lbl; }; -#if 0 - auto createButton = [this](const CRect& bounds, int tag, const char* label, CHoriTxtAlign align, int fontsize) { - CTextButton* button = new CTextButton(bounds, this, tag, label); - auto font = makeOwned("Roboto", fontsize); - button->setFont(font); - button->setTextAlignment(align); - return button; - }; -#endif + auto createClickableLabel = [this, &palette](const CRect& bounds, int tag, const char* label, CHoriTxtAlign align, int fontsize) { STextButton* button = new STextButton(bounds, this, tag, label); auto font = makeOwned("Roboto", fontsize); @@ -982,6 +985,26 @@ void Editor::Impl::createFrameContents() return panel; }; + auto createCheckbox = [this, &palette](const CRect& bounds, int tag, const char* label, CHoriTxtAlign, int) { + auto* checkbox = new CCheckBox(bounds, this, tag, label); + return checkbox; + }; + + auto createTextEdit = [this, &palette] (const CRect& bounds, int tag, const char* label, CHoriTxtAlign align, int fontsize) { + auto* edit = new CTextEdit(bounds, this, tag, label, nullptr); + auto font = makeOwned("Roboto", fontsize); + edit->setFont(font); + edit->setHoriAlign(align); + edit->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + edit->setStyle(CParamDisplay::kRoundRectStyle); + edit->setRoundRectRadius(5.0); + OnThemeChanged.push_back([edit, palette]() { + edit->setFontColor(palette->valueText); + edit->setBackColor(palette->valueBackground); + }); + return edit; + }; + #include "layout/main.hpp" OnThemeChanged.push_back([mainView, theme]() { @@ -1025,6 +1048,11 @@ void Editor::Impl::createFrameContents() mainView_ = owned(mainView); } + if (CTextLabel* label = sfizzVersionLabel_) { + std::string version = GitBuildId[0] ? absl::StrCat(SFIZZ_VERSION ".", GitBuildId) : SFIZZ_VERSION; + label->setText(absl::StrCat(u8"sfizz ", version)); + } + /// currentThemeName_ = theme->loadCurrentName(); theme->load(currentThemeName_); @@ -1061,8 +1089,9 @@ void Editor::Impl::createFrameContents() scalaRootOctaveSlider_->setDefaultValue( static_cast(EditRange::get(EditId::ScalaRootKey).def) / 12); } - adjustMinMaxToEditRange(tuningFrequencySlider_, EditId::TuningFrequency); - tuningFrequencySlider_->setWheelInc(0.1f / EditRange::get(EditId::TuningFrequency).extent()); + adjustMinMaxToEditRange(tuningFrequencyDropdown_, EditId::TuningFrequency); + adjustMinMaxToEditRange(tuningFrequencyEdit_, EditId::TuningFrequency); + tuningFrequencyEdit_->setWheelInc(0.1f / EditRange::get(EditId::TuningFrequency).extent()); adjustMinMaxToEditRange(stretchedTuningSlider_, EditId::StretchTuning); adjustMinMaxToEditRange(sampleQualitySlider_, EditId::SampleQuality); adjustMinMaxToEditRange(oscillatorQualitySlider_, EditId::OscillatorQuality); @@ -1110,14 +1139,25 @@ void Editor::Impl::createFrameContents() }; for (std::pair value : tuningFrequencies) - tuningFrequencySlider_->addEntry(value.second, value.first); - tuningFrequencySlider_->setValueToStringFunction( + tuningFrequencyDropdown_->addEntry(value.second, value.first); + + tuningFrequencyEdit_->setValueToStringFunction( [](float value, char result[256], CParamDisplay*) -> bool { sprintf(result, "%.1f Hz", value); return true; }); + tuningFrequencyEdit_->setStringToValueFunction([](UTF8StringPtr txt, float& result, CTextEdit*) -> bool { + float value; + if (absl::SimpleAtof(txt, &value)) { + result = value; + return true; + } + + return false; + }); + static const char* notesInOctave[12] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", @@ -1616,18 +1656,6 @@ void Editor::Impl::updateScalaRootKeyLabel(int rootKey) label->setText(noteName(rootKey)); } -void Editor::Impl::updateTuningFrequencyLabel(float tuningFrequency) -{ - CTextLabel* label = tuningFrequencyLabel_; - if (!label) - return; - - char text[64]; - sprintf(text, "%.1f", tuningFrequency); - text[sizeof(text) - 1] = '\0'; - label->setText(text); -} - void Editor::Impl::updateStretchedTuningLabel(float stretchedTuning) { CTextLabel* label = stretchedTuningLabel_; @@ -1962,7 +1990,8 @@ void Editor::Impl::valueChanged(CControl* ctl) case kTagSetTuningFrequency: ctrl.uiSendValue(EditId::TuningFrequency, value); - updateTuningFrequencyLabel(value); + if (tuningFrequencyEdit_) + tuningFrequencyEdit_->setValue(value); break; case kTagSetSampleQuality: diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index f640d4472..f732efc52 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -1,7 +1,7 @@ /* This file is generated by the layout maker tool. */ auto* const view__0 = createLogicalGroup(CRect(0, 0, 800, 475), -1, "", kCenterText, 14); mainView = view__0; -auto* const view__1 = createBackground(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); +auto* const view__1 = createBackground(CRect(90, 110, 880, 395), -1, "", kCenterText, 14); imageContainer_ = view__1; view__0->addView(view__1); enterPalette(invertedPalette); @@ -128,80 +128,107 @@ view__45->addView(view__46); auto* const view__47 = createControlsPanel(CRect(0, 0, 790, 285), -1, "", kCenterText, 12); controlsPanel_ = view__47; view__46->addView(view__47); -auto* const view__48 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); +auto* const view__48 = createLogicalGroup(CRect(0, 110, 825, 470), -1, "", kCenterText, 14); subPanels_[kPanelSettings] = view__48; view__0->addView(view__48); -auto* const view__49 = createTitleGroup(CRect(300, 25, 495, 125), -1, "Engine", kCenterText, 12); +auto* const view__49 = createRoundedGroup(CRect(5, 0, 795, 285), -1, "", kCenterText, 14); view__48->addView(view__49); -auto* const view__50 = createValueMenu(CRect(25, 60, 85, 85), kTagSetOversampling, "", kCenterText, 12); +auto* const view__50 = createValueMenu(CRect(170, 75, 240, 100), kTagSetOversampling, "", kCenterText, 12); oversamplingSlider_ = view__50; view__49->addView(view__50); -auto* const view__51 = createValueLabel(CRect(15, 20, 95, 45), -1, "Oversampling", kCenterText, 12); +auto* const view__51 = createLabel(CRect(15, 75, 100, 100), -1, "Oversampling", kLeftText, 12); view__49->addView(view__51); -auto* const view__52 = createValueLabel(CRect(100, 20, 180, 45), -1, "Preload size", kCenterText, 12); +auto* const view__52 = createLabel(CRect(15, 50, 90, 75), -1, "Preload size", kLeftText, 12); view__49->addView(view__52); -auto* const view__53 = createValueMenu(CRect(110, 60, 170, 85), kTagSetPreloadSize, "", kCenterText, 12); +auto* const view__53 = createValueMenu(CRect(170, 50, 240, 75), kTagSetPreloadSize, "", kCenterText, 12); preloadSizeSlider_ = view__53; view__49->addView(view__53); -auto* const view__54 = createTitleGroup(CRect(170, 160, 585, 260), -1, "Tuning", kCenterText, 12); -view__48->addView(view__54); -auto* const view__55 = createValueLabel(CRect(155, 20, 235, 45), -1, "Root key", kCenterText, 12); -view__54->addView(view__55); -auto* const view__56 = createValueMenu(CRect(250, 60, 310, 85), kTagSetTuningFrequency, "", kCenterText, 12); -tuningFrequencySlider_ = view__56; -view__54->addView(view__56); -auto* const view__57 = createValueLabel(CRect(240, 20, 320, 45), -1, "Frequency", kCenterText, 12); -view__54->addView(view__57); -auto* const view__58 = createStyledKnob(CRect(340, 45, 388, 93), kTagSetStretchedTuning, "", kCenterText, 14); -stretchedTuningSlider_ = view__58; -view__54->addView(view__58); -auto* const view__59 = createValueLabel(CRect(325, 20, 405, 45), -1, "Stretch", kCenterText, 12); -view__54->addView(view__59); -auto* const view__60 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12); -view__54->addView(view__60); -auto* const view__61 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); -scalaFileButton_ = view__61; -view__54->addView(view__61); -auto* const view__62 = createValueMenu(CRect(165, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); -scalaRootKeySlider_ = view__62; -view__54->addView(view__62); -auto* const view__63 = createValueMenu(CRect(200, 60, 230, 85), kTagSetScalaRootKey, "", kCenterText, 12); -scalaRootOctaveSlider_ = view__63; -view__54->addView(view__63); -auto* const view__64 = createResetSomethingButton(CRect(120, 60, 145, 85), kTagResetScalaFile, "", kCenterText, 12); -scalaResetButton_ = view__64; -view__54->addView(view__64); -auto* const view__65 = createTitleGroup(CRect(615, 160, 754, 260), -1, "Files", kCenterText, 12); -userFilesGroup_ = view__65; -view__48->addView(view__65); -auto* const view__66 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); -view__65->addView(view__66); -auto* const view__67 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); -userFilesDirButton_ = view__67; -view__65->addView(view__67); -auto* const view__68 = createTitleGroup(CRect(525, 25, 720, 125), -1, "Quality", kCenterText, 12); -view__48->addView(view__68); -auto* const view__69 = createValueMenu(CRect(15, 60, 95, 85), kTagSetSampleQuality, "", kCenterText, 12); -sampleQualitySlider_ = view__69; -view__68->addView(view__69); -auto* const view__70 = createValueLabel(CRect(15, 20, 95, 45), -1, "Sample", kCenterText, 12); -view__68->addView(view__70); -auto* const view__71 = createValueLabel(CRect(100, 20, 180, 45), -1, "Oscillator", kCenterText, 12); -view__68->addView(view__71); -auto* const view__72 = createValueMenu(CRect(100, 60, 180, 85), kTagSetOscillatorQuality, "", kCenterText, 12); -oscillatorQualitySlider_ = view__72; -view__68->addView(view__72); -auto* const view__73 = createTitleGroup(CRect(35, 160, 140, 260), -1, "Appearance", kCenterText, 12); -view__48->addView(view__73); -auto* const view__74 = createOptionMenu(CRect(20, 60, 85, 85), kTagThemeMenu, "", kCenterText, 12); -themeMenu_ = view__74; -view__73->addView(view__74); -auto* const view__75 = createValueLabel(CRect(10, 25, 90, 50), -1, "Theme", kCenterText, 12); -view__73->addView(view__75); -auto* const view__76 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); -piano_ = view__76; -view__0->addView(view__76); -auto* const view__77 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); -subPanels_[kPanelGeneral] = view__77; -view__0->addView(view__77); -view__77->setVisible(false); +auto* const view__54 = createValueMenu(CRect(430, 35, 510, 60), kTagSetSampleQuality, "", kCenterText, 12); +sampleQualitySlider_ = view__54; +view__49->addView(view__54); +auto* const view__55 = createLabel(CRect(285, 35, 335, 60), -1, "Sample", kLeftText, 12); +view__49->addView(view__55); +auto* const view__56 = createLabel(CRect(285, 60, 345, 85), -1, "Oscillator", kLeftText, 12); +view__49->addView(view__56); +auto* const view__57 = createValueMenu(CRect(430, 60, 510, 85), kTagSetOscillatorQuality, "", kCenterText, 12); +oscillatorQualitySlider_ = view__57; +view__49->addView(view__57); +auto* const view__58 = createOptionMenu(CRect(675, 35, 775, 60), kTagThemeMenu, "", kCenterText, 12); +themeMenu_ = view__58; +view__49->addView(view__58); +auto* const view__59 = createLabel(CRect(550, 35, 595, 60), -1, "Theme", kLeftText, 12); +view__49->addView(view__59); +auto* const view__60 = createLabel(CRect(550, 60, 645, 85), -1, "User SFZ folder", kLeftText, 12); +view__49->addView(view__60); +auto* const view__61 = createValueButton(CRect(675, 60, 775, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); +userFilesDirButton_ = view__61; +view__49->addView(view__61); +auto* const view__62 = createLabel(CRect(285, 175, 345, 200), -1, "Root key", kLeftText, 12); +view__49->addView(view__62); +auto* const view__63 = createLabel(CRect(285, 200, 355, 225), -1, "Frequency", kLeftText, 12); +view__49->addView(view__63); +auto* const view__64 = createStyledKnob(CRect(450, 227, 498, 275), kTagSetStretchedTuning, "", kCenterText, 14); +stretchedTuningSlider_ = view__64; +view__49->addView(view__64); +auto* const view__65 = createLabel(CRect(285, 235, 335, 260), -1, "Stretch", kLeftText, 12); +view__49->addView(view__65); +auto* const view__66 = createLabel(CRect(285, 150, 345, 175), -1, "Scala file", kLeftText, 12); +view__49->addView(view__66); +auto* const view__67 = createValueButton(CRect(385, 150, 485, 175), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); +scalaFileButton_ = view__67; +view__49->addView(view__67); +auto* const view__68 = createValueMenu(CRect(445, 175, 480, 200), kTagSetScalaRootKey, "", kCenterText, 12); +scalaRootKeySlider_ = view__68; +view__49->addView(view__68); +auto* const view__69 = createValueMenu(CRect(480, 175, 510, 200), kTagSetScalaRootKey, "", kCenterText, 12); +scalaRootOctaveSlider_ = view__69; +view__49->addView(view__69); +auto* const view__70 = createResetSomethingButton(CRect(485, 150, 510, 175), kTagResetScalaFile, "", kCenterText, 12); +scalaResetButton_ = view__70; +view__49->addView(view__70); +auto* const view__71 = createLabel(CRect(285, 85, 370, 110), -1, "Freewheeling", kLeftText, 12); +view__49->addView(view__71); +auto* const view__72 = createValueMenu(CRect(430, 85, 510, 110), kTagSetOscillatorQuality, "", kCenterText, 12); +freewheelingQualitySlider_ = view__72; +view__49->addView(view__72); +auto* const view__73 = createLabel(CRect(15, 100, 160, 125), -1, "Release cancels sustain", kLeftText, 12); +view__49->addView(view__73); +auto* const view__74 = createCheckbox(CRect(200, 100, 225, 125), -1, "", kCenterText, 14); +view__49->addView(view__74); +auto* const view__75 = createLabel(CRect(15, 30, 240, 50), -1, "SFIZZ_VERSION", kCenterText, 10); +sfizzVersionLabel_ = view__75; +view__49->addView(view__75); +auto* const view__76 = createLabel(CRect(285, 5, 395, 30), -1, "Rendering quality", kLeftText, 12); +view__49->addView(view__76); +auto* const view__77 = createHLine(CRect(15, 25, 240, 30), -1, "", kCenterText, 14); +view__49->addView(view__77); +auto* const view__78 = createLabel(CRect(15, 5, 110, 30), -1, "Engine options", kLeftText, 12); +view__49->addView(view__78); +auto* const view__79 = createHLine(CRect(575, 25, 760, 30), -1, "", kCenterText, 14); +view__49->addView(view__79); +auto* const view__80 = createLabel(CRect(550, 5, 590, 30), -1, "Other", kLeftText, 12); +view__49->addView(view__80); +auto* const view__81 = createLabel(CRect(285, 120, 510, 145), -1, "Tuning", kLeftText, 12); +view__49->addView(view__81); +auto* const view__82 = createHLine(CRect(285, 25, 510, 30), -1, "", kCenterText, 14); +view__49->addView(view__82); +auto* const view__83 = createHLine(CRect(550, 25, 775, 30), -1, "", kCenterText, 14); +view__49->addView(view__83); +auto* const view__84 = createHLine(CRect(285, 140, 510, 145), -1, "", kCenterText, 14); +view__49->addView(view__84); +auto* const view__85 = createChevronValueDropDown(CRect(485, 200, 510, 225), kTagSetTuningFrequency, "", kCenterText, 24); +tuningFrequencyDropdown_ = view__85; +view__49->addView(view__85); +auto* const view__86 = createTextEdit(CRect(425, 200, 485, 225), kTagSetTuningFrequency, "", kCenterText, 12); +tuningFrequencyEdit_ = view__86; +view__49->addView(view__86); +auto* const view__87 = createValueButton(CRect(605, 95, 720, 120), kTagAbout, "About sfizz", kCenterText, 12); +settingsAboutButton_ = view__87; +view__49->addView(view__87); +auto* const view__88 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); +piano_ = view__88; +view__0->addView(view__88); +auto* const view__89 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); +subPanels_[kPanelGeneral] = view__89; +view__0->addView(view__89); +view__89->setVisible(false); From aab807a7b542010b32757698586c8c0ef19e448e Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Fri, 12 Nov 2021 11:40:48 +0100 Subject: [PATCH 2/2] Add new config options and bind them to the UI --- plugins/editor/layout/main.fl | 71 +++++++------ plugins/editor/src/editor/EditIds.cpp | 8 +- plugins/editor/src/editor/EditIds.h | 3 + plugins/editor/src/editor/Editor.cpp | 124 ++++++++++++++++------ plugins/editor/src/editor/layout/main.hpp | 70 ++++++------ plugins/lv2/sfizz.cpp | 21 ++++ plugins/lv2/sfizz.ttl.in | 68 +++++++++++- plugins/lv2/sfizz_lv2.h | 6 ++ plugins/lv2/sfizz_lv2_plugin.h | 3 + plugins/lv2/sfizz_ui.cpp | 81 ++++++++++++-- plugins/vst/SfizzVstController.cpp | 15 +++ plugins/vst/SfizzVstEditor.cpp | 19 +++- plugins/vst/SfizzVstParameters.h | 9 ++ plugins/vst/SfizzVstProcessor.cpp | 12 +++ plugins/vst/SfizzVstState.cpp | 20 ++++ plugins/vst/SfizzVstState.h | 5 +- src/sfizz.h | 8 ++ src/sfizz.hpp | 7 ++ src/sfizz/Defaults.cpp | 4 +- src/sfizz/Defaults.h | 4 +- src/sfizz/Synth.cpp | 7 ++ src/sfizz/Synth.h | 6 ++ src/sfizz/SynthMessaging.cpp | 29 +++++ src/sfizz/sfizz.cpp | 5 + src/sfizz/sfizz_wrapper.cpp | 5 + 25 files changed, 496 insertions(+), 114 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index 8457fa5c2..78bf50ce8 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -245,22 +245,22 @@ widget_class mainView {open } { Fl_Spinner oversamplingSlider_ { comment {tag=kTagSetOversampling} - xywh {175 185 70 25} labelsize 12 textsize 12 + xywh {175 195 70 25} labelsize 12 textsize 12 class ValueMenu } Fl_Box {} { label Oversampling - xywh {20 185 85 25} labelsize 12 align 20 + xywh {20 195 85 25} labelsize 12 align 20 class Label } Fl_Box {} { label {Preload size} - xywh {20 160 75 25} labelsize 12 align 20 + xywh {20 170 75 25} labelsize 12 align 20 class Label } Fl_Spinner preloadSizeSlider_ { comment {tag=kTagSetPreloadSize} - xywh {175 160 70 25} labelsize 12 textsize 12 + xywh {175 170 70 25} labelsize 12 textsize 12 class ValueMenu } Fl_Spinner sampleQualitySlider_ { @@ -275,12 +275,12 @@ widget_class mainView {open } Fl_Box {} { label Oscillator - xywh {290 170 60 25} labelsize 12 align 20 + xywh {290 195 60 25} labelsize 12 align 20 class Label } Fl_Spinner oscillatorQualitySlider_ { comment {tag=kTagSetOscillatorQuality} - xywh {435 170 80 25} labelsize 12 textsize 12 + xywh {435 195 80 25} labelsize 12 textsize 12 class ValueMenu } Fl_Spinner themeMenu_ { @@ -306,72 +306,73 @@ widget_class mainView {open } Fl_Box {} { label {Root key} - xywh {290 285 60 25} labelsize 12 align 20 + xywh {555 285 60 25} labelsize 12 align 20 class Label } Fl_Box {} { label Frequency - xywh {290 310 70 25} labelsize 12 align 20 + xywh {555 310 70 25} labelsize 12 align 20 class Label } Fl_Dial stretchedTuningSlider_ { comment {tag=kTagSetStretchedTuning} - xywh {455 337 48 48} value 0.5 + xywh {720 337 48 48} value 0.5 class StyledKnob } Fl_Box {} { label Stretch - xywh {290 345 50 25} labelsize 12 align 20 + xywh {555 345 50 25} labelsize 12 align 20 class Label } Fl_Box {} { label {Scala file} - xywh {290 260 60 25} labelsize 12 align 20 + xywh {555 260 60 25} labelsize 12 align 20 class Label } Fl_Button scalaFileButton_ { label DefaultScale comment {tag=kTagLoadScalaFile} - xywh {390 260 100 25} labelsize 12 + xywh {655 260 100 25} labelsize 12 class ValueButton } Fl_Spinner scalaRootKeySlider_ { comment {tag=kTagSetScalaRootKey} - xywh {450 285 35 25} labelsize 12 textsize 12 + xywh {715 285 35 25} labelsize 12 textsize 12 class ValueMenu } Fl_Spinner scalaRootOctaveSlider_ { comment {tag=kTagSetScalaRootKey} - xywh {485 285 30 25} labelsize 12 textsize 12 + xywh {750 285 30 25} labelsize 12 textsize 12 class ValueMenu } Fl_Button scalaResetButton_ { comment {tag=kTagResetScalaFile} - xywh {490 260 25 25} labelsize 12 + xywh {755 260 25 25} labelsize 12 class ResetSomethingButton } Fl_Box {} { - label Freewheeling - xywh {290 195 85 25} labelsize 12 align 20 + label {... when freewheeling} + xywh {290 170 145 25} labelsize 12 align 20 class Label } - Fl_Spinner freewheelingQualitySlider_ { - comment {tag=kTagSetOscillatorQuality} - xywh {435 195 80 25} labelsize 12 textsize 12 + Fl_Spinner freewheelingSampleQualitySlider_ { + comment {tag=kTagSetFreewheelingSampleQuality} + xywh {435 170 80 25} labelsize 12 textsize 12 class ValueMenu } Fl_Box {} { - label {Release cancels sustain} - xywh {20 210 145 25} labelsize 12 align 20 + label {Sustain cancels release} + xywh {20 220 145 25} labelsize 12 align 20 class Label } - Fl_Check_Button {} { - xywh {205 210 25 25} down_box DOWN_BOX + Fl_Check_Button sustainCancelsReleaseCheckbox_ { + comment {tag=kTagSetSustainCancelsRelease} selected + xywh {200 220 25 25} down_box DOWN_BOX class Checkbox } Fl_Box sfizzVersionLabel_ { label SFIZZ_VERSION - xywh {20 140 225 20} labelsize 10 + xywh {20 145 225 20} labelsize 10 class Label } Fl_Box {} { @@ -401,7 +402,7 @@ widget_class mainView {open } Fl_Box {} { label Tuning - xywh {290 230 225 25} labelsize 12 align 20 + xywh {555 230 225 25} labelsize 12 align 20 class Label } Fl_Box {} { @@ -416,25 +417,35 @@ widget_class mainView {open } Fl_Box {} { label {Separator 2} - xywh {290 250 225 5} box BORDER_BOX labeltype NO_LABEL + xywh {555 250 225 5} box BORDER_BOX labeltype NO_LABEL class HLine } Fl_Button tuningFrequencyDropdown_ { comment {tag=kTagSetTuningFrequency} - xywh {490 310 25 25} labelsize 24 + xywh {755 310 25 25} labelsize 24 class ChevronValueDropDown } Fl_Text_Editor tuningFrequencyEdit_ { comment {tag=kTagSetTuningFrequency} - xywh {430 310 60 25} labelsize 12 + xywh {695 310 60 25} labelsize 12 class TextEdit } Fl_Button settingsAboutButton_ { label {About sfizz} - comment {tag=kTagAbout} selected + comment {tag=kTagAbout} xywh {610 205 115 25} labelsize 12 class ValueButton } + Fl_Box {} { + label {... when freewheeling} + xywh {290 220 145 25} labelsize 12 align 20 + class Label + } + Fl_Spinner freewheelingOscillatorQualitySlider_ { + comment {tag=kTagSetFreewheelingOscillatorQuality} + xywh {435 220 80 25} labelsize 12 textsize 12 + class ValueMenu + } } } Fl_Box piano_ { diff --git a/plugins/editor/src/editor/EditIds.cpp b/plugins/editor/src/editor/EditIds.cpp index a88feb29e..c4de6bbd7 100644 --- a/plugins/editor/src/editor/EditIds.cpp +++ b/plugins/editor/src/editor/EditIds.cpp @@ -27,9 +27,15 @@ EditRange EditRange::get(EditId id) case EditId::StretchTuning: return { 0, 0, 1 }; case EditId::SampleQuality: - return { 1, 0, 10 }; + return { 2, 0, 10 }; case EditId::OscillatorQuality: return { 1, 0, 3 }; + case EditId::FreewheelingSampleQuality: + return { 10, 0, 10 }; + case EditId::FreewheelingOscillatorQuality: + return { 3, 0, 3 }; + case EditId::SustainCancelsRelease: + return { 0, 0, 1 }; case EditId::UIActivePanel: return { 0, 0, 255 }; } diff --git a/plugins/editor/src/editor/EditIds.h b/plugins/editor/src/editor/EditIds.h index e2ac0d89a..897c7ee33 100644 --- a/plugins/editor/src/editor/EditIds.h +++ b/plugins/editor/src/editor/EditIds.h @@ -20,6 +20,9 @@ enum class EditId : int { StretchTuning, SampleQuality, OscillatorQuality, + FreewheelingSampleQuality, + FreewheelingOscillatorQuality, + SustainCancelsRelease, CanEditUserFilesDir, UserFilesDir, FallbackFilesDir, diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 8b062aac0..fc5e0357e 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -98,8 +98,9 @@ struct Editor::Impl : EditorController::Receiver, kTagSetStretchedTuning, kTagSetSampleQuality, kTagSetOscillatorQuality, - kTagSetFreewheelingQuality, - kTagSetReleaseCancelsSustain, + kTagSetFreewheelingSampleQuality, + kTagSetFreewheelingOscillatorQuality, + kTagSetSustainCancelsRelease, kTagSetCCVolume, kTagSetCCPan, kTagChooseUserFilesDir, @@ -132,7 +133,9 @@ struct Editor::Impl : EditorController::Receiver, CTextLabel* stretchedTuningLabel_ = nullptr; SValueMenu *sampleQualitySlider_ = nullptr; SValueMenu *oscillatorQualitySlider_ = nullptr; - SValueMenu *freewheelingQualitySlider_ = nullptr; + SValueMenu *freewheelingSampleQualitySlider_ = nullptr; + SValueMenu *freewheelingOscillatorQualitySlider_ = nullptr; + CCheckBox *sustainCancelsReleaseCheckbox_ = nullptr; CTextLabel* keyswitchLabel_ = nullptr; CTextLabel* keyswitchInactiveLabel_ = nullptr; CTextLabel* keyswitchBadge_ = nullptr; @@ -448,6 +451,33 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) } } break; + case EditId::FreewheelingSampleQuality: + { + const int value = static_cast(v.to_float()); + if (CControl* slider = freewheelingSampleQualitySlider_) { + slider->setValue(float(value)); + slider->invalid(); + } + } + break; + case EditId::FreewheelingOscillatorQuality: + { + const int value = static_cast(v.to_float()); + if (CControl* slider = freewheelingOscillatorQualitySlider_) { + slider->setValue(float(value)); + slider->invalid(); + } + } + break; + case EditId::SustainCancelsRelease: + { + const bool value = v.to_float(); + if (CControl* checkbox = sustainCancelsReleaseCheckbox_) { + checkbox->setValue(value); + checkbox->invalid(); + } + } + break; case EditId::CanEditUserFilesDir: { if (STitleContainer* group = userFilesGroup_) @@ -1095,6 +1125,9 @@ void Editor::Impl::createFrameContents() adjustMinMaxToEditRange(stretchedTuningSlider_, EditId::StretchTuning); adjustMinMaxToEditRange(sampleQualitySlider_, EditId::SampleQuality); adjustMinMaxToEditRange(oscillatorQualitySlider_, EditId::OscillatorQuality); + adjustMinMaxToEditRange(freewheelingSampleQualitySlider_, EditId::FreewheelingSampleQuality); + adjustMinMaxToEditRange(freewheelingOscillatorQualitySlider_, EditId::FreewheelingOscillatorQuality); + adjustMinMaxToEditRange(sustainCancelsReleaseCheckbox_, EditId::SustainCancelsRelease); for (int value : {1, 2, 4, 8, 16, 32, 64, 96, 128, 160, 192, 224, 256}) numVoicesSlider_->addEntry(std::to_string(value), value); @@ -1186,36 +1219,49 @@ void Editor::Impl::createFrameContents() menu->addEntry("Open SFZ folder", kTagOpenSfzFolder); } - if (SValueMenu *menu = sampleQualitySlider_) { - static const std::array labels {{ - "Nearest", "Linear", "Polynomial", - "Sinc 8", "Sinc 12", "Sinc 16", "Sinc 24", - "Sinc 36", "Sinc 48", "Sinc 60", "Sinc 72", - }}; - for (size_t i = 0; i < labels.size(); ++i) - menu->addEntry(labels[i], float(i)); - menu->setValueToStringFunction2([](float value, std::string& result, CParamDisplay*) -> bool { - int index = int(value); - if (index < 0 || unsigned(index) >= labels.size()) - return false; - result = labels[unsigned(index)]; - return true; - }); - } - if (SValueMenu *menu = oscillatorQualitySlider_) { - static const std::array labels {{ - "Nearest", "Linear", "High", "Dual-High", - }}; - for (size_t i = 0; i < labels.size(); ++i) - menu->addEntry(labels[i], float(i)); - menu->setValueToStringFunction2([](float value, std::string& result, CParamDisplay*) -> bool { - int index = int(value); - if (index < 0 || unsigned(index) >= labels.size()) - return false; - result = labels[unsigned(index)]; - return true; - }); - } + static const std::array sampleQualityLabels {{ + "Nearest", "Linear", "Polynomial", + "Sinc 8", "Sinc 12", "Sinc 16", "Sinc 24", + "Sinc 36", "Sinc 48", "Sinc 60", "Sinc 72", + }}; + + auto setupSampleQualityMenu = [&] (SValueMenu* menu) { + if (menu) { + for (size_t i = 0; i < sampleQualityLabels.size(); ++i) + menu->addEntry(sampleQualityLabels[i], float(i)); + menu->setValueToStringFunction2([](float value, std::string& result, CParamDisplay*) -> bool { + int index = int(value); + if (index < 0 || unsigned(index) >= sampleQualityLabels.size()) + return false; + result = sampleQualityLabels[unsigned(index)]; + return true; + }); + } + }; + + setupSampleQualityMenu(sampleQualitySlider_); + setupSampleQualityMenu(freewheelingSampleQualitySlider_); + + static const std::array oscillatorQualityLabels {{ + "Nearest", "Linear", "High", "Dual-High", + }}; + + auto setupOscillatorQualityMenu = [&] (SValueMenu* menu) { + if (menu) { + for (size_t i = 0; i < oscillatorQualityLabels.size(); ++i) + menu->addEntry(oscillatorQualityLabels[i], float(i)); + menu->setValueToStringFunction2([](float value, std::string& result, CParamDisplay*) -> bool { + int index = int(value); + if (index < 0 || unsigned(index) >= oscillatorQualityLabels.size()) + return false; + result = oscillatorQualityLabels[unsigned(index)]; + return true; + }); + } + }; + + setupOscillatorQualityMenu(oscillatorQualitySlider_); + setupOscillatorQualityMenu(freewheelingOscillatorQualitySlider_); if (SPiano* piano = piano_) { piano->onKeyPressed = [this](unsigned key, float vel) { @@ -2002,6 +2048,18 @@ void Editor::Impl::valueChanged(CControl* ctl) ctrl.uiSendValue(EditId::OscillatorQuality, value); break; + case kTagSetFreewheelingSampleQuality: + ctrl.uiSendValue(EditId::FreewheelingSampleQuality, value); + break; + + case kTagSetFreewheelingOscillatorQuality: + ctrl.uiSendValue(EditId::FreewheelingOscillatorQuality, value); + break; + + case kTagSetSustainCancelsRelease: + ctrl.uiSendValue(EditId::SustainCancelsRelease, value); + break; + case kTagSetStretchedTuning: ctrl.uiSendValue(EditId::StretchTuning, value); updateStretchedTuningLabel(value); diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index f732efc52..546601660 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -133,14 +133,14 @@ subPanels_[kPanelSettings] = view__48; view__0->addView(view__48); auto* const view__49 = createRoundedGroup(CRect(5, 0, 795, 285), -1, "", kCenterText, 14); view__48->addView(view__49); -auto* const view__50 = createValueMenu(CRect(170, 75, 240, 100), kTagSetOversampling, "", kCenterText, 12); +auto* const view__50 = createValueMenu(CRect(170, 85, 240, 110), kTagSetOversampling, "", kCenterText, 12); oversamplingSlider_ = view__50; view__49->addView(view__50); -auto* const view__51 = createLabel(CRect(15, 75, 100, 100), -1, "Oversampling", kLeftText, 12); +auto* const view__51 = createLabel(CRect(15, 85, 100, 110), -1, "Oversampling", kLeftText, 12); view__49->addView(view__51); -auto* const view__52 = createLabel(CRect(15, 50, 90, 75), -1, "Preload size", kLeftText, 12); +auto* const view__52 = createLabel(CRect(15, 60, 90, 85), -1, "Preload size", kLeftText, 12); view__49->addView(view__52); -auto* const view__53 = createValueMenu(CRect(170, 50, 240, 75), kTagSetPreloadSize, "", kCenterText, 12); +auto* const view__53 = createValueMenu(CRect(170, 60, 240, 85), kTagSetPreloadSize, "", kCenterText, 12); preloadSizeSlider_ = view__53; view__49->addView(view__53); auto* const view__54 = createValueMenu(CRect(430, 35, 510, 60), kTagSetSampleQuality, "", kCenterText, 12); @@ -148,9 +148,9 @@ sampleQualitySlider_ = view__54; view__49->addView(view__54); auto* const view__55 = createLabel(CRect(285, 35, 335, 60), -1, "Sample", kLeftText, 12); view__49->addView(view__55); -auto* const view__56 = createLabel(CRect(285, 60, 345, 85), -1, "Oscillator", kLeftText, 12); +auto* const view__56 = createLabel(CRect(285, 85, 345, 110), -1, "Oscillator", kLeftText, 12); view__49->addView(view__56); -auto* const view__57 = createValueMenu(CRect(430, 60, 510, 85), kTagSetOscillatorQuality, "", kCenterText, 12); +auto* const view__57 = createValueMenu(CRect(430, 85, 510, 110), kTagSetOscillatorQuality, "", kCenterText, 12); oscillatorQualitySlider_ = view__57; view__49->addView(view__57); auto* const view__58 = createOptionMenu(CRect(675, 35, 775, 60), kTagThemeMenu, "", kCenterText, 12); @@ -163,39 +163,40 @@ view__49->addView(view__60); auto* const view__61 = createValueButton(CRect(675, 60, 775, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); userFilesDirButton_ = view__61; view__49->addView(view__61); -auto* const view__62 = createLabel(CRect(285, 175, 345, 200), -1, "Root key", kLeftText, 12); +auto* const view__62 = createLabel(CRect(550, 175, 610, 200), -1, "Root key", kLeftText, 12); view__49->addView(view__62); -auto* const view__63 = createLabel(CRect(285, 200, 355, 225), -1, "Frequency", kLeftText, 12); +auto* const view__63 = createLabel(CRect(550, 200, 620, 225), -1, "Frequency", kLeftText, 12); view__49->addView(view__63); -auto* const view__64 = createStyledKnob(CRect(450, 227, 498, 275), kTagSetStretchedTuning, "", kCenterText, 14); +auto* const view__64 = createStyledKnob(CRect(715, 227, 763, 275), kTagSetStretchedTuning, "", kCenterText, 14); stretchedTuningSlider_ = view__64; view__49->addView(view__64); -auto* const view__65 = createLabel(CRect(285, 235, 335, 260), -1, "Stretch", kLeftText, 12); +auto* const view__65 = createLabel(CRect(550, 235, 600, 260), -1, "Stretch", kLeftText, 12); view__49->addView(view__65); -auto* const view__66 = createLabel(CRect(285, 150, 345, 175), -1, "Scala file", kLeftText, 12); +auto* const view__66 = createLabel(CRect(550, 150, 610, 175), -1, "Scala file", kLeftText, 12); view__49->addView(view__66); -auto* const view__67 = createValueButton(CRect(385, 150, 485, 175), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); +auto* const view__67 = createValueButton(CRect(650, 150, 750, 175), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); scalaFileButton_ = view__67; view__49->addView(view__67); -auto* const view__68 = createValueMenu(CRect(445, 175, 480, 200), kTagSetScalaRootKey, "", kCenterText, 12); +auto* const view__68 = createValueMenu(CRect(710, 175, 745, 200), kTagSetScalaRootKey, "", kCenterText, 12); scalaRootKeySlider_ = view__68; view__49->addView(view__68); -auto* const view__69 = createValueMenu(CRect(480, 175, 510, 200), kTagSetScalaRootKey, "", kCenterText, 12); +auto* const view__69 = createValueMenu(CRect(745, 175, 775, 200), kTagSetScalaRootKey, "", kCenterText, 12); scalaRootOctaveSlider_ = view__69; view__49->addView(view__69); -auto* const view__70 = createResetSomethingButton(CRect(485, 150, 510, 175), kTagResetScalaFile, "", kCenterText, 12); +auto* const view__70 = createResetSomethingButton(CRect(750, 150, 775, 175), kTagResetScalaFile, "", kCenterText, 12); scalaResetButton_ = view__70; view__49->addView(view__70); -auto* const view__71 = createLabel(CRect(285, 85, 370, 110), -1, "Freewheeling", kLeftText, 12); +auto* const view__71 = createLabel(CRect(285, 60, 430, 85), -1, "... when freewheeling", kLeftText, 12); view__49->addView(view__71); -auto* const view__72 = createValueMenu(CRect(430, 85, 510, 110), kTagSetOscillatorQuality, "", kCenterText, 12); -freewheelingQualitySlider_ = view__72; +auto* const view__72 = createValueMenu(CRect(430, 60, 510, 85), kTagSetFreewheelingSampleQuality, "", kCenterText, 12); +freewheelingSampleQualitySlider_ = view__72; view__49->addView(view__72); -auto* const view__73 = createLabel(CRect(15, 100, 160, 125), -1, "Release cancels sustain", kLeftText, 12); +auto* const view__73 = createLabel(CRect(15, 110, 160, 135), -1, "Sustain cancels release", kLeftText, 12); view__49->addView(view__73); -auto* const view__74 = createCheckbox(CRect(200, 100, 225, 125), -1, "", kCenterText, 14); +auto* const view__74 = createCheckbox(CRect(195, 110, 220, 135), kTagSetSustainCancelsRelease, "", kCenterText, 14); +sustainCancelsReleaseCheckbox_ = view__74; view__49->addView(view__74); -auto* const view__75 = createLabel(CRect(15, 30, 240, 50), -1, "SFIZZ_VERSION", kCenterText, 10); +auto* const view__75 = createLabel(CRect(15, 35, 240, 55), -1, "SFIZZ_VERSION", kCenterText, 10); sfizzVersionLabel_ = view__75; view__49->addView(view__75); auto* const view__76 = createLabel(CRect(285, 5, 395, 30), -1, "Rendering quality", kLeftText, 12); @@ -208,27 +209,32 @@ auto* const view__79 = createHLine(CRect(575, 25, 760, 30), -1, "", kCenterText, view__49->addView(view__79); auto* const view__80 = createLabel(CRect(550, 5, 590, 30), -1, "Other", kLeftText, 12); view__49->addView(view__80); -auto* const view__81 = createLabel(CRect(285, 120, 510, 145), -1, "Tuning", kLeftText, 12); +auto* const view__81 = createLabel(CRect(550, 120, 775, 145), -1, "Tuning", kLeftText, 12); view__49->addView(view__81); auto* const view__82 = createHLine(CRect(285, 25, 510, 30), -1, "", kCenterText, 14); view__49->addView(view__82); auto* const view__83 = createHLine(CRect(550, 25, 775, 30), -1, "", kCenterText, 14); view__49->addView(view__83); -auto* const view__84 = createHLine(CRect(285, 140, 510, 145), -1, "", kCenterText, 14); +auto* const view__84 = createHLine(CRect(550, 140, 775, 145), -1, "", kCenterText, 14); view__49->addView(view__84); -auto* const view__85 = createChevronValueDropDown(CRect(485, 200, 510, 225), kTagSetTuningFrequency, "", kCenterText, 24); +auto* const view__85 = createChevronValueDropDown(CRect(750, 200, 775, 225), kTagSetTuningFrequency, "", kCenterText, 24); tuningFrequencyDropdown_ = view__85; view__49->addView(view__85); -auto* const view__86 = createTextEdit(CRect(425, 200, 485, 225), kTagSetTuningFrequency, "", kCenterText, 12); +auto* const view__86 = createTextEdit(CRect(690, 200, 750, 225), kTagSetTuningFrequency, "", kCenterText, 12); tuningFrequencyEdit_ = view__86; view__49->addView(view__86); auto* const view__87 = createValueButton(CRect(605, 95, 720, 120), kTagAbout, "About sfizz", kCenterText, 12); settingsAboutButton_ = view__87; view__49->addView(view__87); -auto* const view__88 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); -piano_ = view__88; -view__0->addView(view__88); -auto* const view__89 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); -subPanels_[kPanelGeneral] = view__89; -view__0->addView(view__89); -view__89->setVisible(false); +auto* const view__88 = createLabel(CRect(285, 110, 430, 135), -1, "... when freewheeling", kLeftText, 12); +view__49->addView(view__88); +auto* const view__89 = createValueMenu(CRect(430, 110, 510, 135), kTagSetFreewheelingOscillatorQuality, "", kCenterText, 12); +freewheelingOscillatorQualitySlider_ = view__89; +view__49->addView(view__89); +auto* const view__90 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); +piano_ = view__90; +view__0->addView(view__90); +auto* const view__91 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); +subPanels_[kPanelGeneral] = view__91; +view__0->addView(view__91); +view__91->setVisible(false); diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index a4f097e5b..03321b922 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -259,6 +259,15 @@ connect_port_stereo(LV2_Handle instance, case SFIZZ_NUM_SAMPLES: self->num_samples_port = (float *)data; break; + case SFIZZ_FREEWHEELING_SAMPLE_QUALITY: + self->freewheeling_sample_quality_port = (const float *)data; + break; + case SFIZZ_FREEWHEELING_OSCILLATOR_QUALITY: + self->freewheeling_oscillator_quality_port = (const float *)data; + break; + case SFIZZ_SUSTAIN_CANCELS_RELEASE: + self->sustain_cancels_release_port = (const float *)data; + break; default: break; } @@ -374,6 +383,15 @@ connect_port_multi(LV2_Handle instance, case SFIZZ_MULTI_NUM_SAMPLES: self->num_samples_port = (float *)data; break; + case SFIZZ_MULTI_FREEWHEELING_SAMPLE_QUALITY: + self->freewheeling_sample_quality_port = (const float *)data; + break; + case SFIZZ_MULTI_FREEWHEELING_OSCILLATOR_QUALITY: + self->freewheeling_oscillator_quality_port = (const float *)data; + break; + case SFIZZ_MULTI_SUSTAIN_CANCELS_RELEASE: + self->sustain_cancels_release_port = (const float *)data; + break; default: break; } @@ -1177,6 +1195,9 @@ run(LV2_Handle instance, uint32_t sample_count) sfizz_set_tuning_frequency(self->synth, *(self->tuning_frequency_port)); sfizz_set_sample_quality(self->synth, SFIZZ_PROCESS_LIVE, (int)(*self->sample_quality_port)); sfizz_set_oscillator_quality(self->synth, SFIZZ_PROCESS_LIVE, (int)(*self->oscillator_quality_port)); + sfizz_set_sample_quality(self->synth, SFIZZ_PROCESS_FREEWHEELING, (int)(*self->freewheeling_sample_quality_port)); + sfizz_set_oscillator_quality(self->synth, SFIZZ_PROCESS_FREEWHEELING, (int)(*self->freewheeling_oscillator_quality_port)); + sfizz_set_sustain_cancels_release(self->synth, (*self->sustain_cancels_release_port > 0.0f)); sfizz_lv2_check_stretch_tuning(self); sfizz_lv2_check_preload_size(self); sfizz_lv2_check_oversampling(self); diff --git a/plugins/lv2/sfizz.ttl.in b/plugins/lv2/sfizz.ttl.in index e8eae3a8e..5d7a8f66d 100644 --- a/plugins/lv2/sfizz.ttl.in +++ b/plugins/lv2/sfizz.ttl.in @@ -325,7 +325,7 @@ midnam:update a lv2:Feature . lv2:name "Sample quality", "Qualité des échantillons"@fr , "Qualità del campione"@it ; - pg:group <@LV2PLUGIN_URI@#tuning> ; + pg:group <@LV2PLUGIN_URI@#config> ; lv2:default 2.0 ; lv2:minimum 0.0 ; lv2:maximum 10.0 @@ -336,7 +336,7 @@ midnam:update a lv2:Feature . lv2:name "Oscillator quality", "Qualité des oscillateurs"@fr , "Qualità dell'oscillatore"@it ; - pg:group <@LV2PLUGIN_URI@#tuning> ; + pg:group <@LV2PLUGIN_URI@#config> ; lv2:default 1.0 ; lv2:minimum 0.0 ; lv2:maximum 3.0 @@ -406,6 +406,36 @@ midnam:update a lv2:Feature . lv2:default 0 ; lv2:minimum 0 ; lv2:maximum 65535 ; + ] , [ + a lv2:InputPort, lv2:ControlPort ; + lv2:index 20 ; + lv2:symbol "freewheeling_sample_quality" ; + lv2:name "Freewheeling Sample quality", + "Qualité des échantillons en roue libre"@fr; + pg:group <@LV2PLUGIN_URI@#config> ; + lv2:default 10.0 ; + lv2:minimum 0.0 ; + lv2:maximum 10.0 + ] , [ + a lv2:InputPort, lv2:ControlPort ; + lv2:index 21 ; + lv2:symbol "freewheeling_oscillator_quality" ; + lv2:name "Freewheeling Oscillator quality", + "Qualité des oscillateurs en roue libre"@fr ; + pg:group <@LV2PLUGIN_URI@#config> ; + lv2:default 3.0 ; + lv2:minimum 0.0 ; + lv2:maximum 3.0 + ] , [ + a lv2:InputPort, lv2:ControlPort ; + lv2:index 22 ; + lv2:symbol "sustain_cancels_release" ; + lv2:name "Sustain cancels release"; + pg:group <@LV2PLUGIN_URI@#config> ; + lv2:portProperty lv2:toggled ; + lv2:default 0 ; + lv2:minimum 0 ; + lv2:maximum 1 ; ] ; rdfs:seeAlso . @@ -764,7 +794,7 @@ midnam:update a lv2:Feature . lv2:name "Sample quality", "Qualité des échantillons"@fr , "Qualità del campione"@it ; - pg:group <@LV2PLUGIN_URI@#tuning> ; + pg:group <@LV2PLUGIN_URI@#config> ; lv2:default 2.0 ; lv2:minimum 0.0 ; lv2:maximum 10.0 @@ -775,7 +805,7 @@ midnam:update a lv2:Feature . lv2:name "Oscillator quality", "Qualité des oscillateurs"@fr , "Qualità dell'oscillatore"@it ; - pg:group <@LV2PLUGIN_URI@#tuning> ; + pg:group <@LV2PLUGIN_URI@#config> ; lv2:default 1.0 ; lv2:minimum 0.0 ; lv2:maximum 3.0 @@ -845,6 +875,36 @@ midnam:update a lv2:Feature . lv2:default 0 ; lv2:minimum 0 ; lv2:maximum 65535 ; + ] , [ + a lv2:InputPort, lv2:ControlPort ; + lv2:index 34 ; + lv2:symbol "freewheeling_sample_quality" ; + lv2:name "Freewheeling Sample quality", + "Qualité des échantillons en roue libre"@fr; + pg:group <@LV2PLUGIN_URI@#config> ; + lv2:default 10.0 ; + lv2:minimum 0.0 ; + lv2:maximum 10.0 + ] , [ + a lv2:InputPort, lv2:ControlPort ; + lv2:index 35 ; + lv2:symbol "freewheeling_oscillator_quality" ; + lv2:name "Freewheeling Oscillator quality", + "Qualité des oscillateurs en roue libre"@fr ; + pg:group <@LV2PLUGIN_URI@#config> ; + lv2:default 3.0 ; + lv2:minimum 0.0 ; + lv2:maximum 3.0 + ] , [ + a lv2:InputPort, lv2:ControlPort ; + lv2:index 36 ; + lv2:symbol "sustain_cancels_release" ; + lv2:name "Sustain cancels release"; + pg:group <@LV2PLUGIN_URI@#config> ; + lv2:portProperty lv2:toggled ; + lv2:default 0 ; + lv2:minimum 0 ; + lv2:maximum 1 ; ] ; rdfs:seeAlso . diff --git a/plugins/lv2/sfizz_lv2.h b/plugins/lv2/sfizz_lv2.h index c99f8bbb0..69867119f 100644 --- a/plugins/lv2/sfizz_lv2.h +++ b/plugins/lv2/sfizz_lv2.h @@ -73,6 +73,9 @@ enum SFIZZ_NUM_GROUPS = 17, SFIZZ_NUM_REGIONS = 18, SFIZZ_NUM_SAMPLES = 19, + SFIZZ_FREEWHEELING_SAMPLE_QUALITY = 20, + SFIZZ_FREEWHEELING_OSCILLATOR_QUALITY = 21, + SFIZZ_SUSTAIN_CANCELS_RELEASE = 22, }; enum @@ -111,6 +114,9 @@ enum SFIZZ_MULTI_NUM_GROUPS = 31, SFIZZ_MULTI_NUM_REGIONS = 32, SFIZZ_MULTI_NUM_SAMPLES = 33, + SFIZZ_MULTI_FREEWHEELING_SAMPLE_QUALITY = 34, + SFIZZ_MULTI_FREEWHEELING_OSCILLATOR_QUALITY = 35, + SFIZZ_MULTI_SUSTAIN_CANCELS_RELEASE = 36, }; // For use with instance-access diff --git a/plugins/lv2/sfizz_lv2_plugin.h b/plugins/lv2/sfizz_lv2_plugin.h index e7a41c19b..26119138a 100644 --- a/plugins/lv2/sfizz_lv2_plugin.h +++ b/plugins/lv2/sfizz_lv2_plugin.h @@ -47,6 +47,9 @@ struct sfizz_plugin_t const float *stretch_tuning_port {}; const float *sample_quality_port {}; const float *oscillator_quality_port {}; + const float *freewheeling_sample_quality_port {}; + const float *freewheeling_oscillator_quality_port {}; + const float *sustain_cancels_release_port {}; float *active_voices_port {}; float *num_curves_port {}; float *num_masters_port {}; diff --git a/plugins/lv2/sfizz_ui.cpp b/plugins/lv2/sfizz_ui.cpp index af98100e8..cd25d2881 100644 --- a/plugins/lv2/sfizz_ui.cpp +++ b/plugins/lv2/sfizz_ui.cpp @@ -354,6 +354,15 @@ port_event_stereo(sfizz_ui_t *self, uint32_t port_index, const void *buffer) case SFIZZ_NUM_SAMPLES: self->uiReceiveValue(EditId::UINumPreloadedSamples, v); break; + case SFIZZ_FREEWHEELING_SAMPLE_QUALITY: + self->uiReceiveValue(EditId::FreewheelingSampleQuality, v); + break; + case SFIZZ_FREEWHEELING_OSCILLATOR_QUALITY: + self->uiReceiveValue(EditId::FreewheelingOscillatorQuality, v); + break; + case SFIZZ_SUSTAIN_CANCELS_RELEASE: + self->uiReceiveValue(EditId::SustainCancelsRelease, v); + break; } } @@ -408,6 +417,15 @@ port_event_multi(sfizz_ui_t *self, uint32_t port_index, const void *buffer) case SFIZZ_MULTI_NUM_SAMPLES: self->uiReceiveValue(EditId::UINumPreloadedSamples, v); break; + case SFIZZ_MULTI_FREEWHEELING_SAMPLE_QUALITY: + self->uiReceiveValue(EditId::FreewheelingSampleQuality, v); + break; + case SFIZZ_MULTI_FREEWHEELING_OSCILLATOR_QUALITY: + self->uiReceiveValue(EditId::FreewheelingOscillatorQuality, v); + break; + case SFIZZ_MULTI_SUSTAIN_CANCELS_RELEASE: + self->uiReceiveValue(EditId::SustainCancelsRelease, v); + break; } } @@ -663,31 +681,76 @@ void sfizz_ui_t::uiSendValue(EditId id, const EditValue& v) switch (id) { case EditId::Volume: - sendFloat(SFIZZ_VOLUME, v.to_float()); + if (multi_out) + sendFloat(SFIZZ_MULTI_VOLUME, v.to_float()); + else + sendFloat(SFIZZ_VOLUME, v.to_float()); break; case EditId::Polyphony: - sendFloat(SFIZZ_POLYPHONY, v.to_float()); + if (multi_out) + sendFloat(SFIZZ_MULTI_POLYPHONY, v.to_float()); + else + sendFloat(SFIZZ_POLYPHONY, v.to_float()); break; case EditId::Oversampling: - sendFloat(SFIZZ_OVERSAMPLING, v.to_float()); + if (multi_out) + sendFloat(SFIZZ_MULTI_OVERSAMPLING, v.to_float()); + else + sendFloat(SFIZZ_OVERSAMPLING, v.to_float()); break; case EditId::PreloadSize: - sendFloat(SFIZZ_PRELOAD, v.to_float()); + if (multi_out) + sendFloat(SFIZZ_MULTI_PRELOAD, v.to_float()); + else + sendFloat(SFIZZ_PRELOAD, v.to_float()); break; case EditId::ScalaRootKey: - sendFloat(SFIZZ_SCALA_ROOT_KEY, v.to_float()); + if (multi_out) + sendFloat(SFIZZ_MULTI_SCALA_ROOT_KEY, v.to_float()); + else + sendFloat(SFIZZ_SCALA_ROOT_KEY, v.to_float()); break; case EditId::TuningFrequency: - sendFloat(SFIZZ_TUNING_FREQUENCY, v.to_float()); + if (multi_out) + sendFloat(SFIZZ_MULTI_TUNING_FREQUENCY, v.to_float()); + else + sendFloat(SFIZZ_TUNING_FREQUENCY, v.to_float()); break; case EditId::StretchTuning: - sendFloat(SFIZZ_STRETCH_TUNING, v.to_float()); + if (multi_out) + sendFloat(SFIZZ_MULTI_STRETCH_TUNING, v.to_float()); + else + sendFloat(SFIZZ_STRETCH_TUNING, v.to_float()); break; case EditId::SampleQuality: - sendFloat(SFIZZ_SAMPLE_QUALITY, v.to_float()); + if (multi_out) + sendFloat(SFIZZ_MULTI_SAMPLE_QUALITY, v.to_float()); + else + sendFloat(SFIZZ_SAMPLE_QUALITY, v.to_float()); break; case EditId::OscillatorQuality: - sendFloat(SFIZZ_OSCILLATOR_QUALITY, v.to_float()); + if (multi_out) + sendFloat(SFIZZ_MULTI_OSCILLATOR_QUALITY, v.to_float()); + else + sendFloat(SFIZZ_OSCILLATOR_QUALITY, v.to_float()); + break; + case EditId::FreewheelingSampleQuality: + if (multi_out) + sendFloat(SFIZZ_MULTI_FREEWHEELING_SAMPLE_QUALITY, v.to_float()); + else + sendFloat(SFIZZ_FREEWHEELING_SAMPLE_QUALITY, v.to_float()); + break; + case EditId::FreewheelingOscillatorQuality: + if (multi_out) + sendFloat(SFIZZ_MULTI_FREEWHEELING_OSCILLATOR_QUALITY, v.to_float()); + else + sendFloat(SFIZZ_FREEWHEELING_OSCILLATOR_QUALITY, v.to_float()); + break; + case EditId::SustainCancelsRelease: + if (multi_out) + sendFloat(SFIZZ_MULTI_SUSTAIN_CANCELS_RELEASE, v.to_float()); + else + sendFloat(SFIZZ_SUSTAIN_CANCELS_RELEASE, v.to_float()); break; case EditId::SfzFile: sendPath(sfizz_sfz_file_uri, v.to_string()); diff --git a/plugins/vst/SfizzVstController.cpp b/plugins/vst/SfizzVstController.cpp index 500acf95c..3dab25185 100644 --- a/plugins/vst/SfizzVstController.cpp +++ b/plugins/vst/SfizzVstController.cpp @@ -80,6 +80,18 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) SfizzRange::getForParameter(kPidOscillatorQuality).createParameter( Steinberg::String("Oscillator quality"), pid++, nullptr, 0, Vst::ParameterInfo::kNoFlags, Vst::kRootUnitId)); + parameters.addParameter( + SfizzRange::getForParameter(kPidFreewheelingSampleQuality).createParameter( + Steinberg::String("Freewheeling sample quality"), pid++, nullptr, + 0, Vst::ParameterInfo::kNoFlags, Vst::kRootUnitId)); + parameters.addParameter( + SfizzRange::getForParameter(kPidFreewheelingOscillatorQuality).createParameter( + Steinberg::String("Freewheeling oscillator quality"), pid++, nullptr, + 0, Vst::ParameterInfo::kNoFlags, Vst::kRootUnitId)); + parameters.addParameter( + SfizzRange::getForParameter(kPidSustainCancelsRelease).createParameter( + Steinberg::String("Sustain cancels release"), pid++, nullptr, + 1, Vst::ParameterInfo::kNoFlags, Vst::kRootUnitId)); // MIDI special controllers parameters.addParameter( @@ -267,6 +279,9 @@ tresult PLUGIN_API SfizzVstControllerNoUi::setComponentState(IBStream* stream) setParam(kPidStretchedTuning, s.stretchedTuning); setParam(kPidSampleQuality, s.sampleQuality); setParam(kPidOscillatorQuality, s.oscillatorQuality); + setParam(kPidFreewheelingSampleQuality, s.freewheelingSampleQuality); + setParam(kPidFreewheelingOscillatorQuality, s.freewheelingOscillatorQuality); + setParam(kPidSustainCancelsRelease, s.sustainCancelsRelease); uint32 ccLimit = uint32(std::min(s.controllers.size(), size_t(sfz::config::numCCs))); for (uint32 cc = 0; cc < ccLimit; ++cc) { diff --git a/plugins/vst/SfizzVstEditor.cpp b/plugins/vst/SfizzVstEditor.cpp index ea9cf26c0..758b88fcf 100644 --- a/plugins/vst/SfizzVstEditor.cpp +++ b/plugins/vst/SfizzVstEditor.cpp @@ -343,6 +343,15 @@ void SfizzVstEditor::updateParameter(Vst::Parameter* parameterToUpdate) case kPidOscillatorQuality: uiReceiveValue(EditId::OscillatorQuality, range.denormalize(value)); break; + case kPidFreewheelingSampleQuality: + uiReceiveValue(EditId::FreewheelingSampleQuality, range.denormalize(value)); + break; + case kPidFreewheelingOscillatorQuality: + uiReceiveValue(EditId::FreewheelingOscillatorQuality, range.denormalize(value)); + break; + case kPidSustainCancelsRelease: + uiReceiveValue(EditId::SustainCancelsRelease, range.denormalize(value)); + break; case kPidNumOutputs: uiReceiveValue(EditId::PluginOutputs, (int32)range.denormalize(value)); break; @@ -406,7 +415,15 @@ void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) case EditId::OscillatorQuality: normalizeAndSet(kPidOscillatorQuality, v.to_float()); break; - + case EditId::FreewheelingSampleQuality: + normalizeAndSet(kPidFreewheelingSampleQuality, v.to_float()); + break; + case EditId::FreewheelingOscillatorQuality: + normalizeAndSet(kPidFreewheelingOscillatorQuality, v.to_float()); + break; + case EditId::SustainCancelsRelease: + normalizeAndSet(kPidSustainCancelsRelease, v.to_float()); + break; case EditId::UserFilesDir: SfizzPaths::setSfzConfigDefaultPath(fs::u8path(v.to_string())); break; diff --git a/plugins/vst/SfizzVstParameters.h b/plugins/vst/SfizzVstParameters.h index 6f9c4e9a4..07d3bb4c3 100644 --- a/plugins/vst/SfizzVstParameters.h +++ b/plugins/vst/SfizzVstParameters.h @@ -22,6 +22,9 @@ enum { kPidStretchedTuning, kPidSampleQuality, kPidOscillatorQuality, + kPidFreewheelingSampleQuality, + kPidFreewheelingOscillatorQuality, + kPidSustainCancelsRelease, kPidAftertouch, kPidPitchBend, kPidCC0, @@ -78,6 +81,12 @@ struct SfizzRange { return {2.0, 0.0, 10.0}; case kPidOscillatorQuality: return {1.0, 0.0, 3.0}; + case kPidFreewheelingSampleQuality: + return {10.0, 0.0, 10.0}; + case kPidFreewheelingOscillatorQuality: + return {3.0, 0.0, 3.0}; + case kPidSustainCancelsRelease: + return {0.0, 0.0, 1.0}; case kPidAftertouch: return {0.0, 0.0, 1.0}; case kPidPitchBend: diff --git a/plugins/vst/SfizzVstProcessor.cpp b/plugins/vst/SfizzVstProcessor.cpp index 3457fcac8..7df8689d3 100644 --- a/plugins/vst/SfizzVstProcessor.cpp +++ b/plugins/vst/SfizzVstProcessor.cpp @@ -334,6 +334,9 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) } synth.setSampleQuality(sfz::Sfizz::ProcessLive, _state.sampleQuality); synth.setOscillatorQuality(sfz::Sfizz::ProcessLive, _state.oscillatorQuality); + synth.setSampleQuality(sfz::Sfizz::ProcessFreewheeling, _state.freewheelingSampleQuality); + synth.setOscillatorQuality(sfz::Sfizz::ProcessFreewheeling, _state.freewheelingOscillatorQuality); + synth.setSustainCancelsRelease(_state.sustainCancelsRelease); synth.renderBlock(outputs, numFrames, data.numOutputs); @@ -450,6 +453,15 @@ void SfizzVstProcessor::playOrderedParameter(int32 sampleOffset, Vst::ParamID id case kPidOscillatorQuality: _state.oscillatorQuality = static_cast(range.denormalize(value)); break; + case kPidFreewheelingSampleQuality: + _state.freewheelingSampleQuality = static_cast(range.denormalize(value)); + break; + case kPidFreewheelingOscillatorQuality: + _state.freewheelingOscillatorQuality = static_cast(range.denormalize(value)); + break; + case kPidSustainCancelsRelease: + _state.sustainCancelsRelease = (range.denormalize(value) > 0.0f); + break; case kPidAftertouch: synth.hdChannelAftertouch(sampleOffset, value); break; diff --git a/plugins/vst/SfizzVstState.cpp b/plugins/vst/SfizzVstState.cpp index 160d7abbe..091995915 100644 --- a/plugins/vst/SfizzVstState.cpp +++ b/plugins/vst/SfizzVstState.cpp @@ -73,6 +73,17 @@ tresult SfizzVstState::load(IBStream* state) oscillatorQuality = defaults.oscillatorQuality; } + if (version >= 5) { + if (!s.readInt32(freewheelingSampleQuality)) + return kResultFalse; + + if (!s.readInt32(freewheelingOscillatorQuality)) + return kResultFalse; + + if (!s.readBool(sustainCancelsRelease)) + return kResultFalse; + } + if (version >= 4) { if (!s.readInt32(lastKeyswitch)) return kResultFalse; @@ -143,6 +154,15 @@ tresult SfizzVstState::store(IBStream* state) const if (!s.writeInt32(oscillatorQuality)) return kResultFalse; + if (!s.writeInt32(freewheelingSampleQuality)) + return kResultFalse; + + if (!s.writeInt32(freewheelingOscillatorQuality)) + return kResultFalse; + + if (!s.writeBool(sustainCancelsRelease)) + return kResultFalse; + if (!s.writeInt32(lastKeyswitch)) return kResultFalse; diff --git a/plugins/vst/SfizzVstState.h b/plugins/vst/SfizzVstState.h index 93a7a4ec4..3b43ccfa9 100644 --- a/plugins/vst/SfizzVstState.h +++ b/plugins/vst/SfizzVstState.h @@ -27,10 +27,13 @@ class SfizzVstState { float stretchedTuning = 0.0; int32 sampleQuality = 2; int32 oscillatorQuality = 1; + int32 freewheelingSampleQuality = 10; + int32 freewheelingOscillatorQuality = 3; + bool sustainCancelsRelease = false; int32 lastKeyswitch = -1; std::vector> controllers; - static constexpr uint64 currentStateVersion = 4; + static constexpr uint64 currentStateVersion = 5; tresult load(IBStream* state); tresult store(IBStream* state) const; diff --git a/src/sfizz.h b/src/sfizz.h index a709a6b43..0e55ed93b 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -833,6 +833,14 @@ SFIZZ_EXPORTED_API int sfizz_get_oscillator_quality(sfizz_synth_t* synth, sfizz_ */ SFIZZ_EXPORTED_API void sfizz_set_oscillator_quality(sfizz_synth_t* synth, sfizz_process_mode_t mode, int quality); +/** + * @brief Set whether pressing the sustain pedal cancels the release stage + * + * @param synth The synth. + * @param value +*/ +SFIZZ_EXPORTED_API void sfizz_set_sustain_cancels_release(sfizz_synth_t* synth, bool value); + /** * @brief Set the global instrument volume. * @since 0.2.0 diff --git a/src/sfizz.hpp b/src/sfizz.hpp index 6b42db6fe..4ed458aea 100644 --- a/src/sfizz.hpp +++ b/src/sfizz.hpp @@ -360,6 +360,13 @@ class SFIZZ_EXPORTED_API Sfizz */ void setOscillatorQuality(ProcessMode mode, int quality); + /** + * @brief Set whether pressing the sustain pedal cancels the release stage + * + * @param value + */ + void setSustainCancelsRelease(bool value); + /** * @brief Return the current value for the volume, in dB. * @since 0.2.0 diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index 70bc3d014..319933368 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -40,7 +40,6 @@ FloatSpec oscillatorDetune { 0.0f, {-12000.0f, 12000.0f}, kPermissiveBounds }; FloatSpec oscillatorDetuneMod { 0.0f, {-12000.0f, 12000.0f}, kPermissiveBounds }; FloatSpec oscillatorModDepth { 0.0f, {0.0f, 10000.0f}, kNormalizePercent|kPermissiveBounds }; FloatSpec oscillatorModDepthMod { 0.0f, {0.0f, 10000.0f}, kNormalizePercent|kPermissiveBounds }; -Int32Spec oscillatorQuality { 1, {0, 3}, 0 }; Int64Spec group { 0, {-int32_t_max, uint32_t_max}, 0 }; UInt16Spec output { 0, {0, config::maxChannels / 2 - 1}, kEnforceBounds }; FloatSpec offTime { 6e-3f, {0.0f, 100.0f}, kPermissiveBounds }; @@ -162,6 +161,9 @@ FloatSpec flexEGPointLevel { 0.0f, {-1.0f, 1.0f}, kPermissiveBounds }; FloatSpec flexEGPointLevelMod { 0.0f, {-1.0f, 1.0f}, kPermissiveBounds }; FloatSpec flexEGPointShape { 0.0f, {-100.0f, 100.0f}, kPermissiveBounds }; Int32Spec sampleQuality { 2, {0, 10}, 0 }; +Int32Spec oscillatorQuality { 1, {0, 3}, 0 }; +Int32Spec freewheelingSampleQuality { 10, {0, 10}, 0 }; +Int32Spec freewheelingOscillatorQuality { 3, {0, 3}, 0 }; Int32Spec octaveOffset { 0, {-10, 10}, kPermissiveBounds }; Int32Spec noteOffset { 0, {-127, 127}, kPermissiveBounds }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 9387369e8..0ddcba3e5 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -274,6 +274,8 @@ namespace Default extern const OpcodeSpec flexEGPointLevelMod; extern const OpcodeSpec flexEGPointShape; extern const OpcodeSpec sampleQuality; + extern const OpcodeSpec freewheelingSampleQuality; + extern const OpcodeSpec freewheelingOscillatorQuality; extern const OpcodeSpec octaveOffset; extern const OpcodeSpec noteOffset; extern const OpcodeSpec effect; @@ -335,8 +337,6 @@ namespace Default // Various defaut values // e.g. "additional" or multiple defautl values - constexpr int freewheelingSampleQuality { 10 }; - constexpr int freewheelingOscillatorQuality { 3 }; constexpr float globalVolume { -7.35f }; constexpr float defaultEQFreq [numEQs] { 50.0f, 500.0f, 5000.0f }; } // namespace Default diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 810f0fc25..f5749ff62 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -1810,6 +1810,7 @@ void Synth::setSampleQuality(ProcessMode mode, int quality) synthConfig.liveSampleQuality = quality; break; case ProcessFreewheeling: + // DBG("Set freewheeling quality" << quality); synthConfig.freeWheelingSampleQuality = quality; break; default: @@ -1845,6 +1846,7 @@ void Synth::setOscillatorQuality(ProcessMode mode, int quality) synthConfig.liveOscillatorQuality = quality; break; case ProcessFreewheeling: + // DBG("Set freewheeling oscillator quality" << quality); synthConfig.freeWheelingOscillatorQuality = quality; break; default: @@ -1853,6 +1855,11 @@ void Synth::setOscillatorQuality(ProcessMode mode, int quality) } } +void Synth::setSustainCancelsRelease(bool value) +{ + impl_->resources_.getSynthConfig().sustainCancelsRelease = value; +} + float Synth::getVolume() const noexcept { Impl& impl = *impl_; diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 036500dd1..59e846223 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -334,6 +334,12 @@ class Synth final { * @param quality the quality setting */ void setOscillatorQuality(ProcessMode mode, int quality); + /** + * @brief Set whether pressing the sustain pedal cancels the releases + * + * @param value + */ + void setSustainCancelsRelease(bool value); /** * @brief Get the current value for the volume, in dB. * diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index d57a70fcb..95cbce8dd 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -8,6 +8,7 @@ #include "FilePool.h" #include "Curve.h" #include "MidiState.h" +#include "SynthConfig.h" #include "utility/StringViewHelpers.h" #include #include @@ -1534,6 +1535,34 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co // Setting values // Note: all these must be rt-safe within the parseOpcode method in region + MATCH("/sample_quality", "i") { + impl.resources_.getSynthConfig().liveSampleQuality = + Opcode::transform(Default::sampleQuality, static_cast(args[0].i)); + } break; + + MATCH("/oscillator_quality", "i") { + impl.resources_.getSynthConfig().liveOscillatorQuality = + Opcode::transform(Default::oscillatorQuality, static_cast(args[0].i)); + } break; + + MATCH("/freewheeling_sample_quality", "i") { + impl.resources_.getSynthConfig().freeWheelingSampleQuality = + Opcode::transform(Default::freewheelingSampleQuality, static_cast(args[0].i)); + } break; + + MATCH("/freewheeling_oscillator_quality", "i") { + impl.resources_.getSynthConfig().freeWheelingOscillatorQuality = + Opcode::transform(Default::freewheelingOscillatorQuality, static_cast(args[0].i)); + } break; + + MATCH("/sustain_cancels_release", "T") { + impl.resources_.getSynthConfig().sustainCancelsRelease = true; + } break; + + MATCH("/sustain_cancels_release", "F") { + impl.resources_.getSynthConfig().sustainCancelsRelease = false; + } break; + #define GET_REGION_OR_BREAK(idx) \ if (idx >= impl.layers_.size()) \ break; \ diff --git a/src/sfizz/sfizz.cpp b/src/sfizz/sfizz.cpp index 4c96a69a5..be67cc064 100644 --- a/src/sfizz/sfizz.cpp +++ b/src/sfizz/sfizz.cpp @@ -150,6 +150,11 @@ void sfz::Sfizz::setOscillatorQuality(ProcessMode mode, int quality) synth->synth.setOscillatorQuality(static_cast(mode), quality); } +void sfz::Sfizz::setSustainCancelsRelease(bool value) +{ + synth->synth.setSustainCancelsRelease(value); +} + float sfz::Sfizz::getVolume() const noexcept { return synth->synth.getVolume(); diff --git a/src/sfizz/sfizz_wrapper.cpp b/src/sfizz/sfizz_wrapper.cpp index 0c9a3b350..bfa0983a5 100644 --- a/src/sfizz/sfizz_wrapper.cpp +++ b/src/sfizz/sfizz_wrapper.cpp @@ -236,6 +236,11 @@ void sfizz_set_oscillator_quality(sfizz_synth_t* synth, sfizz_process_mode_t mod return synth->synth.setOscillatorQuality(static_cast(mode), quality); } +void sfizz_set_sustain_cancels_release(sfizz_synth_t* synth, bool value) +{ + return synth->synth.setSustainCancelsRelease(value); +} + void sfizz_set_volume(sfizz_synth_t* synth, float volume) { synth->synth.setVolume(volume);