quaternionboy
quaternionboy

Reputation: 361

Audiokit 5 - connect Sequencer to MIDIInstrument

I can connect to the Sequencer a physical instrument like Shaker or a callBackInstrument fine, but not a MIDIInstrument like SynthKick

var sequencer = Sequencer()
var synthKick = SynthKick()
synthKick.enableMIDI()
var track = sequencer.addTrack(for: synthKick)
track.sequence.add(noteNumber: MIDINoteNumber(60), position: 0, duration: 1)
mixer.addInput(synthKick)

on SynthKick:

public override func start(noteNumber: MIDINoteNumber,
                           velocity: MIDIVelocity,
                           channel: MIDIChannel,
                           timeStamp: MIDITimeStamp? = nil) {
    play(noteNumber: noteNumber)
}

The code above not outputs signal

What I'm doing wrong ?

Upvotes: 0

Views: 225

Answers (1)

JohnOfIreland
JohnOfIreland

Reputation: 281

I know its a long time since you posed this question but I was looking at this stuff myself so I decided to answer.

I used the CallbackInstrumentConductor in the following link:

https://github.com/AudioKit/Cookbook/blob/main/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/CallbackInstrument.swift

to figure out how to extend MIDIInstrument, I used a synth from DunneAudioKit as the output ,

DunneAudioKit :

https://github.com/AudioKit/DunneAudioKit

The following code worked for me, see if this helps

1: imports

import CoreMIDI
import AudioKit
import DunneAudioKit
import SwiftUI

2: extended MIDIInstrument

class Extended_MidiInstrument : MIDIInstrument{
let synth = Synth()
init(){
    super.init()
    self.avAudioNode = synth.avAudioNode
}

override func start(noteNumber: MIDINoteNumber, velocity:   MIDIVelocity, channel: MIDIChannel, timeStamp: MIDITimeStamp? = nil) {
    self.synth.play(noteNumber: noteNumber, velocity: velocity)
}

override func stop(noteNumber: MIDINoteNumber, channel: MIDIChannel, timeStamp: MIDITimeStamp? = nil) {
    self.synth.stop(noteNumber: noteNumber)
}

}

3: the Conductor - heavily influenced by the callback conductor.

class Extended_MidiInstrumentConductor: ObservableObject {

let xmidiInst = Extended_MidiInstrument()
let engine = AudioEngine()
var sequencer = AppleSequencer()
var tempo = 120.0
var division = 1

init() {
    let seq_Track = sequencer.newTrack()
    for i in 0 ..< division {
        seq_Track?.add(noteNumber: 40,
                        velocity: 100,
                        position: Duration(beats: Double(i) / Double(division)),
                        duration: Duration(beats: Double(0.1 / Double(division))))
        seq_Track?.add(noteNumber: 60,
                        velocity: 100,
                        position: Duration(beats: (Double(i) + 0.5) / Double(division)),
                        duration: Duration(beats: Double(0.1 / Double(division))))
    }
    seq_Track?.setMIDIOutput(xmidiInst.midiIn)
    seq_Track?.setLoopInfo(Duration(beats: 1.0), loopCount: 0)
    sequencer.setTempo(tempo)
    engine.output = xmidiInst
}

func start_Engine() {
    do {
        try engine.start()
    } catch let err {
        Log(err)
    }
}

func stop_Engine() {
    engine.stop()
}

}

4: (finally) the view for the conductor in (3)

struct Extended_MidiInstrumentView: View {

@StateObject var conductor : Extended_MidiInstrumentConductor

var body: some View {
    VStack(spacing: 30) {
        Text("Play").onTapGesture {
            self.conductor.sequencer.play()
            print("play called")
        }.foregroundColor(.white)
        Text("Pause").onTapGesture {
            self.conductor.sequencer.stop()
            print("pause called")
        }.foregroundColor(.white)
        Text("Rewind").onTapGesture {
            self.conductor.sequencer.rewind()
            print("rewind called")
        }.foregroundColor(.white)
    }
        .onAppear {
            self.conductor.start_Engine()
        }
        .onDisappear {
            self.conductor.stop_Engine()
        }
}
}

Obviously you don't actually need the print commands, but anyway if that's any help ....

Upvotes: 1

Related Questions