Changeset - 1a34a0e118cc
[Not reviewed]
default
0 1 0
Drew Perttula - 19 years ago 2006-06-19 00:29:36
drewp@bigasterisk.com
ascoltami: new 'go' button that does the Right Thing during a show
1 file changed with 106 insertions and 42 deletions:
0 comments (0 inline, 0 general)
bin/ascoltami
Show inline comments
 
@@ -34,12 +34,20 @@ import run_local
 
from light9 import networking, showconfig, wavelength
 

	
 
from pympd import Mpd
 

	
 
appstyle={'fg':'white','bg':'black'}
 

	
 
def shortSongPath(song, all):
 
    prefixlen = len(os.path.commonprefix(all))
 
    # include to the last os.sep- dont crop path elements in the middle
 
    prefixlen = all[0].rfind(os.sep)+1 
 

	
 
    return os.path.splitext(song[prefixlen:])[0]
 
    
 

	
 
class XMLRPCServe(xmlrpc.XMLRPC):
 
    def __init__(self,player):
 
        xmlrpc.XMLRPC.__init__(self)
 
        self.player=player
 

	
 
    def xmlrpc_echo(self,x):
 
@@ -78,13 +86,13 @@ class XMLRPCServe(xmlrpc.XMLRPC):
 
class Player:
 
    """semprini-style access to mpd. in here is where we add the
 
    padding"""
 

	
 
    song_pad_time = 10
 
    
 
    def __init__(self, app, playlist, media=None):
 
    def __init__(self):
 

	
 
        self.mpd = Mpd()
 
        reactor.connectTCP(*(networking.mpdServer()+(self.mpd,)))
 

	
 
        self.state = tk.StringVar()
 
        self.state.set("stop") # 'stop' 'pause' 'play'
 
@@ -194,12 +202,15 @@ class Player:
 
        elif time > self.total_time.get():
 
            self.mpd.seek(seconds=time - self.total_time.get(), song=2)
 
        else:
 
            self.mpd.seek(seconds=time, song=1)
 
        self.last_autopause_time = time
 

	
 
    def in_post(self):
 
        return (self.current_time.get() > self.total_time.get() +
 
                self.song_pad_time)
 

	
 
    def play_pause_toggle(self):
 
        def finish(status):
 
            if status.state == 'play':
 
                self.mpd.pause()
 
            else:
 
@@ -209,19 +220,60 @@ class Player:
 
    def pause(self):
 
        self.mpd.pause()
 

	
 
    def skip_to_post(self):
 
        self.seek_to(self.total_time.get() + self.song_pad_time)
 
        self.play()
 

	
 

	
 
class GoButton:
 
    def __init__(self, player, statusLabel, songPaths):
 
        self.player = player
 
        self.statusLabel = statusLabel
 
        self.songPaths = songPaths
 

	
 
        self.player.current_time.trace("w", self.updateStatus)
 

	
 
    def _nextAction(self):
 
        state = self.player.state.get() 
 
        if state == 'stop':
 
            currentPath = self.player.filename_var.get()
 
            try:
 
                i = self.songPaths.index(currentPath) + 1
 
            except ValueError:
 
                i = 0
 
            nextPath = self.songPaths[i]
 
            return ("next song %s" % shortSongPath(nextPath,
 
                                                   self.songPaths),
 
                    lambda: self.player.play(nextPath))
 

	
 
        if state == 'pause':
 
            return "play", self.player.play
 

	
 
        if state == 'play':
 
            if self.player.in_post():
 
                return "<nothing>", lambda: None
 
            return "skip to post", self.player.skip_to_post
 
        
 
    def action(self):
 
        desc, func = self._nextAction()
 
        func()
 
        
 
    def updateStatus(self, *args):
 
        desc, func = self._nextAction()
 
        self.statusLabel.config(text=desc)
 
        
 

	
 

	
 
def buildsonglist(root, graph, songs, player):
 
def buildsonglist(root,songfiles,player):
 
    songlist=tk.Frame(root,bd=2,relief='raised',bg='black')
 

	
 
    maxsfwidth=max([len(graph.label(song)) for song in songs])
 
    prefixlen=len(os.path.commonprefix(songfiles))
 
    # include to the last os.sep- dont crop path elements in the middle
 
    prefixlen=songfiles[0].rfind(os.sep)+1 
 
    maxsfwidth=max([len(x[prefixlen:]) for x in songfiles])
 

	
 
    for i,sf in enumerate(songfiles):
 
        b=tk.Button(songlist,text=sf[prefixlen:],width=maxsfwidth,
 
                    anchor='w',pady=0,bd=0,relief='flat',
 
                    font="arial 14 bold")
 
        b.bind("<Configure>",lambda ev,b=b:
 
@@ -239,13 +291,13 @@ def buildsonglist(root, graph, songs, pl
 
        b.config(command=lambda song=song: player.play(song))
 
        b.pack(side='top',fill='both',exp=1,padx=0,pady=0,ipadx=0,ipady=0)
 

	
 

	
 
        def color_buttons(x, y, z, song=song, b=b):
 
            name = player.filename_var.get()
 
            if name == graph.value(song, L9['showPath']):
 
            if name == sf[prefixlen:]:
 
                b['bg'] = 'grey50'
 
            else:
 
                b['bg'] = 'black'
 
        player.filename_var.trace("w", color_buttons)
 
    return songlist
 
 
 
@@ -351,37 +403,39 @@ class Seeker(tk.Frame):
 
                self.scl['troughcolor'] = 'black'
 

	
 
        player.total_time.trace("w",fixleft)
 
        player.current_time.trace("w",fixleft)
 

	
 
class ControlButtons(tk.Frame):
 
    def __init__(self,master):
 
    def __init__(self, master, goButton, player, root):
 
        tk.Frame.__init__(self,master,bg='black')
 
        
 
        self.statebuttons = {} # lowercased name : Button
 
        self.goButton = goButton
 
        self.player = player
 
        for tag, txt,cmd,key in [
 
            ('stop',
 
             'Stop\nC-s', player.stop, "<Control-s>"),
 
            ('pause',
 
             'Pause\nC-p', player.play_pause_toggle, "<Control-p>"),
 
            ('skip intro',
 
             'Skip Intro\nC-i',lambda: player.seek_to(0),
 
             "<Control-i>"),
 
            ('skip to post',
 
             'Skip to Post\nC-t', player.skip_to_post, "<Control-t>"),
 
            ('go', 'Go\nspace', self.goButton.action, "<Key-space>"),
 
            ]:
 
            b = tk.Button(self, text=txt, command=cmd,
 
                          font='arial 16 bold',
 
                          height=3,**appstyle)
 
            b.pack(side='left', fill='x', expand=1)
 
            b.pack(side='left', fill='both', expand=True)
 
            # keyboard bindings
 
            root.bind(key, lambda evt, cmd=cmd: cmd())
 
            self.statebuttons[tag] = b
 

	
 
    def update_state_buttons(self,*args):
 
        state = player.state.get()
 
        state = self.player.state.get()
 

	
 
        if state in ('stop', 'pause'):
 
            self.statebuttons['pause']['text'] = 'Play\nC-p'
 
        else:
 
            self.statebuttons['pause']['text'] = 'Pause\nC-p' 
 

	
 
@@ -394,55 +448,65 @@ class ControlButtons(tk.Frame):
 
                name = 'play'
 

	
 
            if state == name: # name gets changed sometimes for 'pause' -- see right above
 
                button['bg'] = colors.get(name, 'black')
 
            else:
 
                button['bg'] = 'black'
 
        self.goButton.updateStatus()
 

	
 
############################
 
        
 
parser=OptionParser()
 

	
 
(options,songfiles)=parser.parse_args()
 

	
 
graph = showconfig.getGraph()
 

	
 
if len(songfiles)<1:
 
    graph = showconfig.getGraph()
 
    playList = graph.value(L9['show/dance2007'], L9['playList'])
 
    songs = list(graph.items(playList))
 
else:
 
    raise NotImplementedError("don't know how to make rdf song nodes from cmdline song paths")
 
    songfiles = [f for f in os.listdir(showconfig.musicDir())
 
                 if f.endswith('wav')]
 
    songfiles.sort()
 

	
 
root=tk.Tk()
 
root.wm_title("ascoltami")
 
#root.wm_geometry("+1270+440")
 
toplevelat("ascoltami", root)
 
root.config(bg="black")
 
player=Player(None,None)
 
    (options, songfiles) = parser.parse_args()
 

	
 
songlist = buildsonglist(root, graph, songs, player)
 
songlist = buildsonglist(root,songfiles,player)
 
songlist.pack(fill='both',exp=1)
 

	
 
f2 = tk.Frame(bg='black')
 
buts = ControlButtons(f2)
 
buts.pack(side='top',fill='x')
 
    root=tk.Tk()
 
    root.wm_title("ascoltami")
 
    toplevelat("ascoltami", root)
 
    root.config(bg="black")
 
    player=Player()
 

	
 
    songlist = buildsonglist(root, songfiles, player)
 

	
 
player.state.trace_variable('w', buts.update_state_buttons)
 
buts.update_state_buttons()
 
    seeker = Seeker(root, player)
 
    
 
    goRow = tk.Frame(root)
 
    tk.Label(goRow, text="Go button action:",
 
             font='arial 9', **appstyle).pack(side='left', fill='both')
 
    goStatus = tk.Label(goRow, font='arial 12 bold', **appstyle)
 
    goStatus.config(bg='#800000', fg='white')
 
    goStatus.pack(side='left', expand=True, fill='x')
 

	
 
seeker = Seeker(f2,player)
 
seeker.pack(fill='x',exp=1)
 
f2.pack(side='bottom',fill='x')
 
    go = GoButton(player, goStatus, songfiles)
 
    
 
    buts = ControlButtons(root, go, player, root)
 

	
 
tksupport.install(root,ms=10)
 
    songlist.pack(fill='both', expand=True)
 
    buts.pack(side='top', fill='x')
 
    seeker.pack(side='top', fill='x')
 
    goRow.pack(side='top', fill='x')
 

	
 
    player.state.trace_variable('w', buts.update_state_buttons)
 
    buts.update_state_buttons()
 

	
 
    tksupport.install(root,ms=10)
 

	
 
try:
 
    reactor.listenTCP(networking.musicPort(),server.Site(XMLRPCServe(player)))
 
    print "started server on %s" % networking.musicPort()
 
except CannotListenError:
 
    print "no server started- %s is in use" % networking.musicPort()
 
    try:
 
        reactor.listenTCP(networking.musicPort(),server.Site(XMLRPCServe(player)))
 
        print "started server on %s" % networking.musicPort()
 
    except CannotListenError:
 
        print "no server started- %s is in use" % networking.musicPort()
 

	
 
root.bind("<Destroy>",lambda ev: reactor.stop)
 
root.protocol('WM_DELETE_WINDOW', reactor.stop)
 
    root.bind("<Destroy>",lambda ev: reactor.stop)
 
    root.protocol('WM_DELETE_WINDOW', reactor.stop)
 

	
 
reactor.run()
 
    reactor.run()
 
    
 
if __name__ == '__main__':
 
    main()
0 comments (0 inline, 0 general)