Continuing on specifically from the previous thread Having some confusion with PGM - #17 by Digital_Larry
I have whittled down the Faust generated cpp file (which includes all header info as well) to those functions which mention “magic” somehow.
/* ------------------------------------------------------------
author: "Gary Worsham"
copyright: "(c) Gary Worsham 2021"
license: "none"
name: "Harmonic Tremolo"
version: "0.95"
Code generated with Faust 2.32.17 (https://faust.grame.fr)
Compilation options: -a /usr/local/share/faust/juce/juce-plugin.cpp -lang cpp -es 1 -single -ftz 0
------------------------------------------------------------ */
// Using the PluginGuiMagic project (https://foleysfinest.com/developer/pluginguimagic/)
#if defined(PLUGIN_MAGIC)
class FaustPlugInAudioProcessor : public foleys::MagicProcessor, private juce::Timer
{
public:
// juce::AudioProcessorValueTreeState treeState{ *this, nullptr };
FaustPlugInAudioProcessor();
virtual ~FaustPlugInAudioProcessor() {}
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
bool isBusesLayoutSupported (const BusesLayout& layouts) const override;
void processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages) override
{
jassert (! isUsingDoublePrecision());
process (buffer, midiMessages);
}
void processBlock (juce::AudioBuffer<double>& buffer, juce::MidiBuffer& midiMessages) override
{
jassert (isUsingDoublePrecision());
process (buffer, midiMessages);
}
const juce::String getName() const override;
bool acceptsMidi() const override;
bool producesMidi() const override;
double getTailLengthSeconds() const override;
int getNumPrograms() override;
int getCurrentProgram() override;
void setCurrentProgram (int index) override;
const juce::String getProgramName (int index) override;
void changeProgramName (int index, const juce::String& newName) override;
void releaseResources() override
{}
void timerCallback() override;
juce::AudioProcessor::BusesProperties getBusesProperties();
bool supportsDoublePrecisionProcessing() const override;
#ifdef JUCE_POLY
std::unique_ptr<FaustSynthesiser> fSynth;
#else
#if defined(MIDICTRL)
std::unique_ptr<juce_midi_handler> fMIDIHandler;
std::unique_ptr<MidiUI> fMIDIUI;
#endif
std::unique_ptr<faustdsp> fDSP;
#endif
#if defined(OSCCTRL)
std::unique_ptr<JuceOSCUI> fOSCUI;
#endif
#if defined(SOUNDFILE)
std::unique_ptr<SoundUI> fSoundUI;
#endif
JuceStateUI fStateUI;
JuceParameterUI fParameterUI;
private:
template <typename FloatType>
void process (juce::AudioBuffer<FloatType>& buffer, juce::MidiBuffer& midiMessages);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FaustPlugInAudioProcessor)
};
#else
...
};
#endif
#ifndef PLUGIN_MAGIC
FaustPlugInAudioProcessor::FaustPlugInAudioProcessor()
: juce::AudioProcessor (getBusesProperties()), fParameterUI(this)
#else
FaustPlugInAudioProcessor::FaustPlugInAudioProcessor()
: foleys::MagicProcessor (getBusesProperties()), fParameterUI(this)
#endif
{
bool midi_sync = false;
int nvoices = 0;
mydsp* tmp_dsp = new mydsp();
MidiMeta::analyse(tmp_dsp, midi_sync, nvoices);
delete tmp_dsp;
#ifdef PLUGIN_MAGIC
// Digital Larry - I added these two lines and commented out the following one
// to see if it has any effect on the load XML function.
auto defaultGUI = magicState.createDefaultGUITree();
magicState.setGuiValueTree(defaultGUI);
// magicState.setGuiValueTree(BinaryData::magic_xml, BinaryData::magic_xmlSize);
#endif
...
}
#ifndef PLUGIN_MAGIC
bool FaustPlugInAudioProcessor::hasEditor() const
{
return true;
}
//==============================================================================
juce::AudioProcessorEditor* FaustPlugInAudioProcessor::createEditor()
{
// You add the XML into BinaryData later. At the beginning just leave those
// arguments out and you get a default generated editor.
// return new foleys::MagicPluginEditor(magicState, BinaryData::magic_xml, BinaryData::magic_xmlSize);
return new FaustPlugInAudioProcessorEditor (*this);
}
//==============================================================================
void FaustPlugInAudioProcessor::getStateInformation (juce::MemoryBlock& destData)
{
// You should use this method to store your parameters in the memory block.
// You could do that either as raw data, or use the XML or ValueTree classes
// as intermediaries to make it easy to save and load complex data.
fStateUI.getStateInformation(destData);
}
void FaustPlugInAudioProcessor::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.
fStateUI.setStateInformation(data, sizeInBytes);
}
#endif
Here is the Signal Generator .cpp and .h files similarly edited.
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin processor.
==============================================================================
*/
#include "PluginProcessor.h"
//==============================================================================
SignalGeneratorAudioProcessor::SignalGeneratorAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
: foleys::MagicProcessor (juce::AudioProcessor::BusesProperties()
#if ! JucePlugin_IsMidiEffect
#if ! JucePlugin_IsSynth
.withInput ("Input", juce::AudioChannelSet::stereo(), true)
#endif
.withOutput ("Output", juce::AudioChannelSet::stereo(), true)
#endif
),
#else
:
#endif
treeState (*this, nullptr, "PARAMETERS", createParameterLayout())
{
frequency = treeState.getRawParameterValue (IDs::mainFreq);
jassert (frequency != nullptr);
level = treeState.getRawParameterValue (IDs::mainLevel);
jassert (level != nullptr);
lfoFrequency = treeState.getRawParameterValue (IDs::lfoFreq);
jassert (lfoFrequency != nullptr);
lfoLevel = treeState.getRawParameterValue (IDs::lfoLevel);
jassert (lfoLevel != nullptr);
vfoFrequency = treeState.getRawParameterValue (IDs::vfoFreq);
jassert (vfoFrequency != nullptr);
vfoLevel = treeState.getRawParameterValue (IDs::vfoLevel);
jassert (vfoLevel != nullptr);
treeState.addParameterListener (IDs::mainType, this);
treeState.addParameterListener (IDs::lfoType, this);
treeState.addParameterListener (IDs::vfoType, this);
// MAGIC GUI: register an oscilloscope to display in the GUI.
// We keep a pointer to push samples into in processBlock().
// And we are only interested in channel 0
oscilloscope = magicState.createAndAddObject<foleys::MagicOscilloscope>(IDs::oscilloscope, 0);
// Digital Larry - I added these two lines and commented out the following one
// to see if it has any effect on the load XML function.
auto defaultGUI = magicState.createDefaultGUITree();
magicState.setGuiValueTree(defaultGUI);
// magicState.setGuiValueTree (BinaryData::magic_xml, BinaryData::magic_xmlSize);
}
void SignalGeneratorAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
// Use this method as the place to do any pre-playback
// initialisation that you need..
const auto numChannels = getTotalNumOutputChannels();
juce::dsp::ProcessSpec spec;
spec.sampleRate = sampleRate;
spec.maximumBlockSize = juce::uint32 (samplesPerBlock);
spec.numChannels = juce::uint32 (numChannels);
mainOSC.prepare (spec);
lfoOSC.prepare (spec);
vfoOSC.prepare (spec);
setOscillator (mainOSC, WaveType (juce::roundToInt (treeState.getRawParameterValue (IDs::mainType)->load())));
setOscillator (lfoOSC, WaveType (juce::roundToInt (treeState.getRawParameterValue (IDs::lfoType)->load())));
setOscillator (vfoOSC, WaveType (juce::roundToInt (treeState.getRawParameterValue (IDs::vfoType)->load())));
// MAGIC GUI: this will setup all internals like MagicPlotSources etc.
magicState.prepareToPlay (sampleRate, samplesPerBlock);
}
void SignalGeneratorAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
ignoreUnused (midiMessages);
juce::ScopedNoDenormals noDenormals;
auto totalNumInputChannels = getTotalNumInputChannels();
auto totalNumOutputChannels = getTotalNumOutputChannels();
// In case we have more outputs than inputs, this code clears any output
// channels that didn't contain input data, (because these aren't
// guaranteed to be empty - they may contain garbage).
// This is here to avoid people getting screaming feedback
// when they first compile a plugin, but obviously you don't need to keep
// this code if your algorithm always overwrites all the output channels.
for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
buffer.clear (i, 0, buffer.getNumSamples());
auto gain = juce::Decibels::decibelsToGain (level->load());
lfoOSC.setFrequency (*lfoFrequency);
vfoOSC.setFrequency (*vfoFrequency);
auto* channelData = buffer.getWritePointer (0);
for (int i = 0; i < buffer.getNumSamples(); ++i)
{
mainOSC.setFrequency (frequency->load() * (1.0 + vfoOSC.processSample (0.0f) * vfoLevel->load()));
channelData [i] = juce::jlimit (-1.0f, 1.0f,
mainOSC.processSample (0.0f) * gain * ( 1.0f - (lfoLevel->load() * lfoOSC.processSample (0.0f))));
}
for (int i=1; i < getTotalNumOutputChannels(); ++i)
buffer.copyFrom (i, 0, buffer.getReadPointer (0), buffer.getNumSamples());
// MAGIC GUI: push the samples to be displayed
oscilloscope->pushSamples (buffer);
}
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin processor.
==============================================================================
*/
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
//==============================================================================
/**
*/
class SignalGeneratorAudioProcessor : public foleys::MagicProcessor,
private juce::AudioProcessorValueTreeState::Listener
{
public:
enum WaveType
{
None = 0,
Sine,
Triangle,
Square
};
//==============================================================================
SignalGeneratorAudioProcessor();
~SignalGeneratorAudioProcessor();
//==============================================================================
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
void releaseResources() override;
#ifndef JucePlugin_PreferredChannelConfigurations
bool isBusesLayoutSupported (const juce::AudioProcessor::BusesLayout& layouts) const override;
#endif
void parameterChanged (const juce::String& param, float value) override;
void processBlock (juce::AudioBuffer<float>&, juce::MidiBuffer&) override;
//==============================================================================
double getTailLengthSeconds() const override;
private:
//==============================================================================
void setOscillator (juce::dsp::Oscillator<float>& osc, WaveType type);
std::atomic<float>* frequency = nullptr;
std::atomic<float>* level = nullptr;
std::atomic<float>* lfoFrequency = nullptr;
std::atomic<float>* lfoLevel = nullptr;
std::atomic<float>* vfoFrequency = nullptr;
std::atomic<float>* vfoLevel = nullptr;
juce::dsp::Oscillator<float> mainOSC;
juce::dsp::Oscillator<float> lfoOSC;
juce::dsp::Oscillator<float> vfoOSC;
juce::AudioProcessorValueTreeState treeState;
// MAGIC GUI: this is a shorthand where the samples to display are fed to
foleys::MagicPlotSource* oscilloscope = nullptr;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SignalGeneratorAudioProcessor)
};
There are some differences.
This, I attribute to the Signal Generator loading binary resources, while I have not yet done that.
// Digital Larry - I added these two lines and commented out the following one
// to see if it has any effect on the load XML function.
auto defaultGUI = magicState.createDefaultGUITree();
magicState.setGuiValueTree(defaultGUI);
// magicState.setGuiValueTree (BinaryData::magic_xml, BinaryData::magic_xmlSize);
The are several other places also where specific calls are made to support the plot component which I do not have. It’s still not leaping out at me as to what I’ve done wrong.