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.