Dear VB.Net H8t3R,
Try making a single call to Strings.Trim(s) before you start benchmarking. I think a static constructor just bit you on the ass.
Love,
Your nemesis
Since we last spoke, I have realised that a managed VST plug-in is a far from practical application for hosting the CLR. Which means no more COM haxx0ring. Shame.
On the upside, I have discovered the twin joys of Managed C++ and porting DSP code from C to C#. MC++, after several failed attempts, now shuttles calls from the VST host through to C#. The CLR is of course loaded automatically whenever the managed DLL is touched, so hosting it explicitly is pointless.
It is splendid fun. At the moment, much of the real-time processing is done with unsafe code (the VST host passes in pointers to the input and output buffers), but it’s nicer than working in C. Here’s a simple delay:
public class Delay
{
float samplingRate;
float[] delayLine;
int delayLineIndex;
int bufferLength;
private float delayTime;
private float feedback;
private float dryLevel;
private float wetLevel;
private const int MAX_DELAY_TIME = 1000;
public Delay(float delayTime, float feedBack, float dryLevel, float wetLevel, float samplingRate)
{
this.delayTime = delayTime;
this.feedback = feedBack;
this.dryLevel = dryLevel;
this.wetLevel = wetLevel;
this.samplingRate = samplingRate;
int maxBufferLength = CalculateBufferLength(MAX_DELAY_TIME);
delayLine = new float[maxBufferLength];
bufferLength = CalculateBufferLength(delayTime);
this.delayLineIndex = 0;
}
unsafe public void Process(float* input, float* output, int sampleFrames)
{
for (int i = 0; i < sampleFrames; i++)
{
output[i] += (dryLevel * input[i]) + (wetLevel * delayLine[delayLineIndex]);
delayLine[delayLineIndex] = input[i] + (feedback * delayLine[delayLineIndex]);
if (++delayLineIndex >= bufferLength)
{
delayLineIndex = 0;
}
}
}
public float DelayTime
{
get { return delayTime; }
set
{
this.delayTime = value;
this.bufferLength = CalculateBufferLength(value);
}
}
public float Feedback
{
get { return feedback; }
set { feedback = value; }
}
public float DryLevel
{
get { return dryLevel; }
set { dryLevel = value; }
}
public float WetLevel
{
get { return wetLevel; }
set { wetLevel = value; }
}
private int CalculateBufferLength(float delayTime)
{
return (int)(delayTime * samplingRate / 1000);
}
}
Performance hasn’t been an issue so far, but I haven’t tried to do anything particularly taxing. The real test will come when I start creating garbage, although I think Gen 0 collections will be tolerable.