Jump to content

Help with Program Change - Mainstage


virag0

Recommended Posts

Hi, I am a long time Logic User but mostly with 6.4.3. Instead I have decided to build my Mavericks platform around the hardware sequencer and Mainstage 3.0.4 acting as MIDI router and performance platfform. I program all my music on the sequencer, send everything to Mainstage and use the Channel Strips to manage audio and so on. What is msising in Mainstage is a performance oriented Program Change utility that I can use with my Hardware Synth. I spend 90% of the GUI with the channel strips even wihen

"performing".

 

I know all about Mainstage Program changes for MIDI and set my defaults up like that. What I want to do now is have a magic

box that has each of my hardware synths in it, that I can select quickly whatever program I want on my synth and do it with a text label.

 

So, for example I will have a box called "Pulse" which is of course a Waldorf Pulse, with 99 patches in it. I would like to be able

to attach text labels to this so I am selecting "Warm Bass", not "47" or whatever.

 

So, I go to the Scripter Plugin, which I am learning about. I have the following script I put together, derived from info on this forum

and the main reason I signed up. I have hacked this script so many times I am annoyed it will not work for me, with Pulse or

any other hardware synth. I have of course tested my MIDI routing and it is impeccable thanks to Mainstage. I can send Program Changes to all my instruments, no worries but not with Scripter.

 

Here is my script, below. It seems no Program Change is sent through the HandleMIDI() function, ever. I have the MIDI monitor

open and watching traffic for Note info (confirmed by trace etc) and although the script reports a Program Change and a little

light flashes on the Pulse to confirm some kind of Activity, no Program Change is ever sent - no PC MIDI message appears in the Monitor at all. But MIDI works fine, prog changes work if I create an Object in Performance edit. All I really want is what Logic has -

select a track and in the sidebar you get a Program/Bank with text fields for the patch names. Mainstage does not do this very

nicely but I thought it would be easy with Scripter. What am I doing wrong?!

 

// Simple program changer so I can have them all floating above the channel strips as I want.
var PluginParameters = [{name:"ProgramChange", type:"menu", defaultValue:3,numberOfSteps:6, valueStrings:['1', '2', '3', '4', '5', '6']}];
   


   function HandleMIDI(event)
   {
   
   if(event instanceof ProgramChange) {
  
     
      event.trace();
      event.send();
         }
   
  else {
  event.trace();
  event.send();        
}

}

function ParameterChanged(param, value)
   {
        var program = GetParameter("ProgramChange");
                 var pc = new ProgramChange;  
      			pc.number = program;
      			 pc.trace();
      			 pc.send();    						
  }  

 

BTW, I thought this was more appropriate for the Scripter forum rather than Mainstage as it has applications for much more...

 

 

rachel

Link to comment
Share on other sites

  1. You don't need to denote numberOfSteps for a menu.
  2. Your HandleMIDI function isn't doing anything other than tracing events.

 

It looks to me like all you're trying to do is change programs when you make a menu selection; is that not happening?

 

This is the way I'd do what I think you're trying to do:

programs = [
{name: 'Warm Bass', number: 47},
{name: 'Cool Bass', number: 48},
{name: 'Frozen Bass', number: 49}
];

PluginParameters = [{name: 'Program', type: 'menu',
valueStrings: programs.map(function(program) { return program.name; })
}];

function ParameterChanged(index, value) {
   var programChange = new ProgramChange;  
   programChange.number = programs[value].number;
   programChange.send();                      
}

Link to comment
Share on other sites

Thanks very much for replying. The HandleMIDI was only tracing and I could confirm I can send any kind of MIDI message with

Scripter except the ProgramChange event. It is just not passing through. Your menu is the perfect solution but it still does not work

with any MIDI synth I have, even a simple one like the Pulse. When I run the MIDI monitor no program changes are seen

to be sent, but the script itself works perfectly. I wonder if this is a bug in the scripter with Mainstage 3.0.4, as your script should

seemingly work just fine?

 

 

rachel

Link to comment
Share on other sites

I think I will do as you suggest. I have spent several hours on this for awhile and got nowhere. My first example was a very stripped down one to demonstrate it is not even parsing program changes. Interestingly, I used the script that runs a MIDI message monitor

after the Program Change script and it shows a MIDI message "programChange" sent through with a Channel and number. If I set it

to hex mode, I get a triple with the final being a 0 in every case. I wonder if that is indicative of the problem? I set one of my synths

to 50 preset and ran the script and it reset it to 0. It would not change after that. The Pulse and MKS50 both show MIDI activity but

no program change is sent. If I set the MIDI channel to another channel, the message is sent but still nothing happens, so control changes, etc all work fine, just not ProgramChange! No PC message is ever shown in the MIDI Monitor, so perhaps the message string is corrupt, so it does not register as a function? I am writing this up here so others can diagnose. I would like to solve this.

If I can have my synth program changes onscreen with the channel strips, that is brilliant. Ideally, it could be like Logic's and

have it set like you can in the sidebar...

 

 

rachel

Link to comment
Share on other sites

I have logged a Bug Report through Mainstage feedback page. I am hoping others on here using hardware synths could

also please test but I have tried a dozen different methods now and I think there is a problem with Scripter doing this in Mainstage.

 

rachel

Link to comment
Share on other sites

  • 7 months later...

Hi there,

I thought I would ressurect this thread, given that now I am on Mainstage 3.1.1 & the ProgramChange function finally works from

Scripter. I have revisited my initial problem which was no way to look at Program Changes in Mainstage with a meaningful name

while in Performance mode. It is fine having a default patch number set in the Channel Strip, but it says nothing to someone who wants to know what Patch is is supposed to be playing and then quickly address changing it, at least for a single bank, so I tried to do something about it.

 

Jessy provided the JavaScript Logic to do what I wanted, but it never worked in Mainstage till now, so since I got all excited and

interested again, I have since worked on my tiny project a bit more. What I needed now, was a way to use the example Jessy gave me to derive a Patch Change for every bit of gear I want to use in my setup. It seems that the Apple implementation of JavaScript in Logic/Mainstage does not support opening or including a file, so I can't just select the instrument I want to use a patch bank for from

a pick list and an array of patch names in a file, so I have instead concoted this ungainly kluge.

 

What it does is takes a MIDNAM XML format document eg exported from a DAW or MIDI Librarian that supports it and extracts the Patch Names & Numbers into a format that is the Javascript array that needs to be loaded by the script. It concatenates this formatted array into a file then appends Jessy's Javascript Program Change script into it, to create a Script specific to a particular synth loaded with a particular bank of patches. This means you generate a unique script for each synth and patch bank you want to control.

In my case, a MicroKorg that sits out of reach and a bunch of rack synths I cannot be bothered getting out of my chair to read the

LCD on.

 

To use this script select and paste it into a file. It only works as a UNIX shell script so on OSX you need to know how to run Terminal.

Paste the script into a file and give it a meaningful name. In my case I keep all my scripts on my Mac in /opt/scripts and I named

it "patchscripter.sh" - it's a bash shell script. Once you have created the file, set the permissions to mode 755 using "chmod". Once

again you need to be just slightly handy with Terminal as I will not explain here.

 

The script takes two arguments. The first is the input file which MUST be an XML "midnam" file. The second is the name to output the

script to. In my case I run it to create the output in /tmp/ then paste that into scripter or copy the file into the scripter presets and load it from there. You will end up with one for each synth/patch bank you run it for so give them different names.

 

Here is the script below, for those who need such a thing and know how to run it:

 

#!/bin/sh
# Patchscripter.sh - a shell script to convert patch names to scripter Program Change numbers utility
# rachel 20150407

IFS=$'\n'

# $1 is the input file, $2 is the output file. You may set a path to the files.

# grab the patch names from the XML file 
midnam=(`sed -n '/<PatchNameList/,/<\/PatchNameList>/p' $1`)

# convert the Patch Names to a Javascript format array
echo "programs = [" > $2
for i in "${midnam[@]}"
       do
       if [[ ${i} =~ PatchNameList ]]
       then
               echo ""
       else
echo $i |awk -F\" '{print "\{" "name: " "\047"$(NF-3)"\047" "\,", "number: " $(NF-1) "\}\," }' >> $2
       fi
done

sed -i '' '$ s/,$//' $2

echo "]; \n" >> $2


# here document - Javascript follows
cat <<EOF >> $2

   PluginParameters = [{name: 'Program', type: 'menu',
      valueStrings: programs.map(function(program) { return program.name; })
   }];

   function ParameterChanged(index, value) {
       var programChange = new ProgramChange;
       programChange.number = programs[value].number;
       programChange.send();
   }

EOF

# a program change script is created

 

I will update this version with a picklist for the MIDI channel - Scripter ignores the channel strip's MIDI channel and defaults to Ch1.

But for now, if you have a tool that exports patch names, give this a go and let me know... Thanks to Jessy for the original JS script

which I banged my head on for weeks trying to get work but alas a bug in Mainstage....

 

 

rachel

Link to comment
Share on other sites

Here is the same thing with MIDI Channel setting. This has been tested with all my racksynths now and it works fine.

 

#!/bin/sh 

IFS=$'\n'

midnam=(`sed -n '/<PatchNameList/,/<\/PatchNameList>/p' $1`)

echo "programs = [" > $2
for i in "${midnam[@]}"
do
if [[ ${i} =~ PatchNameList ]]
then
	echo ""
else
echo $i |awk -F\" '{print "\{" "name: " "\047"$(NF-3)"\047" "\,", "number: " $(NF-1) "\}\," }' >> $2
fi
done

sed -i '' '$ s/,$//' $2

echo "]; \n" >> $2


# here 
cat <<EOF >> $2

 PluginParameters = [{name: 'Program', type: 'menu',
      valueStrings: programs.map(function(program) { return program.name; })
   },
                    {name: 'MIDI Channel',    		 
      minValue:1, maxValue:16, defaultValue:1, numberOfSteps:15, type:'lin'}
   ];



   function ParameterChanged(index, value) {
       var programChange = new ProgramChange; 
       var channel = GetParameter("MIDI Channel");
       programChange.channel = channel;
       programChange.number = programs[value].number;
       programChange.send();
//      programChange.trace();               
   }

EOF

 

This really useful, at least for me, as Mainstage does not have a method for this, unlike Logic which can display the current patch in the sidebar. It does not seem to demonstrate any CPU overhead with several instances. However, it does use the MIDI slot in the

channel strip, so it does not seem they are "stackable".

 

 

rachel

Link to comment
Share on other sites

Hi Jordi,

thanks for that. I did not see the visual cue until pointed out.

 

Here is an updated version of my script. It shows the patch number along with the patch name, plus improved the MIDI channel

setting as it would sometimes change the patch as well.

 

#!/bin/sh 

IFS=$'\n'

midnam=(`sed -n '/<PatchNameList/,/<\/PatchNameList>/p' $1`)

echo "programs = [" > $2
for i in "${midnam[@]}"
do
if [[ ${i} =~ PatchNameList ]]
then
	echo ""
else
echo $i |awk -F\" '{print "\{" "name: " "\047"$(NF-3)"\047" "\,", "number: " $(NF-1) "\}\," }' >> $2
fi
done

sed -i '' '$ s/,$//' $2

echo "]; \n" >> $2


# here 
cat <<EOF >> $2

var programChange = new ProgramChange;

var  PluginParameters = [{name: 'Program', type: 'menu', defaultValue: 1, valueStrings: programs.map(function(program) 
                                                                 { return program.name+'\t\t\t\t\t\t\t\t\t\t\t'+program.number; }) },        
                        {name: "Channel", minValue:1, maxValue:16, defaultValue:1, numberOfSteps:15, type:'lin'}, 
                       ];
          
   function ParameterChanged(index, value) {

    if (index == 0) {        
                     programChange.number = programs[value].number;
                     programChange.send();
                     }
           
    if (index == 1) { 
                      var chan =    GetParameter('Channel');
                      programChange.channel = chan;
                     }
           
            programChange.trace(); 
                       
   }


EOF

 

If anyone is using this or wants some minor changes, I will see what I can do, but it would be nice to know if this is helpful to

anyone apart from myself....

 

 

 

rachel

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