私の名前はイタリアのアントニオです。このリンク
の例から始めて、xCode 3.2.6 を使用して Audio Unit を作成しようとしています
。
これは私の最初の AU プロジェクトであり、従うべき他の例はありません。
私のプロジェクトは IIR ノッチ フィルターで構成されています。私が作成したアルゴリズムは正常に動作します (Matlab でテストしました) が、AU は正しく動作しません (AU Lab でテストしました)。.mp3 ファイルはフィルタリングされたように聞こえますが、矩形波のようなもの (耳によると思います) が重なっています。
そのノイズの周波数は f0 パラメータに比例するようです。
.cpp ファイルのコードは次のとおりです。
// Filtro.cpp
#include "Filtro.h"
#define pi 3.1415926535
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
COMPONENT_ENTRY(Filtro)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::Filtro
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Filtro::Filtro (AudioUnit component) : AUEffectBase (component) {
CreateElements ();
Globals () -> UseIndexedParameters (kNumberOfParameters);
SetParameter (kParameter_Gain, kDefaultValue_Gain);
SetParameter (kParameter_f0, kDefaultValue_f0);
SetParameter (kParameter_Q, kDefaultValue_Q);
// code for setting default values for the audio unit parameters
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::GetParameterInfo
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ____Parameters
ComponentResult Filtro::GetParameterInfo (
AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
AudioUnitParameterInfo &outParameterInfo
) {
ComponentResult result = noErr;
outParameterInfo.flags = kAudioUnitParameterFlag_IsWritable
| kAudioUnitParameterFlag_IsReadable;
if (inScope == kAudioUnitScope_Global) {
switch (inParameterID) {
case kParameter_Gain:
AUBase::FillInParameterName (
outParameterInfo,
kParamName_Gain,
false
);
outParameterInfo.unit = kAudioUnitParameterUnit_Decibels;
outParameterInfo.minValue = kMinimumValue_Gain;
outParameterInfo.maxValue = kMaximumValue_Gain;
outParameterInfo.defaultValue = kDefaultValue_Gain;
break;
case kParameter_f0: // 9
AUBase::FillInParameterName (
outParameterInfo,
kParamName_f0,
false
);
outParameterInfo.unit = kAudioUnitParameterUnit_Hertz;
outParameterInfo.minValue = kMinimumValue_f0;
outParameterInfo.maxValue = kMaximumValue_f0;
outParameterInfo.defaultValue = kDefaultValue_f0;
outParameterInfo.flags |= kAudioUnitParameterFlag_DisplayLogarithmic;
break;
case kParameter_Q: // 9
AUBase::FillInParameterName (
outParameterInfo,
kParamName_Q,
false
);
outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
outParameterInfo.minValue = kMinimumValue_Q;
outParameterInfo.maxValue = kMaximumValue_Q;
outParameterInfo.defaultValue = kDefaultValue_Q;
outParameterInfo.flags |= kAudioUnitParameterFlag_DisplayLogarithmic;
break;
default:
result = kAudioUnitErr_InvalidParameter;
break;
}
} else {
result = kAudioUnitErr_InvalidParameter;
}
return result;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::GetPropertyInfo
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSStatus Filtro::GetPropertyInfo ( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 &outDataSize,
Boolean &outWritable)
{
return AUEffectBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::GetProperty
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSStatus Filtro::GetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void *outData )
{
return AUEffectBase::GetProperty (inID, inScope, inElement, outData);
}
#pragma mark ____FiltroEffectKernel
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::FiltroKernel::FiltroKernel()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Filtro::FiltroKernel::FiltroKernel (AUEffectBase *inAudioUnit) :
AUKernelBase (inAudioUnit), mSamplesProcessed (0), mCurrentScale (0) // 1
{
mSampleFrequency = GetSampleRate ();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::FiltroKernel::Reset()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Filtro::FiltroKernel::Reset() {
mCurrentScale = 0;
mSamplesProcessed = 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::FiltroKernel::Process
void Filtro::FiltroKernel::Process (const Float32 *inSourceP,
Float32 *inDestP,
UInt32 inSamplesToProcess,
UInt32 inNumChannels,
bool &ioSilence
) {
if (!ioSilence) {
const Float32 *sourceP = inSourceP;
Float32 *destP = inDestP, inputSample, outputSample;
Float32 Fs= mSampleFrequency;
int f0;
float w0, alpha, b0, b1, b2, a0, a1, a2;
float gain, dBgain, Q, coeff[5], x[5]={0,0,0,0,0} , out = 0;
dBgain = GetParameter (kParameter_Gain); //Get parameter from interface
if (dBgain < kMinimumValue_Gain) dBgain = kMinimumValue_Gain; //Check the right range
if (dBgain > kMaximumValue_Gain) dBgain = kMaximumValue_Gain;
f0 = GetParameter (kParameter_f0);
if (f0 < kMinimumValue_f0) f0 = kMinimumValue_f0;
if (f0 > kMaximumValue_f0) f0 = kMaximumValue_f0;
Q = GetParameter (kParameter_Q);
if (Q < kMinimumValue_Q) Q = kMinimumValue_Q;
if (Q > kMaximumValue_Q) Q = kMaximumValue_Q;
w0 = 2*pi*f0/Fs;
alpha = sin(w0)*sinh(log(2)/(log(exp(1))*2) * Q * w0/sin(w0));
b0 = 1;
b1 = -2*cos(w0);
b2 = 1;
a0 = 1 + alpha;
a1 = -2*cos(w0);
a2 = 1 - alpha;
coeff[0] = b0/a0;
coeff[1] = b1/a0;
coeff[2] = b2/a0;
coeff[3] = -a1/a0;
coeff[4] = -a2/a0;
//----------------------------------------------------------------------------------------------//
// y(n) = b0/a0 * x(n) + b1/a0 * x(n-1) + b2/a0 * x(n-2) * -a1/a0 * y(n-1) * -a2/a0 * y(n-2) //
//----------------------------------------------------------------------------------------------//
for (int i = inSamplesToProcess; i > 0; --i) {
int index = static_cast<long>(mSamplesProcessed * mCurrentScale) % 512; //?
if ((mNextScale != mCurrentScale) && (index == 0)) { //??
mCurrentScale = mNextScale;
mSamplesProcessed = 0;
}
if ((mSamplesProcessed >= sampleLimit) && (index == 0)) { // ??
mSamplesProcessed = 0;
}
gain = pow(10, dBgain/20);
inputSample = *sourceP;
x[0] = inputSample; //x(n)
x[3] = outputSample; //y(n-1)
for (int h = 0; h < 5; h++) { // Processing output sample
out = out+x[h]*coeff[h];
}
for (int h = 4; h > 0; h--) {
x[h]=x[h-1]; //I/O array shifting
}
outputSample = out * gain;
out = 0;
*destP = outputSample;
sourceP += 1;
destP += 1;
mSamplesProcessed += 1;
}
}
}
そして、それがヘッダーファイルです:
// Filtro.h
#include "AUEffectBase.h"
#include "AUEffectBase.h"
#include "FiltroVersion.h"
#if AU_DEBUG_DISPATCHER
#include "AUDebugDispatcher.h"
#endif
#ifndef __Filtro_h__
#define __Filtro_h__
#pragma mark ____Filtro Parameter Constants
static CFStringRef kParamName_Gain = CFSTR ("Gain");
static const double kDefaultValue_Gain = 0;
static const double kMinimumValue_Gain = -40;
static const double kMaximumValue_Gain = 0;
static CFStringRef kParamName_f0 = CFSTR ("f0");
static const int kDefaultValue_f0 = 1048;
static const int kMinimumValue_f0 = 50;
static const int kMaximumValue_f0 = 20000;
static CFStringRef kParamName_Q = CFSTR ("Q");
static const double kDefaultValue_Q = 0.1;
static const double kMinimumValue_Q = 0.001;
static const double kMaximumValue_Q = 10;
// parameter identifiers
enum { // Defines constants for identifying the parameters; defines the total number of parameters
kParameter_Gain = 0,
kParameter_f0 = 1,
kParameter_Q = 2,
kNumberOfParameters = 3
};
#pragma mark ____Filtro
class Filtro : public AUEffectBase
{
public:
Filtro(AudioUnit component);
#if AU_DEBUG_DISPATCHER
virtual ~Filtro () { delete mDebugDispatcher; }
#endif
virtual AUKernelBase * NewKernel() { return new FiltroKernel(this); }
virtual OSStatus GetParameterInfo(AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
AudioUnitParameterInfo &outParameterInfo);
virtual OSStatus GetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable );
virtual OSStatus GetProperty(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
virtual bool SupportsTail () { return false; } // FIND
/*! @method Version */
virtual OSStatus Version() { return kFiltroVersion; }
// virtual ComponentResult GetPresets (CFArrayRef *outData) const;
// virtual OSStatus NewFactoryPresetSet (const AUPreset &inNewFactoryPreset);
protected:
class FiltroKernel : public AUKernelBase {
public:
FiltroKernel (AUEffectBase *inAudioUnit); // 1
virtual void Process (
const Float32 *inSourceP,
Float32 *inDestP,
UInt32 inFramesToProcess,
UInt32 inNumChannels, // equal to 1
bool &ioSilence
);
virtual void Reset();
private:
Float32 mSampleFrequency;
long mSamplesProcessed;
enum {sampleLimit = (int) 10E6};
float mCurrentScale;
float mNextScale;
};
};
#endif#include "FiltroVersion.h"
#if AU_DEBUG_DISPATCHER
#include "AUDebugDispatcher.h"
#endif
#ifndef __Filtro_h__
#define __Filtro_h__
#pragma mark ____Filtro Parameter Constants
static CFStringRef kParamName_Gain = CFSTR ("Gain");
static const double kDefaultValue_Gain = 0;
static const double kMinimumValue_Gain = -40;
static const double kMaximumValue_Gain = 0;
static CFStringRef kParamName_f0 = CFSTR ("f0");
static const int kDefaultValue_f0 = 1048;
static const int kMinimumValue_f0 = 50;
static const int kMaximumValue_f0 = 20000;
static CFStringRef kParamName_Q = CFSTR ("Q");
static const double kDefaultValue_Q = 0.1;
static const double kMinimumValue_Q = 0.001;
static const double kMaximumValue_Q = 10;
// parameter identifiers
enum { // Defines constants for identifying the parameters; defines the total number of parameters
kParameter_Gain = 0,
kParameter_f0 = 1,
kParameter_Q = 2,
kNumberOfParameters = 3
};
#pragma mark ____Filtro
class Filtro : public AUEffectBase
{
public:
Filtro(AudioUnit component);
#if AU_DEBUG_DISPATCHER
virtual ~Filtro () { delete mDebugDispatcher; }
#endif
virtual AUKernelBase * NewKernel() { return new FiltroKernel(this); }
virtual OSStatus GetParameterInfo(AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
AudioUnitParameterInfo &outParameterInfo);
virtual OSStatus GetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable );
virtual OSStatus GetProperty(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
virtual bool SupportsTail () { return false; }
/*! @method Version */
virtual OSStatus Version() { return kFiltroVersion; }
protected:
class FiltroKernel : public AUKernelBase {
public:
FiltroKernel (AUEffectBase *inAudioUnit);
virtual void Process (
const Float32 *inSourceP,
Float32 *inDestP,
UInt32 inFramesToProcess,
UInt32 inNumChannels, // equal to 1
bool &ioSilence
);
virtual void Reset();
private:
Float32 mSampleFrequency;
long mSamplesProcessed;
enum {sampleLimit = (int) 10E6};
float mCurrentScale;
float mNextScale;
};
};
#endif
どうもありがとうございます。私の英語がそれほど悪くないことを願っています。