【问题标题】:How to keep AVMIDIPlayer playing?如何保持 AVMIDIPlayer 播放?
【发布时间】:2017-04-25 15:15:41
【问题描述】:

我正在尝试使用 Apple 的 AVMIDIPlayer 对象来播放 MIDI 文件。使用以下代码在 Swift 中似乎很容易:

let midiFile:NSURL = NSURL(fileURLWithPath:"/path/to/midifile.mid")
var midiPlayer: AVMIDIPlayer?

do {
    try midiPlayer = AVMIDIPlayer(contentsOf: midiFile as URL, soundBankURL: nil)
    midiPlayer?.prepareToPlay()
} catch {
    print("could not create MIDI player")
}

midiPlayer?.play {
    print("finished playing")
}

它会播放大约 0.05 秒。我想我需要在某种循环中构建它。我尝试了一个简单的解决方案:

while stillGoing {
midiPlayer?.play {
    let stillGoing = false
}
}

这可行,但会大量增加 CPU。有没有更好的办法? 除了第一条评论,我尝试创建一个类,虽然它没有标记任何错误,但它也不起作用。

class midiPlayer {

var player: AVMIDIPlayer?

    func play(file: String) {
        let myURL = URL(string: file)
do {
    try self.player = AVMIDIPlayer.init(contentsOf: myURL!, soundBankURL: nil)
    self.player?.prepareToPlay()
} catch {
    print("could not create MIDI player")
}
    self.player?.play()
    }
func stop() {
self.player?.stop()
}
}

// main

let myPlayer = midiPlayer()
let midiFile = "/path/to/midifile.mid"
myPlayer.play(file: midiFile)

【问题讨论】:

    标签: swift macos midi coremidi avkit


    【解决方案1】:

    你的循环很接近。你只需要给 CPU 时间去做其他事情,而不是不断检查midiPlayer 是否已经完成。在循环中添加对 usleep() 的调用。这个检查每十分之一秒:

    let midiFile:NSURL = NSURL(fileURLWithPath:"/Users/steve/Desktop/Untitled.mid")
    var midiPlayer: AVMIDIPlayer?
    
    do {
        try midiPlayer = AVMIDIPlayer(contentsOfURL: midiFile, soundBankURL: nil)
        midiPlayer?.prepareToPlay()
    } catch {
        print("could not create MIDI player")
    }
    
    var stillGoing = true
    while stillGoing {
        midiPlayer?.play {
            print("finished playing")
            stillGoing = false
        }
        usleep(100000)
    }
    

    【讨论】:

      【解决方案2】:

      您需要确保midiPlayer 对象在播放完毕之前一直存在。如果上面的代码只是在一个函数中,midiPlayer 将在函数返回时被销毁,因为没有对它的剩余引用。通常,您会将midiPlayer 声明为对象的属性,例如子类控制器。

      【讨论】:

      • 所以我必须用这个代码作为函数/方法创建一个类,然后创建该类的一个实例,并调用该方法?到目前为止,这只是一个 CLI 脚本,所以没有 UI 控制器。
      • 啊,好吧,在这种情况下,使用循环是唯一的方法。在 while 循环中放置一个 'sleep(1)' 调用,这样它就不会占用你所有的 CPU 时间。另外,我很确定您需要将 'midiPlayer?.play' 调用移出 while 循环。
      【解决方案3】:

      结合 Brendan 和 Steve 的答案,关键是 sleepusleep 并将 play 方法固定在循环之外以避免加速 CPU。

      player?.play({return})
      while player!.isPlaying { 
      sleep(1) // or usleep(10000)
      }
      

      原来的stillGoing 值有效,但还有一个isPlaying 方法。

      .play 需要在其括号之间添加一些内容,以避免在完成后永远挂起。

      非常感谢。

      【讨论】:

        猜你喜欢
        • 2015-09-27
        • 2014-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多