AudioKit:将新输入节点连接到混音器时出现问题



我有一个在运行时更改应用程序中仪器的功能。其意图是允许类似于";预设";这可以改变仪器设置——有点像你在";歌曲";DAW的文件。我遇到的问题是,新的混音器连接似乎没有正确,因此音频无法从新添加的乐器中传输到输出。

我的整个信号链可以被描绘成:

[(Instrument Node -> [Instrument Effects] -> AKBooster)] -> Instrument Mixer -> Master Effects -> Master Mixer -> Output

其中第一块表示一组工具及其效果。

管理切换";歌曲";是:

public func connect(trackMap: [Int : InstrumentDefinition], isReconnect: Bool) {

if SequencerController.sharedInstance.synchronizeTracksToTrackMap(trackMap) {

guard let sequencer = SequencerController.sharedInstance.sequencer else { return }
guard let sequence = sequencer.sequence else { return }

var midiInstruments = SequencerController.sharedInstance.midiInstruments
// get track count AFTER synchronizing to trackMap
var trackCount: UInt32 = 0
var status = MusicSequenceGetTrackCount(sequence, &trackCount)
if status != noErr {
print("Conductor.connect(trackMap:) - Error getting track count: (status)")
return
}

for trackIndex in 3 ..< Int(trackCount) {
let instrumentDef = trackMap[trackIndex]!
var track: MusicTrack? = nil
status = MusicSequenceGetIndTrack(sequence, UInt32(trackIndex), &track)
if status != noErr {
print("Conductor.connect(trackMap:) - Error getting sequence track: (status)")
// there's no track associated with this
}
if trackIndex == 3 {
if let soundID = instrumentDef.soundID {
InteractionController.sharedInstance.sequencerInterface.currentSound = soundID
}
}
if let track = track {
var midiInst: SQMIDIInstrument?
var didCreateInstrument = false
switch instrumentDef.instrumentType {
case .sampler:
if let inst = midiInstruments[trackIndex] {
inst.instrumentDefinition = instrumentDef
// While changing presets (or sources; synth/sampler) gate incoming events.
inst.gateEvents = true
// If this track contained a synth, change it to a sampler
if !(inst.instrumentBlock.type == .sampler) {
inst.instrumentBlock.type = .sampler
}
if let soundID = instrumentDef.soundID {
inst.instrumentBlock.changeSoundID(soundID)
}
self.instrumentBlocksByTrack[trackIndex] = inst.instrumentBlock
inst.gateEvents = false
midiInst = inst
} else {
// create a new SQMIDISampler and add
midiInst = SQMIDIInstrument(withInstrumentDefinition: instrumentDef)
// We're replacing this track, so nullify in current midiInstruments dictionary.
midiInstruments[trackIndex] = nil
self.instrumentBlocksByTrack[trackIndex] = midiInst?.instrumentBlock
didCreateInstrument = true
}
case .synth:
// create a new AKSynthOne-based instrument and set preset
if let inst = midiInstruments[trackIndex] {
inst.instrumentDefinition = instrumentDef
inst.gateEvents = true
// If this track contained a sampler, change it to a synth
if !(inst.instrumentBlock.type == .synth) {
inst.instrumentBlock.type = .synth
}
if let soundID = instrumentDef.soundID {
inst.instrumentBlock.changeSoundID(soundID)
}
self.instrumentBlocksByTrack[trackIndex] = inst.instrumentBlock
inst.gateEvents = false
midiInst = inst
} else {
// create a new SQMIDISampler and add
midiInst = SQMIDIInstrument(withInstrumentDefinition: instrumentDef)
// We're replacing this track, so nullify in current midiInstruments dictionary.
midiInstruments[trackIndex] = nil
self.instrumentBlocksByTrack[trackIndex] = midiInst?.instrumentBlock
didCreateInstrument = true
}
case .drumSampler:
if let inst = midiInstruments[trackIndex] {
inst.instrumentDefinition = instrumentDef
inst.gateEvents = true
if !(inst.instrumentBlock.type == .drumSampler) {
inst.instrumentBlock.type = .drumSampler
}
if let soundID = instrumentDef.soundID {
inst.instrumentBlock.changeSoundID(soundID)
}
self.instrumentBlocksByTrack[trackIndex] = inst.instrumentBlock
inst.gateEvents = false
midiInst = inst
} else {
midiInst = SQMIDIInstrument(withInstrumentDefinition: instrumentDef)
// We're replacing this track, so nullify in current midiInstruments dictionary.
midiInstruments[trackIndex] = nil
self.instrumentBlocksByTrack[trackIndex] = midiInst?.instrumentBlock
didCreateInstrument = true
}
default: ()
}

if let inst = midiInst {
SequencerController.setMIDIOutput(inst.midiIn, forTrack: track)
if !isReconnect || didCreateInstrument {
self.instrumentMixer.connect(input: inst.instrumentBlock.booster)
}
midiInstruments[trackIndex] = midiInst
}
}
}
// update the SequencerController's set of midiInstruments
SequencerController.sharedInstance.midiInstruments = midiInstruments
}
}

";midiInstruments";是AKMIDII仪器子类,它将采样器和合成器与仪器效果和增强器(在instrumentBlock中(以及仪器参数(在其instrumentDefinition中(包裹在一起。synchronizeTracksToTrackMap()确保序列具有正确数量的磁道。此函数由Conductor所有,而似乎失败的步骤是self.instrumentMixer.connect(input: inst.instrumentBlock.booster)调用。具体来说,当这个函数添加一个新的音轨,需要一个新混音器连接(即connect(input:)(时,我看到了问题。我可以看到inst正在获取MIDI事件,但没有输出。奇怪的是,曾经一个新的";歌曲";已经创建(添加了曲目和乐器(,我们可以切换到另一首歌,切换回来,乐器就成功连接了。

最终,我们希望能够交换或重新配置上述信号链的第一块;即[(Instrument Node -> [Instrument Effects] -> AKBooster)]部分,代表一个仪器(采样器/合成器(及其效果。我找不到可靠的方法来做到这一点,我非常感谢任何人能给我的建议。

更新:遵循SamB的指导:如何在AudioKit.stop((之后重新连接AKPlayer和AKMixer,并使用AudioKit.engine.connect(inst.instrumentBlock.booster.outputNode, to: self.instrumentMixer.avAudioUnitOrNode, format: nil)而不仅仅是self.instrumentMixer.connect(input:),我能够更接近。仍然没有声音,但我放在我的乐器块中的AKAmplitudeTap(窥探可能出了什么问题(向我表明,那里至少有信号。。。

观看WWDC15视频"核心音频的新功能;非常清楚的是,构建任何AVAudioFoundation信号链的过程是首先将CCD_ 12节点然后将它们CCD_。因此,我重写了所有AudioKit代码的逻辑,跳到苹果的方法,并明确地连接(或分离(节点——例如

AudioKit.engine.attach(akNode.avAudioNode)
AudioKit.engine.connect(akNode.outputNode, to: mixer.avAudioUnitOrNode, format: nil)

通过这种方式重新思考,我能够使事情按预期进行。据我所知,连接/分离时必须关闭发动机,所以我用块来围绕任何连接/分离操作,以切换发动机的关闭/打开。我希望能够避免停止音频,所以如果这不是真正必要的,任何建议或澄清都将不胜感激。

尽管AudioKit很方便,但我认为有点不幸的是,它通过让所有看起来都像连接来向用户隐藏连接/连接的区别。如果你还不了解核心音频——例如,像我一样,主要通过AudioKit来了解它——我强烈建议你考虑先连接,后连接的语义。。。当然,除非您的用例永远不需要更改节点的总数。在我们的案例中,我们需要尽可能减少附件。

最新更新