Я переписал этот ответ, так как я думаю, что ваш вопрос начал расходиться
Во-первых, адресации примеры кода
В первом примере 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 в начале вашего приложения, а затем использовать их из памяти в фонон. Я не знаю достаточно о источнике фононов, чтобы узнать, загружает ли он весь файл в память уже при создании источника из файла или если он всегда выходит на диск. Но если он всегда выйдет на диск, сокращение этого ввода-вывода станет способом снова уменьшить отставание.
Надеюсь, что это полностью отвечает на ваш вопрос!
Да, что я проверял –
И что вы нашли? – jdi
Я использовал QtGui.Qsound, но все же у него есть некоторое отставание. И я реализовал нить, для воспроизведения звука, но отставание все еще там. Это виртуальное пианино, поэтому во время игры есть лаг. Возможно, у вас есть способ уменьшить отставание в игре. –