git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
477
deps/juce/examples/Plugins/AUv3SynthPluginDemo.h
vendored
Normal file
477
deps/juce/examples/Plugins/AUv3SynthPluginDemo.h
vendored
Normal file
@ -0,0 +1,477 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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: AUv3SynthPlugin
|
||||
version: 1.0.0
|
||||
vendor: JUCE
|
||||
website: http://juce.com
|
||||
description: AUv3 synthesiser audio plugin.
|
||||
|
||||
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, xcode_iphone
|
||||
|
||||
moduleFlags: JUCE_STRICT_REFCOUNTEDPOINTER=1
|
||||
|
||||
type: AudioProcessor
|
||||
mainClass: AUv3SynthProcessor
|
||||
|
||||
useLocalCopy: 1
|
||||
|
||||
pluginCharacteristics: pluginIsSynth, pluginWantsMidiIn
|
||||
extraPluginFormats: AUv3
|
||||
|
||||
END_JUCE_PIP_METADATA
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Assets/DemoUtilities.h"
|
||||
|
||||
//==============================================================================
|
||||
class MaterialLookAndFeel : public LookAndFeel_V4
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
MaterialLookAndFeel()
|
||||
{
|
||||
setColour (ResizableWindow::backgroundColourId, windowBackgroundColour);
|
||||
setColour (TextButton::buttonOnColourId, brightButtonColour);
|
||||
setColour (TextButton::buttonColourId, disabledButtonColour);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void drawButtonBackground (Graphics& g,
|
||||
Button& button,
|
||||
const Colour& /*backgroundColour*/,
|
||||
bool /*isMouseOverButton*/,
|
||||
bool isButtonDown) override
|
||||
{
|
||||
auto buttonRect = button.getLocalBounds().toFloat();
|
||||
|
||||
if (isButtonDown)
|
||||
g.setColour (brightButtonColour.withAlpha (0.7f));
|
||||
else if (! button.isEnabled())
|
||||
g.setColour (disabledButtonColour);
|
||||
else
|
||||
g.setColour (brightButtonColour);
|
||||
|
||||
g.fillRoundedRectangle (buttonRect, 5.0f);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void drawButtonText (Graphics& g, TextButton& button, bool isMouseOverButton, bool isButtonDown) override
|
||||
{
|
||||
ignoreUnused (isMouseOverButton, isButtonDown);
|
||||
|
||||
Font font (getTextButtonFont (button, button.getHeight()));
|
||||
g.setFont (font);
|
||||
|
||||
if (button.isEnabled())
|
||||
g.setColour (Colours::white);
|
||||
else
|
||||
g.setColour (backgroundColour);
|
||||
|
||||
g.drawFittedText (button.getButtonText(), 0, 0,
|
||||
button.getWidth(),
|
||||
button.getHeight(),
|
||||
Justification::centred, 2);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void drawLinearSlider (Graphics& g, int x, int y, int width, int height,
|
||||
float sliderPos, float minSliderPos, float maxSliderPos,
|
||||
const Slider::SliderStyle style, Slider& slider) override
|
||||
{
|
||||
ignoreUnused (style, minSliderPos, maxSliderPos);
|
||||
|
||||
auto r = Rectangle<int> (x + haloRadius, y, width - (haloRadius * 2), height);
|
||||
auto backgroundBar = r.withSizeKeepingCentre(r.getWidth(), 2);
|
||||
|
||||
sliderPos = (sliderPos - minSliderPos) / static_cast<float> (width);
|
||||
|
||||
auto knobPos = static_cast<int> (sliderPos * (float) r.getWidth());
|
||||
|
||||
g.setColour (sliderActivePart);
|
||||
g.fillRect (backgroundBar.removeFromLeft (knobPos));
|
||||
|
||||
g.setColour (sliderInactivePart);
|
||||
g.fillRect (backgroundBar);
|
||||
|
||||
if (slider.isMouseOverOrDragging())
|
||||
{
|
||||
auto haloBounds = r.withTrimmedLeft (knobPos - haloRadius)
|
||||
.withWidth (haloRadius * 2)
|
||||
.withSizeKeepingCentre (haloRadius * 2, haloRadius * 2);
|
||||
|
||||
g.setColour (sliderActivePart.withAlpha (0.5f));
|
||||
g.fillEllipse (haloBounds.toFloat());
|
||||
}
|
||||
|
||||
auto knobRadius = slider.isMouseOverOrDragging() ? knobActiveRadius : knobInActiveRadius;
|
||||
auto knobBounds = r.withTrimmedLeft (knobPos - knobRadius)
|
||||
.withWidth (knobRadius * 2)
|
||||
.withSizeKeepingCentre (knobRadius * 2, knobRadius * 2);
|
||||
|
||||
g.setColour (sliderActivePart);
|
||||
g.fillEllipse (knobBounds.toFloat());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Font getTextButtonFont (TextButton& button, int buttonHeight) override
|
||||
{
|
||||
return LookAndFeel_V3::getTextButtonFont (button, buttonHeight).withHeight (buttonFontSize);
|
||||
}
|
||||
|
||||
Font getLabelFont (Label& label) override
|
||||
{
|
||||
return LookAndFeel_V3::getLabelFont (label).withHeight (labelFontSize);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
enum
|
||||
{
|
||||
labelFontSize = 12,
|
||||
buttonFontSize = 15
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
enum
|
||||
{
|
||||
knobActiveRadius = 12,
|
||||
knobInActiveRadius = 8,
|
||||
haloRadius = 18
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
const Colour windowBackgroundColour = Colour (0xff262328);
|
||||
const Colour backgroundColour = Colour (0xff4d4d4d);
|
||||
const Colour brightButtonColour = Colour (0xff80cbc4);
|
||||
const Colour disabledButtonColour = Colour (0xffe4e4e4);
|
||||
const Colour sliderInactivePart = Colour (0xff545d62);
|
||||
const Colour sliderActivePart = Colour (0xff80cbc4);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class AUv3SynthEditor : public AudioProcessorEditor,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
AUv3SynthEditor (AudioProcessor& processorIn)
|
||||
: AudioProcessorEditor (processorIn),
|
||||
roomSizeSlider (Slider::LinearHorizontal, Slider::NoTextBox)
|
||||
{
|
||||
setLookAndFeel (&materialLookAndFeel);
|
||||
|
||||
roomSizeSlider.setValue (getParameterValue ("roomSize"), NotificationType::dontSendNotification);
|
||||
|
||||
recordButton.onClick = [this] { startRecording(); };
|
||||
addAndMakeVisible (recordButton);
|
||||
|
||||
roomSizeSlider.onValueChange = [this] { setParameterValue ("roomSize", (float) roomSizeSlider.getValue()); };
|
||||
roomSizeSlider.setRange (0.0, 1.0);
|
||||
addAndMakeVisible (roomSizeSlider);
|
||||
|
||||
if (auto fileStream = createAssetInputStream ("proaudio.path"))
|
||||
{
|
||||
Path proAudioPath;
|
||||
proAudioPath.loadPathFromStream (*fileStream);
|
||||
proAudioIcon.setPath (proAudioPath);
|
||||
addAndMakeVisible (proAudioIcon);
|
||||
|
||||
auto proAudioIconColour = findColour (TextButton::buttonOnColourId);
|
||||
proAudioIcon.setFill (FillType (proAudioIconColour));
|
||||
}
|
||||
|
||||
setSize (600, 400);
|
||||
startTimer (100);
|
||||
}
|
||||
|
||||
~AUv3SynthEditor() override
|
||||
{
|
||||
setLookAndFeel (nullptr);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (ResizableWindow::backgroundColourId));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto r = getLocalBounds();
|
||||
|
||||
auto guiElementAreaHeight = r.getHeight() / 3;
|
||||
|
||||
proAudioIcon.setTransformToFit (r.removeFromLeft (proportionOfWidth (0.25))
|
||||
.withSizeKeepingCentre (guiElementAreaHeight, guiElementAreaHeight)
|
||||
.toFloat(),
|
||||
RectanglePlacement::fillDestination);
|
||||
|
||||
auto margin = guiElementAreaHeight / 4;
|
||||
r.reduce (margin, margin);
|
||||
|
||||
auto buttonHeight = guiElementAreaHeight - margin;
|
||||
|
||||
recordButton .setBounds (r.removeFromTop (guiElementAreaHeight).withSizeKeepingCentre (r.getWidth(), buttonHeight));
|
||||
roomSizeSlider.setBounds (r.removeFromTop (guiElementAreaHeight).withSizeKeepingCentre (r.getWidth(), buttonHeight));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void startRecording()
|
||||
{
|
||||
recordButton.setEnabled (false);
|
||||
setParameterValue ("isRecording", 1.0f);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void timerCallback() override
|
||||
{
|
||||
auto isRecordingNow = (getParameterValue ("isRecording") >= 0.5f);
|
||||
|
||||
recordButton.setEnabled (! isRecordingNow);
|
||||
roomSizeSlider.setValue (getParameterValue ("roomSize"), NotificationType::dontSendNotification);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AudioProcessorParameter* getParameter (const String& paramId)
|
||||
{
|
||||
if (auto* audioProcessor = getAudioProcessor())
|
||||
{
|
||||
auto& params = audioProcessor->getParameters();
|
||||
|
||||
for (auto p : params)
|
||||
{
|
||||
if (auto* param = dynamic_cast<AudioProcessorParameterWithID*> (p))
|
||||
{
|
||||
if (param->paramID == paramId)
|
||||
return param;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
float getParameterValue (const String& paramId)
|
||||
{
|
||||
if (auto* param = getParameter (paramId))
|
||||
return param->getValue();
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void setParameterValue (const String& paramId, float value)
|
||||
{
|
||||
if (auto* param = getParameter (paramId))
|
||||
param->setValueNotifyingHost (value);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
MaterialLookAndFeel materialLookAndFeel;
|
||||
|
||||
//==============================================================================
|
||||
TextButton recordButton { "Record" };
|
||||
Slider roomSizeSlider;
|
||||
DrawablePath proAudioIcon;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AUv3SynthEditor)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class AUv3SynthProcessor : public AudioProcessor
|
||||
{
|
||||
public:
|
||||
AUv3SynthProcessor ()
|
||||
: AudioProcessor (BusesProperties().withOutput ("Output", AudioChannelSet::stereo(), true)),
|
||||
currentRecording (1, 1), currentProgram (0)
|
||||
{
|
||||
// initialize parameters
|
||||
addParameter (isRecordingParam = new AudioParameterBool ("isRecording", "Is Recording", false));
|
||||
addParameter (roomSizeParam = new AudioParameterFloat ("roomSize", "Room Size", 0.0f, 1.0f, 0.5f));
|
||||
|
||||
formatManager.registerBasicFormats();
|
||||
|
||||
for (auto i = 0; i < maxNumVoices; ++i)
|
||||
synth.addVoice (new SamplerVoice());
|
||||
|
||||
loadNewSample (createAssetInputStream ("singing.ogg"), "ogg");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isBusesLayoutSupported (const BusesLayout& layouts) const override
|
||||
{
|
||||
return (layouts.getMainOutputChannels() <= 2);
|
||||
}
|
||||
|
||||
void prepareToPlay (double sampleRate, int estimatedMaxSizeOfBuffer) override
|
||||
{
|
||||
ignoreUnused (estimatedMaxSizeOfBuffer);
|
||||
|
||||
lastSampleRate = sampleRate;
|
||||
|
||||
currentRecording.setSize (1, static_cast<int> (std::ceil (maxDurationOfRecording * lastSampleRate)));
|
||||
samplesRecorded = 0;
|
||||
|
||||
synth.setCurrentPlaybackSampleRate (lastSampleRate);
|
||||
reverb.setSampleRate (lastSampleRate);
|
||||
}
|
||||
|
||||
void processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages) override
|
||||
{
|
||||
Reverb::Parameters reverbParameters;
|
||||
reverbParameters.roomSize = roomSizeParam->get();
|
||||
|
||||
reverb.setParameters (reverbParameters);
|
||||
synth.renderNextBlock (buffer, midiMessages, 0, buffer.getNumSamples());
|
||||
|
||||
if (getMainBusNumOutputChannels() == 1)
|
||||
reverb.processMono (buffer.getWritePointer (0), buffer.getNumSamples());
|
||||
else if (getMainBusNumOutputChannels() == 2)
|
||||
reverb.processStereo (buffer.getWritePointer (0), buffer.getWritePointer (1), buffer.getNumSamples());
|
||||
}
|
||||
|
||||
using AudioProcessor::processBlock;
|
||||
|
||||
//==============================================================================
|
||||
void releaseResources() override { currentRecording.setSize (1, 1); }
|
||||
|
||||
//==============================================================================
|
||||
bool acceptsMidi() const override { return true; }
|
||||
bool producesMidi() const override { return false; }
|
||||
double getTailLengthSeconds() const override { return 0.0; }
|
||||
|
||||
//==============================================================================
|
||||
AudioProcessorEditor* createEditor() override { return new AUv3SynthEditor (*this); }
|
||||
bool hasEditor() const override { return true; }
|
||||
|
||||
//==============================================================================
|
||||
const String getName() const override { return "AUv3 Synth"; }
|
||||
int getNumPrograms() override { return 4; }
|
||||
int getCurrentProgram() override { return currentProgram; }
|
||||
void setCurrentProgram (int index) override { currentProgram = index; }
|
||||
|
||||
const String getProgramName (int index) override
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return "Piano";
|
||||
case 1: return "Singing";
|
||||
case 2: return "Pinched Balloon";
|
||||
case 3: return "Gazeebo";
|
||||
default: break;
|
||||
}
|
||||
|
||||
return "<Unknown>";
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void changeProgramName (int /*index*/, const String& /*name*/) override {}
|
||||
|
||||
//==============================================================================
|
||||
void getStateInformation (MemoryBlock& destData) override
|
||||
{
|
||||
MemoryOutputStream stream (destData, true);
|
||||
|
||||
stream.writeFloat (*isRecordingParam);
|
||||
stream.writeFloat (*roomSizeParam);
|
||||
}
|
||||
|
||||
void setStateInformation (const void* data, int sizeInBytes) override
|
||||
{
|
||||
MemoryInputStream stream (data, static_cast<size_t> (sizeInBytes), false);
|
||||
|
||||
isRecordingParam->setValueNotifyingHost (stream.readFloat());
|
||||
roomSizeParam->setValueNotifyingHost (stream.readFloat());
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void loadNewSampleBinary (const void* data, int dataSize, const char* format)
|
||||
{
|
||||
auto soundBuffer = std::make_unique<MemoryInputStream> (data, static_cast<std::size_t> (dataSize), false);
|
||||
loadNewSample (std::move (soundBuffer), format);
|
||||
}
|
||||
|
||||
void loadNewSample (std::unique_ptr<InputStream> soundBuffer, const char* format)
|
||||
{
|
||||
std::unique_ptr<AudioFormatReader> formatReader (formatManager.findFormatForFileExtension (format)->createReaderFor (soundBuffer.release(), true));
|
||||
|
||||
BigInteger midiNotes;
|
||||
midiNotes.setRange (0, 126, true);
|
||||
SynthesiserSound::Ptr newSound = new SamplerSound ("Voice", *formatReader, midiNotes, 0x40, 0.0, 0.0, 10.0);
|
||||
synth.removeSound (0);
|
||||
sound = newSound;
|
||||
synth.addSound (sound);
|
||||
}
|
||||
|
||||
void swapSamples()
|
||||
{
|
||||
MemoryBlock mb;
|
||||
auto* stream = new MemoryOutputStream (mb, true);
|
||||
|
||||
{
|
||||
std::unique_ptr<AudioFormatWriter> writer (formatManager.findFormatForFileExtension ("wav")->createWriterFor (stream, lastSampleRate, 1, 16,
|
||||
StringPairArray(), 0));
|
||||
writer->writeFromAudioSampleBuffer (currentRecording, 0, currentRecording.getNumSamples());
|
||||
writer->flush();
|
||||
stream->flush();
|
||||
}
|
||||
|
||||
loadNewSampleBinary (mb.getData(), static_cast<int> (mb.getSize()), "wav");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static constexpr int maxNumVoices = 5;
|
||||
static constexpr double maxDurationOfRecording = 1.0;
|
||||
|
||||
//==============================================================================
|
||||
AudioFormatManager formatManager;
|
||||
|
||||
int samplesRecorded;
|
||||
double lastSampleRate;
|
||||
AudioBuffer<float> currentRecording;
|
||||
|
||||
Reverb reverb;
|
||||
Synthesiser synth;
|
||||
SynthesiserSound::Ptr sound;
|
||||
|
||||
AudioParameterBool* isRecordingParam;
|
||||
AudioParameterFloat* roomSizeParam;
|
||||
|
||||
int currentProgram;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AUv3SynthProcessor)
|
||||
};
|
Reference in New Issue
Block a user