|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2017 - ROLI Ltd.
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- By using JUCE, you agree to the terms of both the JUCE 5 End-User License
- Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
- 27th April 2017).
-
- End User License Agreement: www.juce.com/juce-5-licence
- Privacy Policy: www.juce.com/juce-5-privacy-policy
-
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- #include "PluginProcessor.h"
- #include "PluginEditor.h"
- #include "SinewaveSynth.h"
-
- AudioProcessor* JUCE_CALLTYPE createPluginFilter();
-
-
- //==============================================================================
- JuceDemoPluginAudioProcessor::JuceDemoPluginAudioProcessor()
- : AudioProcessor (getBusesProperties())
- {
- lastPosInfo.resetToDefault();
-
- // This creates our parameters. We'll keep some raw pointers to them in this class,
- // so that we can easily access them later, but the base class will take care of
- // deleting them for us.
- addParameter (gainParam = new AudioParameterFloat ("gain", "Gain", 0.0f, 1.0f, 0.9f));
- addParameter (delayParam = new AudioParameterFloat ("delay", "Delay Feedback", 0.0f, 1.0f, 0.5f));
-
- initialiseSynth();
- }
-
- JuceDemoPluginAudioProcessor::~JuceDemoPluginAudioProcessor()
- {
- }
-
- void JuceDemoPluginAudioProcessor::initialiseSynth()
- {
- const int numVoices = 8;
-
- // Add some voices...
- for (int i = numVoices; --i >= 0;)
- synth.addVoice (new SineWaveVoice());
-
- // ..and give the synth a sound to play
- synth.addSound (new SineWaveSound());
- }
-
- //==============================================================================
- bool JuceDemoPluginAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
- {
- // Only mono/stereo and input/output must have same layout
- const AudioChannelSet& mainOutput = layouts.getMainOutputChannelSet();
- const AudioChannelSet& mainInput = layouts.getMainInputChannelSet();
-
- // input and output layout must either be the same or the input must be disabled altogether
- if (! mainInput.isDisabled() && mainInput != mainOutput)
- return false;
-
- // do not allow disabling the main buses
- if (mainOutput.isDisabled())
- return false;
-
- // only allow stereo and mono
- if (mainOutput.size() > 2)
- return false;
-
- return true;
- }
-
- AudioProcessor::BusesProperties JuceDemoPluginAudioProcessor::getBusesProperties()
- {
- return BusesProperties().withInput ("Input", AudioChannelSet::stereo(), true)
- .withOutput ("Output", AudioChannelSet::stereo(), true);
- }
-
- //==============================================================================
- void JuceDemoPluginAudioProcessor::prepareToPlay (double newSampleRate, int /*samplesPerBlock*/)
- {
- // Use this method as the place to do any pre-playback
- // initialisation that you need..
- synth.setCurrentPlaybackSampleRate (newSampleRate);
- keyboardState.reset();
-
- if (isUsingDoublePrecision())
- {
- delayBufferDouble.setSize (2, 12000);
- delayBufferFloat.setSize (1, 1);
- }
- else
- {
- delayBufferFloat.setSize (2, 12000);
- delayBufferDouble.setSize (1, 1);
- }
-
- reset();
- }
-
- void JuceDemoPluginAudioProcessor::releaseResources()
- {
- // When playback stops, you can use this as an opportunity to free up any
- // spare memory, etc.
- keyboardState.reset();
- }
-
- void JuceDemoPluginAudioProcessor::reset()
- {
- // Use this method as the place to clear any delay lines, buffers, etc, as it
- // means there's been a break in the audio's continuity.
- delayBufferFloat.clear();
- delayBufferDouble.clear();
- }
-
- template <typename FloatType>
- void JuceDemoPluginAudioProcessor::process (AudioBuffer<FloatType>& buffer,
- MidiBuffer& midiMessages,
- AudioBuffer<FloatType>& delayBuffer)
- {
- const int numSamples = buffer.getNumSamples();
-
- // Now pass any incoming midi messages to our keyboard state object, and let it
- // add messages to the buffer if the user is clicking on the on-screen keys
- keyboardState.processNextMidiBuffer (midiMessages, 0, numSamples, true);
-
- // and now get our synth to process these midi events and generate its output.
- synth.renderNextBlock (buffer, midiMessages, 0, numSamples);
-
- // Apply our delay effect to the new output..
- applyDelay (buffer, delayBuffer);
-
- // In case we have more outputs than inputs, we'll clear any output
- // channels that didn't contain input data, (because these aren't
- // guaranteed to be empty - they may contain garbage).
- for (int i = getTotalNumInputChannels(); i < getTotalNumOutputChannels(); ++i)
- buffer.clear (i, 0, numSamples);
-
- applyGain (buffer, delayBuffer); // apply our gain-change to the outgoing data..
-
- // Now ask the host for the current time so we can store it to be displayed later...
- updateCurrentTimeInfoFromHost();
- }
-
- template <typename FloatType>
- void JuceDemoPluginAudioProcessor::applyGain (AudioBuffer<FloatType>& buffer, AudioBuffer<FloatType>& delayBuffer)
- {
- ignoreUnused (delayBuffer);
- const float gainLevel = *gainParam;
-
- for (int channel = 0; channel < getTotalNumOutputChannels(); ++channel)
- buffer.applyGain (channel, 0, buffer.getNumSamples(), gainLevel);
- }
-
- template <typename FloatType>
- void JuceDemoPluginAudioProcessor::applyDelay (AudioBuffer<FloatType>& buffer, AudioBuffer<FloatType>& delayBuffer)
- {
- const int numSamples = buffer.getNumSamples();
- const float delayLevel = *delayParam;
-
- int delayPos = 0;
-
- for (int channel = 0; channel < getTotalNumOutputChannels(); ++channel)
- {
- auto channelData = buffer.getWritePointer (channel);
- auto delayData = delayBuffer.getWritePointer (jmin (channel, delayBuffer.getNumChannels() - 1));
- delayPos = delayPosition;
-
- for (int i = 0; i < numSamples; ++i)
- {
- auto in = channelData[i];
- channelData[i] += delayData[delayPos];
- delayData[delayPos] = (delayData[delayPos] + in) * delayLevel;
-
- if (++delayPos >= delayBuffer.getNumSamples())
- delayPos = 0;
- }
- }
-
- delayPosition = delayPos;
- }
-
- void JuceDemoPluginAudioProcessor::updateCurrentTimeInfoFromHost()
- {
- if (AudioPlayHead* ph = getPlayHead())
- {
- AudioPlayHead::CurrentPositionInfo newTime;
-
- if (ph->getCurrentPosition (newTime))
- {
- lastPosInfo = newTime; // Successfully got the current time from the host..
- return;
- }
- }
-
- // If the host fails to provide the current time, we'll just reset our copy to a default..
- lastPosInfo.resetToDefault();
- }
-
- //==============================================================================
- AudioProcessorEditor* JuceDemoPluginAudioProcessor::createEditor()
- {
- return new JuceDemoPluginAudioProcessorEditor (*this);
- }
-
- //==============================================================================
- void JuceDemoPluginAudioProcessor::getStateInformation (MemoryBlock& destData)
- {
- // You should use this method to store your parameters in the memory block.
- // Here's an example of how you can use XML to make it easy and more robust:
-
- // Create an outer XML element..
- XmlElement xml ("MYPLUGINSETTINGS");
-
- // add some attributes to it..
- xml.setAttribute ("uiWidth", lastUIWidth);
- xml.setAttribute ("uiHeight", lastUIHeight);
-
- // Store the values of all our parameters, using their param ID as the XML attribute
- for (auto* param : getParameters())
- if (auto* p = dynamic_cast<AudioProcessorParameterWithID*> (param))
- xml.setAttribute (p->paramID, p->getValue());
-
- // then use this helper function to stuff it into the binary blob and return it..
- copyXmlToBinary (xml, destData);
- }
-
- void JuceDemoPluginAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
- {
- // You should use this method to restore your parameters from this memory block,
- // whose contents will have been created by the getStateInformation() call.
-
- // This getXmlFromBinary() helper function retrieves our XML from the binary blob..
- ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));
-
- if (xmlState != nullptr)
- {
- // make sure that it's actually our type of XML object..
- if (xmlState->hasTagName ("MYPLUGINSETTINGS"))
- {
- // ok, now pull out our last window size..
- lastUIWidth = jmax (xmlState->getIntAttribute ("uiWidth", lastUIWidth), 400);
- lastUIHeight = jmax (xmlState->getIntAttribute ("uiHeight", lastUIHeight), 200);
-
- // Now reload our parameters..
- for (auto* param : getParameters())
- if (auto* p = dynamic_cast<AudioProcessorParameterWithID*> (param))
- p->setValue ((float) xmlState->getDoubleAttribute (p->paramID, p->getValue()));
- }
- }
- }
-
- void JuceDemoPluginAudioProcessor::updateTrackProperties (const TrackProperties& properties)
- {
- trackProperties = properties;
-
- if (auto* editor = dynamic_cast<JuceDemoPluginAudioProcessorEditor*> (getActiveEditor()))
- editor->updateTrackProperties ();
- }
-
- //==============================================================================
- // This creates new instances of the plugin..
- AudioProcessor* JUCE_CALLTYPE createPluginFilter()
- {
- return new JuceDemoPluginAudioProcessor();
- }
|