Changeset - 83e2c4ceb79a
[Not reviewed]
default
0 4 0
dmcc - 22 years ago 2003-06-14 16:19:40

KeyboardComposer: let's get it working again
KeyboardComposer: let's get it working again
TheShow: get_timelines method
Timeline: it's late, okay?
TimelineDMX: timeline selector, basically copied from that music player
thing
4 files changed with 28 insertions and 17 deletions:
0 comments (0 inline, 0 general)
flax/KeyboardComposer.py
Show inline comments
 
@@ -144,77 +144,77 @@ class KeyboardComposer(Frame):
 
            if col == 0: # make new row
 
                row = self.make_row()
 
                rowcount += 1
 
            current_level = self.current_sub_levels.get(sub.name, 0)
 
            subtk = self.draw_sub_slider(row, col, sub.name, current_level)
 
            self.slider_table[(rowcount, col)] = subtk
 
            col += 1
 
            col %= 10
 

	
 
            subtk.slider_var.trace('w', lambda x, y, z: self.send_levels())
 
    def make_row(self):
 
        row = Frame(self, bd=2)
 
        row.pack(expand=1, fill=BOTH)
 
        self.setup_key_nudgers(row)
 
        self.rows.append(row)
 
        return row
 
    def draw_sub_slider(self, row, col, name, current_level):
 
        subtk = SubmasterTk(row, name, current_level)
 
        subtk.place(relx=col * 0.1, rely=0, relwidth=0.1, relheight=1)
 
        self.setup_key_nudgers(subtk.scale)
 

	
 
        self.slider_vars[name] = subtk.slider_var
 
        return subtk
 
    def highlight_row(self, row):
 
        row = self.rows[row]
 
        row['bg'] = 'red'
 
    def unhighlight_row(self, row):
 
        row = self.rows[row]
 
        row['bg'] = '#d9d9d9'
 
    def get_levels(self):
 
        return dict([(name, slidervar.get()) 
 
            for name, slidervar in self.slider_vars.items()])
 
    def get_dmx_list(self):
 
        scaledsubs = [self.submasters.get_sub_by_name(sub) * level \
 
            for sub, level in self.get_levels().items()]
 

	
 
        maxes = sub_maxes(*scaledsubs)
 
        return maxes.get_dmx_list()
 
    def save(self):
 
        pickle.dump(self.get_levels(), 
 
                    file('.keyboardcomposer.savedlevels', 'w'))
 
    def send_frequent_updates(self):
 
        """called when we get a fade -- send events as quickly as possible"""
 
        if time.time() <= self.stop_frequent_update_time:
 
            self.send_levels()
 
            self.after(10, self.send_frequent_updates)
 
    def send_levels(self):
 
        levels = self.get_dmx_list()
 
        # dmxclient.outputlevels(levels)
 
        dmxclient.outputlevels(levels)
 
        # print "sending levels", levels
 
    def send_levels_loop(self):
 
        self.send_levels()
 
        self.after(1000, self.send_levels_loop)
 
    def refresh(self):
 
        self.save()
 
        self.submasters = Submasters()
 
        self.current_sub_levels = \
 
            pickle.load(file('.keyboardcomposer.savedlevels'))
 
        for r in self.rows:
 
            r.destroy()
 
        self.keyhints.destroy()
 
        self.refreshbutton.destroy()
 
        self.draw_ui()
 

	
 
if __name__ == "__main__":
 
    s = Submasters()
 

	
 
    root = Tk()
 
    tl = toplevelat("Keyboard Composer", existingtoplevel=root)
 
    kc = KeyboardComposer(tl, s)
 
    kc.pack(fill=BOTH, expand=1)
 
    atexit.register(kc.save)
 
    try:
 
        mainloop()
 
    except KeyboardInterrupt:
 
        tl.destroy()
 
        sys.exit()
flax/TheShow.py
Show inline comments
 

	
 

	
 
from Timeline import *
 
from Submaster import Submasters, sub_maxes
 

	
 
class Show:
 
    def __init__(self, timelines, submasters):
 
        self.timelines = dict([(timeline.name, timeline)
 
            for timeline in timelines])
 
        self.submasters = submasters
 
        self.current_timeline = None
 
        self.current_time = 0
 
        try:
 
            self.current_timeline = timelines[0]
 
        except ValueError:
 
            pass
 
    def calc_active_submaster(self):
 
        "get levels from the current timeline at the current time"
 
        if not (self.current_timeline or self.current_time):
 
            return {}
 
        tl = self.current_timeline
 
        tl.set_time(self.current_time)
 
        levels = tl.get_levels()
 
        scaledsubs = [self.submasters.get_sub_by_name(sub) * level \
 
            for sub, level in levels.items()]
 
        maxes = sub_maxes(*scaledsubs)
 

	
 
        return maxes
 
    def set_timeline(self, name):
 
        "select a timeline"
 
        self.current_timeline = self.timelines.get(name)
 
        self.set_time(0)
 
        if not self.current_timeline:
 
            print "Show: '%s' is not the same of a timeline."
 
    def set_time(self, time):
 
        "set time of current timeline"
 
        self.current_time = time
 
        self.current_timeline.set_time(time)
 
    def get_timelines(self):
 
        "Get names of all timelines"
 
        return self.timelines.keys()
 

	
 
# this is the default blender
 
linear = LinearBlender()
 
def T(time, level, **kw):
 
    """This used to be a synonym for TimedEvent:
 

	
 
    T = TimedEvent
 

	
 
    It now acts in a similar way, except that it will fill in a default 
 
    blender if you don't.  The default blender is a LinearBlender.  It also
 
    sets frame to MISSING so the track can fill it in."""
 
    if 'blender' not in kw:
 
        global linear
 
        kw['blender'] = linear
 

	
 
    return TimedEvent(time, level=level, frame=MISSING, **kw)
 

	
 
quad = ExponentialBlender(2)
 
invquad = ExponentialBlender(0.5)
 
smoove = SmoothBlender()
 

	
 
track1 = TimelineTrack('red track',
 
    T(0, 0),
 
    T(4, 0.5, blender=quad),
 
    T(12, 0.7, blender=smoove),
 
    T(15, level=0.0), default_frame='red')
 
track2 = TimelineTrack('green track',
 
    T(0, 0.2, blender=invquad),
 
    T(5, 1.0, blender=smoove),
 
    T(10, 0.8),
 
    T(15, 0.6),
 
    T(20, 0.0), default_frame='green')
 
track3 = TimelineTrack('tableau demo',
 
    T(0, 0.0),
 
    T(2, 1.0, blender=InstantEnd()),
 
    T(18, 1.0),
 
    T(20, 0.0), default_frame='blue')
 
track4 = TimelineTrack('MJ fader',
 
    T(0, 0.0),
 
    T(5, 1.0),
 
    T(10, 0.0), default_frame='red')
 
bump21 = TimelineTrack('bump at 21',
 
    T(0,    0),
 
    T(20.4, 0.05),
 
    T(20.7,   1),
 
    T(25,   0.4),
 
    T(31,   0),
 
    T(31.1, 1),
flax/Timeline.py
Show inline comments
 
@@ -123,117 +123,117 @@ class ExponentialBlender(Blender):
 
        self.exponent = exponent
 
    def __call__(self, startframe, endframe, blendtime, time_since_startframe):
 
        blendtime = blendtime ** self.exponent
 
        return self.linear_blend(startframe, endframe, blendtime)
 

	
 
# 17:02:53 drewp: this makes a big difference for the SmoothBlender 
 
#                 (-x*x*(x-1.5)*2) function
 
class SmoothBlender(Blender):
 
    """Drew's "Smoove" Blender function.  Hopefully he'll document and
 
    parametrize it."""
 
    def __call__(self, startframe, endframe, blendtime, time_since_startframe):
 
        blendtime = (-1 * blendtime) * blendtime * (blendtime - 1.5) * 2
 
        return self.linear_blend(startframe, endframe, blendtime)
 

	
 
class Strobe(Blender):
 
    "Strobes the frame on the right side between offlevel and onlevel."
 
    def __init__(self, ontime, offtime, onlevel=1, offlevel=0):
 
        "times are in seconds (floats)"
 
        make_attributes_from_args('ontime', 'offtime', 'onlevel', 'offlevel')
 
        self.cycletime = ontime + offtime
 
    def __call__(self, startframe, endframe, blendtime, time_since_startframe):
 
        # time into the current period
 
        period_time = time_since_startframe % self.cycletime
 
        if period_time <= self.ontime:
 
            return {endframe.frame : self.onlevel}
 
        else:
 
            return {endframe.frame : self.offlevel}
 

	
 
class TimelineTrack:
 
    """TimelineTrack is a single track in a Timeline.  It consists of a
 
    list of TimedEvents and a name.  Length is automatically the location
 
    of the last TimedEvent.  To extend the Timeline past that, add an
 
    EmptyTimedEvent (which doesn't exist :-/)."""
 
    def __init__(self, name, *timedevents, **kw):
 
        if kw.get('default_frame'):
 
            self.default_frame = kw['default_frame']
 
        else:
 
            self.default_frame = None
 
        self.name = name
 
        self.set_events(list(timedevents))
 
    def set_events(self, events):
 
        """This is given a list of TimedEvents.  They need not be sorted."""
 
        self.events = events
 
        self._cleaup_events()
 
    def _cleaup_events(self):
 
        """This makes sure all events are in the right order and have defaults
 
        filled in if they have missing frames."""
 
        self.events.sort()
 
        self.fill_in_missing frames()
 
        self.fill_in_missing_frames()
 
    def add_event(self, event):
 
        """Add a TimedEvent object to this TimelineTrack"""
 
        self.events.append(event)
 
        self._cleaup_events(self.events)
 
    def delete_event(self, event):
 
        """Delete event by TimedEvent object"""
 
        self.events.remove(event)
 
        self._cleaup_events(self.events)
 
    def delete_event_by_name(self, name):
 
        """Deletes all events matching a certain name"""
 
        self.events = [e for e in self.events if e.name is not name]
 
        self._cleaup_events(self.events)
 
    def delete_event_by_time(self, starttime, endtime=None):
 
        """Deletes all events within a certain time range, inclusive.  endtime
 
        is optional."""
 
        endtime = endtime or starttime
 
        self.events = [e for e in self.events
 
            if e.time >= starttime and e.time <= endtime]
 
        self._cleaup_events(self.events)
 
    def fill_in_missing frames(self):
 
    def fill_in_missing_frames(self):
 
        """Runs through all events and sets TimedEvent with missing frames to
 
        the default frame."""
 
        for event in self.events:
 
            if event.frame == MISSING:
 
                event.frame = self.default_frame
 
    def __str__(self):
 
        return "<TimelineTrack with events: %r>" % self.events
 
    def has_events(self):
 
        """Whether the TimelineTrack has anything in it.  In general,
 
        empty level Tracks should be avoided.  However, empty function tracks
 
        might be common."""
 
        return len(self.events)
 
    def length(self):
 
        """Returns the length of this track in pseudosecond time units.
 
        This is done by finding the position of the last TimedEvent."""
 
        return float(self.events[-1])
 
    def get(self, key, direction=FORWARD):
 
        """Returns the event at a specific time key.  If there is no event
 
        at that time, a search will be performed in direction.  Also note
 
        that if there are multiple events at one time, only the first will
 
        be returned.  (Probably first in order of adding.)  This is not
 
        a problem at the present since this method is intended for LevelFrames,
 
        which must exist at unique times."""
 
        if direction == BACKWARD:
 
            func = last_less_than
 
        else:
 
            func = first_greater_than
 

	
 
        return func(self.events, key)
 
    def get_range(self, i, j, direction=FORWARD):
 
        """Returns all events between i and j, exclusively.  If direction
 
        is FORWARD, j will be included.  If direction is BACKWARD, i will
 
        be included.  This is because this is used to find FunctionFrames
 
        and we assume that any function frames at the start point (which
 
        could be i or j) have been processed."""
 
        return [e for e in self.events if e >= i and e <= j]
 

	
 
        if direction == FORWARD:
 
            return [e for e in self.events if e > i and e <= j]
 
        else:
 
            return [e for e in self.events if e >= i and e < j]
 
    def __getitem__(self, key):
 
        """Returns the event at or after a specific time key.
 
        For example: timeline[3] will get the first event at time 3.
 

	
 
        If you want to get all events at time 3, you are in trouble, but
 
        you could achieve it with something like: 
 
        timeline.get_range(2.99, 3.01, FORWARD) 
flax/TimelineDMX.py
Show inline comments
 
import sys, time, socket
 
sys.path.append("../light8")
 
import Tix as tk
 

	
 
import Patch, Timeline, dmxclient, xmlrpclib
 
import TheShow
 

	
 
Patch.reload_data()
 

	
 
class ShowRunner:
 
    def __init__(self, show):
 
class ShowRunner(tk.Frame):
 
    def __init__(self, master, show):
 
        tk.Frame.__init__(self, master)
 
        self.master = master
 

	
 
        self.show = show
 
        self.find_player()
 
        self.build_timeline_list()
 
    def build_timeline_list(self):
 
        self.tl_list = tk.Frame(self)
 
        for tl in self.show.get_timelines():
 
            b=tk.Button(self.tl_list,text=tl,
 
                        anchor='w',pady=1)
 
            b.config(command=lambda tl=tl: self.set_timeline(tl))
 
            b.pack(side='top',fill='x')
 
        self.tl_list.pack()
 
    def set_timeline(self, tlname):
 
        print "TimelineDMX: set timeline to", tlname
 
        self.show.set_timeline(tlname)
 
    def find_player(self):
 
        self.player = xmlrpclib.Server("http://localhost:8040")
 
    def send_levels(self):
 
        """
 
        sub = self.show.get_levels() # gets levels of subs
 
        leveldict = sub.get_levels() # gets levels of sub contents
 
        print 'resolved levels', leveldict
 

	
 
        levels = [0] * 68
 
        for k, v in leveldict.items():
 
            levels[Patch.get_dmx_channel(k)] = v
 
        """
 
        levels = self.show.calc_active_submaster().get_dmx_list()
 
        
 
        dmxclient.outputlevels(levels)
 
    def sync_times(self):
 
        try:
 
            playtime = self.player.gettime()
 
            self.show.set_time(playtime)
 
        except socket.error, e:
 
            print "Server error %s, waiting"%e
 
            time.sleep(2)
 
    def mainloop(self):
 
        try:
 
            while 1:
 
                self.sync_times()
 
                self.send_levels()
 
                time.sleep(0.01)
 
                self.master.update()
 
        except KeyboardInterrupt:
 
            sys.exit(0)
 

	
 
if __name__ == "__main__":
 
    s = ShowRunner(TheShow.show)
 
    root = tk.Tk()
 
    s = ShowRunner(root, TheShow.show)
 
    s.show.set_timeline('strobe test')
 
    s.pack()
 
    s.mainloop()
0 comments (0 inline, 0 general)