0

我正在使用Naaudio AsioOut对象将数据从输入缓冲区传递到我的delayProc()函数,然后再传递到输出缓冲区。

delayProc()需要float[]缓冲区类型,这可以使用e.GetAsInterleavedSamples(). 问题是我需要将它重新转换为 multidimensional IntPtr,为此我正在使用AsioSampleConvertorclass.

当我尝试应用效果时,它向我显示一个错误:类代码上的AccessViolationExceptionAsioSampleConvertor

所以我认为问题是由于转换float[]IntPtr[]..

我给你一些代码:

OnAudioAvailable()

floatIn = new float[e.SamplesPerBuffer * e.InputBuffers.Length];//*2

e.GetAsInterleavedSamples(floatIn);

floatOut = delayProc(floatIn, e.SamplesPerBuffer * e.InputBuffers.Length, 1.5f);
//conversione da float[] a IntPtr[L][R]
Outp = Marshal.AllocHGlobal(sizeof(float)*floatOut.Length);

Marshal.Copy(floatOut, 0, Outp, floatOut.Length);
NAudio.Wave.Asio.ASIOSampleConvertor.ConvertorFloatToInt2Channels(Outp, e.OutputBuffers, e.InputBuffers.Length, floatOut.Length);

延迟过程()

private float[] delayProc(float[] sourceBuffer, int sampleCount, float delay)
{
    if (OldBuf == null)
    {
        OldBuf = new float[sampleCount];
    }
    float[] BufDly = new float[(int)(sampleCount * delay)];
    int delayLength = (int)(BufDly.Length - (BufDly.Length / delay));
    for (int j = sampleCount - delayLength; j < sampleCount; j++)
        for (int i = 0; i < delayLength; i++)
            BufDly[i] = OldBuf[j];
    for (int j = 0; j < sampleCount; j++)
        for (int i = delayLength; i < BufDly.Length; i++)
            BufDly[i] = sourceBuffer[j];
    for (int i = 0; i < sampleCount; i++)
        OldBuf[i] = sourceBuffer[i];
    return BufDly;
}

AsioSampleConvertor

public static void ConvertorFloatToInt2Channels(IntPtr inputInterleavedBuffer, IntPtr[] asioOutputBuffers, int nbChannels, int nbSamples)
{
    unsafe
    {
        float* inputSamples = (float*)inputInterleavedBuffer;
        int* leftSamples = (int*)asioOutputBuffers[0];
        int* rightSamples = (int*)asioOutputBuffers[1];

        for (int i = 0; i < nbSamples; i++)
        {
            *leftSamples++ = clampToInt(inputSamples[0]);
            *rightSamples++ = clampToInt(inputSamples[1]);
            inputSamples += 2;
        }
    }
}

ClampToInt()

private static int clampToInt(double sampleValue)
{
    sampleValue = (sampleValue < -1.0) ? -1.0 : (sampleValue > 1.0) ? 1.0 : sampleValue;
    return (int)(sampleValue * 2147483647.0);
}

如果您需要其他代码,请询问我。

4

1 回答 1

2

当您打电话时,ConvertorFloatToInt2Channels您正在传递所有通道的样本总数,然后尝试读取那么多样本。因此,您试图从输入缓冲区中读取两倍于实际存在的样本。使用不安全的代码,您试图在分配块结束后解决,这会导致您遇到访问冲突。

for将方法中的循环更改为ConvertorFloatToInt2Channels

for (int i = 0; i < nbSamples; i += 2)

这将阻止您的代码尝试读取源内存块中实际存在的项目数量的两倍。


顺便说一句,你为什么要在这里分配全局内存并使用不安全的代码?为什么不将它们作为托管数组处理?处理数据本身并不会慢很多,并且您可以节省将数据复制到非托管内存和从非托管内存复制数据的所有开销。

尝试这个:

public static void FloatMonoToIntStereo(float[] samples, float[] leftChannel, float[] rightChannel)
{
    for (int i = 0, j = 0; i < samples.Length; i += 2, j++)
    {
        leftChannel[j] = (int)(samples[i] * Int32.MaxValue);
        rightChannel[j] = (int)(samples[i + 1] * Int32.MaxValue);
    }
}

在我的机器上每秒处理大约 1200 万个样本,将样本转换为整数并拆分通道。如果我为每组结果分配缓冲区,则速度大约是该速度的一半。AllocHGlobal当我写它以使用不安全的代码等时,大约又是一半。

永远不要假设不安全的代码更快。

于 2014-05-26T03:21:17.323 回答