michaelrasbury Posted October 12, 2020 Share Posted October 12, 2020 Hello, Every time a Kontakt library is updated by the creator, I loose all my custom CC assignments and have to start over. I'm looking for something similar to the "Modifier" in MIDI channel effects but instead of being able to control one CC, I need to control multiple CC. I want the plugin or script to allow me to reassign my CC to control the defaults in Kontakt. The "Modifier" does this but only allows one CC per instance of the plugin. Quote Link to comment Share on other sites More sharing options...
des99 Posted October 12, 2020 Share Posted October 12, 2020 You can have multiple instances of the Modifier plugin, each only affecting one CC... Or you can have a go with the Scripter to make a script that handles everything in one Scripter instance... Quote Link to comment Share on other sites More sharing options...
michaelrasbury Posted October 12, 2020 Author Share Posted October 12, 2020 You can have multiple instances of the Modifier plugin, each only affecting one CC... Or you can have a go with the Scripter to make a script that handles everything in one Scripter instance... Can you point me to a resource that will show me how to create this CC modifier script? Quote Link to comment Share on other sites More sharing options...
des99 Posted October 12, 2020 Share Posted October 12, 2020 There are example scripts that come with Logic and are self-documenting. Explore them and you should see how to modify events, there are similar enough examples that it should be quite straightforward. Quote Link to comment Share on other sites More sharing options...
michaelrasbury Posted October 12, 2020 Author Share Posted October 12, 2020 There are example scripts that come with Logic and are self-documenting. Explore them and you should see how to modify events, there are similar enough examples that it should be quite straightforward. I tried using the "15-Control Plug-ins" as an example. I was able to change the script so that the CC2 controlled CC1, but then I couldn't figure out how to paste more iterations of the code so that I could simultaneously transform the other nine MIDI CC's I need to alter. I kept getting syntax errors. I need to take incoming CC2 and send it to CC1, and also CC1 and send it to CC21, CC3 and send it to CC20, CC15 to CC26, CC42 to CC16, CC43 to CC17, CC46 to CC28, CC50 to CC29 and CC33 to CC52. I need this to happen all at the same time! Quote Link to comment Share on other sites More sharing options...
des99 Posted October 12, 2020 Share Posted October 12, 2020 Welcome to the wonderful world of coding! You've just had your first taste of how a programmer feels tackling software problems! You can paste in your script here if you want to get some help with it... Quote Link to comment Share on other sites More sharing options...
michaelrasbury Posted October 13, 2020 Author Share Posted October 13, 2020 Welcome to the wonderful world of coding! You've just had your first taste of how a programmer feels tackling software problems! You can paste in your script here if you want to get some help with it... This is about my tenth or so taste LOL after trying to get some KSP working. I also understand HTML pretty well. I also use to program computers in basic a LONG time ago. I'm not totally green. I can understand when it is already there and copy and paste items to make it work. Here's what I've got so far. I'm trying to get it to display more than one CC. var PluginParameters = [ { name:"CC21 Target", type:"target" }]; var PluginParameters = [ { name:"CC2 Target", type:"target" }]; function HandleMIDI(incomingEvent) { if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 21)) { var newEvent = new TargetEvent(); newEvent.target = "CC21 Target"; newEvent.value = incomingEvent.value / 127; newEvent.send(); } else { incomingEvent.send(); }; }; function HandleMIDI(incomingEvent) { if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 2)) { var newEvent = new TargetEvent(); newEvent.target = "CC2 Target"; newEvent.value = incomingEvent.value / 127; newEvent.send(); } else { incomingEvent.send(); }; }; Quote Link to comment Share on other sites More sharing options...
des99 Posted October 13, 2020 Share Posted October 13, 2020 Ok. You can't just duplicate the HandleMIDI callback, there is only one - when a MIDI event comes in, it's passed to that function, so you need to do all the work in that one single function. In short, you want to do something like: if event = CC21, do this stuff else if event = CC22 do this stuff else if event = CC 76 do this stuff Along these lines: function HandleMIDI(incomingEvent) { if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 21)) { var newEvent = new TargetEvent(); newEvent.target = "CC21 Target"; newEvent.value = incomingEvent.value / 127; newEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 22)) { var newEvent = new TargetEvent(); newEvent.target = "CC22 Target"; newEvent.value = incomingEvent.value / 127; newEvent.send(); } else { incomingEvent.send(); }; }; That should get you on the right track... Quote Link to comment Share on other sites More sharing options...
michaelrasbury Posted October 13, 2020 Author Share Posted October 13, 2020 Ok. You can't just duplicate the HandleMIDI callback, there is only one - when a MIDI event comes in, it's passed to that function, so you need to do all the work in that one single function. In short, you want to do something like: if event = CC21, do this stuff else if event = CC22 do this stuff else if event = CC 76 do this stuff Along these lines: function HandleMIDI(incomingEvent) { if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 21)) { var newEvent = new TargetEvent(); newEvent.target = "CC21 Target"; newEvent.value = incomingEvent.value / 127; newEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 22)) { var newEvent = new TargetEvent(); newEvent.target = "CC22 Target"; newEvent.value = incomingEvent.value / 127; newEvent.send(); } else { incomingEvent.send(); }; }; That should get you on the right track... That's of great help but something I don't understand... I need the script to take incoming CC 21 Data and instead send it on as CC1. Incoming CC 20 data needs to output as CC3 Data. In the attached code, I see it looking for CC21 but then I don't see it changing it into CC1. Am I not understanding something? Quote Link to comment Share on other sites More sharing options...
des99 Posted October 13, 2020 Share Posted October 13, 2020 I wasn't planning on writing your code for you (just as you're not offering to write mine for me! ), just helping you along the way with some basics. At the moment, you seem to be setting the new event as a string ("CC21 Target") which I'm not sure is correct, but I'm problem solving my own Logic code related stuff in other languages and can't dive into this right now of refresh my memory of Logic's JS controller MIDI functions - there should be example code there though that will give you clues. Quote Link to comment Share on other sites More sharing options...
David Nahmani Posted October 13, 2020 Share Posted October 13, 2020 CC21 Target is a variable that creates a pop-up menu on the scripter plug-in. Michael, you may not need to declare the variables if you don't mind hard coding the values in the script itself. If have a feeling that script could be much shorter. Quote Link to comment Share on other sites More sharing options...
David Nahmani Posted October 13, 2020 Share Posted October 13, 2020 Here, try this modified and simplified version of Des99's code: function HandleMIDI(incomingEvent) { if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 21)) { incomingEvent.number = 1; incomingEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 20)) { incomingEvent.number = 3; incomingEvent.send(); } else { incomingEvent.send(); }; }; Quote Link to comment Share on other sites More sharing options...
michaelrasbury Posted October 13, 2020 Author Share Posted October 13, 2020 Here, try this modified and simplified version of Des99's code: function HandleMIDI(incomingEvent) { if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 21)) { incomingEvent.number = 1; incomingEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 20)) { incomingEvent.number = 3; incomingEvent.send(); } else { incomingEvent.send(); }; }; That is exactly what I needed! I didn't quite understand the syntax. Here's what I did with your VERY HELPFUL example and it works! function HandleMIDI(incomingEvent) { if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 2)) { incomingEvent.number = 1; incomingEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 1)) { incomingEvent.number = 21; incomingEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 3)) { incomingEvent.number = 20; incomingEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 15)) { incomingEvent.number = 26; incomingEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 42)) { incomingEvent.number = 16; incomingEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 43)) { incomingEvent.number = 17; incomingEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 46)) { incomingEvent.number = 28; incomingEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 50)) { incomingEvent.number = 29; incomingEvent.send(); } else if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 52)) { incomingEvent.number = 33; incomingEvent.send(); } else { incomingEvent.send(); }; }; Quote Link to comment Share on other sites More sharing options...
David Nahmani Posted October 13, 2020 Share Posted October 13, 2020 Great!! Now I'm sure a proper coder would probably screeeaaaam looking at that code. I'm sure this could be coded more elegantly with a switch/case/break for example. But oh well, if it's working, who's to complain, right? Quote Link to comment Share on other sites More sharing options...
des99 Posted October 13, 2020 Share Posted October 13, 2020 Yep, there wasn't much point in introducing new coding concepts when the OP was struggling with the basics, which is why I just illustrated the simplest and most understandable way of doing it. If it works, that's plenty good enough... Quote Link to comment Share on other sites More sharing options...
David Nahmani Posted October 13, 2020 Share Posted October 13, 2020 Yep, there wasn't much point in introducing new coding concepts when the OP was struggling with the basics, which is why I just illustrated the simplest and most understandable way of doing it. If it works, that's plenty good enough... Yes it's certainly more fun to get started that way and learn the "proper way" when and if needed than it is to get started with an academic course on proper algorithm. I'm far from being good at this stuff, but I can kind of haphazardly hack my way through it when needed. Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted October 13, 2020 Share Posted October 13, 2020 The above works fine.. It could be done different ways... There is not necessarily any right or wrong way to do it. I would prefer to setup this kind of situation with an array map, because its easy to maintain and tweak. var ccMap = []; for(let i=0;i<128;i++) { ccMap[i] = i; } ccMap[2] = 1; ccMap[1] = 21; ccMap[3] = 20; ccMap[15] = 26; ccMap[42] = 16; ccMap[43] = 17; ccMap[46] = 28; ccMap[50] = 29; ccMap[52] = 33; function HandleMIDI(event) { if(event instanceof ControlChange) { event.number = ccMap[event.number]; } event.send(); }; Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted October 13, 2020 Share Posted October 13, 2020 You could also get tricky and make the script with a gui for assigning which CC's to remap... But in a lot of ways that involves a lot of extra scripter code and its not that hard to just tweak the above script directly. Quote Link to comment Share on other sites More sharing options...
des99 Posted October 13, 2020 Share Posted October 13, 2020 It's certainly a lot cleaner! Now if you could just come and clean up my code, that would save me an awful lot of effort and I could just go watch Netflix instead... Quote Link to comment Share on other sites More sharing options...
David Nahmani Posted October 13, 2020 Share Posted October 13, 2020 That's awesome. Thanks a lot Steve for chiming in with the clean+elegant way to code this. I learned something right now. Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted October 13, 2020 Share Posted October 13, 2020 cheers Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted October 13, 2020 Share Posted October 13, 2020 one more thing though, I notice the original script provided by michaelrasbury is actually using TargetEvent, which is slightly different/more then merely remapping the CC number. That provides a way to tell Scripter to bypass the kontakt CC automation engine entirely and directly convert CC events directly into parameter automation driven from Scripter. However, the way its all designed this will be a similar problem insomuch that Scripter never knows ahead of time which Plugin parameter is which, which can change depending on the order of plugins in the channel strip, etc.. So Scripter has this method where you have to manually associate the Scripter GUI control to a specific plugin parameter, etc. Well that is the very thing the OP is trying to avoid I think. But anyway just wanted to point out, these final solutions went to CC number mapping and if that is good enough then great, but if we want to dig deeper into using TargetEvent, that would be a deeper topic for further exploration. Quote Link to comment Share on other sites More sharing options...
michaelrasbury Posted October 13, 2020 Author Share Posted October 13, 2020 You could also get tricky and make the script with a gui for assigning which CC's to remap... But in a lot of ways that involves a lot of extra scripter code and its not that hard to just tweak the above script directly. Thanks to all for these lessons! I appreciate the "cleaner" updated code as it is easier for me to edit and make changes to visually. I can generally understand what the code does but still struggle generating it. To be honest, I probably would have paid for a script like you describe above. I started this post by using the script in "Tutorial Scripts" called "15-Control Plugins." It does what you describe above but for only the Modulation Wheel. I tried to duplicate the code to make more CC appear in the popup menus. This is why TargetEvent was left over. I also need to reverse the CC data for a couple of those CC's- meaning instead of my associated controller sending 0-128, I need it to send 128-0 which in turn makes my physical controller send data in the opposite direction. For now, I'm doing that in Kontakt's controller section but of course when I get instrument updates all those custom assignments vanish with the old patch. This is why I am so keen to figure a script! Quote Link to comment Share on other sites More sharing options...
michaelrasbury Posted October 13, 2020 Author Share Posted October 13, 2020 Yep, there wasn't much point in introducing new coding concepts when the OP was struggling with the basics, which is why I just illustrated the simplest and most understandable way of doing it. If it works, that's plenty good enough... I could have handled it lol... but I sincerely appreciate your help! Quote Link to comment Share on other sites More sharing options...
des99 Posted October 13, 2020 Share Posted October 13, 2020 No worries! Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted October 13, 2020 Share Posted October 13, 2020 I also need to reverse the CC data for a couple of those CC's- meaning instead of my associated controller sending 0-128, I need it to send 128-0 which in turn makes my physical controller send data in the opposite direction. So if you need to reverse the controller values, or any other stuff, then you may be better off going back to something like what Des or David suggested earlier...using if/then statements, so you can handle each controller# in a totally different way for each one. You reverse the value like this: event.value = 127-event.value; Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted October 14, 2020 Share Posted October 14, 2020 so maybe like this, I put one example of reversing the order on CC15: function HandleMIDI(event) { if (event instanceof ControlChange) { if (event.number == 2) { event.number = 1; } else if (event.number == 1) { event.number = 21; } else if (event.number == 3) { event.number = 20; } else if (event.number == 15) { event.number = 26; event.value = 127-event.value; // reverse order } else if (event.number == 42) { event.number = 16; } else if (event.number == 43) { event.number = 17; } else if (event.number == 46) { event.number = 28; } else if (event.number == 50) { event.number = 29; } else if (event.number == 52) { event.number = 33; } } event.send(); } I cleaned up a few things to make it easier to read, and don't need to check for ControlChange instanceof so many times over and over.. But you get the point hopefully, do whatever you want with each CC#. In theory you could scale them each differently this way too, etc.. The earlier script I gave uses a so called data-driven approach, which generally is preferable to using complicated nested if/then statements. Its easier to read, easier to troubleshoot and often times is faster execution too, but for small scripts like this, it doesn't really matter, use whatever method that is easiest to understand for yourself. But in case you were wondering, how might we use a data driven approach while handling both the job of remapping CC# and also sometimes occasionally reversing the value order? Well it might be something like this: var ccMap = []; for(let i=0;i<128;i++) { ccMap[i] = {num: i, revorder: false}; } ccMap[2].num = 1; ccMap[1].num = 21; ccMap[3].num = 20; ccMap[15].num = 26; ccMap[15].revorder = true; ccMap[42].num = 16; ccMap[43].num = 17; ccMap[46].num = 28; ccMap[50].num = 29; ccMap[52].num = 33; function HandleMIDI(event) { if (event instanceof ControlChange) { if (ccMap[event.number].revorder == true) { event.value = 127 - event.value; } event.number = ccMap[event.number].num; } event.send(); } As you can see the code is still compact and easy to change CC mappings later...but..its a bit more complicated to understand and possibly made a few heads explode already..but anyway..there you go...two ways to to do it. Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted October 14, 2020 Share Posted October 14, 2020 David also mentioned the switch statement as another alternative. Here is an example of that. Honestly there is not much inherent advantage to switch statements vs If/then statements...its really just a matter of personal style choice, what is easier for you to look at and understand. one advantage of IF statements is that you can include multiple conditions in one IF, and you can easily nest IF statements... the switch statement is best reserved for very simple situations and some programming languages don't even include it. I tend to not use it much myself. There are a couple rare examples I won't get into now about when it's favorable. its nit picking though. How you format your code can make all the difference also in how easy it is to understand when you look at it or need to update it later. Anyway, here is a switch example of the above: function HandleMIDI(event) { if (event instanceof ControlChange) { switch(event.number) { case 2: event.number = 1; break; case 1: event.number = 21; break; case 3: event.number = 20; break; case 15: event.number = 26; event.value = 127-event.value; // reverse order break; case 42: event.number = 16; break; case 43: event.number = 17; break; case 46: event.number = 28; break; case 50: event.number = 29; break; case 52: event.number = 33; break; } } event.send(); } Quote Link to comment Share on other sites More sharing options...
michaelrasbury Posted October 14, 2020 Author Share Posted October 14, 2020 I also need to reverse the CC data for a couple of those CC's- meaning instead of my associated controller sending 0-128, I need it to send 128-0 which in turn makes my physical controller send data in the opposite direction. So if you need to reverse the controller values, or any other stuff, then you may be better off going back to something like what Des or David suggested earlier...using if/then statements, so you can handle each controller# in a totally different way for each one. You reverse the value like this: event.value = 127-event.value; Ok- thanks for all your help! Quote Link to comment Share on other sites More sharing options...
michaelrasbury Posted October 14, 2020 Author Share Posted October 14, 2020 David also mentioned the switch statement as another alternative. Here is an example of that. Thank you so much for your amazing explanations and these incredible resources. This is really useful to me and much easier to understand especially with the four examples. Thank you so much! 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.