在 swift 中播放一系列 MIDI 音符
Play a sequence of MIDI notes in swift
一个接一个地弹奏音符的最佳方式是什么?这是我现在拥有的最实用的代码。
let majorScale = [60, 62, 64, 65, 67, 69, 71, 72]
for i in majorScale {
sampler.startNote(UInt8(i), withVelocity: 127, onChannel: 1)
sleep(1)
sampler.stopNote(UInt8(i), onChannel: 1)
}
这个方法的问题是 sleep() 只接受 UInt8 作为参数,所以我不能用这种方式做一个持续不到 1 秒的笔记。
我首先是一个音乐家。我只是碰巧在大学时对编程有所了解,当时我参加了一对 java 类。也就是说,我真的不知道还有什么其他选择。
有没有我可以用来处理音符时长的内置 MIDI 播放器?
有没有办法"sleep"不到一秒,然后自己计算时长?因为在 100 bpm 下演奏的 1/8 音符将持续 ((60/100)/2) = 0.3 秒。
我应该取而代之的是获取音符信息并制作一个我可以播放的 MIDI 文件吗?
如何最好地解决这个问题?
编辑
这是更新后的代码:
for i in majorScale {
sampler.startNote(UInt8(i), withVelocity: 127, onChannel: 1)
let pause = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 1 * Int64(NSEC_PER_SEC))
dispatch_after(pause, dispatch_get_main_queue()) {
self.sampler.stopNote(UInt8(i), onChannel: 1)
}
sampler.stopNote(UInt8(i), onChannel: 1)
}
所以我意识到了这一点。我将乐器改为风琴(而不是钢琴),它确实会在 1 秒或 10 秒后停止音符,或者我放在那里的任何东西,但它似乎同时在 for 循环中进行,所以所有音符同时发声而不是按顺序发声。
我无法解决这个 midi 方面的问题,但至于暂停或休眠,您应该使用 dispatch_after
。将以下代码放在 sleep(1) 和 stopNote 调用的位置。这将使您能够以纳秒级的精度执行延迟。只需将 dispatch_time_t() 调用的第二个参数更改为您需要的任何时间即可。
let pause = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 1 * Int64(NSEC_PER_SEC))
dispatch_after(pause, dispatch_get_main_queue()) {
sampler.stopNote(UInt8(i), onChannel: 1)
}
尝试使用定时器来控制音符数组的循环。
播放一次音符后,下次开始计时时停止音符。
var playCount = 0
timer = Timer.scheduledTimer(timeInterval: 0.6, target: self, selector: #selector(fireTimerContinue), userInfo: nil, repeats: true)
@objc func fireTimerContinue(){
var note: Int8 = 0
if(index < note_array.count){
note = Int8(note_array[index])
self.audioEngine.sampler.startNote(UInt8(note), withVelocity: UInt8(velocity), onChannel: 0)
playCount += 1
if playCount > 1 {
audioEngine.sampler.stopNote(UInt8(note), onChannel: 0)
playCount = 0
index = index + 1
}
}
}
一个接一个地弹奏音符的最佳方式是什么?这是我现在拥有的最实用的代码。
let majorScale = [60, 62, 64, 65, 67, 69, 71, 72]
for i in majorScale {
sampler.startNote(UInt8(i), withVelocity: 127, onChannel: 1)
sleep(1)
sampler.stopNote(UInt8(i), onChannel: 1)
}
这个方法的问题是 sleep() 只接受 UInt8 作为参数,所以我不能用这种方式做一个持续不到 1 秒的笔记。
我首先是一个音乐家。我只是碰巧在大学时对编程有所了解,当时我参加了一对 java 类。也就是说,我真的不知道还有什么其他选择。
有没有我可以用来处理音符时长的内置 MIDI 播放器?
有没有办法"sleep"不到一秒,然后自己计算时长?因为在 100 bpm 下演奏的 1/8 音符将持续 ((60/100)/2) = 0.3 秒。
我应该取而代之的是获取音符信息并制作一个我可以播放的 MIDI 文件吗?
如何最好地解决这个问题?
编辑
这是更新后的代码:
for i in majorScale {
sampler.startNote(UInt8(i), withVelocity: 127, onChannel: 1)
let pause = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 1 * Int64(NSEC_PER_SEC))
dispatch_after(pause, dispatch_get_main_queue()) {
self.sampler.stopNote(UInt8(i), onChannel: 1)
}
sampler.stopNote(UInt8(i), onChannel: 1)
}
所以我意识到了这一点。我将乐器改为风琴(而不是钢琴),它确实会在 1 秒或 10 秒后停止音符,或者我放在那里的任何东西,但它似乎同时在 for 循环中进行,所以所有音符同时发声而不是按顺序发声。
我无法解决这个 midi 方面的问题,但至于暂停或休眠,您应该使用 dispatch_after
。将以下代码放在 sleep(1) 和 stopNote 调用的位置。这将使您能够以纳秒级的精度执行延迟。只需将 dispatch_time_t() 调用的第二个参数更改为您需要的任何时间即可。
let pause = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 1 * Int64(NSEC_PER_SEC))
dispatch_after(pause, dispatch_get_main_queue()) {
sampler.stopNote(UInt8(i), onChannel: 1)
}
尝试使用定时器来控制音符数组的循环。 播放一次音符后,下次开始计时时停止音符。
var playCount = 0
timer = Timer.scheduledTimer(timeInterval: 0.6, target: self, selector: #selector(fireTimerContinue), userInfo: nil, repeats: true)
@objc func fireTimerContinue(){
var note: Int8 = 0
if(index < note_array.count){
note = Int8(note_array[index])
self.audioEngine.sampler.startNote(UInt8(note), withVelocity: UInt8(velocity), onChannel: 0)
playCount += 1
if playCount > 1 {
audioEngine.sampler.stopNote(UInt8(note), onChannel: 0)
playCount = 0
index = index + 1
}
}
}