本专题已述及 多次我已经成功地使用了 AKMIDICallbackInstrument
与旧 AKAppleSequencer
在我以前的应用程序中。
我开始使用新的 AKSequencer
这绝对是个了不起的东西:优雅的界面,易于使用。然而,我终其一生都无法理解如何用它来处理回调事件。我需要使用一个回调来触发基于音序器播放的GUI事件。
这是我的示例代码。
private func setMetronome(bpm: BPM, beats:Int)
{
sequencer = AKSequencer(targetNode: metronomeSampler)
sequencer.tempo = bpm
sequencer.loopEnabled = false
sequencer.length = Double(beats)
metroCallback.callback = {status, noteNumber, velocity in
if let midiStatus = AKMIDIStatus(byte: status), midiStatus.type != .noteOn { return }
//Do callback stuff here
}
let metroCallbackTrack = sequencer.addTrack(for: metroCallback)
for i in 0..<beats
{
if i == 0
{
sequencer.add(noteNumber: MIDINoteNumber(67), position: Double(i), duration: 1.0)
metroCallbackTrack.add(noteNumber: MIDINoteNumber(67), position: Double(i), duration: 1.0)
}
else if (i % 4 == 0)
{
sequencer.add(noteNumber: MIDINoteNumber(67), position: Double(i), duration: 1.0)
metroCallbackTrack.add(noteNumber: MIDINoteNumber(60), position: Double(i), duration: 1.0)
}
else
{
sequencer.add(noteNumber: MIDINoteNumber(60), position: Double(i), duration: 1.0)
metroCallbackTrack.add(noteNumber: MIDINoteNumber(60), position: Double(i), duration: 1.0)
}
print("seq count:\(i)")
}
for track in sequencer.tracks
{
print("Adding track to mixer:\(track.length)")
track >>> mixer
}
}
这段代码正确地创建了一个序列 n
节奏的数量,它通过我的 AKSampler
世界上的一切都很好。除了没有回调事件发生(使用打印语句来确认)
思想过程
随着 AKAppleSequencer
和 AKMIDICallbackInstrument
,你可以设置 globalMIDIOutput
随着 AKAppleSequencer
与midi输入的 AKMIDICallBackInstrument
.
现在,新的 AKSequencer
和 AKCallbackInstrument
没有这些选项,而新的 "新 "也没有这些选项。AKSequencerTrack
昔日 AKAppleSequencer
会用 AKMusicTrack
对象,可以设置midi输入输出)。) 在查看新的 AKSequencer
它的驱动力是 AKNode
对象。AKCallbackInstrument
是 a AKNode
对象,并且应该能够由具有正确midi数据的轨道驱动。
我在音序器中添加了一个音轨,并从该音轨和必要的midi数据中复制了我想要回调的midi事件,并执行我的GUI事件。然而,用这种方法,它似乎没有调用回调。
有谁知道如何用回调来使用这些新组件?我真的不想再回到过去的 AKAppleSequencer
除非显然没有办法使用新的 AKSequencer
.
要获得 AKCallbackInstrument
与新的 AKSequencer
试着把你的回调工具连接到你的输出上,例如。
metroCallback >>> mixer
不是很明显,但对我来说是有效的。
编辑:包括一个最小的工作版本的新的 AKSequencer
与 AKCallbackInstrument
class SequencerWrapper {
var seq: AKSequencer!
var cbInst: AKCallbackInstrument!
var mixer: AKMixer!
init() {
mixer = AKMixer()
AudioKit.output = mixer
seq = AKSequencer()
cbInst = AKCallbackInstrument()
// set up a track
let track = seq.addTrack(for: cbInst)
for i in 0 ..< 4 {
track.add(noteNumber: 60, position: Double(i), duration: 0.5)
}
track.length = 4.0
track.loopEnabled = true
track >>> mixer // must send track to mixer
// set up the callback instrument
cbInst.callback = { status, note, vel in
guard let status = AKMIDIStatus(byte: status),
let type = status.type,
type == .noteOn else { return }
print("note on: \(note)")
// trigger sampler etc from here
}
cbInst >>> mixer // must send callbackInst to mixer
}
func play() {
seq.playFromStart()
}
}
谢谢 @c_booth 提供的工作示例! 我只是想补充一下,如果像我这样的傻瓜不明白为什么上面的例子不能工作,你仍然需要调用AudioKit.start()。