У меня есть буфер с образцами размером 8 кГц, и я пытаюсь просто применить фильтр нижних частот к буфере. Смысл, я начинаю с буфера 8 кГц образцов, и я хочу в итоге получить буфер из 8khz LOWPASSED образцов. Если я подключу низкочастотный блок и подключу его к блоку вывода по умолчанию и поставлю свой буфер, он будет звучать идеально и неправильно пройденный. Однако, как только я удаляю вывод и вызываю AudioUnitRender на низкочастотном аудиоустройстве напрямую, результирующие сэмплы сглаживаются и обрезаются.автономный рендеринг с фильтром нижних частот вызывает сглаживание и обрезку
#import "EffectMachine.h"
#import <AudioToolbox/AudioToolbox.h>
#import "AudioHelpers.h"
#import "Buffer.h"
@interface EffectMachine()
@property (nonatomic, strong) Buffer *buffer;
@end
typedef struct EffectPlayer {
NSUInteger index;
AudioUnit lowPassUnit;
__unsafe_unretained Buffer *buffer;
} EffectPlayer;
OSStatus EffectMachineCallbackRenderProc(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData);
OSStatus EffectMachineCallbackRenderProc(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData) {
struct EffectPlayer *player = (struct EffectPlayer *)inRefCon;
for (int i = 0; i < inNumberFrames; i++) {
float sample;
if (player->index < player->buffer.size) {
sample = (float)player->buffer.samples[player->index];
player->index += 1;
} else {
sample = 0;
}
((float *)ioData->mBuffers[0].mData)[i] = sample;
((float *)ioData->mBuffers[1].mData)[i] = sample;
}
return noErr;
}
@implementation EffectMachine {
EffectPlayer player;
}
-(instancetype)initWithBuffer:(Buffer *)buffer {
if (self = [super init]) {
self.buffer = buffer;
}
return self;
}
-(Buffer *)process {
struct EffectPlayer initialized = {0};
player = initialized;
player.buffer = self.buffer;
[self setupAudioUnits];
Buffer *buffer = [self processedBuffer];
[self cleanup];
return buffer;
}
-(void)setupAudioUnits {
AudioComponentDescription lowpasscd = {0};
lowpasscd.componentType = kAudioUnitType_Effect;
lowpasscd.componentSubType = kAudioUnitSubType_LowPassFilter;
lowpasscd.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent comp = AudioComponentFindNext(NULL, &lowpasscd);
if (comp == NULL) NSLog(@"can't get lowpass unit");
AudioComponentInstanceNew(comp, &player.lowPassUnit);
AURenderCallbackStruct input;
input.inputProc = EffectMachineCallbackRenderProc;
input.inputProcRefCon = &player;
CheckError(AudioUnitSetProperty(player.lowPassUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&input,
sizeof(input)),
"AudioUnitSetProperty for callback failed");
CheckError(AudioUnitSetParameter(player.lowPassUnit,
kLowPassParam_CutoffFrequency,
kAudioUnitScope_Global,
0,
1500,
0), "AudioUnitSetParameter cutoff for lowpass failed");
CheckError(AudioUnitSetParameter(player.lowPassUnit,
kLowPassParam_Resonance,
kAudioUnitScope_Global,
0,
0,
0), "AudioUnitSetParameter resonance for lowpass failed");
CheckError(AudioUnitInitialize(player.lowPassUnit),
"Couldn't initialize lowpass unit");
}
-(Buffer *)processedBuffer {
AudioBufferList *bufferlist = malloc(sizeof(AudioBufferList));
UInt32 blockSize = 1024;
float *left = malloc(sizeof(float) * blockSize);
float *right = malloc(sizeof(float) * blockSize);
bufferlist->mBuffers[0].mData = left;
bufferlist->mBuffers[1].mData = right;
UInt32 size = sizeof(float) * blockSize;
AudioTimeStamp inTimeStamp;
memset(&inTimeStamp, 0, sizeof(AudioTimeStamp));
inTimeStamp.mSampleTime = 0;
AudioUnitRenderActionFlags flag = 0;
NSUInteger length = ceil(self.buffer.size/(float)blockSize);
double *processed = malloc(sizeof(double) * blockSize * length);
for (int i = 0; i < length; i++) {
bufferlist->mBuffers[0].mDataByteSize = size;
bufferlist->mBuffers[1].mDataByteSize = size;
bufferlist->mNumberBuffers = 2;
inTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
AudioUnitRender(player.lowPassUnit, &flag, &inTimeStamp, 0, blockSize, bufferlist);
for (NSUInteger j = 0; j < blockSize; j++) {
processed[j + (blockSize * i)] = left[j];
}
inTimeStamp.mSampleTime += blockSize;
}
Buffer *buffer = [[Buffer alloc] initWithSamples:processed size:self.buffer.size sampleRate:self.buffer.sampleRate];
free(bufferlist);
free(left);
free(right);
free(processed);
return buffer;
}
-(void)cleanup {
AudioOutputUnitStop(player.lowPassUnit);
AudioUnitUninitialize(player.lowPassUnit);
AudioComponentInstanceDispose(player.lowPassUnit);
}
@end
Если добавить общий вывод и попытаться установить 8KHZ ASBD на входе, то я просто получить мусор шум на выходе .. Похоже, 0,0,0,0,0,17438231945853048031929171968.000000, 0,0,0, -2548199532257382185315640279040.000000 ... Yikes!
Я попытался добавить ASBD на вход и выход блока нижних частот, предоставив ему свойство частоты дискретизации 8 кГц, и он ничего не сделал. Я попытался добавить преобразовательные блоки (с ASBDs, установленными на 8 кГц) раньше, а затем, а затем до И после фильтра нижних частот (в цепочке) это также не сработало.
В качестве побочного вопроса, мой буфер представляет собой монограммы 8 кГц, и если у меня есть список буферов, у mNumberBuffers установлен 1, то мой обработчик ввода нижних частот никогда не вызывается ... Есть ли способ не использовать стереоканалы?
Я могу взглянуть на проблему отсечения, если вы нажмете свои изменения (предположительно, на тот же проект, что и раньше) –