Skip to content

Commit

Permalink
New sound object
Browse files Browse the repository at this point in the history
Created a new sound object for playing songs / sound effects in the game Corderius-College-Amersfoort#13

e.g :

```
sound1 = play.new_sound(file_name="song.mp3", volume=1.0, loops=0)

sound1.play() # start sound
sound1.pause() # pause sound (.play() to unpause)
sound1.stop() # stops song, if .play() is used again it will restart the song
sound1.length_song() # returns the length of the song in seconds

.set_volume() and .get_volume() do as expected, both use floats

sound1.is_playing # checks if current song object is playing
```
  • Loading branch information
TJulesL committed Nov 30, 2024
1 parent ebf5473 commit 2ca3ee0
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
16 changes: 16 additions & 0 deletions play/api/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
Line as _Line,
Text as _Text,
Image as _Image,
Sound as _Sound,
)


Expand Down Expand Up @@ -185,3 +186,18 @@ def new_image( # pylint: disable=too-many-arguments
return _Image(
image=image, x=x, y=y, size=size, angle=angle, transparency=transparency
)


def new_sound( # pylint: disable=too-many-arguments
file_name: str = "file.mp3",
volume: float = 1.0,
loops: int = 0,
) -> _Sound:
"""
Initialize the Sound object.
:param file_name: The sound file to load (file path if not in the same directory as the .py).
:param volume: The initial volume (0.0 to 1.0).
:param loops: Number of times to loop the sound (-1 for infinite, 0 for no loop).
"""

return _Sound(file_name=file_name, volume=volume, loops=loops)
1 change: 1 addition & 0 deletions play/objects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
from .sprite import Sprite
from .text import Text
from .image import Image
from .sound import Sound
92 changes: 92 additions & 0 deletions play/objects/sound.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""Handles custom music/sound being played."""

import os
import pygame
from ..io.logging import play_logger as logger


class Sound:
def __init__(self, file_name, volume=1.0, loops=1):
"""
Initialize the Sound object.
:param file_name: The sound file to load.
:param volume: The initial volume (0.0 to 1.0).
:param loops: Number of times to loop the sound (-1 for infinite).
"""
pygame.mixer.init()
self.sound = None
self.channel = None
self.file_path = file_name
self.volume = volume
self.loops = loops
self.is_paused = False
self.load(file_name)
self.set_volume(volume)

def load(self, file_name):
"""Load a sound file."""
try:
self.sound = pygame.mixer.Sound(file_name)

except FileNotFoundError:
logger.error("File not found", exc_info=True)
logger.info(f"Loaded sound: {file_name}", exc_info=True)

def play(self):
"""Play the loaded sound with the specified loop settings, or resume a paused sound."""
if not self.sound:
logger.warning(
"No sound loaded. Use the 'load' method first.", exc_info=True
)

self.channel = pygame.mixer.find_channel()
if self.channel is None:
logger.warning("No available channels to play the sound.", exc_info=True)

if not self.is_playing():
self.channel.play(self.sound, loops=self.loops)
if self.is_paused:
self.channel.unpause()
self.is_paused = False

def pause(self):
"""Pause the sound."""
if self.channel.get_busy():
self.channel.pause()
self.is_paused = True


def length_song(self):
"""Returns the length of the song as a float"""

return round((self.channel.get_sound().get_length()), 2)

def stop(self):
"""Stop current channel"""
self.channel.stop()

def set_volume(self, volume):
"""Set the volume of the sound (0.0 to 1.0)."""
if not self.sound:
logger.warning(
"No sound loaded. Use the 'load' method first.", exc_info=True
)
if not (0.0 <= volume <= 1.0):
logger.warning("Volume must be between 0.0 and 1.0", exc_info=True)
self.volume = volume
self.sound.set_volume(volume)

def get_volume(self):
"""Get the current volume of the sound."""
if not self.sound:
logger.warning(
"No sound loaded. Use the 'load' method first.", exc_info=True
)
volume = self.sound.get_volume()
return volume

def is_playing(self):
"""Check if the sound is currently playing."""
if self.channel:
return self.channel.get_busy()
return False

0 comments on commit 2ca3ee0

Please sign in to comment.