from __future__ import annotations
import logging
import os
import time
from typing import Any, TYPE_CHECKING
import pygame
from nqp.core.constants import ASSET_PATH, INFINITE
from nqp.core.debug import Timer
if TYPE_CHECKING:
from typing import Dict, List, Optional, Tuple
from nqp.core.game import Game
__all__ = ["Audio"]
[docs]class Audio:
"""
The Audio Engine. It manages all sound interactions
"""
[docs] def __init__(self, game: Game):
with Timer("Audio: initialised"):
self._game: Game = game
self._sounds: Dict[str, pygame.mixer.Sound] = self._load_sounds()
self._unique_sounds: Dict[str, float] = {} # sounds that cant be duplicated. sound_name, remaining_duration
[docs] def update(self, delta_time: float):
# reduce timers in unique sounds
for sound_name, time_remaining in self._unique_sounds.items():
self._unique_sounds[sound_name] = time_remaining - delta_time
@staticmethod
def _load_sounds() -> Dict[str, pygame.mixer.Sound]:
"""
Load all sounds from /assets/sounds
"""
sounds = {}
sound_counter = 0
path = ASSET_PATH / "sounds"
for sound_name in os.listdir(path):
if sound_name.split(".")[-1] == "wav" or sound_name.split(".")[-1] == "mp3":
# avoid duplicates
if sound_name in sounds.keys():
logging.warning(f"{sound_name} already loaded, non-unique file name.")
sound = pygame.mixer.Sound(str(path / sound_name))
sounds[sound_name.split(".")[0]] = sound
sound_counter += 1
logging.debug(f"Audio: {sound_counter} Sounds loaded. ")
return sounds
[docs] def play_sound(
self,
sound_name: str,
loops: int = 0,
max_time: float = -1,
fade_in_ms: float = -1,
allow_duplicates: bool = True,
):
"""
Play sound.
Args:
sound_name: the name of the sound
loops: how many loops. set to INFINITE to make the sound loop infinitely. Can still be stopped.
max_time: how long the sound can play for. -1 means until end.
fade_in_ms: how long the sound will take to get to full volume. -1 means start at full.
allow_duplicates: when the same sound can be played while this is still active.
"""
# check if currently blocked as unique
if sound_name in self._unique_sounds.keys():
logging.debug(f"{sound_name} already playing as unique so not played again.")
try:
sound = self._sounds[sound_name]
# normalise values to pygame's expected defaults
if max_time == -1:
max_time = 0
if fade_in_ms == -1:
fade_in_ms = 0
if loops == INFINITE:
loops = -1
sound.play(loops, max_time, fade_in_ms)
if not allow_duplicates:
# get length
if max_time != 0:
duration = sound.get_length() * (1 + loops)
else:
duration = min(sound.get_length() * (1 + loops), max_time)
self._unique_sounds[sound_name] = duration
except KeyError:
logging.warning(f"Sound [{sound_name} not found.")