我正在开发一项功能,它使用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
    }

现在,我想创建一个自定义的音高校正效果,并将其添加到链.我有一个带音频缓冲区并返回修改后的音频缓冲区的X-C ++库:

- (void)processStereo:(const float *)srcL leftDestination:(float *)dstL rightSource:(const float *)srcR rightDestination:(float *)dstR numSamples:(int)nsmp;

我不知道该怎么做.有什么建议吗?

编辑:基于@mahal的回答,我创建了一个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)

Node分:

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
    }
}

现在它起作用了.

推荐答案

这不是无关紧要的事情,因为您希望在包装效果的AudioUnit中调用SWIFT外部的c代码.例如,让我们来看看DunneAudioKit:

  • /Sources/DunneAudioKit/StereoDelay.swft

  • /Sources/CDunneAudioKit/StereoDelayDSP.mm

  • /Sources/CDunneAudioKit/DunneCore/调制延迟/StereoDelay.cpp

Swift相关问答推荐

并发访问SWIFT中数组的非重叠子范围

如何在SwiftUI中做出适当的曲线?

如何增加 NSStatusBar 图像大小?

如何根据 DatePicker 中选定的日期实现 TabView 页面切换?

为什么这段Swift读写锁代码会导致死锁?

可以使 Swift init 仅可用于 Objective C 吗?

使用 swift 的 Firebase 身份验证

如何在一个视图控制器中创建具有相同行为的多个集合视图?

从 Int 到 String 的属性更改引发 SwiftUI 视图不更新

如何 for each 用户制作一个单独的按钮,以便在按下它时切换 isFollowingUser Bool 并更改为关注?

从 Finder 打开文件时,SwiftUI 的应用程序(_ openFile:) 从未调用过

否定 #available 语句

将if let与逻辑或运算符一起使用

swift 3 错误:参数标签 '(_:)' 不匹配任何可用的重载

在 iOS 中使用 Swift 保存 PDF 文件并显示它们

Swift 中 NSFetchRequest 的多个 NSPredicates?

在 Swift 中将计时器标签格式化为小时:分钟:秒

SwiftUI - 呈现工作表后导航栏按钮不可点击

如何在 SwiftUI Segmented Picker 中更改选定的段 colored颜色

为什么枚举具有计算(computed)属性但在 Swift 中没有存储属性?