使用 Audiokit 录制 midi

Recording midi with Audiokit

我想使用 AudioKit 录制 midi 音频。 我设法做到了,但是当我重放录制的音符时,有延迟并且音符的时间并不总是好的,特别是当我在录音过程中快速弹奏时。

我是这样做的:我有三个按钮,一个用于 Do(Midi 编号 60),一个用于 Re(Midi 编号 62),一个用于 Mi(64)。当一个按钮被按下时,我发送一个 noteOn,我将时间保存在 88 table 的 Floats 中。按下按钮时,我发送一个 noteOff 事件,并将音符保存在 midi 文件中。我可以通过执行 (timeNoteOff-timeNoteOn).

来推断要保存的笔记的长度

这是我的一些代码:

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;
    }
}

这是我在这个保管箱上的 swift 项目,供您测试和修改: https://www.dropbox.com/sh/vnn7soa8aq0180z/AAAzs9PDzND3KPjFIhVobLMya?dl=0

有没有办法避免在生成的录音中不遵守时序?例如,通过使用 AudioKit 中更自定义的技术,而不是在每个音符事件中手动修改音轨 ?

jouerUp 方法中添加注释时出错。你应该写在 lastNoteOn 位置,而不是在 sequencer 的 currentPosition:

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