144

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.

Chachmu
  • 7,725
  • 6
  • 30
  • 35
Josh Hunt
  • 14,225
  • 26
  • 79
  • 98
  • If you need portable Python audio library try [PyAudio](http://people.csail.mit.edu/hubert/pyaudio/). It certainly has a mac port. As for mp3 files: it's certainly doable in "raw" Python, only I'm afraid you'd have to code everything yourself :). If you can afford some external library I've found some [PyAudio - PyLame sample](http://n2.nabble.com/Lame-python-bindings-td33898.html) here. – Grzegorz Gacek Feb 03 '09 at 15:08
  • [Pyglet](http://pyglet.org/) has the ability to play back audio through an external library called [AVbin](http://code.google.com/p/avbin). Pyglet is a ctypes wrapper around native system calls on each platform it supports. Unfortunately, I don't think anything in the standard library will play audio back. – technomalogical Nov 04 '08 at 14:37
  • try [just_playback](https://github.com/cheofusi/just_playback). It's a wrapper around miniaudio that provides playback control functionality like pausing, resuming, seeking and setting the playback volume. – droptop May 09 '21 at 22:29

25 Answers25

55

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')
yehan jaya
  • 675
  • 1
  • 5
  • 10
  • 97
    Reading this made me so emotional. My eyes literally teared up with happiness. Did not expect that kind of reaction from myself. (They linked to a module I made.) – ArtOfWarfare Jan 24 '18 at 14:51
  • +1 for `playsound`. I just tested out a couple solutions here, and this one worked the easiest for me. Unfortunately the `pygame` solution didn't work for me, during a brief test. –  Nov 24 '19 at 19:18
  • @ArtOfWarfare They're moving in herds. – Leo Heinsaar Oct 18 '20 at 07:49
  • 1
    I love how simple and [probabilistic](https://github.com/TaylorSMarks/playsound/blob/master/playsound.py#L6) this module is ( : –  Jan 11 '21 at 16:53
  • Pure Python - except that it relies on MCI for example, doesn't close files, can't play non-blocking, ... – Thomas Weller Nov 29 '21 at 16:26
  • Does not work on Raspbian Lite out of the box due to the dependency on the `Gst` module. – Vlad Jan 19 '22 at 15:02
  • Doesn't work if filename contains non-ascii characters though. – lazarea Jan 20 '22 at 13:48
  • There is one problem with Playsound: you have to include the folder the file is located in, even if it is in the same folder. For example: you have a folder with music.wav and play.py. The folder is called test. You still have to include /test/music.wav when loading. This could be a problem if you change the name of the folder for some reason. It does not default to the folder it is in. – CodeWizard777 Apr 15 '22 at 18:24
  • 1
    playsound is relying on a python 2 subprocess. Please use `pip3 install PyObjC` if you want playsound to run more efficiently. – cssstudent Nov 24 '22 at 04:33
  • For me it returns an error when trying to play a file: "ValueError: Namespace Gst not available" which is fixed by `sudo apt install python3-gst-1.0`. Thanks for writing this module! – Yan King Yin May 31 '23 at 15:11
  • There seems to be a bug: after I installed playsound, HexChat (clone of XChat) freezes upon startup. Wonder if others have the same problem? – Yan King Yin Jun 05 '23 at 15:14
54

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

TML
  • 12,813
  • 3
  • 38
  • 45
22

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.

Erwin Mayer
  • 18,076
  • 9
  • 88
  • 126
20

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.

Paige Ruten
  • 172,675
  • 36
  • 177
  • 197
17

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.

Matthias
  • 4,524
  • 2
  • 31
  • 50
16

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.

Jiaaro
  • 74,485
  • 42
  • 169
  • 190
7

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.

Community
  • 1
  • 1
ArtOfWarfare
  • 20,617
  • 19
  • 137
  • 193
  • I get the following error: "Can't convert 'bytes' object to str implicitly" on Python 3.5 (Windows). – Erwin Mayer Mar 29 '16 at 12:24
  • @ErwinMayer - Are you talking about with the `playsound` module I wrote? I haven't tested it on anything newer than Python 2.7.11... I can certainly look into fixing this on 3.5... – ArtOfWarfare Mar 29 '16 at 13:30
  • Indeed. It must be due to Python 3 differences. – Erwin Mayer Mar 29 '16 at 15:20
  • AppKit _is_ a dependency. – Chris Larson Dec 30 '16 at 19:08
  • @ChrisLarson - AppKit is included with most Mac distributions of Python... unless you're getting Python from a weird source or building it without standard libraries or something, that shouldn't be an onerous dependency. – ArtOfWarfare Dec 30 '16 at 22:24
  • 2
    @ArtOfWarfare That's simply _not_ true. It is installed with the system python, but not with most distributions, including the official distributions from python.org. Most folks I know who use python install one of the distributions to get past the SIP restrictions. To get AppKit for most distributions, a user needs to pip install pyobjc. Which makes it most _definitely_ a dependency. – Chris Larson Dec 30 '16 at 23:25
  • @ArtOfWarfare I'm willing to be corrected on this, but as I'm using the python.org dist and AppKit isn't present, I'm fairly confident here. – Chris Larson Dec 30 '16 at 23:26
  • Hello, thank you for playsound. My issue is, I can't stop playing the audio file after I started it. How can I manually stop the file? Especially because I want to play it with True and False options (so asynchronously as well). When I do that, the program finishes executing but the audio still plays. Any tips on ending the playback of the audio? Both via code as well as a manual termination. – James Carter Aug 21 '18 at 02:54
  • @JamesCarter - You can modify playsound.py. If you're on a Mac, you'll want to look at `nssound`, I imagine it has a `stop()` method you can use. If you're on Windows, you'll probably want to `winCommand('pause', alias)`. Total guesses on my part. I haven't looked at this in 2+ years. I recall I had sound effects in mind and didn't want to make this too complicated. – ArtOfWarfare Aug 21 '18 at 17:52
  • I'm on windows. I'll look into modifying it. I'm not an expert with python but I'll work on it. – James Carter Aug 21 '18 at 18:22
  • This is amazing. I was wondering why my script wasn't playing when running `sound.play()`. You MUST put the sleep function after playing the sound. P.S. Amazing library btw ;) – Dan Sep 20 '22 at 03:30
5

You can see this: http://www.speech.kth.se/snack/

s = Sound() 
s.read('sound.wav') 
s.play()
Mehul Mistri
  • 15,037
  • 14
  • 70
  • 94
user1926182
  • 51
  • 1
  • 1
5

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()
Aaron
  • 51
  • 1
  • 1
  • This is far more complicated than necessary - they asked how to simply play a sound, not how to manipulate it and then play it. My answer trims the unnecessary 90% from this answer and leaves exactly what the asker wanted - playing a sound from a file in OS X using Python. http://stackoverflow.com/a/34984200/901641 – ArtOfWarfare Jan 25 '16 at 02:26
  • Although verbose, I'll disagree with @ArtOfWarfare. This is an amazing answer just for the fact that it shows how to play audio in byte format. This is specially useful when the audio is obtained from a HTTP request, and this happens to be exactly my use case. – Dan Sep 20 '22 at 04:43
  • @Dan - IIRC, playsound accepts URLs as well as filepaths. That might be undocumented and not supported on all platforms, but I'm pretty certain it works with macOS. I think examples should be as short as possible to actually answer the question - this example is far longer than necessary for what was asked. – ArtOfWarfare Sep 28 '22 at 15:14
5

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.

n00p
  • 269
  • 4
  • 11
  • Just a headsup for anyone going for this (as I am). All the libs and their dependencies take forever to build on a Raspberry Pi 1B+ - especially numpy. – pojda Oct 14 '17 at 01:16
  • PS: this didn't work for raspberry pi "NotImplementedError: SoundCard does not support linux2 yet", and couldn't figure out a way to fix it. I'm going with os.system("mpg123 file.mp3") – pojda Oct 14 '17 at 02:42
  • Ah, that sucks. I guess raspberry pi is a somewhat special environment. Perhaps if you posted an issue on the issuetracker you could get it sorted out or fixed. – n00p Oct 14 '17 at 13:28
  • On further thought, perhaps the problem is that you are using an old kernel or old python version. With newer python versions that error should not look like that i think. – n00p Oct 15 '17 at 15:35
  • It's running Raspbian, which is basically a Debian Stretch fork. I gave up and went the os.system way which is working just fine atm. Thanks for helping me out! – pojda Oct 17 '17 at 19:00
3

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.

MikeiLL
  • 6,282
  • 5
  • 37
  • 68
  • Works great though does pause execution while it plays. Perhaps there is an async way to call this? – Praxiteles Feb 04 '16 at 06:49
  • Good questions @Praxiteles. Possibly with threading. [see here](http://stackoverflow.com/questions/984941/python-subprocess-popen-from-a-thread) Please report back if you have a chance to experiment with it. – MikeiLL Feb 05 '16 at 15:51
  • The OP explicitly asked for alternatives to this. – whitey04 May 19 '16 at 20:14
  • The OP is/was looking for an alternative to "execute the afplay file.mp3 command from within Python", and subprocessing still happens within Python, doesn't it. I stand corrected. But it probably doesn't hurt to have this little post here as it may help others. – MikeiLL May 19 '16 at 20:23
  • @whitey04 I (finally) see what you're saying. – MikeiLL Feb 16 '18 at 16:50
3

Install playsound package using :

pip install playsound

Usage:

from playsound import playsound
playsound("file location\audio.p3")
phwt
  • 1,356
  • 1
  • 22
  • 42
Harish
  • 31
  • 1
  • 3
3

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')
2

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()
kenorb
  • 155,785
  • 88
  • 678
  • 743
  • Though interesting, link-only answers are discouraged. At the minimum, you should include in your answer a short example of using it. That also protects your answer from losing all its value, should the repository be renamed and the link go dangling. – spectras May 29 '16 at 11:04
2

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
2

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

garydavenport73
  • 379
  • 2
  • 8
1

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!
Kardi Teknomo
  • 1,375
  • 16
  • 24
1

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.

amarVashishth
  • 847
  • 3
  • 12
  • 26
1

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.

rd10
  • 1,599
  • 2
  • 10
  • 27
1

In a Colab notebook you can do:

from IPython.display import Audio
Audio(waveform, Rate=16000)
Axel Bregnsbo
  • 3,773
  • 2
  • 22
  • 16
1

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)
mytja
  • 56
  • 1
  • 6
0

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
Crawsome
  • 80
  • 1
  • 1
  • 3
0

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

Elijah
  • 1,814
  • 21
  • 27
0

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)
gleitonfranco
  • 791
  • 6
  • 9
-1

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.

ridvankucuk
  • 2,407
  • 1
  • 23
  • 41
pyAddict
  • 1,576
  • 13
  • 15