how to split midi channels?
what are you meaning by "cleaner way "..?
i mean : you take 16 midi filter with data in and out and you save it as subpatch so you can re-use it when you need...?
don't think it more cpu eater than a script...?

i mean : you take 16 midi filter with data in and out and you save it as subpatch so you can re-use it when you need...?
don't think it more cpu eater than a script...?

Ok thanks, I just thought I might be being careless with my computer resources doing it this way as the numbers of modules do add up over the multiple sources that need splitting and every bit of optimization helps me be able to do more in the long run.
i understand and don't affirm it , of course a test with a script could be done...
but don't count with me for a script...
but don't count with me for a script...
here a script. copy+paste in the script module.
CORRECTED:
and a picture:

CORRECTED:
Code: Select all
(*/////////////////////////////////////////////////////
// MEP_splitChn - midi script module for sensomusic usine
// version: 2009-03-23 1.0; author: amiga909
//
// <Description>
// splits midi messages by channel
// <Parameters>
// none
// <Ports>
// [channel 1-16]:
//////////////////////////////////////////////////////
*)
//////////////////////////////////////////////////////
// globals
//////////////////////////////////////////////////////
VAR pIn, pOut1, pOut2, pOut3, pOut4, pOut5, pOut6, pOut7, pOut8, pOut9, pOut10, pOut11, pOut12, pOut13
, pOut14, pOut15, pOut16 : TParameter;
VAR tmp : TMidi;
VAR len, i, len1, len2, len3, len4, len5, len6, len7, len8, len9, len10, len11, len12, len13, len14, len15, len16 : INTEGER;
//////////////////////////////////////////////////////
// initialize
//////////////////////////////////////////////////////
PROCEDURE init;
BEGIN
pIn := createParam('in', ptMidi);
pOut1 := createParam('chn 1', ptMidi);
pOut2 := createParam('chn 2', ptMidi);
pOut3 := createParam('chn 3', ptMidi);
pOut4 := createParam('chn 4', ptMidi);
pOut5 := createParam('chn 5', ptMidi);
pOut6 := createParam('chn 6', ptMidi);
pOut7 := createParam('chn 7', ptMidi);
pOut8 := createParam('chn 8', ptMidi);
pOut9 := createParam('chn 9', ptMidi);
pOut10 := createParam('chn 10', ptMidi);
pOut11 := createParam('chn 11', ptMidi);
pOut12 := createParam('chn 12', ptMidi);
pOut13 := createParam('chn 13', ptMidi);
pOut14 := createParam('chn 14', ptMidi);
pOut15 := createParam('chn 15', ptMidi);
pOut16 := createParam('chn 16', ptMidi);
setIsInput(pOut1,FALSE);
setIsInput(pOut2,FALSE);
setIsInput(pOut3,FALSE);
setIsInput(pOut4,FALSE);
setIsInput(pOut5,FALSE);
setIsInput(pOut6,FALSE);
setIsInput(pOut7,FALSE);
setIsInput(pOut8,FALSE);
setIsInput(pOut9,FALSE);
setIsInput(pOut10,FALSE);
setIsInput(pOut11,FALSE);
setIsInput(pOut12,FALSE);
setIsInput(pOut13,FALSE);
setIsInput(pOut14,FALSE);
setIsInput(pOut15,FALSE);
setIsInput(pOut16,FALSE);
setIsOutput(pIn,FALSE);
END;
////////////////////////////////////////
// main
//////////////////////////////////////////////////////
BEGIN
len := getLength(pIn);
//writeln('len: '+inttostr(len));
IF len > 0 THEN BEGIN
len1 := 0;
len2 := 0;
len3 := 0;
len4 := 0;
len5 := 0;
len6 := 0;
len7 := 0;
len8 := 0;
len9 := 0;
len10 := 0;
len11 := 0;
len12 := 0;
len13 := 0;
len14 := 0;
len15 := 0;
len16 := 0;
FOR i := 0 TO (len - 1) DO BEGIN
getMidiArrayValue(pIn, i, tmp);
IF (tmp.channel = 1) THEN BEGIN
setMidiArrayValue(pOut1, len1, tmp);
len1 := len1 +1;
END
ELSE IF (tmp.channel = 2) THEN BEGIN
setMidiArrayValue(pOut2, len2, tmp);
len2 := len2 +1;
END
ELSE IF (tmp.channel = 3) THEN BEGIN
setMidiArrayValue(pOut3, len3, tmp);
len3 := len3 +1;
END
ELSE IF (tmp.channel = 4) THEN BEGIN
setMidiArrayValue(pOut4, len4, tmp);
len4 := len4 +1;
END
ELSE IF (tmp.channel = 5) THEN BEGIN
setMidiArrayValue(pOut5, len5, tmp);
setLength(pOut5,len5);
len5 := len5 +1;
END
ELSE IF (tmp.channel = 6) THEN BEGIN
setMidiArrayValue(pOut6, len6, tmp);
len6 := len6 +1;
END
ELSE IF (tmp.channel = 7) THEN BEGIN
setMidiArrayValue(pOut7, len7, tmp);
len7 := len7 +1;
END
ELSE IF (tmp.channel = 8) THEN BEGIN
setMidiArrayValue(pOut8, len8, tmp);
len8 := len8 +1;
END
ELSE IF (tmp.channel = 9) THEN BEGIN
setMidiArrayValue(pOut9, len9, tmp);
len9 := len9 +1;
END
ELSE IF (tmp.channel = 10) THEN BEGIN
setMidiArrayValue(pOut10, len10, tmp);
len10 := len10 +1;
END
ELSE IF (tmp.channel = 11) THEN BEGIN
setMidiArrayValue(pOut11, len11, tmp);
len11 := len11 +1;
END
ELSE IF (tmp.channel = 12) THEN BEGIN
setMidiArrayValue(pOut12, len12, tmp);
len12 := len12 +1;
END
ELSE IF (tmp.channel = 13) THEN BEGIN
setMidiArrayValue(pOut13, len13, tmp);
len13 := len13 +1;
END
ELSE IF (tmp.channel = 14) THEN BEGIN
setMidiArrayValue(pOut14, len14, tmp);
len14 := len14 +1;
END
ELSE IF (tmp.channel = 15) THEN BEGIN
setMidiArrayValue(pOut15, len15, tmp);
len15 := len15 +1;
END
ELSE IF (tmp.channel = 16) THEN BEGIN
setMidiArrayValue(pOut16, len16, tmp);
len16 := len16 +1;
END;
setLength(pOut1,len1);
setLength(pOut2,len2);
setLength(pOut3,len3);
setLength(pOut4,len4);
setLength(pOut5,len5);
setLength(pOut6,len6);
setLength(pOut7,len7);
setLength(pOut8,len8);
setLength(pOut9,len9);
setLength(pOut10,len10);
setLength(pOut11,len11);
setLength(pOut12,len12);
setLength(pOut13,len13);
setLength(pOut14,len14);
setLength(pOut15,len15);
setLength(pOut16,len16);
END;
END
ELSE BEGIN
setLength(pOut1, 0);
setLength(pOut2, 0);
setLength(pOut3, 0);
setLength(pOut4, 0);
setLength(pOut5, 0);
setLength(pOut6, 0);
setLength(pOut7, 0);
setLength(pOut8, 0);
setLength(pOut9, 0);
setLength(pOut10, 0);
setLength(pOut11, 0);
setLength(pOut12, 0);
setLength(pOut13, 0);
setLength(pOut14, 0);
setLength(pOut15, 0);
setLength(pOut16, 0);
END;
END.
great !
now we have to test...
)
now we have to test...
easy, easy.....its a very easy thingie, done in 10min.
Sorry, but the script will only work ok when all the incoming MIDI within an execution block is the same channel. You have to keep count of the lengths of each of the outputs separately.
Bjørn S
thanks a lot bsork, u are totally right.
corrected the script above and tested it with copy+paste the same piano roll and changing channels.
seems to work now.
have to check my other scripts for that issue too. thanks again
btw, in some of your scripts I found a bug with channel 16 messages (channel counts from 1-16, data from 0-127)
corrected the script above and tested it with copy+paste the same piano roll and changing channels.
seems to work now.
have to check my other scripts for that issue too. thanks again
btw, in some of your scripts I found a bug with channel 16 messages (channel counts from 1-16, data from 0-127)
What do you mean exactly? Even though the MIDI channels are named 1 to 16, technically they're 0-15 AFAIK, if that's what you're referring to.
Bjørn S
actually I have to apologize.bsork wrote:What do you mean exactly? Even though the MIDI channels are named 1 to 16, technically they're 0-15 AFAIK, if that's what you're referring to.
your excellent clearmidinotes and miditransposewithoctavefoldback run perfect. probably it was rather in one of my buggy attempts, sorry.
to explain what i meant:
from clearmidinotes.script:
GetMidiArrayValue(pIn, i, tmp);
writeln('tmpchan'+inttostr(tmp.channel));
=> if channel = 1: tmpchan: 1
=> if channel = 16: tmpchan: 16
and thats why u put this line before u throw the message in a 0..15 array:
x := tmp.channel - 1;
boa cool this script is very usefull..thx
I so wish I could know usine script as you and bsork, but when you give us some we can try to understand a bit...
I so wish I could know usine script as you and bsork, but when you give us some we can try to understand a bit...
Thanks for the examples....
In the interest of wasting time I made two patches. One with 20 instances of this script and the other with 20x 16 midi filters.
Both were fed 15 channels of 16 beats per bar midi. The midi filter example used about 30Mb and barely any cpu, the script example used about 8Mb and considerable more cpu. (including the vsti generating the midi , the filter patch cpu usage showed about 1.8%, the script patch about 8%)
I think I am best off sticking with multiple filters to split channels
In the interest of wasting time I made two patches. One with 20 instances of this script and the other with 20x 16 midi filters.
Both were fed 15 channels of 16 beats per bar midi. The midi filter example used about 30Mb and barely any cpu, the script example used about 8Mb and considerable more cpu. (including the vsti generating the midi , the filter patch cpu usage showed about 1.8%, the script patch about 8%)
I think I am best off sticking with multiple filters to split channels
EDIT:
@guru: u were faster
yeah, its what I got too (didnt look at the MB usage)
here a test. usine modules vs. script.
first the mentioned no script version, then the script version with 2x2 chn, and 16x16 chn:




and here the patches if u want to try urself:
http://www.sensomusic.com/forums/upload ... script.pat
http://www.sensomusic.com/forums/upload ... script.pat
result:
dont know if this measurement method is reliable?
hmmm.. usine modules are NOT slower from what i got.
not-script version is clearly better if u have only a few channels. they are about the same if it comes to extensive splitting, non-script being rather faster.
kinda disappointing for me.. I wonder if my script could be made faster?
kinda trust enforcing for usine! usine is even better than we expect
@guru: u were faster
yeah, its what I got too (didnt look at the MB usage)
here a test. usine modules vs. script.
first the mentioned no script version, then the script version with 2x2 chn, and 16x16 chn:




and here the patches if u want to try urself:
http://www.sensomusic.com/forums/upload ... script.pat
http://www.sensomusic.com/forums/upload ... script.pat
result:
dont know if this measurement method is reliable?
hmmm.. usine modules are NOT slower from what i got.
not-script version is clearly better if u have only a few channels. they are about the same if it comes to extensive splitting, non-script being rather faster.
kinda disappointing for me.. I wonder if my script could be made faster?
kinda trust enforcing for usine! usine is even better than we expect
mmm that exactlty what I wanted to ask/understand, when are spript more efficient than patching? (exept they certainly allows thing we couldn't do via patch..) they seem to recreacte a patch virtually with same modules no?, so should be same cpu usage no???
quite a good news for me if modules are as efficient as if they were called by the script..
quite a good news for me if modules are as efficient as if they were called by the script..
yeah, the test greatly helped me to understand this efficiency question.
first your question:
scripts dont recreate modules. afaik its a completely different mechanism: modules are compiled, while scripts are interpreted, which means that the actual code for modules is bytecode that is only readable by a machine. script languages (like javascript) do not come up with such an optimized source code but a human readable source code can be executed directly which also means less efficiency.
please correct me if i am wrong.
btw, thanks for your kind words above 23fx23. but the script master here is bsork (except olivier of course). I didnt do much more than recreating his ideas by now (got some queer midi script stuff in the pipeline, maybe I'll be able to add something new sometimes, but i want to finish the easy stuff first...)
about script efficiency. maybe its valid to say that it is a bad idea to recreate stuff with scripts that can be done quite easily with modules. in our example we also need the same amount of wires: a script maybe would be more efficient if you would split channels but merging 2 channels to 1 (means: 1+2 > out1, 15+16 > out8, etc.). scripts can be more powerful if you would want to change the midi filter 'split by channel' param in realtime: if u change the channel while a note is still held u get a nasty hanging note. bsorks method would take care of that.
first your question:
scripts dont recreate modules. afaik its a completely different mechanism: modules are compiled, while scripts are interpreted, which means that the actual code for modules is bytecode that is only readable by a machine. script languages (like javascript) do not come up with such an optimized source code but a human readable source code can be executed directly which also means less efficiency.
please correct me if i am wrong.
btw, thanks for your kind words above 23fx23. but the script master here is bsork (except olivier of course). I didnt do much more than recreating his ideas by now (got some queer midi script stuff in the pipeline, maybe I'll be able to add something new sometimes, but i want to finish the easy stuff first...)
about script efficiency. maybe its valid to say that it is a bad idea to recreate stuff with scripts that can be done quite easily with modules. in our example we also need the same amount of wires: a script maybe would be more efficient if you would split channels but merging 2 channels to 1 (means: 1+2 > out1, 15+16 > out8, etc.). scripts can be more powerful if you would want to change the midi filter 'split by channel' param in realtime: if u change the channel while a note is still held u get a nasty hanging note. bsorks method would take care of that.
Hi, interesting figures you both have got.
I know a script version could be made more effective using a couple of tricks, but no matter how it's constructed, what is most effective will to some extent be dependent on the MIDI data. I'll see if I can find the time tonight to create and post an example that I think would work ok for a relatively dense MIDI stream.
Anyway, no matter how a script is written, I'm sure the module way of doing things would be better when the amount of MIDI data is moderate - especially if only a handful of MIDI channels are in use.
I know a script version could be made more effective using a couple of tricks, but no matter how it's constructed, what is most effective will to some extent be dependent on the MIDI data. I'll see if I can find the time tonight to create and post an example that I think would work ok for a relatively dense MIDI stream.
Anyway, no matter how a script is written, I'm sure the module way of doing things would be better when the amount of MIDI data is moderate - especially if only a handful of MIDI channels are in use.
Bjørn S
I'd love to learn more about these tricks.bsork wrote:I know a script version could be made more effective using a couple of tricks, but no matter how it's constructed, what is most effective will to some extent be dependent on the MIDI data.
the only thing I could think of is rejecting message types like clock (or activesense or sysex) - which would save some wires in comparison to a module version. apart from that I really dont know?
waiting for ur answer, excited to learn
Well, it seems that I should have kept my mouth shut... I've tried different varieties of scripts to minimize the CPU load, but nothing seems remotely like a simple patch with 16 filter modules. I haven't tried many different data streams - just a very dense stream of NoteOns/Offs on a couple of channels, but the CPU load didn't vary much between the various ways I tried. I managed to get it a little more consistent and a bit lower than Amiga909, but not enough to write home about... 
Bjørn S
..so the good news is, as amiga pointed, that usine engine/modules are very well coded 
...and once the 16 ch filter patch is made... or should we maybe do 16 subpatchs that would be activated only on incoming stream to save CPu if chanels are not used, mm gonna try if it worth..?
just made me think CPu contests for things we all want could be ccol to find the best tech..
...and once the 16 ch filter patch is made... or should we maybe do 16 subpatchs that would be activated only on incoming stream to save CPu if chanels are not used, mm gonna try if it worth..?
just made me think CPu contests for things we all want could be ccol to find the best tech..
@bsork: thanks for trying. still, if u'd post your result, me and others might learn better programming.
in the end there is no way to beat mr. senso as it seems.. dont tell me he also walks on water, i might believe it
EDIT: @23fx: for this case I would guess CPU load would not vary significantly if one puts a 'Patch Active' module: the modules to check if a patch should be set active would prolly consume more than an unused midi filter patch itself. as gurulogic pointed out, the only advantage might be less RAM usage.
in the end there is no way to beat mr. senso as it seems.. dont tell me he also walks on water, i might believe it
EDIT: @23fx: for this case I would guess CPU load would not vary significantly if one puts a 'Patch Active' module: the modules to check if a patch should be set active would prolly consume more than an unused midi filter patch itself. as gurulogic pointed out, the only advantage might be less RAM usage.
yup true, let's have a simple 16 filters then. so it's ram vs cpu..might depends on what thingz, maybe. others comparaisons for other problematics could be nice.
Ok, here's one version of the script - it filters out all non-channel messages and the efficiency will be dependenant not only on the number of messages, but also of how many channels are received at once:
By using arrays, at least the code is smaller even if the results CPU-wise aren't much better than coding it the "hard way". Anyway, when doing MIDI scripts of various types, using the MIDI values themselves (channel, CC no, note no, etc) as indexes to arrays is often a good idea IMO. Depends on what the script is doing, of course.
Code: Select all
VAR pIn : Tparameter;
TYPE outArr = ARRAY of Tparameter;
VAR pOut : outArr;
VAR tmp : tMidi;
VAR inLen, min, max, i, x : INTEGER;
VAR outLen : ARRAY OF INTEGER;
VAR updLen : BOOLEAN;
PROCEDURE init;
BEGIN
pIn := CreateParam('midi in', ptMidi); SetIsOutput(pIn, FALSE);
SetArrayLength(pOut, 16);
SetArrayLength(outlen, 16);
FOR i := 0 TO 15 DO BEGIN
pOut[i] := CreateParam('midi ch ' + IntToStr(i + 1), ptMidi);
SetIsInput(pOut[i], FALSE);
END;
min := 16;
max := 0;
updLen := FALSE;
END;
PROCEDURE SetMinMax(y : integer);
BEGIN
IF (y < min) THEN
min := y;
IF (y > max) THEN
max := y;
END;
// main
BEGIN
IF (updLen) THEN BEGIN
FOR i := min TO max DO BEGIN
IF (OutLen[i] > 0) THEN BEGIN
SetLength(pOut[i], 0);
OutLen[i] := 0;
END;
END;
min := 16;
max := 0;
updLen := FALSE;
END;
inLen := GetLength(pIn);
IF (inlen > 0) THEN BEGIN
FOR i := 0 TO (inLen - 1) DO BEGIN
GetMidiArrayValue(pIn, i, tmp);
IF (tmp.msg <= 239) THEN BEGIN
x := tmp.channel - 1;
SetMidiArrayValue(pOut[x], OutLen[x], tmp);
OutLen[x] := OutLen[x] + 1;
SetMinMax(x);
updLen := TRUE;
END;
END;
IF (updLen) THEN BEGIN
FOR i := min TO max DO BEGIN
IF (OutLen[i] > 0) THEN BEGIN
SetLength(pOut[i], OutLen[i]);
END;
END;
END;
END;
END.Bjørn S
thanks a lot. very nice piece of code.
would not have thought u could create and access ports (Tparameter) dynamically.
maybe i'll do a test like gurulogic to compare CPU and RAM usage of the brute-force and the clever way when i get home.
though the script isnt more efficient, i might use it, cause its more elegant, flexible and well arranged than the module version for my taste.
post as addon?
would not have thought u could create and access ports (Tparameter) dynamically.
maybe i'll do a test like gurulogic to compare CPU and RAM usage of the brute-force and the clever way when i get home.
though the script isnt more efficient, i might use it, cause its more elegant, flexible and well arranged than the module version for my taste.
post as addon?
I didn't think of creating an array of in-/outputs myself - it comes from Olivier. Don't quite remember whether I stumbled across it in a supplied script or if it was mentioned in some topic.
I don't think the script belongs in the add-ons section as long as the effiency and the ease of use is bad compared to a relatively simple module-based patch, but thanks for the nice words anyway. I think there are plenty of other scripts in the distro and the add-ons that are better examples of eg using MIDI data as indexex to arrays, or a boolean or three to avoid unneccessary executions.
I don't think the script belongs in the add-ons section as long as the effiency and the ease of use is bad compared to a relatively simple module-based patch, but thanks for the nice words anyway. I think there are plenty of other scripts in the distro and the add-ons that are better examples of eg using MIDI data as indexex to arrays, or a boolean or three to avoid unneccessary executions.
Bjørn S
Who is online
Users browsing this forum: No registered users and 20 guests
