如何解决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”是AKMIDIInstrument子类,它包装了采样器和合成器以及乐器效果和增强器(在instrumentBlock
中)以及乐器的参数(在其instrumentDefinition
中)。 synchronizeTracksToTrackMap()
确保序列具有正确的轨道数。该功能归Conductor
所有,似乎失败的步骤是self.instrumentMixer.connect(input: inst.instrumentBlock.booster)
调用。具体来说,当此函数添加新轨道并需要新的混音器连接(即connect(input:)
)时,我看到了问题。我可以看到inst
正在接收MIDI事件,但是没有输出。奇怪的是,一旦创建了新的“歌曲”(添加了它的音轨和乐器),我们就可以切换到另一首歌曲,然后再切换回去,并且乐器连接成功。
最终,我们希望能够交换或重新配置上面概述的信号链的第一块;即[(Instrument Node -> [Instrument Effects] -> AKBooster)]
部分,代表一种乐器(采样器/合成器)及其效果。我找不到一种可靠的方法,非常感谢任何人都能提供的任何建议。
更新:遵循SamB从这里开始的指导:How to reconnect AKPlayer and AKMixer after AudioKit.stop(),并使用AudioKit.engine.connect(inst.instrumentBlock.booster.outputNode,to: self.instrumentMixer.avAudioUnitOrNode,format: nil)
而不是self.instrumentMixer.connect(input:)
,我可以走得更近。仍然没有声音,但是我在我的instrumentBlock中放的AKAmplitudeTap(窥探可能出了什么问题)告诉我那里至少有信号...
解决方法
观看WWDC15视频“ Core Audio的新增功能”,很明显,建立任何AVAudioFoundation信号链的过程首先是先到attach
个节点,然后是connect
稍后将它们转换成图表。因此,我重写了所有AudioKit代码的逻辑,以跳到Apple的方法,并明确地附加(或分离)并连接节点,例如
AudioKit.engine.attach(akNode.avAudioNode)
AudioKit.engine.connect(akNode.outputNode,to: mixer.avAudioUnitOrNode,format: nil)
以这种方式重新思考,我能够使事情按预期进行。据我了解,安装/拆卸引擎时必须关闭引擎,因此我将所有的添加/拆卸操作都用块包围起来,以关闭/打开引擎。我希望能够避免停止音频,因此,如果真的没有必要,那么我们将不胜感激。
像AudioKit一样方便,我认为它有点遗憾,因为它使所有外观像连接一样,向用户隐藏了附加/连接的区别。如果您还不了解Core Audio(例如像我一样主要通过AudioKit来了解它),我强烈建议您考虑使用Attach-first,connect-later语义...当然,除非您有用例永远不需要更改节点总数。在我们的情况下,我们需要尽可能减少附件。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。