如何让AVMIDIPlayer保持播放?

时间:2017-04-25 15:15:42

标签: swift macos midi coremidi avkit

我尝试使用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)

3 个答案:

答案 0 :(得分:2)

您需要确保/** * Font 1 */ @font-face { font-family: "Flaticon1"; src: url("flaticon1.eot"); src: url("flaticon1.eot#iefix") format("embedded-opentype"), url("flaticon1.woff") format("woff"), url("flaticon1.ttf") format("truetype"), url("flaticon1.svg") format("svg"); font-weight: normal; font-style: normal; } [class^="flaticon1-"]:before, [class*=" flaticon1-"]:before, [class^="flaticon1-"]:after, [class*=" flaticon1-"]:after { font-family: "Flaticon1"; font-size: 20px; font-style: normal; margin-left: 20px; } .flaticon1-basic21:before { content: "\e000"; } .flaticon1-bicycle21:before { content: "\e001"; } .flaticon1-car6:before { content: "\e002"; } /** * Font 2 */ @font-face { font-family: "Flaticon2"; src: url("flaticon2.eot"); src: url("flaticon2.eot#iefix") format("embedded-opentype"), url("flaticon2.woff") format("woff"), url("flaticon2.ttf") format("truetype"), url("flaticon2.svg") format("svg"); font-weight: normal; font-style: normal; } [class^="flaticon2-"]:before, [class*=" flaticon2-"]:before, [class^="flaticon2-"]:after, [class*=" flaticon2-"]:after { font-family: "Flaticon2"; font-size: 20px; font-style: normal; margin-left: 20px; } .flaticon2-basic21:before { content: "\e000"; } .flaticon2-bicycle21:before { content: "\e001"; } .flaticon2-car6:before { content: "\e002"; } 对象存在,直到完成播放为止。如果上面的代码只在一个函数中,那么当函数返回时,midiPlayer将被销毁,因为它没有剩余的引用。通常,您会将midiPlayer声明为对象的属性,如子类控制器。

答案 1 :(得分: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 :(得分:0)

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

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

原始stillGoing值有效,但还有isPlaying方法。

.play在括号之间需要一些东西,以避免在完成后永远挂起。

非常感谢。