mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Converted AudioSampleBuffer into a templated class that can use either float or double types. Used this to implement 64-bit audio plugin support in VST and AU
This commit is contained in:
parent
ba672f03fb
commit
c562cfc3cc
27 changed files with 1713 additions and 1104 deletions
|
|
@ -85,7 +85,20 @@ public:
|
|||
// not interested in controllers in this case.
|
||||
}
|
||||
|
||||
void renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples) override
|
||||
void renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples) override
|
||||
{
|
||||
processBlock (outputBuffer, startSample, numSamples);
|
||||
}
|
||||
|
||||
void renderNextBlock (AudioBuffer<double>& outputBuffer, int startSample, int numSamples) override
|
||||
{
|
||||
processBlock (outputBuffer, startSample, numSamples);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <typename FloatType>
|
||||
void processBlock (AudioBuffer<FloatType>& outputBuffer, int startSample, int numSamples)
|
||||
{
|
||||
if (angleDelta != 0.0)
|
||||
{
|
||||
|
|
@ -93,7 +106,8 @@ public:
|
|||
{
|
||||
while (--numSamples >= 0)
|
||||
{
|
||||
const float currentSample = (float) (sin (currentAngle) * level * tailOff);
|
||||
const FloatType currentSample =
|
||||
static_cast<FloatType> (std::sin (currentAngle) * level * tailOff);
|
||||
|
||||
for (int i = outputBuffer.getNumChannels(); --i >= 0;)
|
||||
outputBuffer.addSample (i, startSample, currentSample);
|
||||
|
|
@ -116,7 +130,7 @@ public:
|
|||
{
|
||||
while (--numSamples >= 0)
|
||||
{
|
||||
const float currentSample = (float) (sin (currentAngle) * level);
|
||||
const FloatType currentSample = static_cast<FloatType> (std::sin (currentAngle) * level);
|
||||
|
||||
for (int i = outputBuffer.getNumChannels(); --i >= 0;)
|
||||
outputBuffer.addSample (i, startSample, currentSample);
|
||||
|
|
@ -128,7 +142,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
private:
|
||||
double currentAngle, angleDelta, level, tailOff;
|
||||
};
|
||||
|
||||
|
|
@ -183,7 +196,6 @@ const float defaultDelay = 0.5f;
|
|||
|
||||
//==============================================================================
|
||||
JuceDemoPluginAudioProcessor::JuceDemoPluginAudioProcessor()
|
||||
: delayBuffer (2, 12000)
|
||||
{
|
||||
// Set up our parameters. The base class will delete them for us.
|
||||
addParameter (gain = new FloatParameter (defaultGain, "Gain"));
|
||||
|
|
@ -213,7 +225,19 @@ void JuceDemoPluginAudioProcessor::prepareToPlay (double newSampleRate, int /*sa
|
|||
// initialisation that you need..
|
||||
synth.setCurrentPlaybackSampleRate (newSampleRate);
|
||||
keyboardState.reset();
|
||||
delayBuffer.clear();
|
||||
|
||||
if (isUsingDoublePrecision())
|
||||
{
|
||||
delayBufferDouble.setSize (2, 12000);
|
||||
delayBufferFloat.setSize (1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
delayBufferFloat.setSize (2, 12000);
|
||||
delayBufferDouble.setSize (1, 1);
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void JuceDemoPluginAudioProcessor::releaseResources()
|
||||
|
|
@ -227,17 +251,21 @@ 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();
|
||||
delayBufferFloat.clear();
|
||||
delayBufferDouble.clear();
|
||||
}
|
||||
|
||||
void JuceDemoPluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
|
||||
template <typename FloatType>
|
||||
void JuceDemoPluginAudioProcessor::process (AudioBuffer<FloatType>& buffer,
|
||||
MidiBuffer& midiMessages,
|
||||
AudioBuffer<FloatType>& delayBuffer)
|
||||
{
|
||||
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->getValue());
|
||||
buffer.applyGain (channel, 0, buffer.getNumSamples(), static_cast<FloatType> (gain->getValue()));
|
||||
|
||||
// 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
|
||||
|
|
@ -249,15 +277,16 @@ void JuceDemoPluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, Midi
|
|||
// Apply our delay effect to the new output..
|
||||
for (channel = 0; channel < getNumInputChannels(); ++channel)
|
||||
{
|
||||
float* channelData = buffer.getWritePointer (channel);
|
||||
float* delayData = delayBuffer.getWritePointer (jmin (channel, delayBuffer.getNumChannels() - 1));
|
||||
FloatType* channelData = buffer.getWritePointer (channel);
|
||||
FloatType* delayData = delayBuffer.getWritePointer (jmin (channel, delayBuffer.getNumChannels() - 1));
|
||||
dp = delayPosition;
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
const float in = channelData[i];
|
||||
const FloatType in = channelData[i];
|
||||
channelData[i] += delayData[dp];
|
||||
delayData[dp] = (delayData[dp] + in) * delay->getValue();
|
||||
delayData[dp] = (delayData[dp] + in) * static_cast<FloatType> (delay->getValue());
|
||||
|
||||
if (++dp >= delayBuffer.getNumSamples())
|
||||
dp = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,13 +28,28 @@ public:
|
|||
//==============================================================================
|
||||
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
|
||||
void releaseResources() override;
|
||||
void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) override;
|
||||
void reset() override;
|
||||
|
||||
//==============================================================================
|
||||
void processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages) override
|
||||
{
|
||||
jassert (! isUsingDoublePrecision());
|
||||
process (buffer, midiMessages, delayBufferFloat);
|
||||
}
|
||||
|
||||
void processBlock (AudioBuffer<double>& buffer, MidiBuffer& midiMessages) override
|
||||
{
|
||||
jassert (isUsingDoublePrecision());
|
||||
process (buffer, midiMessages, delayBufferDouble);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool hasEditor() const override { return true; }
|
||||
AudioProcessorEditor* createEditor() override;
|
||||
|
||||
//==============================================================================
|
||||
bool supportsDoublePrecisionProcessing() const override { return true; }
|
||||
|
||||
//==============================================================================
|
||||
const String getName() const override { return JucePlugin_Name; }
|
||||
|
||||
|
|
@ -83,7 +98,11 @@ public:
|
|||
|
||||
private:
|
||||
//==============================================================================
|
||||
AudioSampleBuffer delayBuffer;
|
||||
template <typename floatType>
|
||||
void process (AudioBuffer<floatType>& buffer, MidiBuffer& midiMessages, AudioBuffer<floatType>& delayBuffer);
|
||||
|
||||
AudioBuffer<float> delayBufferFloat;
|
||||
AudioBuffer<double> delayBufferDouble;
|
||||
int delayPosition;
|
||||
|
||||
// the synth!
|
||||
|
|
|
|||
|
|
@ -1087,7 +1087,8 @@ private:
|
|||
//==============================================================================
|
||||
GraphDocumentComponent::GraphDocumentComponent (AudioPluginFormatManager& formatManager,
|
||||
AudioDeviceManager* deviceManager_)
|
||||
: graph (formatManager), deviceManager (deviceManager_)
|
||||
: graph (formatManager), deviceManager (deviceManager_),
|
||||
graphPlayer (getAppProperties().getUserSettings()->getBoolValue ("doublePrecisionProcessing", false))
|
||||
{
|
||||
addAndMakeVisible (graphPanel = new GraphEditorPanel (graph));
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ public:
|
|||
|
||||
//==============================================================================
|
||||
void createNewPlugin (const PluginDescription* desc, int x, int y);
|
||||
inline void setDoublePrecision (bool doublePrecision) { graphPlayer.setDoublePrecisionProcessing (doublePrecision); }
|
||||
|
||||
//==============================================================================
|
||||
FilterGraph graph;
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@ PopupMenu MainHostWindow::getMenuForIndex (int topLevelMenuIndex, const String&
|
|||
|
||||
menu.addSeparator();
|
||||
menu.addCommandItem (&getCommandManager(), CommandIDs::showAudioSettings);
|
||||
menu.addCommandItem (&getCommandManager(), CommandIDs::toggleDoublePrecision);
|
||||
|
||||
menu.addSeparator();
|
||||
menu.addCommandItem (&getCommandManager(), CommandIDs::aboutBox);
|
||||
|
|
@ -331,6 +332,7 @@ void MainHostWindow::getAllCommands (Array <CommandID>& commands)
|
|||
CommandIDs::saveAs,
|
||||
CommandIDs::showPluginListEditor,
|
||||
CommandIDs::showAudioSettings,
|
||||
CommandIDs::toggleDoublePrecision,
|
||||
CommandIDs::aboutBox,
|
||||
CommandIDs::allWindowsForward
|
||||
};
|
||||
|
|
@ -376,6 +378,10 @@ void MainHostWindow::getCommandInfo (const CommandID commandID, ApplicationComma
|
|||
result.addDefaultKeypress ('a', ModifierKeys::commandModifier);
|
||||
break;
|
||||
|
||||
case CommandIDs::toggleDoublePrecision:
|
||||
updatePrecisionMenuItem (result);
|
||||
break;
|
||||
|
||||
case CommandIDs::aboutBox:
|
||||
result.setInfo ("About...", String::empty, category, 0);
|
||||
break;
|
||||
|
|
@ -427,6 +433,23 @@ bool MainHostWindow::perform (const InvocationInfo& info)
|
|||
showAudioSettings();
|
||||
break;
|
||||
|
||||
case CommandIDs::toggleDoublePrecision:
|
||||
if (PropertiesFile* props = getAppProperties().getUserSettings())
|
||||
{
|
||||
bool newIsDoublePrecision = ! isDoublePrecisionProcessing();
|
||||
props->setValue ("doublePrecisionProcessing", var (newIsDoublePrecision));
|
||||
|
||||
{
|
||||
ApplicationCommandInfo cmdInfo (info.commandID);
|
||||
updatePrecisionMenuItem (cmdInfo);
|
||||
menuItemsChanged();
|
||||
}
|
||||
|
||||
if (graphEditor != nullptr)
|
||||
graphEditor->setDoublePrecision (newIsDoublePrecision);
|
||||
}
|
||||
break;
|
||||
|
||||
case CommandIDs::aboutBox:
|
||||
// TODO
|
||||
break;
|
||||
|
|
@ -524,3 +547,17 @@ GraphDocumentComponent* MainHostWindow::getGraphEditor() const
|
|||
{
|
||||
return dynamic_cast <GraphDocumentComponent*> (getContentComponent());
|
||||
}
|
||||
|
||||
bool MainHostWindow::isDoublePrecisionProcessing()
|
||||
{
|
||||
if (PropertiesFile* props = getAppProperties().getUserSettings())
|
||||
return props->getBoolValue ("doublePrecisionProcessing", false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MainHostWindow::updatePrecisionMenuItem (ApplicationCommandInfo& info)
|
||||
{
|
||||
info.setInfo ("Double floating point precision rendering", String::empty, "General", 0);
|
||||
info.setTicked (isDoublePrecisionProcessing());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ namespace CommandIDs
|
|||
static const int showAudioSettings = 0x30200;
|
||||
static const int aboutBox = 0x30300;
|
||||
static const int allWindowsForward = 0x30400;
|
||||
static const int toggleDoublePrecision = 0x30500;
|
||||
}
|
||||
|
||||
ApplicationCommandManager& getCommandManager();
|
||||
|
|
@ -86,6 +87,9 @@ public:
|
|||
|
||||
GraphDocumentComponent* getGraphEditor() const;
|
||||
|
||||
bool isDoublePrecisionProcessing();
|
||||
void updatePrecisionMenuItem (ApplicationCommandInfo& info);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
AudioDeviceManager deviceManager;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue