【问题标题】:Play a sequence of MIDI notes in swift快速播放一系列 MIDI 音符
【发布时间】:2016-08-11 01:27:42
【问题描述】:

一个接一个地演奏一个音符的最佳方式是什么?这是我现在拥有的最实用的代码。

    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 播放器可以用来处理音符时长?

  • 有没有办法“睡”不到一秒,然后自己计算持续时间?就像以 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 循环中进行,所以所有的音符同时发声,而不是按顺序发声。

【问题讨论】:

    标签: ios swift midi


    【解决方案1】:

    我无法在 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)
    }
    

    【讨论】:

    • 仅仅因为 API 接受纳秒单位并不意味着实际的实现可以接近这个。请参阅 dispatch_after 的文档。这是最大的努力,可能比要求的要长得多。为了准确地播放音乐,通过专门的 APi 肯定有更好的方法
    • 好的,所以我有点明白这里发生了什么......但它并不完全有效。如果我复制上面的代码,它会运行,但会在一瞬间播放整个音阶。它似乎根本没有等待。我用 1000 代替了 1,得到了相同的结果。
    • 对于 BaseZen,我相信您是对的……可能有一个 API 可以处理它,但到此为止简直就是一场噩梦。我几乎更喜欢使用某种睡眠方法。而不是找出另一组复杂的 API。 Apple 关于声音处理的文档参差不齐,在线示例代码的方式也不多。
    • 发布你的整个方法,因为它现在就在调度延迟。
    • 对于初学者,请删除 dispatch_after 函数后的 stopNote 行。你只需要 1 个。
    【解决方案2】:

    尝试使用定时器来控制循环通过 notes 数组。 音符播放一次后,下次计时器开始时停止音符。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-11
      相关资源
      最近更新 更多