diff --git a/bin/ascoltami2 b/bin/ascoltami2 new file mode 100644 --- /dev/null +++ b/bin/ascoltami2 @@ -0,0 +1,37 @@ +#!/usr/bin/python +import web, thread, gobject, sys, optparse, logging +from rdflib import URIRef +sys.path.append(".") +from light9.ascoltami.player import Player +from light9.ascoltami.webapp import makeApp +from light9 import networking, showconfig + +log = logging.getLogger() +logging.basicConfig() +gobject.threads_init() + +parser = optparse.OptionParser() +parser.add_option('--show', + help='show URI, like http://light9.bigasterisk.com/show/dance2008') +parser.add_option("-v", "--verbose", action="store_true", + help="logging.DEBUG") +graph = showconfig.getGraph() +(options, args) = parser.parse_args() + + +log.setLevel(logging.DEBUG if options.verbose else logging.INFO) + +graph = showconfig.getGraph() +if not options.show: + raise ValueError("missing --show http://...") + +player = Player() + +# the cherrypy server would wedge when vidref pounds on it; this +# one seems to run +thread.start_new(web.httpserver.runbasic, + (makeApp(player, graph, URIRef(options.show)).wsgifunc(), + ('0.0.0.0', networking.musicPort()))) + +mainloop = gobject.MainLoop() +mainloop.run() diff --git a/light9/ascoltami/__init__.py b/light9/ascoltami/__init__.py new file mode 100644 diff --git a/light9/ascoltami/index.html b/light9/ascoltami/index.html new file mode 100644 --- /dev/null +++ b/light9/ascoltami/index.html @@ -0,0 +1,111 @@ + + + + + ascoltami + + + + + + + + +
+
+ + +
Song:
+
Time:
+
Left:
+
+
+
+ +
+ + + + + +
+ +bind keys, spacebar, css work + + + + + + \ No newline at end of file diff --git a/light9/ascoltami/player.py b/light9/ascoltami/player.py new file mode 100644 --- /dev/null +++ b/light9/ascoltami/player.py @@ -0,0 +1,103 @@ +#!/usr/bin/python + +""" +alternate to the mpd music player, for ascoltami +""" +from __future__ import division +import time, logging +import gst +log = logging.getLogger() + +class Player(object): + def __init__(self): + + self.playbin = self.pipeline = gst.parse_launch("playbin2 name=b") + self.playStartTime = 0 + self._duration = 0 + self.pauseTime = 0 + + self.setSong("file:///my/proj/light9/show/dance2010/music/07-jacksonmix-complete.wav") + + #self.pipeline = gst.parse_launch("filesrc name=file location=%s ! wavparse name=src ! audioconvert ! alsasink name=out" % songFile) + + def on_any(bus, msg): + print bus, msg + + bus = self.pipeline.get_bus() + bus.add_signal_watch() + #bus.connect('message', on_any) + + def onStreamStatus(bus, message): + (statusType, _elem) = message.parse_stream_status() + if statusType == gst.STREAM_STATUS_TYPE_ENTER: + self.setupAutostop() + + # we should run our own poller looking for crosses over the autostop threshold and pausing. When i used the pipeline.seek end-time, it caused lots of unwanted other pausing and was hard to turn off. + + #print message, bus + bus.connect('message::stream-status', onStreamStatus) + + def seek(self, t): + assert self.playbin.seek_simple( + gst.FORMAT_TIME, + gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE | gst.SEEK_FLAG_SKIP, + t * gst.SECOND) + self.playStartTime = time.time() + + def setSong(self, songUri): + """ + uri like file:///my/proj/light9/show/dance2010/music/07.wav + """ + log.info("set song to %r" % songUri) + self.pipeline.set_state(gst.STATE_READY) + self.pipeline.set_property("uri", songUri) + self.pipeline.set_state(gst.STATE_PLAYING) + self.playStartTime = time.time() + + + +# GST_MESSAGE_DURATION + + + def currentTime(self): + cur, _format = self.playbin.query_position(gst.FORMAT_TIME) + return cur / gst.SECOND + + def duration(self): + return self.playbin.query_duration(gst.FORMAT_TIME)[0] / gst.SECOND + + def pause(self): + self.pipeline.set_state(gst.STATE_PAUSED) + + def resume(self): + self.pipeline.set_state(gst.STATE_PLAYING) + pos = self.currentTime() + autoStop = self.duration() - 10 + if abs(pos - autoStop) < .01: + self.releaseAutostop() + + + def setupAutostop(self): + return + dur = self.duration() + autoStop = (dur - 10.0) + log.info("autostop will be at %s", autoStop) + print "seek", self.pipeline.seek(1.0, gst.FORMAT_TIME, + gst.SEEK_FLAG_ACCURATE, + gst.SEEK_TYPE_NONE, 0, + gst.SEEK_TYPE_SET, autoStop * gst.SECOND) + + def releaseAutostop(self): + log.info("release autostop") + + print "seek", self.pipeline.seek( + 1.0, gst.FORMAT_TIME, + gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE | gst.SEEK_FLAG_SKIP, + gst.SEEK_TYPE_NONE, 0, + gst.SEEK_TYPE_END, 0) + print self.pipeline.get_state() + self.pipeline.set_state(gst.STATE_PLAYING) + + + + diff --git a/light9/ascoltami/webapp.py b/light9/ascoltami/webapp.py new file mode 100644 --- /dev/null +++ b/light9/ascoltami/webapp.py @@ -0,0 +1,64 @@ +import web, jsonlib +from twisted.python.util import sibpath +from light9.namespaces import L9, MUS + +player = None +graph = None +show = None + +class root(object): + def GET(self): + web.header("Content-type", "application/xhtml+xml") + return open(sibpath(__file__, "index.html")).read() + +class timeResource(object): + def GET(self): + return jsonlib.write({"song" : player.playbin.get_property("uri"), + "started" : player.playStartTime, + "duration" : player.duration(), + "t" : player.currentTime()}) + + def POST(self): + params = jsonlib.read(web.data(), use_float=True) + if params.get('pause', False): + player.pause() + if params.get('resume', False): + player.resume() + if 't' in params: + player.seek(params['t']) + return "ok" + +class songs(object): + def GET(self): + + playList = graph.value(show, L9['playList']) + if not playList: + raise ValueError("%r has no l9:playList" % show) + songs = list(graph.items(playList)) + + + web.header("Content-type", "application/json") + return jsonlib.write({"songs" : [ + {"uri" : s, + "path" : graph.value(s, L9['showPath']), + "label" : graph.label(s)} for s in songs]}) + +class songResource(object): + def POST(self): + """post a uri of song to switch to (and start playing)""" + player.setSong(web.data()) + return "ok" + +def makeApp(thePlayer, theGraph, theShow): + global player, graph, show + player, graph, show = thePlayer, theGraph, theShow + + urls = ("/", "root", + "/time", "timeResource", + "/song", "songResource", + "/songs", "songs", + "/api/position", "timeResource", # old + ) + + app = web.application(urls, globals(), autoreload=False) + return app diff --git a/static/style.css b/static/style.css new file mode 100644 --- /dev/null +++ b/static/style.css @@ -0,0 +1,9 @@ +.songs button { + display: inline-block; + width: 300px; +height: 30px; + text-align: left; +} +.songs button:hover { + background: yellow; +} \ No newline at end of file