THERE IT IS: the ultimate custom module for cubase users (at least for me)

If anybody's interested : i now use a matrix widget, instead of 50 buttons widget...

ConstruisTaMap().then(cequilmefaut => {
        receive('/EDIT', 'matrix_articulations', {'props': `JS{
                var props={}
                let Index=parseInt($)+1
                var labs = ${JSON.stringify(mesArticulations)} //permet de retourner mesArticulations sous la bonne forme : ["a","b","c"...]
                var max = labs.length
                props.label= labs[$]
                props.visible = Index <= max    // Renvoi "true" ou "false" pour chaque Index, donc pour chaque widget de la matrice...
                                                // autre possibilité : props.visible = Index > max ? false : true sans rien, ni #, ni ""...
                return props

}).catch(err => {console.log(err);});} 

Where mesArticulations refers to :

async function ConstruisTaMap() 
    mesArticulations = []
    mesCouleurs = []
           for(const uneMap of toutesmesMaps)
1 Like

Hi @Sylvain, @Sub3OneDay , @gcat
Thank you so much for this! I think for many of us this post is a game changer.
Since a few days I try to reproduce your incredible trick with MACKIE to get the tracknames... but I stumble!
I read all the posts about sysex and it doesn't work, it drives me crazy :woozy_face:
I'm on mac and I'm using an updated version of M.Zilmer file which works very well with only one virtual midi port but it's a pain to juggle with the midisends every time I create a new track.

In the reflections you share here I don't know at the end what is the right version of the js/json,
which general setting in the midi field...

Could you share a stable version of your research?



If it can help, i share here mines.

Mon MINI KS.json (6.0 KB)
CubArtic.js (9.0 KB)


So actually, it works pretty well. Sometimes i have some little bugs and have, for example, to select an audio track, and then select the VST track, to get the articulations. Or something like this. I think still related to how the name is updated. Right now for example, at the very beginning, i had to switch between some tracks, a few times, before i could get the articulations. Don't know why. But once done, it's ok.

But it's so cool anyway ! :star_struck:

Just notice that i turned off the "send midi note 44" in the js, just because another part of my session deals with it.

Still have this "typo bug" in the code (trackName.lenth instead of trackName.length). It get worse when corrected, so i let it this way, as i didn't take time to really understand what was going on here. @Sub3OneDay will know better, it's his code :wink: :+1:

Oh, and btw... forget about HUI, stay with MCU... And don't forget to launch o-s-c BEFORE Cubase...

And one last thing, my maps are labelled this way :
"AmpleSound - ASBA - Bass Acoustic.expressionmap"

Good luck with all this !

Merci beaucoup!
I will test this tomorrow

Evening All,

I've tidied the whole thing up a lot and pulled a lot of the sections if it out into functions in the JS to make it all more manageable. Consequently there are many more lines of code now so too many probably to just paste here - I've added a file however with all the code in.

Some of this relates to my specific OSC session so it might not work directly but you should be able to work it all out from this and snip out what you need...
Good luck!

sysexAndNaming.js (23.0 KB)

1 Like

This is fixed I think...

Now not needed if you ensure you have
send('midi', 'MCU_From_OSC', '/note', 1, 44, 127);
Before anything else in the custom module - this is the cubase MCU handshake

Not really - it was a full team effort!

Wow... i just had a look at your js... and wow... just thinking "So many infos ! So much to learn from this !... but when ?.... and when will i get back to real life, now ? :smiley: "

Thank you very much for sharing this :+1:

1 Like

Just wondering - did you ever get through this little bug?…

If you didn’t I have finally got round to looking at it and have solved it in my CM now - track name extreatted cleanly every time, with no offset or random characters, even when going from midi to instrument or audio tracks… let me know and I’ll post if you need it.


Sure you can post your solution, it will help anybody :ok_hand:

Here you go - it's all down to how the MCU reads and erases characters on the LCD screen - if it knows that there are characters from the previous track it will send spaces, so you have to trim these off.

Here is the full function which you need to call:
  function getTrackName(sysExVal) {

    var nameDone = false

        var d = sysExVal.split(" ").slice(6).map(x => parseInt(x, 16)) //this devides up using  .split, then slices off the front 6 elements,  and x => parseInt(x, 16) converts the rest from Hex to Int then .map creates the array d[]
         pos = d[0] // first byte -> position // hex to int

        console.log("position = " + pos)
        //console.log("sysExVal = " + sysExVal)
        text = d.slice(1).map(x => String.fromCharCode(x))// these are the new characters which are updated on the console, the rest -> updated characters
        if (pos < 29) {

            return trackNameJoined
    text.pop() // drop sysex closing byte                    
    trackName = text.join('')

        //MCU only sends what it needs so you need to buffer the previous name and use parts of that
        //Check the length of the new name vs the buffer
        nameLengthCheck = bufferTrackName.length - trackName.length

        //MCU sends some sysex data to tell the screen where to start showing the new characters
        //This is related to the root position on the screen which is 72

        //Check if root position matches the position where the characters are to be placed
        charFromStart = pos - rootPosLCD

        var lengthCheck = charFromStart + trackName.length

    if (lengthCheck < 29) {

        let newEndLength = 29 - charFromStart - trackName.length

        newEnd = bufferTrackName.substring(bufferTrackName.length - newEndLength)

    } else { newEnd = "" }

    if (pos == 72) {       //Full length name received

        trackNameJoined = trackName + newEnd
        bufferTrackName = trackNameJoined
        posBuffer = pos
        // console.log('TrackName Joined = ' + trackNameJoined)

        nameDone = true

    } else if (pos > posBuffer && posBuffer == 72 && nameDone == false) {

        keepStringVal = pos - posBuffer  //new name follows a full string text

        var prevTrackKeep = bufferTrackName.substring(0, keepStringVal)

        trackNameJoined = prevTrackKeep + trackName + newEnd
        bufferTrackName = trackNameJoined
        posBuffer = pos
        nameDone = true

    } else {

        keepStringVal = pos - rootPosLCD  //new name follows a full string text

        var prevTrackKeep = bufferTrackName.substring(0, keepStringVal)

        trackNameJoined = prevTrackKeep + trackName + newEnd
        bufferTrackName = trackNameJoined
        posBuffer = pos
        nameDone = true


        //MCU will sometimes send the characters (MIDI) as part of the track name
        //so you need to strip these out
    const findMidiTag = '(';

    var posMidiTag ="\\(M");
    var posBrackTag ="\\(");

        if (posBrackTag == trackNameJoined.length - 1) {

            trackNameJoined = trackNameJoined.substring(0, (posBrackTag - 1))


        if (posMidiTag > -1) {

            trackNameJoined = trackNameJoined.substring(0, (posMidiTag - 1))


        //trim off all the spaces at the end

        trackNameJoined = trackNameJoined.trimEnd();

        return trackNameJoined


Thanks for sharing the solution. I'm new to OSC and my template only consists of some basic buttons so far triggering commands using Generic Remote. This is way over my head but I'm determined to implement this eventually! Curious @Sub3OneDay what your OSC template looks like.

Welcome to the fun Echo_7...

Since you ask, have a look here:

Something that I made With OSC

Some Extracts from My OSC Panel

Wow that's incredible! The Albion look is awesome haha. I'm sure you spent a while on those visualizations, but it looks really great. I may have to bother you at some point if I struggle with the expression maps! :slight_smile:

1 Like

Feel free to ask away - but be warned - OSC is a black hole... I used to be a composer - I'm now an OSC hobbyist...


Thank you for your great work!!
I'll have to ask a dumb question..
How excatly do I use this in OSC? :joy: :face_holding_back_tears:

After getting to know OSC
I'm always trying to get a better and even better solution for something...
There're just way too much knowledge to learn

I know I'll have to load this in the "custom module".
But after that, what's next?
In the server page, do I need to create a new session?

There is quite a lot on the forum already about Using custom modules generally but I'm (very slowly as busy) trying to pull together a step by step on how to implement this specific solution which I will post when done.


Hey Sylvain! :sob:

Could you plz tell me how do excatly do you use the custom module to read from cubase?

I'm totally new to the custom module.... I've read all the reply in this post, but still don't know how to get it to work. :sob:

And can you plz tell me how do you use osc to remote control the expression map of cubase?

People in this post seems always be talking about reading from cubase. But no one seems to be talking about how to control the expression maps :face_holding_back_tears:

I'd be very glad if you can help me, even just give me some clues

Thanks in advance!


first: very nice work !!!!! At all out there.

I have some questions:

how does the text widget get the data from the custom module?

And if i implement the node module xml2json i get a big err in my osc console?

It would be nice to get some help.