#pragma once #include #include #include "../LookAndFeel.h" #include "../concurrency/BufferConsumer.h" #include "../PluginProcessor.h" #include "LabelledTextBox.h" #include "SvgButton.h" #include "VisualiserSettings.h" enum class FullScreenMode { TOGGLE, FULL_SCREEN, MAIN_COMPONENT, }; class VisualiserWindow; class VisualiserComponent : public juce::Component, public juce::Timer, public juce::Thread, public juce::MouseListener, public juce::SettableTooltipClient { public: VisualiserComponent(OscirenderAudioProcessor& p, VisualiserComponent* parent = nullptr, bool useOldVisualiser = false); ~VisualiserComponent() override; void setIntensity(double intensity); void setPersistence(double persistence); void setHue(double hue); void openSettings(); void childChanged(); void enableFullScreen(); void setFullScreenCallback(std::function callback); void mouseDoubleClick(const juce::MouseEvent& event) override; void setBuffer(std::vector& buffer); void setColours(juce::Colour backgroundColour, juce::Colour waveformColour); void paintXY(juce::Graphics&, juce::Rectangle bounds); void paint(juce::Graphics&) override; void resized() override; void timerCallback() override; void run() override; void setPaused(bool paused); void mouseDown(const juce::MouseEvent& event) override; void mouseMove(const juce::MouseEvent& event) override; bool keyPressed(const juce::KeyPress& key) override; void setFullScreen(bool fullScreen); VisualiserComponent* parent = nullptr; VisualiserComponent* child = nullptr; std::unique_ptr popout = nullptr; std::atomic active = true; private: const double BUFFER_LENGTH_SECS = 0.02; const double DEFAULT_SAMPLE_RATE = 192000.0; std::atomic timerId; std::atomic lastMouseX; std::atomic lastMouseY; bool oldVisualiser; juce::CriticalSection lock; std::vector buffer; std::vector> prevLines; juce::Colour backgroundColour, waveformColour; OscirenderAudioProcessor& audioProcessor; int sampleRate = DEFAULT_SAMPLE_RATE; LabelledTextBox roughness{"Roughness", 1, 8, 1}; LabelledTextBox intensity{"Intensity", 0, 1, 0.01}; SvgButton fullScreenButton{ "fullScreen", BinaryData::fullscreen_svg, juce::Colours::white, juce::Colours::white }; SvgButton popOutButton{ "popOut", BinaryData::open_in_new_svg, juce::Colours::white, juce::Colours::white }; SvgButton settingsButton{ "settings", BinaryData::cog_svg, juce::Colours::white, juce::Colours::white }; juce::WebBrowserComponent::ResourceProvider provider = [this](const juce::String& path) { juce::String mimeType; if (path.endsWith("audio")) { mimeType = "application/octet-stream"; juce::CriticalSection::ScopedLockType scope(lock); std::vector data(buffer.size() * sizeof(float)); std::memcpy(data.data(), buffer.data(), data.size()); juce::WebBrowserComponent::Resource resource = { data, mimeType }; return resource; } else if (path.endsWith(".html")) { mimeType = "text/html"; } else if (path.endsWith(".jpg")) { mimeType = "image/jpeg"; } else if (path.endsWith(".js")) { mimeType = "text/javascript"; } else if (path.endsWith(".svg")) { mimeType = "image/svg+xml"; } std::vector data; int size; const char* file = BinaryData::getNamedResource(path.substring(1).replaceCharacter('.', '_').toRawUTF8(), size); for (int i = 0; i < size; i++) { data.push_back((std::byte) file[i]); } juce::WebBrowserComponent::Resource resource = { data, mimeType }; return resource; }; juce::WebBrowserComponent browser = juce::WebBrowserComponent( juce::WebBrowserComponent::Options() .withNativeIntegrationEnabled() .withResourceProvider(provider) .withNativeFunction("toggleFullscreen", [this](auto& var, auto complete) { enableFullScreen(); }) .withNativeFunction("popout", [this](auto& var, auto complete) { popoutWindow(); }) .withNativeFunction("settings", [this](auto& var, auto complete) { openSettings(); }) .withNativeFunction("isDebug", [this](auto& var, auto complete) { complete((bool) JUCE_DEBUG); }) .withNativeFunction("isOverlay", [this](auto& var, auto complete) { complete(parent != nullptr); }) .withNativeFunction("pause", [this](auto& var, auto complete) { setPaused(active); }) .withNativeFunction("getSettings", [this](auto& var, auto complete) { complete(settings.getSettings()); }) ); std::vector tempBuffer; int precision = 4; std::shared_ptr consumer; std::function fullScreenCallback; VisualiserSettings settings = VisualiserSettings(audioProcessor, *this); SettingsWindow settingsWindow = SettingsWindow("Visualiser Settings"); void resetBuffer(); void popoutWindow(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VisualiserComponent) }; class VisualiserWindow : public juce::DocumentWindow { public: VisualiserWindow(juce::String name, VisualiserComponent* parent) : parent(parent), wasPaused(!parent->active), juce::DocumentWindow(name, juce::Colours::black, juce::DocumentWindow::TitleBarButtons::allButtons) {} void closeButtonPressed() override { parent->setPaused(wasPaused); parent->child = nullptr; parent->childChanged(); parent->resized(); parent->popout.reset(); } private: VisualiserComponent* parent; bool wasPaused; };