Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Play a 440 Hz tone in Pygame
# Generate a 440 Hz square waveform in Pygame by building an array of samples and play
# it for 5 seconds. Change the hard-coded 440 to another value to generate a different
# pitch.
#
# Run with the following command:
# python pygame-play-tone.py
from array import array
from time import sleep
import pygame
from pygame.mixer import Sound, get_init, pre_init
class Note(Sound):
def __init__(self, frequency, volume=.1):
self.frequency = frequency
Sound.__init__(self, self.build_samples())
self.set_volume(volume)
def build_samples(self):
period = int(round(get_init()[0] / self.frequency))
samples = array("h", [0] * period)
amplitude = 2 ** (abs(get_init()[1]) - 1) - 1
for time in range(period):
if time < period / 2:
samples[time] = amplitude
else:
samples[time] = -amplitude
return samples
if __name__ == "__main__":
pre_init(44100, -16, 1, 1024)
pygame.init()
Note(440).play(-1)
sleep(5)
@solarmist

This comment has been minimized.

Copy link

@solarmist solarmist commented Sep 11, 2014

Current pygame needs to change line 28 to
Sound.init(self, buffer=self.build_samples())

@revolunet

This comment has been minimized.

Copy link

@revolunet revolunet commented Dec 16, 2014

you meant line 18

@jolespin

This comment has been minimized.

Copy link

@jolespin jolespin commented Jan 24, 2016

i can't get this to work :/
File "synesthesia.py", line 24, in init
Sound.init(self, buffer=self.build_samples())
AttributeError: type object 'Sound' has no attribute 'init'

@talespadua

This comment has been minimized.

Copy link

@talespadua talespadua commented May 25, 2016

to work, change:
Sound.init(self, buffer=self.build_samples())
to:
pygame.mixer.Sound.init(self, buffer=self.build_samples())

@GeorgeInNC

This comment has been minimized.

Copy link

@GeorgeInNC GeorgeInNC commented Nov 14, 2016

I've tried all the variations proposed and none of them have worked for me. I'm on a Raspberry Pi 3 using Python 3.4.2.

@danellisuk

This comment has been minimized.

Copy link

@danellisuk danellisuk commented Mar 18, 2017

If you are using python3, change xrange to range. This is all that I needed to change for this to work on my Raspberry Pi 3.

@JetStarBlues

This comment has been minimized.

Copy link

@JetStarBlues JetStarBlues commented Jun 24, 2017

As per this answer on StackOverflow, if the snippet doesn't work and you are running it on Windows, the problem might be the need for a screen on Windows. Creating a screen as follows before the call to Note() resolved it for me,

pygame.display.set_mode( ( screen_width, screen_height ) )
@Sitin

This comment has been minimized.

Copy link

@Sitin Sitin commented Oct 2, 2017

This snippet won't produce a sine wave but rather a square wave (which sounds much sharper). For the sine wave replace build_samples with something like:

def build_samples(self):
    sample_rate = pygame.mixer.get_init()[0]
    period = int(round(sample_rate / self.frequency))
    amplitude = 2 ** (abs(pygame.mixer.get_init()[1]) - 1) - 1

    def frame_value(i):
        return amplitude * numpy.sin(2.0 * numpy.pi * frequency * i / sample_rate)

    return numpy.array([frame_value(x) for x in range(0, period)]).astype(numpy.int16)

Or use a simpler approach without inheriting Sound class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment