Simple Pygame Sound at Frequency

How can I create a 440 Hz sound that plays smoothly forever using Pygame sound? I suppose this should be simple enough, but I don't want to use stupid files to complete the task. The ultimate goal of this is to play a note while the key is held, as I asked in another question. Any help would be greatly appreciated since I spent a lot of time searching for an answer to this question.

+6
source share
2 answers

What is 440 Hz sound? There are many types of waves at 440 Hz: sine, saw, square, etc. You can have a flute playing A, and that too can count.

Assuming you need a sine wave, it looks like you can create a sound object using pygame.sndarray.samples . (I have not tested this). You can create patterns with:

 samples = [math.sin(2.0 * math.pi * frequency * t / sample_rate) for t in xrange(0, duration_in_samples)] 

This, I hope, is the basic sinusoidal material. frequency - the desired frequency, Hz. sample_rate - the number of samples / sec in the generated sound: a typical value is 44100 Hz. duration_in_samples - audio length. (5 * 44100 == 5 seconds if your sound has a sampling frequency of 44100 Hz.)

It looks like you might have to convert the samples to numpy.array before moving on to pygame.sndarray.samples . The docs show that the sound should match the format returned by pygame.mixer.get_init , so configure the samples accordingly, but this is the main idea. ( mixer.get_init will tell you the sample_rate variable sample_rate and whether you need to consider stereo, and if you need to adjust the wave amplitude or shift it.)

Make samples an integer of wavelengths and it should loop.

+3
source

After getting too much “ValueError: The depth of the array should match the number of mixer channels” and other similar errors, I found this working example http://www.mail-archive.com/ pygame-users@seul.org /msg16140.html . It correctly generates a multidimensional 16-bit integer array that works with a stereo mixer. The minimum working example below is mainly taken from the previous link with the necessary pygame bits. In Python 2.7.2 with pygame.ver '1.9.1release.

In this example, a 440 Hz tone from one speaker and a 550 Hz tone from another speaker will be played in the stereo setting. After a short game with a duration, I found that audible clicks will appear in the sound loop if you set the “duration” variable to anything other than an integer.

 import pygame from pygame.locals import * import math import numpy size = (1366, 720) bits = 16 #the number of channels specified here is NOT #the channels talked about here http://www.pygame.org/docs/ref/mixer.html#pygame.mixer.get_num_channels pygame.mixer.pre_init(44100, -bits, 2) pygame.init() _display_surf = pygame.display.set_mode(size, pygame.HWSURFACE | pygame.DOUBLEBUF) duration = 1.0 # in seconds #freqency for the left speaker frequency_l = 440 #frequency for the right speaker frequency_r = 550 #this sounds totally different coming out of a laptop versus coming out of headphones sample_rate = 44100 n_samples = int(round(duration*sample_rate)) #setup our numpy array to handle 16 bit ints, which is what we set our mixer to expect with "bits" up above buf = numpy.zeros((n_samples, 2), dtype = numpy.int16) max_sample = 2**(bits - 1) - 1 for s in range(n_samples): t = float(s)/sample_rate # time in seconds #grab the x-coordinate of the sine wave at a given time, while constraining the sample to what our mixer is set to with "bits" buf[s][0] = int(round(max_sample*math.sin(2*math.pi*frequency_l*t))) # left buf[s][1] = int(round(max_sample*0.5*math.sin(2*math.pi*frequency_r*t))) # right sound = pygame.sndarray.make_sound(buf) #play once, then loop forever sound.play(loops = -1) #This will keep the sound playing forever, the quit event handling allows the pygame window to close without crashing _running = True while _running: for event in pygame.event.get(): if event.type == pygame.QUIT: _running = False break pygame.quit() 
+6
source

Source: https://habr.com/ru/post/899581/


All Articles