Jump to content

LPX: Script for changing MIDI channel with Program Change


drb

Recommended Posts

I have created a script for the MIDI plugin Scripter that sets the MIDI channel for channel messages by Program Change messages. This may be of interest if:

 

1) You have a multi-timbral software instrument that does interpret MIDI channels

 

2) but does not interpret Program changes

 

3) and you want to change "voice" within one track.

 

In my case this came up with the Aria version of the Garritan Personal Orchestra and a score that had one musician switching between flute and piccolo. This allowed me to easily keep one staff in the score without having to edit the MIDI channels of the track. Since dirrent MIDI channels are can be used by the Notation part of Logic for polyphonic parts and hiding key switches, this can make changing "voice" easier when global changes to the MIDI channel are not easy.

 

Instructions are in the script. Note that the channel strip MIDI channel must be set to "All".

 

/*
 Implement program change messages as changes in MIDI channel
 for Instruments that implement MIDI channel changes but not program changes.

 Program number becomes MIDI channel.  Starts as 1.
 Program change message results in saving new channel number.
 Program change message not passed through.
 Other channel messages passed through with MIDI channel set to saved channel number
 Non channel message passed through unchanged.

 No configuration parameters.
 Assuming MIDI channel and program numbers start at 1, not 0
 Assuming track MIDI channel set to ALL.
*/

var savedChannel = 1;                                // MIDI channel number to use

function HandleMIDI(event) {
 if ( event instanceof ProgramChange ) {
   if ( 1 <= event.number && event.number <= 16 ) { // ignore if not a good MIDI channel
     savedChannel = event.number;                   // save program number as MIDI channel
   }
 }
 else if ( event instanceof NoteOn ||               // all other channel messages
           event instanceof NoteOff ||
           event instanceof PolyPressure ||
           event instanceof ControlChange ||
           event instanceof ChannelPressure ||
           event instanceof PitchBend ) {
   event.channel = savedChannel;                    // set to saved program number
   event.send();                                    // pass through event
 }
 else {
   event.send();				                           //send anything else through unchanged
 }
}

function reset() {
 savedChannel = 1;                                 // back to default
}

Edited by drb
Link to comment
Share on other sites

anp27, thanks.

 

cmrick, No, you caught me. The case I was using it for, simulating a musician changing instruments, doesn't bring this up. If you are interested, I think it could be done -- but the script would have to track note ons, then generate a note off itself for notes still going during a program change. This would not help with synthesizers that abruptly end release and effects that may go on after a note off when the "voice" changes. So, it still would not be perfect for the case of a program change during a note.

Link to comment
Share on other sites

cmrick, After the last reply, thinking some more, I realized that since what is really happening is a channel change on a multitimbral instument, not a program change, my worries about release and effects may not be correct. This makes your point even better.

 

If you wish, I can try making this change tomorrow (it's late on the east coast).

Link to comment
Share on other sites

Here is a more complex version in an attempt to deal with unfinished business at a program channel change - that is, hanging notes.

 

A note held over a program/channel change can still have odd results. If a new note of the same pitch is started and not finished before the note end of the previous note, the first note off stops the note prematurely. I also try to deal with the sustain and sostenuto controllers. Since some controllers are undefined in the MIDI spec and some are used in non-standard ways, I cannot anticipate all possibilities.

 

For recorded sequence work, I think I will use the first version and be sure one instrument is done before trying to use another.

 

/*
 ProgramNumberToMIDIChannel-1.1.js
 written by David R. Baker
 Version 1.1 2013 08 01

 Implement program change messages as changes in MIDI channel
 for Instruments that implement MIDI channel changes but not program changes.

 Program number becomes MIDI channel.  Starts as 1.
 Program change message results in 
   turning outstanding notes/sustain/sostenuto off (new 1.1) and
   saving new channel number.
 Program change message not passed through.
 Other channel messages passed through with MIDI channel set to saved channel number
 Non channel message passed through unchanged.

 No configuration parameters.
 Assuming MIDI channel numbers start at 1, not 0
 Assuming track MIDI channel set to ALL.
*/

var savedChannel = 1;                                // MIDI channel number to use
var noteOnCnt = [                                    // 1 element for each note number/pitch
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 ];

function HandleMIDI(event) {
 var off = new NoteOff;
 var cc  = new ControlChange;
 //event.trace();
 off.channel = savedChannel;
 off.velocity = 0;
 if ( event instanceof ProgramChange ) {
   if ( 1 <= event.number && event.number <= 16 ) { // ignore if not a good MIDI channel
     for (var i=0; i<128; i++) {                    // for each MIDI pitch
       for (var j=0; j<noteOnCnt[i]; j++) {         //   for each outstanding note on
         off.pitch = i;                             //     send note off
         off.send();
         //Trace("generated note off");
       }
       noteOnCnt[i] = 0;
     }
     cc.channel = savedChannel;
     cc.value = 0;
     cc.number = 64;	                             // turn off sustain
     cc.send();
     //Trace("generated sustain off");
     cc.number = 66;	                             // turn off sostenuto
     cc.send();
     //Trace("generated sostenuto off");
     
     savedChannel = event.number;                   // save program number as MIDI channel
   }
 }
 else if ( event instanceof NoteOn ) {
   noteOnCnt[event.pitch] += 1;                     // increment number of note On's
   event.channel = savedChannel;                    // set to saved program number
   event.send();                                    // pass through event
   }
 else if ( event instanceof NoteOff ) {
   if ( noteOnCnt[event.pitch] > 0 ) {              // odd case of note crossing channel change
     noteOnCnt[event.pitch] -= 1;                   // decrement number of note On's
   }
   event.channel = savedChannel;                    // set to saved program number
   event.send();                                    // pass through event
   }
 else if ( event instanceof PolyPressure ||         // all other channel messages
           event instanceof ControlChange ||
           event instanceof ChannelPressure ||
           event instanceof PitchBend ) {
   event.channel = savedChannel;                    // set to saved program number
   event.send();                                    // pass through event
 }
 else {
   event.send();                                    // pass anything else through unchanged
 }
}

function reset() {
 savedChannel = 1;                                 // back to default
 for (var i=0; i<128; i++) { noteOnCnt[i] = 0; }
}

Link to comment
Share on other sites

  • 4 weeks later...
Here is a more complex version in an attempt to deal with unfinished business at a program channel change - that is, hanging notes.

 

Just tested this using GPO4 with the Woodwind quintet ensemble loaded. It works GREAT! I didn't test your newer code for the program change in between notes though. Thanks again! This is a good workaround to the lack of expression maps within Logic.

 

Somewhat related.... would you have any ideas on how to get Logic's Smart Controls to see the ARIA Player by any chance? Would it involve some special script for this to work? I would love to be able to map ARIA's CCs to the Smart Controls.

Link to comment
Share on other sites

anp27,

 

Thanks again.

 

Note - view this topic for a problem using the script on multiple tracks.

 

http://www.logicprohelp.com/forum/viewtopic.php?f=42&t=98869

 

I hope this will be fixed. Meanwhile, I am having no problem using this script on a single track.

 

On Smart Controls and Aria -- as far as I can tell Aria does not implement the automation parameters (as opposed to MIDI CC's) used by Smart Controls. If you switch the view for a plugin from Editor to controls on Logic instruments (or NI Kontakt for example) you see a bunch of parameters. On Aria, you see none. I am far from guru hood on this topic. So, maybe someone else can see a way that I cannot.

 

Maybe an Environment window could do this.

 

drb

Link to comment
Share on other sites

anp27,

 

Thanks again.

 

Note - view this topic for a problem using the script on multiple tracks.

 

http://www.logicprohelp.com/forum/viewtopic.php?f=42&t=98869

 

I hope this will be fixed. Meanwhile, I am having no problem using this script on a single track.

 

On Smart Controls and Aria -- as far as I can tell Aria does not implement the automation parameters (as opposed to MIDI CC's) used by Smart Controls. If you switch the view for a plugin from Editor to controls on Logic instruments (or NI Kontakt for example) you see a bunch of parameters. On Aria, you see none. I am far from guru hood on this topic. So, maybe someone else can see a way that I cannot.

 

Maybe an Environment window could do this.

 

drb

 

Just checked out that thread :( I'm sure Apple will fix it soon.

 

As for the ARIA Player, I emailed Garritan and asked them about it, will have to wait for their reply. Do you have any hints on how the environment might be used in this situation?

Link to comment
Share on other sites

anp27,

 

On the environment instead of Smart Controls -- I am still learning Logic myself, so I would be figuring out how to make such an environment window from scratch. It appears that faders would do the job, but I have not actually done it.

 

Please post when you hear from Garritan.

 

drb

Link to comment
Share on other sites

FWIW, doing this in the environment will prove a daunting task. And if you don't know the environment, it will take you years to figure out. At one time I was offering an environment macro called "SkiSwitcher" that solves all of these problems (it was donation-ware, but virtually no one donated so it's now off the market.) Anyway, the biggest issue here is not that the problems are unsolvable in scripts, but that you can't run more than one Script in LX without causing problems (thanks drb for pointing this out).
Link to comment
Share on other sites

anp27,

Please post when you hear from Garritan.

drb

 

This is reply I received from Garritan:

 

Unfortunately, the ARIA Player is not compatible with Logic's Smart Control. Since the ARIA player is a dynamic interface, the MIDI controls that are available with it will change from library to library and sometimes from sample to sample. The only way to change MIDI values is to use the UI in the ARIA player itself or to draw the MIDI data into the track itself.

 

Please feel free to respond to this case if you have any further questions about this issue.

 

Erin V.

MakeMusic Customer Support

 

:(

Link to comment
Share on other sites

anp27,

 

Thanks for the Garritan reply. Sort of what I guessed, though the explanation doesn't make sense to me. I think they just haven't implemented the automation stuff. Possibly because a major design and marketing point is that it is playable from a controller.

 

drb

Link to comment
Share on other sites

sforzando.thumb.jpg.5d64ee248731f35e42789170702ddddb.jpg

It works!!

anp27,

 

Thanks for the Garritan reply. Sort of what I guessed, though the explanation doesn't make sense to me. I think they just haven't implemented the automation stuff. Possibly because a major design and marketing point is that it is playable from a controller.

 

drb

 

I was actually expecting an answer like that from them.

 

BUT!

 

I did some poking around on the Web and did an experiment. I went to the Plogue site (which makes the sfz player) and downloaded the 'universal' sfz player that they have. I opened up the 'sforzando' plugin and GUESS WHAT?? The controls within the sforzando player ARE RECOGNIZED by Smart Controls! And I'm able to access all of my Garritan libraries as well! They happen to be fully compatible :) If you want to have access to the Smart Controls as well, I recommend you going to the Plogue site and grabbing the sfz player.

 

Really happy right now :D

Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...