Recording midi with Audiokit

a 夏天 提交于 2019-12-10 11:19:43

问题


I want to record midi audio using AudioKit. I managed to do it but when I replay the recorded notes, there are delays and the timing of the notes is not always the good one, especially when I play fast during the recording.

Here is how i did it : I have three buttons, one for Do (Midi number 60), one for Re (midi number 62), one for Mi (64). When a button is pushed down i send a noteOn, and I save the time in a 88 table of Floats. When the button is pushed up, I send a noteOff event, and I save the note in the midi file. I can deduce the length of the note to save, by doing (timeNoteOff-timeNoteOn).

Here is some of my code :

var sequencer : AKSequencer = AKSequencer()
var track = AKMusicTrack()
var lastNoteOn:[AKDuration] = Array(repeating: AKDuration(seconds: 0), count: 88)
var sampler : AKAppleSampler = AKAppleSampler()

@IBAction func startRecordClick(_ sender: Any) {
    track.clear()
    sequencer.rewind()
    sequencer.play()
}

@IBAction func stopRecordClick(_ sender: Any) {
    if(sequencer.isPlaying){
        sequencer.stop()
    }
}

@IBAction func playClick(_ sender: Any) {
    sequencer.rewind()
    sequencer.play()
    let list = sequencer.tracks[0].getMIDINoteData()
    print(list)
}

@IBAction func doClick(_ sender: Any) {
    jouerDown(a:144, b:60, c:80) // 60 means midi number 60, ie C4
}

@IBAction func doUp(_ sender: Any) {
    jouerUp(a:144, b:60, c:80)
}

override func viewDidLoad() {
    super.viewDidLoad()

    do{try
        sampler.loadMelodicSoundFont("TimGM6mb", preset: 0)
    } catch {
        print("couldn't load sf2 file")
    }
    AudioKit.output = sampler

    let callbackInstr = AKMIDICallbackInstrument()
    callbackInstr.callback = myCallBack

    track = sequencer.newTrack()!
    sequencer.setGlobalMIDIOutput(callbackInstr.midiIn)
    sequencer.preroll()

    try! AudioKit.start()
}

func jouerDown(a:UInt8, b:MIDINoteNumber, c:MIDIVelocity){
    lastNoteOn[Int(b)] = sequencer.currentPosition
    try! sampler.play(noteNumber: b,velocity: c,channel: 0)
}

func jouerUp(a:UInt8, b:MIDINoteNumber, c:MIDIVelocity){
    let x = sequencer.currentPosition
    try! sampler.stop(noteNumber: b, channel: 0)
    if(sequencer.isPlaying){
        track.add(noteNumber: b, velocity: c, position: x, duration: x - lastNoteOn[Int(b)] , channel: 0)
    }
}

func myCallBack(a:UInt8, b:MIDINoteNumber, c:MIDIVelocity) {
    switch(a){
        case 144, 157:
            try! sampler.play(noteNumber: b,velocity: c,channel: 0)
            print("\(a) \(b)")
            break;
        default:
            try! sampler.stop(noteNumber: b, channel: 0)
            break;
    }
}

Here is my swift project on this dropbox for you to test and modify : https://www.dropbox.com/sh/vnn7soa8aq0180z/AAAzs9PDzND3KPjFIhVobLMya?dl=0

Is there a way to avoid the non-respect of the timing in the resulting recording ? For example by using a more custom technique from AudioKit, instead of modifying the track by hand at each note event ?


回答1:


Error in adding notes in jouerUp method. You should write in lastNoteOnposition, not in currentPosition of the sequencer:

track.add(noteNumber: b, velocity: c, position: lastNoteOn[Int(b)], duration: x - lastNoteOn[Int(b)] , channel: 0)


来源:https://stackoverflow.com/questions/54815702/recording-midi-with-audiokit

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!