Jump to content

Changing Mainstage patches automatically


atmos74

Recommended Posts

Hi

 

I am a keyboard player and am using mainstage for live performance. I am using the playback function to run some backing tracks for each song. I am trying to find a way to change my patches automatically so the correct one appears for verse, chorus etc and I do not need to trigger them from a footswitch or similar.

 

I have done some research on this forum and found suggestions on Bidule (which I had a look at but do not know how to use) and scripting (Dewdman42 seems to be the man on this) I tried the scripting route but there seemed to be some issues with looping as the playback was juttering and my keyboard layers disappeared for some reason.

 

Can anyone help, understand if it is not possible!. I do own logic as well so if there is an option to run the backing track in logic with midi triggers I am happy to do that but would need guidance. Sorry I am fairly new to the software......appreciate any help you can give.

 

Thanks

David

Link to comment
Share on other sites

A couple things I notice, some are relevant to your problems and some are just observations or suggestions you may find useful:

 

  1. Looks to me like you are attempting to use Bank Select to direct PC messages to the appropriate song and then PC# 2-n within each song. That's a perfectly fine way to handle it, but the current version of the script doesn't send bank select messages. Bank select messages are created using CC0 and CC32 messages. see this article: http://www.andrelouis.com/qws/art/art009.htm
     
    Here is a version of your script with bank select added:
     
    var NeedsTimingInfo = true;
    
    //========= EDIT THIS ARRAY ====================
    
    var programChanges = [
       {beatPos:4.99, channel:1,  number:1, msb:1, lsb:1}
      ,{beatPos:8.99, channel:1,  number:2, msb:1, lsb:1}
      ,{beatPos:12.99, channel:1, number:3, msb:1, lsb:1}
      ,{beatPos:16.99, channel:1, number:4, msb:1, lsb:1}    
      ,{beatPos:20.99, channel:1, number:5, msb:1, lsb:1}
      ,{beatPos:24.99, channel:1, number:6, msb:1, lsb:1}
      // copy the above line for more Program changes
    ];
    
    
    //========= DO NOT EDIT BELOW HERE =============
    
    var idx = 0;
    var pc = new ProgramChange;  //reuse in a loop
    var cc = new ControlChange;
    
    function ProcessMIDI() {
      /* Get current timing info */
      var info = GetTimingInfo();
     
      /* only do work if playing */
      if ( !info.playing ) {
          idx = 0;
          return;
      }
      
      if (idx < programChanges.length) {
      
         while ( idx < programChanges.length &&
                 info.blockStartBeat <= programChanges[idx].beatPos && 
                 info.blockEndBeat >= programChanges[idx].beatPos ) {
            cc.number = 0;
            cc.channel = programChanges[idx].channel;
            cc.value = programChanges[idx].msb-1;
            cc.send();
            
            cc.number = 32;
            cc.value = programChanges[idx].lsb-1;
            cc.send();
                  
            pc.number = programChanges[idx].number - 1;    
            pc.beatPos = programChanges[idx].beatPos;
            pc.channel = programChanges[idx].channel;  
            pc.send();
            // pc.trace();
            idx++;
         }              
      } 
    }
    
    // ignore incoming midi - might not need this
    function HandleMIDI() {
    }
    


     
    Without the bank select message added to the script, then the song was jumping to the next song. The next song didn't even have a script, and also its possible that an endless midi feedback loop may have somehow ensued, which might explain all the flickering and erratic behavior. Not completely sure about that, it happened to me when I first started using your project, but once I added bank select, it stopped happening...but that is my guess.
     
     

  2. You are sending PC messages on channel 16. Why?
     
     
  3. Mainstage has two ways to consider PC messages, starting at zero or starting at 1, which is the so called "Standard" way. Scripter is hard coded to use the low level midi values, which means the first and lowest PC message you can send with Scripter is value=0. When that PC#0 goes over IAC and back into MainStage, if it is set in preferences to 1-128 as the PC range..which is normal...then that PC=0 will be treated as patch#1.
     
    I added a bit to the scripter script, see above, so that you can use the value of "1" in the array at the top...and it will convert that to an actual PC=0 message, so that when it comes back into MainStage that PC0 will be treated like patch #1. Hope that makes sense. The bank select messages are also handled in the same way. This way the script array you fill out should match the numbers you type into MainStage to define each patch's bank select and PC messages based on 1-128 range.
     
    Also notice that bank select is an MSB/LSB value. See the above article, hope that will make sense. You can literally have over 2 million separately identifiable patches this way.
     
    Side-note: You could simplify this script to only use MSB and skip the LSB. These are known as "course" and "fine" patch bank select, many synths and devices only use the MSB "course" to indicate a bank select...So anyway 128 banks for 128 songs is probably enough if you want to simplify things you can remove the LSB handling from the script and just use MSB. But the script has both for illustrative purposes.
     
     
  4. Another important point that I re-remembered while doing this, but you will want to think about...whenever you select a song, don't select the Set Folder, select the first patch of the song before hitting PLAY. I have found some weird things happen if you select the top folder...then press PLAY, the script works but somehow skips the first patch, I haven't been able to figure out why, but if you get any wierdness with that, that is why..make sure you always select the first patch of each song, then hit PLAY, don't choose the song set folder.

 

Here is an updated version of your MainStage project to check it out.

 

80's Band v3-1.zip

Edited by Dewdman42
Link to comment
Share on other sites

As an advanced alternative, here is a version of the script which uses global values for bank select for the whole script, since each song will basically have its own script...you can just choose one bank select MSB/LSB for the whole song which would handle up to 128 patches within that bank. That keeps the script array smaller and simpler to edit:

 

check it out:

 

var NeedsTimingInfo = true;

//========= EDIT THIS ARRAY ====================

var MSB = 1;
var LSB = 1;

var programChanges = [
   {beatPos:4.99, channel:1,  number:1}
  ,{beatPos:8.99, channel:1,  number:2}
  ,{beatPos:12.99, channel:1, number:3}
  ,{beatPos:16.99, channel:1, number:4}    
  ,{beatPos:20.99, channel:1, number:5}
  ,{beatPos:24.99, channel:1, number:6}
  // copy the above line for more Program changes
];


//========= DO NOT EDIT BELOW HERE =============

var idx = 0;
var pc = new ProgramChange;  //reuse in a loop
var cc = new ControlChange;

function ProcessMIDI() {
  /* Get current timing info */
  var info = GetTimingInfo();
 
  /* only do work if playing */
  if ( !info.playing ) {
      idx = 0;
      return;
  }

  if (idx < programChanges.length) {
  
     while ( idx < programChanges.length &&
             info.blockStartBeat <= programChanges[idx].beatPos && 
             info.blockEndBeat >= programChanges[idx].beatPos ) {
        cc.number = 0;
        cc.channel = programChanges[idx].channel;
        cc.value = MSB-1;
        cc.send();
        
        cc.number = 32;
        cc.value = LSB-1;
        cc.send();
              
        pc.number = programChanges[idx].number-1;    
        pc.beatPos = programChanges[idx].beatPos;
        pc.channel = programChanges[idx].channel;  
        pc.send();
        // pc.trace();
        idx++;
     }              
  } 
}

// ignore incoming midi - might not need this
function HandleMIDI() {
}
Edited by Dewdman42
Link to comment
Share on other sites

An even more advanced version could probably just assume a global midi channel also, to remove it from that script array, to make it easier to edit. You could also reduce that script array to something like the following structure for easy editing in a less-verbose structure. This should make it easier to edit each script for each song.

 

//Global values for this script
var CHANNEL = 1;
var MSB = 1;  //bank select MSB course
var LSB = 1;   // bank select LSB fine

var programChanges = [
   [ 4.99,   1]
  ,[ 8.99,   2]
  ,[ 12.99,  3]
  ,[ 16.99,  4]  
  ,[ 20.99,  5]
  ,[ 24.99,  6]
  // copy the above line for more Program changes
];

 

So the full script using the above would be this in order to make that simpler array work:

 

var NeedsTimingInfo = true;

//========= EDIT THIS ARRAY ====================

//Global values for this script
var CHANNEL = 1;
var MSB = 1;  //bank select MSB course
var LSB = 1;   // bank select LSB fine

var programChanges = [
   [ 4.99,   1]
  ,[ 8.99,   2]
  ,[ 12.99,  3]
  ,[ 16.99,  4]  
  ,[ 20.99,  5]
  ,[ 24.99,  6]
  
  // copy the above line for more Program changes
];

//========= DO NOT EDIT BELOW HERE =============

var idx = 0;
var pc = new ProgramChange;  //reuse in a loop
var cc = new ControlChange;

function ProcessMIDI() {
  /* Get current timing info */
  var info = GetTimingInfo();
 
  /* only do work if playing */
  if ( !info.playing ) {
      idx = 0;
      return;
  }

  if (idx < programChanges.length) {
  
     while ( idx < programChanges.length &&
             info.blockStartBeat <= programChanges[idx][0] && 
             info.blockEndBeat >= programChanges[idx][0] ) {
        cc.number = 0;
        cc.channel = CHANNEL;
        cc.value = MSB-1;
        cc.send();
        
        cc.number = 32;
        cc.value = LSB-1;
        cc.send();
              
        pc.number = programChanges[idx][1]-1;    
        pc.beatPos = programChanges[idx][0];
        pc.channel = CHANNEL;  
        pc.send();
        // pc.trace();
        idx++;
     }              
  } 
}

// ignore incoming midi - might not need this
function HandleMIDI() {
}
Edited by Dewdman42
Link to comment
Share on other sites

Hi, just gave this a try tonight.....should the patches be changing automatically when I hit the play button? Nothing was changing as far as I could tell this end. Apologies if I'm missing something obvious.

I have checked my IAS bus is online. I am using a midi keyboard to add live keys to the track. What midi channel should this be on?

Thanks

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...