簡體   English   中英

在PyQt中播放聲音文件

[英]play sound file in PyQt

我在PyQt中開發了一個播放聲音的軟件。我正在使用Phonon Library播放聲音,但它有一些滯后。所以如何在不使用Phonon Library的情況下在PyQt中播放聲音文件。

這就是我目前使用Phonon的方式:

def Playnote(self,note_id):
    global note    
    note = note_id
    self.PlayThread = PlayThread()
    self.PlayThread.start()




class PlayThread(QtCore.QThread):
  def __init__(self):
  QtCore.QThread.__init__(self)

  def __del__(self):
    self.wait()     
  def run(self):
    global note
    self.m_media = Phonon.MediaObject(self)
    audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
    Phonon.createPath(self.m_media, audioOutput)
    self.m_media.setCurrentSource(Phonon.MediaSource(Phonon.MediaSource(note)))
    self.m_media.play()

現在滯后減少了。 但問題是我在短時間內按下兩個或更多鍵,這是新音符開銷並停止前一個音符。 我需要播放前一個音符直到它結束。

class PlayThread(QtCore.QThread):
   def __init__(self):
    QtCore.QThread.__init__(self)
    self.m_media = Phonon.MediaObject(self)
    self.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
    Phonon.createPath(self.m_media, self.audioOutput)    
   def __del__(self):
      self.wait()       
   def play(self, note):
      self.m_media.setCurrentSource(Phonon.MediaSource(Phonon.MediaSource(note)))
      self.m_media.play()
   def run(self):pass

我已經重寫了這個答案,因為我認為你的問題已經開始出現分歧

首先,解決您的代碼示例

在您的第一個PlayThread示例中,您每次要播放一個鍵時都會啟動一個新線程,然后必須完全設置一個媒體播放器,然后打開源文件,然后播放。 這肯定會導致你的開銷。

在第二個示例中,您傳遞的是run()方法,該方法基本上使線程在啟動后立即結束。 然后你直接在那個QThread上調用play()。 基本上你正在做的是使用QThread像一個基本的QObject類,並在同一主線程中調用play。 我也不明白你為什么要從MediaSource創建一個MediaSource(冗余?)。 但是每次你打電話都會取代聲音,這就是你重新開始播放的原因。

我不認為你真的需要QThreads。

QSound的

在更高級別,您可以使用QSound。 為了減少你可能引發的延遲,你不應該使用play()的靜態方法來動態啟動文件。 相反,您應該在應用程序啟動時預先創建這些QSound對象:

notes = {
    'c': QtGui.QSound("c.wav"),
    'd': QtGui.QSound("d.wav"),
    'e': QtGui.QSound("e.wav"),
}

notes['c'].play()

調用play()不會阻塞,你不需要單獨運行QThread來運行它們。 您也可以在同一個QSound對象上多次調用play,但它的缺點是無法停止所有多個流。 他們將不得不發揮出來。 如果此方法產生的性能可接受性比您所做的要好。 您只需將鋼琴按鈕中的clicked信號連接到正確鍵的play槽即可。

聲子

如果QSound最終會產生太多延遲,那么下一步就是嘗試Phonon。 同樣,為了減少磁盤IO和對象創建的開銷,您需要預先創建這些媒體對象。 您不能使用單個媒體對象同時播放多個流。 因此,您必須選擇是否要嘗試為每個聲音創建一個媒體對象,或者使用一種媒體對象池。 要做一個小的媒體對象池,它需要你抓一個免費的,將其源設置為適當的媒體源對象,然后播放。 一旦完成,它將不得不返回池中。

使用Phonon的級別低於QSound,因此單個媒體對象在調用播放時不能多次播放相同的聲音。 它將忽略后續卡列斯play在播放狀態,如果它已經。 無論如何,基本方法可能是創建一個Key類來幫助組織一個玩家的實體:

class Key(QtCore.QObject):

    def __init__(self, soundFile, parent=None):
        super(Key, self).__init__(parent)

        self.soundFile = soundFile

        self.mediaObject = Phonon.MediaObject(self)
        self._audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
        self._path = Phonon.createPath(self.mediaObject, self._audioOutput)
        self.mediaSource = Phonon.MediaSource(soundFile)
        self.mediaObject.setCurrentSource(self.mediaSource)   

    def play(self):
        self.mediaObject.stop()
        self.mediaObject.seek(0)
        self.mediaObject.play()

這將再次讓你幾乎回到QSound的狀態,除了不同之處在於不止一次調用play()會重新調整聲音,而不是將它們放在彼此之上:

notes = {
    'c': Key("c.wav"),
    'd': Key("d.wav"),
    'e': Key("e.wav"),
}

notes['c'].play()

具有來自相同源的並發流的聲子

我提到了一個媒體對象池,你可以使用它來播放多個並發聲音。 雖然我不會進入該領域,但我可以提出一種簡單的方法來讓你的密鑰同時播放,因為你必須一次打開更多資源,但現在更容易運行,因此效率可能會低一些。

簡單的方法是每個鍵使用一個小的預定媒體對象池,並在每次調用play時通過播放它們進行旋轉

from collections import deque

class Key(QtCore.QObject):

    POOL_COUNT = 3

    def __init__(self, soundFile, parent=None):
        super(Key, self).__init__(parent)
        self.soundFile = soundFile

        self.resourcePool = deque()

        mediaSource = Phonon.MediaSource(soundFile)

        for i in xrange(self.POOL_COUNT):
            mediaObject = Phonon.MediaObject(self)
            audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
            Phonon.createPath(mediaObject, audioOutput)
            mediaObject.setCurrentSource(mediaSource)
            self.resourcePool.append(mediaObject)

    def play(self):
        self.resourcePool.rotate(1)
        m = self.resourcePool[0]
        m.stop()
        m.seek(0)
        m.play()

我們在這里做的是創建了一個deque ,它具有非常方便的能力來旋轉列表n-amount。 所以在init中,我們從同一個源創建3個媒體對象並將它們放在我們的雙端隊列中。 然后,每次調用play時,我們將deque旋轉一次並取出第一個索引並播放它。 這將為您提供3個並發流。

此時,如果延遲仍然存在問題,那么您可能需要調查在應用程序啟動時將所有音頻加載到QBuffer中,然后將它們從內存中用於聲音。 我不太了解聲子源,知道當你從文件創建源時它是否已經將整個文件加載到內存中,或者它總是出現在磁盤上。 但如果它總是出現在磁盤上,減少這個IO將是再次減少延遲的方法。

希望這完全回答你的問題!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM