首页 > 解决方案 > SingletonMusicPlayer 自己播放

问题描述

我想要一个 midi 管理器,这意味着它可以从任何地方调用......一个单例实例......并处理来自不同线程的音乐请求。

这是在操场上

import PlaygroundSupport
import AudioToolbox
class MusicPlayerManager {
    static let sharedInstance = MusicPlayerManager()
    private init() {}

    var musicPlayer : MusicPlayer? = nil
    var sequence : MusicSequence? = nil
    var track : MusicTrack? = nil
    var time = MusicTimeStamp(1.0)
    var player: OSStatus? = nil
    var musicTrack: OSStatus? = nil

    func playNotes(notes: [UInt8]) {
        _ = NewMusicSequence(&sequence)
        player = NewMusicPlayer(&musicPlayer)
        player = MusicPlayerSetSequence(musicPlayer!, sequence)
        player = MusicPlayerStart(musicPlayer!)
        musicTrack = MusicSequenceNewTrack(sequence!, &track)
        for index:Int in 0...6 {
            var note = MIDINoteMessage(channel: 0,
                                       note: notes[index],
                                       velocity: 64,
                                       releaseVelocity: 0,
                                       duration: 1.0)
            guard let track = track else {fatalError()}
            musicTrack = MusicTrackNewMIDINoteEvent(track, time, &note)
            time += 1
        }

        player = MusicPlayerSetSequence(musicPlayer!, sequence)
        player = MusicPlayerStart(musicPlayer!)

    }

}

var notes: [UInt8] = [71,69,62,72,71,69,67]

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    MusicPlayerManager.sharedInstance.playNotes(notes: notes)
}


DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
    MusicPlayerManager.sharedInstance.playNotes(notes: notes)
}



PlaygroundPage.current.needsIndefiniteExecution = true

不幸的是,音乐通常根本不播放,或者在每个实例中都自动播放。

在最坏的情况下,它应该播放音乐的第一个实例;为什么它不能很好地做到这一点?

标签: swift

解决方案


我认为您通过尝试同时从不同线程操作单例上的实例变量在这里遇到了一种形式的读写器问题。如果一次从多个线程调用它,我不知道你想要的音乐播放器行为是什么,但对我来说,一个简单的改进是给你的MusicPlayerManager单例它自己的DispatchQueue,其中多个重叠请求可以按顺序处理。

你可以这样定义:

let concurrentQueue = DispatchQueue(label: "com.stackoverflow.gamma", attributes: .concurrent)

然后将代码包装在playNotes函数中,如下所示:

func playNotes(notes: [UInt8]) {
   self.concurrentQueue.async(flags: .barrier) {
     ...
   }
}

推荐阅读