Playing audio continuously in Python [duplicate] - python

How can I play audio (it would be like a 1 second sound) from a Python script?
It would be best if it was platform independent, but firstly it needs to work on a Mac.
I know I could just execute the afplay file.mp3 command from within Python, but is it possible to do it in raw Python? I would also be better if it didn't rely on external libraries.

Your best bet is probably to use pygame/SDL. It's an external library, but it has great support across platforms.
pygame.mixer.init()
pygame.mixer.music.load("file.mp3")
pygame.mixer.music.play()
You can find more specific documentation about the audio mixer support in the pygame.mixer.music documentation

Try playsound which is a Pure Python, cross platform, single function module with no dependencies for playing sounds.
Install via pip:
$ pip install playsound
Once you've installed, you can use it like this:
from playsound import playsound
playsound('/path/to/a/sound/file/you/want/to/play.mp3')

Take a look at Simpleaudio, which is a relatively recent and lightweight library for this purpose:
> pip install simpleaudio
Then:
import simpleaudio as sa
wave_obj = sa.WaveObject.from_wave_file("path/to/file.wav")
play_obj = wave_obj.play()
play_obj.wait_done()
Make sure to use uncompressed 16 bit PCM files.

You can find information about Python audio here: http://wiki.python.org/moin/Audio/
It doesn't look like it can play .mp3 files without external libraries. You could either convert your .mp3 file to a .wav or other format, or use a library like PyMedia.

In pydub we've recently opted to use ffplay (via subprocess) from the ffmpeg suite of tools, which internally uses SDL.
It works for our purposes – mainly just making it easier to test the results of pydub code in interactive mode – but it has it's downsides, like causing a new program to appear in the dock on mac.
I've linked the implementation above, but a simplified version follows:
import subprocess
def play(audio_file_path):
subprocess.call(["ffplay", "-nodisp", "-autoexit", audio_file_path])
The -nodisp flag stops ffplay from showing a new window, and the -autoexit flag causes ffplay to exit and return a status code when the audio file is done playing.
edit: pydub now uses pyaudio for playback when it's installed and falls back to ffplay to avoid the downsides I mentioned. The link above shows that implementation as well.

Sorry for the late reply, but I think this is a good place to advertise my library ...
AFAIK, the standard library has only one module for playing audio: ossaudiodev.
Sadly, this only works on Linux and FreeBSD.
UPDATE: There is also winsound, but obviously this is also platform-specific.
For something more platform-independent, you'll need to use an external library.
My recommendation is the sounddevice module (but beware, I'm the author).
The package includes the pre-compiled PortAudio library for Mac OS X and Windows, and can be easily installed with:
pip install sounddevice --user
It can play back sound from NumPy arrays, but it can also use plain Python buffers (if NumPy is not available).
To play back a NumPy array, that's all you need (assuming that the audio data has a sampling frequency of 44100 Hz):
import sounddevice as sd
sd.play(myarray, 44100)
For more details, have a look at the documentation.
It cannot read/write sound files, you'll need a separate library for that.

Aaron's answer appears to be about 10x more complicated than necessary. Just do this if you only need an answer that works on OS X:
from AppKit import NSSound
sound = NSSound.alloc()
sound.initWithContentsOfFile_byReference_('/path/to/file.wav', True)
sound.play()
One thing... this returns immediately. So you might want to also do this, if you want the call to block until the sound finishes playing.
from time import sleep
sleep(sound.duration())
Edit: I took this function and combined it with variants for Windows and Linux. The result is a pure python, cross platform module with no dependencies called playsound. I've uploaded it to pypi.
pip install playsound
Then run it like this:
from playsound import playsound
playsound('/path/to/file.wav', block = False)
MP3 files also work on OS X. WAV should work on all platforms. I don't know what other combinations of platform/file format do or don't work - I haven't tried them yet.

You can see this: http://www.speech.kth.se/snack/
s = Sound()
s.read('sound.wav')
s.play()

It is possible to play audio in OS X without any 3rd party libraries using an analogue of the following code. The raw audio data can be input with wave_wave.writeframes. This code extracts 4 seconds of audio from the input file.
import wave
import io
from AppKit import NSSound
wave_output = io.BytesIO()
wave_shell = wave.open(wave_output, mode="wb")
file_path = 'SINE.WAV'
input_audio = wave.open(file_path)
input_audio_frames = input_audio.readframes(input_audio.getnframes())
wave_shell.setnchannels(input_audio.getnchannels())
wave_shell.setsampwidth(input_audio.getsampwidth())
wave_shell.setframerate(input_audio.getframerate())
seconds_multiplier = input_audio.getnchannels() * input_audio.getsampwidth() * input_audio.getframerate()
wave_shell.writeframes(input_audio_frames[second_multiplier:second_multiplier*5])
wave_shell.close()
wave_output.seek(0)
wave_data = wave_output.read()
audio_stream = NSSound.alloc()
audio_stream.initWithData_(wave_data)
audio_stream.play()

This is the easiest & best iv'e found. It supports Linux/pulseaudio, Mac/coreaudio, and Windows/WASAPI.
import soundfile as sf
import soundcard as sc
default_speaker = sc.default_speaker()
samples, samplerate = sf.read('bell.wav')
default_speaker.play(samples, samplerate=samplerate)
See https://github.com/bastibe/PySoundFile and https://github.com/bastibe/SoundCard for tons of other super-useful features.

Also on OSX - from SO, using OSX's afplay command:
import subprocess
subprocess.call(["afplay", "path/to/audio/file"])
UPDATE: All this does is specify how to do what the OP wanted to avoid doing in the first place. I guess I posted this here because what OP wanted to avoid was the info I was looking for. Whoops.

Install playsound package using :
pip install playsound
Usage:
from playsound import playsound
playsound("file location\audio.p3")

Try PySoundCard which uses PortAudio for playback which is available on many platforms.
In addition, it recognizes "professional" sound devices with lots of channels.
Here a small example from the Readme:
from pysoundcard import Stream
"""Loop back five seconds of audio data."""
fs = 44100
blocksize = 16
s = Stream(samplerate=fs, blocksize=blocksize)
s.start()
for n in range(int(fs*5/blocksize)):
s.write(s.read(blocksize))
s.stop()

Mac OS I tried a lot of codes but just this works on me
import pygame
import time
pygame.mixer.init()
pygame.init()
pygame.mixer.music.load('fire alarm sound.mp3') *On my project folder*
i = 0
while i<10:
pygame.mixer.music.play(loops=10, start=0.0)
time.sleep(10)*to protect from closing*
pygame.mixer.music.set_volume(10)
i = i + 1

It's Simple. I did it this way.
For a wav file
from IPython.display import Audio
from scipy.io.wavfile import read
fs, data = read('StarWars60.wav', mmap=True) # fs - sampling frequency
data = data.reshape(-1, 1)
Audio(data = data[:, 0], rate = fs)
For mp3 file
import IPython.display import Audio
Audio('audio_file_name.mp3')

Pypi has a list of modules for python in music. My favorite would be jython because it has more resources and libraries for music. As example of of code to play a single note from the textbook:
# playNote.py
# Demonstrates how to play a single note.
from music import * # import music library
note = Note(C4, HN) # create a middle C half note
Play.midi(note) # and play it!

To play a notification sound using python, call a music player, such as vlc. VLC prompted me to use its commandline version, cvlc, instead.
from subprocess import call
call(["cvlc", "--play-and-exit", "myNotificationTone.mp3"])
It requires vlc to be preinstalled on the device. Tested on Linux(Ubuntu 16.04 LTS); Running Python 3.5.

Try sounddevice
If you don't have the module enter
pip install sounddevice in your terminal.
Then in your preferred Python script (I use Juypter), enter
import sounddevice as sd
sd.play(audio, sr) will play what you want through Python
The best way to get the audio and samplerate you want is with the librosa module. Enter this in terminal if you don't have the librosa module.
pip install librosa
audio, sr = librosa.load('wave_file.wav')
Whatever wav file you want to play, just make sure it's in the same directory as your Python script. This should allow you to play your desired wav file through Python
Cheers,
Charlie
P.S.
Once audio is a "librosa" data object, Python sees it as a numpy array. As an experiment, try playing a long (try 20,000 data points) thing of a random numpy array. Python should play it as white noise. The sounddevice module plays numpy arrays and lists as well.

In a Colab notebook you can do:
from IPython.display import Audio
Audio(waveform, Rate=16000)

This library aims to be simple, cross-platform and have many features: https://github.com/libwinmedia/libwinmedia-py
It requires a libwinmedia shared library, which you can download in Releases tab.
You can install it using pip install libwinmedia
Example:
import libwinmedia
player = libwinmedia.Player(True)
player.set_position_callback(lambda position: print(f"{position} ms."))
media = libwinmedia.Media("test.mp3")
player.open(media)

This should work on Linux, Mac or Windows:
from preferredsoundplayer import *
soundplay("audio.wav")
Should work for mp3 also.
In Linux it will try up to 4 different methods. In Windows it uses winmm.dll. In Mac it uses afplay.
I wrote it because:
I kept having issues with cross-compatibility for playing sounds.
It also manually garbage collects calls to the winmm.dll player in Windows and appropriate closes finished sounds.
It has no dependencies, other than what comes with Windows 10, the standard Linux kernel, MacOS 10.5 or later, and the Python Standard Library.
You can install using pip install preferredsoundplayer (see project) or just utilize the source code which is a single file (source code) .

Put this at the top of your python script you are writing:
import subprocess
If the wav file IS in the directory of the python script:
f = './mySound.wav'
subprocess.Popen(['aplay','-q',f)
If the wav file IS NOT in the directory of the python script:
f = 'mySound.wav'
subprocess.Popen(['aplay','-q', 'wav/' + f)
If you want to learn more about aplay:
man aplay

I recently made my Music Player support all audio files locally. I did this by figuring out a way to use the vlc python module and also the VLC dll files.
You can check it out:
https://github.com/elibroftw/music-caster/blob/master/audio_player.py

For those who use Linux and the other packages haven't worked on MP3 files, audioplayer worked fine for me:
https://pypi.org/project/audioplayer/
from audioplayer import AudioPlayer
AudioPlayer("path/to/somemusic.mp3").play(block=True)

If you're on OSX, you can use the "os" module or "subprocess" etc. to call the OSX "play" command. From the OSX shell, it looks like
play "bah.wav"
It starts to play in about a half-second on my machine.

Simply You can do it with the help of cvlc-
I did it in this way:
import os
os.popen2("cvlc /home/maulo/selfProject/task.mp3 --play-and-exit")
/home/maulo/selfProject/task.mp3. This is the location of my mp3 file.
with the help of "--play-and-exit" you will be able to play again the sound without ending the vlc process.

Related

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: Open multiple images in default image viewer

I am using PIL to open a single image in the default image viewer:
from PIL import Image
img = Image.open('example.jpg')
img.show()
Does any Python module contain a function enabling opening multiple images in the current system's default image viewer? For instance when on OS X, Preview.app should open with the list of images in the sidebar. From the command line this is no problem at all:
$ open my_picture_number_*
Use case is that users should just be able to explore a few dozen images.
Use subprocess.run to run the operating system's default image viewing app. subprocess.run works a lot like a command line. You just need to know what the command is for the operating system you're on. For windows, "explorer" will do; for OS X, as you point out, it's "open." I'm not sure what it is for Linux, maybe "eog"?
So, your code would look like this:
import sys
import subprocess
def openImage(path):
imageViewerFromCommandLine = {'linux':'xdg-open',
'win32':'explorer',
'darwin':'open'}[sys.platform]
subprocess.run([imageViewerFromCommandLine, path])
I've tried to use #jgfoot's answer, which worked, but made my program hang after the viewer was launched. I've solved this issue by using subprocess.Popen instead, like this:
import sys
import subprocess
def openImage(path):
imageViewerFromCommandLine = {'linux':'xdg-open',
'win32':'explorer',
'darwin':'open'}[sys.platform]
subprocess.Popen([imageViewerFromCommandLine, path])

Play m4a in python script with mplayer

I'm posting to a URL, downloading an audio file (m4a) and trying to play it from the terminal with a Python script. When I type
mplayer asdf.m4a
in the terminal it plays fine. But when I execute the following code
from mplayer import Player
player = Player()
player.loadfile('asdf.m4a')
as shown in the mplayer guide, I get the following errors:
mplayer: could not connect to socket
mplayer: No such file or directory
I've been trying to figure this out for a couple days now and it seems like it should be real simple. I don't know what's wrong. I was able to use pygame to play mp3's and ogg's but I need to play m4a and I just can't seem to get mplayer to work for me.
The only related issues I've seen suggested adding nolirc=yes to the mplayer config file. Didn't help.
Any help would be greatly appreciated.
Worst way, but could be usefull:
from subprocess import Popen, PIPE
pipes = dict(stdin=PIPE, stdout=PIPE, stderr=PIPE)
mplayer = Popen(["mplayer", "asdf.m4a"], **pipes)
# to control u can use Popen.communicate
mplayer.communicate(input=b">")
sys.stdout.flush()
Try using the absolute path to the file. If you are running this script in an IDE or debugger, sometimes it can mess up the relative path.
I would try:
import os
from mplayer import Player
player = Player()
abspath = os.path.join(os.path.dirname(__file__), 'asdf.m4a')
player.loadfile(abspath)

Sound alarm when code finishes

I am in a situation where my code takes extremely long to run and I don't want to be staring at it all the time but want to know when it is done.
How can I make the (Python) code sort of sound an "alarm" when it is done? I was contemplating making it play a .wav file when it reaches the end of the code...
Is this even a feasible idea?
If so, how could I do it?
On Windows
import winsound
duration = 1000 # milliseconds
freq = 440 # Hz
winsound.Beep(freq, duration)
Where freq is the frequency in Hz and the duration is in milliseconds.
On Linux and Mac
import os
duration = 1 # seconds
freq = 440 # Hz
os.system('play -nq -t alsa synth {} sine {}'.format(duration, freq))
In order to use this example, you must install sox.
On Debian / Ubuntu / Linux Mint, run this in your terminal:
sudo apt install sox
On Mac, run this in your terminal (using macports):
sudo port install sox
Speech on Mac
import os
os.system('say "your program has finished"')
Speech on Linux
import os
os.system('spd-say "your program has finished"')
You need to install the speech-dispatcher package in Ubuntu (or the corresponding package on other distributions):
sudo apt install speech-dispatcher
print('\007')
Plays the bell sound on Linux. Plays the error sound on Windows 10.
This one seems to work on both Windows and Linux* (from this question):
def beep():
print("\a")
beep()
In Windows, can put at the end:
import winsound
winsound.Beep(500, 1000)
where 500 is the frequency in Herz
1000 is the duration in miliseconds
To work on Linux, you may need to do the following (from QO's comment):
in a terminal, type 'cd /etc/modprobe.d' then 'gksudo gedit blacklist.conf'
comment the line that says 'blacklist pcspkr', then reboot
check also that the terminal preferences has the 'Terminal Bell' checked.
I'm assuming you want the standard system bell, and don't want to concern yourself with frequencies and durations etc., you just want the standard windows bell.
import winsound
winsound.MessageBeep()
ubuntu speech dispatcher can be used:
import subprocess
subprocess.call(['speech-dispatcher']) #start speech dispatcher
subprocess.call(['spd-say', '"your process has finished"'])
Kuchi's answer didn't work for me on OS X Yosemite (10.10.1). I did find the afplay command (here), which you can just call from Python. This works regardless of whether the Terminal audible bell is enabled and without a third-party library.
import os
os.system('afplay /System/Library/Sounds/Sosumi.aiff')
Why use python at all? You might forget to remove it and check it into a repository. Just run your python command with && and another command to run to do the alerting.
python myscript.py &&
notify-send 'Alert' 'Your task is complete' &&
paplay /usr/share/sounds/freedesktop/stereo/suspend-error.oga
or drop a function into your .bashrc. I use apython here but you could override 'python'
function apython() {
/usr/bin/python $*
notify-send 'Alert' "python $* is complete"
paplay /usr/share/sounds/freedesktop/stereo/suspend-error.oga
}
See: Python Sound ("Bell")
This helped me when i wanted to do the same.
All credits go to gbc
Quote:
Have you tried :
import sys
sys.stdout.write('\a')
sys.stdout.flush()
That works for me here on Mac OS 10.5
Actually, I think your original attempt works also with a little modification:
print('\a')
(You just need the single quotes around the character sequence).
It can be done by code as follows:
import time
time.sleep(10) #Set the time
for x in range(60):
time.sleep(1)
print('\a')
A bit more to your question.
I used gTTS package to generate audio from text and then play that audio using Playsound when I was learning webscraping and created a coursera downloader(only free courses).
text2speech = gTTS("Your course " + course_name +
" is downloaded to " + downloads + ". Check it fast.")
text2speech.save("temp.mp3")
winsound.Beep(2500, 1000)
playsound("temp.mp3")
I created a python module that reminds developers on Telegram application after code execution. It might be more helpful than making alarm sound.
Pypi link:
https://pypi.org/project/devreminder/
Github link:
https://github.com/cagataygulten/devreminder
Example:
In [1]>>
from devreminder import DevReminder
import time
In [2]>>
remind = DevReminder(1932126911,False,0)
In [3]>>
remind.me("Example")
time.sleep(6)
Output:
Please follow README file for more information.
On macOS there's a dead simple way to do it.
python file.py && say done
import subprocess
subprocess.call(['D:\greensoft\TTPlayer\TTPlayer.exe', "E:\stridevampaclip.mp3"])

Play simple beep with python without external library

Using only the modules that come with a standard python 2.6 installation, would it be possible to play a simple beeping noise?
If you're on a Unix terminal, you can print "\a" to get a terminal bell:
>>> def beep():
... print "\a"
>>> beep()
Of course, that will print a newline too… So sys.stdout.write("\a") might be better. But you get the idea.
On windows:
import winsound # for sound
import time # for sleep
winsound.Beep(440, 250) # frequency, duration
time.sleep(0.25) # in seconds (0.25 is 250ms)
winsound.Beep(600, 250)
time.sleep(0.25)
34.4. winsound — Sound-playing interface for Windows:
http://docs.python.org/2.6/search.html?q=sound&check_keywords=yes&area=default
See also:
Clear screen and beep for various platforms. (Python recipe)
http://code.activestate.com/recipes/577588-clear-screen-and-beep-for-various-platforms/
On Android with QPython this is how it goes:
import androidhelper
droid=androidhelper.Android()
droid.generateDtmfTones('0',100)
This will place a beep of a certain frequency for certain time.

Categories