|
- /*
- ==============================================================================
-
- This file was auto-generated by the Jucer!
-
- It contains the basic startup code for a Juce application.
-
- ==============================================================================
- */
-
- #include "PluginProcessor.h"
- #include "PluginEditor.h"
-
- AudioProcessor* JUCE_CALLTYPE createPluginFilter();
-
-
- //==============================================================================
- /** A demo synth sound that's just a basic sine wave.. */
- class SineWaveSound : public SynthesiserSound
- {
- public:
- SineWaveSound() {}
-
- bool appliesToNote (const int /*midiNoteNumber*/) { return true; }
- bool appliesToChannel (const int /*midiChannel*/) { return true; }
- };
-
- //==============================================================================
- /** A simple demo synth voice that just plays a sine wave.. */
- class SineWaveVoice : public SynthesiserVoice
- {
- public:
- SineWaveVoice()
- : angleDelta (0.0),
- tailOff (0.0)
- {
- }
-
- bool canPlaySound (SynthesiserSound* sound)
- {
- return dynamic_cast <SineWaveSound*> (sound) != 0;
- }
-
- void startNote (int midiNoteNumber, float velocity,
- SynthesiserSound* /*sound*/, int /*currentPitchWheelPosition*/)
- {
- currentAngle = 0.0;
- level = velocity * 0.15;
- tailOff = 0.0;
-
- double cyclesPerSecond = MidiMessage::getMidiNoteInHertz (midiNoteNumber);
- double cyclesPerSample = cyclesPerSecond / getSampleRate();
-
- angleDelta = cyclesPerSample * 2.0 * double_Pi;
- }
-
- void stopNote (bool allowTailOff)
- {
- if (allowTailOff)
- {
- // start a tail-off by setting this flag. The render callback will pick up on
- // this and do a fade out, calling clearCurrentNote() when it's finished.
-
- if (tailOff == 0.0) // we only need to begin a tail-off if it's not already doing so - the
- // stopNote method could be called more than once.
- tailOff = 1.0;
- }
- else
- {
- // we're being told to stop playing immediately, so reset everything..
-
- clearCurrentNote();
- angleDelta = 0.0;
- }
- }
-
- void pitchWheelMoved (int /*newValue*/)
- {
- // can't be bothered implementing this for the demo!
- }
-
- void controllerMoved (int /*controllerNumber*/, int /*newValue*/)
- {
- // not interested in controllers in this case.
- }
-
- void renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples)
- {
- if (angleDelta != 0.0)
- {
- if (tailOff > 0)
- {
- while (--numSamples >= 0)
- {
- const float currentSample = (float) (sin (currentAngle) * level * tailOff);
-
- for (int i = outputBuffer.getNumChannels(); --i >= 0;)
- *outputBuffer.getSampleData (i, startSample) += currentSample;
-
- currentAngle += angleDelta;
- ++startSample;
-
- tailOff *= 0.99;
-
- if (tailOff <= 0.005)
- {
- clearCurrentNote();
-
- angleDelta = 0.0;
- break;
- }
- }
- }
- else
- {
- while (--numSamples >= 0)
- {
- const float currentSample = (float) (sin (currentAngle) * level);
-
- for (int i = outputBuffer.getNumChannels(); --i >= 0;)
- *outputBuffer.getSampleData (i, startSample) += currentSample;
-
- currentAngle += angleDelta;
- ++startSample;
- }
- }
- }
- }
-
- private:
- double currentAngle, angleDelta, level, tailOff;
- };
-
-
- //==============================================================================
- JuceDemoPluginAudioProcessor::JuceDemoPluginAudioProcessor()
- : delayBuffer (2, 12000)
- {
- // Set up some default values..
- gain = 1.0f;
- delay = 0.5f;
-
- lastUIWidth = 400;
- lastUIHeight = 200;
-
- lastPosInfo.resetToDefault();
- delayPosition = 0;
-
- // Initialise the synth...
- for (int i = 4; --i >= 0;)
- synth.addVoice (new SineWaveVoice()); // These voices will play our custom sine-wave sounds..
-
- synth.addSound (new SineWaveSound());
- }
-
- JuceDemoPluginAudioProcessor::~JuceDemoPluginAudioProcessor()
- {
- }
-
- //==============================================================================
- int JuceDemoPluginAudioProcessor::getNumParameters()
- {
- return totalNumParams;
- }
-
- float JuceDemoPluginAudioProcessor::getParameter (int index)
- {
- // This method will be called by the host, probably on the audio thread, so
- // it's absolutely time-critical. Don't use critical sections or anything
- // UI-related, or anything at all that may block in any way!
- switch (index)
- {
- case gainParam: return gain;
- case delayParam: return delay;
- default: return 0.0f;
- }
- }
-
- void JuceDemoPluginAudioProcessor::setParameter (int index, float newValue)
- {
- // This method will be called by the host, probably on the audio thread, so
- // it's absolutely time-critical. Don't use critical sections or anything
- // UI-related, or anything at all that may block in any way!
- switch (index)
- {
- case gainParam: gain = newValue; break;
- case delayParam: delay = newValue; break;
- default: break;
- }
- }
-
- const String JuceDemoPluginAudioProcessor::getParameterName (int index)
- {
- switch (index)
- {
- case gainParam: return "gain";
- case delayParam: return "delay";
- default: break;
- }
-
- return String::empty;
- }
-
- const String JuceDemoPluginAudioProcessor::getParameterText (int index)
- {
- return String (getParameter (index), 2);
- }
-
- //==============================================================================
- void JuceDemoPluginAudioProcessor::prepareToPlay (double sampleRate, int /*samplesPerBlock*/)
- {
- // Use this method as the place to do any pre-playback
- // initialisation that you need..
- synth.setCurrentPlaybackSampleRate (sampleRate);
- keyboardState.reset();
- delayBuffer.clear();
- }
-
- 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.
- delayBuffer.clear();
- }
-
- void JuceDemoPluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
- {
- const int numSamples = buffer.getNumSamples();
- int channel, dp = 0;
-
- // Go through the incoming data, and apply our gain to it...
- for (channel = 0; channel < getNumInputChannels(); ++channel)
- buffer.applyGain (channel, 0, buffer.getNumSamples(), gain);
-
- // 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 the synth to process these midi events and generate its output.
- synth.renderNextBlock (buffer, midiMessages, 0, numSamples);
-
- // Apply our delay effect to the new output..
- for (channel = 0; channel < getNumInputChannels(); ++channel)
- {
- float* channelData = buffer.getSampleData (channel);
- float* delayData = delayBuffer.getSampleData (jmin (channel, delayBuffer.getNumChannels() - 1));
- dp = delayPosition;
-
- for (int i = 0; i < numSamples; ++i)
- {
- const float in = channelData[i];
- channelData[i] += delayData[dp];
- delayData[dp] = (delayData[dp] + in) * delay;
- if (++dp >= delayBuffer.getNumSamples())
- dp = 0;
- }
- }
-
- delayPosition = dp;
-
- // 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 = getNumInputChannels(); i < getNumOutputChannels(); ++i)
- buffer.clear (i, 0, buffer.getNumSamples());
-
- // ask the host for the current time so we can display it...
- AudioPlayHead::CurrentPositionInfo newTime;
-
- if (getPlayHead() != nullptr && getPlayHead()->getCurrentPosition (newTime))
- {
- // Successfully got the current time from the host..
- lastPosInfo = newTime;
- }
- else
- {
- // If the host fails to fill-in the current time, we'll just clear it 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);
- xml.setAttribute ("gain", gain);
- xml.setAttribute ("delay", delay);
-
- // 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 parameters..
- lastUIWidth = xmlState->getIntAttribute ("uiWidth", lastUIWidth);
- lastUIHeight = xmlState->getIntAttribute ("uiHeight", lastUIHeight);
-
- gain = (float) xmlState->getDoubleAttribute ("gain", gain);
- delay = (float) xmlState->getDoubleAttribute ("delay", delay);
- }
- }
- }
-
- const String JuceDemoPluginAudioProcessor::getInputChannelName (const int channelIndex) const
- {
- return String (channelIndex + 1);
- }
-
- const String JuceDemoPluginAudioProcessor::getOutputChannelName (const int channelIndex) const
- {
- return String (channelIndex + 1);
- }
-
- bool JuceDemoPluginAudioProcessor::isInputChannelStereoPair (int /*index*/) const
- {
- return true;
- }
-
- bool JuceDemoPluginAudioProcessor::isOutputChannelStereoPair (int /*index*/) const
- {
- return true;
- }
-
- bool JuceDemoPluginAudioProcessor::acceptsMidi() const
- {
- #if JucePlugin_WantsMidiInput
- return true;
- #else
- return false;
- #endif
- }
-
- bool JuceDemoPluginAudioProcessor::producesMidi() const
- {
- #if JucePlugin_ProducesMidiOutput
- return true;
- #else
- return false;
- #endif
- }
-
- bool JuceDemoPluginAudioProcessor::silenceInProducesSilenceOut() const
- {
- return false;
- }
-
- double JuceDemoPluginAudioProcessor::getTailLengthSeconds() const
- {
- return 0.0;
- }
-
- //==============================================================================
- // This creates new instances of the plugin..
- AudioProcessor* JUCE_CALLTYPE createPluginFilter()
- {
- return new JuceDemoPluginAudioProcessor();
- }
|