Navigation Menu

Skip to content

Commit

Permalink
AudioPluginHost: Include example plugins in project
Browse files Browse the repository at this point in the history
This change adds the examples from `examples/Plugins` to the
AudioPluginHost, surfacing them as 'internal' plugins in the popup menu.
  • Loading branch information
reuk authored and ed95 committed Apr 16, 2020
1 parent 8433c09 commit f20b93a
Show file tree
Hide file tree
Showing 33 changed files with 1,637 additions and 446 deletions.
13 changes: 11 additions & 2 deletions examples/Assets/DemoUtilities.h
Expand Up @@ -67,10 +67,19 @@ inline File getExamplesDirectory() noexcept
if (exampleDir.exists())
return exampleDir;

int numTries = 0; // keep track of the number of parent directories so we don't go on endlessly
// keep track of the number of parent directories so we don't go on endlessly
for (int numTries = 0; numTries < 15; ++numTries)
{
if (currentFile.getFileName() == "examples")
return currentFile;

const auto sibling = currentFile.getSiblingFile ("examples");

if (sibling.exists())
return sibling;

while (currentFile.getFileName() != "examples" && numTries++ < 15)
currentFile = currentFile.getParentDirectory();
}

return currentFile;
#endif
Expand Down
Expand Up @@ -67,10 +67,19 @@ inline File getExamplesDirectory() noexcept
if (exampleDir.exists())
return exampleDir;

int numTries = 0; // keep track of the number of parent directories so we don't go on endlessly
// keep track of the number of parent directories so we don't go on endlessly
for (int numTries = 0; numTries < 15; ++numTries)
{
if (currentFile.getFileName() == "examples")
return currentFile;

const auto sibling = currentFile.getSiblingFile ("examples");

if (sibling.exists())
return sibling;

while (currentFile.getFileName() != "examples" && numTries++ < 15)
currentFile = currentFile.getParentDirectory();
}

return currentFile;
#endif
Expand Down
9 changes: 6 additions & 3 deletions examples/Plugins/AUv3SynthPluginDemo.h
Expand Up @@ -259,9 +259,9 @@ class AUv3SynthEditor : public AudioProcessorEditor,
//==============================================================================
AudioProcessorParameter* getParameter (const String& paramId)
{
if (auto* processor = getAudioProcessor())
if (auto* audioProcessor = getAudioProcessor())
{
auto& params = processor->getParameters();
auto& params = audioProcessor->getParameters();

for (auto p : params)
{
Expand Down Expand Up @@ -356,13 +356,14 @@ class AUv3SynthProcessor : public AudioProcessor
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; }
bool silenceInProducesSilenceOut() const override { return false; }
double getTailLengthSeconds() const override { return 0.0; }

//==============================================================================
Expand All @@ -383,6 +384,7 @@ class AUv3SynthProcessor : public AudioProcessor
case 1: return "Singing";
case 2: return "Pinched Balloon";
case 3: return "Gazeebo";
default: break;
}

return "<Unknown>";
Expand All @@ -408,6 +410,7 @@ class AUv3SynthProcessor : public AudioProcessor
roomSizeParam->setValueNotifyingHost (stream.readFloat());

}

private:
//==============================================================================
void loadNewSampleBinary (const void* data, int dataSize, const char* format)
Expand Down
4 changes: 3 additions & 1 deletion examples/Plugins/ArpeggiatorPluginDemo.h
Expand Up @@ -71,7 +71,7 @@ class Arpeggiator : public AudioProcessor
notes.clear();
currentNote = 0;
lastNoteValue = -1;
time = 0.0;
time = 0;
rate = static_cast<float> (sampleRate);
}

Expand Down Expand Up @@ -119,6 +119,8 @@ class Arpeggiator : public AudioProcessor
time = (time + numSamples) % noteDuration;
}

using AudioProcessor::processBlock;

//==============================================================================
bool isMidiEffect() const override { return true; }

Expand Down
2 changes: 1 addition & 1 deletion examples/Plugins/AudioPluginDemo.h
Expand Up @@ -275,7 +275,7 @@ class JuceDemoPluginAudioProcessor : public AudioProcessor
}

//==============================================================================
const String getName() const override { return JucePlugin_Name; }
const String getName() const override { return "AudioPluginDemo"; }
bool acceptsMidi() const override { return true; }
bool producesMidi() const override { return true; }
double getTailLengthSeconds() const override { return 0.0; }
Expand Down
4 changes: 3 additions & 1 deletion examples/Plugins/DSPModulePluginDemo.h
Expand Up @@ -198,6 +198,8 @@ class DspModulePluginDemoAudioProcessor : public AudioProcessor
}
}

using AudioProcessor::processBlock;

void reset() override
{
lowPassFilter .reset();
Expand All @@ -217,7 +219,7 @@ class DspModulePluginDemoAudioProcessor : public AudioProcessor
//==============================================================================
bool acceptsMidi() const override { return false; }
bool producesMidi() const override { return false; }
const String getName() const override { return JucePlugin_Name; }
const String getName() const override { return "DSPModulePluginDemo"; }
double getTailLengthSeconds() const override { return 0.0; }

//==============================================================================
Expand Down
5 changes: 5 additions & 0 deletions examples/Plugins/GainPluginDemo.h
Expand Up @@ -71,6 +71,11 @@ class GainProcessor : public AudioProcessor
buffer.applyGain (*gain);
}

void processBlock (AudioBuffer<double>& buffer, MidiBuffer&) override
{
buffer.applyGain ((float) *gain);
}

//==============================================================================
AudioProcessorEditor* createEditor() override { return new GenericAudioProcessorEditor (*this); }
bool hasEditor() const override { return true; }
Expand Down
4 changes: 1 addition & 3 deletions examples/Plugins/InterAppAudioEffectPluginDemo.h
Expand Up @@ -79,8 +79,6 @@ class SimpleMeter : public Component,
g.fillRoundedRectangle (area.toFloat(), 6.0);
}

void resized() override {}

//==============================================================================
// Called from the audio thread.
void update (float newLevel)
Expand Down Expand Up @@ -215,7 +213,7 @@ class IAAEffectProcessor : public AudioProcessor
bool hasEditor() const override { return true; }

//==============================================================================
const String getName() const override { return JucePlugin_Name; }
const String getName() const override { return "InterAppAudioEffectPlugin"; }
bool acceptsMidi() const override { return false; }
bool producesMidi() const override { return false; }
double getTailLengthSeconds() const override { return 0.0; }
Expand Down
117 changes: 62 additions & 55 deletions examples/Plugins/MidiLoggerPluginDemo.h
Expand Up @@ -73,12 +73,49 @@ class MidiQueue
std::vector<MidiMessage> messages = std::vector<MidiMessage> (queueSize);
};

// Stores the last N messages. Safe to access from the message thread only.
class MidiListModel
{
public:
template <typename It>
void addMessages (It begin, It end)
{
const auto numNewMessages = (int) std::distance (begin, end);
const auto numToAdd = juce::jmin (numToStore, numNewMessages);
const auto numToRemove = jmax (0, (int) messages.size() + numToAdd - numToStore);
messages.erase (messages.begin(), std::next (messages.begin(), numToRemove));
messages.insert (messages.end(), std::prev (end, numToAdd), end);

if (onChange != nullptr)
onChange();
}

void clear()
{
messages.clear();

if (onChange != nullptr)
onChange();
}

const MidiMessage& operator[] (size_t ind) const { return messages[ind]; }

size_t size() const { return messages.size(); }

std::function<void()> onChange;

private:
static constexpr auto numToStore = 1000;
std::vector<MidiMessage> messages;
};

//==============================================================================
class MidiTable : public Component,
private TableListBoxModel
{
public:
MidiTable()
MidiTable (MidiListModel& m)
: messages (m)
{
addAndMakeVisible (table);

Expand All @@ -92,26 +129,13 @@ class MidiTable : public Component,
header->addColumn ("Data", dataColumn, 200, 30, -1, TableHeaderComponent::notSortable);
return header;
}());
}

void resized() override { table.setBounds (getLocalBounds()); }

template <typename It>
void addMessages (It begin, It end)
{
const auto numNewMessages = (int) std::distance (begin, end);
const auto numToAdd = juce::jmin (numToStore, numNewMessages);
const auto numToRemove = jmax (0, (int) messages.size() + numToAdd - numToStore);
messages.erase (messages.begin(), std::next (messages.begin(), numToRemove));
messages.insert (messages.end(), end - numToAdd, end);
table.updateContent();
messages.onChange = [&] { table.updateContent(); };
}

void clear()
{
messages.clear();
table.updateContent();
}
~MidiTable() override { messages.onChange = nullptr; }

void resized() override { table.setBounds (getLocalBounds()); }

private:
enum
Expand Down Expand Up @@ -185,22 +209,24 @@ class MidiTable : public Component,
return {};
}

static constexpr auto numToStore = 1000;
std::vector<MidiMessage> messages;

MidiListModel& messages;
TableListBox table;
};

//==============================================================================
class MidiLoggerPluginDemoProcessor : public AudioPluginInstance
class MidiLoggerPluginDemoProcessor : public AudioProcessor,
private Timer
{
public:
MidiLoggerPluginDemoProcessor()
: AudioPluginInstance (BusesProperties())
: AudioProcessor (BusesProperties())
{
state.addChild ({ "uiState", { { "width", 500 }, { "height", 300 } }, {} }, -1, nullptr);
startTimerHz (60);
}

~MidiLoggerPluginDemoProcessor() override { stopTimer(); }

void processBlock (AudioBuffer<float>& audio, MidiBuffer& midi) override { process (audio, midi); }
void processBlock (AudioBuffer<double>& audio, MidiBuffer& midi) override { process (audio, midi); }

Expand All @@ -211,7 +237,7 @@ class MidiLoggerPluginDemoProcessor : public AudioPluginInstance

const String getName() const override { return "MIDILogger"; }
bool acceptsMidi() const override { return true; }
bool producesMidi() const override { return false; }
bool producesMidi() const override { return true; }
double getTailLengthSeconds() const override { return 0.0; }

int getNumPrograms() override { return 0; }
Expand All @@ -235,28 +261,15 @@ class MidiLoggerPluginDemoProcessor : public AudioPluginInstance
state = ValueTree::fromXml (*xmlState);
}

void fillInPluginDescription (PluginDescription& d) const override
{
d.name = getName();
d.uid = d.name.hashCode();
d.category = "Utility";
d.pluginFormatName = "Internal";
d.manufacturerName = "JUCE";
d.version = "1.0";
d.isInstrument = false;
d.numInputChannels = getTotalNumInputChannels();
d.numOutputChannels = getTotalNumOutputChannels();
}

private:
class Editor : public AudioProcessorEditor,
private Timer,
private Value::Listener
{
public:
explicit Editor (MidiLoggerPluginDemoProcessor& ownerIn)
: AudioProcessorEditor (ownerIn),
owner (ownerIn)
owner (ownerIn),
table (owner.model)
{
addAndMakeVisible (table);
addAndMakeVisible (clearButton);
Expand All @@ -269,15 +282,7 @@ class MidiLoggerPluginDemoProcessor : public AudioPluginInstance
lastUIWidth. addListener (this);
lastUIHeight.addListener (this);

clearButton.onClick = [&] { table.clear(); };

startTimerHz (60);
}

~Editor() override
{
stopTimer();
owner.editorBeingDeleted (this);
clearButton.onClick = [&] { owner.model.clear(); };
}

void paint (Graphics& g) override
Expand All @@ -297,13 +302,6 @@ class MidiLoggerPluginDemoProcessor : public AudioPluginInstance
}

private:
void timerCallback() override
{
std::vector<MidiMessage> messages;
owner.queue.pop (std::back_inserter (messages));
table.addMessages (messages.begin(), messages.end());
}

void valueChanged (Value&) override
{
setSize (lastUIWidth.getValue(), lastUIHeight.getValue());
Expand All @@ -317,6 +315,13 @@ class MidiLoggerPluginDemoProcessor : public AudioPluginInstance
Value lastUIWidth, lastUIHeight;
};

void timerCallback() override
{
std::vector<MidiMessage> messages;
queue.pop (std::back_inserter (messages));
model.addMessages (messages.begin(), messages.end());
}

template <typename Element>
void process (AudioBuffer<Element>& audio, MidiBuffer& midi)
{
Expand All @@ -326,6 +331,8 @@ class MidiLoggerPluginDemoProcessor : public AudioPluginInstance

ValueTree state { "state" };
MidiQueue queue;
MidiListModel model; // The data to show in the UI. We keep it around in the processor so that
// the view is persistent even when the plugin UI is closed and reopened.

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiLoggerPluginDemoProcessor)
};
2 changes: 2 additions & 0 deletions examples/Plugins/MultiOutSynthPluginDemo.h
Expand Up @@ -124,6 +124,8 @@ class MultiOutSynth : public AudioProcessor
}
}

using AudioProcessor::processBlock;

//==============================================================================
AudioProcessorEditor* createEditor() override { return new GenericAudioProcessorEditor (*this); }
bool hasEditor() const override { return true; }
Expand Down
2 changes: 2 additions & 0 deletions examples/Plugins/NoiseGatePluginDemo.h
Expand Up @@ -105,6 +105,8 @@ class NoiseGate : public AudioProcessor
}
}

using AudioProcessor::processBlock;

//==============================================================================
AudioProcessorEditor* createEditor() override { return new GenericAudioProcessorEditor (*this); }
bool hasEditor() const override { return true; }
Expand Down

0 comments on commit f20b93a

Please sign in to comment.