Understanding MidiHub as a programming language

Ok, this might be weird, graphical, node based interfaces are programming languages, so I’m trying to figure out what the basic design patterns are. Specifically how the Virtual Ports work.

From DinA -> To VirtualA
From VirtualA -> "Do Something" -> To VirtualA
From VirtualA -> "Do Something Else" -> To VirtualA
From VirtualA -> DinA

is this the same thing as this?

From DinA -> "Do Something" -> "Do Something Else" -> To DinA

Also, there is a Dispatcher to create parallel pipelines, but you merge directly in the To Din node? there are no Listener node that would merge 2 virtual ports back into one?

From DinA -> Dispatcher(VirtualA, VirtualB)
From VirtualA -> FilterChannels(ch02-ch16)
                 -> "Do Something To ch01" -> To DinA
From VirtualB -> FilterChannels(ch01)
                 -> "Do Something to All the other Channels" -> To DinA

is this how I would create an effect that only modifies notes on ch01 and passes everything else thru unchanged?

Because this would mean that pipelines can be used as functions (more or less) and the 2 patterns above allow me to process things in series A() -> B() or in parrallel Dispatcher(A,B), A(), B() right?

Lastly, how would I modulate notes from one channel using notes from another channel? The simplest example would be to create a “master transpose” effect, and use the note value on ch01 to modulate the note values on all the other channels? So C4 would be no change, C#4 would raise all notes by a semitone, and B4 would lower by two. Can you map the offset parameter of the Note Transpose effect to a Virtual Port?

1 Like

You can think of the horizontal pipelines as completely parallel processors. The same event on a port (virtual or not), gets processed in all pipelines with matching input.

The first example you wrote is actually impossible, as it would cause an infinite loop. :slight_smile: The editor prevents this state from happening. Instead, let’s consider this:

From DinA -> To VirtualA
From VirtualA -> "Do Something" -> To VirtualB
From VirtualA -> "Do Something Else" -> To VirtualB
From VirtualB -> DinA

This is a graph showing how an event would flow through such a pipeline:

From_DinA -> From_Virtual A -> Do Something       \
          |                                       |-> From_VirtualB -> To_DinA
          -> From_Virtual A -> Do Something Else  /

The incoming event from DinA gets sent into Virtual A, its copies are processed in all ‘Virtual A’ pipelines, then they are merged into Virtual B pipeline and sent to Din A output.

The Dispatcher pipe dispatches events to separate MIDI channels. One MIDI port is capable of having 16 channels. It can be used to send each note played to a different channel.

The merging of port data itself happens automatically, if the events are forwarded to the same output.

So if you want to process MIDI Ch1 one way, the rest of the channels in some way, then you should use a pipeline like:

From DinA -> Filter Ch (keep Ch1 only) -> To Virtual A
From DinA -> Filter Ch (keep Ch2-Ch16) -> To Virtual B
From VirtualA -> Process one way -> To DinA
From VirtualB -> Process another way -> To DinA

These virtual pipelines could be considered as sort of functions, where you can share the processing pipelines for many inputs. But duplicating the processing may be necessary to have more control over where the output goes.

At the moment it’s not possible to be done within the processing pipelines, but you could map a CC to control this. We plan to add some more features in this area in future updates, as well as more mapping options.

4 Likes

In the example you gave:

From_DinA -> From_Virtual A -> Do Something       \
          |                                       |-> From_VirtualB -> To_DinA
          -> From_Virtual A -> Do Something Else  /

`The incoming event from DinA gets sent into Virtual A, its copies are processed in all ‘Virtual A’ pipelines, then they are merged into Virtual B pipeline and sent to Din A output.

At the end when you say “they are merged into Virtual pipeline B”

In what order are they merged? This was a critical part of the OP’s question I believe.

Is there a guaranteed order? Do Something → Do Something Else? Or is it random? It must be serialized in MIDI, so there must be some decision on ordering somewhere.

It is not easily predictable, but should be in the order you’ve placed the From_Virtual A pipes. Is there some certain situation you have in mind where you’d be concerned about the order?

Edit: Ok, found your Xform PC -> Stop, PC, Start topic :slight_smile: