在 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 类。也就是说,我真的不知道还有什么其他选择。

如何最好地解决这个问题?

编辑

这是更新后的代码:

    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

        }

      }
  }