341 lines
11 KiB
C++
341 lines
11 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Project : VST SDK
|
|
//
|
|
// Category : Helpers
|
|
// Filename : public.sdk/source/vst/vstaudioprocessoralgo.h
|
|
// Created by : Steinberg, 04/2015
|
|
// Description : Helper algo for AudioBusBuffers
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
// This file is part of a Steinberg SDK. It is subject to the license terms
|
|
// in the LICENSE file found in the top-level directory of this distribution
|
|
// and at www.steinberg.net/sdklicenses.
|
|
// No part of the SDK, including this file, may be copied, modified, propagated,
|
|
// or distributed except according to the terms contained in the LICENSE file.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
|
|
#include "pluginterfaces/vst/ivstaudioprocessor.h"
|
|
#include "pluginterfaces/vst/ivstevents.h"
|
|
#include "pluginterfaces/vst/ivstparameterchanges.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
namespace Steinberg {
|
|
namespace Vst {
|
|
|
|
//---helpers---------
|
|
/** Returns the current channelBuffers used (depending of symbolicSampleSize). */
|
|
inline void** getChannelBuffersPointer (const ProcessSetup& processSetup,
|
|
const AudioBusBuffers& bufs)
|
|
{
|
|
if (processSetup.symbolicSampleSize == kSample32)
|
|
return (void**)bufs.channelBuffers32;
|
|
return (void**)bufs.channelBuffers64;
|
|
}
|
|
|
|
/** Returns the size in bytes of numSamples for one channel depending of symbolicSampleSize.*/
|
|
inline uint32 getSampleFramesSizeInBytes (const ProcessSetup& processSetup, int32 numSamples)
|
|
{
|
|
if (processSetup.symbolicSampleSize == kSample32)
|
|
return numSamples * sizeof (Sample32);
|
|
return numSamples * sizeof (Sample64);
|
|
}
|
|
|
|
/** return the bit-mask of channels for the given number of channel
|
|
* for example:
|
|
* numChannels = 1 => 0b0001 (binar) = 0x01 = 1 (decimal)
|
|
* numChannels = 2 => 0b0011 (binar) = 0x03 = 3 (decimal)
|
|
* numChannels = 6 => 0b0011 1111 (binar) = 0x3F = 63 (decimal)
|
|
*/
|
|
inline uint64 getChannelMask (int32 numChannels)
|
|
{
|
|
if (numChannels >= 64)
|
|
return kMaxInt64u;
|
|
|
|
return ((uint64)1 << numChannels) - 1;
|
|
}
|
|
|
|
namespace Algo {
|
|
|
|
//------------------------------------------------------------------------
|
|
template <typename T>
|
|
inline void foreach (AudioBusBuffers* audioBusBuffers, int32 busCount, const T& func)
|
|
{
|
|
if (!audioBusBuffers)
|
|
return;
|
|
|
|
for (int32 busIndex = 0; busIndex < busCount; ++busIndex)
|
|
{
|
|
func (audioBusBuffers[busIndex]);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
template <typename T>
|
|
inline void foreach32 (AudioBusBuffers& audioBuffer, const T& func)
|
|
{
|
|
for (int32 channelIndex = 0; channelIndex < audioBuffer.numChannels; ++channelIndex)
|
|
{
|
|
if (!audioBuffer.channelBuffers32[channelIndex])
|
|
return;
|
|
|
|
func (audioBuffer.channelBuffers32[channelIndex]);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
template <typename T>
|
|
inline void foreach64 (AudioBusBuffers& audioBuffer, const T& func)
|
|
{
|
|
for (int32 channelIndex = 0; channelIndex < audioBuffer.numChannels; ++channelIndex)
|
|
{
|
|
if (!audioBuffer.channelBuffers64[channelIndex])
|
|
return;
|
|
|
|
func (audioBuffer.channelBuffers64[channelIndex]);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
template <typename T>
|
|
inline void foreach32 (AudioBusBuffers& buffer1, AudioBusBuffers& buffer2, const T& func)
|
|
{
|
|
int32 numChannels = std::min<int32> (buffer1.numChannels, buffer2.numChannels);
|
|
|
|
for (int32 channelIndex = 0; channelIndex < numChannels; ++channelIndex)
|
|
{
|
|
func (buffer1.channelBuffers32[channelIndex], buffer2.channelBuffers32[channelIndex],
|
|
channelIndex);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
template <typename T>
|
|
inline void foreach64 (AudioBusBuffers& buffer1, AudioBusBuffers& buffer2, const T& func)
|
|
{
|
|
int32 numChannels = std::min<int32> (buffer1.numChannels, buffer2.numChannels);
|
|
|
|
for (int32 channelIndex = 0; channelIndex < numChannels; ++channelIndex)
|
|
{
|
|
func (buffer1.channelBuffers64[channelIndex], buffer2.channelBuffers64[channelIndex],
|
|
channelIndex);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
inline void copy32 (AudioBusBuffers* src, AudioBusBuffers* dest, int32 sliceSize, int32 startIndex)
|
|
{
|
|
if (!src || !dest)
|
|
return;
|
|
|
|
int32 numChannels = std::min<int32> (src->numChannels, dest->numChannels);
|
|
size_t numBytes = sliceSize * sizeof (Sample32);
|
|
for (int32 chIdx = 0; chIdx < numChannels; ++chIdx)
|
|
{
|
|
memcpy (&dest->channelBuffers32[chIdx][startIndex], src->channelBuffers32[chIdx], numBytes);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
inline void copy64 (AudioBusBuffers* src, AudioBusBuffers* dest, int32 sliceSize, int32 startIndex)
|
|
{
|
|
if (!src || !dest)
|
|
return;
|
|
|
|
int32 numChannels = std::min<int32> (src->numChannels, dest->numChannels);
|
|
size_t numBytes = sliceSize * sizeof (Sample64);
|
|
for (int32 chIdx = 0; chIdx < numChannels; ++chIdx)
|
|
{
|
|
memcpy (&dest->channelBuffers64[chIdx][startIndex], src->channelBuffers64[chIdx], numBytes);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
inline void clear32 (AudioBusBuffers* audioBusBuffers, int32 sampleCount, int32 busCount = 1)
|
|
{
|
|
if (!audioBusBuffers)
|
|
return;
|
|
|
|
const int32 numBytes = sampleCount * sizeof (Sample32);
|
|
foreach (audioBusBuffers, busCount, [&] (AudioBusBuffers& audioBuffer) {
|
|
foreach32 (audioBuffer,
|
|
[&] (Sample32* channelBuffer) { memset (channelBuffer, 0, numBytes); });
|
|
});
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
inline void clear64 (AudioBusBuffers* audioBusBuffers, int32 sampleCount, int32 busCount = 1)
|
|
{
|
|
if (!audioBusBuffers)
|
|
return;
|
|
|
|
const int32 numBytes = sampleCount * sizeof (Sample64);
|
|
foreach (audioBusBuffers, busCount, [&] (AudioBusBuffers& audioBuffer) {
|
|
foreach64 (audioBuffer,
|
|
[&] (Sample64* channelBuffer) { memset (channelBuffer, 0, numBytes); });
|
|
});
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
inline void mix32 (AudioBusBuffers& src, AudioBusBuffers& dest, int32 sampleCount)
|
|
{
|
|
foreach32 (src, dest, [&] (Sample32* srcBuffer, Sample32* destBuffer, int32 /*channelIndex*/) {
|
|
for (int32 sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex)
|
|
destBuffer[sampleIndex] += srcBuffer[sampleIndex];
|
|
});
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
inline void mix64 (AudioBusBuffers& src, AudioBusBuffers& dest, int32 sampleCount)
|
|
{
|
|
foreach64 (src, dest, [&] (Sample64* srcBuffer, Sample64* destBuffer, int32 /*channelIndex*/) {
|
|
for (int32 sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex)
|
|
destBuffer[sampleIndex] += srcBuffer[sampleIndex];
|
|
});
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
/* Multiply buffer with a constant */
|
|
template <typename T>
|
|
inline void multiply(T* srcBuffer, T* destBuffer, int32 sampleCount, T factor)
|
|
{
|
|
for (int32 sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex)
|
|
destBuffer[sampleIndex] = srcBuffer[sampleIndex] * factor;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
/* Multiply all channels of AudioBusBuffer with a constant */
|
|
inline void multiply32 (AudioBusBuffers& src, AudioBusBuffers& dest, int32 sampleCount, float factor)
|
|
{
|
|
foreach32 (src, dest, [&](Sample32* srcBuffer, Sample32* destBuffer, int32 /*channelIndex*/) {
|
|
multiply (srcBuffer, destBuffer, sampleCount, factor);
|
|
});
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
/* Multiply all channels of AudioBusBuffer with a constant */
|
|
inline void multiply64 (AudioBusBuffers& src, AudioBusBuffers& dest, int32 sampleCount, double factor)
|
|
{
|
|
foreach64 (src, dest, [&] (Sample64* srcBuffer, Sample64* destBuffer, int32 /*channelIndex*/) {
|
|
multiply (srcBuffer, destBuffer, sampleCount, factor);
|
|
});
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
inline bool isSilent32 (AudioBusBuffers& audioBuffer, int32 sampleCount, int32 startIndex = 0)
|
|
{
|
|
const float epsilon = 1e-10f; // under -200dB...
|
|
|
|
sampleCount += startIndex;
|
|
for (int32 channelIndex = 0; channelIndex < audioBuffer.numChannels; ++channelIndex)
|
|
{
|
|
if (!audioBuffer.channelBuffers32[channelIndex])
|
|
return true;
|
|
|
|
for (int32 sampleIndex = startIndex; sampleIndex < sampleCount; ++sampleIndex)
|
|
{
|
|
float val = audioBuffer.channelBuffers32[channelIndex][sampleIndex];
|
|
if (std::abs (val) > epsilon)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
inline bool isSilent64 (AudioBusBuffers& audioBuffer, int32 sampleCount, int32 startIndex = 0)
|
|
{
|
|
const double epsilon = 1e-10f; // under -200dB...
|
|
|
|
sampleCount += startIndex;
|
|
for (int32 channelIndex = 0; channelIndex < audioBuffer.numChannels; ++channelIndex)
|
|
{
|
|
if (!audioBuffer.channelBuffers64[channelIndex])
|
|
return true;
|
|
|
|
for (int32 sampleIndex = startIndex; sampleIndex < sampleCount; ++sampleIndex)
|
|
{
|
|
double val = audioBuffer.channelBuffers64[channelIndex][sampleIndex];
|
|
if (std::abs (val) > epsilon)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
//------------------------------------------------------------------------
|
|
template <typename T>
|
|
inline void foreach (IEventList* eventList, const T& func)
|
|
{
|
|
if (!eventList)
|
|
return;
|
|
|
|
auto eventCount = eventList->getEventCount ();
|
|
for (int32 eventIndex = 0; eventIndex < eventCount; ++eventIndex)
|
|
{
|
|
Vst::Event event = {};
|
|
if (eventList->getEvent (eventIndex, event) != kResultOk)
|
|
continue;
|
|
|
|
func (event);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
template <typename T>
|
|
inline void foreach (IParamValueQueue& paramQueue, const T& func)
|
|
{
|
|
auto paramId = paramQueue.getParameterId ();
|
|
auto numPoints = paramQueue.getPointCount ();
|
|
for (int32 pointIndex = 0; pointIndex < numPoints; ++pointIndex)
|
|
{
|
|
int32 sampleOffset = 0;
|
|
ParamValue value = 0;
|
|
if (paramQueue.getPoint (pointIndex, sampleOffset, value) != kResultOk)
|
|
continue;
|
|
|
|
func (paramId, sampleOffset, value);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
template <typename T>
|
|
inline void foreachLast (IParamValueQueue& paramQueue, const T& func)
|
|
{
|
|
auto paramId = paramQueue.getParameterId ();
|
|
auto numPoints = paramQueue.getPointCount ();
|
|
int32 sampleOffset = 0;
|
|
ParamValue value = 0;
|
|
if (paramQueue.getPoint (numPoints - 1, sampleOffset, value) == kResultOk)
|
|
func (paramId, sampleOffset, value);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
template <typename T>
|
|
inline void foreach (IParameterChanges* changes, const T& func)
|
|
{
|
|
if (!changes)
|
|
return;
|
|
|
|
auto paramCount = changes->getParameterCount ();
|
|
for (int32 paramIndex = 0; paramIndex < paramCount; ++paramIndex)
|
|
{
|
|
auto paramValueQueue = changes->getParameterData (paramIndex);
|
|
if (!paramValueQueue)
|
|
continue;
|
|
|
|
func (*paramValueQueue);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
} // namespace Algo
|
|
} // namespace Vst
|
|
} // namespace Steinberg
|