Ableton Live Control Surface Development Adventure: EP-01

EP-01: HELLO, WORLD! I bought a budget M-VAVE SMK25-II MIDI controller a few days ago and later found out that it cannot control Ableton Live out of the box. I did some research and got a few options: Select "MackieControl" for Control Surface in the Live's setting Use an unofficial MidiSuite preset and remote script that I found online. Write a custom MIDI remote script from scratch As a software developer myself, I chose option 3. What a great learning opportunity! Ableton Live loads remote scripts from multiple directories. Some information regarding the control surface can be found at https://help.ableton.com/hc/en-us/articles/206240184-Creating-your-own-Control-Surface-script. Also Live loads from [USER_LIBRARY_PATH]/Remote Scripts folder. For me, I chose [USER_LIBRARY_PATH]/Remote Scripts and created a folder called SMK25II there. Basically, that folder is a python package which exports a function called create_instance. And that function returns a Control Surface object, which controls Ableton Live and do other stuff. To get started, I created __init__.py, logger.py and SMK25II.py. Here's the current folder structure: . ├── __init__.py ├── SMK25II.py └── logger.py logger.py is pretty simple. It uses logging package and exports a logger. from logging import getLogger logger = getLogger(__name__) As I mentioned before, __init__.py should export a function called create_instance and that function should return a Control Surface object. Since there's no documentation for ControlSurface object, I had to do research and read some codes. And here's the minimal ControlSurface object which does not throw an error. from .logger import logger class SMK25II: def __init__(self, _): logger.info("Hello, World!") def disconnect(self): pass def refresh_state(self): """ Live is calls this method. But I have no idea what it is for (at the moment). """ pass def update_display(self): """ Live is calls this method. But I have no idea what it is for (at the moment). """ pass def connect_script_instances(self, _): """ Live is calls this method. But I have no idea what it is for (at the moment). """ pass def can_lock_to_devices(self): """ Live is calls this method. But I have no idea what it is for (at the moment). """ return False def build_midi_map(self, _): """ Live is calls this method. But I have no idea what it is for (at the moment). """ pass Then, I fired up Ableton Live and select my Control Surface SMK25II in the settings. Input/Output are not important as of now. The "Hello, World!" is logged in the Ableton Live's Log.txt file. Log.txt path can be found at https://help.ableton.com/hc/en-us/articles/5301568366354-Reading-Live-Crash-Reports. Well, this is the end of EP-01. Even though this series is written based on the M-VAVE SMK25-II, some concepts can be applied to other controllers as well. Thanks for reading! See you in the next episode.

Mar 14, 2025 - 15:08
 0
Ableton Live Control Surface Development Adventure: EP-01

EP-01: HELLO, WORLD!

I bought a budget M-VAVE SMK25-II MIDI controller a few days ago and later found out that it cannot control Ableton Live out of the box. I did some research and got a few options:

  1. Select "MackieControl" for Control Surface in the Live's setting
  2. Use an unofficial MidiSuite preset and remote script that I found online.
  3. Write a custom MIDI remote script from scratch

As a software developer myself, I chose option 3. What a great learning opportunity!

Ableton Live loads remote scripts from multiple directories. Some information regarding the control surface can be found at https://help.ableton.com/hc/en-us/articles/206240184-Creating-your-own-Control-Surface-script. Also Live loads from [USER_LIBRARY_PATH]/Remote Scripts folder.

For me, I chose [USER_LIBRARY_PATH]/Remote Scripts and created a folder called SMK25II there. Basically, that folder is a python package which exports a function called create_instance. And that function returns a Control Surface object, which controls Ableton Live and do other stuff.

To get started, I created __init__.py, logger.py and SMK25II.py. Here's the current folder structure:

.
├── __init__.py
├── SMK25II.py
└── logger.py

logger.py is pretty simple. It uses logging package and exports a logger.

from logging import getLogger

logger = getLogger(__name__)

As I mentioned before, __init__.py should export a function called create_instance and that function should return a Control Surface object.

Since there's no documentation for ControlSurface object, I had to do research and read some codes. And here's the minimal ControlSurface object which does not throw an error.

from .logger import logger

class SMK25II:
    def __init__(self, _):
        logger.info("Hello, World!")

    def disconnect(self):
        pass

    def refresh_state(self):
        """
        Live is calls this method. But I have no idea what it is for (at the moment).
        """
        pass

    def update_display(self):
        """
        Live is calls this method. But I have no idea what it is for (at the moment).
        """
        pass

    def connect_script_instances(self, _):
        """
        Live is calls this method. But I have no idea what it is for (at the moment).
        """
        pass

    def can_lock_to_devices(self):
        """
        Live is calls this method. But I have no idea what it is for (at the moment).
        """
        return False

    def build_midi_map(self, _):
        """
        Live is calls this method. But I have no idea what it is for (at the moment).
        """
        pass

Then, I fired up Ableton Live and select my Control Surface SMK25II in the settings. Input/Output are not important as of now.

Ableton Live's Settings

The "Hello, World!" is logged in the Ableton Live's Log.txt file. Log.txt path can be found at https://help.ableton.com/hc/en-us/articles/5301568366354-Reading-Live-Crash-Reports.

Hello, World!

Well, this is the end of EP-01. Even though this series is written based on the M-VAVE SMK25-II, some concepts can be applied to other controllers as well. Thanks for reading! See you in the next episode.