Showing posts with label PyAudio. Show all posts
Showing posts with label PyAudio. Show all posts

Thursday, October 22, 2015

Play a list of WAV files with PyAudio

By Vasudev Ram




While looking at various Python libraries, I remembered PyAudio, which I had blogged about here earlier:

PyAudio and PortAudio - like ODBC for sound

This time I thought of using it to play a list of WAV files. So I wrote a small Python program for that, adapting one of the PyAudio examples. Here it is, in the file pyaudio_play_wav.py:
'''
Module to play WAV files using PyAudio.
Author: Vasudev Ram - http://jugad2.blogspot.com
Adapted from the example at:
https://people.csail.mit.edu/hubert/pyaudio/#docs
PyAudio Example: Play a wave file.
'''

import pyaudio
import wave
import sys
import os.path
import time

CHUNK_SIZE = 1024

def play_wav(wav_filename, chunk_size=CHUNK_SIZE):
    '''
    Play (on the attached system sound device) the WAV file
    named wav_filename.
    '''

    try:
        print 'Trying to play file ' + wav_filename
        wf = wave.open(wav_filename, 'rb')
    except IOError as ioe:
        sys.stderr.write('IOError on file ' + wav_filename + '\n' + \
        str(ioe) + '. Skipping.\n')
        return
    except EOFError as eofe:
        sys.stderr.write('EOFError on file ' + wav_filename + '\n' + \
        str(eofe) + '. Skipping.\n')
        return

    # Instantiate PyAudio.
    p = pyaudio.PyAudio()

    # Open stream.
    stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
        channels=wf.getnchannels(),
        rate=wf.getframerate(),
                    output=True)

    data = wf.readframes(chunk_size)
    while len(data) > 0:
        stream.write(data)
        data = wf.readframes(chunk_size)

    # Stop stream.
    stream.stop_stream()
    stream.close()

    # Close PyAudio.
    p.terminate()

def usage():
    prog_name = os.path.basename(sys.argv[0])
    print "Usage: {} filename.wav".format(prog_name)
    print "or: {} -f wav_file_list.txt".format(prog_name)

def main():
    lsa = len(sys.argv)
    if lsa < 2:
        usage()
        sys.exit(1)
    elif lsa == 2:
        play_wav(sys.argv[1])
    else:
        if sys.argv[1] != '-f':
            usage()
            sys.exit(1)
        with open(sys.argv[2]) as wav_list_fil:
            for wav_filename in wav_list_fil:
                # Remove trailing newline.
                if wav_filename[-1] == '\n':
                    wav_filename = wav_filename[:-1]
                play_wav(wav_filename)
                time.sleep(3)

if __name__ == '__main__':
    main()
Then I ran it as follows:

$ python pyaudio_play_wav.py chimes.wav

$ python pyaudio_play_wav.py chord.wav

$ python pyaudio_play_wav.py -f wav_file_list.txt

where wav_file_list.txt contained these two lines:

chimes.wav
chord.wav
Worked okay and played the specified WAV files. I also ran it a few times with test cases that should trigger errors - the error cases that the current code handles. This worked okay too. You can use one or more WAV files to try out the program. Other than modules in the Python stdlib, the only dependency is PyAudio, which you can install with pip. - Enjoy.

- Vasudev Ram - Online Python training and programming

Signup to hear about new products and services I create.

Posts about Python  Posts about xtopdf

My ActiveState recipes

Thursday, November 7, 2013

A simple alarm clock in Python (command-line)

By Vasudev Ram



(Updated the post after a while, so it may show up twice in some feed readers (but with more info), sorry ...)

I had a need to set alarms for myself while working at the computer, to remind me to stop the current task and do some other task. Was using my smartphone's alarm clock app, but found that the volume was a bit too high, even at the lowest volume setting. So I thought of writing a simple alarm clock in Python as a command-line utility. Here it the code for it:
# alarm_clock.py

# Description: A simple Python program to make the computer act 
# like an alarm clock. Start it running from the command line 
# with a command line argument specifying the duration in minutes 
# after which to sound the alarm. It will sleep for that long, 
# and then beep a few times. Use a duration of 0 to test the 
# alarm immediiately, e.g. for checking that the volume is okay.

# Author: Vasudev Ram - http://www.dancingbison.com

import sys
import string
from time import sleep

sa = sys.argv
lsa = len(sys.argv)
if lsa != 2:
    print "Usage: [ python ] alarm_clock.py duration_in_minutes"
    print "Example: [ python ] alarm_clock.py 10"
    print "Use a value of 0 minutes for testing the alarm immediately."
    print "Beeps a few times after the duration is over."
    print "Press Ctrl-C to terminate the alarm clock early."
    sys.exit(1)

try:
    minutes = int(sa[1])
except ValueError:
    print "Invalid numeric value (%s) for minutes" % sa[1]
    print "Should be an integer >= 0"
    sys.exit(1)

if minutes < 0:
    print "Invalid value for minutes, should be >= 0"
    sys.exit(1)

seconds = minutes * 60

if minutes == 1:
    unit_word = " minute"
else:
    unit_word = " minutes"

try:
    if minutes > 0:
        print "Sleeping for " + str(minutes) + unit_word
        sleep(seconds)
    print "Wake up"
    for i in range(5):
        print chr(7),
        sleep(1)
except KeyboardInterrupt:
    print "Interrupted by user"
    sys.exit(1)

# EOF

Run it without any command line arguments to see how to use it:

C:> python alarm_clock.py

or

C:> alarm_clock.py

Use the first version of the command above, if your Python interpreter is not registered with the OS as the default application to run .py files, and the second version if it is registered. Usually the latter is the case, so you can omit the word python at the beginning of the command. The square brackets shown in the usage message (see the code) are not to be typed literally, they are there to indicate that the word within them is optional (a standard convention used on UNIX).

You can pass an argument of 0 for the duration, to test the alarm clock immediately, e.g. to see if the volume suits you or not. If not, increase or decrease the volume of your computer speakers.

I find this simple alarm clock program more convenient to use (when at my computer, of course) than either my smartphone's alarm clock app, or my traditional (physical) alarm clock like the one in the image above :-) (*)

I just have to keep one command window open, run that program in it, e.g.:

alarm_clock.py 30

to remind me to change tasks after 30 minutes. And when I want to set and run the alarm again, I just hit up arrow, change the time at the end of the command if needed, and hit Enter.

In fact, on my machine, I also created a batch file called alarm.bat, which accepts an argument and passes it to alarm_clock.py, so all I really have to type at the command line is:

alarm 30

(*) (Okay, I don't really have one of those old-fashioned alarm clocks; I have a modern plastic one. But I'd like to pick up one of those old-fashioned pocket watches like the one below, at some antique or second-hand shop some day. My grandfather had one of those ...

old-fashioned pocket watch

The tool uses the print chr(7) method to make the beeps. I did this to make it portable between Windows and Linux. It is possible to use the winsound module (only on Windows) for making the sound instead. See my earlier post about Python's winsound module: Try the Python WinSound API. It would also be possible to use other sound libraries instead, of course, on either Linux or Windows. For example, check out my earlier post about PyAudio (which also has a link to an earlier post about pyglet, another sound library option).

I'd also earlier written a digital clock (not an alarm clock, just a clock display) in 3 lines of Delphi code :-)

Of course, there are many variations and improvements possible on an alarm clock utility, such as having a GUI, making it look like a real alarm clock, and others. I may work on some of those at some point later. Meanwhile, this simple one works well enough for my current needs.


- Vasudev Ram - Dancing Bison Enterprises

Read other posts about Python on my blog.

Read other posts about utilities on my blog.

Contact me





O'Reilly 50% Ebook Deal of the Day

Sunday, April 28, 2013

PySynth, a pure Python music synthesizer


By Vasudev Ram

PySynth is a music synthesizer library written in Python. (*)

Excerpt from the site:

[ There are three variants: PySynth A is faster, only needs Python itself, and sounds more like a cross between a flute and organ. PySynth B is more complex in sound and needs NumPy. It's supposed to be a little closer to a piano. (No competition for Pianoteq of course, but a reasonable fit for keyboard music.) Finally, PySynth S is more comparable to a guitar, banjo, or harpsichord, depending on note length and pitch.

The current release of the synthesizer is monophonic, i.e. it can only play one note at a time. (Although successive notes can overlap in PySynth B and S, but not A.) However, two output files can be mixed together as in the case of the stereo files below. ]

(*) Interestingly, the Changes section of the above linked PySynth page seems to indicate that PySynth uses both Pyglet and PyAudio, both of which I had blogged about some time ago:

Playing an MP3 with pyglet and Python is easy

PyAudio and PortAudio - like ODBC for sound

Here is PySynth on Github

PySynth supports ABC notation and can generate WAV audio files.

Here is an example tune:

D D C C B A G

and here is a PySynth program to play that tune as a WAV file:
# pysynth-ddccbag.py

import pysynth

test = ( ('d', 4), ('d', 4), ('c', 4), ('c', 4), ('b', 4), ('a', 4), ('g', 3) )
pysynth.make_wav(test, fn = "ddccbag.wav")
For some reason the last note seems to get partially cut off on my PC. Not sure whether that is a bug or a feature :-) or something to do with my hardware. Maybe the latter, since I'm using my laptop's built-in speakers.

Run that program as:
python pysynth-ddccbag.py 

Then play the generated WAV file ddccbag.wav in a music player, such as VLC or some other one.

Here are a few better examples of sound synthesis by PySynth - the links are to MP4 files, which you can download and play without needing Python or PySynth:

The Sailor’s Hornpipe — PySynth S

Bach: Jesu, Joy of Man’s Desiring — PySynth S (treble) and B (bass)

Also check my recent post: Play the piano on your computer with Python.

If you want to try it out, note that the program has a couple of bugs, related to the frequencies of notes, since I am not musically trained; I just wrote it for fun and as an experiment. Though some of the post comments gave some background and suggested corrections, they did not seem to be sure, and corrected themselves, so I have not implemented any of those suggestions yet.


Enjoy.

- Vasudev Ram - Dancing Bison Enterprises

Thursday, October 13, 2011

PyAudio and PortAudio - like ODBC for sound

By Vasudev Ram - dancingbison.com | @vasudevram | jugad2.blogspot.com

PyAudio and PortAudio are I/O libraries for sound (i.e. audio).

I'm stretching the analogy a bit here, but they made me think:

"... like ODBC for sound". (*)

PyAudio is a Python interface to PortAudio.

PyAudio:

http://people.csail.mit.edu/hubert/pyaudio/

Excerpt:

[ PyAudio provides Python bindings for PortAudio, the cross-platform audio I/O library. With PyAudio, you can easily use Python to play and record audio on a variety of platforms. ]

PortAudio:

http://www.portaudio.com/

PortAudio apps:

http://www.portaudio.com/apps.html

I installed PyAudio for Windows. Installation was trivial. It also automatically installed the PortAudio DLL (actually, the .pyd file).

I then tried a PyAudio Python program from the docs to play a small .WAV file. It worked.

(*) That's because PyAudio and PortAudio support both:

a) different platforms (Windows, Linux, Mac, UNIX)

b) different "Host APIs" on the same platform, where the different Host API's have, obviously, different API's, but PortAudio (and hence PyAudio) hide those differences behind a uniform interface (to some extent).


UPDATE: If you interested in checking out other Python multimedia libraries, you may also like to read this earlier post of mine about pyglet:

Playing an MP3 with pyglet and Python is easy

pyglet has some of the same benefits as PyAudio - cross-platform, easy to use, etc.

Posted via email

- Vasudev Ram @ Dancing Bison