2012-03-25 3 views
3

Я разработал программное обеспечение в PyQt, которое воспроизводит звук. Я пользуюсь фононной библиотекой для воспроизведения звука, но у меня есть некоторое отставание. Так как я могу воспроизводить звуковой файл в PyQt без использования библиотеки Phonon ,воспроизведение звукового файла в 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 

ответ

9

Я переписал этот ответ, так как я думаю, что ваш вопрос начал расходиться

Во-первых, адресации примеры кода

В первом примере PlayThread, вы начинаете новый нить каждый раз, когда вы хотите сыграть ключ, который затем должен полностью настроить медиаплеер и открыть исходный файл, а затем воспроизвести. Это определенно вызывает вас накладные расходы.

В вашем втором примере вы проходите по методу run(), который в основном делает конец потока сразу после его запуска. И тогда вы прямо вызываете play() на этом QThread. По сути дела, вы используете QThread, как базовый класс QObject, и вызываете игру внутри одного и того же основного потока. Я также не понимаю, почему вы создаете 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, но он имеет недостаток в том, что он не может остановить все множественные потоки. Им придется разыграть. Если этот метод приводит к приемлемой производительности, чем вы сделали. Вы просто просто подключите сигнал clicked с кнопки фортепьяно к слоту play соответствующего ключа.

Phonon

Если QSound ли в конечном итоге производит слишком много лаг, то ваш следующий шаг должен был бы попробовать Phonon. Опять же, чтобы уменьшить накладные расходы на создание IO диска и создание объекта, вам необходимо предварительно создать эти медиа-объекты. Вы не можете использовать один медиа-объект для одновременного воспроизведения нескольких потоков. Поэтому вам нужно выбрать, хотите ли вы попытаться создать один медиа-объект для каждого звука или использовать пул медиа-объектов. Чтобы сделать небольшой пул медиа-объектов, для этого потребуется, чтобы вы захватили бесплатный, установили его источник в соответствующий объект источника мультимедиа, а затем сыграли. Как только он будет завершен, его нужно будет вернуть в пул.

Использование Phonon ниже уровня QSound, поэтому один медиа-объект не может воспроизводить один и тот же звук несколько раз при вызове воспроизведения. Он будет игнорировать последующие вызовы до play, если он уже находится в состоянии воспроизведения. Независимо от того, основной подход может создать ключевой класс, чтобы помочь организовать юридическое лицо игрока,:

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() 

Phonon с параллельными потоками из одного источника

Я упомянул о наличии пула медиа-объектов, которые вы использовали бы для воспроизведения нескольких одновременных звуков. Хотя я не буду входить в эту область, я могу предложить простой способ одновременного доступа к вашим клавишам, которые могут быть немного менее эффективными, так как вам нужно открыть больше ресурсов сразу, но теперь проще работать.

Простой подход заключается в использовании небольшого предопределенного пула объектов медиа на ключ, и чередовать играть их каждый раз, когда вы звоните 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-значению. Итак, в init мы создаем 3 объекта мультимедиа из одного источника и помещаем их в наш deque. Затем, каждый раз, когда вы вызываете игру, мы поворачиваем deque на один и берём первый индекс и воспроизводим его. Это даст вам 3 одновременных потока.

На этом этапе, если отставание по-прежнему является проблемой, вам, возможно, придется исследовать загрузку всего вашего звука в QBuffer в начале вашего приложения, а затем использовать их из памяти в фонон. Я не знаю достаточно о источнике фононов, чтобы узнать, загружает ли он весь файл в память уже при создании источника из файла или если он всегда выходит на диск. Но если он всегда выйдет на диск, сокращение этого ввода-вывода станет способом снова уменьшить отставание.

Надеюсь, что это полностью отвечает на ваш вопрос!

+0

Да, что я проверял –

+0

И что вы нашли? – jdi

+0

Я использовал QtGui.Qsound, но все же у него есть некоторое отставание. И я реализовал нить, для воспроизведения звука, но отставание все еще там. Это виртуальное пианино, поэтому во время игры есть лаг. Возможно, у вас есть способ уменьшить отставание в игре. –

Смежные вопросы