1

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

3 回答 3

2

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

于 2017-04-25T21:21:26.187 回答
2

你很接近你的循环。你只需要给 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)
}
于 2017-04-26T15:54:47.717 回答
0

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

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

原始stillGoing值有效,但也有一种isPlaying方法。

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

非常感谢。

于 2017-04-26T17:03:33.880 回答