Thinking out loud: a scripting language for Cantabile

Some thoughts after having followed the discussion for some time:

Two scenarios for scripting, with different requirements for a scripting language:

  1. real-time processing within the audio cycle - mostly MIDI processing. For that, we would need a very efficient language, ideally without any time-consuming garbage collect requirements. Explicit memory allocation, simple data types only, simple control structures, limited and explicitly declared access to Cantabile variables, etc. And ideally pre-compiled for speed

  2. General, more complex automation tasks (“super-bindings”) to react to MIDI and other Cantabile Events (e.g. state changes). These wouldn’t need to run within the audio thread - more like batch scripts to automate the UI. For these tasks, a different language might be better suited - full on-demand access to Cantabile variables, objects and binding points, more complex data and control structures, etc…

Maybe two different languages?

Cheers

Torsten

3 Likes

Coming in late to the discussion here. One thought I had regarding the difficulties and complications of a language with a garbage collector running on the audio engine, would be to consider that if you’re creating your own internal language, you can place your own constraints on it, to suit the application. One possible approach would be to require all memory/variables etc. to be declared up-front in the script, before any actual execution. It’s an approach I’ve seen in some embedded development, where there’s no OS or runtime, and all memory is mapped out in advance at the start by the compiler, onto on-CPU RAM/registers.

I know it might feel cumbersome to those coming from a memory-managed scripting language background, but it would mean scripts could run super-fast with no memory management problems, which is exactly what you’d want for anything running on the audio thread. It may also be not such a big disadvantage for the kinds of things people might want to run in the audio engine, which I’m guessing would be mostly small, tight, relatively simple processing units.

An approach to consider, at least.

2 Likes

Thanks all the feedback guys.

Crazy idea (maybe not): what about C as the scripting language for stuff on the real-time thread?

I’ve been playing around with tcc (tiny c compiler) and its ability to compile C code directly to memory and run it is very cool. Some implicitly included header files for MIDI data packets etc… and the audio engine could call this reasonably easily.

Yes, or rather than some weird syntax that requires declaring things up front, link the user’s C code with a runtime that explodes if you do anything bad on the audio thread (like allocating memory, reading a file etc…)

The more I think about it, the more I like the idea of using C

Brad

4 Likes

Not crazy at all. Standard C is a good and easy language, and if you say tcc is very cool, C is welcome. image :rofl: :rofl:

2 Likes

Great idea. As long as we get a couple of useful automatic #includes and an easy structure to read the incoming midi data buffer, vst parameter automation (sample accurate) and put stuff into the output buffer.

A midi processor should pretty much work like a vst MIDI plugin; as such it will probably need a very simple structure

  • a definition section, defining used variables and buffers, as well as automation parameters exposed. Maybe also defining input and output ports (if you want to have multiple)? It also should define the external (Cantabile) variables used by the script so the environment can provide a “current cache” for these variables
  • an initialization section whenever the script is instantiated to set useful base values for the variables
  • a “queue processing” section that gets called for every MIDI data buffer and that has access to time-stamped MIDI and automation data for the current batch

Unlike ReaJS, which has a “slider” section, which handles vst parameter changes, I’d prefer parameter changes in the “buffer processing” section, so we have a common (time-position-ordered) input queue of MIDI events and automation events. That would make it very easy to work with sample-accurate automation - walk through the input queue item by item and process them in order. So every MIDI event is processed with the most current VST parameter values.

Just thinking out loud, based on my experience building ReaJS scripts…

3 Likes

C is fine by me. :slight_smile: it was always intended as a lightweight language that could be quite close to the architecture.

Anyone for assembler? :wink:

1 Like

Are we still talking about a scripting language, or are you envisioning a plugin API for user-compiled binary extensions to Cantabile (e.g., DLLs)?

The latter seems to me like the ideal solution, since it would allow C programmers to write super-fast real-time code when needed, while also allowing you (or anyone) to write a plugin that implements a safer, more user-friendly scripting language (e.g., a plugin that interprets or JIT-compiles user-supplied scripts and calls the underlying C API to effect script actions). That would give you the freedom to develop scripting capabilities as an optional plugin without adding that code complexity directly to Cantabile’s core.

1 Like

@brad I could definitely live with C as the language. My memory needs are pretty small (20 or less variables), and I’m not looking to print out messages on the UI or anything. I could live with the suggestion of defining all variables at the top of the script; this would both speed execution and eliminate the need for complex memory cleanup.

Here are three things that I found difficult or impossible to program in Cantabile via MIDI:

  1. Thinning data – i.e., sending only the nth event of some type
  2. Creating last-note priority for mono leads
  3. Storing the current value of a pedal or knob
  4. Mapping all notes of any velocity to the same note on a different channel.

I know the 4th one can be done with the current generation of Filters, but it takes 3-4 of them, as well as both a little imagination and careful ordering. It could probably be done with 1-2 lines of C code.

Regards
-BW

I like the three things adding up to 4 :joy:

All of this is pretty easy using ReaJS - and I’d expect it to be even easier in a future MIDI processor

1 Like

Everything starts at “Hello World”…

4 Likes

That’s excellent!!!

One thing I wonder about, since it’s compiling to real C and executing it. If this eventually makes it into Cantabile, will it be possible to protect the Cantabile session from crashes in any way?

2 Likes

One small step for a Brad, one giant leap for Cantabile users, I hope. :slightly_smiling_face:
I know, it’s not a original thought, but I really like this Hello World.

1 Like

Only in so much as the language itself would be “safe”: bounds checking on arrays, no direct pointer references, support for exceptions etc…

1 Like

Maybe a dumb question, but what is this all meant to do? Can anyone please give me an example?

There are no dumb questions, but this requires some background and forward thinking…

The idea behind all of this is to provide the ability to do user scripting in Cantabile - both in the audio engine (eg: MIDI processing) and in general (app level control like load a song, switch states etc…). The whole idea started because support for binding expressions were so well received, but also so limited (only supports expressions, no flow control and can’t run on the audio thread).

I got to thinking about what it would take to add a more capable scripting language but wanted some feedback on whether it would useful and what it would be used for - hence the reason I posted this topic in the first place and you can read back through the replies to see some interesting suggestions.

But before I can add scripting, I need a scripting language. But for it to run on the audio thread, there are some very strict requirements so it can run without stalling and causing glitches. This makes me very wary of using an existing language - either because they use garbage collectors that are known to stall, or because they’re loosely typed which makes them slower, or because they’re just too unknown, or because I just don’t like the language, or because I have “not invented here syndrome”.

So I decided to do a little proof-of-concept for a language that:

  • Has well controlled memory management. In this case it has a garbage collector but is designed to be very incremental so as to not cause stalls. It also supports plugging in a heap allocator so it can use Cantabile’s non-blocking heap to run on the audio thread
  • Strongly typed - for performance reasons
  • Compiled to machine code - again for performance reasons
  • Is strictly single threaded, but only on a per-script basis - for simplicity
  • Is very focused on scripting - ie: designed for small automation and processing tasks, not for building entire applications, has top-level statements and minimal to no “plumbing” code.
  • Is modern and clean - I’m modelling it very closely on C#.

And that’s all this is… a proof-of-concept language to see if the above is possible.

So far it certainly looks possible - I’ve built a tiny language that will meet all of the above but is so far very limited and barely does anything.

It’s also probably too much work to be worth it - but I’m continuing to play with it mostly because I find it interesting but also because it might pay off in the long run. For now, don’t expect this to see the light of day but I might continue to ramble on about it (although I think I’ll shift the discussion from Cantabile forum to the Topten Software blog).

So far, I’ve treated this as a holiday period project but will probably move it to a side project as I don’t want it to interfere with on-going Cantabile development once I switch back into work mode.

Also, in the meantime I hit on the idea of using C for the audio thread scripting - that is much more likely to happen.

3 Likes

Thanks. All good. Just thought it worth asking as I don’t understand the uses for this level of configurability.

For myself… I grew up with BASIC and COBOL. C remains baffling to me, so I doubt I’ll be dabbling! But never say never…

I think that regardless of how straightforward the resulting language is, it is likely to remain something only a small portion of users write scripts for. That would suggest to me another requirement worth considering - ease of sharing of scripts. That way a broader group of people can benefit from the shared work of those who delve into the coding. So the ability to pass small text files around holding scripts, and for them to be as minimally tied to a person’s particular setup as possible, such as keeping them agnostic to things like port names.

6 Likes

Hi @Neil_Durant,

This is a good point. My thoughts here were to not store the script content in the song/rack files directly. But rather have a directory of scripts, that are referenced from the songs. I guess similar to how you add a plugin, you could add a script. Something like that…

It’s a long way off yet, but definitely worth thinking about.

Brad

2 Likes

For those interested in following along with the development of this (it’ll be a side project to Cantabile) I’m moving the discussion to the Topten Software Blog where I’ll be publishing a new article about it each week - second one coming out tomorrow.

Please feel free to comment if so inclined (you’ll need to subscribe to a free member account to leave comments).

2 Likes

Just one thought/question from me. Where in Cantabile will we be able to use this scripting language?

I am asking as it occurred to me it would be good to be able to script your own custom MIDI filters in MIDI routes, but cannot recollect that being discussed as an option