There is a problem at await self.playback_queue.join() that make the play function running indefinetly, diagnonise it, fix it.

#!/usr/bin/env python3

"""
Basic example of edge_tts usage.
"""

import asyncio
import os
import re
import time
import uuid
import pygame
import edge_tts

TEXT = "Assurez-vous toujours de la bonne réputation de votre tailleur. Il n'y a rien de pire que de se retrouver avec un pantalon déchiré au beau milieu de nulle part !|Toto|male|message"

class WoWTTS:
FIRST_OVERLAP_MS = -1000
OVERLAP_MS = 800
MALE_VOICES = {
"fr-FR-RemyMultilingualNeural",
"fr-BE-GerardNeural",
"fr-FR-HenriNeural",
"fr-CH-FabriceNeural"
#"fr-CA-AntoineNeural"
}
FEMALE_VOICES = {
"fr-FR-VivienneMultilingualNeural",
"fr-BE-CharlineNeural",
"fr-FR-DeniseNeural",
"fr-CH-ArianeNeural",
"fr-CA-SylvieNeural"
}




RACES_PITCH = {
    'humanoïde': (-30, 20),
    'elf': (-15, 15),
    'dwarf': (-30, 10),
    'orc': (-40, -20)
    # Add more races and their corresponding pitch ranges as needed
}
def __init__(self):        
    self.playback_queue = asyncio.Queue()
    pygame.mixer.init()

async def generate_tts_audio(self, text_segments, voice, formatted_pitch):
    for segment in text_segments:
        unique_id = str(uuid.uuid4())
        file_name = f"{unique_id}.mp3"
        
        communicate = edge_tts.Communicate(segment, voice, pitch=formatted_pitch)
        await communicate.save(file_name)
        
        await self.playback_queue.put(file_name)

async def playback_loop(self):
    index = 0
    pygame.mixer.init()  # Ensure pygame mixer is initialized
    while True:
        print(index)
        file_name = await self.playback_queue.get()
        sound = pygame.mixer.Sound(file_name)
        sound.play()

        length_ms = sound.get_length() * 1000
        if index == 0:
            # Calculate wait_time considering negative overlap for the first sound
            if WoWTTS.FIRST_OVERLAP_MS < 0:
                # Play next sound x ms before the current sound ends
                wait_time = length_ms + WoWTTS.FIRST_OVERLAP_MS
            else:
                wait_time = length_ms - WoWTTS.FIRST_OVERLAP_MS
        else:
            # Calculate wait_time for subsequent sounds
            if WoWTTS.OVERLAP_MS < 0:
                # Play next sound x ms before the current sound ends
                wait_time = length_ms + WoWTTS.OVERLAP_MS
            else:
                wait_time = length_ms - WoWTTS.OVERLAP_MS
        
        wait_time = max(wait_time, 0) / 1000.0  # Ensure wait_time is not negative and convert to seconds

        index += 1

        await asyncio.sleep(wait_time)

        os.remove(file_name)
        self.playback_queue.task_done()  # Mark the task as done after playback

async def play(self, text_to_read, npc_sex, npc_race, pitch_index, voice_index, voice_effect):
    voice = self.get_voice_from_index_and_sex(voice_index, npc_sex)        
    pitch = self.get_pitch_from_index_and_race(pitch_index, npc_race)
    formatted_pitch = self.format_pitch(pitch)
    
    # Split the remaining text by .!?
    text_segments = re.split(r'[.!?,]', text_to_read)
    text_segments = [seg.strip() for seg in text_segments if seg.strip()]

    print("Voice : " + voice)

    # Combine the first segment with the rest of the text segments
    #text_segments.insert(0, first_segment)

    generator_task = asyncio.create_task(self.generate_tts_audio(text_segments, voice, formatted_pitch))
    playback_task = asyncio.create_task(self.playback_loop())

    print("woot1")
    await generator_task
    print("woot2")
    await self.playback_queue.join()  # Ensure all queued audio files have been played
    print("woot3")
    playback_task.cancel()  # Stop the playback loop
    print("woot4")
    

def get_voice_from_index_and_sex(self, voice_index, npc_sex):
    voices = WoWTTS.MALE_VOICES if npc_sex.lower() == 'male' else WoWTTS.FEMALE_VOICES
    voice_list = sorted(list(voices))
    index = int(voice_index * (len(voice_list) - 1))
    return voice_list[index]

def get_pitch_from_index_and_race(self, pitch_index, npc_race):
    pitch_range = WoWTTS.RACES_PITCH.get(npc_race, (0, 0))
    min_pitch, max_pitch = pitch_range
    pitch = min_pitch + pitch_index * (max_pitch - min_pitch)
    return pitch

def format_pitch(self, pitch):
    return f"{pitch:+.0f}Hz"
if name == 'main':
# Example usage
WoWTTS = WoWTTS()




async def main():
    await WoWTTS.play("Savez-vous, Brahim, qu'il n'y a rien de pire que de se retrouver avec un pantalon déchiré au beau milieu de nulle part !. Bonjour ! Assurez-vous toujours de la bonne réputation de votre tailleur. Il n'y a rien de pire que de se retrouver avec un pantalon déchiré au beau milieu de nulle part !", 'male', 'humanoïde', 0, 0.5, None)
    await WoWTTS.play("Bonjour ! Ça va bien !", 'male', 'orc', 0.5, 0.8, None)
    await WoWTTS.play("Bonjour ! Ça va bien !", 'male', 'orc', 0.5, 0.8, None)
    await WoWTTS.play("Bonjour ! Ça va bien !", 'male', 'orc', 0.5, 0.8, None)
    await WoWTTS.play("Bonjour ! Ça va bien !", 'male', 'orc', 0.5, 0.8, None)
    await WoWTTS.play("Bonjour ! Ça va bien !", 'male', 'orc', 0.5, 0.8, None)
    await WoWTTS.play("Bonjour ! Ça va bien !", 'male', 'orc', 0.5, 0.8, None)

# Run the main function in the event loop
asyncio.run(main())