Jump to content

One button for multiple parameters | MainStage 3


YOSSI MOR

Recommended Posts

Hi, I'm wondering whether it is possible to add a button in layout mode to be set for multiple parameters.

for example:

I would like to have a button that will change the send routing with every press.

say I have 4 reverb aux sends: a Room, plate, stage, and a Hall so each press will change it from room to plate and so on in a cycle manner

is it possible? maybe using the scripter plugin? I really don't know how to write a javascript code.

is there any tutorial for it? or maybe a forum with scrip plugin available ?

thank you

Link to comment
Share on other sites

  • David Nahmani changed the title to One button for multiple parameters | MainStage 3

I actually can somewhat imagine a scenario where this could be possible using Scripter; but it would be pretty messy.

I'd be more interested in the general idea behind this problem and if there is possibly another way around this. For example: Is it necessary to switch the Sends? Could it be an option to mute/unmute the Returns instead?

Link to comment
Share on other sites

I'm not familiar enough with MainStage to know if there is a way to do this in MainStage.  in LogicPro you can do this by setting up a TrackStack and putting a smart control on the stack itself...that smart control can then control any plugin within any of the tracks inside that track stack.  Maybe that is possible in MainStage?  In LogicPro this can be done in the environment too, but MainStage doesn't have environment...but it has a lot of menu-driven ways to do similar things as the environment so maybe it can already do it somehow, but I don't know MainStage well enough to suggest any specifics.

Scripter can generally only access the track it is on.  So the only way I can think of would be to create a scripter parameter...(which would be a single button that is controllable from MainStage layout)...but then have it send midi over IAC, which would route back into MainStage..and then you have to convert that midi using smart controls or something into controlling the plugin parameters on each track strip, etc..  That sounds messier to me.  MainStage may have a much more built in way to do it, but I suspect Scripter would not be involved.  However if you get to a point where you decide you need Scripter to do something, by all means ask and I'll be happy to try to help you figure that part out.

Link to comment
Share on other sites

1 minute ago, Dewdman42 said:

So the only way I can think of would be to create a scripter parameter...(which would be a single button that is controllable from MainStage layout)...but then have it send midi over IAC, which would route back into MainStage

That was indeed my thinking; I've done something similar (with Scripter on the concert level) before.

 

 

Link to comment
Share on other sites

12 minutes ago, Dewdman42 said:

if you put scripter on a strip at the concert level, can it find the plugin parameters in the songs below it?

That was actually not my intention. I thought about having four different Sends instead and activating them "round robin". That would be my first approach here.

Link to comment
Share on other sites

Yes, I was working along those lines here.

So far I've done this with two Sends: Create two Buttons and assign them on the Patch level so that each one turns one Send on and the other one off. Easily scalable to four Buttons/Sends.

Next create another button which then goes the detour through the scripter on the concert level and the IAC.This button in turn controls "round robin" the four buttons.

 

Link to comment
Share on other sites

Thank you for the answers, I will try to refine my request.
Sometimes there are a lot of functions that you want to control that you simply don't have enough buttons for them on your controller.
I told myself it could have been very useful if I had a way to control with the help of one knob in my sends.
That is, if I have 4 types of reverb at the concert level when each reverb is on its own aux channel.
And one instrument channel with a piano sound, it could have been really comfortable if I could select with one button the reverb to which I want to send the piano and with the help of the knob I set the sending volume.
Basically the button determines which Send is in focus now and the knob determines how many to send to the same reverb. So I can choose that I want to send 20 percent to the room reverb and 50 percent to the hall reverb and all with the help of one button and one knob

Link to comment
Share on other sites

Ok, so that's a different approach. Am I reading this right, this is about having several sends active simultaneously?

I had done a "proof of concept" implementation of the way I had understood it first (activating a single send and muting all the others). But in general the way you describe it should be possible as well. Not sure if this would work without jumps in values, though.

Link to comment
Share on other sites

Just as a quick update: a "proof of concept" implementation for the new description works; I can hit a button on my xTouch mini and a single encoder controls either the upper or lower send. This could be extended to more sends; all the processing for this is done in Mainstage. It's a bit fiddly to avoid potential MIDI feedback loops though.

 

Link to comment
Share on other sites

 

OK, let's do this step by step in several installments. I'll describe my thoughts and of course invite all kinds of criticism; after all there might be easier ways to accomplish all this.

Our goal for this installment: creating the basic environment; we'll extend and expand this in the future.

What we really need to avoid is MIDI feedback loops so we're not processing all data over and over. So I want a dedicated IAC bus here which we will simply call "Mainstage"; any other name would be fine. We also could use the existing bus but I would like to start with a "clean slate" here.

IAC.jpg.a36709d0a8a0ca11d90e4f8d9c14ddc0.jpg

(I'm using some orange background in Mainstage for better visibility.)

In Layout mode we create a "MIDI Activity" control and assign it to the IAC bus we created:

1212054404_MIDIactivity.thumb.jpg.594aea0f8f05268ebc2b97f1980a9bae.jpg

Next we create a Drum pad and again assign it to the same IAC bus. I set the note it will send to G#0; any other note would be fine as well.

493130901_Drumpad.thumb.jpg.b52a04de5da4ea77bbbf0468aeae3b19.jpg

It's important that all other (existing) controls are mapped to a specific MIDI device, not to "All". For example, my keyboard and its wheel and pedals are all mapped to my "USB Keystation 49e" even though it doesn't have 88 keys.

Let's switch to Edit mode now. The MIDI Activity control should light up when clicking the Drum pad but not when playing any other MIDI controller.

Now let's create an "External Instrument Channel Strip" directly at the Concert Level. You'll get a warning message; just create it anyway.

In the "MIDI Input" part of the Inspector set it again to the IAC port. Add the Scripter as MIDI FX. Leave the MIDI Output empty for now.

544537955_externalInstrument.thumb.jpg.b585d167d5f0a13029947c1b97fb1952.jpg

Open the Scripter plugin and select the "2 - Trace Events" script from "Factory -> Tutorial scripts". Click "Open Script in Editor".

Scripter.jpg.f20ff4ffb627d90abb59731f2e1ecad1.jpg

You'll now see the actual script. Hit "Run Script" the clear the console. Now every time you click the drum pad the MIDI data sent by it is displayed in the console.

45301819_scriptandtrace.jpg.63fe0775bebe806b6703ae0ef2ff79e1.jpg

This concludes this part. I've attached the actual Mainstage concert as well; so basically all that should be done there is to select the proper IAC bus for it to work as described.

All this might sound extremely basic but it's the foundation of things to come. We now have a controller that sends data to the Concert itself; and those data can easily be further manipulated. Stay tuned.

 

Set_1a.concert.zip

Edited by gacki
  • Like 1
  • Love 1
Link to comment
Share on other sites

Part II

Now we want to introduce a counter. We do this with the script attached below. The Concert is the same as in the last part.

Here's the code:

 

var counter = 0;
var maxelements = 4;    // number of elements you want to control

function HandleMIDI(event) {
    
     if (event instanceof NoteOn) {
    
        if (event.pitch >= 0)    {
//        if (event.pitch == 32)    {
                counter++;
                if (counter >= maxelements)
                    counter = 0;
                Trace(counter);
                }
        }
}

 

The line

        if (event.pitch >= 0)

processes notes regardless of the note number; the line

//        if (event.pitch == 32)

processes one single note (the G#0 I specified for the Drum pad in the concert). You can use either one at the moment; in the final script we'll probably stick to just a single note so we could possibly use other notes for different purposes.

Anyway - each time the script receives a note (which comes from the Drum pad we click) it will advance the counter variable and print it to the console. Once the counter reaches the max value as specified in the variable maxelements it will be reset to zero and everything starts anew.

1170954377_scriptandtrace2.jpg.a7b111f50732248b2d075c9f2af88fb7.jpg

You can change the value of the maxelements variable to make the counter go to 2 or 10 or whatever you like.

This concludes this part. We now have a (global) counter that cycles through the values by each press of the Drum pad. Of course that counter doesn't do anything useful yet. But we will build on that in the next part.

Note to Counter round robin.pst

Edited by gacki
  • Love 1
Link to comment
Share on other sites

Part III

This is where we manipulate a controller depending on the counter. I'll add the concert and the script as attachments.

First we add a knob to the concert:

knob.thumb.jpg.e144fea2fff426dd5afe7dd6ad87d310.jpg

The settings don't matter much at all (yet); however we set "MIDI Thru" to "Do not pass through" and "Send value to" to "None", just to be on the safe side.

I'll probably also try this with different controller types later.

Now let's configure the knob on the Concert level.

700103428_knobconf.thumb.jpg.de8c5f0abaad0cea5bb1fc19996ef192.jpg

We set it so that it always sends Controller #21 to our IAC port which means that hopefully the data will make it into our "external instrument" channel strip.

If we use the "2 - Trace Events" script from the Tutorial scripts we can see that the data from the knob makes its way to the Scripter plugin:

995527944_scriptandtrace3.jpg.6481235879e3dde1547edbc72c426dd2.jpg

However we can see multiple identical knob values. This generally seems to happen when operating the knob via mouse; when using an external hardware MIDI controller (which we will do later in this series) it no longer happens.

New script:

 

 

var counter = 0;
var maxelements = 4;    // number of elements you want to control


function HandleMIDI(event) {
    
    Trace(event);
    
    if (event instanceof NoteOn) {

        if (event.pitch >= 0)    {
//        if (event.pitch == 32)    {
                counter++;
                if (counter >= maxelements)
                    counter = 0;
                Trace(counter);
                }
     }          
     else if (event instanceof ControlChange)    {
         if (event.number == 21)    {    // expected controller#
             var cc = new ControlChange;
             cc.channel = 16;
             cc.number = event.number + counter;
             cc.value = event.value;
             cc.send();
             Trace(cc);
         }
         
     }
}

 

I've added another Trace(event); near the top to show the changes happening.

The first part of the script is practically identical to the one from the previous installment: clicking the drum button advances the counter.

The second part modifies the controller.

If we get an incoming controller #21 (and only then!) we set the channel of a new controller variable (cc) to 16.  Then we set the new controller number to the one from the old controller (in this case #21) and add the counter. After this we set the new controller value to the one from the old controller as well. Finally we send the new controller (except that at the moment we're not actually sending it anywhere).

If we've done everything correctly we should get (when moving the knob) either controller #21, #22, #23 or #24 round robin for each click of the drum pad. Since we use the Trace function at various points this should easily be visible:

766275236_scriptandtrace4.jpg.66c66a4ecf418d95be51a6767561aeb5.jpg

And it works! We can see the controller pairs: first the input data which is always on channel 1 and ctrl #21 and below it the modified data which is always on channel 16 and on either #21, #22 or #23 in this screenshot (#24 works as well; I just didn't want to make another screenshot). After #24 it jumps back to #21.

This concludes this part. We now can use a single knob and the drum pad (and of course the Scripter) to create different controllers. But so far we don't use this to actually change parameters. This will be our objective in the next part.

 

 

 

Note to Counter modifying controller.pst Set_1b.concert.zip

Link to comment
Share on other sites

Part IV

Here we're starting to put things together. This is (more or less) the "proof of concept" part which leaves a number of things to be desired. Those will be addressed in a later part.

Let's recap: We've created a counter that is advanced (and reset after a certain number of times) when pressing a drum pad; and we've also re-mapped the knob data depending on the counter. This script is already sufficient for what we're going to do now so we're not going to make any changes this time.

First let's set up a new patch and four effects busses for it. I've used a standard electric piano and four effects that are easily distinguishable. You can do this any way you like.

1077549952_PatchEffects.thumb.jpg.62f5ba3e30819da74afd16b599631137.jpg

Next, we're creating a new knob in the Layout called "Send 1"; we'll leave everything else at the defaults.

1065510564_Send1.thumb.jpg.47bb7bb752c379a974efed6cf3ca5beb.jpg

We duplicate this knob three more times so that we get four knobs for four sends.

Back in Edit mode we assign those four knobs to the Send Levels for the four Sends (shown only for Send 1 here):

69632857_Send1Assign.thumb.jpg.1c061d8a027bb733af4d392ca7e617a8.jpg

At this point it is a good idea to check if everything works as planned: In Performance mode the four new controls should be controlling the send levels for the different effects. If this works we can move on to the final steps (for now).

Back to Layout mode.

The Hardware Input for our first knob needs to be set manually; we can't use the "Assign" function here. Input is the Mainstage IAC Driver, Channel 16; Controller #21.

210042523_Send1Input.jpg.59224d9e7586e147bf8ed496223a02f6.jpg

Send 2 is similarly set but to Controller #22, Send 3 to #23 and Send 4 to #24.

We're almost there.

Back to Edit mode.

In the "External" channel strip with the Scripter we set the MIDI Output to "Mainstage IAC Driver" as well.

1922889167_Ext.StriptoIAC.jpg.e302f5f1237ba7b5b8fe0288fac98bfc.jpg

And that's it!

In Performance mode the large knob now will control one of the four sends, depending on the number of presses on the drum pad. The value will naturally jump to the new value instead of just incrementing/decrementing. I'm still working on this.

Apart from the jumping value there are a couple of other issues:

- It would be nice to see which Send is controlled by the knob. People familiar with Scripter will probably see trivial solutions for this; in fact I had included this in the very first "proof of concept" attempt. I left this out (for now) to build the functionality step by step.

- All this should be controlled by an external controller. This is trivial as well (in fact it's as easy as "learning" the assignments for the Drum pad and the large knob).

So there are a couple of loose ends to tie up. This will happen in another installment.

 

Set_1c.concert.zip

Edited by gacki
Link to comment
Share on other sites

Part V

This is where everything should come together to a usable solution. Unfortunately it is getting a bit messy because now we need to check for many additional things in Scripter.

First: Which Send is currently active for modification?

The solution for this is to use the counter and additional drum pads.

2071273275_sendindicator.thumb.jpg.b8b3fca07a98560ea945e43cdb7a5f0d.jpg

I've created four Drum Pads over the individual sends; assigned again to the Mainstage IAC driver, Channel 16 and note number C-2 ascending.

To avoid a MIDI feedback loop it is crucial the the large Drum Pad (which is used to switch through the sends) uses a different note number; mine uses 32 (G#0). We also need to modify the Scripter code now so only this particular note is essentially triggering the script.

I've tried to break up the script into single functions this time to make everything more readable. More on this in a second.

In Edit mode I've assigned on the Concert level all four new Drum Pads to send the highest note (127) to the Mainstage IAC bus; this is mainly to get rid of the "?" and to get a defined single output. It serves no other purpose. I mainly want to avoid that the data shows up unexpectedly somewhere else.

Important: We're doing this on the Concert level, not on individual patches. So we only have to do this once.

360296038_padassign.thumb.jpg.61a9ae9cfb10a9ad9963889ccfe72141.jpg

And while we're at it we assign similarly the large Drum Pad to G#0.

No let's have a look at the script. I've included a number of Trace functions to show what is happening here.

 

var counter = 0;
var maxelements = 4;	// number of elements you want to control

function TurnOffAllPads(){
			var i = 0;
			
        		while (i < maxelements)	{	// sending Note Off to turn off all four drum pads
//        			Trace (i);
        			var nf = new NoteOn;
        			nf.channel = 16;
        			nf.pitch = i;
        			nf.velocity = 0;
        			nf.send();
        			Trace("Turn off " +nf);
        			i++;
        		}

}

function TurnOnSinglePad(number)	{
			var nn = new NoteOn;
   			nn.channel = 16;
     		nn.pitch = number;
        		nn.velocity = 127;
        		Trace("Turn on " + nn);
        		nn.send();	// turning on the drum pad for the current bus


}

function HandleMIDI(event) {
	
	Trace("incoming " +event);
	
	if (event instanceof NoteOn) { 

        if (event.pitch == 32)	{
			
        		counter++;
        		if (counter >= maxelements)
        			counter = 0;
        		Trace("counter: " + counter);
        		
			TurnOffAllPads();
			TurnOnSinglePad(counter);

        		} 
     }  		
     else if (event instanceof ControlChange)	{
     	if (event.number == 11){	// Controller #11: Expression, sent on Patch change by "dummy" external instrument channel strip
     	// reset display
     		TurnOffAllPads();
			TurnOnSinglePad(0);
			counter = 0;	
     	}
     	else if (event.number == 21)	{	// expected controller#
     		var cc = new ControlChange;
    		 	cc.channel = 16;
     		cc.number = event.number + counter;
     		cc.value = event.value;
     		cc.send();
//     		Trace(cc);
     	}
     	
     }
}

Let's look at the single functions. Many things have stayed the same; I'm not going over them again.

In HandleMIDI(event) we now check for a Note On with the value G#0; all other Note On's are ignored.

 

    Trace("incoming " +event);
    
    if (event instanceof NoteOn) {

        if (event.pitch == 32)    {
            
                counter++;
                if (counter >= maxelements)
                    counter = 0;
                Trace("counter: " + counter);
                
            TurnOffAllPads();
            TurnOnSinglePad(counter);

                }
     }          

The two functions

            TurnOffAllPads();
            TurnOnSinglePad(counter);

are key here. Let's look at the second one.

 

function TurnOnSinglePad(number)    {
            var nn = new NoteOn;
               nn.channel = 16;
             nn.pitch = number;
                nn.velocity = 127;
                Trace("Turn on " + nn);
                nn.send();    // turning on the drum pad for the current bus
}

The function gets the counter (in our case 0 to 3) as parameter and sends a Note on with that particular Note number to the Mainstage IAC bus. This will turn on the Drum Pad atop each Send. That's it.

Of course turning on a Drum Pad will not turn off another Drum Pad by itself. Since I'm a bit lazy I don't want to track which Drum Pad was activated before so I'm simply turning off all of them each time. This is done with the following function:

 

function TurnOffAllPads(){
            var i = 0;
            
                while (i < maxelements)    {    // sending Note Off to turn off all four drum pads
//                    Trace (i);
                    var nf = new NoteOn;
                    nf.channel = 16;
                    nf.pitch = i;
                    nf.velocity = 0;
                    nf.send();
                    Trace("Turn off " +nf);
                    i++;
                }

}

This function will send a Note On with velocity 0 to all Drum Pads, turning them hereby off.

So what the script does now is:

- receive Note On with Note number 32

- increment counter

- turn off all Drum Pads

- turn on Drum Pad that corresponds to the counter

This already works comparatively well, with a couple of exceptions.

script.thumb.jpg.a14d915acfdc7a5614a8cf6739363e38.jpg

 

Before this screenshot Bus 2 was selected; I then pressed the "Sends" Drum Pad once. Let's walk through the Traces for this.

incoming [NoteOn channel:16 pitch:32 [G#0] velocity:100]
counter: 2
Turn off [NoteOn channel:16 pitch:0 [C-2] velocity:0]
Turn off [NoteOn channel:16 pitch:1 [C#-2] velocity:0]
Turn off [NoteOn channel:16 pitch:2 [D-2] velocity:0]
Turn off [NoteOn channel:16 pitch:3 [D#-2] velocity:0]
Turn on [NoteOn channel:16 pitch:2 [D-2] velocity:127]
incoming [NoteOff channel:16 pitch:1 [C#-2] velocity:64]
incoming [NoteOn channel:16 pitch:2 [D-2] velocity:127]
incoming [NoteOff channel:16 pitch:32 [G#0] velocity:0]
>

The first "incoming" event is the Note On coming from pressing the "Sends" Drum Pad.

The counter is incremented to "2".

Now come the four "Turn off" commands.

This is followed by the "Turn On" command for the third Drum Pad which accordingly lights up red.

However now we have to deal with three more incoming events (and this makes it clear why it's so crucial to avoid MIDI feedback loops).

The final "incoming" event is uncritical - this is the "Note Off" from releasing the "Sends" Drum Pad.

incoming [NoteOff channel:16 pitch:1 [C#-2] velocity:64]

This is actually coming from the (previously lit) Drum Pad for Bus 2. It received the "Turn Off" command and consequently put its own "Note Off" on the Mainstage IAC bus.

And finally

incoming [NoteOn channel:16 pitch:2 [D-2] velocity:127]

This is the newly lit Drum Pad for Bus 3. It received its "Turn On" message from the script and consequently put its own Note On on the bus. We can see that this is not a Note On with Note G8 - I simply forgot to assign this one as described above (and didn't feel like making new screen shots). It's corrected in the Mainstage file I've attached.

But there are still some problems.

When starting Mainstage (or re-starting the script) the counter is set to 0 but the first Drum Pad usually isn't lit. Similarly there might be a bit of uncertainty when switching Patches.

I tried to implement this in the Idle() function to no avail.

However there is a simple workaround.

On the Patch level I've created another "external Instrument" Channel strip with no MIDI input; MIDI Output is going to the Mainstage IAC bus, Channel 16. It's essentially a dummy strip (I named it accordingly):

dummy.thumb.jpg.d5f7a0361a44fcf0e55826fd69f0ddff.jpg

Now activate "Send Expression" in the "MIDI Output" tab:

567937424_sendexpression.jpg.077970ddeeccca3913dafebc309292df.jpg

The actual data that is sent does not serve any purpose except resetting the counter and activating the first Drum Pad.

     else if (event instanceof ControlChange)	{
     	if (event.number == 11){	// Controller #11: Expression, sent on Patch change by "dummy" external instrument channel strip
     	// reset display
     		TurnOffAllPads();
			TurnOnSinglePad(0);
			counter = 0;	
     	}

This means that with every Patch change the counter is reset and the first Bus is selected.

And finally: hardware control.

I have isolated the external control from the internal control via the IAC bus to such a degree that it should be possible to merely "learn" the assignments for the "Sends" button and the large knob. In fact I'm using a Behringer xTouch mini to do this and it was non-critical to use different knobs or buttons for hardware control. The functionality always stayed the same.

1812734752_xtouchassign.thumb.jpg.286c87e542c37d17fa205934c21610e9.jpg

For example, here the xTouch mini sends C0 to control the button - but the button itself will always send G#0 to the Scripter plugin because we've mapped him as such on the Concert level.

So this is basically it. There is still the issue of the parameter jumps when switching to a different Send. There are ways around this which I may address in a followup part. But apart from that I consider this a working solution.

As usual I'm open for comments etc.

 

 

 

Set_1d.concert.zip Note to Counter 1d.pst

Link to comment
Share on other sites

  • 1 year later...

 

Sorry, I'm writing through a translator.

Hello; I am full of admiration looking at these possibilities.

I use the X-Touch mini controller and Studiologic SL73 with Mainstage 3.

I would like to make it so that, depending on the layer activated by the button (chanel 1-4), the parameters of the selected instrument change on 4 encoders.

This idea is in Studiologic numa X piano:
https://www.youtube.com/watch?v=a3KKV1wtNzM&t=9s

Is something like this (in a simplified version) possible?

e.g.
Encoders 1-4 are responsible for the volume of the instrument and clicking the encoder activates or deactivates the layer - that's what I've done.

Encoders 5-8 are responsible for adjusting the parameters of the instrument selected using the button under encoder 1-4.

Regards

 

Edited by Marek Michalik
Link to comment
Share on other sites

(I use a translator)

Thank you for your interest. To avoid offtopic, you can move the topic to another thread, but I don't know what to call it and how to do it.

I will wait patiently.

The one-button solution is also great and if only parameter jumps were eliminated, it would be an ideal solution. Maybe this direction is even BETTER 🙂

Regards

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