/* ============================================================================== PluginEditor.h Created: 4 Nov 2025 6:20:46pm Author: mickl ============================================================================== */ #pragma once #include #include "PluginProcessor.h" extern const String localDevServerAddress; std::optional getResource(const String& url); //============================================================================== class SinglePageBrowser : public WebBrowserComponent { public: using WebBrowserComponent::WebBrowserComponent; // Prevent page loads from navigating away from our single page web app bool pageAboutToLoad(const String& newURL) override; bool pageisLoaded = false; void pageFinishedLoading(const String& newURL) override { pageisLoaded = true; } }; //============================================================================== class WebViewPluginAudioProcessorEditor : public AudioProcessorEditor, private Timer { public: explicit WebViewPluginAudioProcessorEditor(WebViewPluginAudioProcessor&); ~WebViewPluginAudioProcessorEditor() { delete webComponent; for (auto& attatchments : slider_attatchments) { delete attatchments; } for (auto& relays : slider_relays) { delete relays; } for (auto& attatchments : toggle_attatchments) { delete attatchments; } for (auto& relays : toggle_relays) { delete relays; } } std::optional getResource(const String& url); //============================================================================== void paint(Graphics&) override; void resized() override; int getControlParameterIndex(Component&) override { return controlParameterIndexReceiver.getControlParameterIndex(); } void timerCallback() override { if(webComponent->pageisLoaded){ webComponent->pageisLoaded = false; reload_count = 60; } if (reload_count) { if (--reload_count == 0) { /*for (int i = 0; i < processorRef.parameters.sliderIds.size(); ++i) { slider_attatchments.push_back(new WebSliderParameterAttachment( *processorRef.state.getParameter(processorRef.parameters.sliderIds[i]), *slider_relays.back(), processorRef.state.undoManager)); } for (int i = 0; i < processorRef.parameters.toggleIds.size(); ++i) { toggle_attatchments.push_back(new WebToggleButtonParameterAttachment( *processorRef.state.getParameter(processorRef.parameters.toggleIds[i]), *toggle_relays.back(), processorRef.state.undoManager)); }*/ } } static constexpr size_t numFramesBuffered = 5; SpinLock::ScopedLockType lock{ processorRef.midiLock }; static int64 callbackCounter = 0; processorRef.new_midi = false; juce::Array notes; int voice_num = 0; for (auto& voice : processorRef.shifter.voices) { if (voice.onoff_) { auto obj = new DynamicObject(); obj->setProperty("voice", voice_num); obj->setProperty("midi", voice.GetMidiNote()); notes.add(var(obj)); } voice_num++; } DynamicObject::Ptr d(new DynamicObject()); d->setProperty("notes", notes); webComponent->emitEventIfBrowserIsVisible("midNoteData", d.get()); d->clear(); if (processorRef.shifter.GetAutoTuneEnable()) { d->setProperty("input_pitch", processorRef.shifter.getInputPitch()); d->setProperty("output_pitch", processorRef.shifter.getOutputPitch()); } else { d->setProperty("input_pitch", -1); d->setProperty("output_pitch", -1); } webComponent->emitEventIfBrowserIsVisible("autoTuneData", d.get()); } private: WebViewPluginAudioProcessor& processorRef; std::vector slider_relays; std::vector< WebSliderParameterAttachment*> slider_attatchments; std::vector toggle_relays; std::vector< WebToggleButtonParameterAttachment*> toggle_attatchments; WebControlParameterIndexReceiver controlParameterIndexReceiver; SinglePageBrowser* webComponent = nullptr; std::deque> spectrumDataFrames; int reload_count = 0; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WebViewPluginAudioProcessorEditor) };