Java Callbacks?

Post Reply New Topic
RELATED
PRODUCTS

Post

Struggling here with really wanting to have C or JavaScript like callbacks where you can pass in a function pointer to a function vs defining an interface just to do a single use callback.

I did a bunch of google searches on the subject and they all say "build an interface"...I'd be happy to if it made sense but this really adds a lot of uneccessary code and passing around objects to do the callback. When you could simply pass a a function pointer. So I think there must be a better way...

... it seems like bitwig has callbacks right? They don't make you create implement an interface to get a callback from an observer. What is the programming pattern for that? How can I learn more about this wizardry

addValueObserver(), addIsPlayingObserver()...addHasContentObserver()... these all take some sort of specialized class as a parameter... IndexedBooleanValueObserver for example... Any ideas what the contents of that object type is? how it works? and why i can just pass a function into it? I love it because its so simple to use!
----------------------------------------------------------------------
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest

Post

My answer may not be the most accurate (I develop in Scala, not Java) but it's the quickest :)

Snippet from Bitwig-generated project template:

Code: Select all

      host.getMidiInPort(0).setMidiCallback((ShortMidiMessageReceivedCallback)msg -> onMidi0(msg));
...
   private void onMidi0(ShortMidiMessage msg)
...
   void setMidiCallback(ShortMidiDataReceivedCallback callback);
...
public interface ShortMidiDataReceivedCallback extends Callback
{
   void midiReceived(int statusByte, int data1, int data2);
}
If I'm reading this right, this is passing `onMidi0` function to `setMidiCallback` (as an anonymous class implementing a single-method ShortMidiDataReceivedCallback interface). I didn't try compiling that and cannot tell if that is correct (does it magically know how to turn three Ints into a ShortMidiMessage?), but it is demonstrating the capability to a) pass functions via anonymous lambdas and b) implement single-method interfaces inline as a function.

Scala definitely has those capabilities, I'm assuming modern Java is similar. Here is the Scala version:

Code: Select all

    host.getMidiInPort(0).setMidiCallback((s: Int, d1: Int, d2: Int) => onMidi0(new ShortMidiMessage(s, d1, d2)))
...
  private def onMidi0(msg: ShortMidiMessage): Unit
(explicitly converting 3 Int arguments to ShortMidiMessage, no magic)

Post


Post

Totally in line with the conversation... thanks minortom! Probably gonna take me a bit to grok this, so I can implement them into my extension.

After a couple days of working through the examples in the drivenbymoss framework and experimenting them... I've been able to pass in the function reference... but now after all the previous googling and now reading this and I understand how that actually works! I get how to pass in the function reference to one of the bitwig callbacks clearly now and how the lambda really works.

My questions is, how do i implement one of these myself? is it all there? in https://www.javacodemonk.com/single-abs ... a-44f22fc3 ... or am I missing something.

like in JavaScript I would have something like this..

Code: Select all

function setCallback(callback) {
   this.callback = callback;
}

function doCallback() {
   this.callback();
}
A couple things confusing to me in the example from javacodemunk... is that Runnable seems to be something that you would only use for multi-threading. where as I want my callbacks to block the thread and process, possibly even return some values... Specifically I also don't see in the examples is where the callback function stored and actually gets executed. Also some of the language typing <T> in all these places in the javacodemunk example is very new to me, but i'm sure i'll get that too in the next couple days.

Code: Select all

 public<T> Future<T> invoke(Callable<T> runnable) {
        return executor.submit(runnable);
    }
I will google, read and sleep on this some more. maybe come back with a more specific example or an answer to my worries. Thanks again minortom! :D
----------------------------------------------------------------------
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest

Post

Kirkwood West wrote: Mon Oct 05, 2020 5:52 pm Totally in line with the conversation... thanks minortom! Probably gonna take me a bit to grok this, so I can implement them into my extension.

After a couple days of working through the examples in the drivenbymoss framework and experimenting them... I've been able to pass in the function reference... but now after all the previous googling and now reading this and I understand how that actually works! I get how to pass in the function reference to one of the bitwig callbacks clearly now and how the lambda really works.

My questions is, how do i implement one of these myself? is it all there? in https://www.javacodemonk.com/single-abs ... a-44f22fc3 ... or am I missing something.

like in JavaScript I would have something like this..

Code: Select all

function setCallback(callback) {
   this.callback = callback;
}

function doCallback() {
   this.callback();
}
Simply create an interface with only 1 method and tag it with @FunctionalInterface., e.g.

Code: Select all

@FunctionalInterface
interface MyCallback
{
   void dontCallMeIwillCallYou(event);
}
The setter looks like:

Code: Select all

void setMyCallback (MyCallback callback)
Usage:

Code: Select all

anInstanceOfAFunkyClass.setMyCallback (event -> doSomething());
which actually is only a shortcut for the following code:

Code: Select all

anInstanceOfAFunkyClass.setMyCallback (new MyCallback ()
{
  @Override
  public void dontCallMeIwillCallYou(event)
  {
    doSomething());
  }
});
Stay away from everything multi-threading!!! Until you absolutely know what you are doing.

Post

Thanks for the funky code Moss! So Stoked! <3 will get after it!
moss wrote: Tue Oct 06, 2020 8:41 am Stay away from everything multi-threading!!! Until you absolutely know what you are doing.
bruh... I plan to blow the planet up! infinite loops for life! :hihi:

will be certainly interesting when I get to this. I want to try building a display in that graphics window that you covered in your multi-threading tutorial. Will see... its on the wish list. You think its worth sending a feature request for this?
----------------------------------------------------------------------
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest

Post

Technically, the Bitwig API is uses thread-purposed classes, because....it is threaded internally. addValueObserver callbacks are not guaranteed to be called in order relative to each other for disparate *Values. A trick I've had to use a lot to get a semblance of synchronous API is using the threaded classes Atomic*, which guarantee that all sets happen before all gets iirc.

Just for a small example of why there must be at least a surface level understanding of threading is this little bug I had: if you booted one of my scripts, all the pads in a column lit up the exact same way. This was because I used both track.clipLauncherSlotBank().getItemAt(i).position().addValueObserver. and track.clipLauncherSlotBank().addPlaybackStateObserver. The bug was called because even though the first value observer might have been called, the playbackStateObserver would always use the position from the initial Value as the position (0), and since I was filtering events based off it, all the pads (in a column) would follow the state of the very first pad.

Post

moss wrote: Tue Oct 06, 2020 8:41 am

Code: Select all

@FunctionalInterface
interface MyCallback
{
   void dontCallMeIwillCallYou(event);
}
was experimenting this morning... failed. ended up with just passing the class into another class. what would be the data type for the event?
----------------------------------------------------------------------
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest

Post

Kirkwood West wrote: Fri Oct 09, 2020 5:23 pm
moss wrote: Tue Oct 06, 2020 8:41 am

Code: Select all

@FunctionalInterface
interface MyCallback
{
   void dontCallMeIwillCallYou(event);
}
was experimenting this morning... failed. ended up with just passing the class into another class. what would be the data type for the event?
Ah, sorry that happens when do not use an IDE :-)
You can give it any type you need, you could also have multiple parameters or none at all.

Post Reply

Return to “Controller Scripting”