| 
				
				
				
				 | 
			
			 | 
			@@ -0,0 +1,407 @@ | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			/*
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  ==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   This file is part of the JUCE examples.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   Copyright (c) 2020 - Raw Material Software Limited
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   The code included in this file is provided under the terms of the ISC license
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   To use, copy, modify, and/or distribute this software for any purpose with or
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   without fee is hereby granted provided that the above copyright notice and
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   this permission notice appear in all copies.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   PURPOSE, ARE DISCLAIMED.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  ==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			*/
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			/*******************************************************************************
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 The block below describes the properties of this PIP. A PIP is a short snippet
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 of code that can be read by the Projucer and used to generate a JUCE project.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 BEGIN_JUCE_PIP_METADATA
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 name:             ReaperEmbeddedViewDemo
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 version:          1.0.0
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 vendor:           JUCE
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 website:          http://juce.com
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 description:      An audio plugin which embeds a secondary view in VST2 and
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                   VST3 formats in REAPER
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 dependencies:     juce_audio_basics, juce_audio_devices, juce_audio_formats,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                   juce_audio_plugin_client, juce_audio_processors,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                   juce_audio_utils, juce_core, juce_data_structures,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                   juce_events, juce_graphics, juce_gui_basics, juce_gui_extra
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 exporters:        xcode_mac, vs2019, linux_make
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 moduleFlags:      JUCE_STRICT_REFCOUNTEDPOINTER=1
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 type:             AudioProcessor
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 mainClass:        ReaperEmbeddedViewDemo
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 useLocalCopy:     1
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 END_JUCE_PIP_METADATA
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			*******************************************************************************/
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			/*  This demo shows how to use the VSTCallbackHandler and VST3ClientExtensions
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    classes to provide extended functionality in compatible VST/VST3 hosts.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    If this project is built as a VST or VST3 plugin and loaded in REAPER
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    6.29 or higher, it will provide an embedded level meter in the track
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    control panel. To enable the embedded view, right-click on the plugin
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    and select "Show embedded UI in TCP".
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    The plugin's editor also include a button which can be used to toggle
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    all inserts on and off.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			*/
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#pragma once
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#include <pluginterfaces/base/ftypes.h>
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#include <pluginterfaces/base/funknown.h>
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#include <pluginterfaces/vst/ivsthostapplication.h>
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			namespace reaper
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			{
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant",
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                         "-Wunused-parameter")
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    using namespace Steinberg;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    using INT_PTR = pointer_sized_int;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    using uint32 = Steinberg::uint32;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    #include "extern/reaper_plugin_fx_embed.h"
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    #include "extern/reaper_vst3_interfaces.h"
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    //==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    /*  These should live in a file which is guaranteed to be compiled only once
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        (i.e. a .cpp file, normally). This demo is a bit special, because we know
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        that this header will only be included in a single translation unit.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			     */
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    DEF_CLASS_IID (IReaperHostApplication)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    DEF_CLASS_IID (IReaperUIEmbedInterface)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			//==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			struct EmbeddedViewListener
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			{
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    virtual ~EmbeddedViewListener() = default;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    virtual Steinberg::TPtrInt handledEmbeddedUIMessage (int msg,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                         Steinberg::TPtrInt parm2,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                         Steinberg::TPtrInt parm3) = 0;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			};
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			//==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			class EmbeddedUI : public reaper::IReaperUIEmbedInterface
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			{
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			public:
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    explicit EmbeddedUI (EmbeddedViewListener& demo) : listener (demo) {}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    Steinberg::TPtrInt embed_message (int msg,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                      Steinberg::TPtrInt parm2,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                      Steinberg::TPtrInt parm3) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return listener.handledEmbeddedUIMessage (msg, parm2, parm3);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    Steinberg::uint32 PLUGIN_API addRef() override   { return (Steinberg::uint32) ++refCount; }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    Steinberg::uint32 PLUGIN_API release() override  { return (Steinberg::uint32) --refCount; }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID tuid, void** obj) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (std::memcmp (tuid, iid, sizeof (Steinberg::TUID)) == 0)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            *obj = this;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            return Steinberg::kResultOk;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        *obj = nullptr;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return Steinberg::kNoInterface;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			private:
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EmbeddedViewListener& listener;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::atomic<int> refCount { 1 };
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			};
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			//==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			class Editor : public AudioProcessorEditor
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			{
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			public:
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    explicit Editor (AudioProcessor& proc,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                     AudioParameterFloat& param,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                     void (*globalBypass) (int))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        : AudioProcessorEditor (proc), attachment (param, slider)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        addAndMakeVisible (slider);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        addAndMakeVisible (bypassButton);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        // Clicking will bypass *everything*
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        bypassButton.onClick = [globalBypass] { if (globalBypass != nullptr) globalBypass (-1); };
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        setSize (300, 80);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void resized() override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        auto b = getLocalBounds();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        slider.setBounds (b.removeFromTop (40));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        bypassButton.setBounds (b);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void paint (Graphics& g) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        g.fillAll (Colours::darkgrey);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			private:
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    Slider slider;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    TextButton bypassButton { "global bypass" };
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    SliderParameterAttachment attachment;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			};
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			//==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			class ReaperEmbeddedViewDemo  : public AudioProcessor,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                public VSTCallbackHandler,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                public VST3ClientExtensions,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                private EmbeddedViewListener,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                private Timer
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			{
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			public:
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    ReaperEmbeddedViewDemo()
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        addParameter (gain = new AudioParameterFloat ("gain", "Gain", 0.0f, 1.0f, 0.5f));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        startTimerHz (60);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void prepareToPlay (double, int) override {}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void reset() override {}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void releaseResources() override {}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void processBlock (AudioBuffer<float>&  audio, MidiBuffer&) override { processBlockImpl (audio); }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void processBlock (AudioBuffer<double>& audio, MidiBuffer&) override { processBlockImpl (audio); }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    //==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    AudioProcessorEditor* createEditor() override { return new Editor (*this, *gain, globalBypassFn); }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    bool hasEditor() const override               { return true;   }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    //==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    const String getName() const override { return "ReaperEmbeddedViewDemo"; }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    bool acceptsMidi()  const override { return false; }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    bool producesMidi() const override { return false; }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    bool isMidiEffect() const override { return false; }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    double getTailLengthSeconds() const override { return 0.0; }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    //==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int getNumPrograms()    override { return 1; }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int getCurrentProgram() override { return 0; }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void setCurrentProgram (int) override {}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    const String getProgramName (int) override { return {}; }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void changeProgramName (int, const String&) override {}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    //==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void getStateInformation (MemoryBlock& destData) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        MemoryOutputStream (destData, true).writeFloat (*gain);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void setStateInformation (const void* data, int sizeInBytes) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        gain->setValueNotifyingHost (MemoryInputStream (data,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                        static_cast<size_t> (sizeInBytes),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                        false).readFloat());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int32_t queryIEditController (const Steinberg::TUID tuid, void** obj) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (std::memcmp (tuid, embeddedUi.iid, sizeof (Steinberg::TUID)) == 0)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            *obj = &embeddedUi;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            return Steinberg::kResultOk;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        *obj = nullptr;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return Steinberg::kNoInterface;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void setIHostApplication (Steinberg::FUnknown* ptr) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (ptr == nullptr)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            return;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        void* objPtr = nullptr;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (ptr->queryInterface (reaper::IReaperHostApplication::iid, &objPtr) == Steinberg::kResultOk)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (void* fnPtr = static_cast<reaper::IReaperHostApplication*> (objPtr)->getReaperApi ("BypassFxAllTracks"))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                globalBypassFn = reinterpret_cast<void (*) (int)> (fnPtr);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    pointer_sized_int handleVstPluginCanDo (int32, pointer_sized_int, void* ptr, float) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (auto* str = static_cast<const char*> (ptr))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (strcmp (str, "hasCockosEmbeddedUI") == 0)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                return 0xbeef0000;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (strcmp (str, "hasCockosExtensions") == 0)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                return 0xbeef0000;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return 0;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    pointer_sized_int handleVstManufacturerSpecific (int32,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                     pointer_sized_int value,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                     void* ptr,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                     float opt) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return (pointer_sized_int) handledEmbeddedUIMessage ((int) opt,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                             (Steinberg::TPtrInt) value,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                             (Steinberg::TPtrInt) ptr);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void handleVstHostCallbackAvailable (std::function<VstHostCallbackType>&& hostcb) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        char functionName[] = "BypassFxAllTracks";
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        globalBypassFn = reinterpret_cast<void (*) (int)> (hostcb ((int32_t) 0xdeadbeef, (int32_t) 0xdeadf00d, 0, functionName, 0.0));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			private:
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    template <typename Float>
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void processBlockImpl (AudioBuffer<Float>& audio)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        audio.applyGain (*gain);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto minMax = audio.findMinMax (0, 0, audio.getNumSamples());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto newMax = (float) std::max (std::abs (minMax.getStart()), std::abs (minMax.getEnd()));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        auto loaded = storedLevel.load();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        while (loaded < newMax && ! storedLevel.compare_exchange_weak (loaded, newMax)) {}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void timerCallback() override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        levelToDraw = std::max (levelToDraw * 0.95f, storedLevel.exchange (0.0f));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    Steinberg::TPtrInt getSizeInfo (reaper::REAPER_FXEMBED_SizeHints* sizeHints)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (sizeHints == nullptr)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            return 0;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        sizeHints->preferred_aspect = 1 << 16;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        sizeHints->minimum_aspect   = 1 << 16;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        sizeHints->min_height = sizeHints->min_width = 50;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        sizeHints->max_height = sizeHints->max_width = 1000;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return 1;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    Steinberg::TPtrInt doPaint (reaper::REAPER_FXEMBED_IBitmap* bitmap,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                reaper::REAPER_FXEMBED_DrawInfo* drawInfo)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (bitmap == nullptr || drawInfo == nullptr)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            return 0;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        Image img (juce::Image::PixelFormat::ARGB, bitmap->getWidth(), bitmap->getHeight(), true);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        Graphics g (img);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        g.fillAll (Colours::black);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto bounds = g.getClipBounds();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto corner = 3.0f;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        g.setColour (Colours::darkgrey);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        g.fillRoundedRectangle (bounds.withSizeKeepingCentre (20, bounds.getHeight() - 6).toFloat(),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                corner);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto minDb = -50.0f;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto maxDb = 6.0f;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto levelInDb = Decibels::gainToDecibels (levelToDraw, minDb);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto fractionOfHeight = jmap (levelInDb, minDb, maxDb, 0.0f, 1.0f);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto trackBounds = bounds.withSizeKeepingCentre (16, bounds.getHeight() - 10).toFloat();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        g.setColour (Colours::black);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto zeroDbIndicatorY = trackBounds.proportionOfHeight (jmap (0.0f,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                                            minDb,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                                            maxDb,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                                            0.0f,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                                            1.0f));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        g.drawHorizontalLine ((int) (trackBounds.getBottom() - zeroDbIndicatorY),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                              trackBounds.getX(),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                              trackBounds.getRight());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        g.setGradientFill (ColourGradient (Colours::darkgreen,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                           { 0.0f, (float) bounds.getHeight() },
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                           Colours::darkred,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                           { 0.0f, 0.0f },
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                           false));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        g.fillRoundedRectangle (trackBounds.withHeight (trackBounds.proportionOfHeight (fractionOfHeight))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                           .withBottomY (trackBounds.getBottom()),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                corner);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        Image::BitmapData imgData { img, Image::BitmapData::readOnly };
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto pixelsWidth = imgData.pixelStride * imgData.width;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        auto* px = bitmap->getBits();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto rowSpan = bitmap->getRowSpan();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const auto numRows = bitmap->getHeight();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (int y = 0; y < numRows; ++y)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            std::memcpy (px + (y * rowSpan), imgData.getLinePointer (y), (size_t) pixelsWidth);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return 1;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    Steinberg::TPtrInt handledEmbeddedUIMessage (int msg,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                 Steinberg::TPtrInt parm2,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                 Steinberg::TPtrInt parm3) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        switch (msg)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_IS_SUPPORTED:
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                return 1;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_PAINT:
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                return doPaint (reinterpret_cast<reaper::REAPER_FXEMBED_IBitmap*> (parm2),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                reinterpret_cast<reaper::REAPER_FXEMBED_DrawInfo*> (parm3));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_GETMINMAXINFO:
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                return getSizeInfo (reinterpret_cast<reaper::REAPER_FXEMBED_SizeHints*> (parm3));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            // Implementing mouse behaviour is left as an exercise for the reaper, I mean reader
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_CREATE:          break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_DESTROY:         break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_SETCURSOR:       break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_MOUSEMOVE:       break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_LBUTTONDOWN:     break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_LBUTTONUP:       break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_LBUTTONDBLCLK:   break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_RBUTTONDOWN:     break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_RBUTTONUP:       break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_RBUTTONDBLCLK:   break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            case REAPER_FXEMBED_WM_MOUSEWHEEL:      break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return 0;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    AudioParameterFloat* gain = nullptr;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void (*globalBypassFn) (int) = nullptr;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EmbeddedUI embeddedUi { *this };
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::atomic<float> storedLevel { 0.0f };
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    float levelToDraw = 0.0f;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			};
 |