Playing Audio with QtMultimedia? - python

Part of a PyQt5 program I'm writing is to take in an audio stream and play it back. I've searched around and this is the code I have found that is said to work:
url = QtCore.QUrl.fromLocalFile('office theme.mp3')
content = QtMultimedia.QMediaContent(url)
player = QtMultimedia.QMediaPlayer()
player.setMedia(content)
player.play()
However, this does not work for me. I have tried putting the code in a variety of places (after the window.show() call, inside and outside of various classes I have, etc). I can verify that the MP3 is valid as I can play it in Clementine, VLC, and Dolphin. It was also taken directly from my Plex server, so it's definitely a valid MP3 file. I have tried converting this file to OGG and to WAV with no luck. I have also tried FLAC and AAC audio files and they do not work either.
I saw on a forum that someone suggested running a command to check if PyQt could see any audio devices. I ran the following code and it returned multiple audio output devices:
print(QtMultimedia.QAudioDeviceInfo.availableDevices(QtMultimedia.QAudio.AudioOutput))
All I need to do is take in a reference to an audio file (eventually opened from a file dialogue, but I'll cross that bridge when I come to it) and play it. Am I doing it incorrectly? I am by no means an expert on PyQt and have been experimenting for a couple of days only.
I'm currently running on Antergos Arch Linux.

You have to pass the complete path, but if you want to just pass the name of the file and that the program adds the rest you can use QDir::current():
import sys
from PyQt5 import QtCore, QtWidgets, QtMultimedia
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
filename = 'office theme.mp3'
fullpath = QtCore.QDir.current().absoluteFilePath(filename)
url = QtCore.QUrl.fromLocalFile(fullpath)
content = QtMultimedia.QMediaContent(url)
player = QtMultimedia.QMediaPlayer()
player.setMedia(content)
player.play()
sys.exit(app.exec_())

Related

Play QSound from a resource file?

I'm trying to load a QSound file from a qrc file but I can't find a way to do it. Is it possible?
Something like:
sound = QSound(":/audio/my_sound.ogg")
sound.play()
Unlike pixmaps, this syntax doesn't work for audio.
I'll be using pyinstaller to package the scripts and it would be useful if there was a way to include the sound files in the exe as well.
First make sure you can play an ogg file...on my system I get a console error with the ogg file...so also with the ogg resource
QSound.play("my_sound.ogg") # Error decoding source file:my_sound.ogg
QSound.play(":/audio/my_sound.ogg") # Error decoding source file::/audio/my_sound.ogg
Using a wav file works for me, so it verifies QSound can indeed play from a resource.
import sys
from PyQt5.QtCore import QCoreApplication, QFile
from PyQt5.QtMultimedia import QSound
import resources # compiled via: pyrcc5 -o resources.py resources.qrc
if __name__ == '__main__':
app = QCoreApplication(sys.argv)
# QSound.play("test.wav") # Plays fine
# Using a wav file in the resource as follows gives the following results
# <!DOCTYPE RCC>
# <RCC version="1.0">
# <qresource prefix="audio">
# <file>test.wav</file>
# </qresource>
# </RCC>
QSound.play(":/audio/test.wav") # Plays fine
sound = QSound(":/audio/test.wav")
sound.play() # Plays fine
QSound(":/audio/test.wav").play() # no sound...no error
# QFile.copy(":/audio/my_sound.ogg", "temp.ogg") # Could also copy to a local file to make sure was found in resource
sys.exit(app.exec_())
I haven't heard of qsound but i know many sound player modules such as pygame,playsound etc you can see the syntax in there sites they support play, stop, pause and much more

Hide ffmpeg's console window when running YoutubeDL in GUI application

I'm developing a basic application which can download YouTube videos. Throughout the development, I had several quirks, including issues with formats.
I decided to use a hopefully foolproof format syntax that youtube-dl will happily download for me in almost any case.
Part of my YoutubeDL options look like this:
self.ydl_opts = {
'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
'quiet': True,
'progress_hooks': [self.ydl_progress],
'outtmpl': None
}
The outtmpl is inserted later on when output folder is chosen by the user.
Since I'm using this format string, youtube-dl uses ffmpeg to merge(?) the audio and video if they are downloaded separately.
When it does that, it opens very annoying console windows that capture the focus and interrupt other things I might be doing while the videos are downloading.
My question is, how can I prevent ffmpeg or youtube-dl from creating those console windows from appearing, aka. how can I hide them?
EDIT:
I'll provide bare bones script that reproduces the problem:
from __future__ import unicode_literals
from PyQt4 import QtGui, QtCore
import youtube_dl, sys
def on_progress(info):
print info.get("_percent_str", "Finished")
ydl_opts = {
'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
'progress_hooks': [on_progress],
'quiet': True,
'outtmpl': "C:/Users/Raketa/Desktop/%(title)s.%(ext)s"
}
ydl = youtube_dl.YoutubeDL(ydl_opts)
class DownloadThread(QtCore.QThread):
def __init__(self):
super(DownloadThread, self).__init__()
self.start()
def __del__(self):
self.wait()
def run(self):
print "Download start"
ydl.download(["https://www.youtube.com/watch?v=uy7BiiOI_No"])
print "Download end"
class Application(QtGui.QMainWindow):
def __init__(self):
super(Application, self).__init__()
self.dl_thread = DownloadThread()
def run(self):
self.show()
def main():
master = QtGui.QApplication(sys.argv)
app = Application()
app.run()
sys.exit(master.exec_())
if __name__ == '__main__':
main()
2(?) consoles appear at start of each download and 1 longer lasting console appears when both video and audio are downloaded. When downloading longer videos, the last console becomes unbearable.
Is it possible to get rid of those?
The problem is not really related to the code. In fact, it's more a "windows problem". If I run the code on my computer (which is a linux one), there's no problem. There's only one console (that one I used to launch the script).
I think that if you rename the file with .pyw, it will work. According to that link: How to hide console window in python?
On Windows systems, there is no notion of an “executable mode”. The Python installer automatically associates .py files with python.exe so that a double-click on a Python file will run it as a script. The extension can also be .pyw, in that case, the console window that normally appears is suppressed.
That would solve your problem
(If not, maybe you could run the code in a console (and not double-clicking on the file browser) to see where the problem comes from and give me some feedback :))

Python- Error in playing mp3 audio using vlc-command line

Objective
I wanted to use the os module to play an audio file using VLC player at a faster rate.
os.system("vlc 'C:\Users\user\Desktop\file1.mp3' --rate=1.5")
What should have happened
A VLC player window should have popped open and the music should have started playing at a speed 1.5 times that of the default speed.
What happened instead
File reading failed:
VLC could not open the file "C:\Program Files\VideoLAN\VLC\'C:\Users\user\Desktop\file1.mp3'". (%m)
Your input can't be opened:
VLC is unable to open the MRL 'file:///C:/Program%20Files/VideoLAN/VLC/%27C%3A/Users/user/Desktop/file1.mp3%27'. Check the log for details.
Code
import os
os.chdir("C:\Program Files\VideoLAN\VLC")
os.system("vlc 'C:\Users\user\Desktop\file1.mp3' --rate=1.5")
Where did I go wrong?
How can I resolve the error?
This might be because of the extra quoting required in Windows paths
If you are using Python >=3.5 you can use subprocess.run instead of os.system which could help with the quoting issues as well.
import subprocess
subprocess.run(['vlc', r'C:\Users\user\Desktop\file1.mp3',
'--play-and-exit', '--rate=1.5'])
If you are using python 2.7 you may also use the following.
import subprocess
subprocess.Popen(r'vlc --rate 5 C:\Users\user\Desktop\file1.mp3',shell = True)
AFAIK, the rate switch should be given immediately after vlc. This worked for me
Please let me know if it solved your purpose.

Python/gtk gtk.gdk.pixbuf_new_from_file() always fails

Hi I'm trying to use a python gtk script under python 2.7.3; on Linux (under X11) and it needs to load images into pixbufs from disk.
However, python returns a glib.GError: "Couldn't recognize the image file format" regardless of what type of file I try to open;
eg: with: pixbuf = gtk.gdk.pixbuf_new_from_file( filename )
I can do a gtk.gdk.pixbuf_get_formats(), and in the list of dictionaries which is returned, the formats I have tried to load are listed .png, .ppm, .jpg.
When I try a gtk.gdk.pixbuf_get_file_info( filename ), though, it returns None.
Other GTK based programs such as Gimp, load these same images just fine; and gtk scripts that don't load icons from disk, but which draw buttons -- etc. work just fine.
How would I search for the cause of this malfunction?
Am I missing some kind of a mime-type file ?
Is there an alternate path using other gtk function calls that might accomplish the loading another way?
This works for me:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import gtk
def win_with_image():
pixbuf = gtk.gdk.pixbuf_new_from_file("photo.png")
print pixbuf
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
image = gtk.Image()
image.set_from_pixbuf(pixbuf)
win.add(image)
win.connect("destroy", gtk.main_quit)
win.show_all()
if __name__ == '__main__':
win_with_image()
gtk.main()
If this doesn`t work for you, try to:
start google and type your error and choose the second link (http://aptosid.com/index.php?name=PNphpBB2&file=viewtopic&t=2246), in general this helps almost always.
reinstall libglib
install gtk (maybe some graphical libs - libpng, libjpeg, f.e.)
reinstall python/gtk package
fix broken package repository
change files permissions

How to watch directory for file modifications

I'm on a mac. I've been using Launchd's WatchPaths directive to watch a directory for file changes. My script only triggers when a file is added or deleted from the watched directory.
However, the script does not trigger when a file is modified..
Essentially, I'm trying to create a DIY Dropbox for syncing my Sites folder.
Is there a way to do this via launchd, bash or python?
I think linux has something like inotify, but I am not aware of a solution for mac.
I tried my hand at the problem, using the MacFSEvents
package (available on PyPI, too):
import os
from fsevents import Observer, Stream
def callback(file_event):
print file_event.name # the path of the modified file
def main():
observer = Observer()
observe_path = os.getcwd() # just for this example
stream = Stream(callback, observe_path, file_events=True)
observer.start()
observer.schedule(stream)
if __name__ == '__main__':
main()
This will call callback any time a file is created, modified, or deleted (you can check which event occurred using the value of file_event.mask).
Note that you will probably want to observe on a thread outside of the main thread (the above program refuses to quit, even on KeyboardInterrupt). More information on the API can be found in the MacFSEvents README. Hope this helps!

Categories