繁体   English   中英

如何在按下键时播放给定Hz的音调,并在释放时停止播放?

[英]How do I play a tone of a given Hz while a key is pressed AND stop playing it when it is released?

我找到了播放声音的代码:

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)

为了方便起见,我使用此方法:

def playSound(hz,ms):
    pre_init(44100, -16, 1, 1024)
    Note(hz).play(ms)

将-1设置为ms会无限播放声音。

我的问题是我无法控制声音何时停止。 我尝试在其上播放另一个听不见的频率,但是两者都可以同时播放。 关于在释放琴键后如何结束声音播放的任何想法?

您必须构建"mainloop"来定期检查密钥。

但是系统仅将按键事件发送到活动窗口,因此您必须创建窗口。

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()

编辑:显示按下键的示例。

顺便说一句:某些键盘发送的按键不超过4个。

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()

在此处输入图片说明

我在Cemetech询问并得到了以下解决方案:

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()

它似乎可以正常工作并且有多个注释。 感谢大家!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM