【发布时间】:2020-09-12 23:39:18
【问题描述】:
我有一个功能可以在运行时更改我们应用中的仪器。其目的是允许诸如“预设”之类的东西可以改变乐器设置——有点像你在 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(以查看可能出现的问题)显示至少那里有信号......
【问题讨论】: