swift 如何在AudioKit中实现自定义音频效果节点?

plicqrtu  于 12个月前  发布在  Swift
关注(0)|答案(1)|浏览(188)

我正在开发一个使用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
    }

字符串
现在我想创建一个自定义的音高校正效果,并将其添加到链中。我有一个XNUMX-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
    }
}


现在起作用了

6yoyoihd

6yoyoihd1#

这并不简单,因为你想在一个AudioUnit中调用swift外部的c代码来 Package 你的效果。看看DunneAudioKit,例如:

  • /来源/DunneAudioKit/StereoDelay.swift
  • /Sources/CDunneAudioKit/StereoDelayDSP.mm
  • /Sources/CDunneAudioKit/DunneCore/Modulated Delay/StereoDelay.cpp

相关问题