合唱失真 我是插件开发和C++的新手。我试图使用XCode音频单元模板编写一个合唱插件。然而,当我用正弦波测试插件时,我可以听到一些轻微的失真。我相信我使用的插值技术有问题,尽管我已经用了一千遍,但还是没有弄清楚我做错了什么。以下是我编写的代码,其中包括音频单元的重要部分: private: //state variables... enum {kWaveArraySize = 2000}; //number of points in the LFO sine array to hold the points float mSine[kWaveArraySize]; float *waveArrayPointer; //pointer to point in the array Variable to hold Sampling Rate Float32 SR; long mSamplesProcessed; //variable to keep track of samples processed enum {sampleLimit = (int)10E6}; //limit to reset sine wave float mCurrentScale, mNextScale; //scaling factor for the LFO sine TAUBuffer<Float32> Buffer; //circular buffer Float32 rawIndex; //raw read Index UInt32 ReadIndex, NextIndex; //the Read Index and the sample after the Read Index for Linear Interpolation UInt32 WriteIndex; //the Write Index UInt32 BufferSize; //Size of Buffer UInt32 MaxBufferSize; //Allocated Number of Samples Float32 DelayTime; //Delay Time going to be calculated according to LFO Float32 inputSample, outputSample, freq, Depth, //Variables to hold the frequency of the LFO and Depth parameter samplesPerCycle, //number of samples per LFO cycle InterpOutput, //interpolated output variable fracDelay, DryValue, WetValue; //fractional Delay, Dry and Wet value variables VibratoUnit::VibratoUnitKernel::VibratoUnitKernel (AUEffectBase *inAudioUnit) : AUKernelBase (inAudioUnit), mSamplesProcessed(0), mCurrentScale(0) { for (int i = 0; i<kWaveArraySize; ++i) //loop to calculate one cycle of LFO { double radians = i * 2.0 * pi / kWaveArraySize; mSine[i] = (sin(radians) + 1.0) * 0.5; } SR = GetSampleRate(); BufferSize = SR; MaxBufferSize = BufferSize + 20; Buffer.AllocateClear(MaxBufferSize); ReadIndex = MaxBufferSize - 1; WriteIndex = MaxBufferSize - 1; //Give both ReadIndex and WriteIndex a Value outside the buffer so they would be reset to 0 in the process method void VibratoUnit::VibratoUnitKernel::Reset() //Reset and clear { mCurrentScale = 0; mSamplesProcessed = 0; Buffer.Clear(); } //------------------PROCESS METHOD-----------------------// void VibratoUnit::VibratoUnitKernel::Process( const Float32 *inSourceP, Float32 *inDestP, UInt32 inFramesToProcess, UInt32 inNumChannels, bool &ioSilence ) { UInt32 nSampleFrames = inFramesToProcess; const Float32 *sourceP = inSourceP; Float32 *destP = inDestP; freq = GetParameter(kParamFreq); Depth = GetParameter(kParamDepth); Depth = (SR/1000.0)*Depth; WetValue = GetParameter(kParamDryWet); DryValue = 1.0 - WetValue; waveArrayPointer = &mSine[0]; samplesPerCycle = SR/freq; mNextScale = kWaveArraySize/samplesPerCycle; //----processing loop----// while (nSampleFrames-- > 0) { int index = static_cast<long> (mSamplesProcessed * mCurrentScale)%kWaveArraySize; //Find index for in the LFO wave table if ((mNextScale != mCurrentScale) && (index == 0)) { mCurrentScale = mNextScale; mSamplesProcessed = 0; //change LFO in 0 crossing } if ((mSamplesProcessed >= sampleLimit) && (index == 0)) { mSamplesProcessed = 0; // reset samples processed } if (WriteIndex >= BufferSize) //reset write Index if goes outside the buffer { WriteIndex = 0; } inputSample = *sourceP; sourceP += inNumChannels; DelayTime = waveArrayPointer[index]; //receive raw sine value between 0 and 1 DelayTime = (Depth*DelayTime)+Depth; //calculate delay value according to sine wave rawIndex = WriteIndex - DelayTime; //calculate rawIndex relative to the write Index position if (rawIndex < 0) { rawIndex = BufferSize + rawIndex; } ReadIndex = (UInt32)rawIndex; //calculate readIndex according to rawIndex position fracDelay = DelayTime - (UInt32)DelayTime; //calculate fractional delay time NextIndex = ReadIndex + 1; //for interpolation if (NextIndex >= BufferSize) //bounds checking { NextIndex = 0; } InterpOutput = (fracDelay*Buffer[ReadIndex]) + ((1.0-fracDelay)*Buffer[NextIndex]); //calculate interpolated value Buffer[ReadIndex] = InterpOutput; //write the interpolated output to buffer Buffer[WriteIndex] = inputSample; //write inputsample to buffer outputSample = (Buffer[ReadIndex]*WetValue) + (inputSample * DryValue); //read output sample from buffer WriteIndex++; //increment writeIndex mSamplesProcessed++; //increment samplesprocessed *destP = outputSample; destP += inNumChannels; } } private://状态变量。。。 枚举{kWaveArraySize=2000}//LFO正弦阵列中用于保存点的点数 浮动mSine[kWaveArraySize]; 浮动*波阵指针//指向数组变量中用于保持采样率的点的指针 32锶; 长样本处理//变量以跟踪已处理的样本 枚举{sampleLimit=(int)10E6}//复位正弦波的极限 浮点mCurrentScale、mNextScale//LFO正弦的比例因子 缓冲区//循环缓冲器 浮动指数//原始读取索引 UInt32读取索引,下一个索引//线性插值的读取索引和读取索引后的样本 UInt32写索引//写入索引 UInt32缓冲区大小//缓冲区大小 UInt32最大缓冲区大小//分配的样本数 延迟时间//延迟时间将根据LFO计算 Float32输入样本,输出样本, freq,Depth,//用于保存LFO频率和Depth参数的变量 samplesPerCycle,//每个LFO循环的样本数 interput,//插值输出变量 分形延迟、干值、湿值//分数延迟、干和湿值变量 振动核仁::振动核仁::振动核仁(AUEffectBase*inuidiounit):AUKernelBase(inuidiounit), mSamplesProcessed(0),mCurrentScale(0) { 对于(int i=0;i 0){ int index=static_cast(mSamplesProcessed*mccurrentscale)%kwaveralysize;//在LFO波形表中查找的索引 如果((mNextScale!=mCurrentScale)&&(index==0)) { mCurrentScale=mNextScale; mSamplesProcessed=0;//更改0交叉中的LFO } if((mSamplesProcessed>=sampleLimit)&&(index==0)) { mSamplesProcessed=0;//重置已处理的样本 } if(WriteIndex>=BufferSize)//如果写入索引超出缓冲区,则重置写入索引 { WriteIndex=0; } inputSample=*sourceP; sourceP+=inNumChannels; DelayTime=waveArrayPointer[index];//接收介于0和1之间的原始正弦值 DelayTime=(深度*延迟时间)+深度;//根据正弦波计算延迟值 rawIndex=WriteIndex-DelayTime;//计算相对于写入索引位置的rawIndex 如果(指数=BufferSize)//边界检查 { NextIndex=0; } InterOutput=(fracDelay*缓冲区[ReadIndex])+((1.0-fracDelay)*缓冲区[NextIndex]);//计算插值 Buffer[ReadIndex]=interput;//将插值输出写入缓冲区 缓冲区[WriteIndex]=inputSample;//将inputSample写入缓冲区 outputSample=(缓冲区[ReadIndex]*WetValue)+(inputSample*DryValue);//从缓冲区读取输出样本 WriteIndex++;//递增WriteIndex mSamplesProcessed++;//递增已处理的样本数 *destP=输出样本; destP+=inNumChannels; } }

合唱失真 我是插件开发和C++的新手。我试图使用XCode音频单元模板编写一个合唱插件。然而,当我用正弦波测试插件时,我可以听到一些轻微的失真。我相信我使用的插值技术有问题,尽管我已经用了一千遍,但还是没有弄清楚我做错了什么。以下是我编写的代码,其中包括音频单元的重要部分: private: //state variables... enum {kWaveArraySize = 2000}; //number of points in the LFO sine array to hold the points float mSine[kWaveArraySize]; float *waveArrayPointer; //pointer to point in the array Variable to hold Sampling Rate Float32 SR; long mSamplesProcessed; //variable to keep track of samples processed enum {sampleLimit = (int)10E6}; //limit to reset sine wave float mCurrentScale, mNextScale; //scaling factor for the LFO sine TAUBuffer<Float32> Buffer; //circular buffer Float32 rawIndex; //raw read Index UInt32 ReadIndex, NextIndex; //the Read Index and the sample after the Read Index for Linear Interpolation UInt32 WriteIndex; //the Write Index UInt32 BufferSize; //Size of Buffer UInt32 MaxBufferSize; //Allocated Number of Samples Float32 DelayTime; //Delay Time going to be calculated according to LFO Float32 inputSample, outputSample, freq, Depth, //Variables to hold the frequency of the LFO and Depth parameter samplesPerCycle, //number of samples per LFO cycle InterpOutput, //interpolated output variable fracDelay, DryValue, WetValue; //fractional Delay, Dry and Wet value variables VibratoUnit::VibratoUnitKernel::VibratoUnitKernel (AUEffectBase *inAudioUnit) : AUKernelBase (inAudioUnit), mSamplesProcessed(0), mCurrentScale(0) { for (int i = 0; i<kWaveArraySize; ++i) //loop to calculate one cycle of LFO { double radians = i * 2.0 * pi / kWaveArraySize; mSine[i] = (sin(radians) + 1.0) * 0.5; } SR = GetSampleRate(); BufferSize = SR; MaxBufferSize = BufferSize + 20; Buffer.AllocateClear(MaxBufferSize); ReadIndex = MaxBufferSize - 1; WriteIndex = MaxBufferSize - 1; //Give both ReadIndex and WriteIndex a Value outside the buffer so they would be reset to 0 in the process method void VibratoUnit::VibratoUnitKernel::Reset() //Reset and clear { mCurrentScale = 0; mSamplesProcessed = 0; Buffer.Clear(); } //------------------PROCESS METHOD-----------------------// void VibratoUnit::VibratoUnitKernel::Process( const Float32 *inSourceP, Float32 *inDestP, UInt32 inFramesToProcess, UInt32 inNumChannels, bool &ioSilence ) { UInt32 nSampleFrames = inFramesToProcess; const Float32 *sourceP = inSourceP; Float32 *destP = inDestP; freq = GetParameter(kParamFreq); Depth = GetParameter(kParamDepth); Depth = (SR/1000.0)*Depth; WetValue = GetParameter(kParamDryWet); DryValue = 1.0 - WetValue; waveArrayPointer = &mSine[0]; samplesPerCycle = SR/freq; mNextScale = kWaveArraySize/samplesPerCycle; //----processing loop----// while (nSampleFrames-- > 0) { int index = static_cast<long> (mSamplesProcessed * mCurrentScale)%kWaveArraySize; //Find index for in the LFO wave table if ((mNextScale != mCurrentScale) && (index == 0)) { mCurrentScale = mNextScale; mSamplesProcessed = 0; //change LFO in 0 crossing } if ((mSamplesProcessed >= sampleLimit) && (index == 0)) { mSamplesProcessed = 0; // reset samples processed } if (WriteIndex >= BufferSize) //reset write Index if goes outside the buffer { WriteIndex = 0; } inputSample = *sourceP; sourceP += inNumChannels; DelayTime = waveArrayPointer[index]; //receive raw sine value between 0 and 1 DelayTime = (Depth*DelayTime)+Depth; //calculate delay value according to sine wave rawIndex = WriteIndex - DelayTime; //calculate rawIndex relative to the write Index position if (rawIndex < 0) { rawIndex = BufferSize + rawIndex; } ReadIndex = (UInt32)rawIndex; //calculate readIndex according to rawIndex position fracDelay = DelayTime - (UInt32)DelayTime; //calculate fractional delay time NextIndex = ReadIndex + 1; //for interpolation if (NextIndex >= BufferSize) //bounds checking { NextIndex = 0; } InterpOutput = (fracDelay*Buffer[ReadIndex]) + ((1.0-fracDelay)*Buffer[NextIndex]); //calculate interpolated value Buffer[ReadIndex] = InterpOutput; //write the interpolated output to buffer Buffer[WriteIndex] = inputSample; //write inputsample to buffer outputSample = (Buffer[ReadIndex]*WetValue) + (inputSample * DryValue); //read output sample from buffer WriteIndex++; //increment writeIndex mSamplesProcessed++; //increment samplesprocessed *destP = outputSample; destP += inNumChannels; } } private://状态变量。。。 枚举{kWaveArraySize=2000}//LFO正弦阵列中用于保存点的点数 浮动mSine[kWaveArraySize]; 浮动*波阵指针//指向数组变量中用于保持采样率的点的指针 32锶; 长样本处理//变量以跟踪已处理的样本 枚举{sampleLimit=(int)10E6}//复位正弦波的极限 浮点mCurrentScale、mNextScale//LFO正弦的比例因子 缓冲区//循环缓冲器 浮动指数//原始读取索引 UInt32读取索引,下一个索引//线性插值的读取索引和读取索引后的样本 UInt32写索引//写入索引 UInt32缓冲区大小//缓冲区大小 UInt32最大缓冲区大小//分配的样本数 延迟时间//延迟时间将根据LFO计算 Float32输入样本,输出样本, freq,Depth,//用于保存LFO频率和Depth参数的变量 samplesPerCycle,//每个LFO循环的样本数 interput,//插值输出变量 分形延迟、干值、湿值//分数延迟、干和湿值变量 振动核仁::振动核仁::振动核仁(AUEffectBase*inuidiounit):AUKernelBase(inuidiounit), mSamplesProcessed(0),mCurrentScale(0) { 对于(int i=0;i 0){ int index=static_cast(mSamplesProcessed*mccurrentscale)%kwaveralysize;//在LFO波形表中查找的索引 如果((mNextScale!=mCurrentScale)&&(index==0)) { mCurrentScale=mNextScale; mSamplesProcessed=0;//更改0交叉中的LFO } if((mSamplesProcessed>=sampleLimit)&&(index==0)) { mSamplesProcessed=0;//重置已处理的样本 } if(WriteIndex>=BufferSize)//如果写入索引超出缓冲区,则重置写入索引 { WriteIndex=0; } inputSample=*sourceP; sourceP+=inNumChannels; DelayTime=waveArrayPointer[index];//接收介于0和1之间的原始正弦值 DelayTime=(深度*延迟时间)+深度;//根据正弦波计算延迟值 rawIndex=WriteIndex-DelayTime;//计算相对于写入索引位置的rawIndex 如果(指数=BufferSize)//边界检查 { NextIndex=0; } InterOutput=(fracDelay*缓冲区[ReadIndex])+((1.0-fracDelay)*缓冲区[NextIndex]);//计算插值 Buffer[ReadIndex]=interput;//将插值输出写入缓冲区 缓冲区[WriteIndex]=inputSample;//将inputSample写入缓冲区 outputSample=(缓冲区[ReadIndex]*WetValue)+(inputSample*DryValue);//从缓冲区读取输出样本 WriteIndex++;//递增WriteIndex mSamplesProcessed++;//递增已处理的样本数 *destP=输出样本; destP+=inNumChannels; } },c++,xcode,signal-processing,core-audio,effects,C++,Xcode,Signal Processing,Core Audio,Effects,提前感谢您的帮助。您也可以尝试将此信息发布到music dsp邮件列表中。那些家伙很厉害

提前感谢您的帮助。

您也可以尝试将此信息发布到music dsp邮件列表中。那些家伙很厉害