Source code for serge.sound
"""The sound classes"""
import os
import pygame
import common
import serialize
import registry
import events
#
# Initialise the pygame sound subsystem
pygame.mixer.init()
pygame.mixer.set_num_channels(common.NUM_AUDIO_CHANNELS)
class UnknownSound(Exception): """The sound was not found"""
class BadSound(Exception): """Could not load sound from"""
class InvalidMusicFile(Exception): """The music file could not be played"""
[docs]class AudioRegistry(registry.GeneralStore, common.EventAware):
"""Registry for audio"""
def __init__(self):
"""Initialise the registry"""
super(AudioRegistry, self).__init__()
self._paused = False
self.initEvents()
self.playing = None
[docs] def play(self, name, loops=0):
"""Play a sound
:param name: the name of the sound to play
:param loops: the number of times to loop the sound (0=do not loop, -1=loop forever)
"""
self.getItem(name).play(loops)
self.playing = self.getItem(name)
[docs] def playSequence(self, sequence):
"""Play a sequence of sounds"""
#
# Play the first sound and then get its channel to use to play
# the other sounds in sequence
first = self.getItem(sequence[0])
first.play()
channel = first.getChannel()
#
if channel:
for name in sequence[1:]:
channel.queue(self.getItem(name).getSound())
[docs] def pause(self):
"""Pause all sounds"""
self._paused = True
if self.playing:
self.playing.pause()
[docs] def unpause(self):
"""Unpause all sounds"""
self._paused = False
if self.playing:
self.playing.unpause()
[docs] def toggle(self):
"""Toggle whether music or sound is playing or not"""
if self.isPaused():
self.unpause()
else:
self.pause()
[docs] def isPaused(self):
"""Return True if we are paused"""
return self._paused
[docs] def update(self, interval):
"""Update the registry looking for events
The method is called automatically by the engine.
"""
[docs] def isPlaying(self):
"""Return True if we are playing"""
class Store(AudioRegistry):
"""Stores sounds"""
def _registerItem(self, name, path):
"""Register the sound"""
#
# Load the sound
try:
sound = SoundItem(self._resolveFilename(path))
except Exception, err:
raise BadSound('Failed to load sound from "%s": %s' % (path, err))
#
# Remember the settings used to create the sound
self.raw_items.append([name, path])
self.items[name] = sound
return sound
def isPlaying(self):
"""Return True if we are playing"""
return pygame.mixer.get_busy()
[docs]class MusicStore(AudioRegistry):
"""Stores music"""
def __init__(self):
"""Initialise the store"""
super(MusicStore, self).__init__()
self._last_playing = None
self.playlist = None
def _registerItem(self, name, path):
"""Register the music"""
if not os.path.isfile(self._resolveFilename(path)):
raise BadSound('No music file "%s"' % self._resolveFilename(path))
#
# Remember the settings used to create the music
self.raw_items.append([name, path])
self.items[name] = MusicItem(self._resolveFilename(path))
return self.items[name]
[docs] def update(self, interval):
"""Update the registry looking for events
The method is called automatically by the engine.
"""
super(MusicStore, self).update(interval)
if not self.isPlaying() and self._last_playing:
self.processEvent((events.E_TRACK_ENDED, self))
#
# If playing a playlist then move to the next one
if self.playing and not self._paused and self.playlist:
new = self.playlist.pop(0)
self.play(new)
self.playlist.append(new)
#
self._last_playing = self.isPlaying()
[docs] def isPlaying(self):
"""Return True if we are playing"""
return pygame.mixer.music.get_busy()
[docs] def isPlayingSong(self, name):
"""Return True if the named song is playing
:param name: the name of the music item
"""
return self.playing == self.getItem(name)
[docs] def setPlaylist(self, item_list):
"""Set a playlist"""
current = item_list.pop(0)
item_list.append(current)
self.play(current)
self.playlist = item_list
[docs] def fadeout(self, time):
"""Fadeout the currently playing track
:param time: the time over which the music fades out in seconds (0=immediate)
"""
pygame.mixer.music.fadeout(int(time))
self.playing = False
[docs] def setVolume(self, volume):
"""Set the volume
:param volume: the volume of the music (0=silent, 1=full volume)
"""
pygame.mixer.music.set_volume(volume)
[docs] def getVolume(self):
"""Returns the volume (0=silent, 1=full volume)"""
return pygame.mixer.music.get_volume()
[docs]class MusicItem(object):
"""Represents a music item"""
def __init__(self, path):
"""Initialise the piece of music"""
self._path = path
self._paused = False
[docs] def play(self, loops=0):
"""Play the music
:param loops: the number of times to loop the music (0=do not loop, -1=loop forever)
"""
pygame.mixer.music.stop()
try:
pygame.mixer.music.load(self._path)
except Exception, err:
raise InvalidMusicFile('Unable to play music file "%s": %s' % (self._path, err))
#
Music.playing = self
self._paused = False
if not Music.isPaused():
pygame.mixer.music.play(loops)
return True
else:
return False
[docs] def pause(self):
"""Pause the music"""
pygame.mixer.music.pause()
self._paused = True
[docs] def unpause(self):
"""Pause the music"""
if Music.playing == self and self._paused:
pygame.mixer.music.unpause()
else:
pygame.mixer.music.play()
[docs] def stop(self):
"""Stop the music"""
pygame.mixer.music.stop()
Music.playing = None
self._paused = False
[docs]class SoundItem(object):
"""Represents a sound item
:param path: the path to the sound file
"""
def __init__(self, path=None, sound=None):
"""Initialise the sound"""
if path:
self._sound = pygame.mixer.Sound(path)
else:
self._sound = sound
self._channel = None
[docs] def play(self, loops=0):
"""Play the music
:param loops: the number of times to loop the sound (0=do not loop, -1=loop forever)
"""
if not Sounds.isPaused():
self._channel = self._sound.play(loops)
return True
return False
[docs] def pause(self):
"""Pause the sound"""
self._sound.stop()
[docs] def unpause(self):
"""Pause the sound"""
self._sound.play()
[docs] def stop(self):
"""Stop the sound"""
self._sound.stop()
[docs] def set_volume(self, volume):
"""Set the volume of the sound
:param volume: the volume of the sound (0=silent, 1=full volume)
"""
self._sound.set_volume(volume)
[docs] def get_volume(self):
"""Return the volume that the sound is playing at (0=silent, 1=full volume)"""
return self._sound.get_volume()
[docs] def fadeout(self, time):
"""Fadeout the sound
:param time: the time over which the sound fades out in seconds (0=immediate)
"""
self._sound.fadeout(time)
[docs] def isPlaying(self):
"""Return True if the sound is currently playing"""
if self._channel and self._channel.get_busy():
return True
else:
return False
[docs] def getSound(self):
"""Return the underlying pygame sound object"""
return self._sound
[docs] def getChannel(self):
"""Return the underlying pygame channel object"""
return self._channel
Sounds = Store()
Music = MusicStore()