Presets radio-button for changing from current to another Rackspace/Variation

For my own education in GP scripting, I started to write a script for implementing “presets” radio-button for changing from current to another Rackspace/Variation. The idea is to add a panel of buttons and a script to a set of rackspaces. This is how it looks :

My script works fine until I activate the “SwitchToProgramNumber” option. I have a “doSwitching” Boolean variable for this purpose in the Initialisation section of my script. When “SwitchToProgramNumber” is activated the script starts to live from its own will :grimacing: I added a set of deguging “Print” for better understanding what happens, but I still don’t.

Could someone clarify this behaviour to me ?

Here is the script :

    // Tell GP Script the names of our widgets and FLAGS
var
    MIDIin             : MidiInBlock;
    Button1, Button2   : Widget
    Button1_pushed : Boolean
    Button2_pushed : Boolean
    doSwitching    : Boolean   

//    LedButton          : Widget Array
//    Label              : Widget Array    
//    Button3,Button4,Button5,Button6,Button7,Button8 :Widget
//    Label1,Label2,Label3,Label4,Label5,Label6,Label7,Label8:Widget


initialization

//    OpenLogWindow(); // For convenience

    Print("=== INITIALIZATION ''" + GetRackspaceName() + "'' called ===");
    Print(" ");
    
    // Problems occur when switching is activated :-(
    doSwitching = True; // Do Rackspace/Variation switching
//    doSwitching = False;// Prevent Rackspace/Variation switching
    
    Button1_pushed = False;
    Button2_pushed = False;
    //LedButton = [Button1,Button2,Button3,Button4,Button5,Button6,Button7,Button8]
    //Label  = [Label1,Label2,Label3,Label4,Label5,Label6,Label7,Label8]
    
End


// Called when rackspace is activated

On Activate

   Print("=== ACTIVATE ''" + GetRackspaceName() + "'' called ===");
   Print(" ");

   // Release all buttons
   Button1_pushed = False;
   Button2_pushed = False;

   SetWidgetValue(Button1, 0.0);
   SetWidgetValue(Button2, 0.0);   
   
End


// Called when you switch away from a rackspace
On Deactivate
   Print("=== DEACTIVATE ''" + GetRackspaceName() + "'' called ===");
   Print(" ");

   // Release all buttons
   Button1_pushed = False;
   Button2_pushed = False;

   SetWidgetValue(Button1, 0.0);
   SetWidgetValue(Button2, 0.0);   
End


// Called when you switch variations
On Variation(oldVariation : integer, newVariation : integer)
 
   Print("@@@ VARIATION ''" + GetVariationName(GetCurrentVariation()) + "'' called @@@ (in ''" + GetRackspaceName() + "'')");
   Print(" ");

   // Release all buttons
   Button1_pushed = False;
   Button2_pushed = False;

   SetWidgetValue(Button1, 0.0);
   SetWidgetValue(Button2, 0.0);
   
End

    
// Called when your twist the SLOW_LED_BUTTON widget
On WidgetValueChanged(newValue : double) from Button1

    Print("Button1 callback start ============");
    If (Button1_pushed)
      Then Print("  Button1 ON");
      Else Print("  Button1 OFF");
    End
    If (Button2_pushed)
      Then Print("  Button2 ON");
      Else Print("  Button2 OFF");
    End

    If (!Button1_pushed)
	Then
	    If (newValue == 1.0)
	    Then
		  Print("  Button1 pushed");

		  Button1_pushed = True;   
		  Button2_pushed = False;
		  SetWidgetValue(Button2, 0.0);

		  //SendNow(MIDIin, MakeProgramChangeMessageEx(0,0));//Program, Channel
		  If (doSwitching) Then SwitchToProgramNumber(0,0); End //Program,Bank
	    End
	Else //Button is already pushed
        // with False => keeps out for the moment
	    If (newValue == 0.0)
	    Then
	      Print("  Button1 keeps pushed!!");
		  SetWidgetValue(Button1, 1.0);
		End
    End
    
    
    Print("Button1 callback stop ============");   
    Print(" ");
End

    
// Called when your twist the SLOW_LED_BUTTON widget
On WidgetValueChanged(newValue : double) from Button2

    Print("Button2 callback start ============");
    If (Button1_pushed)
      Then Print("  Button1 ON");
      Else Print("  Button1 OFF");
    End
    If (Button2_pushed)
      Then Print("  Button2 ON");
      Else Print("  Button2 OFF");
    End
  
    If (!Button2_pushed)
	Then
	    If (newValue == 1.0)
	    Then
		  Print("  Button2 pushed");
		  
		  Button2_pushed = True;   
		  Button1_pushed = False;
		  SetWidgetValue(Button1, 0.0);
		  
		  //SendNow(MIDIin, MakeProgramChangeMessageEx(0,0));//Program, Channel
		  If (doSwitching) Then SwitchToProgramNumber(1,0); End//Program,Bank
		End
	Else //Button is already pushed
        // with False => keeps out for the moment        
	    If (newValue == 0.0)
	    Then
	      Print("  Button2 keeps pushed!!");
		  SetWidgetValue(Button2, 1.0);
		End
    End
    Print("Button2 callback stop ============");   
    Print(" ");
End

I’m not in a position to debug your script but I would note that if you’re using buttons to trigger callbacks that change variations, make sure that you check the “Ignore variations” for those buttons otherwise whenever you change variations, those buttons will most likely get changed

Hi,
just to better understand what you want to do…
You have a rackspace with, say eight variations and you intend to switch between these eight variations with a group of eight buttons which should behave like radio buttons?
Do you also want to map these (radio)buttons to some hardware-buttons on your controller?
If so, then i might have an idea of how to achive this, but first answer me please if my assumptions are right. :wink:
Cheers!
Erik

@dhj : I will check this again

@schamass : yes, that’s right. For testing purposes I limited my script to switching between 2 variations in a single rackspace, but the idea is to copy this script and the associated buttons panel to a set of different rackspace. For the moment, I didn’t care about mapping buttons of an external MIDI controller.

Hi David,
it seems that it is trickier than i thought at first, switching between the variations gets me always caught in an endless loop… no idea at the moment, how to prevent this.
I have that dim feeling that i am overlooking something really simple…

Here you are!
Switcher.rackspace.zip (4.0 KB)

This kind of thing really needs to be done from global scripts but unfortunately GP doesn’t (yet) have that capability.

3 Likes

Very Cool !!! Now I have to implement this somewhere :rofl:

@dhj
Thanks for this answer. I am away from my GP piano rig, so I checked your file from my iPhone without testing it with GP.

It seems that you generalized my approach using arrays (what I initially planned to do until I came back to the 2 buttons version for debuging purposes). It is much cleaner! In a way your code seems similar to mine, but you didn’t forbid a user to « pull-out » an already pushed radio button (i.e. switch-off the button). The behavior of my buttons was perfect until I tried to change the Rackspace/Variation.

I also noted that you replaced my SwitchToProgramNumber function by a SwitchVariation. SwitchVariation won’t allow to change to another rackspace, which is one of my goals, but does it do the same within a single rackspace ? (I first wanted to send a Program Change message to my MIDI in, but it surprisingly didn’t work :frowning: )

Please, let me know if you could find some major issue, in my script. Next time I will also attach a full rackspace file. It is easier, I didn’t think about it…

I will test the rackspace file you sent once back at home. Many thanks for your help.

David

:persevere: I could have done it, if i only had found the “ignore variations” option for a widget.
I think, having this not ticked on, makes the whole thing quite difficult (up to impossible).
Well at least i have learned again something important (even if it only was to check the given options more carefully).:sunglasses:
Thanks, Dr. David!:beers:

Sorry - as I mentioned above, I’m not in a position to debug user scripts. But I just put together a quick hack (took me about 2 minutes) to show the way forward. I’m not able to develop perfect finished perfectly working scripts for people.

Of course! And we don’t want you to develop scripts for us.

It is my 7th day if use of GP, and I rather want to learn something to get more autonomy. Perhaps the « ignore variations » is the key as said @schamass ? I will have to check this all…

@dhj Your first advice was the good one! I confirm that checking the “ignore variations” option solves the issue with my script. I can go on working on it, and I can also stop to set all buttons to 0 in all system callbacks.

My presets radio-button are close to work, look at this:

Presets_radio-buttons

Switching between variations within the same rackspace is not a problem. But switching to another rackspace is more tricky. In this case, as there are no global variables shared by the scripts of the different rackspaces, it is difficult to know which preset button is currently pushed when switching to another rackspace (like the existing GetVariationNumber() function, a GetCurrentProgramNumber() function would greatly help for this).
So I decided to store the ID of the current preset button in the value parameter of the first label in the first rackspace. This can be accessed by the scripts of all the different rackspaces using the “external widget” functions.

The last issues I encounter are all related to the initial state of the widget buttons when switching to another rackspace.

  1. The first issue is that, when switching to another rackspace, all the “new value” widget callback functions are automatically called. In my application this is like pushing all the buttons one by one, eventually without knowing their initial states. There is no way to distinguish a button which has been really pushed from one of these “initialization” callback functions.
    There are no “new values”, but only initial values. So are these callback functions really necessary ?

  2. If I could be sure, when these initialization callback functions would occur, I could perhaps come to a strategy to block their first action. But they seem to be called in a random order. Even the rackspace “Activate” callback function is called in the middle the widget button initialization callback functions.
    Is it really logical that the rackspace “Activate” callback function is not the first callback function called ? Or at least the first to be called after all the widget initialization callback functions ?

  3. I came to the conclusion that a solution could be to force all the widget buttons to an initial “0” value when switching to a rackspace. I thought this could be achieved by setting all the widget button properties to:

  • Recall value on load 0.0 (<= I used the “save” button for all the widgets)
  • Also recall on activate
  • Ignore variations (as this works great within the same rackspace)
    And it works… but not all the time, because the “0.0” recall values are sometimes magically replaced by “100.0” while playing and using the preset buttons !!!
    Is there any explanation for this ? Can this be avoided ?
  1. By the way, don’t you think it could be interesting to be able to do some “silent” SetWidgetValue() operations ? (I mean without causing a “new value” callback)

Thanks for the upcoming discussions :wink:

David

I must admit, it have also had some thoughts about not only having a “On WidgetValueChanged()” callback but also something like “On ButtonPushed()” or “On WidgetMoved()”.
But i also see that a callback on the ValueChange is the most versatile function that could be implemented because it works on all sorts of widgets equally.
I also can’t really think of any other use for this quite special function than handling something like radio-buttons…

I didn’t question the WidgetValueChanged() callback function in itself which is perfect.

I am only questioning the way it is automatically called by the system when there is not really a “new value” but an “initial value”. And even, can we speak from an “initial value”, when switching from a rackspace to another one, and then switching back to the former one again ? I understand that, when a rackspace is activated again, widgets have perhaps to send their values to their respective plugins, and perhaps it make also sense to call their respective callback functions too. But then, I would like to have a solution to know that it is the first time a widget callback function is called, such that I can know that it is not really a new value. I could use a flag for each callback function to prevent their first action. But I don’t know where to initialize such a flag each time a rackspace is activated, because the widget callback function can possibly be called before the initialization of its flag.
Of course, I could use external widget label values again to store this flags, but it makes things complicated.

@David-san - the fundamental problem is you’re trying to do something for which GP Script (in its current incarnation) was not designed. Callbacks are asynchronous - there’s no explicit ordering - there’s no concept of “first time” for a widget — when a widget is set to a value (no matter how), you get informed.
Rackspaces are independent of each other and so trying to use one rackspace to “control” another is going to be problematical.
GP Script is going to get a major overhaul over the next year and some of the things you’re trying to do will probably be easier

The futur will be so exiting :wink: But the current possibilities are already very nice :+1:

May I ask you to react to my point 3) regarding the saved “recall values” that are replaced ? If it would’t be the case, my problem would also be solved.

Regards,

David

Just set a variable before you set the widget value and in the callback you can react on that variable.

That’s exactly what I am doing. It works fine, but it makes the source code more complicated and even if I can prevent any action of the callback function, the callback function is called anyway.

You’re probably changing the widget somewhere in your script, which will cause another callback.