If in playAudioFile is performed, icon has changed but play() method dosen't work. Every time the condition is false.
This code works in some files, but I can't see a rule. Format files and file's long doesn't matter. I tried with .wav, .mp3 and .mp4 for a try.
In windows player every files work.
import sys
import os
from PyQt5.QtCore import QUrl
from PyQt5.uic import loadUi
from PyQt5.QtWidgets import QApplication, QStackedWidget, QMainWindow, QStyle
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
class Term2(QMainWindow):
def __init__(self):
super().__init__()
loadUi('screen2.ui', self)
# create player
self.player = QMediaPlayer()
self.choose_music()
self.btn_play.clicked.connect(self.playAudioFile)
# play audio
def choose_music(self):
filepath = os.path.join(os.getcwd(), 'pc.wav')
url = QUrl.fromLocalFile(filepath)
content = QMediaContent(url)
self.player.setMedia(content)
print(filepath)
def playAudioFile(self):
if self.player.state() == QMediaPlayer.PlayingState:
self.player.pause()
self.btn_play.setIcon(
self.style().standardIcon(QStyle.SP_MediaPlay)
)
else:
self.player.play()
self.btn_play.setIcon(
self.style().standardIcon(QStyle.SP_MediaPause)
)
app = QApplication(sys.argv)
widget = QStackedWidget()
t2 = Term2()
widget.setWindowTitle('Project)
widget.setFixedWidth(700)
widget.setFixedHeight(400)
widget.addWidget(t2)
widget.show()
sys.exit(app.exec_())
I created button in Qt Designer and import in loadUi('screen2.ui', self)
I would use an audio player from a different library, that one appears quite old. I would recommend looking into playsound or the pygame audio mixer.
Playsound works like this:
from playsound import playsound
playsound(path_to_audio_file)
It is quite limited in abilities, but is simple, reliable, and works with all mp3 and wav formats. Here is a tutorial: https://www.geeksforgeeks.org/play-sound-in-python/
If you want something a little more advanced I would try out pygames audio mixer, you can play stuff, control volumes, timings and more. At its most basic:
from pygame import mixer
mixer.init()
mixer.music.load(path_to_audio_file)
mixer.music.play()
The best format for the mixer is wav, but others would probably work.
A tutorial for this one:
https://www.geeksforgeeks.org/python-playing-audio-file-in-pygame/
Related
I've been having an issue migrating to PyQt6 with QAudioOutput and QMediaPlayer where the QMediaPlayer object seems to not work with any QAudioOutput I make. If I set a QAudioOutput object the video will fail to render and the event loop gets sluggish like buggy things are happening. Also the QMediaPlayer does not seem to be incrementing the QAudioOutput object's reference counter when QMediaPlayer.setAudioOutput is used, because unless I keep a reference to the object myself it gets cleared.
Here is some demo code:
import sys
from PyQt6.QtWidgets import QMainWindow, QApplication
from PyQt6.QtCore import QUrl
from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput
from PyQt6.QtMultimediaWidgets import QVideoWidget
class MainWin(QMainWindow):
def __init__(self, file_path):
super(MainWin, self).__init__()
self.cent_wid = QVideoWidget()
self.setCentralWidget(self.cent_wid)
self.player = QMediaPlayer()
self.audio_output = QAudioOutput()
#self.player.setAudioOutput(self.audio_output)
self.audio_output.setVolume(1.0)
self.player.setVideoOutput(self.cent_wid)
self.file_path = file_path
def showEvent(self, a0) -> None:
super(MainWin, self).showEvent(a0)
self.player.setSource(QUrl.fromLocalFile(self.file_path))
self.player.play()
if __name__ == '__main__':
app = QApplication([])
frm = MainWin(sys.argv[1])
frm.show()
app.exec()
For me, the above will run and play the video file (first argument for path), but the "player.setAudioOutput" is commented out. If it is uncommented then the player will fail. I've tried manually setting the QAudioDevice and PyQt (6.2.3, 6.2.2). Despite messing around for quite a while I can't get anything to work. Any ideas?
Although not a solution to this problem I have determined that the issue is with the vorbis audio codec on windows. Since Qt dropped DirectShow and only supports WMF this caused an issue on my computer. Unfortunately, I have not been able to get Qt to cooperate with any attempts to install codecs. Not 3rd party codecs or the "Web Media Extensions" from ms store. Below is some code that appears to prove that the vorbis codec is the issue (along with only files needing that codec breaking Qt):
from PyQt6.QtMultimedia import QMediaFormat
mf = QMediaFormat()
for codec in mf.supportedAudioCodecs(QMediaFormat.ConversionMode.Decode):
print(codec.name)
QSound from pyqt5 has been giving me trouble, some wav files work well. Others cause the Qt app to error and not run. I have with research narrowed the culprit down to the headers of the wav files.
If I open the wav file in Audacity and export it as a wav file... the exported wav file works perfectly. However I need a solution that runs from within my python script.
I am getting my wav files from Watson's Text-To-Speech api, not sure if I can control what headers it includes.
import sys
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow
from PyQt5.QtCore import Qt
from PyQt5.QtMultimedia import QSound
from ibm_watson import TextToSpeechV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator
def list_to_speech(text, language='ja-JP_EmiV3Voice'):
api_key = "my_api_key"
url = "url"
# Set up service
authenticator = IAMAuthenticator(api_key)
# Now TTS service
tts = TextToSpeechV1(authenticator=authenticator)
# Set Service URL
tts.set_service_url(url)
with open('text_to_speech.wav', 'wb') as audio_file:
res = tts.synthesize(text, accept='audio/wav', voice=language).get_result()
audio_file.write(res.content)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.sound = QSound("text_to_speech.wav")
self.sound.play()
label = QLabel("This PyQt5 window will (try to) play the wav file!")
label.setAlignment(Qt.AlignCenter)
self.setCentralWidget(label)
if __name__ == "__main__":
# the file saved by list_to_speech won't play as QSound(text_to_speech.wav).play()
# (instead it crashes the app before opening)
#
# if I open the text_to_speech.wav file in Audacity and export it with empty headers,
# then comment out next line, it works.
list_to_speech("ありがとう")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
A possible solution is not to use QSound but rather QMediaPlayer that allows handling other codecs:
import os
import sys
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
# ...
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
filename = os.path.join(CURRENT_DIR, "text_to_speech.wav")
self.player = QMediaPlayer()
url = QUrl.fromLocalFile(filename)
self.player.setMedia(QMediaContent(url))
self.player.play()
label = QLabel("This PyQt5 window will (try to) play the wav file!")
label.setAlignment(Qt.AlignCenter)
self.setCentralWidget(label)
# ...
Note: Another option is to use another format like mp3.
I'm making an app which copy files from one directory to another. I want it to produce sound when the process finishes. I can't figure out how to make QSoundEffect produce sounds when it's inside some function or class. The only time it works is when the code looks like the following:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
app = QApplication(sys.argv)
win = QMainWindow()
filepath = "C:\Windows\Media\Windows Error.wav"
sound = QSoundEffect()
sound.setSource(QUrl.fromLocalFile(filepath))
sound.play()
win.show()
sys.exit(app.exec_())
Why doesn't it work when code looks like that? How to make it work in a function or a class?
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
def play_sound():
filepath = "C:\Windows\Media\Windows Error.wav"
sound = QSoundEffect()
sound.setSource(QUrl.fromLocalFile(filepath))
sound.play()
app = QApplication(sys.argv)
win = QMainWindow()
play_sound()
win.show()
sys.exit(app.exec_())
The problem is that "sound" is a local variable of the play_sound function so it will be eliminated when that method finishes executing which is almost instantaneous.
The solution is to extend the life cycle:
Python style: use a global variable
sound = None
def play_sound():
filepath = "C:\Windows\Media\Windows Error.wav"
global sound
sound = QSoundEffect()
sound.setSource(QUrl.fromLocalFile(filepath))
sound.play()
Qt style: set a parent
def play_sound():
filepath = "C:\Windows\Media\Windows Error.wav"
sound = QSoundEffect(QCoreApplication.instance())
sound.setSource(QUrl.fromLocalFile(filepath))
sound.play()
When I am using other programs (e.g. opening a pdf or word), I will select some text contents (like a word or paragraph) by using the mouse. I want my python program to get this text content. How to do this using PyQt, or some other Python library?
This is an easy task, you haven't specified the pyqt version, so I'll post the solution for PyQt4, here you go:
from PyQt4.QtCore import QObject, pyqtSlot, SIGNAL, SLOT
from PyQt4.QtGui import QApplication, QMessageBox
import sys
class MyClipboard(QObject):
#pyqtSlot()
def changedSlot(self):
if(QApplication.clipboard().mimeData().hasText()):
QMessageBox.information(None, "Text has been copied somewhere!",
QApplication.clipboard().text())
def main():
app = QApplication(sys.argv)
listener = MyClipboard()
app.setQuitOnLastWindowClosed(False)
QObject.connect(QApplication.clipboard(), SIGNAL(
"dataChanged()"), listener, SLOT("changedSlot()"))
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I wrote a simple video player using Phonon in PyQt4. The videos are playing fine. But I am unable to seek the video to given position. This the code I've written:
#!/usr/bin/python
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.phonon import Phonon
import sys
class VideoPlayer(QWidget):
def __init__(self, address, parent = None):
self.address = address
QWidget.__init__(self)
self.player = Phonon.VideoPlayer(Phonon.VideoCategory, self)
self.player.load(Phonon.MediaSource(self.address))
window = QHBoxLayout(self)
window.addWidget(self.player)
self.setWindowTitle("Simple Video Player")
self.player.play()
self.player.seek(10240)
app = QApplication(sys.argv)
vp = VideoPlayer(sys.argv[1])
vp.show()
app.exec_()
All I am trying to do is to start and stop a video at given positions.
Thanks in advance.
It is not possible to seek to a position in a media source whilst it is still loading.
So connect a handler to the media object's stateChanged signal, and wait until it's state changes to PlayingState before attempting to seek.
self.player.mediaObject().stateChanged.connect(self.handleStateChanged)
...
def handleStateChanged(self, newstate, oldstate):
if newstate == Phonon.PlayingState:
self.player.seek(10240)
Some media isn't easily seekable by Phonon. The documentation says
Note that the backend is free to ignore the seek request if the media source isn't seekable; you can check this by asking the media object of the VideoPlayer.
player->mediaObject()->isSeekable();
My guess is that your video isn't seekable.
What media are you using? Things like streaming video (for example), generally aren't seekable.