以下是一个AVAudioEngine MIDI文件播放器的示例代码,包括当前进度和MIDI结束回调的实现:
import AVFoundation
class MidiPlayer {
var engine: AVAudioEngine!
var player: AVAudioPlayerNode!
var sequencer: AVAudioSequencer!
var currentPosition: TimeInterval = 0
var duration: TimeInterval = 0
var completionHandler: (() -> Void)?
init() {
engine = AVAudioEngine()
player = AVAudioPlayerNode()
engine.attach(player)
engine.connect(player, to: engine.mainMixerNode, format: nil)
}
func loadMidiFile(url: URL) {
do {
sequencer = try AVAudioSequencer(url: url)
sequencer.prepareToPlay()
duration = sequencer.duration.seconds
} catch {
print("Failed to load MIDI file: \(error.localizedDescription)")
}
}
func play() {
do {
try engine.start()
player.play()
sequencer.currentPosition = currentPosition
sequencer.addPlayer(player)
} catch {
print("Failed to start audio engine: \(error.localizedDescription)")
}
}
func pause() {
player.pause()
currentPosition = sequencer.currentPosition.seconds
engine.stop()
}
func stop() {
player.stop()
currentPosition = 0
engine.stop()
}
func addCompletionHandler(completion: @escaping () -> Void) {
completionHandler = completion
NotificationCenter.default.addObserver(self, selector: #selector(handleMidiCompletion), name: .AVAudioEngineConfigurationChange, object: nil)
}
@objc func handleMidiCompletion(notification: NSNotification) {
if sequencer.isPlaying {
return
}
completionHandler?()
completionHandler = nil
NotificationCenter.default.removeObserver(self, name: .AVAudioEngineConfigurationChange, object: nil)
}
}
使用示例:
let midiPlayer = MidiPlayer()
let midiFileURL = Bundle.main.url(forResource: "example", withExtension: "mid")!
midiPlayer.loadMidiFile(url: midiFileURL)
midiPlayer.addCompletionHandler {
print("MIDI playback completed")
}
midiPlayer.play()
这个示例代码创建了一个MidiPlayer
类,封装了AVAudioEngine和AVAudioPlayerNode的功能。它提供了加载MIDI文件、播放、暂停和停止的方法,并且可以在MIDI播放完成时添加一个回调处理程序。要使用它,首先创建一个MidiPlayer
对象,然后调用loadMidiFile
方法加载MIDI文件,使用addCompletionHandler
方法添加一个回调处理程序,最后调用play
方法开始播放MIDI文件。
请将"example.mid"替换为您自己的MIDI文件的名称,并确保将其添加到项目的资源中。