Dewdman42 Posted August 31, 2020 Share Posted August 31, 2020 I have worked out a way to use up to 64 midi channels into a single instance of Kontakt, using ports A,B,C,D, which normally are only accessible through the standalone version, but this tutorial and supplied templates will let you access them in the plugin version. Here are two LogicPro projects provided, one is an empty template, and the other is a working example using the factory kontakt instruments as an example case using 28 midi channels into a single Kontakt instance. Template: KontaktMulti64.zip Example Project: KontaktMulti64Example.logicx.zip Truthfully, its probably a better idea in LogicPro to spread the cpu load to multiple kontakt instances in most cases, but I offer this solution for anyone seeking anything similar or to build upon further. One case where this kind of thing can make a lot of sense is when working with an instrument that has more than 16 articulations as separate kontakt instruments. Working Example In this case Kontakt is loaded with 28 instruments in slots A and B. Here is a screenshot of the B slot with 14 channels B1->B14 using some instruments. Slot A also has 14 instruments. Here is the arrange page showing the tracks.. Clicking on any track will find midi routed to the right instrument in kontakt, including in the B slot... The mixer can accommodate up to 25 stereo returns, so in this example I have 28 instruments (a few are consolidated in the audio returns) and their separate returns are giving me all the mixer channels for each one: How it works This is enabled by two special tricks. One is that I am using the old VePro6 multiport macro to insert CC99 events in front of all events coming from each track. In addition to that, a special Scripter script is being used on the kontakt channel. This script translates the CC99 events into ProgramChange events containing the port number. It also handles a few other housekeeping tasks related to ALL NOTES OFF that were part of the old VePro multiport macro templates. This script is already included in the above project templates. (Note, it might be possible to modify the environment multiport macro to generate PC messages directly instead of CC99 and then avoid needing this special script, but the ALL NOTES OFF handling is still somewhat needed. I just reused the old multiport macros as is for now.) //============================================================= // Handle NoteOff, like we had to do with CC99 stuff in VePro // but also convert CC99 to PC messages 1-4 // don't index port value by zero. //============================================================= var NeedsTimingInfo = true; //only needed to detect play state var TRACE = false; var TRACE99 = false; var MAXFLUSH = 20; // array to track the last received port for any given channel var lastPort = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; var tempLastPort = 0; var maxPorts = 0; var pc = new ProgramChange; //============================================================= // Actual HandleMIDI function //============================================================= function HandleMIDI(event) { // keep track of the current port for each channel // don't forward on the CC99 event if(event instanceof ControlChange && event.number == 99) { //if( event.value+1 != lastPort[event.channel]) { if( event.value+1 != tempLastPort) { tempLastPort = event.value+1; lastPort[event.channel] = tempLastPort; // convert to PC by number pc.number = event.value+1; pc.channel = event.channel; pc.port = event.value+1; pc.send(); if(TRACE99) { logEvent(event); } } return; } else { event.port = lastPort[event.channel]; if(event instanceof NoteOn && event.port > maxPorts) { maxPorts = event.port; } } //================================================ // If all Notes Off for channel, handle specially, // forward to all ports //================================================ if (event instanceof ControlChange && event.number == 123 && event.value == 0) { AllNotesOffByChannel(event.channel); return; } //============================================== // INSERT code here for sending keyswitches, etc // when inserting keyswitches, send the port attr // and call SendByPort(event). For example: // var keyswitch = new NoteOn; // keyswitch.port = lastPort[event.channel]; // SendByPort(keyswitch); //============================================== // Send actual event event.send(); logEvent(event); } //========================================= // send VEP multi port encoder in front // of actual event //========================================= function SendByPort(event) { if(event.port != undefined && event.port > 0) { pc.channel = event.channel; pc.number = event.port; pc.send(); if(TRACE99) { logEvent(cc99); } } event.send(); logEvent(event); } //=================================================== // Prcoess MIDI is used to detact transport STOP // in order to send AllNotesOff to all ports/channels //=================================================== var playState = false; function ProcessMIDI() { var ctx = GetTimingInfo(); if (ctx.playing) { playState = true; } else { if (playState == true) { // stop recently happened AllNotesOff(); playState = false; } } } //==================================== // AllNotesOff all Channels //==================================== function AllNotesOff() { for (var chan = 1; chan <= 16; chan++) { AllNotesOffByChannel(chan); } maxPorts = 0; } //======================================= // Propagate AllNotesOff to all ports // for a given midi channel //======================================= var ccOff = new ControlChange; ccOff.number = 123; ccOff.value = 0; // var note = new NoteOn; function AllNotesOffByChannel(channel) { for (var port = 1; port <= maxPorts; port++) { ccOff.channel = channel; ccOff.port = port; SendByPort(ccOff); } } //=================================== // Buffered Tracing if turned on //=================================== var buffer = []; function logEvent(event) { var port = (event.port == undefined || event.port < 1) ? "" : (" [port:"+event.port.toString().padStart(2, "0")+"]"); logMsg(event.toString() + port); } function logMsg(str) { if(TRACE) { buffer.push(str); } } function logErr(str) { buffer.push(str); } function Idle() { for (var i = 0; i < MAXFLUSH; i++) { if (buffer.length > 0) { Trace(buffer.shift()); } } } In addition to the above, Kontakt is using a special KSP multi-script which translates the ProgramChange messages into appropriate midi routing to ports A,B,C,D. The preloaded Kontakt multi has this KSP script included in it. on init declare $runningPort declare $channel $runningPort := 1 end on on midi_in { Detect PC#127, only for BYTE2 values 1-4 } if ($MIDI_COMMAND = $MIDI_COMMAND_PROGRAM_CHANGE) if( $MIDI_BYTE_1 < 5 ) $runningPort := $MIDI_BYTE_1 ignore_midi exit end if end if {All other midi events, rechannelize to port based on last running port# } $channel := ($runningPort-1) * 16 + $MIDI_CHANNEL set_event_par($EVENT_ID,$EVENT_PAR_MIDI_CHANNEL,$channel) end on That's all there is to say about it really. It works like a charm for the most part. 64 tracks to one kontakt instance. The general approach can be further enhanced in combination with Articulation Sets to provide, for example, more than 16 articulations in a single kontakt instance. Hope anyone finds this useful or generates further ideas or discussion. As I said, I think this is somewhat a hypothetical exercise to see if it was possible, in actuality, I would rather run separate instances of Kontakt per instrument in LogicPro in order to spread CPU load around. Generally. Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted August 31, 2020 Author Share Posted August 31, 2020 I also made some scripts and templates for handling more than 16 articulations to a large Kontakt multi. This is more interesting actually then the above example, and does not require any environment multi-port macro. I will be sharing more information about that at a future time, but suffice it to say for now that its possible to have up to 64 articulationID's that drive events to up to 64 separate listening midi channels within a single kontakt instance.. Nice. That is definitely interesting to me. However, I also found that in some ways it might be easier to just send 64 articulationID's to multiple instances of kontakt..which is also possible in LogicPro by using a simple environment splitter or even a track stack and then a small script to filter out which articulationID's are handled by each kontakt instance. That avoids needing any special KSP script and is probably the way to go for this kind of task... but anyway, if someone wants it all in one simple channel..then the above KSP trick is definitely useful for that. Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted November 4, 2022 Author Share Posted November 4, 2022 various related scripts are found here for anyone that feels like taking this further... https://gitlab.com/dewdman42/kprouter/-/tree/master Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.