Python launchpad control surface script conks out randomnly

Learn about building and using Max for Live devices.
Post Reply
iainduncan
Posts: 42
Joined: Tue Jun 12, 2012 6:06 pm
Location: BC, Canada
Contact:

Python launchpad control surface script conks out randomnly

Post by iainduncan » Fri Jan 18, 2013 2:04 am

So, I have a python control surface script, which is working, but then just stops working, seeming randomnly, and I can't for the life of me figure out why. The details:

- it's for using User 1 mode on the Launchpad
- input into ableton is handled by setting the input for my script to be the OSX IAC 3 buffer, and I have the launchpad midi duplicated in MIDI Patchbay to send to IAC 3
- I also have the stock launchpad control surface running, with it's input set to Launchpad.
- the script changes device paramaters, this always works fine for a while after enabling it, and then some time later, off to sleep! grr,,

I'll paste the script below in a second reply. Any hits would be most welcome!

Iain

iainduncan
Posts: 42
Joined: Tue Jun 12, 2012 6:06 pm
Location: BC, Canada
Contact:

Re: Python launchpad control surface script conks out randomnly

Post by iainduncan » Fri Jan 18, 2013 2:07 am

Code: Select all

""" 
controller.py  
"""

# This allows us (and the Framework methods) to use the Live API on occasion
import Live 
# Base class for all classes representing control elements on a controller
from _Framework.InputControlElement import * 
# Central base class for scripts based on the new Framework
from _Framework.ControlSurface import ControlSurface 
# Class encapsulating all functions in Live's transport section
from _Framework.TransportComponent import TransportComponent 
# Class representing a button a the controller
from _Framework.ButtonElement import ButtonElement 

# Class encompassing several scene to cover a defined section of Live's session
from _Framework.SessionComponent import SessionComponent 

from datetime import datetime

# import the LiveUtils helpers
from LiveUtils import *

# macro of control channel we're using
# the launchpad transmits on channel 1
CHANNEL = 0  

# device offset is the offset for where in the device list the chains start
DEVICE_OFFSET = 1 
TRACK_OFFSET = 8

SESSION = 0
USER_1 = 1
USER_2 = 2
MIXER = 3

NOTE_ON_EVENT              = 144
NOTE_OFF_EVENT             = 128
CC_EVENT                   = 176

LED_rgb                    = 0x00
LED_Rgb                    = 0x10
LED_rGb                    = 0x20
LED_rgB                    = 0x30
LED_RGb                    = 0x40
LED_RgB                    = 0x50
LED_rGB                    = 0x60
LED_RGB                    = 0x70


# a map of launchpad midi keys to column and row
launchpad_map = {
    64: (0,0), 65:(1,0), 66:(2,0), 67:(3,0), 96:(4,0), 97:(5,0), 98:(6,0), 99:(7,0),
    60: (0,1), 61:(1,1), 62:(2,1), 63:(3,1), 92:(4,1), 93:(5,1), 94:(6,1), 95:(7,1),
    56: (0,2), 57:(1,2), 58:(2,2), 59:(3,2), 88:(4,2), 89:(5,2), 90:(6,2), 91:(7,2),
    52: (0,3), 53:(1,3), 54:(2,3), 55:(3,3), 84:(4,3), 85:(5,3), 86:(6,3), 87:(7,3),
    48: (0,4), 49:(1,4), 50:(2,4), 51:(3,4), 80:(4,4), 81:(5,4), 82:(6,4), 83:(7,4),
    44: (0,5), 45:(1,5), 46:(2,5), 47:(3,5), 76:(4,5), 77:(5,5), 78:(6,5), 79:(7,5),
    40: (0,6), 41:(1,6), 42:(2,6), 43:(3,6), 72:(4,6), 73:(5,6), 74:(6,6), 75:(7,6),
    36: (0,7), 37:(1,7), 38:(2,7), 39:(3,7), 68:(4,7), 69:(5,7), 70:(6,7), 71:(7,7),
}
launchpad_columns = [
    [64,60,56,52,48,44,40,36],
    [65,61,57,53,49,45,41,37],
    [66,62,58,54,50,46,42,38],
    [67,63,59,55,51,47,43,39],
    [96,92,88,84,80,76,72,68],
    [97,93,89,85,81,77,73,69],
    [98,94,90,86,82,78,74,70],
    [99,95,91,87,83,79,75,71]
]


class Controller(ControlSurface):
    
    # this controls the size of the coloured box for our script
    num_tracks = 8
    num_scenes = 8

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        self.log_message("Controller.__init__() %s" % datetime.now() )
        self._c_instance = c_instance
        
        # assume mode starts in session mode
        self.mode = 0 
        self.launchpad_buttons = []
        self.mode_buttons = []
        self.create_mode_buttons()
        self.create_patch_buttons()

        self.log_message("Controller.__init__() DONE %s" % datetime.now() )


    def send_midi(self, midi_event_bytes):
        #self.log_message("sending midi: %s" % str(midi_event_bytes) )
        self._c_instance.send_midi(midi_event_bytes)


    def disconnect(self):
        "called by Ableton on unload, should remove any listeners"
        for button in self.launchpad_buttons:
            button.remove_value_listener(self.cb_activate_chain)


    def create_mode_buttons(self):
        for cc_num in (108,109,110,111):
            mode_btn = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, cc_num)
            mode_btn.set_identifier( cc_num - 108 )
            mode_btn.add_value_listener(self.cb_switch_mode, identify_sender=True)
            self.launchpad_buttons.append(mode_btn)
            

    def cb_switch_mode(self, value, sender):
        mode = sender._msg_identifier
        self.log_message("cb_switch_mode() changing mode to: %i" % mode)
        self.mode = mode


    def create_patch_buttons(self):
        "create the button callbacks"
        # make button elements for each launchpad button 
        # this is how we deal with midi input, make InputElements for each message
        for note_num, (track_num, chain_num) in launchpad_map.items():
       
            # self.log_message(" connecting %i : %i : %i" % (note_num, track_num, chain_num) )
            button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, note_num)
            # store the number in the launchpad for this button
            button.set_identifier( (track_num*8)+chain_num )

            # add a callback to the button
            button.add_value_listener(self.cb_activate_chain, identify_sender=True)
            self.launchpad_buttons.append(button)


    def cb_activate_chain(self, value, sender):
        "callback fired from a InputControl, value will be the midi vel"
        #self.log_message("Controller.activate_chain: value: %s sender: %s" % (value, sender) )
        
        if self.mode != USER_1:
            #self.log_message("wrong mode, ignoring")
            return 

        midi_note_num = sender._original_identifier
        msg_id = sender._msg_identifier
        track_num = ( msg_id / 8 ) + TRACK_OFFSET
        param_num = msg_id % 8

        if value:
            self.log_message(" cb_activate_chain: track %i : param %i " % (track_num, param_num) )
            
            # send light-off to all other rows in the column
            for note_num in launchpad_columns[ track_num - TRACK_OFFSET ]:
                self.send_midi( (NOTE_ON_EVENT, note_num, LED_rgb) )    
            # send light on to this one
            self.send_midi( (NOTE_ON_EVENT, midi_note_num, LED_rGb) ) 
            
            try:   
                chain_device = getTrack(track_num).devices[ DEVICE_OFFSET ] 
                # loop through the macro params
                for i in range(0, 7): 
                    if i  == param_num:
                        #self.log_message("  setting param %i to 127" % i)
                        chain_device.parameters[i+1].value = 127
                    else:
                        chain_device.parameters[i+1].value = 0

            except Exception, e:
                self.log_message("\n exception: %s\n" % e)
                pass



amounra93
Posts: 432
Joined: Sat Jan 24, 2009 8:16 pm
Location: Arcata, CA
Contact:

Re: Python launchpad control surface script conks out randomnly

Post by amounra93 » Fri Jan 18, 2013 4:00 am

You're hitting an error, it will often break further processing depending on what it is. What's your log.txt file look like when this happens?
http://www.aumhaa.com for Monomod and other m4l goodies.

iainduncan
Posts: 42
Joined: Tue Jun 12, 2012 6:06 pm
Location: BC, Canada
Contact:

Re: Python launchpad control surface script conks out randomnly

Post by iainduncan » Fri Jan 18, 2013 6:25 am

Thanks. I notice there are errors in the log, but I'm not sure which scripts they are from and they don't seem to have to do with what I'm trying in the script. I guess tomorrow I'll try turning off all other inputs and seeing if I can get the errors happening with nothing but that control surface running. Here's some of my log in case you can decipher it!

Iain

Code: Select all

41700876 ms. AMidiIO: Midi Devices: 
  MidiInDevice [Name="Computer Keyboard", Track=true, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="IAC  (IAC 1)", Track=true, Sync=false, Remote=true, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="IAC  (IAC Bus 2)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="IAC  (IAC Bus 3)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="BCF2000 2 (Port 1)", Track=true, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="BCF2000 2 (Port 2)", Track=true, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="Launchpad 2 (Launchpad)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiOutDevice [Name="IAC  (IAC 1)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
  MidiOutDevice [Name="IAC  (IAC Bus 2)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
  MidiOutDevice [Name="IAC  (IAC Bus 3)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
  MidiOutDevice [Name="BCF2000 2 (Port 1)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
  MidiOutDevice [Name="BCF2000 2 (Port 2)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
  MidiOutDevice [Name="Launchpad 2 (Launchpad)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
41701426 ms. RemoteScriptError: Traceback (most recent call last):

41701427 ms. RemoteScriptError:   File "MIDI Remote Scripts/_Framework/ControlSurface.py", line 366, in build_midi_map

41701427 ms. RemoteScriptError: AssertionError
41701427 ms. RemoteScriptError: 
41701427 ms. RemoteScriptError: 

41701975 ms. RemoteScriptError: Traceback (most recent call last):

41701976 ms. RemoteScriptError:   File "MIDI Remote Scripts/_Framework/ControlSurface.py", line 460, in receive_midi

41701976 ms. RemoteScriptError:   File "MIDI Remote Scripts/_Framework/ControlSurface.py", line 469, in handle_sysex

41701976 ms. RemoteScriptError: AssertionError
41701976 ms. RemoteScriptError: 
41701976 ms. RemoteScriptError: 

41703392 ms. AMidiIO: Start CloseAllActivatedDevices
41703392 ms. AMidiIO: End CloseAllActivatedDevices
41703394 ms. AMidiIO: Start OpenAllActivatedDevices
41703405 ms. AMidiIO: End OpenAllActivatedDevices
41703421 ms. AMidiIO: Midi Remote Scripts: 
  MidiRemoteScript 1 [Control Surface="Launchpad" Input="None" Output="None"]
  MidiRemoteScript 2 [Control Surface="Launchpad" Input="None" Output="None"]
  MidiRemoteScript 3 [Control Surface="AA_Launchpad_2" Input="IAC  (IAC Bus 3)" Output="None"]
  MidiRemoteScript 4 [Control Surface="None" Input="None" Output="None"]
  MidiRemoteScript 5 [Control Surface="None" Input="None" Output="None"]
  MidiRemoteScript 6 [Control Surface="None" Input="None" Output="None"]
41703421 ms. AMidiIO: Takeover Mode: Value Scaling
41703422 ms. AMidiIO: Midi Devices: 
  MidiInDevice [Name="Computer Keyboard", Track=true, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="IAC  (IAC 1)", Track=true, Sync=false, Remote=true, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="IAC  (IAC Bus 2)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="IAC  (IAC Bus 3)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="BCF2000 2 (Port 1)", Track=true, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="BCF2000 2 (Port 2)", Track=true, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiOutDevice [Name="IAC  (IAC 1)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
  MidiOutDevice [Name="IAC  (IAC Bus 2)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
  MidiOutDevice [Name="IAC  (IAC Bus 3)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
  MidiOutDevice [Name="BCF2000 2 (Port 1)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
  MidiOutDevice [Name="BCF2000 2 (Port 2)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
41703968 ms. RemoteScriptError: Traceback (most recent call last):

41703968 ms. RemoteScriptError:   File "MIDI Remote Scripts/_Framework/ControlSurface.py", line 366, in build_midi_map

41703968 ms. RemoteScriptError: AssertionError
41703969 ms. RemoteScriptError: 
41703969 ms. RemoteScriptError: 

41705192 ms. AMidiIO: Start CloseAllActivatedDevices
41705193 ms. AMidiIO: End CloseAllActivatedDevices
41705194 ms. AMidiIO: Start OpenAllActivatedDevices
41705196 ms. AMidiIO: End OpenAllActivatedDevices
41705202 ms. AMidiIO: Midi Remote Scripts: 
  MidiRemoteScript 1 [Control Surface="Launchpad" Input="None" Output="None"]
  MidiRemoteScript 2 [Control Surface="Launchpad" Input="None" Output="None"]
  MidiRemoteScript 3 [Control Surface="AA_Launchpad_2" Input="IAC  (IAC Bus 3)" Output="None"]
  MidiRemoteScript 4 [Control Surface="None" Input="None" Output="None"]
  MidiRemoteScript 5 [Control Surface="None" Input="None" Output="None"]
  MidiRemoteScript 6 [Control Surface="None" Input="None" Output="None"]
41705202 ms. AMidiIO: Takeover Mode: Value Scaling
41705214 ms. AMidiIO: Midi Devices: 
  MidiInDevice [Name="Computer Keyboard", Track=true, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="IAC  (IAC 1)", Track=true, Sync=false, Remote=true, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="IAC  (IAC Bus 2)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiInDevice [Name="IAC  (IAC Bus 3)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, Sync Type="MIDI Clock", MTC Frame Rate="All", MTC Start Offset=0]
  MidiOutDevice [Name="IAC  (IAC 1)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
  MidiOutDevice [Name="IAC  (IAC Bus 2)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
  MidiOutDevice [Name="IAC  (IAC Bus 3)", Track=false, Sync=false, Remote=false, MIDI Clock Sync Delay=0, MIDI Clock Type="Song"]
41705751 ms. RemoteScriptError: Traceback (most recent call last):

41705751 ms. RemoteScriptError:   File "MIDI Remote Scripts/_Framework/ControlSurface.py", line 366, in build_midi_map

41705752 ms. RemoteScriptError: AssertionError
41705753 ms. RemoteScriptError: 
41705753 ms. RemoteScriptError: 


amounra93
Posts: 432
Joined: Sat Jan 24, 2009 8:16 pm
Location: Arcata, CA
Contact:

Re: Python launchpad control surface script conks out randomnly

Post by amounra93 » Fri Jan 18, 2013 11:44 pm

One thing: you need to override the handle_sysex() method of the ControlSurface module....it's just a placeholder in the super(), so it's hitting an assertion error and possibly derailing some other stuff. I'm not sure about the assertion error with build_midi_map....are you calling it directly from somewhere else? You should only be requesting it, via _request_rebuild_midi_map(). Probably, it's because you haven't set_suppress_rebuild_requests(True) in your ControlSurface __init__()....any of the stock scripts use this method, you should follow that protocol when using the _Framework modules.
http://www.aumhaa.com for Monomod and other m4l goodies.

iainduncan
Posts: 42
Joined: Tue Jun 12, 2012 6:06 pm
Location: BC, Canada
Contact:

Re: Python launchpad control surface script conks out randomnly

Post by iainduncan » Sat Jan 19, 2013 7:10 pm

Awesome, thanks. I've been hunting for a decent example of a script doing all the right housekeeping but haven't found any. If you know of one, please share!

Thanks so much
iain

Post Reply