Управление генератором с помощью секвенсора в AudioKit v5

Я пытаюсь управлять осциллятором с помощью секвенсора с AudioKit v5, и у меня возникла загвоздка. Я делаю подкласс MIDIInstrument, но не уверен, правильно ли это. См. Код ниже.

Я получаю эту ошибку при запуске:

AVAEInternal.h: 76 обязательное условие - ложь: [AVAudioEngine.mm:413:AttachNode: (node! = Nil)]

Есть предыдущий пост об этом со старой версией AK, который был несколько полезен, но ни одна из ссылок на примеры в нем не работает: Как управлять частотой генератора с помощью секвенсора

Можете ли вы указать мне правильное направление? Большое спасибо!

РЕДАКТИРОВАТЬ: небольшой прогресс? Я неправильно понял функцию AudioEngine и у меня было 2 экземпляра, поэтому я удалил один, что устранило ошибку. И добавление track!.setMIDIOutput(instrument.midiIn) теперь записывает 4 ноты, но по-прежнему нет звука. MIDIInstrument похоже принимает MIDIClientRef, но я не вижу ссылки на это в классе секвенсора ...

import AudioKit
import CAudioKit

class Test2 {

    var instrument: OscMIDIInstrument
    var sequencer: AppleSequencer
    
    init() {

        instrument = OscMIDIInstrument()
        sequencer = AppleSequencer()
        sequencer.setGlobalMIDIOutput(instrument.midiIn)
        instrument.enableMIDI()
                
        let track = sequencer.newTrack()
        track!.setMIDIOutput(instrument.midiIn)
        for i in 0 ..< 4 {
            track!.add(noteNumber: 60, velocity: 64, position: Duration(seconds: Double(i)), duration: Duration(seconds: 0.5))
        }

    }
    
    func testButton() {
        if sequencer.isPlaying {
            sequencer.stop()
        } else {
            sequencer.rewind()
            sequencer.play()
        }
    }
    
}

class OscMIDIInstrument: MIDIInstrument {
    
    var akEngine: AudioEngine
    var osc: Oscillator
    
    init() {
        akEngine = AudioEngine()
        osc = Oscillator()
        super.init()
        akEngine.output = osc
        osc.amplitude = 0.1
        osc.frequency = 440.0
        do {
            try akEngine.start()
        } catch {
            print("Couldn't start AudioEngine.")
        }
    }
    
    override func receivedMIDINoteOn(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel, portID: MIDIUniqueID? = nil, offset: MIDITimeStamp = 0) {
        osc.play()
    }
    
    override func receivedMIDINoteOff(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel, portID: MIDIUniqueID? = nil, offset: MIDITimeStamp = 0) {
        osc.stop()
    }
    
}

person Eggsalad    schedule 23.04.2021    source источник


Ответы (1)


Получилось, что-то вроде. Я нашел этот пример, который указал мне на MIDICallbackInstrument: https://github.com/AudioKit/Cookbook/blob/main/Cookbook/Cookbook/Recipes/CallbackInstrument.swift

Оставшаяся проблема заключается в том, что вы, по-видимому, не можете реализовать сообщения sysex таким образом, я думаю, потому что сообщения обратного вызова ограничены 3 байтами.

Так что я все еще ищу лучшее решение, если кто-то может помочь.

Большое спасибо!

class Test {

    let akEngine = AudioEngine()
    let sequencer = AppleSequencer()
    let osc = Oscillator()
        
    init() {

        let callbackInstrument = MIDICallbackInstrument { [self] status, note, _ in
            guard let midiStatus = MIDIStatusType.from(byte: status) else {
                return
            }
                if midiStatus == .noteOn {
                    print("NoteOn \(note) at \(sequencer.currentPosition.seconds)")
                    osc.play()
                } else if midiStatus == .noteOff {
                    print("NoteOff \(note) at \(sequencer.currentPosition.seconds)")
                    osc.stop()
                }
            }

        let track = sequencer.newTrack()
        for i in 0..< 4 {
            track!.add(noteNumber: 60, velocity: 64, position: Duration(seconds: Double(i)), duration: Duration(seconds: 0.25))
        }
        track?.setMIDIOutput(callbackInstrument.midiIn)

        akEngine.output = osc
        
        do {
            try akEngine.start()
        } catch {
            print("Couldn't start AudioEngine.")
        }

    }
    
    func play() {
        if sequencer.isPlaying {
            sequencer.stop()
        } else {
            sequencer.rewind()
            sequencer.play()
        }
    }
    
}
person Eggsalad    schedule 26.04.2021