/* ============================================================================== This file is part of the JUCE tutorials. Copyright (c) 2017 - ROLI Ltd. 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: SynthForwardingToSerum version: 2.0.0 vendor: JUCE website: http://juce.com description: VSTi inside a VSTi test 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_dsp, juce_events, juce_graphics, juce_gui_basics, juce_gui_extra exporters: xcode_mac, vs2017 moduleFlags: JUCE_PLUGINHOST_VST=1 type: AudioProcessor mainClass: TestAudioProcessor useLocalCopy: 1 END_JUCE_PIP_METADATA *******************************************************************************/ #pragma once //////////////////////////////////////////////////////////////////////////////////////////////////// class PluginWindow : public juce::DocumentWindow { public: PluginWindow(juce::Component* iComponent) : juce::DocumentWindow("Instrument", juce::Colours::black, DocumentWindow::closeButton, true) { jassert(iComponent); setContentOwned(iComponent, true); setVisible(true); setResizable(false, false); const auto area = Rectangle(0, 0, iComponent->getWidth(), iComponent->getHeight()); setUsingNativeTitleBar(true); centreWithSize(area.getWidth(), area.getHeight()); toFront(true); } ~PluginWindow() {} }; //============================================================================== class TestAudioProcessor : public AudioProcessor { public: //============================================================================== TestAudioProcessor() : AudioProcessor (BusesProperties().withOutput ("Output", AudioChannelSet::stereo(), true)) { pluginManager.addDefaultFormats(); } ~TestAudioProcessor() {} //============================================================================== void prepareToPlay (double sampleRate, int samplesPerBlock) override { midiMessageCollector.reset (sampleRate); if(plugin) { plugin->prepareToPlay(sampleRate, samplesPerBlock); } } void releaseResources() override {} bool isBusesLayoutSupported (const BusesLayout& layouts) const override { // This is the place where you check if the layout is supported. // In this template code we only support mono or stereo. if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono() && layouts.getMainOutputChannelSet() != AudioChannelSet::stereo()) return false; return true; } void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) override { ScopedNoDenormals noDenormals; auto totalNumInputChannels = getTotalNumInputChannels(); auto totalNumOutputChannels = getTotalNumOutputChannels(); midiMessageCollector.removeNextBlockOfMessages (midiMessages, buffer.getNumSamples()); for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i) buffer.clear (i, 0, buffer.getNumSamples()); if(plugin) { plugin->processBlock(buffer, midiMessages); } } void createPlugin(const File& vstFile) { suspendProcessing(true); KnownPluginList list; StringArray vstFilenames{ vstFile.getFullPathName() }; OwnedArray typesFound; list.scanAndAddDragAndDroppedFiles(pluginManager, vstFilenames, typesFound); if(!typesFound.isEmpty()) { String errorMessage; auto * instance = pluginManager.createPluginInstance(*typesFound.getFirst(), getSampleRate(), getBlockSize(), errorMessage); if(instance) { instance->prepareToPlay(getSampleRate(), getBlockSize()); plugin = instance; auto * editor = plugin->createEditor(); if(editor) { pluginWindow = new PluginWindow(editor); } } } suspendProcessing(false); } //============================================================================== AudioProcessorEditor* createEditor() override { return new TestAudioProcessorEditor (*this); } bool hasEditor() const override { return true; } //============================================================================== const String getName() const override { return JucePlugin_Name; } bool acceptsMidi() const override { return true; } 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&) override {} void setStateInformation (const void*, int) override {} //============================================================================== MidiMessageCollector& getMidiMessageCollector() noexcept { return midiMessageCollector; } private: //============================================================================== class TestAudioProcessorEditor : public AudioProcessorEditor, public Button::Listener { public: TestAudioProcessorEditor (TestAudioProcessor& p) : AudioProcessorEditor (&p), processor (p) { addAndMakeVisible (midiKeyboardComponent); addAndMakeVisible(vstLoadBtn); vstLoadBtn.setButtonText("Load VST from DLL..."); vstLoadBtn.addListener(this); setSize (400, 300); midiKeyboardComponent.setMidiChannel (2); midiKeyboardState.addListener (& processor.getMidiMessageCollector()); } ~TestAudioProcessorEditor() { vstLoadBtn.removeListener(this); midiKeyboardState.removeListener (& processor.getMidiMessageCollector()); } //============================================================================== void paint (Graphics& g) override { g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId)); } void resized() override { auto area = getLocalBounds(); vstLoadBtn.setBounds(area.removeFromTop(50).reduced(10)); midiKeyboardComponent.setBounds(area.removeFromBottom(80).reduced(10)); } void buttonClicked(Button* btn) override { if(btn == &vstLoadBtn) { #if JUCE_MAC File defaultFile("/Library/Audio/Plug-Ins/VST"); WildcardFileFilter wildcardFilter("*.vst", String(), "VST files"); const int flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories; #else File defaultFile; WildcardFileFilter wildcardFilter("*.dll", String(), "VST files"); const int flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles; #endif FileBrowserComponent browser(flags, defaultFile, &wildcardFilter, nullptr); FileChooserDialogBox dialogBox ("Open VST...", "Please choose the VST to open...", browser, false, Colours::lightgrey); if (dialogBox.show()) { File selectedFile = browser.getSelectedFile(0); processor.createPlugin(selectedFile); } } } private: //============================================================================== TestAudioProcessor& processor; MidiKeyboardState midiKeyboardState; MidiKeyboardComponent midiKeyboardComponent { midiKeyboardState, MidiKeyboardComponent::horizontalKeyboard }; TextButton vstLoadBtn; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TestAudioProcessorEditor) }; //============================================================================== MidiMessageCollector midiMessageCollector; AudioPluginFormatManager pluginManager; ScopedPointer plugin; ScopedPointer pluginWindow; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TestAudioProcessor) };