Files @ eca35927bdd4
Branch filter:

Location: light9/light9/effect/effecteval.py

drewp@bigasterisk.com
from __future__ import division
from rdflib import URIRef, Literal
from light9.namespaces import L9, RDF, 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"

log = logging.getLogger('effecteval')

def literalColor(rnorm, gnorm, bnorm):
    return Literal(rgb_to_hex([int(rnorm * 255), int(gnorm * 255), int(bnorm * 255)]))

def literalColorHsv(h, s, v):
    return literalColor(*hsv_to_rgb(h, s, v))
    
def nsin(x): return (math.sin(x * (2 * math.pi)) + 1) / 2
def ncos(x): return (math.cos(x * (2 * math.pi)) + 1) / 2
def nsquare(t, on=.5):
    return (t % 1.0) < on
def lerp(a, b, t):
    return a + (b - a) * t
def noise(t):
    return pnoise1(t % 1000.0, 2)
def clamp(lo, hi, x):
    return max(lo, min(hi, x))
    
class EffectEval(object):
    """
    runs one effect's code to turn effect attr settings into output
    device settings. No state; suitable for reload().
    """
    def __init__(self, graph, effect, simpleOutputs):
        self.graph = graph
        self.effect = effect
        self.simpleOutputs = simpleOutputs

    def outputFromEffect(self, effectSettings, songTime, noteTime):
        """
        From effect attr settings, like strength=0.75, to output device
        settings like light1/bright=0.72;light2/bright=0.78. This runs
        the effect code.
        """
        # both callers need to apply note overrides
        effectSettings = dict(effectSettings) # we should make everything into nice float and Color objects too

        strength = float(effectSettings[L9['strength']])
        if strength <= 0:
            return DeviceSettings(self.graph, []), {'zero': True}

        report = {}
        out = {} # (dev, attr): value

        out.update(self.simpleOutputs.values(
            self.effect, strength, effectSettings.get(L9['colorScale'], None)))

        if self.effect.startswith(L9['effect/']):
            tail = 'effect_' + self.effect[len(L9['effect/']):]
            try:
                func = globals()[tail]
            except KeyError:
                report['error'] = 'effect code not found for %s' % self.effect
            else:
                out.update(func(effectSettings, strength, songTime, noteTime))

        outList = [(d, a, v) for (d, a), v in out.iteritems()]
        return DeviceSettings(self.graph, outList), report
                  

def effect_Curtain(effectSettings, strength, songTime, noteTime):
    return {
        (L9['device/lowPattern%s' % n], L9['color']):
        literalColor(strength, strength, strength)
        for n in range(301,308+1)
        }
    
def effect_animRainbow(effectSettings, strength, songTime, noteTime):
    out = {}
    tint = effectSettings.get(L9['tint'], '#ffffff')
    tintStrength = float(effectSettings.get(L9['tintStrength'], 0))
    tr, tg, tb = hex_to_rgb(tint)
    for n in range(1, 5+1):
        scl = strength * nsin(songTime + n * .3)**3
        col = literalColor(
            scl * lerp(nsin(songTime + n * .2), tr/255, tintStrength),
            scl * lerp(nsin(songTime + n * .2 + .3), tg/255, tintStrength),
            scl * lerp(nsin(songTime + n * .3 + .6), tb/255, tintStrength))

        dev = L9['device/aura%s' % n]
        out.update({
            (dev, L9['color']): col,
            (dev, L9['zoom']): .9,
            })
        ang = songTime * 4
        out.update({
        (dev, L9['rx']): lerp(.27, .7, (n-1)/4) + .2 * math.sin(ang+n),
        (dev, L9['ry']): lerp(.46, .52, (n-1)/4) + .5 * math.cos(ang+n),
            })
    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)

        dev = L9['device/aura%s' % n]
        out.update({
            (dev, L9['color']): col,
            (dev, L9['zoom']): .95,
            })
        ang = songTime * 4
        out.update({
        (dev, L9['rx']): lerp(.27, .8, (n-1)/4) + .2 * math.sin(ang+n),
        (dev, L9['ry']): lerp(.46, .52, (n-1)/4) + .4 * math.cos(ang+n),
            })
    return out

def effect_qpan(effectSettings, strength, songTime, noteTime):
    dev = L9['device/q2']
    dur = 4
    col = scale(scale('#ffffff', strength),
                effectSettings.get(L9['colorScale']) or '#ffffff')
    return {
        (dev, L9['color']): col,
        (dev, L9['focus']): 0.589,
        (dev, L9['rx']): lerp(0.778, 0.291, clamp(0, 1, noteTime / dur)),
        (dev, L9['ry']): 0.383,
        (dev, L9['zoom']): 0.714,
    }

def effect_pulseRainbow(effectSettings, strength, songTime, noteTime):
    out = {}
    tint = effectSettings.get(L9['tint'], '#ffffff')
    tintStrength = float(effectSettings.get(L9['tintStrength'], 0))
    tr, tg, tb = hex_to_rgb(tint)
    for n in range(1, 5+1):
        scl = strength 
        col = literalColor(
            scl * lerp(nsin(songTime + n * .2), tr/255, tintStrength),
            scl * lerp(nsin(songTime + n * .2 + .3), tg/255, tintStrength),
            scl * lerp(nsin(songTime + n * .3 + .6), tb/255, tintStrength))

        dev = L9['device/aura%s' % n]
        out.update({
            (dev, L9['color']): col,
            (dev, L9['zoom']): .5,
            })
        out.update({
        (dev, L9['rx']): lerp(.27, .7, (n-1)/4),
        (dev, L9['ry']): lerp(.46, .52, (n-1)/4),
            })
    return out


def effect_aurawash(effectSettings, strength, songTime, noteTime):
    out = {}
    scl = strength
    period = float(effectSettings.get(L9['period'], 125/60/4))
    if period < .05:
        quantTime = songTime
    else:
        quantTime = int(songTime / period) * period
    noisePos = quantTime * 6.3456
    
    col = literalColorHsv(noise(noisePos), 1, scl)
    col = scale(col, effectSettings.get(L9['colorScale']) or '#ffffff')
                
    print songTime, quantTime, col

    for n in range(1, 5+1):
        dev = L9['device/aura%s' % n]
        out.update({
            (dev, L9['color']): col,
            (dev, L9['zoom']): .5,
            })
        out.update({
        (dev, L9['rx']): lerp(.27, .7, (n-1)/4),
        (dev, L9['ry']): lerp(.46, .52, (n-1)/4),
            })
    return out

def effect_qsweep(effectSettings, strength, songTime, noteTime):
    out = {}
    period = float(effectSettings.get(L9['period'], 2))

    col = effectSettings.get(L9['colorScale'], '#ffffff')
    col = scale(col, effectSettings.get(L9['strength'], 1))

    
    for n in range(1, 3+1):
        dev = L9['device/q%s' % n]
        out.update({
            (dev, L9['color']): col,
            (dev, L9['zoom']): effectSettings.get(L9['zoom'], .5),
            })
        out.update({
            (dev, L9['rx']):
            lerp(.3, .8, nsin(songTime / period + n / 4)),
        (dev, L9['ry']): effectSettings.get(L9['ry'], .2),
            })
    return out

def effect_qsweepusa(effectSettings, strength, songTime, noteTime):
    out = {}
    period = float(effectSettings.get(L9['period'], 2))

    colmap = {
        1: '#ff0000',
        2: '#888888',
        3: '#5050ff',
    }
    
    for n in range(1, 3+1):
        dev = L9['device/q%s' % n]
        out.update({
            (dev, L9['color']): scale(colmap[n], effectSettings.get(L9['strength'], 1)),
            (dev, L9['zoom']): effectSettings.get(L9['zoom'], .5),
            })
        out.update({
            (dev, L9['rx']):
            lerp(.3, .8, nsin(songTime / period + n / 4)),
            (dev, L9['ry']): effectSettings.get(L9['ry'], .5),
            })
    return out

chase1_members = [
        DEV['backlight1'],
        DEV['lip1'],
        DEV['backlight2'],
        DEV['down2'],
        DEV['lip2'],
        DEV['backlight3'],
        DEV['down3'],
        DEV['lip3'],
        DEV['backlight4'],
        DEV['down4'],
        DEV['lip4'],
        DEV['backlight5'],
        DEV['down5Edge'],
        DEV['lip5'],
        #DEV['upCenter'],
        ]
chase2_members = chase1_members * 10
random.shuffle(chase2_members)

def effect_chase1(effectSettings, strength, songTime, noteTime):
    members = chase1_members + chase1_members[-2:0:-1]
    
    out = {}
    period = float(effectSettings.get(L9['period'], 2 / len(members)))

    for i, dev in enumerate(members):
        cursor = (songTime / period) % float(len(members))
        dist = abs(i - cursor)
        radius = 3
        if dist < radius:
            col = effectSettings.get(L9['colorScale'], '#ffffff')
            col = scale(col, effectSettings.get(L9['strength'], 1))
            col = scale(col, (1 - dist / radius))
        
            out.update({
                (dev, L9['color']): col,
            })
    return out

def effect_chase2(effectSettings, strength, songTime, noteTime):
    members = chase2_members
    
    out = {}
    period = float(effectSettings.get(L9['period'], 0.3))

    for i, dev in enumerate(members):
        cursor = (songTime / period) % float(len(members))
        dist = abs(i - cursor)
        radius = 3
        if dist < radius:
            col = effectSettings.get(L9['colorScale'], '#ffffff')
            col = scale(col, effectSettings.get(L9['strength'], 1))
            col = scale(col, (1 - dist / radius))
        
            out.update({
                (dev, L9['color']): col,
            })
    return out
    
def effect_whirlscolor(effectSettings, strength, songTime, noteTime):
    out = {}

    col = effectSettings.get(L9['colorScale'], '#ffffff')
    col = scale(col, effectSettings.get(L9['strength'], 1))
    
    for n in (1, 3):
        dev = L9['device/q%s' % n]
        scl = strength
        col = literalColorHsv(((songTime / 5) + (n / 5)) % 1, 1, scl)
        out.update({
            (dev, L9['color']): col,
            })

    return out


def effect_orangeSearch(effectSettings, strength, songTime, noteTime):
    dev = L9['device/auraStage']
    return {(dev, L9['color']): '#a885ff',
            (dev, L9['rx']): lerp(.65, 1, nsin(songTime / 2.0)),
            (dev, L9['ry']): .6,
            (dev, L9['zoom']): 1,
            }
    
def effect_Strobe(effectSettings, strength, songTime, noteTime):
    rate = 2
    duty = .3
    offset = 0
    f = (((songTime + offset) * rate) % 1.0)
    c = (f < duty) * strength
    col = rgb_to_hex([int(c * 255), int(c * 255), int(c * 255)])
    return {(L9['device/colorStrip'], L9['color']): Literal(col)}

def effect_lightning(effectSettings, strength, songTime, noteTime):
    devs = [L9['device/veryLow1'], L9['device/veryLow2'],
            L9['device/veryLow3'], L9['device/veryLow4'],
            L9['device/veryLow5'], L9['device/backlight1'],
            L9['device/backlight2'], L9['device/backlight3'],
            L9['device/backlight4'], L9['device/backlight5'],
            L9['device/down2'], L9['device/down3'],
            L9['device/down4'], L9['device/hexLow3'],
            L9['device/hexLow5'], L9['device/lip1 5'],
            L9['device/postL1'], L9['device/postR1']]
    out = {}
    col = rgb_to_hex([int(255 * strength)] * 3)
    for i, dev in enumerate(devs):
        n = noise(songTime * 8 + i * 6.543)
        if n > .4:
            out[(dev, L9['color'])] = col
    return out