# HG changeset patch # User drewp@bigasterisk.com # Date 2019-06-08 07:45:25 # Node ID f66dbe51202556782fd1d1c38295d69988c51d8f # Parent 9a81855ec766d99d0f3befc54afcda5242ee3ffb reformat Ignore-this: c968c4cd1b9a580c7b0fedc00df8a80 diff --git a/bin/ascoltami2 b/bin/ascoltami2 --- a/bin/ascoltami2 +++ b/bin/ascoltami2 @@ -17,6 +17,7 @@ from gi.repository import GObject, Gst gatherProcessStats() + class App(object): def __init__(self, graph, show): diff --git a/bin/effecteval b/bin/effecteval --- a/bin/effecteval +++ b/bin/effecteval @@ -23,6 +23,7 @@ from light9.coffee import StaticCoffee gatherProcessStats() + class EffectEdit(PrettyErrorHandler, cyclone.web.RequestHandler): def get(self): diff --git a/light9/collector/collector.py b/light9/collector/collector.py --- a/light9/collector/collector.py +++ b/light9/collector/collector.py @@ -202,7 +202,9 @@ class Collector: index = DmxMessageIndex(_index) _, outArray = pendingOut[outputUri] if outArray[index] != 0: - log.warn(f'conflict: {output} output array was already nonzero at 0-based index {index}') + log.warn( + f'conflict: {output} output array was already nonzero at 0-based index {index}' + ) raise ValueError(f"someone already wrote to index {index}") outArray[index] = value diff --git a/light9/collector/dmx_controller_output.py b/light9/collector/dmx_controller_output.py --- a/light9/collector/dmx_controller_output.py +++ b/light9/collector/dmx_controller_output.py @@ -11,13 +11,15 @@ from pyftdi import ftdi #FTDI device info -vendor=0x0403 -product=0x6001 +vendor = 0x0403 +product = 0x6001 + ##################### # DMX USB controller ##################### class OpenDmxUsb(): + def __init__(self): self.baud_rate = 250000 self.data_bits = 8 @@ -29,30 +31,43 @@ class OpenDmxUsb(): #Initialize the controller def _init_dmx(self): - self.ftdi=ftdi.Ftdi() - self.ftdi.open(vendor,product,0) + self.ftdi = ftdi.Ftdi() + self.ftdi.open(vendor, product, 0) self.ftdi.set_baudrate(self.baud_rate) - self.ftdi.set_line_property(self.data_bits,self.stop_bits,self.parity,break_=0) + self.ftdi.set_line_property(self.data_bits, + self.stop_bits, + self.parity, + break_=0) self.ftdi.set_flowctrl(self.flow_ctrl) self.ftdi.purge_rx_buffer() self.ftdi.purge_tx_buffer() self.ftdi.set_rts(self.rts_state) #Send DMX data - def send_dmx(self,channelVals): + def send_dmx(self, channelVals): assert self.ftdi.write_data(channelVals) == 513 # Need to generate two bits for break - self.ftdi.set_line_property(self.data_bits,self.stop_bits,self.parity,break_=1) - self.ftdi.set_line_property(self.data_bits,self.stop_bits,self.parity,break_=1) - self.ftdi.set_line_property(self.data_bits,self.stop_bits,self.parity,break_=0) + self.ftdi.set_line_property(self.data_bits, + self.stop_bits, + self.parity, + break_=1) + self.ftdi.set_line_property(self.data_bits, + self.stop_bits, + self.parity, + break_=1) + self.ftdi.set_line_property(self.data_bits, + self.stop_bits, + self.parity, + break_=0) -if __name__=="__main__": - dmxUsb=OpenDmxUsb() + +if __name__ == "__main__": + dmxUsb = OpenDmxUsb() - channelVals=bytearray([0]*513) - channelVals[0]=0 # dummy channel 0 - while(True): - for x in range(1,468+1): + channelVals = bytearray([0] * 513) + channelVals[0] = 0 # dummy channel 0 + while (True): + for x in range(1, 468 + 1): channelVals[x] = 255 dmxUsb.send_dmx(channelVals) diff --git a/light9/collector/output.py b/light9/collector/output.py --- a/light9/collector/output.py +++ b/light9/collector/output.py @@ -28,10 +28,8 @@ class Output(object): scales.init(self, self.statPath) self._writeStats = scales.collection( - self.statPath + '/write', - scales.IntStat('succeed'), - scales.IntStat('fail'), - scales.PmfStat('call', recalcPeriod=1), + self.statPath + '/write', scales.IntStat('succeed'), + scales.IntStat('fail'), scales.PmfStat('call', recalcPeriod=1), scales.RecentFpsStat('fps')) self._currentBuffer = b'' @@ -42,7 +40,7 @@ class Output(object): def reconnect(self): pass - + def shortId(self) -> str: """short string to distinguish outputs""" return self.uri.rstrip('/').rsplit('/')[-1] @@ -57,7 +55,7 @@ class Output(object): if msg != self._lastLoggedMsg: log.debug(msg) self._lastLoggedMsg = msg - + def _write(self, buf: bytes) -> None: """ write buffer to output hardware (may be throttled if updates are @@ -69,6 +67,7 @@ class Output(object): log.error('unrecoverable- exiting') reactor.crash() + class DummyOutput(Output): def __init__(self, uri, **kw): @@ -104,19 +103,20 @@ class BackgroundLoopOutput(Output): d = threads.deferToThread(self._write, sendingBuffer) d.addCallbacks(done, err) + class FtdiDmx(BackgroundLoopOutput): + def __init__(self, uri, lastDmxChannel, rate=22): super().__init__(uri) self.lastDmxChannel = lastDmxChannel from .dmx_controller_output import OpenDmxUsb self.dmx = OpenDmxUsb() - + def _write(self, buf): self._writeStats.fps.mark() with self._writeStats.call.time(): if not buf: - logAllDmx.debug('%s: empty buf- no output', - self.shortId()) + logAllDmx.debug('%s: empty buf- no output', self.shortId()) return # ok to truncate the last channels if they just went @@ -126,9 +126,8 @@ class FtdiDmx(BackgroundLoopOutput): if logAllDmx.isEnabledFor(logging.DEBUG): # for testing fps, smooth fades, etc - logAllDmx.debug( - '%s: %s...' % - (self.shortId(), ' '.join(map(str, buf[:32])))) + logAllDmx.debug('%s: %s...' % + (self.shortId(), ' '.join(map(str, buf[:32])))) self.dmx.send_dmx(buf) @@ -190,13 +189,14 @@ class Udmx(BackgroundLoopOutput): super().__init__(uri, rate=rate) self._errStats = scales.collection(self.statPath + '/write', - scales.IntStat('overflow'), - scales.IntStat('ioError'), - scales.IntStat('pipeError') - ) + scales.IntStat('overflow'), + scales.IntStat('ioError'), + scales.IntStat('pipeError')) self.reconnect() + def shortId(self) -> str: return super().shortId() + f'_bus={self.bus}' + def reconnect(self): self._connected = 0 from pyudmx import pyudmx @@ -220,8 +220,7 @@ class Udmx(BackgroundLoopOutput): with self._writeStats.call.time(): try: if not buf: - logAllDmx.debug('%s: empty buf- no output', - self.shortId()) + logAllDmx.debug('%s: empty buf- no output', self.shortId()) return # ok to truncate the last channels if they just went @@ -247,14 +246,14 @@ class Udmx(BackgroundLoopOutput): self._errStats.overflow += 1 return - if e.errno == 5: # i/o err + if e.errno == 5: # i/o err self._errStats.ioError += 1 return - if e.errno == 32: # pipe err + if e.errno == 32: # pipe err self._errStats.pipeError += 1 return - + msg = 'usb: sending %s bytes to %r; error %r' % (len(buf), self.uri, e) log.warn(msg) diff --git a/light9/effect/effecteval.py b/light9/effect/effecteval.py --- a/light9/effect/effecteval.py +++ b/light9/effect/effecteval.py @@ -387,6 +387,7 @@ def effect_lightning(effectSettings, str out[(dev, L9['color'])] = col return out + def sample(img, x, y, repeat=False): if 0 <= x < img.width: return img.getpixel((x, y)) @@ -395,6 +396,7 @@ def sample(img, x, y, repeat=False): else: return img.getpixel((x % img.width, y)) + def effect_image(effectSettings, strength, songTime, noteTime): out = {} imgPath = f'cur/anim/{effectSettings[L9["image"]]}' diff --git a/light9/effect/sequencer.py b/light9/effect/sequencer.py --- a/light9/effect/sequencer.py +++ b/light9/effect/sequencer.py @@ -120,8 +120,7 @@ class Note(object): 'effectClass': self.effectEval.effect, } effectSettings: Dict[DeviceAttr, Union[float, str]] = dict( - (DeviceAttr(da), v) - for da, v in self.baseEffectSettings.items()) + (DeviceAttr(da), v) for da, v in self.baseEffectSettings.items()) effectSettings[L9['strength']] = self.evalCurve(t) def prettyFormat(x: Union[float, str]): @@ -192,7 +191,7 @@ class Sequencer(object): log.debug('seq.onCodeChange') self.graph.addHandler(self.compileGraph) #self.updateLoop() - + @compileStats.graph.time() def compileGraph(self) -> None: """rebuild our data from the graph""" @@ -209,7 +208,8 @@ class Sequencer(object): self.notes[song] = [] for note in self.graph.objects(song, L9['note']): try: - n = Note(self.graph, NoteUri(note), effecteval, self.simpleOutputs) + n = Note(self.graph, NoteUri(note), effecteval, + self.simpleOutputs) except Exception: log.warn(f"failed to build Note {note} - skipping") anyErrors = True @@ -235,14 +235,14 @@ class Sequencer(object): if not self.lastLoopSucceeded: log.info('Sequencer.update is working') self.lastLoopSucceeded = True - + delay = max(0, 1 / self.fps - took) reactor.callLater(delay, self.updateLoop) @updateStats.updateFps.rate() @inlineCallbacks def update(self) -> Deferred: - + with updateStats.s0_getMusic.time(): musicState = self.music.getLatest() if not musicState.get('song') or not isinstance( @@ -257,8 +257,7 @@ class Sequencer(object): with updateStats.s1_eval.time(): settings = [] - songNotes = sorted(self.notes.get(song, []), - key=lambda n: n.uri) + songNotes = sorted(self.notes.get(song, []), key=lambda n: n.uri) noteReports = [] for note in songNotes: try: @@ -272,7 +271,7 @@ class Sequencer(object): dispatcher.send('state', update={'songNotes': noteReports}) - with updateStats.s3_send.time(): # our measurement + with updateStats.s3_send.time(): # our measurement sendSecs = yield self.sendToCollector(devSettings) # sendToCollector's own measurement. @@ -280,6 +279,7 @@ class Sequencer(object): #if isinstance(sendSecs, float): # updateStats.s3_send_client = sendSecs + class Updates(cyclone.sse.SSEHandler): def __init__(self, application, request, **kwargs) -> None: diff --git a/light9/subclient.py b/light9/subclient.py --- a/light9/subclient.py +++ b/light9/subclient.py @@ -12,7 +12,7 @@ log = logging.getLogger() class SubClient: graph: SyncedGraph session: URIRef - + def __init__(self): """assumed that your init saves self.graph""" pass # we may later need init code for network setup