Частотная модуляция AVAudioEngine в реальном времени

Я хотел бы изменить входящий сигнал в режиме реального времени и отправить его на динамики устройств iOS. Я читал, что для таких задач можно использовать AVAudioEngine. Но не могу найти документацию или примеры того, чего я хотел бы достичь.

Для целей тестирования я сделал:

audioEngine = AVAudioEngine()

let unitEffect = AVAudioUnitReverb()
unitEffect.wetDryMix = 50

audioEngine.attach(unitEffect)

audioEngine.connect(audioEngine.inputNode, to: unitEffect, format: nil)
audioEngine.connect(unitEffect, to: audioEngine.outputNode, format: nil)

audioEngine.prepare()

и если нажать кнопку, я просто делаю:

do {
    try audioEngine.start()
} catch {
    print(error)
}

or audioEngine.stop().

Эффект реверберации применяется к сигналу, и я слышу, что он работает. Итак, теперь я хотел бы избавиться от реверберации и:

  1. модулировать входящий сигнал, например инвертировать сигнал, модулировать частоту и т. д. Есть ли какой-то набор эффектов, которые можно использовать, или возможность каким-то математическим образом модулировать частоту?
  2. При запуске на устройстве iOS я получаю здесь реверберацию, но вывод идет только на верхний динамик телефона, а не на громкий нижний. Как это изменить?

person Leo    schedule 21.02.2018    source источник


Ответы (1)


Этот репозиторий github буквально сделал это: https://github.com/dave234/AppleAudioUnit.

Просто добавьте BufferedAudioUnit в свой проект оттуда и подклассируйте его своей реализацией следующим образом:

AudioProcessingUnit.h:

#import "BufferedAudioUnit.h"

@interface AudioProcessingUnit : BufferedAudioUnit

@end

AudioProcessingUnit.m:

#import "AudioProcessingUnit.h"

@implementation AudioProcessingUnit

-(ProcessEventsBlock)processEventsBlock:(AVAudioFormat *)format {

    return ^(AudioBufferList       *inBuffer,
             AudioBufferList       *outBuffer,
             const AudioTimeStamp  *timestamp,
             AVAudioFrameCount     frameCount,
             const AURenderEvent   *realtimeEventListHead) {

        for (int i = 0; i < inBuffer->mNumberBuffers; i++) {

            float *buffer = inBuffer->mBuffers[i].mData;
            for (int j = 0; j < inBuffer->mBuffers[i].mDataByteSize; j++) {
                buffer[j] = /*process it here*/;
            }

            memcpy(outBuffer->mBuffers[i].mData, inBuffer->mBuffers[i].mData, inBuffer->mBuffers[i].mDataByteSize);
        }
    };
}

@end

И в вашей настройке AVAudioEngine:

let audioComponentDescription = AudioComponentDescription(
            componentType: kAudioUnitType_Effect,
            componentSubType: kAudioUnitSubType_VoiceProcessingIO,
            componentManufacturer: 0x0,
            componentFlags: 0,
            componentFlagsMask: 0
        );

        AUAudioUnit.registerSubclass(
            AudioProcessingUnit.self,
            as: audioComponentDescription,
            name: "AudioProcessingUnit",
            version: 1
        )

        AVAudioUnit.instantiate(
            with: audioComponentDescription,
            options: .init(rawValue: 0)
        ) { (audioUnit, error) in
            guard let audioUnit = audioUnit else {
                NSLog("Audio unit is NULL")
                return
            }

            let formatHardwareInput = self.engine.inputNode.inputFormat(forBus: 0)

            self.engine.attach(audioUnit)
            self.engine.connect(
                self.engine.inputNode,
                to: audioUnit,
                format: formatHardwareInput
            )
            self.engine.connect(
                audioUnit,
                to: self.engine.outputNode,
                format: formatHardwareInput
            )
        }
person Roman Samoilenko    schedule 18.07.2019