Initial release
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Project : VST SDK
|
||||
//
|
||||
// Category : Examples
|
||||
// Filename : public.sdk/samples/vst/common/logscale.h
|
||||
// Created by : Steinberg, 10/2010
|
||||
// Description :
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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/base/ftypes.h"
|
||||
#include "pluginterfaces/base/ustring.h"
|
||||
#include "public.sdk/source/vst/vstparameters.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace Steinberg {
|
||||
namespace Vst {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** LogScale class.
|
||||
Scales [srcMin srcMax] to [destMin destMax]
|
||||
|
||||
Scaling curve is defined by given outValue for given inValue
|
||||
|
||||
\section example1 Example for stretched lower range
|
||||
LogScale myLogScale (0, 1, 0, 1, 0.5, 0.1); \n
|
||||
means: input and output ranges are the same, but myLogScale.scale (0.5) is 0.1 ([0, 0.5, 1] => [0, 0.1, 1])
|
||||
|
||||
\section example2 Example for compressed lower range
|
||||
LogScale myLogScale (0, 1, 0, 1, 0.5, 0.9); \n
|
||||
means: input and output ranges are the same, but myLogScale.scale (0.5) is 0.9 ([0, 0.5, 1] => [0, 0.9, 1])
|
||||
|
||||
\section example3 Example for filter frequency range
|
||||
LogScale myLogScale (0, 1, 80, 22000, 0.5, 2000); \n
|
||||
means: input range is between 0 and 1 and output range is between 80 and 22000 and myLogScale.scale (0.5) is 2000
|
||||
([0, 0.5, 1] => [80, 2000, 22000])
|
||||
*/
|
||||
template <class T>
|
||||
class LogScale
|
||||
{
|
||||
public:
|
||||
/** Constructor. */
|
||||
LogScale (T srcMin, T srcMax, T destMin, T destMax, T inValue=0.5, T outValue=0.1);
|
||||
/** Default Constructor with [0, 0.5, 1] => [0, 0.1, 1]. */
|
||||
LogScale ();
|
||||
|
||||
/** Applies a new scale setting. Note that destMin should be different than destMax! The same for srcMin and srcMax. */
|
||||
void changeScaling (T srcMin, T srcMax, T destMin, T destMax, T inValue, T outValue);
|
||||
|
||||
/** Computes the scale from pIn input buffer to pOut output buffer (pIn and POut could be the same buffer). */
|
||||
void scale (T* pIn, T* pOut, int32 nSamples);
|
||||
/** Computes for one given value the scale. */
|
||||
T scale (T input) const;
|
||||
|
||||
/** Computes the inverse scale from pIn input buffer to pOut output buffer (pIn and POut could be the same buffer). */
|
||||
void invscale (T* pIn, T* pOut, int32 nSamples);
|
||||
/** Computes for one given value the inverse scale. */
|
||||
T invscale (T input) const;
|
||||
/** Same than invscale with a check of the input. */
|
||||
T invscaleCheck (T in) const;
|
||||
|
||||
protected:
|
||||
|
||||
void setScaling (T srcMin, T srcMax, T destMin, T destMax, T inValue, T outValue);
|
||||
T scaleFactor;
|
||||
T scaleFactorInv;
|
||||
T srcScale;
|
||||
T srcScaleInv;
|
||||
T srcMin;
|
||||
T expo;
|
||||
T expoInv;
|
||||
T destMin;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
LogScale<T>::LogScale (T srcMin, T srcMax, T destMin, T destMax, T inValue, T outValue)
|
||||
{
|
||||
setScaling (srcMin, srcMax, destMin, destMax, inValue, outValue);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
LogScale<T>::LogScale ()
|
||||
{
|
||||
setScaling (0.f, 1.f, 0.f, 1.f, 0.5f, 0.1f);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void LogScale<T>::changeScaling (T srcMin, T srcMax, T destMin, T destMax, T inValue, T outValue)
|
||||
{
|
||||
setScaling (srcMin, srcMax, destMin, destMax, inValue, outValue);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void LogScale<T>::setScaling (T _srcMin, T _srcMax, T _destMin, T _destMax, T inValue, T outValue)
|
||||
{
|
||||
srcMin = _srcMin;
|
||||
destMin = _destMin;
|
||||
|
||||
scaleFactor = (_destMax - _destMin);
|
||||
scaleFactorInv = 1.f / scaleFactor;
|
||||
|
||||
inValue = (inValue - _srcMin) / (_srcMax - _srcMin);
|
||||
|
||||
SMTG_ASSERT (inValue > 0.);
|
||||
|
||||
expo = ::log ((outValue - _destMin) / scaleFactor) / ::log (inValue);
|
||||
expoInv = 1.f / expo;
|
||||
|
||||
srcScale = (_srcMax - _srcMin);
|
||||
srcScaleInv = 1.f / srcScale;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void LogScale<T>::scale (T* pIn, T* pOut, int32 nSamples)
|
||||
{
|
||||
for (int32 i = 0; i < nSamples; i++)
|
||||
pOut[i] = ::powf ((float)((pIn[i] - srcMin) * srcScaleInv), (float)expo) * scaleFactor + destMin;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
T LogScale<T>::scale (T input) const
|
||||
{
|
||||
return ::powf ((float)((input - srcMin) * srcScaleInv), (float)expo) * scaleFactor + destMin;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void LogScale<T>::invscale (T* pIn, T* pOut, int32 nSamples)
|
||||
{
|
||||
for (int32 i = 0; i < nSamples; i++)
|
||||
pOut[i] = ::powf ((float)((pIn[i] - destMin) * scaleFactorInv), (float)expoInv) * srcScale + srcMin;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
T LogScale<T>::invscale (T input) const
|
||||
{
|
||||
return ::powf ((float)((input - destMin) * scaleFactorInv), (float)expoInv) * srcScale + srcMin;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
T LogScale<T>::invscaleCheck (T input) const
|
||||
{
|
||||
T basis = (float)((input - destMin) * scaleFactorInv);
|
||||
|
||||
if (basis < 0.)
|
||||
basis = 0.;
|
||||
|
||||
return ::powf ((float)basis, (float)expoInv) * srcScale + srcMin;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Parameter class with a LogScale.
|
||||
Define a parameter using the LogScale.
|
||||
|
||||
\sa Steinberg::Vst::LogScale
|
||||
*/
|
||||
template <class T>
|
||||
class LogScaleParameter : public Parameter
|
||||
{
|
||||
public:
|
||||
LogScaleParameter (const TChar* title, ParamID tag, LogScale<T>& logScale,
|
||||
const TChar* units = nullptr, int32 flags = ParameterInfo::kCanAutomate,
|
||||
UnitID unitID = kRootUnitId)
|
||||
: Parameter (title, tag, units, 0., 0, flags, unitID), logScale (logScale)
|
||||
{
|
||||
}
|
||||
|
||||
void toString (ParamValue _valueNormalized, String128 string) const SMTG_OVERRIDE
|
||||
{
|
||||
UString128 wrapper;
|
||||
wrapper.printFloat (toPlain (_valueNormalized), precision);
|
||||
wrapper.copyTo (string, 128);
|
||||
}
|
||||
|
||||
bool fromString (const TChar* string, ParamValue& _valueNormalized) const SMTG_OVERRIDE
|
||||
{
|
||||
UString wrapper ((TChar*)string, strlen16 (string));
|
||||
if (wrapper.scanFloat (_valueNormalized))
|
||||
{
|
||||
_valueNormalized = toNormalized (_valueNormalized);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ParamValue toPlain (ParamValue _valueNormalized) const SMTG_OVERRIDE
|
||||
{
|
||||
return logScale.scale (_valueNormalized);
|
||||
}
|
||||
|
||||
ParamValue toNormalized (ParamValue plainValue) const SMTG_OVERRIDE
|
||||
{
|
||||
return logScale.invscale (plainValue);
|
||||
}
|
||||
|
||||
OBJ_METHODS (LogScaleParameter<T>, Parameter)
|
||||
protected:
|
||||
LogScale<T>& logScale;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // namespace Vst
|
||||
} // namespace Steinberg
|
||||
@@ -0,0 +1,164 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Project : VST SDK
|
||||
//
|
||||
// Category : Examples
|
||||
// Filename : public.sdk/samples/vst/common/voicebase.h
|
||||
// Created by : Steinberg, 02/2010
|
||||
// Description :
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 "base/source/fdebug.h"
|
||||
#include "pluginterfaces/vst/vsttypes.h"
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
#undef DEBUG_LOG
|
||||
#endif
|
||||
|
||||
#define DEBUG_LOG DEVELOPMENT
|
||||
|
||||
namespace Steinberg {
|
||||
namespace Vst {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Example Voice class for the Steinberg::Vst::VoiceProcessorImplementation
|
||||
|
||||
Implementation classes need to implement the following additional method:
|
||||
\code{.cpp}
|
||||
bool process (SamplePrecision* outputBuffers[numChannels], int32 numSamples);
|
||||
\endcode
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
template <uint32 numValues, class SamplePrecision, uint32 numChannels, class GlobalParameterStorage>
|
||||
class VoiceBase
|
||||
{
|
||||
public:
|
||||
/** Returns the current note id of this voice. */
|
||||
int32 getNoteId () const { return noteId; }
|
||||
|
||||
/** Sets a new GlobalParameterStorage. */
|
||||
virtual void setGlobalParameterStorage (GlobalParameterStorage* globalParameters)
|
||||
{
|
||||
this->globalParameters = globalParameters;
|
||||
}
|
||||
/** Sets the sampleRate. */
|
||||
virtual void setSampleRate (ParamValue sampleRate) { this->sampleRate = sampleRate; }
|
||||
/** Returns the sampleRate. */
|
||||
float getSampleRate () const { return (float)sampleRate; }
|
||||
|
||||
virtual void setNoteExpressionValue (int32 index, ParamValue value)
|
||||
{
|
||||
if (index < numValues)
|
||||
values[index] = value;
|
||||
}
|
||||
|
||||
virtual void noteOn (int32 pitch, ParamValue velocity, float tuning, int32 sampleOffset,
|
||||
int32 noteId);
|
||||
virtual void noteOff (ParamValue velocity, int32 sampleOffset);
|
||||
|
||||
virtual void reset ()
|
||||
{
|
||||
noteOnSampleOffset = -1;
|
||||
noteOffSampleOffset = -1;
|
||||
noteId = -1;
|
||||
tuning = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
protected:
|
||||
VoiceBase ();
|
||||
VoiceBase (const VoiceBase& vb);
|
||||
virtual ~VoiceBase ();
|
||||
|
||||
GlobalParameterStorage* globalParameters;
|
||||
|
||||
int32 noteId;
|
||||
int32 pitch;
|
||||
int32 noteOnSampleOffset;
|
||||
int32 noteOffSampleOffset;
|
||||
float tuning {0};
|
||||
|
||||
ParamValue sampleRate;
|
||||
ParamValue noteOnVelocity;
|
||||
ParamValue noteOffVelocity;
|
||||
ParamValue values[numValues];
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <uint32 numValues, class SamplePrecision, uint32 numChannels, class GlobalParameterStorage>
|
||||
VoiceBase<numValues, SamplePrecision, numChannels, GlobalParameterStorage>::VoiceBase ()
|
||||
: globalParameters (0)
|
||||
, noteId (-1)
|
||||
, pitch (-1)
|
||||
, noteOnSampleOffset (0)
|
||||
, noteOffSampleOffset (0)
|
||||
, sampleRate (44100.)
|
||||
, noteOnVelocity (0.)
|
||||
, noteOffVelocity (0.)
|
||||
, values {0}
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <uint32 numValues, class SamplePrecision, uint32 numChannels, class GlobalParameterStorage>
|
||||
VoiceBase<numValues, SamplePrecision, numChannels, GlobalParameterStorage>::VoiceBase (
|
||||
const VoiceBase<numValues, SamplePrecision, numChannels, GlobalParameterStorage>& vb)
|
||||
: globalParameters (vb.globalParameters)
|
||||
, noteId (vb.noteId)
|
||||
, pitch (vb.pitch)
|
||||
, noteOnSampleOffset (vb.noteOnSampleOffset)
|
||||
, noteOffSampleOffset (vb.noteOffSampleOffset)
|
||||
, noteOnVelocity (vb.noteOnVelocity)
|
||||
, noteOffVelocity (vb.noteOffVelocity)
|
||||
, sampleRate (vb.sampleRate)
|
||||
{
|
||||
for (uint32 i = 0; i < numValues; i++)
|
||||
values[i] = vb.values[i];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <uint32 numValues, class SamplePrecision, uint32 numChannels, class GlobalParameterStorage>
|
||||
VoiceBase<numValues, SamplePrecision, numChannels, GlobalParameterStorage>::~VoiceBase ()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <uint32 numValues, class SamplePrecision, uint32 numChannels, class GlobalParameterStorage>
|
||||
void VoiceBase<numValues, SamplePrecision, numChannels, GlobalParameterStorage>::noteOn (
|
||||
int32 pitch, ParamValue velocity, float tuning, int32 sampleOffset, int32 nId)
|
||||
{
|
||||
this->pitch = pitch;
|
||||
noteOnVelocity = velocity;
|
||||
noteOnSampleOffset = sampleOffset;
|
||||
noteId = nId;
|
||||
this->tuning = tuning;
|
||||
|
||||
#if DEBUG_LOG
|
||||
FDebugPrint ("NoteOn :%d\n", nId);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <uint32 numValues, class SamplePrecision, uint32 numChannels, class GlobalParameterStorage>
|
||||
void VoiceBase<numValues, SamplePrecision, numChannels, GlobalParameterStorage>::noteOff (
|
||||
ParamValue velocity, int32 sampleOffset)
|
||||
{
|
||||
noteOffVelocity = velocity;
|
||||
noteOffSampleOffset = sampleOffset;
|
||||
|
||||
#if DEBUG_LOG
|
||||
FDebugPrint ("NoteOff:%d\n", this->noteId);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // namespace Vst
|
||||
} // namespace Steinberg
|
||||
@@ -0,0 +1,438 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Project : VST SDK
|
||||
//
|
||||
// Category : Examples
|
||||
// Filename : public.sdk/samples/vst/common/voiceprocessor.h
|
||||
// Created by : Steinberg, 02/2010
|
||||
// Description :
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 "base/source/fdebug.h"
|
||||
#include "pluginterfaces/vst/ivstaudioprocessor.h"
|
||||
#include "pluginterfaces/vst/ivstevents.h"
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
#undef DEBUG_LOG
|
||||
#endif
|
||||
|
||||
#define DEBUG_LOG DEVELOPMENT
|
||||
|
||||
#ifndef VOICEPROCESSOR_BLOCKSIZE
|
||||
#define VOICEPROCESSOR_BLOCKSIZE 32
|
||||
#endif
|
||||
|
||||
namespace Steinberg {
|
||||
namespace Vst {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** A Voice Processor class.
|
||||
|
||||
A virtual base class for a voice manager implementation.
|
||||
|
||||
The idea behind this class is to make it easier to support either single precision or double
|
||||
precision samples (float or double) or different channel layouts.
|
||||
|
||||
Example:
|
||||
\code{.cpp}
|
||||
//------------------------------------------------------------------------
|
||||
class MySynthProcessor : public AudioEffect
|
||||
{
|
||||
public:
|
||||
tresult PLUGIN_API setActive (TBool state);
|
||||
tresult PLUGIN_API process (ProcessData& data);
|
||||
|
||||
protected:
|
||||
VoiceProcessor* voiceProcessor;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API MySynthProcessor::setActive (TBool state)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
if (processSetup.symbolicSampleSize == kSample32)
|
||||
voiceProcessor = new VoiceProcessorImplementation<float, Voice<float>, 2, MAX_VOICES, void> (processSetup.sampleRate, 0);
|
||||
else if (processSetup.symbolicSampleSize == kSample64)
|
||||
voiceProcessor = new VoiceProcessorImplementation<double, Voice<double>, 2, MAX_VOICES, void> (processSetup.sampleRate, 0);
|
||||
else
|
||||
return kInvalidArgument;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete voiceProcessor;
|
||||
voiceProcessor = 0;
|
||||
}
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API MySynthProcessor::process (ProcessData& data)
|
||||
{
|
||||
return voiceProcessor->process (data);
|
||||
}
|
||||
\endcode
|
||||
|
||||
\sa Steinberg::Vst::VoiceProcessorImplementation
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
class VoiceProcessor
|
||||
{
|
||||
public:
|
||||
VoiceProcessor () {}
|
||||
virtual ~VoiceProcessor () {}
|
||||
|
||||
virtual tresult process (ProcessData& data) = 0;
|
||||
virtual void processEvent (Event evt) = 0;
|
||||
|
||||
virtual void clearAllVoices ()
|
||||
{
|
||||
activeVoices = 0;
|
||||
}
|
||||
|
||||
/** Returns the number of active voices. */
|
||||
int32 getActiveVoices () const { return activeVoices; }
|
||||
|
||||
void clearOutputNeeded (bool val) { mClearOutputNeeded = val; }
|
||||
|
||||
protected:
|
||||
int32 activeVoices {0};
|
||||
bool mClearOutputNeeded {true};
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** A Simple Voice Processor Implementation supporting note expression events.
|
||||
|
||||
\param Precision must be either float or double
|
||||
\param VoiceClass the voice class
|
||||
\param numChannels number of channels
|
||||
\param maxVoices number of maximum voices
|
||||
\param GlobalParameterStorage a class holding global parameters
|
||||
|
||||
The VoiceClass must implement the following methods:
|
||||
\code{.cpp}
|
||||
int32 getNoteId () const;
|
||||
void setGlobalParameterStorage (GlobalParameterStorage* globalParameters);
|
||||
void setSampleRate (ParamValue sampleRate);
|
||||
void setNoteExpressionValue (int32 index, ParamValue value);
|
||||
void noteOn (int32 pitch, ParamValue velocity, float tuning, int32 sampleOffset, int32 noteId);
|
||||
void noteOff (ParamValue velocity, int32 sampleOffset);
|
||||
bool process (SamplePrecision* outputBuffers[numChannels], int32 numSamples);
|
||||
void reset ()
|
||||
\endcode
|
||||
|
||||
See \ref Steinberg::Vst::VoiceBase for an example base class.
|
||||
|
||||
This implementation does not support advanced features like voice stealing when maxVoices is
|
||||
reached, etc ...
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Precision, class VoiceClass, int32 numChannels, int32 maxVoices,
|
||||
class GlobalParameterStorage>
|
||||
class VoiceProcessorImplementation : public VoiceProcessor
|
||||
{
|
||||
public:
|
||||
VoiceProcessorImplementation (float sampleRate, GlobalParameterStorage* globalParameters = 0);
|
||||
~VoiceProcessorImplementation () override;
|
||||
|
||||
tresult process (ProcessData& data) override;
|
||||
void processEvent (Event evt) override;
|
||||
|
||||
void clearAllVoices () override;
|
||||
protected:
|
||||
VoiceClass* getVoice (int32 noteId);
|
||||
VoiceClass* findVoice (int32 noteId);
|
||||
VoiceClass voices[maxVoices];
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Precision, class VoiceClass, int32 numChannels, int32 maxVoices,
|
||||
class GlobalParameterStorage>
|
||||
VoiceProcessorImplementation<
|
||||
Precision, VoiceClass, numChannels, maxVoices,
|
||||
GlobalParameterStorage>::VoiceProcessorImplementation (float sampleRate,
|
||||
GlobalParameterStorage* globalParameters)
|
||||
{
|
||||
for (int32 i = 0; i < maxVoices; i++)
|
||||
{
|
||||
voices[i].setGlobalParameterStorage (globalParameters);
|
||||
voices[i].setSampleRate (sampleRate);
|
||||
voices[i].reset ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Precision, class VoiceClass, int32 numChannels, int32 maxVoices,
|
||||
class GlobalParameterStorage>
|
||||
VoiceProcessorImplementation<Precision, VoiceClass, numChannels, maxVoices,
|
||||
GlobalParameterStorage>::~VoiceProcessorImplementation ()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Precision, class VoiceClass, int32 numChannels, int32 maxVoices,
|
||||
class GlobalParameterStorage>
|
||||
VoiceClass* VoiceProcessorImplementation<Precision, VoiceClass, numChannels, maxVoices,
|
||||
GlobalParameterStorage>::getVoice (int32 noteId)
|
||||
{
|
||||
VoiceClass* firstFreeVoice = 0;
|
||||
if (noteId != -1)
|
||||
{
|
||||
for (int32 i = 0; i < maxVoices; i++)
|
||||
{
|
||||
if (voices[i].getNoteId () == noteId)
|
||||
{
|
||||
return &voices[i];
|
||||
}
|
||||
else if (firstFreeVoice == 0 && voices[i].getNoteId () == -1)
|
||||
{
|
||||
firstFreeVoice = &voices[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return firstFreeVoice;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Precision, class VoiceClass, int32 numChannels, int32 maxVoices,
|
||||
class GlobalParameterStorage>
|
||||
VoiceClass* VoiceProcessorImplementation<Precision, VoiceClass, numChannels, maxVoices,
|
||||
GlobalParameterStorage>::findVoice (int32 noteId)
|
||||
{
|
||||
if (noteId != -1)
|
||||
{
|
||||
for (int32 i = 0; i < maxVoices; i++)
|
||||
{
|
||||
if (voices[i].getNoteId () == noteId)
|
||||
{
|
||||
return &voices[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Precision, class VoiceClass, int32 numChannels, int32 maxVoices,
|
||||
class GlobalParameterStorage>
|
||||
void VoiceProcessorImplementation<Precision, VoiceClass, numChannels, maxVoices,
|
||||
GlobalParameterStorage>::clearAllVoices ()
|
||||
{
|
||||
for (int32 i = 0; i < maxVoices; i++)
|
||||
{
|
||||
if (voices[i].getNoteId () != -1)
|
||||
voices[i].reset ();
|
||||
}
|
||||
VoiceProcessor::clearAllVoices ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Precision, class VoiceClass, int32 numChannels, int32 maxVoices,
|
||||
class GlobalParameterStorage>
|
||||
void VoiceProcessorImplementation<Precision, VoiceClass, numChannels, maxVoices,
|
||||
GlobalParameterStorage>::processEvent (Event e)
|
||||
{
|
||||
switch (e.type)
|
||||
{
|
||||
//--- --------------------
|
||||
case Event::kNoteOnEvent:
|
||||
{
|
||||
if (e.noteOn.noteId == -1)
|
||||
e.noteOn.noteId = e.noteOn.pitch;
|
||||
VoiceClass* voice = getVoice (e.noteOn.noteId);
|
||||
if (voice)
|
||||
{
|
||||
voice->noteOn (e.noteOn.pitch, e.noteOn.velocity, e.noteOn.tuning, e.sampleOffset,
|
||||
e.noteOn.noteId);
|
||||
this->activeVoices++;
|
||||
// data.outputEvents->addEvent (e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
//--- --------------------
|
||||
case Event::kNoteOffEvent:
|
||||
{
|
||||
if (e.noteOff.noteId == -1)
|
||||
e.noteOff.noteId = e.noteOff.pitch;
|
||||
VoiceClass* voice = findVoice (e.noteOff.noteId);
|
||||
if (voice)
|
||||
{
|
||||
voice->noteOff (e.noteOff.velocity, e.sampleOffset);
|
||||
// data.outputEvents->addEvent (e);
|
||||
}
|
||||
#if DEBUG_LOG
|
||||
else
|
||||
{
|
||||
FDebugPrint ("Voice for kNoteOffEvent not found : %d\n", e.noteOff.noteId);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
//--- --------------------
|
||||
case Event::kNoteExpressionValueEvent:
|
||||
{
|
||||
VoiceClass* voice = findVoice (e.noteExpressionValue.noteId);
|
||||
if (voice)
|
||||
{
|
||||
voice->setNoteExpressionValue (e.noteExpressionValue.typeId,
|
||||
e.noteExpressionValue.value);
|
||||
// data.outputEvents->addEvent (e);
|
||||
}
|
||||
#if DEBUG_LOG
|
||||
else
|
||||
{
|
||||
FDebugPrint ("Voice for kNoteExpressionValueEvent not found : %d\n",
|
||||
e.noteExpressionValue.noteId);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#if VOICEPROCESSOR_BLOCKSIZE <= 0 // voice processing happens in chunks of the block size
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Precision, class VoiceClass, int32 numChannels, int32 maxVoices,
|
||||
class GlobalParameterStorage>
|
||||
tresult VoiceProcessorImplementation<Precision, VoiceClass, numChannels, maxVoices,
|
||||
GlobalParameterStorage>::process (ProcessData& data)
|
||||
{
|
||||
if (mClearOutputNeeded)
|
||||
for (int32 i = 0; i < numChannels; i++)
|
||||
memset (data.outputs[0].channelBuffers32[i], 0, data.numSamples * sizeof (Precision));
|
||||
|
||||
IEventList* inputEvents = data.inputEvents;
|
||||
if (inputEvents)
|
||||
{
|
||||
Event e;
|
||||
int32 numEvents = inputEvents->getEventCount ();
|
||||
for (int32 i = 0; i < numEvents; i++)
|
||||
{
|
||||
if (inputEvents->getEvent (i, e) == kResultTrue)
|
||||
{
|
||||
processEvent (e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < maxVoices; i++)
|
||||
{
|
||||
if (voices[i].getNoteId () != -1)
|
||||
{
|
||||
if (!voices[i].process ((Precision**)data.outputs[0].channelBuffers32, data.numSamples))
|
||||
{
|
||||
voices[i].reset ();
|
||||
this->activeVoices--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#else // voice processing happens in chunks of VOICEPROCESSOR_BLOCKSIZE samples
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Precision, class VoiceClass, int32 numChannels, int32 maxVoices,
|
||||
class GlobalParameterStorage>
|
||||
tresult VoiceProcessorImplementation<Precision, VoiceClass, numChannels, maxVoices,
|
||||
GlobalParameterStorage>::process (ProcessData& data)
|
||||
{
|
||||
const int32 kBlockSize = VOICEPROCESSOR_BLOCKSIZE;
|
||||
|
||||
int32 numSamples = data.numSamples;
|
||||
int32 samplesProcessed = 0;
|
||||
|
||||
IEventList* inputEvents = data.inputEvents;
|
||||
Event e = {};
|
||||
Event* eventPtr = nullptr;
|
||||
int32 eventIndex = 0;
|
||||
int32 numEvents = inputEvents ? inputEvents->getEventCount () : 0;
|
||||
|
||||
// get the first event
|
||||
if (numEvents)
|
||||
{
|
||||
inputEvents->getEvent (0, e);
|
||||
eventPtr = &e;
|
||||
}
|
||||
|
||||
// initialize audio output buffers
|
||||
Precision* buffers[numChannels];
|
||||
for (int32 i = 0; i < numChannels; i++)
|
||||
{
|
||||
buffers[i] = (Precision*)data.outputs[0].channelBuffers32[i];
|
||||
if (mClearOutputNeeded)
|
||||
memset (buffers[i], 0, data.numSamples * sizeof (Precision));
|
||||
}
|
||||
|
||||
while (numSamples > 0)
|
||||
{
|
||||
int32 samplesToProcess = std::min<int32> (kBlockSize, numSamples);
|
||||
while (eventPtr != nullptr)
|
||||
{
|
||||
// if the event is not in the current processing block then adapt offset for next block
|
||||
if (e.sampleOffset > samplesToProcess)
|
||||
{
|
||||
e.sampleOffset -= samplesToProcess;
|
||||
break;
|
||||
}
|
||||
|
||||
processEvent (e);
|
||||
|
||||
// get next event
|
||||
eventIndex++;
|
||||
if (eventIndex < numEvents)
|
||||
{
|
||||
if (inputEvents->getEvent (eventIndex, e) == kResultTrue)
|
||||
{
|
||||
e.sampleOffset -= samplesProcessed;
|
||||
}
|
||||
else
|
||||
{
|
||||
eventPtr = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eventPtr = nullptr;
|
||||
}
|
||||
} // end while (event != 0)
|
||||
|
||||
// now process the block
|
||||
for (int32 i = 0; i < maxVoices; i++)
|
||||
{
|
||||
if (voices[i].getNoteId () != -1)
|
||||
{
|
||||
if (!voices[i].process (buffers, samplesToProcess))
|
||||
{
|
||||
voices[i].reset ();
|
||||
this->activeVoices--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update the counters
|
||||
for (int32 i = 0; i < numChannels; i++)
|
||||
buffers[i] += samplesToProcess;
|
||||
numSamples -= samplesToProcess;
|
||||
samplesProcessed += samplesToProcess;
|
||||
|
||||
} // end while (numSamples > 0)
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // namespace Vst
|
||||
} // namespace Steinberg
|
||||
Reference in New Issue
Block a user