I decided to finally use Live for the purpose for which I originally bought it (back in ... uh... 2009): Playing live! I have an A&H Xone:K1 and a small MIDI keyboard, and those two and a laptop are everything I want to use - I would like my setup to be super portable, and these three items fit in my backpack with all necessary cables and my sound card and headphones, which is perfect: I can set up anywhere and all I need is a wall outlet and a line in. So I started to plan how I was going to set up the performance set and the controls, and I quickly reached the point where it became apparent that pure in-app MIDI mapping would not be enough for what I wanted. So I am now delving into Remote Scripts!
Unfortunately, there is no official support for writing these, but a few people have made astonishing efforts to collect all kinds of info. There's also remotify, an app that can generate scripts from a nice friendly GUI. I tried to work with that at first, but I realized the control scheme I envisioned was probably not going to be a straightforward thing to implement in their editor (nevermind that it would be somewhat costly to unlock the necessary capabilities). So I decided to forge ahead on my own for now.
I hope that writing down my experiences with the system, and the challenges I'm facing, will not just keep me motivated to go through with this, and eventually have a great way to play live, but may also help others who have advanced needs in this area.
Resources
My first research efforts brought up the decompiled remote scripts that came with Live, and reference docs for a crucial part, the _Framework (both provided by Julien Bayle @ https://github.com/gluon/AbletonLive10. ... oteScripts & https://structure-void.com/AbletonLiveR ... Framework/), the reference for Live's API from nsuspray @ https://nsuspray.github.io/Live_API_Doc/10.1.0.xml, and Hanz Petrov's intro to _Framework @ http://remotescripts.blogspot.com/2010/ ... asses.html. I also found two remote scripts for the Xone:K2, which has an essentially identical layout to my target controller, and while they didn't work the way I wanted my script to work, the methods used in them have already been extremely valuable to learn from (https://github.com/macfergus/live-xonek2 by macfergus and https://maps.djtechtools.com/mappings/8209 by Nicola de Bello)
The first hurdle was that much of the information on how to write my own script was not just fragmented and spread over dozens of different forums, repositories and websites, but much of it was outdated, pertaining to versions of Live or Python that had in the meantime changed. This continues to be a source of churn, and it's part of why I'm writing this thread.
Development Environment
I use VSCode to write the scripts, on a Windows machine. The script files are kept in Live's Resources/MIDI Remote Scripts directory, which is important - it's also possible to get them to work by placing them in the User Library, but that has one incredible drawback: No hot reload! The only way to see changes in scripts in the User Library is to close and re-open Live, which can take 5 minutes on my machine, and that is a major drag for when all that's changed is a typo somewhere. But scripts in Resources can be unassigned and re-assigned in the Live Preferences > Link/MIDI dialog, and will happily reload without having to quit the app. I keep Live's Log.txt open in a window to use for inline debugging.
My First Script
I am not a (good) programmer. I can do a bit of scripting, and I have dabbled in gamedev and shader coding, but I've never written Python before, and I am unfamiliar with many of even the most basic programming concepts. I am coming to this as a beginner, and probably doing a lot of things wrong initially. Please, if you have superior knowledge, correct me!
It took me hours to just get a "Hello World" to work, but now it does.
For this to work, there need to be two files: __init__.py, which will let Live use my code, and the file containing that code (I called mine wfK1.py). Forgive me for going into excruciating detail here, but to me as a non-initiated user it helps to understand what exactly is going on.
The init file looks like this ('#' prefaces comments):
Code: Select all
# this tells Live the filename in which to look for my code
import wfK1
# this is the standardized function with which Live loads
# any script. c_instance is the Control Surface slot in Live's
# prefs, as far as I can tell
def create_instance(c_instance):
# this is what it should load
# (the thing inside my file that's called 'K1')
return wfK1.K1(c_instance)
Code: Select all
# this lets me use Live's own generic Control Surface code
# to handle a bunch of background tasks in interfacing
# with the app, so I will only have to customize the behavior
# I want and not re-do all the plumbing
from _Framework.ControlSurface import ControlSurface
# this is the thing that'll be loaded in the __init__.py file.
# it's going to be based on the generic Control Surface
# (the slot that was called c_instance in __init__.py)
class K1(ControlSurface):
# this defines the function to construct what code
# ('self', i.e. this very thing I wrote below) the slot
# ('instance') will be assigned
def __init__(self, instance):
# this tells the compiler (which turns the script into
# instructions Live can actually execute) to start with
# the generic Control Surface initial setup. Super
# means that we're executing a command in there
# instead of code in here.
super(K1, self).__init__(instance, False)
# this is, as far as I can tell, a protection against crashes,
# everything I do will be encapsulated in this guard. I
# found a bunch of sources and scripts that
# recommended to import the 'with' command, which
# wasn't available in older versions of the script language,
# but that turned out to not be necessary in Live 10
with self.component_guard():
# now we can do things! The first line shows a message
# in Live's own status bar, the second adds a line to Log.txt
self.show_message("Hello World")
self.log_message("wayfinder K1 remote script loaded")
(Screenshot from Log.txt)
Next step: Getting something on the controller to actually control something in Live!