[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[pygame] Re: noob questions about creating and playing sounds



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<jjalocha@xxxxxxxxx> 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()