Quick answer: Call set_endevent on the Channel object returned by Sound.play() — not on the Sound. Then look for that event type in your event loop.
Code wants to know when a voice line finishes so the next can play. set_endevent was called but the event never appears in the queue.
Capture the Channel
VOICE_END = pygame.USEREVENT + 3
channel = voice_clip.play() # play() returns the Channel
channel.set_endevent(VOICE_END) # set it on THAT channel
Sound.play() returns the Channel it grabbed (or None if all channels are busy). The endevent is a per-channel setting — setting it on the Sound does nothing.
Handle None
If every channel is busy, play() returns None. Guard for it — calling set_endevent on None throws. Either reserve a channel for voice or raise set_num_channels.
Poll for the Event
for event in pygame.event.get():
if event.type == VOICE_END:
play_next_voice_line()
The endevent posts to the normal event queue when that channel goes idle — including when the sound is stopped, not just when it ends naturally.
Reserve a Voice Channel
pygame.mixer.set_reserved(1)
voice_channel = pygame.mixer.Channel(0)
voice_channel.set_endevent(VOICE_END)
voice_channel.play(voice_clip)
A dedicated channel means the endevent is always wired to the same channel — no “which channel did I get” uncertainty.
Verifying
A voice line finishes, VOICE_END fires once, the next line plays. Stopping the channel early also fires it — handle that as “done” too.
“End events are per-Channel. Capture the channel from play(), set the event on it.”
A reserved channel per audio role (voice, music, UI) makes endevents and stop logic far easier to reason about.