AudioKit: использование нового AKSequencer с любым набором инструментов обратного вызова
Эта тема освещалась много раз, и я успешно использовалAKMIDICallbackInstrument
со старым AKAppleSequencer
в моих предыдущих приложениях.
Я начинаю пользоваться новым AKSequencer
что абсолютно феноменально: элегантный интерфейс и простота использования. Однако я не могу понять, как с его помощью обрабатывать события обратного вызова. Мне нужно использовать обратный вызов, чтобы запускать события графического интерфейса пользователя на основе воспроизведения секвенсора.
Вот мой пример кода:
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
являетсяAKNode
объект и должен иметь возможность управлять треком с правильными данными midi.
Я добавляю трек в свой секвенсор, и из этого трека, и необходимые midi-данные, которые точно дублируют midi-события, которые я хочу вызвать, и выполнить мои GUI-события. Однако при таком подходе он, похоже, не вызывает обратный вызов.
Кто-нибудь знает, как использовать эти новые компоненты с обратным вызовом? Я действительно не хочу возвращаться кAKAppleSequencer
если явно нет способа управлять обратными вызовами с новым AKSequencer
.
3 ответа
Получить 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().
Рабочая версия приведенного выше примера для Audiokit 5.3. На самом деле собственный секвенсор теперь является частью AudioKitEx, поэтому вам придется импортировать оба пакета. Очень жаль, что в поваренной книге нет рабочего примера. В общем, самый точный и надежный таймер для iOS и Mac.
Из предыдущего примера я ввел новые Classnames, отбросил микшер и сократил Sequencer до одного SequencerTrack, это возможно, потому что они работают сами по себе. С аудиокитом 5.3. невозможно, подключить трек к микшеру напрямую, кроме того оператор >>> больше не работает.
Так что это должна быть самая минимальная версия Audiokit Sequencer:
// Created by c_booth,
// current version by Heiko Henrich on 23.12.22.
//
import AudioKit
import AudioKitEX
import AVFoundation
class SequencerWrapper {
var cbInst: CallbackInstrument!
var engine: AudioEngine!
var track: SequencerTrack!
init() {
engine = AudioEngine()
cbInst = CallbackInstrument { status, note, vel in
guard let status = MIDIStatus(byte: status),
let type = status.type,
type == .noteOn else { return }
print("note on: \(note)")
// trigger sampler etc from here
}
engine.output = cbInst
// set up a track
track = SequencerTrack(targetNode: cbInst)
track.add(noteNumber: 60, position: 0, duration: 0.5)
track.length = 1.0
try! engine.start()
track.playFromStart()
}
}