Lim (lua in max) beta

hi friends, here’s a lil project baby I’ve been working on for a bit :

in this video I’m running earthsea.lua ( from we ) mostly unmodified within the max/msp environment, connected to a patch. it’s kind of barely stable as of writing, but I figured I’d put the idea out there today at least to see what comes to mind for everyone.

what my goals are for this project :

  1. solve the issues revolving around developing grid apps in pure max, especially for beginning programmers. designing grid interfaces in lua is more approachable and flexible than doing so in pure max, while developing a sound engine in max around a lua script is fairly intuitive imo.

  2. help unite hardware-focused grid artists with software-focused grid artists, most of whom probably work in ableton/m4l. there will not be a completely shared codebase between norns and lim, but there will be a lot of crossover where previously there was none. ‘midi’ focused scripts, for example, will hopefully just be copy-and-paste, and easily turned into m4l midi devices. right now, engine commands are just sent out of the lim.grid abstraction while params can be set with messages in.

what my goals aren’t for this project :

  1. emulating norns hardware. laptop computers do not have encoders, keys, and a tiny screen, obvi. I’d rather focus on sulutions for controlling scripts that are more appropriate for the context, like integrating params and Ableton Live Parameters, for example, or just adding more faders and the like to the grid scripts. I like to use midi cc’s, personally. we’ll see how things go.

  2. porting SC engines. really I think the advantage of working in ableton or max is more options for what an ‘engine’ would be (whenever the engine is something like a synth). in the case of softcut (sc no more), I’ll be working on a solution in the near future to help sub in karma~. this is less than ideal, so I’ll be exploring better solutions since buffer stuff is one of my main interests with grids.

but anyway, with that in mind, I’d love to hear from everyone else - if you would be interested in develong or using lim apps and how ! this is essentially an early cut from a larger project I’m developing for me, so it’s really for the community, and I’m down with building it out in a way that makes sense for everyone else.

my immediate next goals will be working w/ @Dan_Derks on a m4l less concepts probably and making a karma~ based modification of mlr in m4l once the 2.0 script is out. woo !


softcut itself can also “easily” be ported to msp~ (/AU) if that is desirable

… though to be clear, i dunno if i’d recommend it as a first c/c++ project.
you’d be taking this:

and smashing it into something like this:

… and again, it already runs on macOS as a jack client.

1 Like

sounds like my kind of job


so stoked, @Andrew – this looks incredible! wonderful work.

I forgot to tell you, I ported it this weekend in anticipation of dope lim grid integration!


If you don’t need brightness levels, that couldn’t be more false. [matrixctrl] is life!

Oh, this is beautiful. Thanks!



I started learning Max a few months ago mostly in anticipation of acquiring a grid this year (and just spent this entire week attending courses with a max teacher), and I just stumbled upon this, it looks amazing!
Now I can’t wait to try it out :slight_smile:, thanks a lot for your work!

yay ! would be stoked to have anyone try this out & help me beta test. I think lua is a better grid programming choice for anyone less familiar with max.

this is starting to get beyond me so I’m throwing it out to there

I’m using to run lua (same as the crow folks), but I really can’t tell if I can do C bindings in that environment. for the most part I’ve just been doing workarounds in max whenever I’ve come across a C binding in norns/lua, but my workarounds for metro.lua are just not having it. there really isn’t a way to do timers in pure lua and doing timing back and forth from max is causing incredibly spontaneous full application crashes.

from what I can comprehend from the docs it seems like I need access to the interpreter to add C to my script, but I’m assuming in this case I don’t have that, and also, like how would I package that anyway ? can I just include a C file from lua ? (I’m using dofile() to include other lua scripts from lua) ? will max let me do that ?

In addition to loading Lua scripts, can load compiled C
modules (on OSX only right now) that extend its capabilites.

A very old max forum post mentioned this but I could not find any further info. :triumph::triumph::triumph:

any insight from the lua experts would be greatly appreciated !

1 Like

I’m definitely not an expert, but a lua script should be able to load a specially-compiled C library (usually with a .so extension) as a shared object/library, with loadlib():

Shared libraries can be really fussy to build and distribute though. I wonder how good you could get timing resolution if you just had a max metro just send bangs at a regular interval, and count those? Could that get down to 1ms, 10ms?

1 Like

C functions have to be compiled and linked one way or another. they don’t have to be defined in the lua interpreter code, that’s just used as an example for the PIL book.

sorry i don’t specifically know the best way to build+link a dynamic library for use in… i assume that @germinal is right and it’s not really different from loading a .so/.dylib for lua in general, but there could be complications for sure. (like the way lua is being embedded in a cocoa app. i see some stuff from the author on the lua mailing list, maybe a thread worth pulling.) you could look at a sample external project for guidance on compilation/installation settings for dylibs loaded by max.

if you are gonna go that route i would recommend using the Max scheduler API instead of getting in its way by managing your own timing threads

it would be nice if the main max SDK was exposed in lua, but i’m guessing that’s not the case and you can only manage jit objects, yea?

finally i’ll echo the opinion that dealing with low-level extensions to the lua environment in max generally sounds like a source of pain; at minimum you will have to distribute an extra bit of compiled binary code for each platform. a workaround in max would be way easier to manage.

off the top of my head i would concur that a fast metro object could provide a scheduler tick, and that could drive a little soft-timer system in lua using coroutines. this would have much coarser resolution than norns metros, but usable for many things (and not significantly worse than using the max scheduler from C.)


so, to elaborate, my current genius method of doing this now is sending a message to a js object whenever I need to initiate a metro, js gets Task object ticking, Task callback sends a message out and back into In my tests it seemed like below a certain timing threshold max would just crash. just a guess since I didn’t have any error messages to work with, but It’s not hard to imagine all sorts of scheduling issues coming out of this.

looks like it. for using jitter objects and some C bindings to OpenGL ? would be nice if I could take a look at those libraries but I’m guessing I can’t.

so, essentially, once I get a c lib loaded it’ll have access to everything an external would ?

I keep running into fossil evidence of lua~ which I suppose did exactly that, exposed msp to a lua script, but given I can’t find an active download link I might assume that one’s extinct.

but uhhhhhhhhh yea maybe since this is my first go at things I should keep it simple and “quantize” my events to one metro. def something I considered. is 1ms as far as I can take that down ? In my head that seemed too high to get something musical, but I haven’t tested it yet. will for sure start on the easy route now that it’s back in play.

as a bonus with that method I suppose I can sync to the global when in m4l for the tempo-friendlies

thanks for the goods @germinal @zebra

1 Like

i’m making a lot of assumptions, but i’d think it would basically work if your C source included the max SDK headers. the lua interpreter must be linked to the SDK one way or another.

but yea this might be a rough place to start if you haven’t built and used C dynamic libraries before.

is 1ms as far as I can take that down ?

i guess. haven’t used max in a long time. IIRC you can change the scheduler tick rate a bit, but i dunno what metro exposes these days. it’s not gonna be much faster than 1ms. (maybe 32 samples or something.)

but anyyways, i don’t see how would be able to produce more precise timings than the max scheduler itself, so it’s a bit of a moot point.

1ms is plenty of resolution for musical applications. unless you have the ability to produce 1khz tones by drumming them. (/controversial opinion)


working on it. getting there. intense training for sure.

but tyty I think I’m just gonna go off and make myself a metro to same time/brain cells - will report back !


some more norns/max dev questions for this thread:

I’ve been spending the last few days studying up and working on an external for softcut (using MaxCpp per @zebra’s suggestion above). It’s been pretty approachable, I think I’m almost ready to get a successful build but I’m getting these kind of confounding Undefined Symbol errors from the linker.


That looks like it’s coming from the sofcut code, but we know that works so I’m wondering if it’s somewhere in my Xcode target config or c++ versions or somewhere on that side of thing. From what I’ve gathered this error is supposed to mean a function is declared and not defined, but seems like it can also point to trickier issues.

This is the only code I’ve actually written, doesn’t really seem like it’s the source of the problem though.

#include "maxcpp6.h"
#include "softcut/SoftCut.h"
#include "softcut/Types.h"
#include "Utilities.h"

// inherit from the MSP base class, template-specialized for myself:

class Softcut_msp : public MspCpp6<Softcut_msp> {

enum { MaxBlockFrames = 2048, NumVoices = 6 };
enum { BufFrames = 16777216 };

softcut::SoftCut<NumVoices> cut;

float buf[2][BufFrames];

bool enabled[NumVoices];
softcut::phase_t quantPhase[NumVoices];

Softcut_msp(t_symbol * sym, long ac, t_atom * av) {
    setupIO(NumVoices, NumVoices);
    post("object created");
    for(int i=0; i<NumVoices; ++i) {
        cut.setVoiceBuffer(i, buf[i&1], BufFrames);

~Softcut_msp() {
    post("object freed");

// methods:
void bang(long inlet) {
    post("bang in inlet %i!", inlet);
void test(long inlet, t_symbol * s, long ac, t_atom * av) {
    post("%s in inlet %i (%i args)", s->s_name, inlet, ac);

// default signal processing method is called 'perform'
void perform(double **ins, long numins, double **outs, long numouts, long sampleframes) {
    // example code to invert inputs
    for (long v = 0; v < numouts; v++) {
        double * in = ins[v];
        double * out = outs[v];
        if (!enabled[v]) {
        cut.processBlock(v, (const float *) in, (float*) out, (int) sampleframes);

C74_EXPORT int main(void) {
    // create a class with the given name:
    REGISTER_METHOD(Softcut_msp, bang);
    REGISTER_METHOD_GIMME(Softcut_msp, test);

anywho, I’ll keep digging but wanted to post in case anyone had any quick pointers

it looks like you are not compiling SoftCutVoice.cpp

is your xcode project on github? that might be a better place to share stuff (there could be quite a bit more of this) and i can probably help

(that said, i’ve found setting up xcode to build max externals to be a serious PITA in the past. i just end up customizing sample projects and leaving them in the SDK directory tree.)

@andrew oh but real quick, take a look at the CMake targets for crone:

you will probably want to compile src/softcut/*.cpp

IIRC, softcut doesn’t have any library dependencies, but does need a standard like c++11 or c++14 or something.

also, thanks for taking that on!

1 Like

ahhh yes compiling the code would be useful !

here’s a quick repo

just a straight modification of the msp example right now ( maxcpp-master goes in the sdk folder which you probably already know that )

I added boost ? couldn’t seem to get it going without ?

anyway that’s probably that tidbit of info I needed to move forward tomorrow but feel free to poke with the repo ofc

1 Like

oh, good good - sorry yes, just using BOOST_ASSERT i think? should be fine to lose those lines at this point

TBH i will probably not take time to work with this myself (unless needed, no prob) but happy to answer such q’s

hey @andrew

just a heads-up, and sorry this is kinda off topic, but
i forked your softcut port to check it out, and ended just starting over:
[ ]

spoiler: doesn’t work yet. something is borked with the buffer format or i dunno. i will continue to poke at this, but wanted to let you know asap, in case it saves duplicate work.

some differences with this project:

  • uses max8 sdk, not max6
  • doesn’t use maxcpp, which doesn’t seem necessary anymore
  • uses new softcut sources from norns repo, not stale ones from the standalone version
  • i cleaned out the boost dependencies
  • the external only implements one voice
  • takes buffer argument from MSP instead of managing a huge buffer itself

(these last two things make it a much better citizen of max-land i think. i would probably make some more changes eventually, like a signal-rate position reset trigger.)


ah nice nice, thnx for the info. the last two were in the plan once I got some output happening but sounds like yr taking it in a better direction that what I could attempt to throw together !

rlly excited to have this in my patches - appreciate the contribution as always @zebra