Welcome, guest | Sign In | My Account | Store | Cart

This simple script shows how to play back a sound file using the mixer module from the pygame library. If you have pygame installed, this will work on all major platforms. The mixer module supports WAV and OGG files with many different sample rates, bits per sample and channels. The script will play back all supported files given on the command line sequentially.

Python, 105 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
#!/usr/bin/env python
"""Play sound files using the pygame mixer module."""


__program__   = "soundplay.py"
__author__    = "Christopher Arndt"
__version__   = "1.1"
__revision__  = "$Rev: 136 $"
__date__      = "$Date: 2007-06-06 19:18:47 +0200 (Mi, 06 Jun 2007) $"
__copyright__ = "Public domain"

import sys
import pygame

# global constants
FREQ = 44100   # same as audio CD
BITSIZE = -16  # unsigned 16 bit
CHANNELS = 2   # 1 == mono, 2 == stereo
BUFFER = 1024  # audio buffer size in no. of samples
FRAMERATE = 30 # how often to check if playback has finished

def playsound(soundfile):
    """Play sound through default mixer channel in blocking manner.
    
    This will load the whole sound into memory before playback
    """

    sound = pygame.mixer.Sound(soundfile)
    clock = pygame.time.Clock()
    sound.play()
    while pygame.mixer.get_busy():
        clock.tick(FRAMERATE)

def playmusic(soundfile):
    """Stream music with mixer.music module in blocking manner.
    
    This will stream the sound from disk while playing.
    """

    clock = pygame.time.Clock()
    pygame.mixer.music.load(soundfile)
    pygame.mixer.music.play()
    while pygame.mixer.music.get_busy():
        clock.tick(FRAMERATE)

def playmusic2(soundfile):
    """Stream music with mixer.music module using the event module to wait
       until the playback has finished.

    This method doesn't use a busy/poll loop, but has the disadvantage that 
    you neet to initialize the video module to use the event module.
    
    Also, interrupting the playback with Ctrl-C does not work :-(
    
    Change the call to 'playmusic' in the 'main' function to 'playmusic2'
    to use this method.
    """

    pygame.init()

    pygame.mixer.music.load(soundfile)
    pygame.mixer.music.set_endevent(pygame.constants.USEREVENT)
    pygame.event.set_allowed(pygame.constants.USEREVENT)
    pygame.mixer.music.play()
    pygame.event.wait()

def main(args):
    # look at command line
    streaming = False
    if args and args[0] == '-s':
        streaming = True
        args.pop(0)
    if not args:
        print >>sys.stderr, "usage: soundplay [-s] FILE"
        print >>sys.stderr, "  -s    use streaming mode"
        return 2

    # initialize pygame.mixer module
    # if these setting do not work with your audio system
    # change the global constants accordingly
    try:
        pygame.mixer.init(FREQ, BITSIZE, CHANNELS, BUFFER)
    except pygame.error, exc:
        print >>sys.stderr, "Could not initialize sound system: %s" % exc
        return 1

    try:
        for soundfile in args:
            try:
                # play it!
                if streaming:
                    playmusic(soundfile)
                else:
                    playsound(soundfile)
            except pygame.error, exc:
                print >>sys.stderr, "Could not play sound file: %s" % soundfile
                print exc
                continue
    except KeyboardInterrupt:
        # if user hits Ctrl-C, exit gracefully
        pass
    return 0

if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))

Using the computer's audio system is normally a highly platform-dependant task. The mixer module of the pygame library gives you a simple API to play back and control sounds, which works accross all major platforms. This is made possible by the underlying SDL_mixer library.

This example script shows how to play back sound files from the command line, similar to comands like play(1) or aplay(1) on Linux, but it should work on all platforms where pygame with the mixer module is installed.

Because pygame is a library for writing games and multimedia applications, it provides a Sound object that allows to play back sounds in the background while returning control back to your program. For a command line script that just plays back a sound and does nothing else, we have to wait until the sound has finished playing. Otherwise the script would start the playback and then exit immediately, thereby cutting off the sound again and nothing would be heard.

We wait for the sound to finish using a while-loop, that runs as long as pygame.mixer.get_busy() returns True. To prevent this loop from eating up all CPU cycles, we use the pygame.time.Clock object and its tick() method to pause the loop for a few microseconds on every iteration. When the sound has stopped playing, the loop exits and the next file on the command line is played back or the script exits if there are no further files.

Update: I included two more functions that use the pygame.mixer.music module to play back a sound file streaming it from the disk rather than loading the whole sound into memory before playback. The first function, 'playmusic', uses a busy/poll loop, like the 'playsound' function. The second implementation, 'playmusic2', uses the event module to wait until the sound has finished playing. Since the second method has some drawbacks in this scenario (see docstrings), the first method is the default. You can switch to streaming mode by giving the '-s' option on the command line.

References:

pygame: http://pygame.org