-
-
Save ohsqueezy/6540433 to your computer and use it in GitHub Desktop.
# 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) |
you meant line 18
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'
to work, change:
Sound.init(self, buffer=self.build_samples())
to:
pygame.mixer.Sound.init(self, buffer=self.build_samples())
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.
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.
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 ) )
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.
Current pygame needs to change line 28 to
Sound.init(self, buffer=self.build_samples())