Source code for albow.music

# ---------------------------------------------------------------------------
#
#   Albow - Music
#
#---------------------------------------------------------------------------

from __future__ import division
import os
from random import randrange

try:
    from pygame.mixer import music
except ImportError:
    music = None
    print "Music not available"

if music:
    import root

    music.set_endevent(root.MUSIC_END_EVENT)

from resource import resource_path
from root import schedule

#---------------------------------------------------------------------------

fadeout_time = 1  # Time over which to fade out music (sec)
change_delay = 2  # Delay between end of one item and starting the next (sec)

#---------------------------------------------------------------------------

music_enabled = True
current_music = None
current_playlist = None
next_change_delay = 0

#---------------------------------------------------------------------------


[docs]class PlayList(object): """A collection of music filenames to be played sequentially or randomly. If random is true, items will be played in a random order. If repeat is true, the list will be repeated indefinitely, otherwise each item will only be played once.""" def __init__(self, items, random=False, repeat=False): self.items = list(items) self.random = random self.repeat = repeat
[docs] def next(self): """Returns the next item to be played.""" items = self.items if items: if self.random: n = len(items) if self.repeat: n = (n + 1) // 2 i = randrange(n) else: i = 0 item = items.pop(i) if self.repeat: items.append(item) return item #---------------------------------------------------------------------------
[docs]def get_music(*names, **kwds): """Return the full pathname of a music file from the "music" resource subdirectory.""" prefix = kwds.pop('prefix', "music") return resource_path(prefix, *names)
[docs]def get_playlist(*names, **kwds): prefix = kwds.pop('prefix', "music") dirpath = get_music(*names, **{'prefix': prefix}) items = [os.path.join(dirpath, filename) for filename in os.listdir(dirpath) if not filename.startswith(".")] items.sort() return PlayList(items, **kwds)
[docs]def change_playlist(new_playlist): """Fade out any currently playing music and start playing from the given playlist.""" #print "albow.music: change_playlist" ### global current_music, current_playlist, next_change_delay if music and new_playlist is not current_playlist: current_playlist = new_playlist if music_enabled: music.fadeout(fadeout_time * 1000) next_change_delay = max(0, change_delay - fadeout_time) jog_music() else: current_music = None
[docs]def change_music(new_music, repeat=False): """Fade out any currently playing music and start playing the given music file.""" #print "albow.music: change_music" ### if music and new_music is not current_music: if new_music: new_playlist = PlayList([new_music], repeat=repeat) else: new_playlist = None change_playlist(new_playlist)
[docs]def music_end(): #print "albow.music: music_end" ### schedule(next_change_delay, jog_music)
[docs]def jog_music(): """If no music is currently playing, start playing the next item from the current playlist.""" if music_enabled and not music.get_busy(): start_next_music()
[docs]def start_next_music(): """Start playing the next item from the current playlist immediately.""" #print "albow.music: start_next_music" ### global current_music, next_change_delay if music_enabled and current_playlist: next_music = current_playlist.next() if next_music: print "albow.music: loading", repr(next_music) ### music.load(next_music) music.play() next_change_delay = change_delay current_music = next_music
[docs]def get_music_enabled(): return music_enabled
[docs]def set_music_enabled(state): global music_enabled if music_enabled != state: music_enabled = state if state: # Music pausing doesn't always seem to work. #music.unpause() if current_music: # After stopping and restarting currently loaded music, # fadeout no longer works. #print "albow.music: reloading", repr(current_music) ### music.load(current_music) music.play() else: jog_music() else: #music.pause() music.stop() #---------------------------------------------------------------------------
from pygame import Rect from albow.widget import Widget from albow.controls import Label, Button, CheckBox from albow.layout import Row, Column, Grid from albow.dialogs import Dialog
[docs]class EnableMusicControl(CheckBox):
[docs] def get_value(self): return get_music_enabled()
[docs] def set_value(self, x): set_music_enabled(x)
[docs]class MusicVolumeControl(Widget): def __init__(self, **kwds): Widget.__init__(self, Rect((0, 0), (100, 20)), **kwds)
[docs] def draw(self, surf): r = self.get_margin_rect() r.width = int(round(music.get_volume() * r.width)) surf.fill(self.fg_color, r)
[docs] def mouse_down(self, e): self.mouse_drag(e)
[docs] def mouse_drag(self, e): m = self.margin w = self.width - 2 * m x = max(0.0, min(1.0, (e.local[0] - m) / w)) music.set_volume(x) self.invalidate()
[docs]class MusicOptionsDialog(Dialog): def __init__(self): Dialog.__init__(self) emc = EnableMusicControl() mvc = MusicVolumeControl() controls = Grid([ [Label("Enable Music"), emc], [Label("Music Volume"), mvc], ]) buttons = Button("OK", self.ok) contents = Column([controls, buttons], align='r', spacing=20) contents.topleft = (20, 20) self.add(contents) self.shrink_wrap()
[docs]def show_music_options_dialog(): dlog = MusicOptionsDialog() dlog.present()