10

I do not understand the example material for pyaudio. It seems they had written an entire small program and it threw me off.

How do I just play a single audio file?

Format is not an issue, I just want to know the bare minimum code I need to play an audio file.

petezurich
  • 9,280
  • 9
  • 43
  • 57
JShoe
  • 3,186
  • 9
  • 38
  • 61

3 Answers3

19

May be this small wrapper (warning: created on knees) of their example will help you to understand the meaning of code they wrote.

import pyaudio
import wave
import sys

class AudioFile:
    chunk = 1024

    def __init__(self, file):
        """ Init audio stream """ 
        self.wf = wave.open(file, 'rb')
        self.p = pyaudio.PyAudio()
        self.stream = self.p.open(
            format = self.p.get_format_from_width(self.wf.getsampwidth()),
            channels = self.wf.getnchannels(),
            rate = self.wf.getframerate(),
            output = True
        )

    def play(self):
        """ Play entire file """
        data = self.wf.readframes(self.chunk)
        while data != b'':
            self.stream.write(data)
            data = self.wf.readframes(self.chunk)

    def close(self):
        """ Graceful shutdown """ 
        self.stream.close()
        self.p.terminate()

# Usage example for pyaudio
a = AudioFile("1.wav")
a.play()
a.close()
Tad
  • 4,668
  • 34
  • 35
Mikhail Churbanov
  • 4,436
  • 1
  • 28
  • 36
19

The example seems pretty clear to me. You simply save the example as playwav.py call:

python playwav.py my_fav_wav.wav

The wave example with some extra comments:

import pyaudio
import wave
import sys

# length of data to read.
chunk = 1024

# validation. If a wave file hasn't been specified, exit.
if len(sys.argv) < 2:
    print "Plays a wave file.\n\n" +\
          "Usage: %s filename.wav" % sys.argv[0]
    sys.exit(-1)

'''
************************************************************************
      This is the start of the "minimum needed to read a wave"
************************************************************************
'''
# open the file for reading.
wf = wave.open(sys.argv[1], 'rb')

# create an audio object
p = pyaudio.PyAudio()

# open stream based on the wave object which has been input.
stream = p.open(format =
                p.get_format_from_width(wf.getsampwidth()),
                channels = wf.getnchannels(),
                rate = wf.getframerate(),
                output = True)

# read data (based on the chunk size)
data = wf.readframes(chunk)

# play stream (looping from beginning of file to the end)
while data:
    # writing to the stream is what *actually* plays the sound.
    stream.write(data)
    data = wf.readframes(chunk)


# cleanup stuff.
wf.close()
stream.close()    
p.terminate()
cwallenpoole
  • 79,954
  • 26
  • 128
  • 166
  • But I the print stuff necessary? – JShoe Aug 05 '11 at 03:56
  • I get `Cannot connect to server request channel` `jack server is not running or cannot be started` – Jonathan Jul 02 '15 at 08:22
  • @JonathanLeaders You may wat to make that a new question – cwallenpoole Jul 02 '15 at 14:27
  • Apparently it plays regardless of the error, just at the wrong speed, so i went with pygame.mixer – Jonathan Jul 02 '15 at 22:06
  • 2
    With Python 3 I had to replace the condition to `if len(data) > 0`; otherwise this loop turns to infinite – SwiftStudier May 14 '18 at 18:55
  • @SwiftStudier With Python you can solve the issue with `while data != b""` as well, following the original answer's method. Apparently, in Python 3, a binary string is a sequence of octets, while a standard string is a sequence of Unicode characters. Python2 ignores the b in front of a string, so I would suggest OP to edit his answer. tl, dr: `b""==""` returns False. – mazunki Mar 09 '19 at 22:03
  • 1
    `while data: ` works correctly, also needs `wf.close()` – Gringo Suave Feb 13 '20 at 02:16
0

This way requires ffmpeg for pydub, but can play not only wave files:

import pyaudio
import sys
from pydub import AudioSegment


if len(sys.argv) <= 1:
    print('No File Name!')
    sys.exit(1)


chunk = 1024
fn = ' '.join(sys.argv[1:])


pd = AudioSegment.from_file(fn)
p = pyaudio.PyAudio()

stream = p.open(format =
                p.get_format_from_width(pd.sample_width),
                channels = pd.channels,
                rate = pd.frame_rate,
                output = True)


i = 0
data = pd[:chunk]._data
while data:
    stream.write(data)
    i += chunk
    data = pd[i:i + chunk]._data


stream.close()    
p.terminate()
sys.exit(0)