I want to implement the following working code : async def main():
# Initialize PyAudio
p = pyaudio.PyAudio()
stream = None

# Create a container for the full audio data
full_audio_data = bytearray()

# Fetch audio data from edge_tts
communicate = edge_tts.Communicate(TEXT, VOICE)
async for chunk in communicate.stream():
if chunk[“type”] == “audio”:
# Directly append MP3 audio data
full_audio_data.extend(chunk[“data”])
elif chunk[“type”] == “WordBoundary”:
print(f"WordBoundary: {chunk}“)

if full_audio_data:
# Convert the full audio data from MP3 to WAV once
audio_segment = AudioSegment.from_file(BytesIO(full_audio_data), format=“mp3”)
raw_data = audio_segment.raw_data

# Open a single stream with the correct audio properties
stream = p.open(
format=p.get_format_from_width(audio_segment.sample_width),
channels=audio_segment.channels,
rate=audio_segment.frame_rate,
output=True
)

# Stream the audio
stream.write(raw_data)

# Stop and close the stream
stream.stop_stream()
stream.close()

# Terminate the PyAudio instance
p.terminate()

in this code :

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 text into segments of three words
text_words = text_to_read.split()
first_segment = " ".join(text_words[:1])
remaining_text = " ".join(text_words[1:])

# Split the remaining text by .!?
text_segments = re.split(r’[.!?]', remaining_text)
text_segments = [seg.strip() for seg in text_segments if seg.strip()]

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

await generator_task
await self.playback_queue.join() # Ensure all queued audio files have been played
playback_task.cancel() # Stop the playback loop

DO IT