MIDI Remote API Help with LED activation

So I’m getting in over my head with the JS API for MIDI Remote.

Ultimately I want to get my X-touch One working in the way that I want, which I think I’ll be able to with the API. However, at the moment I’m experimenting with simpler controllers, and am having issues getting LEDs on buttons to work in the way I would expect. I’m by no means a JS developer, I’m just trying to learn as I go, so please take this into account!

I’ve created a functional script for my APC mini (which has a grid of buttons which send out Note On/Note Off, and illuminate as you would expect when used with the ‘consumer’ MIDI Remote - they light up when the button is pressed, and then go out when it’s released).

I want to control the LEDs, and at the moment I have the following script (this is part of a for loop, but you get the idea):

var button = deviceDriver.mSurface.makeButton(buttonIndex * 2, 8 - channelIndex, 2, 1)
        
            var note_number = (channelIndex * 8 ) + buttonIndex

            button.mSurfaceValue.mMidiBinding
                .setInputPort(midiInput).setOutputPort(midiOutput)
                .bindToNote (0, note_number)

            button.mSurfaceValue.mOnProcessValueChange = function(activeDevice, value) { 
                if (value)
                    turnOnLED(activeDevice, note_number)
                else
                    turnOffLED(activeDevice, note_number)
            }

This doesn’t work. However, if I change it so it’s always a fixed note number:

button.mSurfaceValue.mOnProcessValueChange = function(activeDevice, value) { 
                if (value)
                    turnOnLED(activeDevice, 1)
                else
                    turnOffLED(activeDevice, 1)
            }

This does work, but only on the same LED for all the buttons (i.e. the press status of any of the 64 buttons is reflected on button 1).

I’ve found the documentation pretty impenetrable (it seems merely to list methods and attributes, rather than actually document properly), and have just been doing trial and error and looking at a couple of scripts that users on here have posted. I think it would be helpful to encourage posting of JS files as well as .midiremote as then people can learn from what others have done.

Any help on this would be appreciated - I didn’t expect this part of it to be this difficult!

where do you have the implementation of the functions turnOnLED and turnOffLED?
try to add console.log(note_number.toString()) and verify in the log message view in Cubase, if the note numbers match with the APC mini.

Hi Marco

turnOnLED and turnOffLED are yours, from your CC121 script. They are in section one of the script, and work fine - definitely have the right numbers for the note_number variable, as if I don’t add the callback, I get buttons that light up when I press them (and work fine in the MIDI Remote display on screen), but they stay lit up, even after I’ve let go.

ok, so you’re saying that the correct buttons turn on the LED but do not turn it off anymore?
What host parameters did you assign to these buttons?
I would add a console.log inside the turnOffLED function to check if it is really called.
Also check with a console.log(value.toString()) that the value is 0.0 when releasing the button.

Yeah, if I don’t attached the callback function, then the LEDs in the buttons light up when I press them (and stay on). If I attach the callback function, then the LEDs don’t light up (other than if I fix the number at 1).

I haven’t assigned any host parameters yet - I wanted to get this part of things working first (although I had the same issue with the transport buttons on my X-Touch one script, and they were attached functions).

Both the on and off functions are being called (console log shows this).

I’m wondering if this is because note_number has a value in the loop when the callback is created, but it doesn’t have one when the function is actually called? I’m not fluent in JS (I’ve done a fair bit of Python and encountered similar things, such as mutable default arguments), so wondering if I’m missing something which is of this ilk…

So, further testing has shown this to be the case - if I hard-code the value in there, it works. But I can’t use the variable note_number, as it refers to the current value of note_number (which at that point is 98 purely by chance of the order I’ve done things in… and by bad coincidence is the only pad which doesn’t have an LED in, so it didn’t light up!)

I was thinking I could just add an attribute to the button variable (as I would have been able to in python), with something like this:

button['note_value'] = note_value

<snip>

turnOnLED(activeDevice, button['note_value'])

and then access that, but that doesn’t work - I get a value back of undefined from that (so that the button with note value of 0 gets turned on and off for all these buttons).

Any ideas how I can do this neatly? Hand-coding it for each one kinda removes the point of being able to use loops!

python: button[‘note_value’] = note_value
javascript: button.note_value = note_value

Maybe that’s it? IDK JS is painful. There are a lot of different way to do the same thing, and lots of little gotchas.

BTW I’m using TypeScript because ES5 is just too painful. I mean… it’s like VST2 era JS.

tsconfig.json goes in the same directory as your .tx file.

delete this line

Object.defineProperty(exports, "__esModule", { value: true });

edit this line

var deviceDriver = midiremote_api_v1_1.default.makeDeviceDriver('...

to

var deviceDriver = midiremote_api_v1_1..makeDeviceDriver('...

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      ".": ["."],
      "midiremote_api_v1": ["../api/v1"],
    },
    "module": "commonjs",
    "moduleResolution": "node",
    "target": "es5",
    "checkJs": true,
    "lib": ["es5"]
  }
}

Maybe someone knows how to fix the tsconfig so you don’t have to manually edit the js that is generated?

Also you loose completion that are type sensitive. I know there must be a fix, but I can’t find it. It looks like they built the API in TS so there should be a way.

The api description file is typescript. That’s what drives the autocomplete in vscode.

But I don’t think the export was done expecting anyone to write in TS. I haven’t written a lot of JS in the last 4-5 years or so. A lot before that, but not ES5.

I tried to get the import to work, but it doesn’t quite. So, manually editing.
Do you know how to fix that?

Thanks - I did try the dot notation, but VS Code complained about it. Using brackets notation (both of which work in Python, BTW), did ‘work’ in terms of VS Code not complaining about it, but didn’t functionally work…

I don’t know enough about ES5 to know how painful it is, but it’s certainly painful not being able to use

console.log(object)

So I can see what’s available and hopefully answer my own questions…

Anyone know how you can do a directory on an object in this situation here, so I can see what attributes are available (and should be assigned already, after all, given that the midi note number is assigned, and that’s what I want to access)?

oh wait…
Is that the same Button? It doesn’t already have a “note_value” member.
If I am guessing correctly, you need to save that somewhere else.

… or if you are trying to set the button element’s response
it is

 button.bindToNote(midi_channel, note_value)

Hi Guys, please have alook at the JavaSCript concept of Closures, as that’s what you have to understand to solve that problem:

I’ve already set the button’s note value prior to setting the callback function:

button.mSurfaceValue.mMidiBinding
                .setInputPort(midiInput).setOutputPort(midiOutput)
                .bindToNote (0, note_number)

Yea, TS will complain because of the import but:

var debug = true;
var DEBUG = function(logString) {
    if(debug){
        console.log(logString)
    }
}

Will narrow that complaint to one line. The JS it creates still works, as long as you do the two edits described above.

You have to remember to bind any immediate functions you create within an class though.

    method()
    {
        foo  = 
            function(arg1, arg2) {
                ...
            }.bind(this);
        }
    }

Closures are called “immediate functions” in other languages.

Do you know how to get the imports for TS working? It would make things a lot easier.

Is there no way for the function to access the button’s attribute?

The example given in the article doesn’t make it particularly clear what’s actually happening in terms of why i is the passed variable that’s then carried into the loop, and because the code I have is different (it’s not directly using the loop variable, nor is what’s inside the loop directly calling a function) it’s a little opaque as to how this would translate to the situation I’m in.

I’m a bit afraid about what you are trying to do with the tsconfig there. Do you want to use a transpiler, like Babel?

I don’t know Babel. I just followed the instructions that MS provided for what the config should look like. Then Google the errors and people were just like, delete the line manually, so… just to get things done, I’ve been doing that. Will google babble.

Hi @djaychela, could you please share the entire script, so I can have a look, please?