//----------------------------------------------------------------------------- // 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 #include 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 inline void foreach (AudioBusBuffers* audioBusBuffers, int32 busCount, const T& func) { if (!audioBusBuffers) return; for (int32 busIndex = 0; busIndex < busCount; ++busIndex) { func (audioBusBuffers[busIndex]); } } //------------------------------------------------------------------------ template 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 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 inline void foreach32 (AudioBusBuffers& buffer1, AudioBusBuffers& buffer2, const T& func) { int32 numChannels = std::min (buffer1.numChannels, buffer2.numChannels); for (int32 channelIndex = 0; channelIndex < numChannels; ++channelIndex) { func (buffer1.channelBuffers32[channelIndex], buffer2.channelBuffers32[channelIndex], channelIndex); } } //------------------------------------------------------------------------ template inline void foreach64 (AudioBusBuffers& buffer1, AudioBusBuffers& buffer2, const T& func) { int32 numChannels = std::min (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 (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 (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 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 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 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 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 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