我正在开发一个使用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
}
}
型
现在起作用了
1条答案
按热度按时间6yoyoihd1#
这并不简单,因为你想在一个AudioUnit中调用swift外部的c代码来 Package 你的效果。看看DunneAudioKit,例如: