I found this code for playing sounds:
from array import array # need a newline between normal text and code, edited to make it so
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)
I use this method to for convenience:
def playSound(hz,ms):
pre_init(44100, -16, 1, 1024)
Note(hz).play(ms)
Putting -1 for ms plays the sound infinitely.
My problem is that I have no way of controlling when the sound stops. I have tried playing another inaudible frequency over it, but both can play at the same time. Any ideas on how to end the playing of the sound upon releasing the key?
You have to build "mainloop"
to check keys periodically.
But system sends key events only to active window so you have to create window.
import pygame
import array
class Note(pygame.mixer.Sound):
def __init__(self, frequency, volume=.1):
self.frequency = frequency
pygame.mixer.Sound.__init__(self, self.build_samples())
self.set_volume(volume)
def build_samples(self):
period = int(round(pygame.mixer.get_init()[0] / self.frequency))
samples = array.array("h", [0] * period)
amplitude = 2 ** (abs(pygame.mixer.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__":
# --- init ---
pygame.mixer.pre_init(44100, -16, 1, 1024)
pygame.init()
screen = pygame.display.set_mode((100, 100))
# --- objects ---
tones = {
pygame.K_q: Note(440),
pygame.K_w: Note(340),
pygame.K_e: Note(540)
}
# --- mainloop ---
running = True
while running:
for event in pygame.event.get():
# closing window
if event.type == pygame.QUIT:
running = False
# pressing key
elif event.type == pygame.KEYDOWN:
if event.key in tones:
print('press:', event.key)
tones[event.key].play(-1)
# releasing key
elif event.type == pygame.KEYUP:
if event.key in tones:
print('release:', event.key)
tones[event.key].stop()
# --- end ---
pygame.quit()
EDIT: example which display pressed keys.
BTW: some keyboards don't send more then 4 pressed keys.
import pygame
import array
class Note(pygame.mixer.Sound):
def __init__(self, frequency, volume=.1):
self.frequency = frequency
pygame.mixer.Sound.__init__(self, self.build_samples())
self.set_volume(volume)
def build_samples(self):
period = int(round(pygame.mixer.get_init()[0] / self.frequency))
samples = array.array("h", [0] * period)
amplitude = 2 ** (abs(pygame.mixer.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__":
# --- init ---
pygame.mixer.pre_init(44100, -16, 1, 1024)
pygame.init()
screen = pygame.display.set_mode((110, 100))
# --- objects ---
keys = [
(pygame.K_q, 140),
(pygame.K_w, 240),
(pygame.K_e, 340),
(pygame.K_r, 440),
(pygame.K_t, 540),
]
tones = {}
pressed = {}
for key, val in keys:
tones[key] = Note(val)
pressed[key] = False
# --- mainloop ---
running = True
while running:
# - events -
for event in pygame.event.get():
# closing window
if event.type == pygame.QUIT:
running = False
# pressing key
elif event.type == pygame.KEYDOWN:
if event.key in tones:
#print('press:', event.key)
tones[event.key].play(-1)
pressed[event.key] = True
# releasing key
elif event.type == pygame.KEYUP:
if event.key in tones:
#print('release:', event.key)
tones[event.key].stop()
pressed[event.key] = False
# - draws -
# clear screen
screen.fill((0,0,0))
# draw pressed keys
for idx, key in enumerate(keys):
if key[0] in pressed and pressed[key[0]]:
x = 21*idx
pygame.draw.rect(screen, (255,255,255), (x, 0, 20, 50))
# send buffer on monitor
pygame.display.flip()
# --- end ---
pygame.quit()
I asked on Cemetech and got this solution:
from array import array
import pygame
from pygame.mixer import Sound, get_init, pre_init
class Note(pygame.mixer.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
pre_init(44100, -16, 1, 1024)
pygame.init()
screen = pygame.display.set_mode([640, 480], 0)
sounds = {}
keymap = {
pygame.K_z: 880,
pygame.K_x: 440
}
while True:
evt = pygame.event.wait()
if evt.type == pygame.QUIT:
break
elif evt.type == pygame.KEYDOWN:
if evt.key in keymap:
note = Note(keymap[evt.key])
note.play(-1)
sounds[evt.key] = note
elif evt.type == pygame.KEYUP:
if evt.key in sounds:
sounds.pop(evt.key).stop()
pygame.quit()
It seems to work correctly and for multiple notes. Thanks everyone!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.