Help Make my Script more compact?

Hi scripters! I just got going with scripting and I’m loving it, despite my very old, out of date, and never-very-advanced coding skills. Here’s my issue: In trying to free up some screen real estate on my iPad (using it as a control surface to control GP via TouchOSC), I decided to get rid of all my ‘return from fx’ faders, since I really only need 2 settings, full on, or off, but I need the ‘off’ to happen as a long slow fade out. Hence, I borrowed from @pianopaul and @tonycore’s lovely existing fade-out scripts that they shared here, and slightly modified it for my own needs. So far, so good, it works exactly as intended! (Thanks for sharing those scripts, guys!). The only problem is, I have 16 instances of this that I need, and I’ve been struggling to figure out a way to make the code elegant and compact so that I can avoid simply copying and pasting 16 times (with appropriate variables) to get it to work across all 16 channels. I tried my best to apply arrays and then index into them using for loops, but I just can’t get it to work. I’m a terrible programmer, but I think I know enough to know that there has to be a way to do this - maybe using a custom function??? I’ll post here what I have so far, which is working fine, which is the first 3 iterations (using the old copy-paste method). I was at least able to save a little space by using arrays and indexing in the ‘initialization’ section. But I can’t figure out how to do something similar in the callback and time-passing sections. Any help or suggestion would be greatly appreciated! TIA.
Here’s the code, sorry it’s long but that’s what I’m trying to solve. This code compiles and runs perfectly, and as I said I could keep copy-pasting out to 16, but if there’s a cleaner, more compact way, I’d prefer it (and I’ll learn something for future scripts, hopefully this helps others learn as well):

Var
    ReturnFaderFX1, ReturnFaderFX2, ReturnFaderFX3 : Widget       // FX return fader. which will be moved by ramp function
    ReturnFaderFX : Widget Array = [ReturnFaderFX1, ReturnFaderFX2, ReturnFaderFX3]    
    FadeOutButtonFX1, FadeOutButtonFX2, FadeOutButtonFX3 : Widget // FX return fader fade out button, to be used to trigger fade out slowly (on), and reset to full volume (off)
    FadeOutButtonFX : Widget Array = [FadeOutButtonFX1, FadeOutButtonFX2, FadeOutButtonFX3]
    BypassButtonFX1, BypassButtonFX2, BypassButtonFX3 : Widget    // FX Bypass Button
    BypassButtonFX : Widget Array = [BypassButtonFX1, BypassButtonFX2, BypassButtonFX3]
    myRamp1, myRamp2, myRamp3 : Ramp                              // A generator that moves smoothly from 0.0 to 1.0 over some specified time
    Ramps : Ramp Array = [myRamp1, myRamp2, myRamp3]
    StartValue1, StartValue2, StartValue3 : double                // This remembers the initial value of the fader so that when we start again
                                                                  // the fader will be reset to this value
    StartValue : double Array = [StartValue1, StartValue2, StartValue3]
    Running1, Running2, Running3 : Boolean                        // Keep track of whether we are currently running the ramp
    Running : Boolean Array = [Running1, Running2, Running3]
    i : integer

initialization
    For i = 0; i < 3; i = i + 1 Do
        SetGeneratorOneShot(Ramps[i], true)  // Generator will only run once when triggered         
        SetGeneratorLength(Ramps[i], 10000); // 10 seconds
        Running[i] = false // When we start up, the ramp is not running
        
    End
end




// 1) This callback will be triggered only when the FadeOutButtonFX1 is engaged, 'on' will fade out, 'off' will return to preset default level
On WidgetValueChanged (newValue : Double) from FadeOutButtonFX1
    If not Running1
        then
            StartValue1 := GetWidgetValue(ReturnFaderFX1) // Get the initial level of the fader (NB make sure it's not already 0)
                                                          // otherwise nothing will happen
            Running1 = true                               // Remember that we are now running the ramp
            EnableGenerator(myRamp1,true)                 // Arm the ramp function generator
            SetTimersRunning(true)                        // The ramp function generator will now start producing values
        else
            SetWidgetValue(ReturnFaderFX1, StartValue1)   // If we were running then reset the fader to the default level again
            Running1 = false                              // and remember that we are now NOT running
            SetWidgetValue(BypassButtonFX1, 0)            // Once we reset the fader to default level, we 'unbypass' the plugin, ready to start fresh
    End
End

// 1) This gets called by the ramp generator as time passes
On TimePassing(timeX : integer, amplitudeY : double) from myRamp1
    if Running1 
        then
             // The amplitude of the ramp goes from 0.0 to 1.0 so if we multiply that amplitude
             // by the INITIAL start value of the knob, we generate a value that gets closer to the
             // actual StartValue over time
             // Therefore, subtracting that from the initial StartValue causes the
             // the actual value to reduce down to zero
             // Hence the knob slowly reduces to 0
            SetWidgetValue(ReturnFaderFX1, StartValue1 - StartValue1 * amplitudeY)   
            if GetWidgetValue(ReturnFaderFX1) < 0.01 then
            SetWidgetValue(BypassButtonFX1, 100) //Once fader goes to zero, we bypass the plugin to 'clear' out any lingering sound before resetting to default level     
            end
    end
End

// 2) This callback will be triggered only when the FadeOutButtonFX2 is engaged, 'on' will fade out, 'off' will return to preset default level
On WidgetValueChanged (newValue : Double) from FadeOutButtonFX2
    If not Running2
        then
            StartValue2 := GetWidgetValue(ReturnFaderFX2) // Get the initial level of the fader (NB make sure it's not already 0)
                                                          // otherwise nothing will happen
            Running2 = true                               // Remember that we are now running the ramp
            EnableGenerator(myRamp2,true)                 // Arm the ramp function generator
            SetTimersRunning(true)                        // The ramp function generator will now start producing values
        else
            SetWidgetValue(ReturnFaderFX2, StartValue2)   // If we were running then reset the fader to the default level again
            Running2 = false                              // and remember that we are now NOT running
            SetWidgetValue(BypassButtonFX2, 0)            // Once we reset the fader to default level, we 'unbypass' the plugin, ready to start fresh
    End
End

// 2) This gets called by the ramp generator as time passes
On TimePassing(timeX : integer, amplitudeY : double) from myRamp2
    if Running2 
        then
             // The amplitude of the ramp goes from 0.0 to 1.0 so if we multiply that amplitude
             // by the INITIAL start value of the knob, we generate a value that gets closer to the
             // actual StartValue over time
             // Therefore, subtracting that from the initial StartValue causes the
             // the actual value to reduce down to zero
             // Hence the knob slowly reduces to 0
            SetWidgetValue(ReturnFaderFX2, StartValue2 - StartValue2 * amplitudeY)   
            if GetWidgetValue(ReturnFaderFX2) < 0.01 then
            SetWidgetValue(BypassButtonFX2, 100) //Once fader goes to zero, we bypass the plugin to 'clear' out any lingering sound before resetting to default level     
            end
    end
End

// 3) This callback will be triggered only when the FadeOutButtonFX3 is engaged, 'on' will fade out, 'off' will return to preset default level
On WidgetValueChanged (newValue : Double) from FadeOutButtonFX3
    If not Running3
        then
            StartValue3 := GetWidgetValue(ReturnFaderFX3) // Get the initial level of the fader (NB make sure it's not already 0)
                                                          // otherwise nothing will happen
            Running3 = true                               // Remember that we are now running the ramp
            EnableGenerator(myRamp3,true)                 // Arm the ramp function generator
            SetTimersRunning(true)                        // The ramp function generator will now start producing values
        else
            SetWidgetValue(ReturnFaderFX3, StartValue3)   // If we were running then reset the fader to the default level again
            Running3 = false                              // and remember that we are now NOT running
            SetWidgetValue(BypassButtonFX3, 0)            // Once we reset the fader to default level, we 'unbypass' the plugin, ready to start fresh
    End
End

// 3) This gets called by the ramp generator as time passes
On TimePassing(timeX : integer, amplitudeY : double) from myRamp3
    if Running3 
        then
             // The amplitude of the ramp goes from 0.0 to 1.0 so if we multiply that amplitude
             // by the INITIAL start value of the knob, we generate a value that gets closer to the
             // actual StartValue over time
             // Therefore, subtracting that from the initial StartValue causes the
             // the actual value to reduce down to zero
             // Hence the knob slowly reduces to 0
            SetWidgetValue(ReturnFaderFX3, StartValue3 - StartValue3 * amplitudeY)   
            if GetWidgetValue(ReturnFaderFX3) < 0.01 then
            SetWidgetValue(BypassButtonFX3, 100) //Once fader goes to zero, we bypass the plugin to 'clear' out any lingering sound before resetting to default level     
            end
    end
End



Are all 16 of the faders moving at the same time, or will it be random as to which you need to fade out?

Hi @joebot, could you also post the gig file which makes use of this GPScript, it is easier to compile it and play with it to answer you question. :nerd_face:

1 Like

It will be random, each moving individually, whenever I need to (slowly) mute or turn back on that individual channel.

@joebot:

Since you already have bundled all the relevant variables and widgets in corresponding arrays with common size, you could create a user function (i called it “DoFading(i:integer)”) using the arrays instead of the particular variables… so in each callback for widget changes you would only call your function and just deliver the array index which shall be handled…
(I haven’t tried if this actually works… not at my own PC at the moment, but the concept should be clear…)

Function DoFading(i:integer)
If not Running[i]
        then
            StartValue[i] := GetWidgetValue(ReturnFaderFX[i]) 
            Running[i] = true                               // Remember that we are now running the ramp
            EnableGenerator(Ramps[i],true)                 // Arm the ramp function generator
            SetTimersRunning(true)                        // The ramp function generator will now start producing values
        else
            SetWidgetValue(ReturnFaderFX[i], StartValue[i])   // If we were running then reset the fader to the default level again
            Running[i] = false                              // and remember that we are now NOT running
            SetWidgetValue(BypassButtonFX[i], 0)            
    End
End

Then in each WidgetValueChanged callback you would just write

DoFading(1)

This would shorten the script by some lines…

YES!!! This makes perfect sense, thank you so much. (I don’t know why functions are so elusive to me - once someone shows me how to do it, it seems so obvious, but my brain just doesn’t seem to have that missing piece). It seems I could do something similar for the TImePassing section as well, place the ‘if/then’ statement inside the function (using the arrays as you did), and then just call that function by its index number. It does make me wonder: would it be possible to put the whole callback inside the function, not just the if/then statement? I’m not in the studio, but will try all of the above later and report back. Many thanks!!!

1 Like

Oh, sure… the TimePassing part could also be put in a user function… i’ve completely missed that part. :smiley:
I’m not sure if it was better to have it in it’s own function or if it also could be combined with the fading part function… that’s something you’d have to try.

EDIT: As far as i know, a callback always has to stand by it’s own… it won’t work within a function.

Well @schamass I finally tried this and unfortunately I can’t get it to work. Not sure why. I did my primitive troubleshooting by putting print statements everywhere, and as far as I can tell, when you call the function and pass an integer argument to it such as DoFading(0), the Boolean array (Running) and the Ramp array (Ramps) don’t seem to be able to pick up this integer and use it as an index number to index into the array. I’m using what I believe is the standard indexing syntax, as you used it: Running[x], Ramps[x] etc. But only the Widget and Double arrays seems to actually be ‘indexible’ if that makes sense. I tried everything I can think of, and I’m stuck :frowning_face:

I won’t be able to check this before tomorrow evening or maybe even Saturday, so maybe someone else might help you with this, if it’s urgent …
One thing to try: Use another variable name instead of “i” because this is already used in the global variables. I’m not sure if this could cause strange side effects…
Edit: And make sure that the user function is standing at first place, right after the “var” block!

Thanks for all your help, @schamass
I did indeed change the variable name already for the reason you mentioned. I also moved the function to right after the Var block per your suggestion. Same results, not working.
If you get a chance over the weekend to have a look, please do. It’s not urgent - I can always make it work the long way.

1 Like

Again, the easiest way for other GPScripter to test your GPScript is to use a gig file where the many widgets handle names you used are already defined… :nerd_face:

1 Like

OK, i got it running when stuffed both, the “On WidgetValueChanged” and the “On TimePassing” code into their own functions and hence had to make a stringent use of the Arrays, and made no more mixed use of the Array’s index and the corresponding single variables…
BTW: I also used the new “On WidgetValueChanged” version for multiple widgets which again shortens the code by some lines! :wink:
Anyway… here is the working code:


Var
    ReturnFaderFX1, ReturnFaderFX2, ReturnFaderFX3 : Widget       // FX return fader. which will be moved by ramp function
    ReturnFaderFX : Widget Array = [ReturnFaderFX1, ReturnFaderFX2, ReturnFaderFX3]    
    
    FadeOutButtonFX1, FadeOutButtonFX2, FadeOutButtonFX3 : Widget // FX return fader fade out button, to be used to trigger fade out slowly (on), and reset to full volume (off)
    FadeOutButtonFX : Widget Array = [FadeOutButtonFX1, FadeOutButtonFX2, FadeOutButtonFX3]
    
    BypassButtonFX1, BypassButtonFX2, BypassButtonFX3 : Widget    // FX Bypass Button
    BypassButtonFX : Widget Array = [BypassButtonFX1, BypassButtonFX2, BypassButtonFX3]
    
    myRamp1, myRamp2, myRamp3 : Ramp                              // A generator that moves smoothly from 0.0 to 1.0 over some specified time
    Ramps : Ramp Array = [myRamp1, myRamp2, myRamp3]
    
    StartValue1, StartValue2, StartValue3 : double                // This remembers the initial value of the fader so that when we start again the fader will be reset to this value
    StartValue : double Array = [StartValue1, StartValue2, StartValue3]
    
    Running1, Running2, Running3 : Boolean                        // Keep track of whether we are currently running the ramp
    Running : Boolean Array = [Running1, Running2, Running3]


Function SetFading (Ai : integer) //User function to initiate a fade-out per Array index
If not Running[Ai]
        then
            StartValue[Ai] = GetWidgetValue(ReturnFaderFX[Ai]) // Get the initial level of the fader (NB make sure it's not already 0)
                                                          // otherwise nothing will happen
            Running[Ai] = true                               // Remember that we are now running the ramp
            EnableGenerator(Ramps[Ai],true)                 // Arm the ramp function generator
            SetTimersRunning(true)                        // The ramp function generator will now start producing values
        else
            SetWidgetValue(ReturnFaderFX[Ai], StartValue[Ai])   // If we were running then reset the fader to the default level again
            Running[Ai] = false                              // and remember that we are now NOT running
            SetWidgetValue(BypassButtonFX[Ai], 0)            // Once we reset the fader to default level, we 'unbypass' the plugin, ready to start fresh
    End
End

Function DoFading (Ai: integer, AmpY : double) //User function to move the widget during fade-out per Array index
if Running[Ai] 
        then
             // The amplitude of the ramp goes from 0.0 to 1.0 so if we multiply that amplitude
             // by the INITIAL start value of the knob, we generate a value that gets closer to the
             // actual StartValue over time
             // Therefore, subtracting that from the initial StartValue causes the
             // the actual value to reduce down to zero
             // Hence the knob slowly reduces to 0
            SetWidgetValue(ReturnFaderFX[Ai], StartValue[Ai] - (StartValue[Ai] * AmpY))   
            if GetWidgetValue(ReturnFaderFX[Ai]) < 0.01 then
                SetWidgetValue(BypassButtonFX[Ai], 100) //Once fader goes to zero, we bypass the plugin to 'clear' out any lingering sound before resetting to default level     
            end
    end
End


initialization
Var
i : integer

    For i = 0; i < 3; i = i + 1 Do
        SetGeneratorOneShot(Ramps[i], true)  // Generator will only run once when triggered         
        SetGeneratorLength(Ramps[i], 10000); // 10 seconds
        Running[i] = false // When we start up, the ramp is not running
        StartValue[i] = GetWidgetValue(ReturnFaderFX[i])
        
    End
end

// Called when any of several widgets changed
// The widget and index parameters are optional
// 1) This callback will be triggered only when the FadeOutButtonFX[index] is engaged, 'on' will fade out, 'off' will return to preset default level
On WidgetValueChanged(w : Widget, index: integer, newValue : double) from FadeOutButtonFX1, FadeOutButtonFX2, FadeOutButtonFX3
    SetFading (index)
End


// 1) This gets called by the ramp generator as time passes
On TimePassing(timeX : integer, amplitudeY : double) from myRamp1
    DoFading (0,amplitudeY)
End


// 2) This gets called by the ramp generator as time passes
On TimePassing(timeX : integer, amplitudeY : double) from myRamp2
    DoFading (1,amplitudeY)
End


// 3) This gets called by the ramp generator as time passes
On TimePassing(timeX : integer, amplitudeY : double) from myRamp3
    DoFading (2,amplitudeY)
End

And also an according gig file, so that all the forum members have something to study and to play with…
fade-out.gig (121.6 KB)

(@joebot you had been asked twice to upload yours, but didn’t do… why? this would have been so helpful) :beers:

3 Likes

Just for clarity, a callback and a function are technically similar, the only semantic difference is that a callback is invoked by the runtime system whereas a function is invoked by a user.

Some languages don’t distinguish between the two which leads to all sorts of issues, i.e. you can’t look at a function and determine from it whether it’s something you call or something that the runtime system calls.

That is why I use On … for callbacks and Function … for functions. You get extra clarity as you can see who calls the entity.

Of course, because the compiler can distinguish between those things, that’s what allows those extra constraints such as matching, etc

1 Like

Hey @schamass!!!

  1. first of all, I apologize, yes of course I should have uploaded my gig file. I got caught up trying to solve the coding problem, and was lost in the maze of my own incompetence as a coder and simply forgot to upload it. Then I went away for 3 days to the mountains with no internet (highly recommended, btw!), and I just got back. So, again, I’m sorry, that was poor forum etiquette of me, will always upload my gig file first thing from now on. Now that you’ve uploaded yours, it’s not necessary as yours is much cleaner as a teaching tool for others to study and play with, as you said. But it should not have been your task to recreate my faders and buttons with the appropriate names. I owe you many beers for this! Many many thanks, really.
  2. It works! So thank you for that as well.
  3. I wish I could say I understand why it works now, but it didn’t before. The only thing I can see that is different (besides the ‘new “On WidgetValueChanged” version for multiple widgets’ as you pointed out) is that you have a) declared the variable ‘I’ inside the Initialization block rather than in the Var block, and b) added a function for the OnTimePassing code that takes the same ‘Ai’ variable as the original fading function. Were both of these steps necessary to get it to work? Is it possible to explain to an idiot like me why this made a difference??
  4. Regarding the OnWidgetValueChanged block, when you list out the widget names in order after the ‘from’ clause, then pass (index) to the function, does this essentially mean that a new array is automatically being created by the list of widgets after the ‘from’ clause? Just trying to fully grasp everything that you’ve done here. I see this described in the manual, I’m just trying to clarify how it works.
  5. You may have noticed that whenever you load up the gig file, or flip to a different Rackspace and back again, the On WidgetValueChanged callback is triggered, and the faders start to move. Presumably, no matter what setting you have for the widget values ‘Initial value on gig load(Default)’, it sends out a value event, which is received by the callback. Is there any way around this? It’s not the end of the world, but it does mean to get to the non-faded out position (which is where one generally wants to start from), I have to click all the widget buttons to return the faders to their un-faded positions. There doesn’t seem to be a ‘matching’ value parameter to use here (as there is with the On NoteEvent callback), so there doesn’t seem to be a way to constrain the callback to just the On or Off position of the buttons…
    Anyway - thanks again for all the time you put into this. It’s VERY much appreciated.
1 Like
  1. No biggie… i just wondered. So, if i had the choice to be in nature or in the forum, i’d go hiking too. Hope you had a nice trip
  2. Good to know. :+1:
  3. I noticed that if everything was based on arrays, it worked. Therefore i had to put the OnTimePassing stuff into its own function, so that i could use arrays and the corresponding index number. The diffrence between declaring a variable in the “var” block or within a function is that the definition in the “var” block makes it a “global” variable (is available in the whole script without further definition), but a definition within a function makes it “local” (only available within this particular function block).
    So, theoretically i could have used “i” in all the function blocks as it’s always a local variable - nothing that has to be seen outside of its own function. But i decided the “Ai” (like ArrayIndex) would be a better choice for its purpose (i also could have named it “Martha”… wouldn’t make a diffrence :wink: )
    Maybe my question about Arrays in this sub forum (i also needed to have some clarification) might help you understand the issue we faced by mixing the separate variables and the arrays (of which i thought they would point to the varaibles that we used to define them - but they actually don’t):
    Understanding Arrays - #3 by schamass
  4. Yes, that’s right… the names after the “from” are used to identify the widgets to be “listened to” and the one that’s been triggered can then be used by its name (parameter “widget”) or by its index from the names-row (parameter “index”).
  5. Hm… that’s something i’d have to have a closer look at…
    Some options i can spontaniously think of…
    You could try to only call the SetFading() if the according widget gets switched “ON” (newValue >0.5), so if it changes its state by being switched OFF, nothing will happen.
    You could experiment with the “default value” of the widget’s properties
    Or you could use another set of variables to store the starting values on initialization, but which you don’t change anymore within the code, so you’d always have a “fallback”. This could then be re-written to the widgets each time for “On Activation” of the rackspace (whenever you activate it).
    Or an additional set of widgets which would only represent the starting values and a separate widget/function to store the actual state to them, and then “On Activation” the values of the “buffer widgets” would be transferred to the “real ones”- that way you could change things on the fly too.

Uuuuf when the solution is pointed out, it’s always so painfully obvious that it hurts. I was not born to be a coder, sadly. Your instincts are of course spot on w/r/t question 5 - one simple line of code fixes the ‘starts to fade on gig load or Rackspace return’ problem. Just add that value check with an if statement in the first function:

Function SetFading (Ai : integer) //User function to initiate a fade-out per Array index
If not Running[Ai]
        then
            StartValue[Ai] = GetWidgetValue(ReturnFaderFX[Ai]) // Get the initial level of the fader (NB make sure it's not already 0)
                                                          // otherwise nothing will happen
            if GetWidgetValue(FadeOutButtonFX[Ai]) > 0.5 then                                              
            Running[Ai] = true                               // Remember that we are now running the ramp
            EnableGenerator(Ramps[Ai],true)                 // Arm the ramp function generator
            SetTimersRunning(true)                        // The ramp function generator will now start producing values
            End
        else
            SetWidgetValue(ReturnFaderFX[Ai], StartValue[Ai])   // If we were running then reset the fader to the default level again
            Running[Ai] = false                              // and remember that we are now NOT running
            SetWidgetValue(BypassButtonFX[Ai], 0)            // Once we reset the fader to default level, we 'unbypass' the plugin, ready to start fresh
    End
End

Ok, great if that solved the problem - BUT… :grin: :nerd_face:

…but you better should have placed the IF clause right into the "On WidgetValueChanged()" callback.
Like this:

On WidgetValueChanged(w : Widget, index: integer, newValue : double) from FadeOutButtonFX1, FadeOutButtonFX2, FadeOutButtonFX3
    If newValue >0.6 Then
          SetFading (index)
    end
End

That way you wouldn’t have to call the "SetFading()" function at all if the regarding switch-widget isn’t actually changing to ON. For an “OFF-change”, it would just do nothing and then wait for the next event to happen.

The way you did it,

  • the SetFading() function is called on each change of the trigger-widget
    (no matter if going ON or OFF),
  • on every call (ON or OFF) there will be a test for the Running[Ai] boolean,
  • if TRUE then you would fetch the widget’s value and store it into a variable…

and first then, after all those steps, you are going to test if the function should continue to run or not by checking if the trigger button was switched ON.
If not, all those steps were made without any needs.

And maybe (one day) you would like to do something completely diffrent than calling "SetFading()" if the widget was going to be switched from ON to OFF, then your IF clause in the SetFading() function was definitely at the wrong place at last.

This is more elegant and less steps, BUT there’s one problem: it basically invalidates the Else clause inside the SetFading function. Remember, it’s all triggered by an on/off toggle button widget, and the way that whole if/else clause works is we want one toggle (let’s say ‘on’) to trigger the fade, and the other toggle, ‘off’, to trigger the return to full volume with bypass restored. So if we only call the function when the widget sends out it’s ‘on’ value (100), the Else clause doesn’t work. well, it works with 3 additional button presses :slight_smile:
Now, I suppose I could move that Else code to it’s own function, maybe called DoReset, where it becomes an If clause, and then I could do an if/else inside the On WidgetValueChange callback…
That would be taking the spirit of what you are saying - which is, always make it more elegant (fewer lines of code, less processing at runtime is always better). I will report back!

And…I failed. The beauty of the original fade-out code that I borrowed from @pianopaul is that it stores the fader’s original position (StartValue) so that it can reset to that when needed later. And by having the fade out and the reset in the same function, we can use the same Array index variable (StartValue[Ai] is in both the Then clause and Else clause). If you try to split out the SetFading function into 2 separate functions, you lose the ability to check that initial fader value, store it, and reset to it later. I’m sure there’s a way to do it, but it seems you would need to pass a value between functions. A global variable, maybe?

Having read this twice i tend to think that there might be something “special” about your rackspace version which i can’t grip… so please upload the gig- or rackspace file where this happens, then we might have the chance to see what’s actually going on.
Thanks in advance for helping us to help you. :wink:

2 Likes