Эта тема была рассмотрена Много раз, и я успешно использовал 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 с миди-вводом AKMIDICallBackInstrument.

Теперь новые AKSequencer и AKCallbackInstrument не имеют этих опций, равно как и новые AKSequencerTrack (старый AKAppleSequencer будет использовать AKMusicTrack объекты, которые могли бы установить миди-ввод /вывод). Рассматривая реализацию нового AKSequencer, он управляется AKNode объектами, AKCallbackInstrument является объектом AKNode и должен иметь возможность ведомый треком с нужными миди данными.

Я добавляю трек в мой секвенсор и из этого трека необходимые миди-данные, которые точно дублируют миди-события, на которые я хочу отозвать, и выполняю события GUI. Однако при таком подходе он не вызывает обратный вызов.

У кого-нибудь есть идеи, как использовать эти новые компоненты с обратным вызовом? Я действительно не хочу возвращаться к AKAppleSequencer, если нет явного способа управлять обратными вызовами с новым AKSequencer.

1
Max 29 Апр 2020 в 02:26

2 ответа

Чтобы 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()
    }
}
2
c_booth 18 Май 2020 в 17:28

Спасибо за рабочий пример @c_booth! Я просто хотел добавить для таких макетов, как я, которые не могли понять, почему вышеприведенный пример не работает, вам все равно нужно вызвать AudioKit.start ().

0
Daniel 22 Май 2020 в 15:15