Jump to content

Program Change via MIDI Scripter


SRF_Audio

Recommended Posts

Hello all, 

 

Probably against my better judgement, I continue to try to make Mainstage work for me as my go-to tool for live performance. 

 

With the release of 3.3.1, I'm coming back around to give this another go. I'm already developed an inelegant, but functional method that uses the IAC bus and Logic to send events. But the MIDI scripter seems to offer the tantalizing possibility of being totally self contained in MS.

 

I know just enough basic javascript to know that I'm a terrible programmer. ;-)

 

So I was hoping to get some help from those who are more savvy at using the MIDI scripter. It still boggles the mind that the dev team wouldn't include that as an example script, as it seems to be a glaringly obvious usage of the program. (And, a feature that I have submitted feedback for several times.)

 

Goal:

To automate patch changes and parameters in time with Playback tracks throughout a concert.

 

Possible methods:

1) Call the state of Playback Markers (preferably at the Set level), and use each marker change to generate Program Change Messages that Mainstage will receive and respond to.

2) Call the state of the master clock/beat clock/MIDI clock, and use a specific beat to trigger PC messages.

 

I have been reading through the manual all morning, pulling my hair out because I just don't have the programming skills to translate the example scripts over to my solution.

Any ideas? 

Link to comment
Share on other sites

I could be wrong, but I don't believe Mainstage has any notion of bar:beat.  It can run midi clock, which is just a metronome, it does not track anything related to point in time on a timeline.  

 

I agree that the ability to auto-send program changes over time would be an extremely useful feature.  Most people I know that use backing tracks just play MP3's and don't mess around with midi sequencer playback...and even with that, the metronome wouldn't even necessarily be running...

 

I think you would need some kind of sequencer that runs as a plugin.  a plugin that has its own bar:Beat counter which you can then use to send program changes.  

 

So I don't have a great answer for you but I don't think the scripter will get it for you.  

 

You could experiment with the following idea, maybe you will get some where.

Edited by Dewdman42
Link to comment
Share on other sites

Another idea that just occurred to me is that you could add your own bar:beat counter to a Scripter script.  So basically have it keep track of its own location in time, based on the number of midi clocks that have gone by...and send your program changes at the appropriate times.  that might work actually!  Unfortunately I don't know anything about writing scripts.  ;-)
Link to comment
Share on other sites

I was kind of curious about this, so here's a start, I leave the rest to you...

 

var NeedsTimingInfo = true;

function ProcessMIDI() {
      var info = GetTimingInfo();
      if (info.playing)
          Trace(info.blockStartBeat)
  }

This simple thing just prints out the beat as a decimal value every time processMidi is called.  You can probably figure out some simple scripts. So if you want to send a program change on beat 10 let's say, then check to see if info.blockStartBeat is <= 10 and info.blockEndBeat is >= 10.  If so, then send the program change. 

 

A more elaborate script could be developed to let you specify the program change hit points in an easier way

Link to comment
Share on other sites

Here ya go...a more complete example, this sends a program change at beat 10 and beat 20:

 

var NeedsTimingInfo = true;

function ProcessMIDI() {
   /* Get current timing info */
   var info = GetTimingInfo();
  
   /* only do work if playing */
   if (info.playing) {
           
      /* if beat 10 is in current process block, then send program */
      if (info.blockStartBeat < 10 && info.blockEndBeat >= 10 ) {
            var pc = new ProgramChange;       
            pc.number = 33;     /* send program change 33 */    
            pc.beatPos = 10;
            pc.channel = 2;  
            pc.send();
            pc.trace();  
      }

      /* if beat 20 is in current process block, then send program */
      if (info.blockStartBeat < 20 && info.blockEndBeat >= 20 ) {
            var pc = new ProgramChange;       
            pc.number = 56;     /* send program change 33 */    
            pc.beatPos = 20;
            pc.channel = 5;  
            pc.send();
            pc.trace();  
      }
   }
}

Link to comment
Share on other sites

  • 1 month later...
  • 3 weeks later...
There is actually an even easier way.  You can attach a midi file to the patch and embed a program change in there, no scripter needed

Could you expand on this a bit? I've been using Mainstage since the beginning, and I have never figured out a way to attach a MIDI file to a patch/set.

Link to comment
Share on other sites

Here ya go...a more complete example, this sends a program change at beat 10 and beat 20:

 

var NeedsTimingInfo = true;

function ProcessMIDI() {
   /* Get current timing info */
   var info = GetTimingInfo();
  
   /* only do work if playing */
   if (info.playing) {
           
      /* if beat 10 is in current process block, then send program */
      if (info.blockStartBeat < 10 && info.blockEndBeat >= 10 ) {
            var pc = new ProgramChange;       
            pc.number = 33;     /* send program change 33 */    
            pc.beatPos = 10;
            pc.channel = 2;  
            pc.send();
            pc.trace();  
      }

      /* if beat 20 is in current process block, then send program */
      if (info.blockStartBeat < 20 && info.blockEndBeat >= 20 ) {
            var pc = new ProgramChange;       
            pc.number = 56;     /* send program change 33 */    
            pc.beatPos = 20;
            pc.channel = 5;  
            pc.send();
            pc.trace();  
      }
   }
}

Just wanted to follow up with you. First off, wonderful idea. I still don't quite have the execution that I'm looking for, but I'm getting closer. 

 

I changed out the BlockStartBeat for a BeatPos Property, and I've got it successfully sending over the IAC bus at the right time. I just need to go in and prevent the MIDI feedback loop, and figure out why it's sending on a different channel, etc. 

 

But, if I can get this resolved....this is really close to the solution that many people want I think. 

 

I still don't know why the Playback plug can't just load up a standard MIDI file that you build in Logic with everything prebuilt.

Link to comment
Share on other sites

you don't load a midi file into the playback plugin.  The actual mainstage "patch" has a place to configure a midifile which will be played automatically when you load the patch.  

 

to get rid of the midi loop, if you're sending to an IAC bus...then actually I don't know a way to get rid of the loop in Mainstage.  In LPX you can block it from coming back in, but I don't know of a way in mainstage...interesting dilemna

Link to comment
Share on other sites

you don't load a midi file into the playback plugin.  The actual mainstage "patch" has a place to configure a midifile which will be played automatically when you load the patch.  

 

to get rid of the midi loop, if you're sending to an IAC bus...then actually I don't know a way to get rid of the loop in Mainstage.  In LPX you can block it from coming back in, but I don't know of a way in mainstage...interesting dilemna

I have never seen or heard of this feature. How do you attach a MIDI file to a patch?

Link to comment
Share on other sites

Create an external MIDI Instrument then look at the channel strip inspector > MIDI out tab.

You can see a send MIDI file 'Select' button. Use that to load your MIDI file.

Ok, this is really, really cool. I had never run into this feature just because I haven't used external MIDI tracks in Mainstage hardly ever. 

 

So now, the next magical question is...how to get the MIDI file to trigger MS3 Patch changes over the IAC bus at the correct beat position...

Link to comment
Share on other sites

  • 4 weeks later...

The easiest way is:

 

  1. Create an external instrument mixer strip
  2. select that mixer strip, by clicking on it
  3. Notice that on the channel strip inspector there is a tab called "midi Output". Select that tab
  4. you will see a checkbox to send midifile and a button to select the midifile to send

 

That's it. Then make a midifile using LogicPro or some other sequencer that sends your program changes at exactly the place in time you want.

 

Now all that being said, this feature of Mainstage is extremely limited. You can only configure it to send the midifile starting with then the patch is called up in mainstage. There is no PLAY or STOP functionality, supposedly. I'm not even sure if it uses the current tempo set in mainstage or not...If anyone gets this working, please let us know.

 

Otherwise if you use some kind of midi plugin sequencer, in combination with the external instrument plugin on an instrument strip, then you can use the Play button in Mainstage to start and stop, control tempo, etc..still kind of crude, but a little more control. But hey you might actually WANT it to start playing the second you call up the patch, so that you don't actually have to hit play, in which case the built in midifile player is actually perfect...just remember you can't stop it once it starts until you switch patches at the very least, some people ahve said you can only stop it by stopping mainstage, I don't really know. Good luck...

 

The midi scripter script I gave above is a simple way to midi plugin option to send program changes at certain points of time... But it will require you to tweak the script and then you have to hit the PLAY button to get it going.

Link to comment
Share on other sites

Here's an improved version of the midi scripter script that makes it a lot easier to edit if anyone finds it useful.

 

var NeedsTimingInfo = true;

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

var programChanges = [
   {beatPos:10, channel:2, number:33}
  ,{beatPos:20, channel:5, number:56}
// copy the above line for more Program changes
];

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

function ProcessMIDI() {
  /* Get current timing info */
  var info = GetTimingInfo();
 
  /* only do work if playing */
  if (info.playing) {
          
     for (i=0;i<programChanges.length;i++) {
     
        if (info.blockStartBeat < programChanges[i].beatPos &&
                 info.blockEndBeat >= programChanges[i].beatPos ) {
                    
           var pc = new ProgramChange;       
           pc.number = programChanges[i].number;    
           pc.beatPos = programChanges[i].beatPos;
           pc.channel = programChanges[i].channel;  
           pc.send();
           //pc.trace();
        }
     }
  }
}

Link to comment
Share on other sites

Thanks Dewdman. I haven't messed with it since a few weeks ago, but when I was in there working with it...it seemed to trigger the beat clock at a totally weird time scale. I had Snoize MIDI monitor open so I could see when things were happening, and it was just all over the place.

 

I couldn't get an accurate view of when it was triggering the file, vs. when Mainstage received and responded.

 

I'll work on it some more next week and get back to you guys.

 

This has been almost a 2 year quest to get this "Mainstage fully automated" pipe dream to come true.

I was using another method, that worked (sort of)...but the IAC bus is so damn unreliable in it's MIDI timing.

Link to comment
Share on other sites

the midi IAC bus is not as bad as you're making it sound. If so, then you have some major problem somewhere. I have used IAC for years without any issues and sub-millisecond latency over the IAC bus...it should not be an issue truly. However, if you get a midi loop or something...wierd stuff could happen. But honestly you should not notice any timing problems at all over IAC.
Link to comment
Share on other sites

I wrestled with trying to find a clever way to do automate midi changes for a couple years and finally bought a license for ableton live intro ($75 during a sale). I use it in parallel with MS to do all my playback and midi automation and it has worked very well. The combo is very nice because you can leverage the strengths of both programs.
Link to comment
Share on other sites

  • 3 weeks later...
This has been almost a 2 year quest to get this "Mainstage fully automated" pipe dream to come true.

I'm with you on this. It shouldn't be this hard. That being typed, I am aware that the developers never considered timeline automation - and actually may never consider it. Which is a real shame. Which is why the development of a time-based playback plugin with MIDI timing implemented would be amazing. Seems so odd that the playback plugin can't take cues from the audio in it.

 

Then again, another issue I've run into is if backing tracks have more than one tempo in the file. MainStage really doesn't like that, which makes time based effects less effective unfortunately.

 

Like you, I'm on that quest to fully automate MainStage without the need for a 3rd party app.

Link to comment
Share on other sites

This is a good point about tempo changes and I don’t know how mainstage would handle tempo changes in a midi file but I’d try that first. I also don’t know whether the audio playback plugin follows the mainstage metronome. If you have a single tune with tempo changes in it, that might be where mainstage starts to fall short, but it’s worth thinking about.
Link to comment
Share on other sites

Yea so I looked into it a little bit.. tempo changes need to happen with Patch changes. You can configure each patch to have a certain tempo, so change the patches to trigger new tempos. That's about it. If you need tempo changes within a song, then I guess you could use a "Set" for a song and have patches within it for the sections that have different tempo. But I'm not at all sure what the playback plugin would do across those patch changes...might be ok if its in a channel strip at the Set level.

 

You could automate patch changes for a song by sending program changes over IAC back around into Mainstage again. But frankly that sounds kind of fiddly to me. I think if you have some somewhat complex stuff to do with timelines and tempo changes...but off using a different tool frankly. But when i get some time I will try to see if I can hobble something together in Mainstage

 

What I don't know much about is the Playback plugin and how it can sync to the metronome

Link to comment
Share on other sites

Here is a test mainstage concert I put together getting some of the things working mentioned in this thread. In order to use it properly you will need to do the following steps first:

 

  1. Using Apple Audio Midi Setup, create an IAC port, if you don't already have one available.
  2. In Mainstage, select the "Set" called "My Song"
  3. The second channel strip in that set is called "pg sender", set the Midi Output on that channel to the IAC port you created in step 1

 

That's it. Select the My Song Set and Hit play and watch the tempo change and listen to the Apple Loop in the Playback plugin sync to the metronome. Make sure to turn on the metronome to hear the tempo changing. You will also see every bar the patch changes between one of the three patches inside the My Song Set.

 

So what is happening? The "Set" is being used for a song, which has tempo changes in it by using a different patch for each tempo. The Apple Loop is syncing to the metronome, which is why you will hear it speed up and slow down. Program changes are being sent using the Scripter plugin, in this case they are being sent over IAC, which loops around and comes back into Mainstage, which causes the patch to change for each one, once per bar, you can watch it change patches and you will hear the tempo change since each patch has a different tempo set.

 

So there are a few different tricks going on there. Hope it helps someone.

TempoChanges.concert.zip

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