Swift AudioKit:如何构建音高受AR包络控制的VCO? [英] Swift AudioKit: How to build an VCO who's pitch is controlled by an AR-envelope?

查看:118
本文介绍了Swift AudioKit:如何构建音高受AR包络控制的VCO?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是AudioKit的新手.我想建立一个VCO,其音高由可重新触发的A(H)R包络(衰减可调)控制,我正在寻找最佳或最常用的方法.

经过一些研究(过滤器信封示例./p>

我尝试过:

enum PitchEnvVCOSynthParameter: Int {
    case frequency, decayTime, gate
}

struct PitchEnvVCO {
    static var frequency: AKOperation {
        return AKOperation.parameters[PitchEnvVCOSynthParameter.frequency.rawValue]
    }
    static var decayTime: AKOperation {
        return AKOperation.parameters[PitchEnvVCOSynthParameter.decayTime.rawValue]
    }
    static var gate: AKOperation {
        return AKOperation.parameters[PitchEnvVCOSynthParameter.gate.rawValue]
    }
}

extension AKOperationGenerator {
    var frequency: Double {
        get { return self.parameters[PitchEnvVCOSynthParameter.frequency.rawValue] }
        set(newValue) { self.parameters[PitchEnvVCOSynthParameter.frequency.rawValue] = newValue }
    }
    var decayTime: Double {
        get { return self.parameters[PitchEnvVCOSynthParameter.decayTime.rawValue] }
        set(newValue) { self.parameters[PitchEnvVCOSynthParameter.decayTime.rawValue] = newValue }
    }
    var gate: Double {
        get { return self.parameters[PitchEnvVCOSynthParameter.gate.rawValue] }
        set(newValue) { self.parameters[PitchEnvVCOSynthParameter.gate.rawValue] = newValue }
    }
}

使用

class SimpleGenerator: AKNode {

    var generator = AKOperationGenerator { parameters in

        var oscillator = AKOperation.squareWave(frequency: PitchEnvVCO.frequency.triggeredWithEnvelope(
           trigger: PitchEnvVCO.gate,
           attack: 0.01,
           hold: 0.01,
           release: 0.2
        )).triggeredWithEnvelope(trigger: PitchEnvVCO.gate, attack: 0.1, hold: 0.01, release: 0.5)

        return oscillator
    }

    var vco1Freq: Double = 440.0 {
        didSet {
            generator.parameters[PitchEnvVCOSynthParameter.frequency.rawValue] = vco1Freq
        }
    }

    var pitchDecay: Double = 0.1 {
        didSet {
            generator.parameters[PitchEnvVCOSynthParameter.decayTime.rawValue] = pitchDecay
        }
    }
    var sourceMixer = AKMixer()

    func start() {
        generator.parameters = [vco1Freq, pitchDecay, 0] // Initialize the array
        generator.start()
    }

    func triggerGate(_ freq: Double) {
        vco1FreqOffset = freq
        generator.parameters[PitchEnvVCOSynthParameter.gate.rawValue] = 1
        // or generator.trigger(1)
    }

    override init() {
        sourceMixer = AKMixer(generator)
        super.init()
        avAudioNode = sourceMixer.avAudioNode
    }
}

我通过音序器轨道触发发生器,触发回溯

let seqPositioncallbackTrack = sequencer.newTrack()
seqPositioncallbackTrack?.setMIDIOutput(sequencerCallbackInst.midiIn)
sequencerCallbackInst.callback = { status, noteNumber, velocity in
    self.onSequencerStepChange(status: status, noteNumber: noteNumber, velocity: velocity)
}
//...for i in 0 ..< numberOfSteps...etc.
seqPositioncallbackTrack?.add(noteNumber: MIDINoteNumber(i), 
    velocity: 100, 
    position: AKDuration(beats: Double(i)), 
    duration: AKDuration(beats: 0.5)
)

效果很好.但是我只是听到无休止的声音(频率正确).只有第一个触发器的音高会增大.其他触发器不会重新触发信封.怎么了-我怎么弄错了? THNX

解决方案

似乎我需要找到正确的门控开启时间长度(注意音序器步长的长度),并向将门设置为零.

...duration: AKDuration(seconds: 0.03)


private func onSequencerStepChange(status: AKMIDIStatus, noteNumber: MIDINoteNumber, velocity: MIDIVelocity) {

    if status == .noteOn {
        core.triggerGateOn(seq1Values[Int(noteNumber)])
    }
    else if status == .noteOff {
        core.triggerGateOff()
    }
    else { return }

}
...
// splitting func triggerGate(_ freq: Double) into on/off:
func triggerGateOn(_ freq: Double) {
    generator.parameters[PitchEnvVCOSynthParameter.gate.rawValue] = 1
}

func triggerGateOff() {
    generator.parameters[PitchEnvVCOSynthParameter.gate.rawValue] = 0
}

当持续时间太短时,它似乎也不起作用,表示< 0.03-那么我想比在完成攻击时间之前快将关门设置为关闭. 还有我必须使用释放时间来模拟的衰减时间

let generator = AKOperationGenerator { parameters in

    let oscillator = AKOperation.squareWave(
        frequency: PitchEnvVCO.frequency.triggeredWithEnvelope(
            trigger: PitchEnvVCO.gate,
            attack: 0.01,
            hold: 0.0,
            release: PitchEnvVCO.freqDecayTime
        ),
        amplitude: PitchEnvVCO.amplitude.triggeredWithEnvelope(
            trigger: PitchEnvVCO.gate,
            attack: 0.01,
            hold: 0.0,
            release: PitchEnvVCO.ampDecayTime
        )
    )
    return oscillator
}

确定-我找到的正确答案是and wrong directions) it looks to me that I have to go with AKOperationGenerator and AKOperation.

Best example to follow was the Filter Envelope example from the playgrounds.

I tried:

enum PitchEnvVCOSynthParameter: Int {
    case frequency, decayTime, gate
}

struct PitchEnvVCO {
    static var frequency: AKOperation {
        return AKOperation.parameters[PitchEnvVCOSynthParameter.frequency.rawValue]
    }
    static var decayTime: AKOperation {
        return AKOperation.parameters[PitchEnvVCOSynthParameter.decayTime.rawValue]
    }
    static var gate: AKOperation {
        return AKOperation.parameters[PitchEnvVCOSynthParameter.gate.rawValue]
    }
}

extension AKOperationGenerator {
    var frequency: Double {
        get { return self.parameters[PitchEnvVCOSynthParameter.frequency.rawValue] }
        set(newValue) { self.parameters[PitchEnvVCOSynthParameter.frequency.rawValue] = newValue }
    }
    var decayTime: Double {
        get { return self.parameters[PitchEnvVCOSynthParameter.decayTime.rawValue] }
        set(newValue) { self.parameters[PitchEnvVCOSynthParameter.decayTime.rawValue] = newValue }
    }
    var gate: Double {
        get { return self.parameters[PitchEnvVCOSynthParameter.gate.rawValue] }
        set(newValue) { self.parameters[PitchEnvVCOSynthParameter.gate.rawValue] = newValue }
    }
}

with

class SimpleGenerator: AKNode {

    var generator = AKOperationGenerator { parameters in

        var oscillator = AKOperation.squareWave(frequency: PitchEnvVCO.frequency.triggeredWithEnvelope(
           trigger: PitchEnvVCO.gate,
           attack: 0.01,
           hold: 0.01,
           release: 0.2
        )).triggeredWithEnvelope(trigger: PitchEnvVCO.gate, attack: 0.1, hold: 0.01, release: 0.5)

        return oscillator
    }

    var vco1Freq: Double = 440.0 {
        didSet {
            generator.parameters[PitchEnvVCOSynthParameter.frequency.rawValue] = vco1Freq
        }
    }

    var pitchDecay: Double = 0.1 {
        didSet {
            generator.parameters[PitchEnvVCOSynthParameter.decayTime.rawValue] = pitchDecay
        }
    }
    var sourceMixer = AKMixer()

    func start() {
        generator.parameters = [vco1Freq, pitchDecay, 0] // Initialize the array
        generator.start()
    }

    func triggerGate(_ freq: Double) {
        vco1FreqOffset = freq
        generator.parameters[PitchEnvVCOSynthParameter.gate.rawValue] = 1
        // or generator.trigger(1)
    }

    override init() {
        sourceMixer = AKMixer(generator)
        super.init()
        avAudioNode = sourceMixer.avAudioNode
    }
}

I trigger the generator via a sequencer track, triggering a calback

let seqPositioncallbackTrack = sequencer.newTrack()
seqPositioncallbackTrack?.setMIDIOutput(sequencerCallbackInst.midiIn)
sequencerCallbackInst.callback = { status, noteNumber, velocity in
    self.onSequencerStepChange(status: status, noteNumber: noteNumber, velocity: velocity)
}
//...for i in 0 ..< numberOfSteps...etc.
seqPositioncallbackTrack?.add(noteNumber: MIDINoteNumber(i), 
    velocity: 100, 
    position: AKDuration(beats: Double(i)), 
    duration: AKDuration(beats: 0.5)
)

which works fine. But I just hear an endless tone (with the correct frequency). Only the first trigger swells in pitch. The other triggers don't re-trigger the envelopes. How comes - what get I wrong? THNX

解决方案

It seems like I needed to find the correct length of the gate-on time (note length of sequencer step duration) and also send a gate-off event to set the gate to zero.

...duration: AKDuration(seconds: 0.03)


private func onSequencerStepChange(status: AKMIDIStatus, noteNumber: MIDINoteNumber, velocity: MIDIVelocity) {

    if status == .noteOn {
        core.triggerGateOn(seq1Values[Int(noteNumber)])
    }
    else if status == .noteOff {
        core.triggerGateOff()
    }
    else { return }

}
...
// splitting func triggerGate(_ freq: Double) into on/off:
func triggerGateOn(_ freq: Double) {
    generator.parameters[PitchEnvVCOSynthParameter.gate.rawValue] = 1
}

func triggerGateOff() {
    generator.parameters[PitchEnvVCOSynthParameter.gate.rawValue] = 0
}

it also seems not to work when the duration time is too short, means < 0.03 - then I guess the gate-on is faster set to off than the attack time was finished. also the decay time I had to simulate using the release time instead

let generator = AKOperationGenerator { parameters in

    let oscillator = AKOperation.squareWave(
        frequency: PitchEnvVCO.frequency.triggeredWithEnvelope(
            trigger: PitchEnvVCO.gate,
            attack: 0.01,
            hold: 0.0,
            release: PitchEnvVCO.freqDecayTime
        ),
        amplitude: PitchEnvVCO.amplitude.triggeredWithEnvelope(
            trigger: PitchEnvVCO.gate,
            attack: 0.01,
            hold: 0.0,
            release: PitchEnvVCO.ampDecayTime
        )
    )
    return oscillator
}

EDIT: ok - the correct answer I found I posted here

这篇关于Swift AudioKit:如何构建音高受AR包络控制的VCO?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆