//----------------------------------------------------------------------------- // Project : VST SDK // // Category : Helpers // Filename : public.sdk/source/vst/hosting/parameterchanges.cpp // Created by : Steinberg, 03/05/2008. // Description : VST 3 parameter changes implementation // //----------------------------------------------------------------------------- // 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. //----------------------------------------------------------------------------- #include "parameterchanges.h" namespace Steinberg { namespace Vst { //----------------------------------------------------------------------------- IMPLEMENT_FUNKNOWN_METHODS (ParameterChanges, IParameterChanges, IParameterChanges::iid) IMPLEMENT_FUNKNOWN_METHODS (ParameterValueQueue, IParamValueQueue, IParamValueQueue::iid) constexpr int32 kQueueReservedPoints = 5; //----------------------------------------------------------------------------- ParameterValueQueue::ParameterValueQueue (ParamID paramID) : paramID (paramID) { values.reserve (kQueueReservedPoints); FUNKNOWN_CTOR } //----------------------------------------------------------------------------- ParameterValueQueue::~ParameterValueQueue () { FUNKNOWN_DTOR } //----------------------------------------------------------------------------- void ParameterValueQueue::clear () { values.clear (); } //----------------------------------------------------------------------------- int32 PLUGIN_API ParameterValueQueue::getPointCount () { return static_cast (values.size ()); } //----------------------------------------------------------------------------- tresult PLUGIN_API ParameterValueQueue::getPoint (int32 index, int32& sampleOffset, ParamValue& value) { if (index >= 0 && index < static_cast (values.size ())) { const ParameterQueueValue& queueValue = values[index]; sampleOffset = queueValue.sampleOffset; value = queueValue.value; return kResultTrue; } return kResultFalse; } //----------------------------------------------------------------------------- tresult PLUGIN_API ParameterValueQueue::addPoint (int32 sampleOffset, ParamValue value, int32& index) { auto destIndex = static_cast(values.size ()); for (uint32 i = 0; i < values.size (); i++) { if (values[i].sampleOffset == sampleOffset) { values[i].value = value; index = i; return kResultTrue; } if (values[i].sampleOffset > sampleOffset) { destIndex = i; break; } } // need new point ParameterQueueValue queueValue (value, sampleOffset); if (destIndex == static_cast (values.size ())) values.emplace_back (queueValue); else values.insert (values.begin () + destIndex, queueValue); index = destIndex; return kResultTrue; } //----------------------------------------------------------------------------- // ParameterChanges //----------------------------------------------------------------------------- ParameterChanges::ParameterChanges (int32 maxParameters) { FUNKNOWN_CTOR setMaxParameters (maxParameters); } //----------------------------------------------------------------------------- ParameterChanges::~ParameterChanges () { FUNKNOWN_DTOR } //----------------------------------------------------------------------------- void ParameterChanges::setMaxParameters (int32 maxParameters) { if (maxParameters < 0) return; while (static_cast (queues.size ()) < maxParameters) { queues.emplace_back (owned (new ParameterValueQueue (kNoParamId))); } while (static_cast (queues.size ()) > maxParameters) { queues.pop_back (); } if (usedQueueCount > maxParameters) usedQueueCount = maxParameters; } //----------------------------------------------------------------------------- void ParameterChanges::clearQueue () { usedQueueCount = 0; } //----------------------------------------------------------------------------- int32 PLUGIN_API ParameterChanges::getParameterCount () { return usedQueueCount; } //----------------------------------------------------------------------------- IParamValueQueue* PLUGIN_API ParameterChanges::getParameterData (int32 index) { if (index >= 0 && index < usedQueueCount) return queues[index]; return nullptr; } //----------------------------------------------------------------------------- IParamValueQueue* PLUGIN_API ParameterChanges::addParameterData (const ParamID& pid, int32& index) { for (int32 i = 0; i < usedQueueCount; i++) { if (queues[i]->getParameterId () == pid) { index = i; return queues[i]; } } ParameterValueQueue* valueQueue = nullptr; if (usedQueueCount < static_cast (queues.size ())) { valueQueue = queues[usedQueueCount]; valueQueue->setParamID (pid); valueQueue->clear (); } else { queues.emplace_back (owned (new ParameterValueQueue (pid))); valueQueue = queues.back (); } index = usedQueueCount; usedQueueCount++; return valueQueue; } //----------------------------------------------------------------------------- // ParameterChangeTransfer //----------------------------------------------------------------------------- ParameterChangeTransfer::ParameterChangeTransfer (int32 maxParameters) : size (0) , changes (nullptr) , readIndex (0) , writeIndex (0) { setMaxParameters (maxParameters); } //----------------------------------------------------------------------------- ParameterChangeTransfer::~ParameterChangeTransfer () { setMaxParameters (0); } //----------------------------------------------------------------------------- void ParameterChangeTransfer::setMaxParameters (int32 maxParameters) { // reserve memory for twice the amount of all parameters int32 newSize = maxParameters * 2; if (size != newSize) { if (changes) delete [] changes; changes = nullptr; size = newSize; if (size > 0) changes = new ParameterChange [size]; } } //----------------------------------------------------------------------------- void ParameterChangeTransfer::addChange (ParamID pid, ParamValue value, int32 sampleOffset) { if (changes) { changes[writeIndex].id = pid; changes[writeIndex].value = value; changes[writeIndex].sampleOffset = sampleOffset; int32 newWriteIndex = writeIndex + 1; if (newWriteIndex >= size) newWriteIndex = 0; if (readIndex != newWriteIndex) writeIndex = newWriteIndex; } } //----------------------------------------------------------------------------- bool ParameterChangeTransfer::getNextChange (ParamID& pid, ParamValue& value, int32& sampleOffset) { if (!changes) return false; int32 currentWriteIndex = writeIndex; if (readIndex != currentWriteIndex) { pid = changes [readIndex].id; value = changes [readIndex].value; sampleOffset = changes [readIndex].sampleOffset; int32 newReadIndex = readIndex + 1; if (newReadIndex >= size) newReadIndex = 0; readIndex = newReadIndex; return true; } return false; } //----------------------------------------------------------------------------- void ParameterChangeTransfer::transferChangesTo (ParameterChanges& dest) { ParamID pid; ParamValue value; int32 sampleOffset; int32 index; while (getNextChange (pid, value, sampleOffset)) { IParamValueQueue* queue = dest.addParameterData (pid, index); if (queue) { queue->addPoint (sampleOffset, value, index); } } } //----------------------------------------------------------------------------- void ParameterChangeTransfer::transferChangesFrom (ParameterChanges& source) { ParamValue value; int32 sampleOffset; for (int32 i = 0; i < source.getParameterCount (); i++) { IParamValueQueue* queue = source.getParameterData (i); if (queue) { for (int32 j = 0; j < queue->getPointCount (); j++) { if (queue->getPoint (j, sampleOffset, value) == kResultTrue) { addChange (queue->getParameterId (), value, sampleOffset); } } } } } //------------------------------------------------------------------------ } // namespace Vst } // namespace Steinberg