Understanding observers

Post Reply New Topic
RELATED
PRODUCTS

Post

Hi there

I'm having a bit of a time figuring out how the observers work. Basically I just want to send back a color to the controller based on the track color to some buttons. I guess I have to put in the addColorObserver somewhere, but how do I put it into a function? I might be a bit slow, I read Tom's page about it, but didn't emerge any the wiser.

I already have detection of track, rgb-buttons and midi to/from working (at least as much as the controller allows for now). Here is the code I'm using to send MIDI back, nothing much yet, but at least it works as intended. My question is just where I'll put the observer in this scenario?

Code: Select all

function rgbLedMidiOut(channelIn, controlIn, hue, sat, bri) {
    
    var midiChannelOut = [176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187];
    var channelSelect = 0;
    
    if (channelIn == 176) {
        channelSelect = 0;
    } else if (channelIn == 177) {
        channelSelect = 3;
    } else if (channelIn == 178) {
        channelSelect = 6;
    } else if (channelIn == 179) {
        channelSelect = 9;
    }
    
    println(midiChannelOut[channelSelect]);
    println(midiChannelOut[channelSelect] + 1);
    println(midiChannelOut[channelSelect] + 2);
    
    host.getMidiOutPort(0).sendMidi(midiChannelOut[channelSelect], controlIn, hue);
    host.getMidiOutPort(0).sendMidi((midiChannelOut[channelSelect] + 1), controlIn, sat);
    host.getMidiOutPort(0).sendMidi((midiChannelOut[channelSelect] + 2), controlIn, bri);
}
(yeah, it's a bit of a mess to send the three channels of color data back)

Post

Magneson wrote:Hi there

I'm having a bit of a time figuring out how the observers work. Basically I just want to send back a color to the controller based on the track color to some buttons. I guess I have to put in the addColorObserver somewhere, but how do I put it into a function? I might be a bit slow, I read Tom's page about it, but didn't emerge any the wiser.

I already have detection of track, rgb-buttons and midi to/from working (at least as much as the controller allows for now). Here is the code I'm using to send MIDI back, nothing much yet, but at least it works as intended. My question is just where I'll put the observer in this scenario?

Code: Select all

function rgbLedMidiOut(channelIn, controlIn, hue, sat, bri) {
    
    var midiChannelOut = [176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187];
    var channelSelect = 0;
    
    if (channelIn == 176) {
        channelSelect = 0;
    } else if (channelIn == 177) {
        channelSelect = 3;
    } else if (channelIn == 178) {
        channelSelect = 6;
    } else if (channelIn == 179) {
        channelSelect = 9;
    }
    
    println(midiChannelOut[channelSelect]);
    println(midiChannelOut[channelSelect] + 1);
    println(midiChannelOut[channelSelect] + 2);
    
    host.getMidiOutPort(0).sendMidi(midiChannelOut[channelSelect], controlIn, hue);
    host.getMidiOutPort(0).sendMidi((midiChannelOut[channelSelect] + 1), controlIn, sat);
    host.getMidiOutPort(0).sendMidi((midiChannelOut[channelSelect] + 2), controlIn, bri);
}
(yeah, it's a bit of a mess to send the three channels of color data back)
Looks like you are using NI stuff? Bitwig colors are in RGB, so you need to convert RGB to HSB, I am doing this with the Maschine and clip colors.

You might want to check out Framework4Bitwig eventually, all this stuff is taken care of for you. :)

https://github.com/teotigraphix/Framework4Bitwig

I could help you out down the road if you were interested.

Mike

Code: Select all


// TrackBank created in init()
var trackBank;

// global model in your case
var tracks = createTracks(8);

function addObservers(trackBank)
{
    for (var i = 0; i < 8; i++)
    {
        // you could add ANY track observers here, this just shows color
        var track = trackBank.getChannel (i);
        var slots= track .getClipLauncherSlots ();
        slots.addColorObserver (doObjectIndex (this, i, handleSlotColor));
    }
}

...

function handleSlotColor = function (index, slot, red, green, blue)
{
    // save this information into your model when you update your controller with the code above
    // 'tracks' would be globally accessed here.
    // getColorIndex() could return a custom Color class you create that takes RGB, converts to HSB
   // then saves that instance into the slot, when you then go to access the slot when you are ready to
   // send your MIDI, you just access your color instance's h, s, b values and send them on the correct channel
    tracks[index].slots[slot].color = this.getColorIndex (red, green, blue);
};

/**
 * Framework4Bitwig's track creation. (Creates the persistent model for a track bank.
 * All the object variables below get updated in all the observers.
 */
function createTracks(count)
{
    var tracks = [];
    for (var i = 0; i < count; i++)
    {
        var t =
        {
            index: i,
            position: i,
            exists: false,
            selected: false,
            name: '',
            volumeStr: '',
            volume: 0,
            panStr: '',
            pan: 0,
            vu: 0,
            mute: false,
            solo: false,
            recarm: false,
            monitor: false,
            autoMonitor: false,
            sends: [],
            slots: [],
            crossfadeMode: 'AB'
        };
        for (var j = 0; j < this.numScenes; j++)
            t.slots.push ({ index: j });
        for (var j = 0; j < this.numSends; j++)
            t.sends.push ({ index: j });
        tracks.push (t);
    }
    return tracks;
};

/**
 * Utility:  Keeps index and object scope in the callback.
 */
function doObjectIndex (object, index, f)
{
    return function ()
    {
        var args = [ index ];
        for (var i = 0; i < arguments.length; i++)
            args[i + 1] = arguments[i];
        f.apply (object, args);
    };
}
Michael Schmalle
http://www.teotigraphix.com
Surfing on sine waves

Maschine4Bitwig - Studio, MK2, MikroMK2, MK1
http://www.teotigraphix.com/bitwig/maschine

Post

Thanks Mike great as always, I'll sure take a look at it :). Yes it is NIs Dj controller (S4 mk2) which has proved pretty useful in our bands scenario at least. I originally started writing a small live looper and FX unit for it in Reaktor, but then I stumbled across Bitwig which provides a bunch of additional features and a seemingly easier approach and workflow to say the least, so I'd rather make an effort here instead (even if it means learning JS).

The biggest problem with the S4 at the moment is that there is a bug in the midi receive part of the controller making the color changes affect buttons also on deck b, c and d. Apart from that it is a pretty easy controller to deal with, as there are only one set of numbers for the buttons/knobs, and then the decks are differentiated by channel.

I'd really appreciate some help from time to time if possible, I'm pretty new to JavaScript (only dabbled a bit in processing before), so I'll probably make a mess to start with.

Post

Hmm,I get an error message from the color conversion function:
missing ( before function parameters.
And then it points to this line:

Code: Select all

function handleSlotColor = function (index, slot, red, green, blue)

Post

My bad, this was a copy paste thing from existing code;

It's;

Code: Select all

function handleSlotColor(index, slot, red, green, blue)
{
    tracks[index].slots[slot].color = getColor(red, green, blue);
}

function getColor (red, green, blue)
{
    // do your color conversion here, return a color object
    return new Color(r, g, b);
}

function Color(r, g, b)
{
    this.h = null;
    this.s = null;
    this.b = null;
    // do your conversions and set the above member fields
}
Mike
Michael Schmalle
http://www.teotigraphix.com
Surfing on sine waves

Maschine4Bitwig - Studio, MK2, MikroMK2, MK1
http://www.teotigraphix.com/bitwig/maschine

Post

Thanks!

Post

Observers are just a way to be notified and retrieve values when they change in BWS.
You don't put them directly in the code where you need the colour, but you create the observers in the init() function and write for instance the colour into a variable or array whenever it changes. Then in your code you grab the colour from that variable/array.
You simply can't access most values directly.

Since observers only fire on change, you can also use them to keep your controller lights updated.

If you can explain what part you don't get, I'm happy to explain further.
I found it pretty opaque at first as well.

Cheers,

Tom
"Out beyond the ideas of wrongdoing and rightdoing, there is a field. I’ll meet you there." - Rumi
ScreenDream Instagram Mastodon

Post

Thanks Tom! (and thanks for the scripts and tutorials).

I think it's just me needing a more direct explanation of the exact functions, where to put them and what they do. I guess that is more of a reference thing though. I think the Processing reference is a great way to show it, where the functions parts are explained and a small example of just exactly what it is the function does. On the other hand, it might be that it has made me a bit unprepared for more direct usage of java(script) as it shaves off some of the parts that probably are made clear in the reference nest (as where to put stuff).

Your explanation here was pretty much spot on in that matter, could I ask for an example of code to pull out just a single slot color?

Post

Well, it may take a while until the docs get to the level of Processing ;-)
It's my dream too, but don't hold your breath yet, the API is still changing a lot ATM...

I assume you already have your slots and variables defined globally.

Then in init() you create your observer like this pseudocode (adapt to your variables etc.):

Code: Select all

YourClipLauncherSlots.addColorObserver(function(index, red, green, blue) {
   YourVariable[index].red = red;
   YourVariable[index].green = green;
   YourVariable[index].blue = blue;
   coloursHaveChanged = true;
});
You can then react to the flag coloursHaveChanged however you see fit, for instance in the flush() function, which is getting called whenever an observer fires.
Often it makes sense to check there what actually changed from the previous state and only send the changes - some controllers are a bit sensitive when it comes to Midi load...

I hope this makes sense.

Cheers,

Tom
"Out beyond the ideas of wrongdoing and rightdoing, there is a field. I’ll meet you there." - Rumi
ScreenDream Instagram Mastodon

Post

Thank you Thomas. I've been a bit busy lately, and were a bit impatient as I used the demo where I couldn't save, which got a bit tedious. When I then got my producer pack, that wasn't licensed for beta usage, but now I'm finally up & running with 1.1 so I'll hopefully get some progression on it soon. Great to have help in the forums!

Cheers!

Post Reply

Return to “Controller Scripting”