如何在AudioKit 5.6中实现自定义音高校正效果节点?
基于AudioKit 5.6的实时麦克风音效链与自定义音高校正节点实现
我正在开发一个基于AudioKit 5.6的功能,用于对麦克风输入施加实时音效,且支持用户调整参数。
现有效果链代码
private func initializeEffects() { guard let inputNode = engine.input else { return } fader = Fader(inputNode, gain: 1) compressor = Compressor(fader) compressor.masterGain = 0 dynamicRangeCompressor = DynamicRangeCompressor(compressor) dynamicRangeCompressor.ratio = 100 dynamicRangeCompressor.attackDuration = 0.01 dynamicRangeCompressor.releaseDuration = 0.1 dynamicRangeCompressorDryWetMixer = DryWetMixer(compressor, dynamicRangeCompressor) dynamicRangeCompressorDryWetMixer.balance = 0.75 bandPassButterworth = BandPassButterworthFilter(dynamicRangeCompressorDryWetMixer) bandPassButterworth.bandwidth = 4000 bandPassButterworth.centerFrequency = 0 delay = Delay(bandPassButterworth) delay.feedback = 20 delay.time = 0.25 delay.dryWetMix = 100 delayDryWetMixer = DryWetMixer(bandPassButterworth, delay) delayDryWetMixer.balance = 0 reverb = Reverb(delayDryWetMixer) reverb.dryWetMix = 0 reverb.loadFactoryPreset(.largeChamber) pitchShifter = PitchShifter(reverb) flanger = Flanger(pitchShifter) flanger.frequency = 1 flanger.depth = 1 flanger.feedback = 0 flanger.dryWetMix = 1 flangerDryWetMixer = DryWetMixer(pitchShifter, flanger) flangerDryWetMixer.balance = 0.5 stringResonator = StringResonator(flangerDryWetMixer) stringResonator.feedback = 0.9 stringResonatorDryWetMixer = DryWetMixer(flangerDryWetMixer, stringResonator) stringResonatorDryWetMixer.balance = 0 engine.output = stringResonatorDryWetMixer }
自定义音高校正效果需求
现在需要创建一个自定义音高校正效果并加入该效果链,我有一个Objective-C++库,其提供的音频缓冲区处理方法如下:
- (void)processStereo:(const float *)srcL leftDestination:(float *)dstL rightSource:(const float *)srcR rightDestination:(float *)dstR numSamples:(int)nsmp;
自定义DSP层实现
经过参考资料后,完成了DSP层的实现代码:
#include "SoundpipeDSPBase.h" #include "ParameterRamper.h" #include "Soundpipe.h" #include "CSoundpipeAudioKit.h" #include "tuna.h" enum TunaParameter : AUParameterAddress { TunaFilterPitchCorrectionParameterSpeed, }; class TunaDSP : public SoundpipeDSPBase { private: float speed = 0; ParameterRamper speedRamp; tuna *tuner; public: TunaDSP() { parameters[TunaFilterPitchCorrectionParameterSpeed] = &speedRamp; } void setSpeed(float speed) { this->speed = speed; tuner->setpar(tuna::TUNA_SPEED, speed); reset(); } void init(int channelCount, double sampleRate) override { SoundpipeDSPBase::init(channelCount, sampleRate); tuner = new tuna(); tuner->setpar(tuna::TUNA_SPEED, 1); } void deinit() override { SoundpipeDSPBase::deinit(); } void reset() override { SoundpipeDSPBase::reset(); if (!isInitialized) return; tuner = new tuna(); } #define CHUNKSIZE 8 // defines ramp interval void process(FrameRange range) override { const float *inBuffers[2]; float *outBuffers[2]; inBuffers[0] = (const float *)inputBufferLists[0]->mBuffers[0].mData + range.start; inBuffers[1] = (const float *)inputBufferLists[0]->mBuffers[1].mData + range.start; outBuffers[0] = (float *)outputBufferList->mBuffers[0].mData + range.start; outBuffers[1] = (float *)outputBufferList->mBuffers[1].mData + range.start; //unsigned inChannelCount = inputBufferLists[0]->mNumberBuffers; //unsigned outChannelCount = outputBufferList->mNumberBuffers; if (!isStarted) { // effect bypassed: just copy input to output memcpy(outBuffers[0], inBuffers[0], range.count * sizeof(float)); memcpy(outBuffers[1], inBuffers[1], range.count * sizeof(float)); return; } // process in chunks of maximum length CHUNKSIZE for (int frameIndex = 0; frameIndex < range.count; frameIndex += CHUNKSIZE) { int chunkSize = range.count - frameIndex; if (chunkSize > CHUNKSIZE) chunkSize = CHUNKSIZE; tuner->process(inBuffers[0], inBuffers[1], outBuffers[0], outBuffers[1], chunkSize); // advance pointers inBuffers[0] += chunkSize; inBuffers[1] += chunkSize; outBuffers[0] += chunkSize; outBuffers[1] += chunkSize; } } }; void akTunaFilterPitchCorrectionSetSpeed(DSPRef dspRef, float speed) { auto dsp = dynamic_cast<TunaDSP *>(dspRef); assert(dsp); dsp->setSpeed(speed); } AK_REGISTER_DSP(TunaDSP, "tuna") AK_REGISTER_PARAMETER(TunaFilterPitchCorrectionParameterSpeed)
自定义AudioKit Node实现
对应的Swift节点实现代码如下,目前该自定义音高校正效果节点已可正常工作:
import Foundation import AudioKit import AudioKitEX import CAudioKitEX public class PitchCorrectionAudioKitNode: Node { let input: Node /// Connected nodes public var connections: [Node] { [input] } /// Underlying AVAudioNode public var avAudioNode = instantiate(effect: "tuna") // MARK: - Parameters /// Specification details for feedback public static let speedDef = NodeParameterDef( identifier: "speed", name: "Speed", address: akGetParameterAddress("TunaFilterPitchCorrectionParameterSpeed"), defaultValue: 0.6, range: 0.0 ... 1.0, unit: .percent ) @Parameter(speedDef) public var speed: AUValue // MARK: - Initialization /// Initialize this pitch correction node /// /// - Parameters: /// - input: Input node to process /// public init( _ input: Node, speed: AUValue = speedDef.defaultValue ) { self.input = input setupParameters() self.speed = speed } }
内容的提问来源于stack exchange,提问作者Sotiris Kaniras
相关产品推荐
相关产品推荐

