Changeset - 3c523c71da29
[Not reviewed]
default
! ! !
Drew Perttula - 6 years ago 2019-05-25 12:10:51
drewp@bigasterisk.com
pyflakes cleanups and some refactors
Ignore-this: f7372e678699175feb4e628eee3d768c
61 files changed with 286 insertions and 291 deletions:
0 comments (0 inline, 0 general)
bin/ascoltami2
Show inline comments
 
#!bin/python
 
from run_local import log
 
from twisted.internet import reactor
 
import web, _thread, sys, optparse, logging
 
import sys, optparse, logging
 
from rdflib import URIRef
 
import gi
 
gi.require_version('Gst', '1.0')
 
gi.require_version('Gtk', '3.0')
 

	
 
from light9.ascoltami.player import Player
 
from light9.ascoltami.playlist import Playlist, NoSuchSong
 
from light9.ascoltami.webapp import makeWebApp, songUri, songLocation
 
from light9 import networking, showconfig
 

	
 
from gi.repository import GObject, Gst, Gtk
 
from gi.repository import GObject, Gst
 

	
 

	
 
class App(object):
 

	
 
    def __init__(self, graph, show):
 
        self.graph = graph
bin/captureDevice
Show inline comments
 
@@ -20,12 +20,13 @@ from light9 import networking, showconfi
 
from rdfdb.syncedgraph import SyncedGraph
 
from light9.paint.capture import writeCaptureDescription
 
from light9.greplin_cyclone import StatsForCyclone
 
from light9.effect.settings import DeviceSettings
 
from light9.collector.collector_client import sendToCollector
 
from rdfdb.patch import Patch
 
from light9.zmqtransport import parseJsonMessage
 

	
 
stats = scales.collection('/webServer', scales.PmfStat('setAttr'))
 

	
 

	
 
class Camera(object):
 

	
 
@@ -171,13 +172,14 @@ def launch(graph):
 
                          (r'/()', cyclone.web.StaticFileHandler, {
 
                              "path": "light9/web",
 
                              "default_filename": "captureDevice.html"
 
                          }),
 
                          (r'/stats', StatsForCyclone),
 
                      ]),
 
                      interface='::')
 
                      interface='::',
 
                      cap=cap)
 
    log.info('serving http on %s', networking.captureDevice.port)
 

	
 

	
 
def main():
 
    parser = optparse.OptionParser()
 
    parser.add_option("-v",
bin/collector
Show inline comments
 
@@ -6,133 +6,31 @@ custom code for some attributes.
 

	
 
Input can be over http or zmq.
 
"""
 

	
 
from run_local import log
 

	
 
from rdflib import URIRef, Literal
 
from twisted.internet import reactor, utils
 
from txzmq import ZmqEndpoint, ZmqFactory, ZmqPullConnection
 
import json
 
import logging
 
import optparse
 
import time
 
import traceback
 
import cyclone.web, cyclone.websocket
 
from greplin import scales
 

	
 
from cycloneerr import PrettyErrorHandler
 
from light9.collector.output import EnttecDmx, Udmx, DummyOutput
 
from light9 import networking
 
from light9.collector.collector import Collector
 
from light9.namespaces import L9
 
from light9 import networking
 
from rdfdb.syncedgraph import SyncedGraph
 
from light9.collector.weblisteners import WebListeners
 
from light9.greplin_cyclone import StatsForCyclone
 

	
 

	
 
def parseJsonMessage(msg):
 
    body = json.loads(msg)
 
    settings = []
 
    for device, attr, value in body['settings']:
 
        if isinstance(value, str) and value.startswith('http'):
 
            value = URIRef(value)
 
        else:
 
            value = Literal(value)
 
        settings.append((URIRef(device), URIRef(attr), value))
 
    return body['client'], body['clientSession'], settings, body['sendTime']
 

	
 

	
 
def startZmq(port, collector):
 
    stats = scales.collection('/zmqServer', scales.PmfStat('setAttr'))
 

	
 
    zf = ZmqFactory()
 
    addr = 'tcp://*:%s' % port
 
    log.info('creating zmq endpoint at %r', addr)
 
    e = ZmqEndpoint('bind', addr)
 

	
 
    class Pull(ZmqPullConnection):
 
        #highWaterMark = 3
 
        def onPull(self, message):
 
            with stats.setAttr.time():
 
                # todo: new compressed protocol where you send all URIs up
 
                # front and then use small ints to refer to devices and
 
                # attributes in subsequent requests.
 
                client, clientSession, settings, sendTime = parseJsonMessage(
 
                    message[0])
 
                collector.setAttrs(client, clientSession, settings, sendTime)
 

	
 
    s = Pull(zf, e)
 

	
 

	
 
class WebListeners(object):
 

	
 
    def __init__(self):
 
        self.clients = []
 
        self.pendingMessageForDev = {}  # dev: (attrs, outputmap)
 
        self.lastFlush = 0
 

	
 
    def addClient(self, client):
 
        self.clients.append([client, {}])  # seen = {dev: attrs}
 
        log.info('added client %s %s', len(self.clients), client)
 
from light9.namespaces import L9
 
from light9.zmqtransport import parseJsonMessage, startZmq
 
from rdfdb.syncedgraph import SyncedGraph
 

	
 
    def delClient(self, client):
 
        self.clients = [[c, t] for c, t in self.clients if c != client]
 
        log.info('delClient %s, %s left', client, len(self.clients))
 

	
 
    def outputAttrsSet(self, dev, attrs, outputMap):
 
        """called often- don't be slow"""
 

	
 
        self.pendingMessageForDev[dev] = (attrs, outputMap)
 
        try:
 
            self._flush()
 
        except Exception:
 
            traceback.print_exc()
 
            raise
 

	
 
    def _flush(self):
 
        now = time.time()
 
        if now < self.lastFlush + .05 or not self.clients:
 
            return
 
        self.lastFlush = now
 

	
 
        while self.pendingMessageForDev:
 
            dev, (attrs, outputMap) = self.pendingMessageForDev.popitem()
 

	
 
            msg = None  # lazy, since makeMsg is slow
 
from light9.collector.output import EnttecDmx, Udmx, DummyOutput  # noqa
 

	
 
            # this omits repeats, but can still send many
 
            # messages/sec. Not sure if piling up messages for the browser
 
            # could lead to slowdowns in the real dmx output.
 
            for client, seen in self.clients:
 
                if seen.get(dev) == attrs:
 
                    continue
 
                if msg is None:
 
                    msg = self.makeMsg(dev, attrs, outputMap)
 

	
 
                seen[dev] = attrs
 
                client.sendMessage(msg)
 

	
 
    def makeMsg(self, dev, attrs, outputMap):
 
        attrRows = []
 
        for attr, val in list(attrs.items()):
 
            output, index = outputMap[(dev, attr)]
 
            attrRows.append({
 
                'attr': attr.rsplit('/')[-1],
 
                'val': val,
 
                'chan': (output.shortId(), index + 1)
 
            })
 
        attrRows.sort(key=lambda r: r['chan'])
 
        for row in attrRows:
 
            row['chan'] = '%s %s' % (row['chan'][0], row['chan'][1])
 

	
 
        msg = json.dumps({'outputAttrsSet': {
 
            'dev': dev,
 
            'attrs': attrRows
 
        }},
 
                         sort_keys=True)
 
        return msg
 

	
 

	
 
class Updates(cyclone.websocket.WebSocketHandler):
 

	
 
    def connectionMade(self, *args, **kwargs):
 
        log.info('socket connect %s', self)
 
@@ -160,16 +58,14 @@ class Attrs(PrettyErrorHandler, cyclone.
 

	
 

	
 
def launch(graph, doLoadTest=False):
 
    try:
 
        # todo: drive outputs with config files
 
        outputs = [
 
            # EnttecDmx(L9['output/dmxA/'], '/dev/dmx3', 80),
 
            Udmx(L9['output/dmxA/'], bus=5, numChannels=80),
 
            #DummyOutput(L9['output/dmxA/'], 80),
 
            Udmx(L9['output/dmxB/'], bus=7, numChannels=500),
 
            DummyOutput(L9['output/dmxA/'], 80),
 
            DummyOutput(L9['output/dmxB/'], 510),
 
        ]
 
    except Exception:
 
        log.error("setting up outputs:")
 
        traceback.print_exc()
 
        raise
 
    listeners = WebListeners()
bin/collector_loadtest.py
Show inline comments
 
import sys
 
sys.path.append('bin')
 
from run_local import log
 
from light9.collector.collector_client import sendToCollector, sendToCollectorZmq
 
from light9.collector.collector_client import sendToCollector
 
from light9.namespaces import L9, DEV
 
from twisted.internet import reactor
 
import time
 
import logging
 
log.setLevel(logging.DEBUG)
 

	
bin/effecteval
Show inline comments
 
#!bin/python
 

	
 
from run_local import log
 
from twisted.internet import reactor
 
from twisted.internet.defer import inlineCallbacks, returnValue
 
import cyclone.web, cyclone.websocket, cyclone.httpclient
 
import sys, optparse, logging, subprocess, json, itertools
 
import sys, optparse, logging, json, itertools
 
from rdflib import URIRef, Literal
 

	
 
sys.path.append('/usr/lib/pymodules/python2.7/')  # for numpy, on rpi
 
sys.path.append('/usr/lib/python2.7/dist-packages')  # For numpy
 
from light9 import networking, showconfig
 
from light9.effecteval.effect import EffectNode
 
@@ -17,12 +17,13 @@ from light9.greplin_cyclone import Stats
 
from light9.namespaces import L9
 
from rdfdb.patch import Patch
 
from rdfdb.syncedgraph import SyncedGraph
 
from greplin import scales
 

	
 
from cycloneerr import PrettyErrorHandler
 
from light9.coffee import StaticCoffee
 

	
 

	
 
class EffectEdit(PrettyErrorHandler, cyclone.web.RequestHandler):
 

	
 
    def get(self):
 
        self.set_header('Content-Type', 'text/html')
 
@@ -198,15 +199,15 @@ class EffectEval(PrettyErrorHandler, cyc
 
# Completely not sure where the effect background loop should
 
# go. Another process could own it, and get this request repeatedly:
 
class SongEffectsEval(PrettyErrorHandler, cyclone.web.RequestHandler):
 

	
 
    def get(self):
 
        song = URIRef(self.get_argument('song'))
 
        effects = effectsForSong(self.settings.graph, song)
 
        effects = effectsForSong(self.settings.graph, song) # noqa
 
        raise NotImplementedError
 
        self.write(maxDict(effectDmxDict(e) for e in effects))
 
        self.write(maxDict(effectDmxDict(e) for e in effects)) # noqa
 
        # return dmx dict for all effects in the song, already combined
 

	
 

	
 
class App(object):
 

	
 
    def __init__(self, show, outputWhere):
 
@@ -256,25 +257,12 @@ class App(object):
 
                                                  graph=self.graph,
 
                                                  stats=self.stats)
 
        reactor.listenTCP(networking.effectEval.port, self.cycloneApp)
 
        log.info("listening on %s" % networking.effectEval.port)
 

	
 

	
 
class StaticCoffee(PrettyErrorHandler, cyclone.web.RequestHandler):
 

	
 
    def initialize(self, src):
 
        super(StaticCoffee, self).initialize()
 
        self.src = src
 

	
 
    def get(self):
 
        self.set_header('Content-Type', 'application/javascript')
 
        self.write(
 
            subprocess.check_output(
 
                ['/usr/bin/coffee', '--compile', '--print', self.src]))
 

	
 

	
 
if __name__ == "__main__":
 
    parser = optparse.OptionParser()
 
    parser.add_option(
 
        '--show',
 
        help='show URI, like http://light9.bigasterisk.com/show/dance2008',
 
        default=showconfig.showUri())
bin/homepageConfig
Show inline comments
 
#!bin/python
 
from run_local import log
 
from rdflib import RDF, URIRef
 
from light9 import networking, showconfig
 
from light9 import showconfig
 
from light9.namespaces import L9
 
from urllib.parse import urlparse
 
from urllib.parse import splitport
 

	
 
from rdfdb.syncedgraph import SyncedGraph
 
from twisted.internet import reactor
 

	
 
log.info('generating config')
 
graph = showconfig.getGraph()
 

	
 
netHome = graph.value(showconfig.showUri(), L9['networking'])
 
webServer = graph.value(netHome, L9['webServer'])
 
if not webServer:
 
    raise ValueError('no %r :webServer' % netHome)
bin/inputdemo
Show inline comments
 
@@ -2,19 +2,18 @@
 
import sys
 
sys.path.append('/usr/lib/python2.7/dist-packages')  # For gtk
 
from twisted.internet import gtk3reactor
 
gtk3reactor.install()
 
from twisted.internet import reactor
 
from rdflib import URIRef
 
import optparse, logging, urllib.request, urllib.parse, urllib.error, time
 
import optparse, logging, time
 
from gi.repository import Gtk
 
from run_local import log
 
from light9 import showconfig, networking
 
from light9 import networking
 
from light9 import clientsession
 
from rdfdb.syncedgraph import SyncedGraph
 
import cyclone.httpclient
 
from light9.curvecalc.client import sendLiveInputPoint
 

	
 

	
 
class App(object):
 

	
 
    def __init__(self):
bin/inputquneo
Show inline comments
 
@@ -6,13 +6,13 @@ read Quneo midi events, write to curveca
 
from run_local import log
 
import logging, urllib.request, urllib.parse, urllib.error
 
import cyclone.web, cyclone.httpclient
 
from rdflib import URIRef
 
from twisted.internet import reactor, task
 
from light9.curvecalc.client import sendLiveInputPoint
 
from light9.namespaces import L9, RDF, RDFS
 
from light9.namespaces import L9, RDF
 
from rdfdb.syncedgraph import SyncedGraph
 
from light9 import networking
 

	
 
import sys
 
sys.path.append('/usr/lib/python2.7/dist-packages')  # For pygame
 
import pygame.midi
 
@@ -106,9 +106,10 @@ class WatchMidi(object):
 

	
 
def main():
 
    log.setLevel(logging.DEBUG)
 
    graph = SyncedGraph(networking.rdfdb.url, "inputQuneo")
 
    wm = WatchMidi(graph)
 
    reactor.run()
 
    del wm
 

	
 

	
 
main()
bin/keyboardcomposer
Show inline comments
 
@@ -339,22 +339,22 @@ class KeyboardComposer(tk.Frame, SubClie
 

	
 
    def setup_key_nudgers(self, tkobject):
 
        for d, keys in list(nudge_keys.items()):
 
            for key in keys:
 
                # lowercase makes full=0
 
                keysym = "<KeyPress-%s>" % key
 
                tkobject.bind(keysym, \
 
                    lambda evt, num=keys.index(key), d=d: \
 
                        self.got_nudger(num, d))
 
                tkobject.bind(keysym,
 
                              lambda evt, num=keys.index(key), d=d: self.
 
                              got_nudger(num, d))
 

	
 
                # uppercase makes full=1
 
                keysym = "<KeyPress-%s>" % key.upper()
 
                keysym = keysym.replace('SEMICOLON', 'colon')
 
                tkobject.bind(keysym, \
 
                    lambda evt, num=keys.index(key), d=d: \
 
                        self.got_nudger(num, d, full=1))
 
                tkobject.bind(keysym,
 
                              lambda evt, num=keys.index(key), d=d: self.
 
                              got_nudger(num, d, full=1))
 

	
 
        # Row changing:
 
        # Page dn, C-n, and ] do down
 
        # Page up, C-p, and ' do up
 
        for key in '<Prior> <Next> <Control-n> <Control-p> ' \
 
                   '<Key-bracketright> <Key-apostrophe>'.split():
bin/listsongs
Show inline comments
 
@@ -4,13 +4,13 @@
 
in .zshrc:
 

	
 
function _songs { local expl;  _description files expl 'songs';  compadd "$expl[@]" - `${LIGHT9_SHOW}/../../bin/listsongs` }
 
compdef _songs curvecalc
 
"""
 

	
 
from run_local import log
 
from run_local import log  # noqa
 
from twisted.internet import reactor
 
from rdflib import RDF
 
from light9 import networking
 
from light9.namespaces import L9
 
from rdfdb.syncedgraph import SyncedGraph
 

	
bin/musicPad
Show inline comments
 
@@ -2,13 +2,12 @@
 
"""
 
rewrite all the songs with silence at the start and end
 
"""
 
import sys, wave, logging, os
 
sys.path.append(".")
 
from light9 import showconfig
 
from light9.namespaces import L9
 
from light9.ascoltami.playlist import Playlist
 
logging.basicConfig(level=logging.INFO)
 
log = logging.getLogger()
 

	
 
introPad = 4
 
postPad = 9  # 5 + autostop + 4
bin/musictime
Show inline comments
 
#!/usr/bin/env python
 
import run_local
 
import run_local  # noqa
 
import light9.networking
 

	
 
import tkinter as tk
 
import time
 
import restkit, jsonlib
 

	
bin/paintserver
Show inline comments
 
@@ -10,13 +10,13 @@ from greplin import scales
 
import optparse, sys, logging
 
import cyclone.web
 
from rdflib import URIRef
 
from light9 import clientsession
 
import light9.paint.solve
 
from cycloneerr import PrettyErrorHandler
 
from light9.namespaces import RDF, L9, DEV
 
from light9.namespaces import L9, DEV
 
import imp
 

	
 

	
 
class Solve(PrettyErrorHandler, cyclone.web.RequestHandler):
 

	
 
    def post(self):
bin/picamserve
Show inline comments
 
@@ -159,13 +159,12 @@ class Pics(cyclone.web.RequestHandler):
 
            fpsReport = FpsReport()
 

	
 
            def onFrame(frameTime, frame):
 
                if not self.running:
 
                    raise StopIteration
 

	
 
                now = time.time()
 
                self.write("%s %s\n" % (len(frame), frameTime))
 
                self.write(frame)
 
                self.flush()
 

	
 
                fpsReport.frame()
 

	
bin/rdfdb
Show inline comments
 
#!bin/python
 
import run_local
 
import run_local  # noqa
 
import os
 
from light9 import networking, showconfig
 
import rdfdb.service
 

	
 
rdfdb.service.main(
 
    dirUriMap={
bin/subserver
Show inline comments
 
#!bin/python
 
"""
 
live web display of all existing subs with pictures, mainly for
 
dragging them into CC or Timeline
 
"""
 
from run_local import log
 
import sys, optparse, logging, json, subprocess, datetime
 
import optparse, logging, json, subprocess, datetime
 
from dateutil.tz import tzlocal
 
from twisted.internet import reactor, defer
 
import cyclone.web, cyclone.httpclient, cyclone.websocket
 
from rdflib import RDF, URIRef, Literal
 
from rdflib import URIRef, Literal
 
import pyjade.utils
 
from rdfdb.syncedgraph import SyncedGraph
 
from rdfdb.patch import Patch
 
from light9.namespaces import L9, DCTERMS
 
from light9 import networking, showconfig
 

	
bin/vidref
Show inline comments
 
@@ -4,16 +4,15 @@ import sys
 
sys.path.append('/usr/lib/python2.7/dist-packages')  # For gtk
 
from twisted.internet import gtk2reactor
 
gtk2reactor.install()
 
from twisted.internet import reactor, defer
 
import gobject
 
gobject.threads_init()
 
import gtk
 
import sys, logging, optparse, json
 
import cyclone.web, cyclone.httpclient, cyclone.websocket
 
from light9 import networking, showconfig
 
from light9 import networking
 
from light9.vidref.main import Gui
 
from light9.vidref.replay import snapshotDir
 
from rdfdb.syncedgraph import SyncedGraph
 

	
 
# find replay dirs correctly. show multiple
 
# replays. trash. reorder/pin. dump takes that are too short; they're
 
@@ -39,13 +38,13 @@ class Snapshot(cyclone.web.RequestHandle
 
            out = networking.vidref.path(
 
                "snapshot/%s" % outputFilename[len(snapshotDir()):].lstrip('/'))
 

	
 
            self.write(json.dumps({'snapshot': out}))
 
            self.set_header("Location", out)
 
            self.set_status(303)
 
        except Exception as e:
 
        except Exception:
 
            import traceback
 
            traceback.print_exc()
 
            raise
 

	
 

	
 
class SnapshotPic(cyclone.web.StaticFileHandler):
bin/vidrefsetup
Show inline comments
 
#!bin/python
 
""" this should be part of vidref, but I haven't worked out sharing
 
camera captures with a continuous camera capture yet """
 

	
 
from run_local import log
 
import sys, optparse, logging, json, subprocess, datetime
 
from dateutil.tz import tzlocal
 
from twisted.internet import reactor, defer
 
import optparse, logging
 
from twisted.internet import reactor
 
import cyclone.web, cyclone.httpclient, cyclone.websocket
 
from rdflib import RDF, URIRef, Literal
 
import pyjade.utils
 
from rdflib import URIRef
 
from rdfdb.syncedgraph import SyncedGraph
 
from rdfdb.patch import Patch
 
from light9.namespaces import L9, DCTERMS
 
from light9.namespaces import L9
 
from light9 import networking, showconfig
 

	
 
from cycloneerr import PrettyErrorHandler
 

	
 

	
 
class RedirToCamera(PrettyErrorHandler, cyclone.web.RequestHandler):
bin/wavecurve
Show inline comments
 
#!bin/python
 
import optparse
 
import run_local
 
from run_local import log
 
from light9.wavepoints import simp
 

	
 

	
 
def createCurve(inpath, outpath, t):
 
    print("reading %s, writing %s" % (inpath, outpath))
 
    points = simp(inpath.replace('.ogg', '.wav'), seconds_per_average=t)
 

	
 
    f = file(outpath, 'w')
 
    f = open(outpath, 'w')
 
    for time_val in points:
 
        print("%s %s" % time_val, file=f)
 
    log.info(r'Wrote {outpath}')
 

	
 

	
 
parser = optparse.OptionParser(usage="""%prog inputSong.wav outputCurve
 

	
 
You probably just want -a
 

	
 
@@ -27,14 +28,12 @@ parser.add_option("-a",
 
                  action="store_true",
 
                  help="make standard curves for all songs")
 
options, args = parser.parse_args()
 

	
 
if options.all:
 
    from light9 import showconfig
 
    from light9.namespaces import L9
 
    from rdflib import RDF
 
    from light9.ascoltami.playlist import Playlist
 
    graph = showconfig.getGraph()
 

	
 
    playlist = Playlist.fromShow(showconfig.getGraph(), showconfig.showUri())
 
    for song in playlist.allSongs():
 
        inpath = showconfig.songOnDisk(song)
lib/ipython_view.py
Show inline comments
 
@@ -18,17 +18,18 @@ is available at U{http://www.opensource.
 
from gi.repository import Gtk
 
from gi.repository import Gdk
 
import re
 
import sys
 
import os
 
from gi.repository import Pango
 
from StringIO import StringIO
 
from io import StringIO
 
from functools import reduce
 
 
 
try:
 
	import IPython
 
except Exception,e:
 
except Exception as e:
 
	raise "Error importing IPython (%s)" % str(e)
 
 
 
ansi_colors =  {'0;30': 'Black',
 
                '0;31': 'Red',
 
                '0;32': 'Green',
 
                '0;33': 'Brown',
 
@@ -145,17 +146,17 @@ class IterableIPShell:
 
      if not str2.startswith(str1[:i+1]):
 
        return str1[:i]
 
    return str1
 
 
 
  def shell(self, cmd,verbose=0,debug=0,header=''):
 
    stat = 0
 
    if verbose or debug: print header+cmd
 
    if verbose or debug: print(header+cmd)
 
    # flush stdout so we don't mangle python's buffering
 
    if not debug:
 
      input, output = os.popen4(cmd)
 
      print output.read()
 
      print(output.read())
 
      output.close()
 
      input.close()
 
 
 
class ConsoleView(Gtk.TextView):
 
  def __init__(self):
 
    Gtk.TextView.__init__(self)
light9/Fadable.py
Show inline comments
 
# taken from SnackMix -- now that's reusable code
 
from tkinter.tix import *
 
import time
 

	
 

	
 
class Fadable:
 
    """Fading mixin: must mix in with a Tk widget (or something that has
 
    'after' at least) This is currently used by VolumeBox and MixerTk.
light9/FlyingFader.py
Show inline comments
 
from tkinter.tix import *
 
from time import time, sleep
 

	
 
from tkinter import tix
 
from time import time
 

	
 
class Mass:
 

	
 
    def __init__(self):
 
        self.x = 0  # position
 
        self.xgoal = 0  # position goal
 
@@ -62,23 +61,23 @@ class Mass:
 
        self.xgoal = newx
 

	
 
    def ismoving(self):
 
        return not self._stopped
 

	
 

	
 
class FlyingFader(Frame):
 
class FlyingFader(tix.Frame):
 

	
 
    def __init__(self,
 
                 master,
 
                 variable,
 
                 label,
 
                 fadedur=1.5,
 
                 font=('Arial', 8),
 
                 labelwidth=12,
 
                 **kw):
 
        Frame.__init__(self, master)
 
        tix.Frame.__init__(self, master)
 
        self.name = label
 
        self.variable = variable
 

	
 
        self.mass = Mass()
 

	
 
        self.config({'bd': 1, 'relief': 'raised'})
 
@@ -91,31 +90,29 @@ class FlyingFader(Frame):
 
            'width': 20,
 
            'length': 200,
 
            'orient': 'vert'
 
        }
 
        scaleopts.update(kw)
 
        if scaleopts['orient'] == 'vert':
 
            side1 = TOP
 
            side2 = BOTTOM
 
            side2 = tix.BOTTOM
 
        else:
 
            side1 = RIGHT
 
            side2 = LEFT
 
            side2 = tix.LEFT
 

	
 
        self.scale = Scale(self, **scaleopts)
 
        self.vlabel = Label(self, text="0.0", width=6, font=font)
 
        self.label = Label(self,
 
        self.scale = tix.Scale(self, **scaleopts)
 
        self.vlabel = tix.Label(self, text="0.0", width=6, font=font)
 
        self.label = tix.Label(self,
 
                           text=label,
 
                           font=font,
 
                           anchor='w',
 
                           width=labelwidth)  #wraplength=40, )
 

	
 
        self.oldtrough = self.scale['troughcolor']
 

	
 
        self.scale.pack(side=side2, expand=1, fill=BOTH, anchor='c')
 
        self.vlabel.pack(side=side2, expand=0, fill=X)
 
        self.label.pack(side=side2, expand=0, fill=X)
 
        self.scale.pack(side=side2, expand=1, fill=tix.BOTH, anchor='c')
 
        self.vlabel.pack(side=side2, expand=0, fill=tix.X)
 
        self.label.pack(side=side2, expand=0, fill=tix.X)
 

	
 
        for k in range(1, 10):
 
            self.scale.bind(
 
                "<Key-%d>" % k, lambda evt, k=k: self.newfade(k / 10.0, evt))
 

	
 
        self.scale.bind("<Key-0>", lambda evt: self.newfade(1.0, evt))
 
@@ -147,13 +144,13 @@ class FlyingFader(Frame):
 
    def newfade(self, newlevel, evt=None, length=None):
 

	
 
        # these are currently unused-- Mass needs to accept a speed input
 
        mult = 1
 
        if evt.state & 8 and evt.state & 4: mult = 0.25  # both
 
        elif evt.state & 8: mult = 0.5  # alt
 
        elif evt.state & 4: mult = 2  # control
 
        elif evt.state & 4: mult = 2  # control # noqa
 

	
 
        self.mass.x = self.variable.get()
 
        self.mass.goto(newlevel)
 

	
 
        self.gofade()
 

	
 
@@ -201,25 +198,22 @@ def colorfade(scale, lev):
 
    out = [int(l + lev * (h - l)) for h, l in zip(high, low)]
 
    col = "#%02X%02X%02X" % tuple(out)
 
    scale.config(troughcolor=col)
 

	
 

	
 
if __name__ == '__main__':
 
    root = Tk()
 
    root = tix.Tk()
 
    root.tk_focusFollowsMouse()
 

	
 
    FlyingFader(root, variable=DoubleVar(), label="suck").pack(side=LEFT,
 
                                                               expand=1,
 
                                                               fill=BOTH)
 
    FlyingFader(root, variable=DoubleVar(), label="moof").pack(side=LEFT,
 
    FlyingFader(root, variable=tix.DoubleVar(),
 
                label="suck").pack(side=tix.LEFT, expand=1, fill=tix.BOTH)
 
    FlyingFader(root, variable=tix.DoubleVar(),
 
                label="moof").pack(side=tix.LEFT, expand=1, fill=tix.BOTH)
 
    FlyingFader(root, variable=tix.DoubleVar(),
 
                label="zarf").pack(side=tix.LEFT, expand=1, fill=tix.BOTH)
 
    FlyingFader(root,
 
                variable=tix.DoubleVar(),
 
                label="long name goes here.  got it?").pack(side=tix.LEFT,
 
                                                               expand=1,
 
                                                               fill=BOTH)
 
    FlyingFader(root, variable=DoubleVar(), label="zarf").pack(side=LEFT,
 
                                                               expand=1,
 
                                                               fill=BOTH)
 
    FlyingFader(root,
 
                variable=DoubleVar(),
 
                label="long name goes here.  got it?").pack(side=LEFT,
 
                                                            expand=1,
 
                                                            fill=BOTH)
 
                                                            fill=tix.BOTH)
 

	
 
    root.mainloop()
light9/Patch.py
Show inline comments
 
import os
 
from rdflib import RDF
 
from light9.namespaces import L9
 
from light9 import showconfig
 

	
 

	
 
def resolve_name(channelname):
light9/Submaster.py
Show inline comments
 
import os, logging, time
 
import logging
 
from rdflib import Graph, RDF
 
from rdflib import RDFS, Literal, BNode
 
from light9.namespaces import L9, XSD
 
from light9.TLUtility import dict_scale, dict_max
 
from light9 import showconfig
 
from light9.Patch import resolve_name, get_dmx_channel, get_channel_uri, reload_data
 
from light9.Patch import resolve_name, get_dmx_channel, get_channel_uri
 
from louie import dispatcher
 
from .rdfdb.patch import Patch
 
from rdfdb.patch import Patch
 
log = logging.getLogger('submaster')
 

	
 

	
 
class Submaster(object):
 
    """mapping of channels to levels"""
 

	
 
@@ -70,13 +70,13 @@ class Submaster(object):
 
        return "<'%s': [%s]>" % (getattr(self, 'name', 'no name yet'), levels)
 

	
 
    def __cmp__(self, other):
 
        # not sure how useful this is
 
        if not isinstance(other, Submaster):
 
            return -1
 
        return cmp(self.ident(), other.ident())
 
        return cmp(self.ident(), other.ident()) # noqa
 

	
 
    def __hash__(self):
 
        return hash(self.ident())
 

	
 
    def get_dmx_list(self):
 
        leveldict = self.get_levels()  # gets levels of sub contents
 
@@ -186,13 +186,13 @@ class PersistentSubmaster(Submaster):
 
            if not name:
 
                log.error("sub %r has channel %r with no name- "
 
                          "leaving out that channel" % (self.name, chan))
 
                continue
 
            try:
 
                self.levels[name] = float(val)
 
            except:
 
            except Exception:
 
                log.error("name %r val %r" % (name, val))
 
                raise
 

	
 
    def _saveContext(self):
 
        """the context in which we should save all the lightLevel triples for
 
        this sub"""
 
@@ -323,17 +323,17 @@ class Submasters(object):
 
            del self.submasters[s]
 
            dispatcher.send("lost submaster", subUri=s)
 
        log.info("findSubs finished, %s subs", len(self.submasters))
 

	
 
    def get_all_subs(self):
 
        "All Submaster objects"
 
        l = sorted(list(self.submasters.items()))
 
        l = [x[1] for x in l]
 
        v = sorted(list(self.submasters.items()))
 
        v = [x[1] for x in v]
 
        songs = []
 
        notsongs = []
 
        for s in l:
 
        for s in v:
 
            if s.name and s.name.startswith('song'):
 
                songs.append(s)
 
            else:
 
                notsongs.append(s)
 
        combined = notsongs + songs
 

	
light9/TLUtility.py
Show inline comments
 
@@ -53,13 +53,13 @@ def enumerate(*collections):
 
def dumpobj(o):
 
    """Prints all the object's non-callable attributes"""
 
    print(repr(o))
 
    for a in [x for x in dir(o) if not callable(getattr(o, x))]:
 
        try:
 
            print("  %20s: %s " % (a, getattr(o, a)))
 
        except:
 
        except Exception:
 
            pass
 
    print("")
 

	
 

	
 
def dict_filter_update(d, **newitems):
 
    """Adds a set of new keys and values to dictionary 'd' if the values are
 
@@ -187,13 +187,13 @@ def dict_max(*dicts):
 
            newdict[k] = max(v, newdict.get(k, 0))
 
    return newdict
 

	
 

	
 
def dict_scale(d, scl):
 
    """scales all values in dict and returns a new dict"""
 
    return dict([(k, v * scl) for k, v in list(d.items())])
 
    return dict([(k, v * scl) for k, v in d.items()])
 

	
 

	
 
def dict_subset(d, dkeys, default=0):
 
    """Subset of dictionary d: only the keys in dkeys.  If you plan on omitting
 
    keys, make sure you like the default."""
 
    newd = {}  # dirty variables!
light9/ascoltami/player.py
Show inline comments
 
#!/usr/bin/python
 
"""
 
alternate to the mpd music player, for ascoltami
 
"""
 

	
 
import time, logging, traceback
 
from gi.repository import GObject, Gst
 
from twisted.internet import reactor, task
 
from gi.repository import Gst
 
from twisted.internet import task
 

	
 
log = logging.getLogger()
 

	
 

	
 
class Player(object):
 

	
 
@@ -27,13 +27,13 @@ class Player(object):
 
        self.autoStopTime = 0
 
        self.lastSetSongUri = None
 
        self.onEOS = onEOS
 

	
 
        task.LoopingCall(self.watchTime).start(.050)
 

	
 
        bus = self.pipeline.get_bus()
 
        #bus = self.pipeline.get_bus()
 
        # not working- see notes in pollForMessages
 
        #self.watchForMessages(bus)
 

	
 
    def watchTime(self):
 
        try:
 
            self.pollForMessages()
 
@@ -43,13 +43,13 @@ class Player(object):
 
                      self.autoStopTime, t)
 
            if self.lastWatchTime < self.autoStopTime < t:
 
                log.info("autostop")
 
                self.pause()
 

	
 
            self.lastWatchTime = t
 
        except:
 
        except Exception:
 
            traceback.print_exc()
 

	
 
    def watchForMessages(self, bus):
 
        """this would be nicer than pollForMessages but it's not working for
 
        me. It's like add_signal_watch isn't running."""
 
        bus.add_signal_watch()
light9/ascoltami/playlist.py
Show inline comments
 
@@ -16,19 +16,19 @@ class Playlist(object):
 
    def nextSong(self, currentSong):
 
        """Returns the next song in the playlist or raises NoSuchSong if 
 
        we are at the end of the playlist."""
 
        try:
 
            currentIndex = self.songs.index(currentSong)
 
        except IndexError:
 
            raise ValueError("%r is not in the current playlist (%r)." % \
 
            raise ValueError("%r is not in the current playlist (%r)." %
 
                (currentSong, self.playlistUri))
 

	
 
        try:
 
            nextSong = self.songs[currentIndex + 1]
 
        except IndexError:
 
            raise NoSuchSong("%r is the last item in the playlist." % \
 
            raise NoSuchSong("%r is the last item in the playlist." %
 
                             currentSong)
 

	
 
        return nextSong
 

	
 
    def allSongs(self):
 
        """Returns a list of all song URIs in order."""
light9/ascoltami/webapp.py
Show inline comments
 
import json, socket, subprocess, cyclone.web, os
 
import json, socket, subprocess, cyclone.web
 
from twisted.python.util import sibpath
 
from twisted.python.filepath import FilePath
 
from light9.namespaces import L9
 
from light9.showconfig import getSongsFromShow, songOnDisk
 
from rdflib import URIRef
 
from web.contrib.template import render_genshi
 
render = render_genshi([sibpath(__file__, ".")], auto_reload=True)
 

	
 
@@ -137,13 +136,13 @@ class output(PrettyErrorHandler, cyclone
 
class goButton(PrettyErrorHandler, cyclone.web.RequestHandler):
 

	
 
    def post(self):
 
        """
 
        if music is playing, this silently does nothing.
 
        """
 
        graph, player = self.settings.app.graph, self.settings.app.player
 
        player = self.settings.app.player
 

	
 
        if player.isAutostopped():
 
            player.resume()
 
        elif player.isPlaying():
 
            pass
 
        else:
light9/coffee.py
Show inline comments
 
new file 100644
 
from cycloneerr import PrettyErrorHandler
 
import cyclone.web
 
import subprocess
 

	
 

	
 
class StaticCoffee(PrettyErrorHandler, cyclone.web.RequestHandler):
 
    """
 
    e.g.
 

	
 
            (r'/effect\.js', StaticCoffee, {
 
                'src': 'light9/effecteval/effect.coffee'
 
            }),
 
    """ # noqa
 

	
 
    def initialize(self, src):
 
        super(StaticCoffee, self).initialize()
 
        self.src = src
 

	
 
    def get(self):
 
        self.set_header('Content-Type', 'application/javascript')
 
        self.write(
 
            subprocess.check_output(
 
                ['/usr/bin/coffee', '--compile', '--print', self.src]))
light9/collector/collector.py
Show inline comments
 
@@ -4,14 +4,15 @@ from rdflib import Literal
 
from light9.namespaces import L9, RDF
 
from light9.collector.output import setListElem
 
from light9.collector.device import toOutputAttrs, resolve
 

	
 
# types only
 
from rdflib import Graph, URIRef
 
from typing import List, Dict, Tuple, Any, TypeVar, Generic
 
from typing import List, Dict, Tuple, TypeVar, Generic, Optional
 
from light9.collector.output import Output
 
from light9.collector.weblisteners import WebListeners
 

	
 
ClientType = TypeVar('ClientType')
 
ClientSessionType = TypeVar('ClientSessionType')
 

	
 
log = logging.getLogger('collector')
 

	
 
@@ -21,13 +22,13 @@ def outputMap(graph, outputs):
 
    """From rdf config graph, compute a map of
 
       (device, outputattr) : (output, index)
 
    that explains which output index to set for any device update.
 
    """
 
    ret = {}
 

	
 
    outputByUri = {}  # universeUri : output
 
    outputByUri: Dict[URIRef, Output] = {}  # universeUri : output
 
    for out in outputs:
 
        outputByUri[out.uri] = out
 

	
 
    for dc in graph.subjects(RDF.type, L9['DeviceClass']):
 
        log.info('mapping DeviceClass %s', dc)
 
        for dev in graph.subjects(RDF.type, dc):
 
@@ -47,14 +48,17 @@ def outputMap(graph, outputs):
 
                log.debug('    map %s to %s,%s', outputAttr, output, index)
 
    return ret
 

	
 

	
 
class Collector(Generic[ClientType, ClientSessionType]):
 

	
 
    def __init__(self, graph, outputs, listeners=None, clientTimeoutSec=10):
 
        # type: (Graph, List[Output], List[Listener], float) -> None
 
    def __init__(self,
 
                 graph: Graph,
 
                 outputs: List[Output],
 
                 listeners: Optional[WebListeners] = None,
 
                 clientTimeoutSec: float = 10):
 
        self.graph = graph
 
        self.outputs = outputs
 
        self.listeners = listeners
 
        self.clientTimeoutSec = clientTimeoutSec
 
        self.initTime = time.time()
 
        self.allDevices = set()
light9/collector/collector_test.py
Show inline comments
 
import unittest
 
import datetime, time
 
from freezegun import freeze_time
 
from rdflib import Namespace, URIRef
 
from rdflib import Namespace
 

	
 
from light9.namespaces import L9, DEV
 
from light9.collector.collector import Collector, outputMap
 
from rdfdb.mock_syncedgraph import MockSyncedGraph
 

	
 
UDMX = Namespace('http://light9.bigasterisk.com/output/udmx/')
light9/collector/device.py
Show inline comments
 
import logging
 
import math
 
from light9.namespaces import L9, RDF, DEV
 
from light9.namespaces import L9
 
from rdflib import Literal
 
from webcolors import hex_to_rgb, rgb_to_hex
 
from colormath.color_objects import sRGBColor, CMYColor
 
import colormath.color_conversions
 

	
 
log = logging.getLogger('device')
light9/collector/output.py
Show inline comments
 
from rdflib import URIRef
 
import sys
 
import time
 
import usb.core
 
import logging
 
from twisted.internet import task, threads, reactor
 
from twisted.internet import threads, reactor
 
from greplin import scales
 
log = logging.getLogger('output')
 

	
 

	
 
# eliminate this: lists are always padded now
 
def setListElem(outList, index, value, fill=0, combine=lambda old, new: new):
light9/collector/weblisteners.py
Show inline comments
 
new file 100644
 
import logging, traceback, time, json
 
log = logging.getLogger('weblisteners')
 

	
 
class WebListeners(object):
 

	
 
    def __init__(self):
 
        self.clients = []
 
        self.pendingMessageForDev = {}  # dev: (attrs, outputmap)
 
        self.lastFlush = 0
 

	
 
    def addClient(self, client):
 
        self.clients.append([client, {}])  # seen = {dev: attrs}
 
        log.info('added client %s %s', len(self.clients), client)
 

	
 
    def delClient(self, client):
 
        self.clients = [[c, t] for c, t in self.clients if c != client]
 
        log.info('delClient %s, %s left', client, len(self.clients))
 

	
 
    def outputAttrsSet(self, dev, attrs, outputMap):
 
        """called often- don't be slow"""
 

	
 
        self.pendingMessageForDev[dev] = (attrs, outputMap)
 
        try:
 
            self._flush()
 
        except Exception:
 
            traceback.print_exc()
 
            raise
 

	
 
    def _flush(self):
 
        now = time.time()
 
        if now < self.lastFlush + .05 or not self.clients:
 
            return
 
        self.lastFlush = now
 

	
 
        while self.pendingMessageForDev:
 
            dev, (attrs, outputMap) = self.pendingMessageForDev.popitem()
 

	
 
            msg = None  # lazy, since makeMsg is slow
 

	
 
            # this omits repeats, but can still send many
 
            # messages/sec. Not sure if piling up messages for the browser
 
            # could lead to slowdowns in the real dmx output.
 
            for client, seen in self.clients:
 
                if seen.get(dev) == attrs:
 
                    continue
 
                if msg is None:
 
                    msg = self.makeMsg(dev, attrs, outputMap)
 

	
 
                seen[dev] = attrs
 
                client.sendMessage(msg)
 

	
 
    def makeMsg(self, dev, attrs, outputMap):
 
        attrRows = []
 
        for attr, val in attrs.items():
 
            output, index = outputMap[(dev, attr)]
 
            attrRows.append({
 
                'attr': attr.rsplit('/')[-1],
 
                'val': val,
 
                'chan': (output.shortId(), index + 1)
 
            })
 
        attrRows.sort(key=lambda r: r['chan'])
 
        for row in attrRows:
 
            row['chan'] = '%s %s' % (row['chan'][0], row['chan'][1])
 

	
 
        msg = json.dumps({'outputAttrsSet': {
 
            'dev': dev,
 
            'attrs': attrRows
 
        }},
 
                         sort_keys=True)
 
        return msg
light9/curvecalc/client.py
Show inline comments
 
"""
 
client code for talking to curvecalc
 
"""
 
import cyclone.httpclient
 
from light9 import networking
 
import urllib.request, urllib.parse, urllib.error
 
from run_local import log
 

	
 

	
 
def sendLiveInputPoint(curve, value):
 
    f = cyclone.httpclient.fetch(networking.curveCalc.path('liveInputPoint'),
 
                                 method='POST',
 
                                 timeout=1,
light9/curvecalc/curve.py
Show inline comments
 
import glob, time, logging, ast, os
 
import logging, ast, os
 
from bisect import bisect_left, bisect
 
import louie as dispatcher
 
from twisted.internet import reactor
 
from rdflib import Literal
 
from light9 import showconfig
 
from light9.namespaces import L9, RDF, RDFS
 
@@ -42,13 +42,13 @@ class Curve(object):
 

	
 
    def toggleMute(self):
 
        self.muted = not self.muted
 

	
 
    def load(self, filename):
 
        self.points[:] = []
 
        for line in file(filename):
 
        for line in open(filename):
 
            x, y = line.split()
 
            self.points.append((float(x), ast.literal_eval(y)))
 
        self.points.sort()
 
        dispatcher.send("points changed", sender=self)
 

	
 
    def set_from_string(self, pts):
 
@@ -72,13 +72,13 @@ class Curve(object):
 

	
 
    def save(self, filename):
 
        # this is just around for markers, now
 
        if filename.endswith('-music') or filename.endswith('_music'):
 
            print("not saving music track")
 
            return
 
        f = file(filename, 'w')
 
        f = open(filename, 'w')
 
        for p in self.points:
 
            f.write("%s %r\n" % p)
 
        f.close()
 

	
 
    def eval(self, t, allow_muting=True):
 
        if self.muted and allow_muting:
light9/curvecalc/curveedit.py
Show inline comments
 
"""
 
this may be split out from curvecalc someday, since it doesn't
 
need to be tied to a gui """
 
import cgi, time
 
import cgi
 
from twisted.internet import reactor
 
import cyclone.web, cyclone.httpclient, cyclone.websocket
 
from rdflib import URIRef
 
from cycloneerr import PrettyErrorHandler
 
from run_local import log
 
from louie import dispatcher
 

	
 

	
 
def serveCurveEdit(port, hoverTimeResponse, curveset):
 
    """
 
    /hoverTime requests actually are handled by the curvecalc gui
light9/curvecalc/curveview.py
Show inline comments
 
import math, logging, traceback
 
import math, logging
 
from gi.repository import Gtk
 
from gi.repository import Gdk
 
from gi.repository import GooCanvas
 
import louie as dispatcher
 
from rdflib import Literal
 
from twisted.internet import reactor
 
from light9.curvecalc.zoomcontrol import RegionZoom
 
from light9.curvecalc import cursors
 
from light9.curvecalc.curve import introPad, postPad
 
from lib.goocanvas_compat import Points, polyline_new_line
 
import imp
 

	
 
log = logging.getLogger()
 
print("curveview.py toplevel")
 
@@ -1273,14 +1272,14 @@ class Curvesetview(object):
 
                self.curveRow_from_name(n).box, Gtk.PACK_START)
 

	
 
    def onKeyPress(self, widget, event):
 
        if not self.live:  # workaround for old instances living past reload()
 
            return
 

	
 
        r = self.row_under_mouse()
 
        key = event.string
 
        #r = self.row_under_mouse()
 
        #key = event.string
 
        pass  # no handlers right now
 

	
 
    def row_under_mouse(self):
 
        x, y = self.curvesVBox.get_pointer()
 
        for r in self.allCurveRows:
 
            inRowX, inRowY = self.curvesVBox.translate_coordinates(r.box, x, y)
light9/curvecalc/output.py
Show inline comments
 
import time, logging
 
from twisted.internet import reactor
 
from light9 import Submaster, dmxclient
 
from light9.namespaces import L9
 
from light9.curvecalc.subterm import Subterm
 

	
 
from louie import dispatcher
 
log = logging.getLogger("output")
 

	
 

	
 
class Output(object):
light9/curvecalc/subterm.py
Show inline comments
 
import math, os, random, logging
 
from rdflib import Graph, URIRef, RDF, RDFS, Literal
 
import logging
 
from rdflib import Literal
 
from louie import dispatcher
 
import light9.Effects
 
from light9 import Submaster, showconfig, prof
 
from light9 import Submaster
 
from light9.Patch import get_dmx_channel
 
from rdfdb.patch import Patch
 
from light9.namespaces import L9
 
log = logging.getLogger()
 

	
 

	
light9/curvecalc/zoomcontrol.py
Show inline comments
 
from gi.repository import Gtk
 
from gi.repository import GObject
 
from gi.repository import GooCanvas
 
import louie as dispatcher
 
from light9.curvecalc import cursors
 
from lib.goocanvas_compat import Points, polyline_new_line
 
from twisted.internet import reactor
 

	
light9/dmxchanedit.py
Show inline comments
 
@@ -15,13 +15,13 @@ proposal for new attribute system:
 
- we always want to plan some attributes for each light: where to center; what stage to cover; what color gel to apply; whether the light is burned out
 
- we have to stop packing these into the names. Names should be like 'b33' or 'blue3' or just '44'. maybe 'blacklight'.
 

	
 
"""
 

	
 
import tkinter as tk
 
from rdflib import RDF, Literal
 
from rdflib import RDF
 
import math, logging
 
from decimal import Decimal
 
from light9.namespaces import L9
 
log = logging.getLogger('dmxchanedit')
 
stdfont = ('Arial', 7)
 

	
light9/dmxclient.py
Show inline comments
 
@@ -69,8 +69,8 @@ def outputlevels(levellist, twisted=0, c
 

	
 

	
 
dummy = os.getenv('DMXDUMMY')
 
if dummy:
 
    print("dmxclient: DMX is in dummy mode.")
 

	
 
    def outputlevels(*args, **kw):
 
    def outputlevels(*args, **kw): # noqa
 
        pass
light9/effect/effecteval.py
Show inline comments
 
from rdflib import URIRef, Literal
 
from light9.namespaces import L9, RDF, DEV
 
from rdflib import Literal
 
from light9.namespaces import L9, DEV
 
from webcolors import rgb_to_hex, hex_to_rgb
 
from colorsys import hsv_to_rgb
 
from decimal import Decimal
 
import math
 
import traceback
 
from noise import pnoise1
 
import logging
 
import time
 
from light9.effect.settings import DeviceSettings
 
from light9.effect.scale import scale
 
import random
 
random.seed(0)
 
print("reload effecteval")
 

	
 
@@ -132,13 +129,12 @@ def effect_animRainbow(effectSettings, s
 
    return out
 

	
 

	
 
def effect_auraSparkles(effectSettings, strength, songTime, noteTime):
 
    out = {}
 
    tint = effectSettings.get(L9['tint'], '#ffffff')
 
    tintStrength = float(effectSettings.get(L9['tintStrength'], 0))
 
    print(effectSettings)
 
    tr, tg, tb = hex_to_rgb(tint)
 
    for n in range(1, 5 + 1):
 
        scl = strength * ((int(songTime * 10) % n) < 1)
 
        col = literalColorHsv((songTime + (n / 5)) % 1, 1, scl)
 

	
light9/effect/sequencer.py
Show inline comments
 
@@ -41,13 +41,15 @@ class Note(object):
 
        self.baseEffectSettings = {}  # {effectAttr: value}
 
        for s in g.objects(uri, L9['setting']):
 
            settingValues = dict(g.predicate_objects(s))
 
            ea = settingValues[L9['effectAttr']]
 
            self.baseEffectSettings[ea] = settingValues[L9['value']]
 

	
 
        floatVal = lambda s, p: float(g.value(s, p).toPython())
 
        def floatVal(s, p):
 
            return float(g.value(s, p).toPython())
 

	
 
        originTime = floatVal(uri, L9['originTime'])
 
        self.points = []
 
        for curve in g.objects(uri, L9['curve']):
 
            self.points.extend(
 
                self.getCurvePoints(curve, L9['strength'], originTime))
 
        self.points.sort()
light9/effect/settings.py
Show inline comments
 
@@ -3,14 +3,13 @@ Data structure and convertors for a tabl
 
rows. These might be effect attrs ('strength'), device attrs ('rx'),
 
or output attrs (dmx channel).
 
"""
 
import decimal
 
import numpy
 
from rdflib import URIRef, Literal
 
from light9.namespaces import RDF, L9, DEV
 
from rdfdb.patch import Patch
 
from light9.namespaces import RDF, L9
 
import logging
 
log = logging.getLogger('settings')
 
from light9.collector.device import resolve
 

	
 

	
 
def parseHex(h):
light9/effect/settings_test.py
Show inline comments
 
import unittest
 
from rdflib import Literal
 
from rdfdb.patch import Patch
 
from rdfdb.localsyncedgraph import LocalSyncedGraph
 
from light9.namespaces import RDF, L9, DEV
 
from light9.namespaces import L9, DEV
 
from light9.effect.settings import DeviceSettings
 

	
 

	
 
class TestDeviceSettings(unittest.TestCase):
 

	
 
    def setUp(self):
light9/effecteval/effectloop.py
Show inline comments
 
import time, json, logging, traceback
 
import numpy
 
import serial
 
from twisted.internet import reactor, threads
 
from twisted.internet import reactor
 
from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 
from twisted.internet.error import TimeoutError
 
from rdflib import URIRef, Literal
 
from rdflib import URIRef
 
import cyclone.httpclient
 
from light9.namespaces import L9, RDF, RDFS
 
from light9.namespaces import L9, RDF
 
from light9.effecteval.effect import EffectNode
 
from light9 import Effects
 
from light9 import networking
 
from light9 import Submaster
 
from light9 import dmxclient
 
from light9 import prof
 
log = logging.getLogger('effectloop')
 

	
 

	
 
class EffectLoop(object):
 
    """maintains a collection of the current EffectNodes, gets time from
 
    music player, sends dmx"""
light9/gtkpyconsole.py
Show inline comments
 
from lib.ipython_view import IPythonView
 
import gi
 
import gi # noqa
 
from gi.repository import Gtk
 
from gi.repository import Pango
 

	
 

	
 
def togglePyConsole(self, item, user_ns):
 
    """
light9/namespaces.py
Show inline comments
 
from rdflib import Namespace, RDF, RDFS
 
from rdflib import Namespace, RDF, RDFS  # noqa
 

	
 

	
 
# Namespace was showing up in profiles
 
class FastNs(object):
 

	
 
    def __init__(self, base):
light9/paint/solve.py
Show inline comments
 
from light9.namespaces import RDF, L9, DEV
 
from light9.namespaces import L9, DEV
 
from PIL import Image
 
import numpy
 
import scipy.misc, scipy.ndimage, scipy.optimize
 
import cairo
 
import logging
 

	
 
from light9.effect.settings import DeviceSettings, parseHex, toHex
 
from light9.effect.settings import DeviceSettings, parseHex
 

	
 
log = logging.getLogger('solve')
 

	
 
# numpy images in this file are (x, y, c) layout.
 

	
 

	
 
@@ -148,13 +148,13 @@ class Solver(object):
 
    def bestMatch(self, img, device=None):
 
        """the one sample that best matches this image"""
 
        #img = self._blur(img)
 
        results = []
 
        dist = ImageDist(img)
 
        if device is None:
 
            items = list(self.samples.items())
 
            items = self.samples.items()
 
        else:
 
            items = self.samplesForDevice[device]
 
        for uri, img2 in sorted(items):
 
            if img.shape != img2.shape:
 
                log.warn("mismatch %s %s", img.shape, img2.shape)
 
                continue
 
@@ -217,24 +217,24 @@ class Solver(object):
 
        sampleDist = {}
 
        dist = ImageDist(pic0Blur)
 
        for sample, picSample in sorted(self.blurredSamples.items()):
 
            #saveNumpy('/tmp/sample_%s.png' % sample.split('/')[-1],
 
            #          f(picSample))
 
            sampleDist[sample] = dist.distanceTo(picSample)
 
        results = sorted([(d, uri) for uri, d in list(sampleDist.items())])
 
        results = sorted([(d, uri) for uri, d in sampleDist.items()])
 

	
 
        sample = results[0][1]
 

	
 
        # this is wrong; some wrong-alignments ought to be dimmer than full
 
        brightest0 = brightest(pic0)
 
        brightestSample = brightest(self.samples[sample])
 
        #brightestSample = brightest(self.samples[sample])
 

	
 
        if max(brightest0) < 1 / 255:
 
            return DeviceSettings(self.graph, [])
 

	
 
        scale = brightest0 / brightestSample
 
        #scale = brightest0 / brightestSample
 

	
 
        s = DeviceSettings.fromResource(self.graph, sample)
 
        # missing color scale, but it was wrong to operate on all devs at once
 
        return s
 

	
 
    def solveBrute(self, painting):
 
@@ -297,13 +297,13 @@ class Solver(object):
 
        assert isinstance(settings, DeviceSettings)
 
        layers = []
 

	
 
        for dev, devSettings in settings.byDevice():
 
            requestedColor = devSettings.getValue(dev, L9['color'])
 
            candidatePics = []  # (distance, path, picColor)
 
            for sample, s in list(self.sampleSettings.items()):
 
            for sample, s in self.sampleSettings.items():
 
                path = self.path[sample]
 
                otherDevSettings = s.ofDevice(dev)
 
                if not otherDevSettings:
 
                    continue
 
                dist = devSettings.distanceTo(otherDevSettings)
 
                log.info('  candidate pic %s %s dist=%s', sample, path, dist)
light9/paint/solve_test.py
Show inline comments
 
import unittest
 
import numpy.testing
 
from . import solve
 
from rdflib import Namespace
 
from light9.namespaces import RDF, L9, DEV
 
from light9.namespaces import L9, DEV
 
from rdfdb.localsyncedgraph import LocalSyncedGraph
 
from light9.effect.settings import DeviceSettings
 

	
 

	
 
class TestSolve(unittest.TestCase):
 

	
light9/showconfig.py
Show inline comments
 
import logging, warnings
 
from twisted.python.filepath import FilePath
 
from os import path, getenv
 
from rdflib import Graph
 
from rdflib import URIRef
 
from .namespaces import MUS, L9
 
from .namespaces import L9
 
log = logging.getLogger('showconfig')
 

	
 
_config = None  # graph
 

	
 

	
 
def getGraph():
light9/subclient.py
Show inline comments
 
from light9.collector.collector_client import sendToCollector
 
from twisted.internet import reactor, task
 
from twisted.internet import reactor
 
import traceback
 
import time
 
import logging
 
log = logging.getLogger()
 

	
 

	
 
@@ -35,10 +35,10 @@ class SubClient:
 
        d.addCallbacks(done, err)
 

	
 
    def _send_sub(self):
 
        try:
 
            with self.graph.currentState() as g:
 
                outputSettings = self.get_output_settings(_graph=g)
 
        except:
 
        except Exception:
 
            traceback.print_exc()
 
            return
 
        return sendToCollector('subclient', self.session, outputSettings)
light9/uihelpers.py
Show inline comments
 
@@ -30,13 +30,13 @@ def toplevel_savegeometry(tl, name):
 
    try:
 
        geo = tl.geometry()
 
        if not geo.startswith("1x1"):
 
            f = open(".light9-window-geometry-%s" % name.replace(' ', '_'), 'w')
 
            f.write(tl.geometry())
 
        # else the window never got mapped
 
    except Exception as e:
 
    except Exception:
 
        # it's ok if there's no saved geometry
 
        pass
 

	
 

	
 
def toplevelat(name, existingtoplevel=None, graph=None, session=None):
 
    tl = existingtoplevel or Toplevel()
light9/vidref/main.py
Show inline comments
 
@@ -76,13 +76,13 @@ class Gui(object):
 

	
 
    def updateLoop(self):
 
        position = self.musicTime.getLatest()
 
        try:
 
            with gtk.gdk.lock:
 
                self.replayViews.update(position)
 
        except:
 
        except Exception:
 
            traceback.print_exc()
 
        return True
 

	
 
    def getInputs(self):
 
        return ['auto', 'dv', 'video0']
 

	
light9/vidref/musictime.py
Show inline comments
 
import restkit, time, json, logging
 
import time, json, logging
 
from light9 import networking
 
from twisted.internet import reactor
 
from cyclone.httpclient import fetch
 
from restkit.errors import ResourceNotFound
 
import http_parser.http
 
log = logging.getLogger()
 

	
 

	
 
class MusicTime(object):
 
    """
 
    fetch times from ascoltami in a background thread; return times
 
@@ -26,13 +24,12 @@ class MusicTime(object):
 
        make up times between the samples, and we'll just run off the
 
        end of a song)
 
        """
 
        self.period = period
 
        self.hoverPeriod = .05
 
        self.onChange = onChange
 
        self.musicResource = restkit.Resource(networking.musicPlayer.url)
 

	
 
        self.position = {}
 
        # driven by our pollCurvecalcTime and also by Gui.incomingTime
 
        self.lastHoverTime = None  # None means "no recent value"
 
        self.pollMusicTime()
 
        if pollCurvecalc:
 
@@ -122,9 +119,12 @@ class MusicTime(object):
 
        d = fetch(networking.curveCalc.path("hoverTime"))
 
        d.addCallback(cb)
 
        d.addErrback(eb)  # note this includes errors in cb()
 

	
 
    def sendTime(self, t):
 
        """request that the player go to this time"""
 
        self.musicResource.post("time",
 
                                payload=json.dumps({"t": t}),
 
                                headers={"content-type": "application/json"})
 
        fetch(
 
            method=b'POST',
 
            url=networking.musicPlayer.path('time'),
 
            body=json.dumps({"t": t}),
 
            headers={b"content-type": [b"application/json"]},
 
        )
light9/vidref/remotepivideo.py
Show inline comments
 
@@ -3,14 +3,14 @@ like videorecorder.py, but talks to a bi
 
"""
 
import os, time, logging
 
import gtk
 
import numpy
 
import treq
 
from twisted.internet import defer
 
from light9.vidref.replay import framerate, songDir, takeDir, snapshotDir
 
from light9 import prof, showconfig
 
from light9.vidref.replay import songDir, takeDir, snapshotDir
 
from light9 import showconfig
 
from light9.namespaces import L9
 
from PIL import Image
 
from io import StringIO
 
log = logging.getLogger('remotepi')
 

	
 

	
light9/vidref/videorecorder.py
Show inline comments
 
@@ -155,13 +155,13 @@ class VideoRecordSink(gst.Element):
 
        try:
 
            cap = buffer.caps[0]
 
            #print "cap", (cap['width'], cap['height'])
 
            img = Image.fromstring('RGB', (cap['width'], cap['height']),
 
                                   buffer.data)
 
            self.imagesToSave.put((position, img, buffer.timestamp))
 
        except:
 
        except Exception:
 
            traceback.print_exc()
 

	
 
        return gst.FLOW_OK
 

	
 
    def saveImg(self, position, img, bufferTimestamp):
 
        if not position['song']:
light9/wavepoints.py
Show inline comments
 
import wave, audioop
 

	
 

	
 
def simp(filename, seconds_per_average=0.001):
 
    """smaller seconds_per_average means fewer data points"""
 
    wavefile = wave.open(filename, 'rb')
 
    print("# gnuplot data for %s, seconds_per_average=%s" % \
 
    print("# gnuplot data for %s, seconds_per_average=%s" %
 
        (filename, seconds_per_average))
 
    print(
 
        "# %d channels, samplewidth: %d, framerate: %s, frames: %d\n# Compression type: %s (%s)"
 
        % wavefile.getparams())
 

	
 
    framerate = wavefile.getframerate()  # frames / second
 

	
 
    frames_to_read = int(framerate * seconds_per_average)
 
    print("# frames_to_read=%s" % frames_to_read)
 

	
 
    time_and_max = []
 
    values = []
 
    count = 0
light9/zmqtransport.py
Show inline comments
 
new file 100644
 
import json
 
from rdflib import URIRef, Literal
 
from greplin import scales
 
from txzmq import ZmqEndpoint, ZmqFactory, ZmqPullConnection
 
import logging
 

	
 
log = logging.getLogger('zmq')
 

	
 

	
 
def parseJsonMessage(msg):
 
    body = json.loads(msg)
 
    settings = []
 
    for device, attr, value in body['settings']:
 
        if isinstance(value, str) and value.startswith('http'):
 
            value = URIRef(value)
 
        else:
 
            value = Literal(value)
 
        settings.append((URIRef(device), URIRef(attr), value))
 
    return body['client'], body['clientSession'], settings, body['sendTime']
 

	
 

	
 
def startZmq(port, collector):
 
    stats = scales.collection('/zmqServer', scales.PmfStat('setAttr'))
 

	
 
    zf = ZmqFactory()
 
    addr = 'tcp://*:%s' % port
 
    log.info('creating zmq endpoint at %r', addr)
 
    e = ZmqEndpoint('bind', addr)
 

	
 
    class Pull(ZmqPullConnection):
 
        #highWaterMark = 3
 
        def onPull(self, message):
 
            with stats.setAttr.time():
 
                # todo: new compressed protocol where you send all URIs up
 
                # front and then use small ints to refer to devices and
 
                # attributes in subsequent requests.
 
                client, clientSession, settings, sendTime = parseJsonMessage(
 
                    message[0])
 
                collector.setAttrs(client, clientSession, settings, sendTime)
 

	
 
    Pull(zf, e)
0 comments (0 inline, 0 general)