Python 如何使用pygame按顺序运行声音循环?

Python 如何使用pygame按顺序运行声音循环?,python,python-3.x,audio,tkinter,pygame,Python,Python 3.x,Audio,Tkinter,Pygame,我一直在试验前几天我得到的一个奇怪的想法,我想知道是否有人知道解决我遇到的问题的方法 所以,我想做的是一个声音的串联,循环一个随机的次数,然后移动到下一个声音,再循环一个随机的次数,然后移动到下一个,然后继续这样做,比如说,100个其他声音 这就像一个预先确定的声音列表,以固定的顺序激活,但每个声音都有一个“循环”变量,它本质上是两个数字之间的一个随机整数,决定了在进入下一个数字之前声音循环的次数 我制作这个动画是因为我不善于解释事情 我知道这听起来很愚蠢,毫无意义,有点疯狂,但正如我所说,这

我一直在试验前几天我得到的一个奇怪的想法,我想知道是否有人知道解决我遇到的问题的方法

所以,我想做的是一个声音的串联,循环一个随机的次数,然后移动到下一个声音,再循环一个随机的次数,然后移动到下一个,然后继续这样做,比如说,100个其他声音

这就像一个预先确定的声音列表,以固定的顺序激活,但每个声音都有一个“循环”变量,它本质上是两个数字之间的一个随机整数,决定了在进入下一个数字之前声音循环的次数

我制作这个动画是因为我不善于解释事情

我知道这听起来很愚蠢,毫无意义,有点疯狂,但正如我所说,这是一个实验

这似乎很容易,所以我尝试了以下方法:

(顺便说一句,我正在使用Tkinter和pygame)

但问题是pygame不会等待每个循环结束,它会同时播放每个声音

然后,我突然想到,使用“For循环”可能会解决这个问题,可能类似于这样,但声音:

def activate():
    randomnumber1 = randint(0, 3)
    for i in range(randomnumber1):
        print(1)

    randomnumber2 = randint(0, 3)
    for i in range(randomnumber2):
        print(2)

    randomnumber3 = randint(0, 3)
    for i in range(randomnumber3):
        print(3)

    randomnumber4 = randint(0, 3)
    for i in range(randomnumber4):
        print(4)
像这样:

def activate():
    randomnumber1 = randint(0, 3)
    for i in range(randomnumber1):
        sound1 = pygame.mixer.Sound("sound2.wav")
        pygame.mixer.Sound.play(sound1)

    randomnumber2 = randint(0, 3)
    for i in range(randomnumber2):
        sound2 = pygame.mixer.Sound("sound3.wav")
        pygame.mixer.Sound.play(sound2)

    randomnumber3 = randint(0, 3)
    for i in range(randomnumber3):
        sound3 = pygame.mixer.Sound("sound4.wav")
        pygame.mixer.Sound.play(sound3)

    randomnumber4 = randint(0, 3)
    for i in range(randomnumber4):
        sound4 = pygame.mixer.Sound("sound5.wav")
        pygame.mixer.Sound.play(sound4)
但是没有起作用

然后我想起winsound是同步运行的,据我所知,您无法指定声音循环的次数,因此我尝试:

def activate():
    randomnumber1 = randint(0, 3)
    for i in range(randomnumber1):
        winsound.PlaySound("sound2.wav", winsound.SND_ASYNC)

    randomnumber2 = randint(0, 3)
    for i in range(randomnumber2):
        winsound.PlaySound("sound3.wav", winsound.SND_ASYNC)

    randomnumber3 = randint(0, 3)
    for i in range(randomnumber3):
        winsound.PlaySound("sound4.wav", winsound.SND_ASYNC)

    randomnumber4 = randint(0, 3)
    for i in range(randomnumber4):
        winsound.PlaySound("sound5.wav", winsound.SND_ASYNC)
但它也不起作用

现在我在胡闹时间。睡眠,因为每个声音都有一个特定的持续时间,我想我可以计算出每个循环必须等待的时间

像这样,也许:

sound2.wav持续1.5s,所以假设随机数为2,即1.5s声音片段的2个循环

2*1.5s=3s

random_number_1 = randint(0, 3)
    sound1 = pygame.mixer.Sound("sound2.wav")
    pygame.mixer.Sound.play(sound1, random_number_1)
    time.sleep(random_number_1*1.5)
但到目前为止,这一切都非常不稳定、混乱和怪异,而事实上,时间冻结意味着它对我几乎毫无用处


总而言之。。。如果您知道一种使pygame声音同步运行的方法,或者有一种更简单的解决方案,我没有看到,请告诉我

一种简单的方法是使用
pygame.mixer.Channel()
函数
set\u endevent()

channel2 = pygame.mixer.Channel(1)
channel2.set_endevent( pygame.USEREVENT+1 )
当声音停止播放时,这将发送您指定的事件队列(此处
pygame.USEREVENT+1

我做了一个快速演示示例。它播放一个长背景音,然后连续播放一个随机短音。当收到
pygame.USEREVENT+1
事件时,会立即启动新的声音

import pygame
import random

# Window size
WINDOW_WIDTH    = 400
WINDOW_HEIGHT   = 400
WINDOW_SURFACE  = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE

DARK_BLUE = (   3,   5,  54)

### initialisation
pygame.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
pygame.display.set_caption("Random Sound")

### sound
# create separate Channel objects for simultaneous playback
channel1 = pygame.mixer.Channel(0) # argument must be int
channel2 = pygame.mixer.Channel(1)

# define the event that's sent when a sound stops playing:
channel2.set_endevent( pygame.USEREVENT+1 )

# Rain sound from: https://www.freesoundslibrary.com/sound-of-rain-falling-mp3/ (CC BY 4.0)
rain_sound = pygame.mixer.Sound( 'rain-falling.ogg' )
channel1.play( rain_sound, -1 )   # loop the rain sound forever
# and ...  All are (CC BY 4.0)
# https://www.freesoundslibrary.com/car-horn-sound-effect/
# https://www.freesoundslibrary.com/duck-quack/ 
# https://www.freesoundslibrary.com/cash-register-sound-effect/
# https://www.freesoundslibrary.com/turkey-gobble-call/
# https://www.freesoundslibrary.com/single-ding-sound-effect/
# https://www.freesoundslibrary.com/dog-bark-sound-effect/
# 
horn     = pygame.mixer.Sound( 'car-horn2.ogg' )      # converted from MP3 to OGG
quack    = pygame.mixer.Sound( 'duck-quack.ogg' )
ca_ching = pygame.mixer.Sound( 'cash-register.ogg' )
bark     = pygame.mixer.Sound( 'dog-bark.ogg' )
ding     = pygame.mixer.Sound( 'single-ding.ogg' )
gobble   = pygame.mixer.Sound( 'turkey-gobble.ogg' )

# Sound list
all_sounds = [ horn, quack, ca_ching, bark, ding, gobble ]
# Start with a random sound
channel2.play( random.choice( all_sounds ) )

### Main Loop
clock = pygame.time.Clock()
done = False
while not done:

    # Handle user-input
    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True
        elif ( event.type == pygame.USEREVENT+1 ):
            # Channel2 sound ended, start another!
            channel2.play( random.choice( all_sounds ) )
            print( "Sound ended" )

    # Update the window, but not more than 60fps
    window.fill( DARK_BLUE )
    pygame.display.flip()

    # Clamp FPS
    clock.tick_busy_loop(60)

pygame.quit()
freesoundslibrary.com上的很多声音都很长(例如:多个鸭子叫声)。我用这个工具把它们剪成短促的声音,在两边留下一瞬间的安静

编辑: 要将其更改为预先确定的列表,只需保留当前_声音的记录

# Sound list
all_sounds = [ horn, quack, ca_ching, bark, ding, gobble ]
# Start with the first sound
channel2.play( all_sounds[ 0 ] )
current_sound_index = 0

...

    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True
        elif ( event.type == pygame.USEREVENT+1 ):
            # Channel2 sound ended, start the next sound!
            current_sound_index += 1
            if ( current_sound_index < len( all_sounds ) ):
                channel2.play( all_sounds[ current_sound_index ] )
                print( "Sound ended" )
            else:
                print( "Played all sounds" )
#声音列表
所有声音=[喇叭、嘎嘎声、嘎吱声、吠声、叮当声、狼吞虎咽声]
#从第一个声音开始
通道2.播放(所有声音[0])
当前声音索引=0
...
对于pygame.event.get()中的事件:
如果(event.type==pygame.QUIT):
完成=正确
elif(event.type==pygame.USEREVENT+1):
#通道2声音结束,开始下一个声音!
当前声音指数+=1
如果(当前声音索引
哇,非常感谢你,金斯利,这真是太有洞察力了。我很抱歉在我最初的帖子中说得不够清楚,但我想做的是一个“预先确定”的声音列表,其中每个声音循环基于一个随机间隔,该间隔与当时播放的声音相关,但你的回答给了我一些尝试的想法。我在原来的帖子中添加了一个小动画,旁边还有一个更清晰的解释,因为我在解释事情方面太糟糕了。再次感谢你,如果我误解了你的答案,我道歉(我不是真正的程序员)不用担心,很高兴我能帮上忙。要使上面的示例播放预先确定的列表,只需保留一条记录,记录从
所有声音中播放的声音索引,然后播放下一个,而不是随机播放。@Austin.W-请参见编辑。这有点接近你需要的。我想从这一点上你可以很容易地计算出随机的比赛时间。嗯,我非常感谢你@Kingsley,我真的很感激你。现在我正在尝试实现“循环随机化器”,我相信我最终会找到答案的
# Sound list
all_sounds = [ horn, quack, ca_ching, bark, ding, gobble ]
# Start with the first sound
channel2.play( all_sounds[ 0 ] )
current_sound_index = 0

...

    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True
        elif ( event.type == pygame.USEREVENT+1 ):
            # Channel2 sound ended, start the next sound!
            current_sound_index += 1
            if ( current_sound_index < len( all_sounds ) ):
                channel2.play( all_sounds[ current_sound_index ] )
                print( "Sound ended" )
            else:
                print( "Played all sounds" )