swift - 使用 Audiokit 录制 MIDI
问题描述
我想使用 AudioKit 录制 MIDI 音频。我设法做到了,但是当我重放录制的音符时,会有延迟,而且音符的时间并不总是好的,尤其是当我在录音过程中快速弹奏时。
我是这样做的:我有三个按钮,一个用于 Do(Midi 编号 60),一个用于 Re(midi 编号 62),一个用于 Mi(64)。当按下按钮时,我会发送一个 noteOn,并将时间保存在 88 个浮点数表中。当按钮被按下时,我发送一个 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;
}
}
这是我在此保管箱上的快速项目,供您测试和修改: https ://www.dropbox.com/sh/vnn7soa8aq0180z/AAAzs9PDzND3KPjFIhVobLMya?dl=0
有没有办法避免在结果记录中不尊重时间?例如,通过使用来自 AudioKit 的更自定义的技术,而不是在每个音符事件中手动修改音轨?
解决方案
jouerUp
在方法中添加注释时出错。你应该写在适当的lastNoteOn
位置,而不是在currentPosition
定序器中:
track.add(noteNumber: b, velocity: c, position: lastNoteOn[Int(b)], duration: x - lastNoteOn[Int(b)] , channel: 0)
推荐阅读
- mysql - 如何通过 SQL 上的两个不同因素过滤信息排序?
- php - 使用 Laravel Eloquent 进行基本选择不起作用
- ngxs - NGXS 和与 Angular 9 的兼容性
- kubernetes - 如何修复来自服务器的 kubectl 错误(NotFound):服务器找不到请求的资源
- embedded-linux - 是否有一种准确的方法来计算 i.MX6 上 GPIO 引脚的中断?
- wpf - CefSharp WPF 关闭透明背景
- excel - 分析和更新动态表宏 VBA
- regex - 正则表达式匹配括号和逗号之间的字符串,但存在多个括号
- python - Pytorch GPU 内存分配
- jenkins - Jenkins 传递 Active Choices 参数的值