channelizing works but how to wait for note off?

glennyg

2014-03-04 15:25:05

Hi there. I'm trying to recreate the common hardware feature where you can switch midi receive/local on and off for a sound, for instance to layer strings over a piano. The hardware waits for note off or velocity=0 before turning off midi receive so you don't get hung notes.

I'm using this translator I found on the forum (thanks metastatik) and it is working fine, after I allowed for my keyboard sending velocity =0 instead of note off messages. It gets around potential hung notes by not allowing a channel change while notes are playing (using gb as a counter).

Incoming pp qq vv
Rules:
if pp>144 then exit rules, skip Outgoing Action
if qq<12 then Goto "Set Channel"
rr=pp+ga
if pp==128 then vv=0
if vv>0 then gb=gb+1
if vv==0 then gb=gb-1
exit rules, execute Outgoing Action
Label "Set Channel"
if pp!=144 then exit rules, skip Outgoing Action
if gb>0 then exit rules, skip Outgoing Action
ga=qq
exit rules, skip Outgoing Action
Outgoing rr qq vv

What I really want to do is make a channel which is being switched off wait for note off or velocity=0 message before it stops transmitting on that channel. So I could hold a chord with piano on Ch1 AND strings playing on Ch2, switch off the strings while holding the chord, and the strings will only stop when I release the notes. This is how multi-timbral keyboards function.

Any ideas???
cheers
Glenn

DvlsAdvct

2014-03-04 20:24:36

Hi Glenn

I just want to make sure we are on the same page before moving forward, since I don't have your project in front of me.

Have you created this multitimbral workflow all directly in MT, or is your controller/keyboard handling some or all of the work? I am asking just so I can be sure of what messages are being sent and received to figure out the best solution.

Thanks
Jared

mschnell

2014-03-04 20:26:35

Why not simply always send the note-off (velocity=0) messages to both channels (= instruments), while sending the note-on messages (velocity>0) messages only to the selected channel(s) ?

And how in fact do you manage to send the note-on events to both channels (to produce the said layering plus hangs) ?

-Michael

glennyg

2014-03-04 23:02:00

OK, thanks for jumping in.

My controller sends on Ch1. All my splitting of Ch1 into other channels and key ranges etc happens inside Forte.

I need to be able to also send channels 2-8 to Forte and be able to turn the transmission of those channels and Ch1 on and off in MT. For now, I will continue to use the lowest 8 midi notes (00 - 07) as toggle switches but the switches could be anything as my controller has pads too.

When I switch transmission of a channel off, I need it to wait for a note off or vel=0 event for any notes that were being held when the switch was triggered. So I can be playing a piano on Ch1, hold a chord, turn transmission of CH1 off. Turn Ch2 on.

1) the next note on event will be on Ch2
2) any notes on Ch1 that were being held when I switched Ch1 transmission off will still get note off events on Ch1 when I release them.

Of course, Ch2 might be layer sound in which case I simply leave Ch1 on, add transmission of Ch2, and have Ch2 follow the same rules as per above so when I switch Ch2 back OFF, it waits for note off/vel=0 events for any held notes.

cheers and thanks
Glenn

mschnell

2014-03-05 00:03:31

Hmm.

Maybe MT is better suited to handle the layers and the key ranges. But synchronizing the Forte scenes and the MT presets might be a problem when doing so.

But anyway: what is Forte supposed to do with the data on channels 2..8, if layers and the key ranges are handled internally ?

Using some keys as mode switches should be no problem with MT.

To me the whole "waiting for vel=0" does not make sense. If you send all note-off events (e.g. note on with vel=0) to all cannels (instruments), hangs should be avoided right away. If you really intend to delay the "program change" you manually initialized, until you actively released all keys (IMHO: plus the damper pedal), MT should be able to handle this. But It should be done in a way completely independent of layering and key ranges.

-Michael

glennyg

2014-03-05 15:01:48

Yes, it might be easiest to re-channel note off messages so they always go out on every channel no mater what and then just use the switches to re-channel the note on messages. Thanks for that idea.

Forte's internal midi implementation is a bit complicated to go into here but it is very good. Basically you can select one or more midi channels for a given instrument to receive on. If it is a multi-timbral instrument you can then split that into as many channels as you need and assign each its own key range and controller assignments. Very flexible and clear.

I think I'll be able to get that preset going tomorrow, thanks. Out of curiosity I would like to see a "wait for note off" translator too.

mschnell

2014-03-05 18:51:28

I do know the Midi routing Forte does. Same is perfectly suited for the internal purpose of hosting multiple multitimbral instrument but does not provide any rules at all, so using Forte and MT together makes a lot of sense. (An integration of both products would be highly desirable.)

In fact - on top of curiosity - I do see that a hold-off for a switch does make sense.

In the moment I myself use a very simple setup, with neither MT nor Forte involved yet (but supposedly to come).

I just use the NI Kontakt stand-alone and start it with a multi-rack filled with different non multitembral instruments, each activated by a different program change message. With this, I easily get note-hangs when switching the program while holding the damper pedal. As most instruments are either truncating a voice after some seconds (piano) or don't use the damper pedal (organ), this is not a big issue, but makes clear the potential thread.

Of course MT can count the active notes (velocity > 0 vs. velocity = 0), to know when a mode switch is to be done

->
( ( (counter gets 0 while damper is off) or (damper gets off while counter is zero) ) and (mode switch has been requested) ) or

( (mode switch is requested) while ( ( counter is zero) and (damper is off ) ) )

of course you need another global variable for the damper state and the mode switch request storage.

-Michael

glennyg

2014-03-06 08:11:53

Ok, I have a working version of it now.

I'm using buttons on my controller assigned to send CC102-109 as my switches.

Since Ch1 is my main channel, it is slightly simpler than the others.
------------------------
Translator 1
(for Ch1 from controller)

Incoming Message: pp qq vv

Rules:
ss=vv
if ga==1 then ss=0
if pp==176 then Goto "Make ga flag"
exit rules, execute Outgoing Action
Label "Make ga flag"
oo=pp+qq
if oo!=278 then exit rules, execute Outgoing Action
oo=oo+vv
if oo==278 then ga=1
if oo==405 then ga=2
exit rules, execute Outgoing Action

Outgoing Message: pp qq ss
-------------------
It watches for 0x90 (control change) and then does a further check to make sure it is the one I assigned to the switch on the controller (CC102). Then it checks the value and if the value is 0 (button not lit) it makes all 3rd bytes 00 by way of a global variable. Any new notes that come in after it is switched off will be treated as note off messages. Note off messages originating from the controller pass through unchanged. This means that you will never get hung notes, which was exactly what I wanted. I can play a chord and switch a channel "off" and the notes will sustain until I release them, just like a hardware multi-timbral synth. Sustain pedal works as normal, so you can hold a chord with the sustain, switch the channel "off" and it will hold until you release the sustain pedal.

A side effect is that if you change a CC like ModWheel while the switch is on it works as normal, but if you change it while the switch is off it resets the CC to 0. Fortunately pitch wheel is not effected because it isn't a CC message. I could do some more steps to stop CCs resetting but it doesn't bother me. It probably will eventually.

The assigning of the global variable to 2 was for tracking purposes but might come in handy down the track.

The subsequent switches are identical except for allowing for the different CC numbers on the switches and changing the channel of the output, as below.

-------------------
Translator 2
(uses Ch1 on controller to control instrument on Ch2)

Incoming Message: pp qq vv

Rules:
ss=vv
if gb==1 then ss=0
if pp==176 then Goto "Make gb flag"
pp=pp+1
exit rules, execute Outgoing Action
Label "Make gb flag"
oo=pp+qq
pp=pp+1
if oo!=279 then exit rules, execute Outgoing Action
oo=oo+vv
if oo==279 then gb=1
if oo==406 then gb=2
pp=pp+1
exit rules, execute Outgoing Action

Outgoing Message: pp qq ss
------------------

Thanks for the helpful advice. I still think it would be preferable to use the switches to mute everything except note off or velocity=0 messages until all notes have been accounted for and then to mute midi completely. As it is, the midi data stream includes a heap of note and CC messages to instruments that aren't being heard. So if anyone wants a :oops: at that, I'd love to see it.
cheers
Glenn

glennyg

2014-03-06 12:53:36

Wow, c-r-a-c-k is a filtered word here? OK....if anyone wants a SHOT at that.

glennyg

2014-03-06 16:33:26

OK I have made a much better version now. The previous one was using too much polyphony by making all notes velocity 0 if the switch was off. This one doesn't send note on messages if the switch is off.
Also doesn't reset controllers as the last one did. Both possibilities for the global flag are defined for tracking purposes only. Of course only the "off" switch needs to be specified.

I think it's done but always love to see refinements from the gurus.

UPDATE! This is several lines shorter and doesn't use any Labels. Also previous version allowed sustain pedal to cause hung notes.

Controller is transmitting on Ch1. Switches assigned to CC102, CC103, CC104 etc.

Check for CC message > check if matches the controller switch > set global variable value.
Check for sustain=off message, always send it.
If controller is sending note-on-velocity=0 instead of note off, make it a note off message (saves polyphony) and always send it.
Check for note off message > always send it.
If flag shows switch is off, don't transmit any other message types (i.e. transmits note off and sustain off messages only).
----------
Translator 1
(for control of Ch1)

Incoming Message: pp qq vv

Rules:
if pp==176 then oo=pp+qq
if oo==278 then oo=oo+vv
if oo==278 then ga=1
if oo==405 then ga=2
if oo==240 then oo=oo+vv
if oo==240 then exit rules, execute Outgoing Action
if pp==144 then ww=pp+vv
if ww==pp then pp=pp-16
if pp<144 then exit rules, execute Outgoing Action
if ga==1 then exit rules, skip Outgoing Action
exit rules, execute Outgoing Action

Outgoing Message: pp qq vv
-----------
Translator 2
(For control of Ch2. Note the offsets from Translator 1. Apply on duplicate Translators for up to 16 channels)

Incoming Message: pp qq vv

Rules:
pp=pp+1
if pp==177 then oo=pp+qq
if oo==280 then oo=oo+vv
if oo==280 then gb=1
if oo==407 then gb=2
if oo==241 then oo=oo+vv
if oo==241 then exit rules, execute Outgoing Action
if pp==145 then ww=pp+vv
if ww==pp then pp=pp-16
if pp<144 then exit rules, execute Outgoing Action
if gb==1 then exit rules, skip Outgoing Action
exit rules, execute Outgoing Action


Outgoing Message: pp qq vv
----------

mschnell

2014-03-06 18:54:31

Just a short hint without any deeper analysis:

1) Perhaps you should do

"exit rules, execute Outgoing Action"

not in a condition, but always if no condition hits, to allow for unknown messages to do what they are meant for.



2) Maybe you should allow the builtin filter of a MT Translator do it's work and not have all of them handle all messages: one or more translator(s) for (each channel and)
- note on
- note off
- controller change

This will result in more translators but supposedly better performance and is more according to MT's design.

-Michael

glennyg

2014-03-07 06:26:40

I'd really like to see your re-coding of it to show those suggestions in action.

mschnell

2014-03-07 07:16:22

Maybe the helpful peaple from Bome jump in.

But I would start trying to do Translators:

Incoming Message: 144 qq vv
...


Incoming Message: 128 qq vv
...


Incoming Message: 176 qq vv
...


(Supposedly two or some or all of each of them.)

And with that avoid the "if" cascade.

(The "if" cascade with 145, 129, 177 just duplicates the other one, as pp is increased before. )

-Michael

glennyg

2014-03-07 08:45:37

Yeah...I wanted one translator per channel. Otherwise by the time you've created 16 channel switches, you would have over 50 translators. Doesn't seem elegant to me, but hey, I'm a newbie. If you actually coded it up and posted it I'd probably see how your way is better. Would love to see it complete to further my understanding of how to do it properly.

mschnell

2014-03-07 09:38:05

It seems like with the current Translator version a single translator can only generate a single message from each input message (but maybe I am not an expert). I learned that a future version of Translator will feature real scripting and thus would be able to do that in a more compact programming.

OTOH what messages do you want to duplicate ? If it's only the note-on events, you still "only" need one (very simple) translator per output channel plus one or two for controlling the global variables.

If you also want to duplicate cc messages this will need more translators.

But I feel this is how Translator (currently) is meant to be used.

-Michael

glennyg

2014-03-07 11:02:41

mschnell -I'd really have to see your version, so code it!

Updated code in the post above now that adds a label so controllers don't get reset. You can apply modwheel, switch off the channel, move the modwheel, turn the channel back on - and it will be at the value you set before you turned the channel off. Much better.

glennyg

2014-03-07 15:28:18

Updated version (above) - more economical and fixed a problem with sustain messages.