I finally used the ossaudiodev module from the Python standard library, because I was unable to play a noise-free sound using pygame.mixer.Sound. OSS is not portable, but at least, it should make it easy to process in real-time.
The full working code is attached as a reference for other people with similar needs. This code example was adapted from the following source: http://www.google.com/codesearch/p#dOPNNT5w2nY/svn/collective/funittest/trunk/doc/src/soundout.py On Mon, Jul 20, 2009 at 9:44 AM, Jerzy Jalocha N<jjalo...@gmail.com> wrote: > Hi, I am starting to experiment with Pygame and how to generate sounds > and play them back. Here is a code snippet, the full (working) code is > below. > > def play_maxtime(sound, duration): > sound.play(loops=-1, maxtime=duration) > pygame.time.delay(duration) > > I have a few questions about this: > > * Why is it that play_maxtime doesn't work without the time.delay? > When I remove the delay line, no sound is played, despite the use of > the maxtime argument. > > * Why does this sound so ugly? This method (and play_loops below) > produces a terrible rattle, regardless the sample-rate. (Note, that I > am using 16 bit, which should produce at least decent quality. And it > is not clipping.) > > * Anyone knows how to create the sound in real-time, and feed it to > the sound card? For example, make the frequency depend on the mouse > position. > > Since it is quite difficult to find information and examples about how > to create and play back sounds in Python and Pygame, I am posting the > complete working example below, for reference. Maybe other noobs might > find it useful. This code was adapted from a post on other mailing > list: http://mail.python.org/pipermail/tutor/2009-March/067724.html > > > import numpy > import pygame > > # Create the sound wave in the required bit-rate. > def sine_array(freq, amplitude, sample_rate): > wavelength = sample_rate / freq > omega = 2 * numpy.pi / wavelength > xvalues = numpy.arange(wavelength) * omega > return numpy.int16(amplitude * numpy.sin(xvalues)) > > # Two different methods for playing the sound. > def play_maxtime(sound, duration): > sound.play(loops=-1, maxtime=duration) > pygame.time.delay(duration) > > def play_loops(sound, duration): > sound.play(loops=-1) > pygame.time.delay(duration) > sound.stop() > > # Initialize PyGame & PyGame sound system. > sample_rate, bit_rate, channels = 22050, -16, 1 > pygame.mixer.pre_init(sample_rate, bit_rate, channels) > pygame.init() > sample_rate, bit_rate, channels = pygame.mixer.get_init() > assert bit_rate == -16 # sine_array only implements 16 bit signed > pygame.sndarray.use_arraytype('numpy') > > # Create a sound array, and convert it to a Sound object. > sound_array = sine_array(440, 20000, sample_rate) > sound = pygame.sndarray.make_sound(sound_array) > > # Play the sound using two different methods. > duration = 2000 > play_maxtime(sound, duration) > pygame.time.delay(duration) > play_loops(sound, duration) >
#! /usr/bin/env python import math import struct from cStringIO import StringIO import ossaudiodev as oss # Initialize OSS sound system. device = oss.open('/dev/dsp', 'w') bitrate, channels, samplerate = device.setparameters(oss.AFMT_S16_LE, 1, 22050) assert channels == 1 assert bitrate == 16 # Only 16 bit implemented below # Create sound. pitch = 440 # Hz duration = 1 # s sound_buffer = StringIO() nsamples = int(samplerate * duration) omega = 2.0 * math.pi * pitch / samplerate for n in xrange(nsamples): sample = math.sin(omega * n) value = int(sample * 32767) # 2**16 / 2 - 1 data = struct.pack('<h', value) # short (signed) sound_buffer.write(data) # Play back. device.write(sound_buffer.getvalue()) device.close()