From 9952d28b97e26e92817d38c59f08b8b86d51185e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 14 Apr 2021 06:36:17 +0200 Subject: [PATCH] Volume meter for plugin editors --- cmake/SfizzConfig.cmake | 5 + plugins/CMakeLists.txt | 3 +- plugins/common/plugin/RMSFollower.h | 73 ++++++ plugins/editor/layout/main.fl | 12 +- plugins/editor/src/editor/EditIds.h | 3 + plugins/editor/src/editor/Editor.cpp | 31 ++- plugins/editor/src/editor/GUIComponents.cpp | 69 ++++++ plugins/editor/src/editor/GUIComponents.h | 35 +++ plugins/editor/src/editor/layout/main.hpp | 232 ++++++++++---------- plugins/lv2/CMakeLists.txt | 6 + plugins/lv2/sfizz.cpp | 43 +++- plugins/lv2/sfizz_lv2.h | 6 + plugins/lv2/sfizz_lv2_common.cpp | 7 + plugins/lv2/sfizz_lv2_plugin.h | 10 + plugins/lv2/sfizz_ui.cpp | 26 +++ plugins/lv2/sfizz_ui.ttl.in | 2 +- plugins/vst/SfizzVstController.cpp | 16 ++ plugins/vst/SfizzVstEditor.cpp | 19 ++ plugins/vst/SfizzVstEditor.h | 5 +- plugins/vst/SfizzVstParameters.h | 9 + plugins/vst/SfizzVstProcessor.cpp | 28 ++- plugins/vst/SfizzVstProcessor.h | 5 + src/CMakeLists.txt | 3 - 23 files changed, 514 insertions(+), 134 deletions(-) create mode 100644 plugins/common/plugin/RMSFollower.h diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 40f248de..1cb4b0e6 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -45,6 +45,11 @@ if(WIN32) add_compile_definitions(_WIN32_WINNT=0x601) endif() +# Define the math constants everywhere +if(WIN32) + add_compile_definitions(_USE_MATH_DEFINES) +endif() + # Set macOS compatibility level if(APPLE) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9") diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index e9c21104..3201b27d 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -1,4 +1,5 @@ add_library(plugins-common STATIC EXCLUDE_FROM_ALL + "common/plugin/RMSFollower.h" "common/plugin/MessageUtils.h" "common/plugin/MessageUtils.cpp" "common/plugin/InstrumentDescription.h" @@ -28,7 +29,7 @@ endif() target_include_directories(plugins-common PUBLIC "common") target_link_libraries(plugins-common PUBLIC sfizz::spin_mutex - PUBLIC sfizz::filesystem absl::strings + PUBLIC sfizz::simde sfizz::filesystem absl::strings PRIVATE sfizz::pugixml PRIVATE sfizz::internal sfizz::sfizz) add_library(sfizz::plugins-common ALIAS plugins-common) diff --git a/plugins/common/plugin/RMSFollower.h b/plugins/common/plugin/RMSFollower.h new file mode 100644 index 00000000..43cc7ac2 --- /dev/null +++ b/plugins/common/plugin/RMSFollower.h @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include +#include + +class RMSFollower { +public: + RMSFollower() + { + updatePole(); + } + + void clear() + { + mem_ = simde_mm_setzero_ps(); + } + + void init(float sampleRate) + { + sampleRate_ = sampleRate; + updatePole(); + clear(); + } + + void setT60(float t60) + { + t60_ = t60; + updatePole(); + } + + void process(const float* leftBlock, const float* rightBlock, size_t numFrames) + { + simde__m128 mem = mem_; + const simde__m128 pole = simde_mm_load1_ps(&pole_); + for (size_t i = 0; i < numFrames; ++i) { + float left = leftBlock[i]; + float right = rightBlock[i]; + simde__m128 input = simde_mm_setr_ps(left, right, 0.0f, 0.0f); + input = simde_mm_mul_ps(input, input); + simde__m128 output = simde_mm_add_ps(input, simde_mm_mul_ps(pole, simde_mm_sub_ps(mem, input))); + mem = output; + } + mem_ = mem; + } + + simde__m128 getMS() const + { + return mem_; + } + + simde__m128 getRMS() const + { + return simde_mm_sqrt_ps(mem_); + } + +private: + void updatePole() + { + pole_ = std::exp(float(-2.0 * M_PI) / (t60_ * sampleRate_)); + } + +private: + simde__m128 mem_ {}; + float pole_ {}; + float t60_ = 300e-3; + float sampleRate_ = 44100; +}; diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index c5ac9708..2ec8a0e4 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -134,10 +134,6 @@ widget_class mainView {open xywh {610 70 60 5} labelsize 12 hide class ValueLabel } - Fl_Box {} { - xywh {745 20 35 55} box BORDER_BOX - class VMeter - } Fl_Box volumeCCKnob_ { label Volume comment {tag=kTagSetCCVolume} @@ -150,6 +146,14 @@ widget_class mainView {open xywh {655 10 70 90} box BORDER_BOX labelsize 12 align 17 class KnobCCBox } + Fl_Box leftMeter_ { + xywh {740 10 15 90} box BORDER_BOX + class VMeter + } + Fl_Box rightMeter_ {selected + xywh {760 10 15 90} box BORDER_BOX + class VMeter + } } } Fl_Group {subPanels_[kPanelGeneral]} { diff --git a/plugins/editor/src/editor/EditIds.h b/plugins/editor/src/editor/EditIds.h index 3f55d31b..c0070ed6 100644 --- a/plugins/editor/src/editor/EditIds.h +++ b/plugins/editor/src/editor/EditIds.h @@ -38,6 +38,9 @@ enum class EditId : int { CC_RANGE(ControllerDefault), CC_RANGE(ControllerLabel), // + LeftLevel, + RightLevel, + // UINumCurves, UINumMasters, UINumGroups, diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 1e5850aa..f98d5854 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -153,6 +153,9 @@ struct Editor::Impl : EditorController::Receiver, SKnobCCBox* volumeCCKnob_ = nullptr; SKnobCCBox* panCCKnob_ = nullptr; + SLevelMeter* leftMeter_ = nullptr; + SLevelMeter* rightMeter_ = nullptr; + SAboutDialog* aboutDialog_ = nullptr; SharedPointer backgroundBitmap_; @@ -504,6 +507,20 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) updateBackgroundImage(value.c_str()); } break; + case EditId::LeftLevel: + { + const float value = v.to_float(); + if (SLevelMeter* meter = leftMeter_) + meter->setValue(value); + } + break; + case EditId::RightLevel: + { + const float value = v.to_float(); + if (SLevelMeter* meter = rightMeter_) + meter->setValue(value); + } + break; default: if (editIdIsKey(id)) { const int key = keyForEditId(id); @@ -703,11 +720,15 @@ void Editor::Impl::createFrameContents() lbl->setFont(font); return lbl; }; - auto createVMeter = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { - // TODO the volume meter... - CViewContainer* container = new CViewContainer(bounds); - container->setBackgroundColor(CColor(0x00, 0x00, 0x00, 0x00)); - return container; + auto createVMeter = [this, &palette](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { + SLevelMeter* meter = new SLevelMeter(bounds); + meter->setNormalFillColor(CColor(0x00, 0xaa, 0x11)); + meter->setDangerFillColor(CColor(0xaa, 0x00, 0x00)); + OnThemeChanged.push_back([meter, palette]() { + meter->setFrameColor(palette->inactiveText); + meter->setBackColor(palette->knobInactiveTrack); + }); + return meter; }; #if 0 auto createButton = [this](const CRect& bounds, int tag, const char* label, CHoriTxtAlign align, int fontsize) { diff --git a/plugins/editor/src/editor/GUIComponents.cpp b/plugins/editor/src/editor/GUIComponents.cpp index a70f70e2..76d7f9a0 100644 --- a/plugins/editor/src/editor/GUIComponents.cpp +++ b/plugins/editor/src/editor/GUIComponents.cpp @@ -979,6 +979,75 @@ void SControlsPanel::ControlSlotListener::controlEndEdit(CControl* pControl) panel_->EndEditFunction(pControl->getTag()); } +/// +SLevelMeter::SLevelMeter(const CRect& size) + : CView(size) +{ +} + +void SLevelMeter::setValue(float value) +{ + if (value_ == value) + return; + + value_ = value; + invalid(); +} + +void SLevelMeter::draw(CDrawContext* dc) +{ + float dbValue = 20.0f * std::log10(value_); + float fill = (dbValue - dbMin_) / (dbMax_ - dbMin_); + fill = (fill < 0.0f) ? 0.0f : fill; + fill = (fill > 1.0f) ? 1.0f : fill; + + CRect largeBounds = getViewSize(); + CRect fillBounds = largeBounds; + fillBounds.top = largeBounds.bottom - fill * largeBounds.getHeight(); + + const CColor safeColor = safeFillColor_; + const CColor dangerColor = dangerFillColor_; + + CColor fillColor; + if (safeColor == dangerColor) { + fillColor = safeColor; + } + else { + float thres = dangerThreshold_; + float mix = (fill - thres) / (1.0f - thres); + mix = (mix < 0.0f) ? 0.0f : mix; + + CCoord safeH, safeS, safeV, safeA; + CCoord dangerH, dangerS, dangerV, dangerA; + safeColor.toHSV(safeH, safeS, safeV); + dangerColor.toHSV(dangerH, dangerS, dangerV); + safeA = safeColor.alpha / 255.0; + dangerA = dangerColor.alpha / 255.0; + + CCoord H, S, V, A; + H = safeH + mix * (dangerH - safeH); + S = safeS + mix * (dangerS - safeS); + V = safeV + mix * (dangerV - safeV); + A = safeA + mix * (dangerA - safeA); + + fillColor.fromHSV(H, S, V); + fillColor.alpha = static_cast(A * 255.0); + } + + dc->setDrawMode(kAliasing); + + if (backColor_.alpha > 0) { + dc->setFillColor(backColor_); + dc->drawRect(largeBounds, kDrawFilled); + } + + dc->setFrameColor(frameColor_); + dc->setFillColor(fillColor); + + dc->drawRect(fillBounds, kDrawFilled); + dc->drawRect(largeBounds); +} + /// SPlaceHolder::SPlaceHolder(const CRect& size, const CColor& color) : CView(size), color_(color) diff --git a/plugins/editor/src/editor/GUIComponents.h b/plugins/editor/src/editor/GUIComponents.h index b3cbc056..99378f2a 100644 --- a/plugins/editor/src/editor/GUIComponents.h +++ b/plugins/editor/src/editor/GUIComponents.h @@ -365,6 +365,41 @@ private: SharedPointer relayoutTrigger_; }; +/// +class SLevelMeter : public CView { +public: + explicit SLevelMeter(const CRect& size); + + float getValue() const { return value_; } + void setValue(float value); + + float getDangerThreshold() const { return dangerThreshold_; } + void setDangerThreshold(float thres) { dangerThreshold_ = thres; invalid(); } + + CColor getFrameColor() const { return frameColor_; } + void setFrameColor(CColor color) { frameColor_ = color; invalid(); } + CColor getBackColor() const { return backColor_; } + void setBackColor(CColor color) { backColor_ = color; invalid(); } + + CColor getNormalFillColor() const { return safeFillColor_; } + void setNormalFillColor(CColor color) { safeFillColor_ = color; invalid(); } + CColor getDangerFillColor() const { return dangerFillColor_; } + void setDangerFillColor(CColor color) { dangerFillColor_ = color; invalid(); } + +protected: + void draw(CDrawContext* dc) override; + +private: + float value_ = 0; + float dangerThreshold_ = 0.5; + float dbMin_ = -40; + float dbMax_ = 0; + CColor frameColor_; + CColor safeFillColor_; + CColor dangerFillColor_; + CColor backColor_; +}; + /// class SPlaceHolder : public CView { public: diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index 7c0ebf31..26536478 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -72,124 +72,128 @@ view__26->setVisible(false); auto* const view__27 = createValueLabel(CRect(40, 65, 100, 70), -1, "Center", kCenterText, 12); view__25->addView(view__27); view__27->setVisible(false); -auto* const view__28 = createVMeter(CRect(175, 15, 210, 70), -1, "", kCenterText, 14); +auto* const view__28 = createKnobCCBox(CRect(10, 5, 80, 95), kTagSetCCVolume, "Volume", kCenterText, 12); +volumeCCKnob_ = view__28; view__25->addView(view__28); -auto* const view__29 = createKnobCCBox(CRect(10, 5, 80, 95), kTagSetCCVolume, "Volume", kCenterText, 12); -volumeCCKnob_ = view__29; +auto* const view__29 = createKnobCCBox(CRect(85, 5, 155, 95), kTagSetCCPan, "Pan", kCenterText, 12); +panCCKnob_ = view__29; view__25->addView(view__29); -auto* const view__30 = createKnobCCBox(CRect(85, 5, 155, 95), kTagSetCCPan, "Pan", kCenterText, 12); -panCCKnob_ = view__30; +auto* const view__30 = createVMeter(CRect(170, 5, 185, 95), -1, "", kCenterText, 14); +leftMeter_ = view__30; view__25->addView(view__30); +auto* const view__31 = createVMeter(CRect(190, 5, 205, 95), -1, "", kCenterText, 14); +rightMeter_ = view__31; +view__25->addView(view__31); enterPalette(defaultPalette); -auto* const view__31 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14); -subPanels_[kPanelGeneral] = view__31; -view__0->addView(view__31); -view__31->setVisible(false); -auto* const view__32 = createRoundedGroup(CRect(0, 0, 175, 280), -1, "", kCenterText, 14); -view__31->addView(view__32); -auto* const view__33 = createLabel(CRect(15, 10, 75, 35), -1, "Curves:", kLeftText, 14); +auto* const view__32 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14); +subPanels_[kPanelGeneral] = view__32; +view__0->addView(view__32); +view__32->setVisible(false); +auto* const view__33 = createRoundedGroup(CRect(0, 0, 175, 280), -1, "", kCenterText, 14); view__32->addView(view__33); -auto* const view__34 = createLabel(CRect(15, 35, 75, 60), -1, "Masters:", kLeftText, 14); -view__32->addView(view__34); -auto* const view__35 = createLabel(CRect(15, 60, 75, 85), -1, "Groups:", kLeftText, 14); -view__32->addView(view__35); -auto* const view__36 = createLabel(CRect(15, 85, 75, 110), -1, "Regions:", kLeftText, 14); -view__32->addView(view__36); -auto* const view__37 = createLabel(CRect(15, 110, 75, 135), -1, "Samples:", kLeftText, 14); -view__32->addView(view__37); -auto* const view__38 = createLabel(CRect(115, 10, 155, 35), -1, "0", kCenterText, 14); -infoCurvesLabel_ = view__38; -view__32->addView(view__38); -auto* const view__39 = createLabel(CRect(115, 35, 155, 60), -1, "0", kCenterText, 14); -infoMastersLabel_ = view__39; -view__32->addView(view__39); -auto* const view__40 = createLabel(CRect(115, 60, 155, 85), -1, "0", kCenterText, 14); -infoGroupsLabel_ = view__40; -view__32->addView(view__40); -auto* const view__41 = createLabel(CRect(115, 85, 155, 110), -1, "0", kCenterText, 14); -infoRegionsLabel_ = view__41; -view__32->addView(view__41); -auto* const view__42 = createLabel(CRect(115, 110, 155, 135), -1, "0", kCenterText, 14); -infoSamplesLabel_ = view__42; -view__32->addView(view__42); -auto* const view__43 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); -subPanels_[kPanelControls] = view__43; -view__0->addView(view__43); -view__43->setVisible(false); -auto* const view__44 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); -view__43->addView(view__44); -auto* const view__45 = createControlsPanel(CRect(0, 0, 790, 285), -1, "", kCenterText, 12); -controlsPanel_ = view__45; +auto* const view__34 = createLabel(CRect(15, 10, 75, 35), -1, "Curves:", kLeftText, 14); +view__33->addView(view__34); +auto* const view__35 = createLabel(CRect(15, 35, 75, 60), -1, "Masters:", kLeftText, 14); +view__33->addView(view__35); +auto* const view__36 = createLabel(CRect(15, 60, 75, 85), -1, "Groups:", kLeftText, 14); +view__33->addView(view__36); +auto* const view__37 = createLabel(CRect(15, 85, 75, 110), -1, "Regions:", kLeftText, 14); +view__33->addView(view__37); +auto* const view__38 = createLabel(CRect(15, 110, 75, 135), -1, "Samples:", kLeftText, 14); +view__33->addView(view__38); +auto* const view__39 = createLabel(CRect(115, 10, 155, 35), -1, "0", kCenterText, 14); +infoCurvesLabel_ = view__39; +view__33->addView(view__39); +auto* const view__40 = createLabel(CRect(115, 35, 155, 60), -1, "0", kCenterText, 14); +infoMastersLabel_ = view__40; +view__33->addView(view__40); +auto* const view__41 = createLabel(CRect(115, 60, 155, 85), -1, "0", kCenterText, 14); +infoGroupsLabel_ = view__41; +view__33->addView(view__41); +auto* const view__42 = createLabel(CRect(115, 85, 155, 110), -1, "0", kCenterText, 14); +infoRegionsLabel_ = view__42; +view__33->addView(view__42); +auto* const view__43 = createLabel(CRect(115, 110, 155, 135), -1, "0", kCenterText, 14); +infoSamplesLabel_ = view__43; +view__33->addView(view__43); +auto* const view__44 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); +subPanels_[kPanelControls] = view__44; +view__0->addView(view__44); +view__44->setVisible(false); +auto* const view__45 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); view__44->addView(view__45); -auto* const view__46 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); -subPanels_[kPanelSettings] = view__46; -view__0->addView(view__46); -auto* const view__47 = createTitleGroup(CRect(300, 26, 495, 126), -1, "Engine", kCenterText, 12); -view__46->addView(view__47); -auto* const view__48 = createValueMenu(CRect(25, 60, 85, 85), kTagSetOversampling, "", kCenterText, 12); -oversamplingSlider_ = view__48; +auto* const view__46 = createControlsPanel(CRect(0, 0, 790, 285), -1, "", kCenterText, 12); +controlsPanel_ = view__46; +view__45->addView(view__46); +auto* const view__47 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); +subPanels_[kPanelSettings] = view__47; +view__0->addView(view__47); +auto* const view__48 = createTitleGroup(CRect(300, 26, 495, 126), -1, "Engine", kCenterText, 12); view__47->addView(view__48); -auto* const view__49 = createValueLabel(CRect(15, 20, 95, 45), -1, "Oversampling", kCenterText, 12); -view__47->addView(view__49); -auto* const view__50 = createValueLabel(CRect(100, 20, 180, 45), -1, "Preload size", kCenterText, 12); -view__47->addView(view__50); -auto* const view__51 = createValueMenu(CRect(110, 60, 170, 85), kTagSetPreloadSize, "", kCenterText, 12); -preloadSizeSlider_ = view__51; -view__47->addView(view__51); -auto* const view__52 = createTitleGroup(CRect(170, 161, 585, 261), -1, "Tuning", kCenterText, 12); -view__46->addView(view__52); -auto* const view__53 = createValueLabel(CRect(155, 20, 235, 45), -1, "Root key", kCenterText, 12); -view__52->addView(view__53); -auto* const view__54 = createValueMenu(CRect(250, 60, 310, 85), kTagSetTuningFrequency, "", kCenterText, 12); -tuningFrequencySlider_ = view__54; -view__52->addView(view__54); -auto* const view__55 = createValueLabel(CRect(240, 20, 320, 45), -1, "Frequency", kCenterText, 12); -view__52->addView(view__55); -auto* const view__56 = createStyledKnob(CRect(340, 45, 388, 93), kTagSetStretchedTuning, "", kCenterText, 14); -stretchedTuningSlider_ = view__56; -view__52->addView(view__56); -auto* const view__57 = createValueLabel(CRect(325, 20, 405, 45), -1, "Stretch", kCenterText, 12); -view__52->addView(view__57); -auto* const view__58 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12); -view__52->addView(view__58); -auto* const view__59 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); -scalaFileButton_ = view__59; -view__52->addView(view__59); -auto* const view__60 = createValueMenu(CRect(165, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); -scalaRootKeySlider_ = view__60; -view__52->addView(view__60); -auto* const view__61 = createValueMenu(CRect(200, 60, 230, 85), kTagSetScalaRootKey, "", kCenterText, 12); -scalaRootOctaveSlider_ = view__61; -view__52->addView(view__61); -auto* const view__62 = createResetSomethingButton(CRect(120, 60, 145, 85), kTagResetScalaFile, "", kCenterText, 12); -scalaResetButton_ = view__62; -view__52->addView(view__62); -auto* const view__63 = createTitleGroup(CRect(615, 161, 754, 261), -1, "Files", kCenterText, 12); -userFilesGroup_ = view__63; -view__46->addView(view__63); -auto* const view__64 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); -view__63->addView(view__64); -auto* const view__65 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); -userFilesDirButton_ = view__65; -view__63->addView(view__65); -auto* const view__66 = createTitleGroup(CRect(525, 26, 720, 126), -1, "Quality", kCenterText, 12); -view__46->addView(view__66); -auto* const view__67 = createValueMenu(CRect(15, 60, 95, 85), kTagSetSampleQuality, "", kCenterText, 12); -sampleQualitySlider_ = view__67; -view__66->addView(view__67); -auto* const view__68 = createValueLabel(CRect(15, 20, 95, 45), -1, "Sample", kCenterText, 12); -view__66->addView(view__68); -auto* const view__69 = createValueLabel(CRect(100, 20, 180, 45), -1, "Oscillator", kCenterText, 12); -view__66->addView(view__69); -auto* const view__70 = createValueMenu(CRect(100, 60, 180, 85), kTagSetOscillatorQuality, "", kCenterText, 12); -oscillatorQualitySlider_ = view__70; -view__66->addView(view__70); -auto* const view__71 = createTitleGroup(CRect(35, 161, 140, 261), -1, "Theme", kCenterText, 12); -view__46->addView(view__71); -view__71->setVisible(false); -auto* const view__72 = createOptionMenu(CRect(20, 60, 85, 85), kTagThemeMenu, "", kCenterText, 12); -themeMenu_ = view__72; -view__71->addView(view__72); -auto* const view__73 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); -piano_ = view__73; -view__0->addView(view__73); +auto* const view__49 = createValueMenu(CRect(25, 60, 85, 85), kTagSetOversampling, "", kCenterText, 12); +oversamplingSlider_ = view__49; +view__48->addView(view__49); +auto* const view__50 = createValueLabel(CRect(15, 20, 95, 45), -1, "Oversampling", kCenterText, 12); +view__48->addView(view__50); +auto* const view__51 = createValueLabel(CRect(100, 20, 180, 45), -1, "Preload size", kCenterText, 12); +view__48->addView(view__51); +auto* const view__52 = createValueMenu(CRect(110, 60, 170, 85), kTagSetPreloadSize, "", kCenterText, 12); +preloadSizeSlider_ = view__52; +view__48->addView(view__52); +auto* const view__53 = createTitleGroup(CRect(170, 161, 585, 261), -1, "Tuning", kCenterText, 12); +view__47->addView(view__53); +auto* const view__54 = createValueLabel(CRect(155, 20, 235, 45), -1, "Root key", kCenterText, 12); +view__53->addView(view__54); +auto* const view__55 = createValueMenu(CRect(250, 60, 310, 85), kTagSetTuningFrequency, "", kCenterText, 12); +tuningFrequencySlider_ = view__55; +view__53->addView(view__55); +auto* const view__56 = createValueLabel(CRect(240, 20, 320, 45), -1, "Frequency", kCenterText, 12); +view__53->addView(view__56); +auto* const view__57 = createStyledKnob(CRect(340, 45, 388, 93), kTagSetStretchedTuning, "", kCenterText, 14); +stretchedTuningSlider_ = view__57; +view__53->addView(view__57); +auto* const view__58 = createValueLabel(CRect(325, 20, 405, 45), -1, "Stretch", kCenterText, 12); +view__53->addView(view__58); +auto* const view__59 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12); +view__53->addView(view__59); +auto* const view__60 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); +scalaFileButton_ = view__60; +view__53->addView(view__60); +auto* const view__61 = createValueMenu(CRect(165, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); +scalaRootKeySlider_ = view__61; +view__53->addView(view__61); +auto* const view__62 = createValueMenu(CRect(200, 60, 230, 85), kTagSetScalaRootKey, "", kCenterText, 12); +scalaRootOctaveSlider_ = view__62; +view__53->addView(view__62); +auto* const view__63 = createResetSomethingButton(CRect(120, 60, 145, 85), kTagResetScalaFile, "", kCenterText, 12); +scalaResetButton_ = view__63; +view__53->addView(view__63); +auto* const view__64 = createTitleGroup(CRect(615, 161, 754, 261), -1, "Files", kCenterText, 12); +userFilesGroup_ = view__64; +view__47->addView(view__64); +auto* const view__65 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); +view__64->addView(view__65); +auto* const view__66 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); +userFilesDirButton_ = view__66; +view__64->addView(view__66); +auto* const view__67 = createTitleGroup(CRect(525, 26, 720, 126), -1, "Quality", kCenterText, 12); +view__47->addView(view__67); +auto* const view__68 = createValueMenu(CRect(15, 60, 95, 85), kTagSetSampleQuality, "", kCenterText, 12); +sampleQualitySlider_ = view__68; +view__67->addView(view__68); +auto* const view__69 = createValueLabel(CRect(15, 20, 95, 45), -1, "Sample", kCenterText, 12); +view__67->addView(view__69); +auto* const view__70 = createValueLabel(CRect(100, 20, 180, 45), -1, "Oscillator", kCenterText, 12); +view__67->addView(view__70); +auto* const view__71 = createValueMenu(CRect(100, 60, 180, 85), kTagSetOscillatorQuality, "", kCenterText, 12); +oscillatorQualitySlider_ = view__71; +view__67->addView(view__71); +auto* const view__72 = createTitleGroup(CRect(35, 161, 140, 261), -1, "Theme", kCenterText, 12); +view__47->addView(view__72); +view__72->setVisible(false); +auto* const view__73 = createOptionMenu(CRect(20, 60, 85, 85), kTagThemeMenu, "", kCenterText, 12); +themeMenu_ = view__73; +view__72->addView(view__73); +auto* const view__74 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); +piano_ = view__74; +view__0->addView(view__74); diff --git a/plugins/lv2/CMakeLists.txt b/plugins/lv2/CMakeLists.txt index 828be738..18305a32 100644 --- a/plugins/lv2/CMakeLists.txt +++ b/plugins/lv2/CMakeLists.txt @@ -61,6 +61,12 @@ if(SFIZZ_LV2_UI) endif() endif() +# Define a preprocessor variable to indicate a build with UI enabled +if(SFIZZ_LV2_UI) + target_compile_definitions(${LV2PLUGIN_PRJ_NAME} PRIVATE "SFIZZ_LV2_UI=1") + target_compile_definitions(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE "SFIZZ_LV2_UI=1") +endif() + # Remove the "lib" prefix, rename the target name and build it in the .lv build dir # /lv2/_lv2. to # /lv2/.lv2/. diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index 6a001e72..0c60824a 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -121,9 +121,9 @@ sfizz_lv2_map_required_uris(sfizz_plugin_t *self) self->sfizz_preload_size_uri = map->map(map->handle, SFIZZ__preloadSize); self->sfizz_oversampling_uri = map->map(map->handle, SFIZZ__oversampling); self->sfizz_log_status_uri = map->map(map->handle, SFIZZ__logStatus); - self->sfizz_log_status_uri = map->map(map->handle, SFIZZ__logStatus); self->sfizz_check_modification_uri = map->map(map->handle, SFIZZ__checkModification); self->sfizz_osc_blob_uri = map->map(map->handle, SFIZZ__OSCBlob); + self->sfizz_audio_level_uri = map->map(map->handle, SFIZZ__AudioLevel); self->time_position_uri = map->map(map->handle, LV2_TIME__Position); self->time_bar_uri = map->map(map->handle, LV2_TIME__bar); self->time_bar_beat_uri = map->map(map->handle, LV2_TIME__barBeat); @@ -532,6 +532,9 @@ activate(LV2_Handle instance) sfizz_set_samples_per_block(self->synth, self->max_block_size); sfizz_set_sample_rate(self->synth, self->sample_rate); self->must_update_midnam.store(1); +#if defined(SFIZZ_LV2_UI) + self->rms_follower.init(self->sample_rate); +#endif } static void @@ -576,6 +579,30 @@ sfizz_lv2_send_controller(sfizz_plugin_t *self, LV2_Atom_Forge* forge, unsigned lv2_atom_forge_pop(forge, &frame); } +#if defined(SFIZZ_LV2_UI) +static void +sfizz_lv2_send_levels(sfizz_plugin_t *self, LV2_Atom_Forge* forge, float left, float right) +{ + const float levels[] = {left, right}; + uint32_t num_levels = sizeof(levels) / sizeof(levels[0]); + + bool write_ok = lv2_atom_forge_frame_time(forge, 0); + + LV2_Atom_Vector *vector = nullptr; + if (write_ok) { + LV2_Atom_Forge_Ref ref = lv2_atom_forge_vector(forge, sizeof(float), self->atom_float_uri, num_levels, levels); + write_ok = ref; + if (write_ok) + vector = (LV2_Atom_Vector *)lv2_atom_forge_deref(forge, ref); + } + + if (write_ok) + vector->atom.type = self->sfizz_audio_level_uri; + + (void)write_ok; +} +#endif + static void sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, int delay, const LV2_Atom_Object *obj) { @@ -1046,6 +1073,20 @@ run(LV2_Handle instance, uint32_t sample_count) spin_mutex_unlock(self->synth_mutex); +#if defined(SFIZZ_LV2_UI) + if (self->ui_active) + { + self->rms_follower.process(self->output_buffers[0], self->output_buffers[1], sample_count); + const simde__m128 rms = self->rms_follower.getRMS(); + const float *levels = (const float *)&rms; + sfizz_lv2_send_levels(self, &self->forge_notify, levels[0], levels[1]); + } + else + { + self->rms_follower.clear(); + } +#endif + lv2_atom_forge_pop(&self->forge_notify, ¬ify_frame); lv2_atom_forge_pop(&self->forge_automate, &automate_frame); } diff --git a/plugins/lv2/sfizz_lv2.h b/plugins/lv2/sfizz_lv2.h index 51a53896..dfc3a116 100644 --- a/plugins/lv2/sfizz_lv2.h +++ b/plugins/lv2/sfizz_lv2.h @@ -44,6 +44,8 @@ #define SFIZZ__checkModification SFIZZ_URI ":" "check_modification" // OSC atoms #define SFIZZ__OSCBlob SFIZZ_URI ":" "OSCBlob" +// Level atoms +#define SFIZZ__AudioLevel SFIZZ_URI ":" "AudioLevel" enum { @@ -89,6 +91,10 @@ bool sfizz_lv2_fetch_description( sfizz_plugin_t *self, const int *serial, uint8_t **descp, uint32_t *sizep, int *serialp); +#if defined(SFIZZ_LV2_UI) +void sfizz_lv2_set_ui_active(sfizz_plugin_t *self, bool ui_active); +#endif + // Mapping URID to CC and vice-versa struct sfizz_lv2_ccmap; sfizz_lv2_ccmap *sfizz_lv2_ccmap_create(LV2_URID_Map* map); diff --git a/plugins/lv2/sfizz_lv2_common.cpp b/plugins/lv2/sfizz_lv2_common.cpp index 7881db1d..30bf4b63 100644 --- a/plugins/lv2/sfizz_lv2_common.cpp +++ b/plugins/lv2/sfizz_lv2_common.cpp @@ -31,6 +31,13 @@ bool sfizz_lv2_fetch_description( return true; } +#if defined(SFIZZ_LV2_UI) +void sfizz_lv2_set_ui_active(sfizz_plugin_t *self, bool ui_active) +{ + self->ui_active = ui_active; +} +#endif + struct sfizz_lv2_ccmap { LV2_URID *cc_to_urid; int *urid_to_cc; diff --git a/plugins/lv2/sfizz_lv2_plugin.h b/plugins/lv2/sfizz_lv2_plugin.h index 2eed6d52..d9c4fe43 100644 --- a/plugins/lv2/sfizz_lv2_plugin.h +++ b/plugins/lv2/sfizz_lv2_plugin.h @@ -7,6 +7,9 @@ #pragma once #include "sfizz_lv2.h" +#if defined(SFIZZ_LV2_UI) +#include "plugin/RMSFollower.h" +#endif #include #include #include @@ -89,6 +92,7 @@ struct sfizz_plugin_t LV2_URID sfizz_check_modification_uri {}; LV2_URID sfizz_active_voices_uri {}; LV2_URID sfizz_osc_blob_uri {}; + LV2_URID sfizz_audio_level_uri {}; LV2_URID time_position_uri {}; LV2_URID time_bar_uri {}; LV2_URID time_bar_beat_uri {}; @@ -145,4 +149,10 @@ struct sfizz_plugin_t // OSC uint8_t osc_temp[OSC_TEMP_SIZE] {}; + +#if defined(SFIZZ_LV2_UI) + // UI + volatile bool ui_active = false; + RMSFollower rms_follower; +#endif }; diff --git a/plugins/lv2/sfizz_ui.cpp b/plugins/lv2/sfizz_ui.cpp index 93a90813..bd943833 100644 --- a/plugins/lv2/sfizz_ui.cpp +++ b/plugins/lv2/sfizz_ui.cpp @@ -116,6 +116,7 @@ struct sfizz_ui_t : EditorController, VSTGUIEditorInterface { LV2_URID sfizz_sfz_file_uri; LV2_URID sfizz_scala_file_uri; LV2_URID sfizz_osc_blob_uri; + LV2_URID sfizz_audio_level_uri; std::unique_ptr ccmap; uint8_t osc_temp[OSC_TEMP_SIZE]; @@ -217,6 +218,7 @@ instantiate(const LV2UI_Descriptor *descriptor, self->sfizz_sfz_file_uri = map->map(map->handle, SFIZZ__sfzFile); self->sfizz_scala_file_uri = map->map(map->handle, SFIZZ__tuningfile); self->sfizz_osc_blob_uri = map->map(map->handle, SFIZZ__OSCBlob); + self->sfizz_audio_level_uri = map->map(map->handle, SFIZZ__AudioLevel); self->ccmap.reset(sfizz_lv2_ccmap_create(map)); // set up the resource path @@ -287,6 +289,7 @@ static void cleanup(LV2UI_Handle ui) { sfizz_ui_t *self = (sfizz_ui_t *)ui; + sfizz_lv2_set_ui_active(self->plugin, false); delete self; } @@ -391,6 +394,27 @@ port_event(LV2UI_Handle ui, if (sfizz_extract_message(LV2_ATOM_BODY_CONST(atom), atom->size, buffer, sizeof(buffer), &path, &sig, &args) > 0) self->uiReceiveMessage(path, sig, args); } + else if (atom->type == self->sfizz_audio_level_uri) { + const LV2_Atom_Vector *vector = reinterpret_cast(atom); + + if (vector->body.child_type == self->atom_float_uri && + vector->body.child_size == sizeof(float)) + { + const uint8_t *vec_body = reinterpret_cast( + LV2_ATOM_CONTENTS_CONST(LV2_Atom_Vector, vector)); + const uint8_t *vec_end = reinterpret_cast( + LV2_ATOM_BODY_CONST(&vector->atom)) + vector->atom.size; + + const float *levels = reinterpret_cast(vec_body); + uint32_t count = static_cast((vec_end - vec_body) / sizeof(float)); + + float left = (count > 0) ? levels[0] : 0.0f; + float right = (count > 1) ? levels[1] : 0.0f; + + self->uiReceiveValue(EditId::LeftLevel, left); + self->uiReceiveValue(EditId::RightLevel, right); + } + } } (void)buffer_size; @@ -466,6 +490,8 @@ idle(LV2UI_Handle ui) (void)self; #endif + sfizz_lv2_set_ui_active(self->plugin, self->uiFrame->isVisible()); + return 0; } diff --git a/plugins/lv2/sfizz_ui.ttl.in b/plugins/lv2/sfizz_ui.ttl.in index 06ee2e31..a0150653 100644 --- a/plugins/lv2/sfizz_ui.ttl.in +++ b/plugins/lv2/sfizz_ui.ttl.in @@ -12,4 +12,4 @@ lv2:optionalFeature ui:touch ; lv2:requiredFeature urid:map ; lv2:requiredFeature urid:unmap ; - lv2:requiredFeature . + lv2:requiredFeature . diff --git a/plugins/vst/SfizzVstController.cpp b/plugins/vst/SfizzVstController.cpp index 4e92f8b4..17c3098b 100644 --- a/plugins/vst/SfizzVstController.cpp +++ b/plugins/vst/SfizzVstController.cpp @@ -92,6 +92,22 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) Vst::kRootUnitId, shortTitle)); } + // Volume levels + parameters.addParameter( + SfizzRange::getForParameter(kPidLeftLevel).createParameter( + Steinberg::String("Left level"), pid++, nullptr, + 0, Vst::ParameterInfo::kIsReadOnly|Vst::ParameterInfo::kIsHidden, Vst::kRootUnitId)); + parameters.addParameter( + SfizzRange::getForParameter(kPidRightLevel).createParameter( + Steinberg::String("Right level"), pid++, nullptr, + 0, Vst::ParameterInfo::kIsReadOnly|Vst::ParameterInfo::kIsHidden, Vst::kRootUnitId)); + + // Editor status + parameters.addParameter( + SfizzRange::getForParameter(kPidEditorOpen).createParameter( + Steinberg::String("Editor open"), pid++, nullptr, + 0, Vst::ParameterInfo::kIsReadOnly|Vst::ParameterInfo::kIsHidden, Vst::kRootUnitId)); + // Initial MIDI mapping for (int32 i = 0; i < Vst::kCountCtrlNumber; ++i) { Vst::ParamID id = Vst::kNoParamId; diff --git a/plugins/vst/SfizzVstEditor.cpp b/plugins/vst/SfizzVstEditor.cpp index 8a95afa7..6c85bfd3 100644 --- a/plugins/vst/SfizzVstEditor.cpp +++ b/plugins/vst/SfizzVstEditor.cpp @@ -122,6 +122,8 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p uiReceiveValue(EditId::UserFilesDir, userFilesDir.value_or(fs::path()).u8string()); uiReceiveValue(EditId::FallbackFilesDir, SfizzPaths::getSfzFallbackDefaultPath().u8string()); + updateEditorIsOpenParameter(); + return true; } @@ -153,6 +155,16 @@ void PLUGIN_API SfizzVstEditor::close() std::lock_guard lock(noteEventQueueMutex_); noteEventQueue_.reset(); } + + updateEditorIsOpenParameter(); +} + +void SfizzVstEditor::updateEditorIsOpenParameter() +{ + SfizzVstController* ctrl = getController(); + bool editorIsOpen = frame && frame->isVisible(); + ctrl->setParamNormalized(kPidEditorOpen, editorIsOpen); + ctrl->performEdit(kPidEditorOpen, editorIsOpen); } /// @@ -180,6 +192,7 @@ CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message) if (message == CVSTGUITimer::kMsgTimer) { processOscQueue(); processNoteEventQueue(); + updateEditorIsOpenParameter(); // Note(jpc) for Reaper, it can fail at open time } return result; @@ -296,6 +309,12 @@ void PLUGIN_API SfizzVstEditor::update(FUnknown* changedUnknown, int32 message) case kPidOscillatorQuality: uiReceiveValue(EditId::OscillatorQuality, range.denormalize(value)); break; + case kPidLeftLevel: + uiReceiveValue(EditId::LeftLevel, range.denormalize(value)); + break; + case kPidRightLevel: + uiReceiveValue(EditId::RightLevel, range.denormalize(value)); + break; default: if (id >= kPidCC0 && id <= kPidCCLast) { int cc = int(id - kPidCC0); diff --git a/plugins/vst/SfizzVstEditor.h b/plugins/vst/SfizzVstEditor.h index 780e2b2f..d254dbd8 100644 --- a/plugins/vst/SfizzVstEditor.h +++ b/plugins/vst/SfizzVstEditor.h @@ -37,15 +37,14 @@ public: return static_cast(Vst::VSTGUIEditor::getController()); } + void updateEditorIsOpenParameter(); + // VSTGUIEditor CMessageResult notify(CBaseObject* sender, const char* message) override; // FObject void PLUGIN_API update(FUnknown* changedUnknown, int32 message) override; // - void updateState(const SfizzVstState& state); - void updatePlayState(const SfizzPlayState& playState); - private: void processOscQueue(); void processNoteEventQueue(); diff --git a/plugins/vst/SfizzVstParameters.h b/plugins/vst/SfizzVstParameters.h index f1791653..cfe1c473 100644 --- a/plugins/vst/SfizzVstParameters.h +++ b/plugins/vst/SfizzVstParameters.h @@ -26,6 +26,9 @@ enum { kPidPitchBend, kPidCC0, kPidCCLast = kPidCC0 + sfz::config::numCCs - 1, + kPidLeftLevel, + kPidRightLevel, + kPidEditorOpen, /* Reserved */ kNumParameters, }; @@ -78,6 +81,12 @@ struct SfizzRange { return {0.0, 0.0, 1.0}; case kPidPitchBend: return {0.0, -1.0, 1.0}; + case kPidLeftLevel: + return {0.0, 0.0, 1.0}; + case kPidRightLevel: + return {0.0, 0.0, 1.0}; + case kPidEditorOpen: + return {0.0, 0.0, 1.0}; default: if (id >= kPidCC0 && id <= kPidCCLast) return {0.0, 0.0, 1.0}; diff --git a/plugins/vst/SfizzVstProcessor.cpp b/plugins/vst/SfizzVstProcessor.cpp index 7ae97bc3..5dca65d1 100644 --- a/plugins/vst/SfizzVstProcessor.cpp +++ b/plugins/vst/SfizzVstProcessor.cpp @@ -37,7 +37,7 @@ static const char* kMsgIdSetPreloadSize = "SetPreloadSize"; static const char* kMsgIdReceiveMessage = "ReceiveMessage"; static const char* kMsgIdNoteEvents = "NoteEvents"; -static constexpr std::chrono::milliseconds kBackgroundIdleInterval { 50 }; +static constexpr std::chrono::milliseconds kBackgroundIdleInterval { 20 }; SfizzVstProcessor::SfizzVstProcessor() : _oscTemp(new uint8_t[kOscTempSize]), @@ -106,6 +106,8 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context) _noteEventsCurrentCycle.fill(-1.0f); + _editorIsOpen = false; + return result; } @@ -221,6 +223,7 @@ tresult PLUGIN_API SfizzVstProcessor::setActive(TBool state) if (state) { synth->setSampleRate(processSetup.sampleRate); synth->setSamplesPerBlock(processSetup.maxSamplesPerBlock); + _rmsFollower.init(processSetup.sampleRate); initializeEventProcessor(processSetup, kNumParameters); startBackgroundWork(); } else { @@ -286,6 +289,24 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) synth.renderBlock(outputs, numFrames, numChannels); + // Update levels, if editor is open, otherwise skip + RMSFollower& rmsFollower = _rmsFollower; + if (_editorIsOpen) { + rmsFollower.process(outputs[0], outputs[1], numFrames); + simde__m128 rms = _rmsFollower.getRMS(); + float left = reinterpret_cast(&rms)[0]; + float right = reinterpret_cast(&rms)[1]; + if (Vst::IParameterChanges* pcs = data.outputParameterChanges) { + int32 index; + if (Vst::IParamValueQueue* vq = pcs->addParameterData(kPidLeftLevel, index)) + vq->addPoint(0, left, index); + if (Vst::IParamValueQueue* vq = pcs->addParameterData(kPidRightLevel, index)) + vq->addPoint(0, right, index); + } + } + else + rmsFollower.clear(); + // Request OSC updates sfz::Client& client = *_client; synth.sendMessage(client, 0, "/sw/last/current", "", nullptr); @@ -388,6 +409,9 @@ void SfizzVstProcessor::playOrderedParameter(int32 sampleOffset, Vst::ParamID id case kPidPitchBend: synth.hdPitchWheel(sampleOffset, range.denormalize(value)); break; + case kPidEditorOpen: + _editorIsOpen = value != 0; + break; default: if (id >= kPidCC0 && id <= kPidCCLast) { int32 ccNumber = static_cast(id - kPidCC0); @@ -713,7 +737,7 @@ void SfizzVstProcessor::doBackgroundIdle(size_t idleCounter) sendMessage(notification); } - if (idleCounter % 10 == 0) { + if (idleCounter % 25 == 0) { if (_synth->shouldReloadFile()) { fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n"); std::lock_guard lock(_processMutex); diff --git a/plugins/vst/SfizzVstProcessor.h b/plugins/vst/SfizzVstProcessor.h index e686b86e..1ab35a9d 100644 --- a/plugins/vst/SfizzVstProcessor.h +++ b/plugins/vst/SfizzVstProcessor.h @@ -7,6 +7,7 @@ #pragma once #include "SfizzVstState.h" #include "OrderedEventProcessor.h" +#include "plugin/RMSFollower.h" #include "sfizz/RTSemaphore.h" #include "ring_buffer/ring_buffer.h" #include "public.sdk/source/vst/vstaudioeffect.h" @@ -63,6 +64,10 @@ private: // whether allowed to perform events (owns the processing lock) bool _canPerformEventsAndParameters {}; + // level meters + RMSFollower _rmsFollower; + bool _editorIsOpen = false; + // client sfz::ClientPtr _client; std::unique_ptr _oscTemp; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d4d1dff..ea627f7d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -296,9 +296,6 @@ if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_USE_SNDFILE=1") target_link_libraries(sfizz_internal PUBLIC st_audiofile) endif() -if(WIN32) - target_compile_definitions(sfizz_internal PRIVATE _USE_MATH_DEFINES) -endif() if(SFIZZ_RELEASE_ASSERTS) target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_ENABLE_RELEASE_ASSERT=1") endif()