Jump to content

defaultValue not working


Danny Wyatt

Recommended Posts

Parameters

 

so first you have to realize something about all plugins in general. All plugins have a concept known as "Parameters". Parameters are data connectors that plugins expose to the host so that the host DAW can set them and automate them. Every plugin you have ever used has a list of parameters, which may or may not even be displayed by the plugin's actual GUI. The plugin Window in LogicPro has a way to view those parameters are raw sliders. Here is the Pianoteq7 plugin parameter list for example:

 

1344934986_ScreenShot2022-02-15at10_35_23AM.thumb.jpg.766b51216c017da49172a3285cde00e3.jpg

 

Likewise if you open the automation list for that plugin you will see the same list of "parameters", which are all automatable:

 

340315634_ScreenShot2022-02-15at10_36_55AM.thumb.jpg.03cd7b8435e675083aa52a737d0fc074.jpg

 

Scripter Parameters

 

Like all good plugins, the Scripter plugin has the ability to expose parameters to the host DAW, except that we are able to modify what that list of parameters will be by using the PluginParameters array.

 

var PluginParameters = [];

PluginParameters.push({
  name: "TestParam",
  type: "lin",
  minValue: 0,
  maxValue: 127,
  numberOfSteps: 127
});

 

1275670191_ScreenShot2022-02-15at10_44_12AM.thumb.jpg.b09f4e7c28360fcfe976c82eee2a544e.jpg

 

The Scripter plugin does not have a custom GUI like most plugins, it simply displays the same "control" GUI that you can select for other plugins if you want using the View menu. Note that the Scripter plugin window does not have a way to change that. What we see on the Scripter GUI is basically the raw basic list of plugin parameters....and we can edit the values of those parameters, the same way you can edit plugin parameters of other plugins when in "control" mode (as shown above)

 

So the point to make here is that the PluginParameters array is not really a "GUI" creation paradigm per say, its simply a parameter list definition paradigm...and LogicPro happens to provide a way for any plugin to display all the parameters in a list, which we see above.

 

What are Plugin Parameter really then?

 

Plugin Parameters are the mechanism by which all plugins communicate various non-audio and non-midi data with the host DAW. This is how automation works. Its also how you can setup a plugin, set a bunch of things in the GUI, program your FX or synth for example, and then when you save the host DAW project, the current settings of those parameters are saved with the project. That way when you load the project later, not only is the plugin loaded into the track, but the last "settings" you had set will also be reloaded into the plugin. Those settings are basically those Parameter values as they were at the time you saved the project. When you save a plugin "preset", that is also basically saving those parameter values as a preset, so that you can load the plugin and load a particular preset, which loads the list of parameter data values at the time it was saved.

 

By convention, nearly all plugins follow this pattern of using the Parameter list to stash certain kinds of data that you want the DAW to be able to interact with, and also by convention plugins when reloaded in a saved project will read the list of parameter values that the host DAW is remembering, restoring the plugin to the last state it was in. When you load a plugin the first time, it starts with a clean slate or perhaps some default values.

 

What does Scripter do?

 

So this is what happens with Scripter. When you first load a new script into Scripter, it will construct a list of Parameters if you have defined the PluginParameters array. And while it is doing that, it will use the defaultValue to determine the very first initialization value to use for each parameter. After that point in time however, the host is in control of those parameters a bit more. After that point in time, the Parameter list is connected to the host automation and to being saved with the project as parameter values for that particular plugin instance. In the case of Scripter, executing RunScript, will not reset that value!

 

Hitting RunScript will recompile the script, it will reset all the other vars, but it will not reset the Parameter values.

 

Notice also that if you save the script as a Scripter preset, the parameter values are also stored with that! So if you load one of the saved Scripter presets, it loads the script, compiles it AND also loads the parameter values that were present at the time you saved the Scripter preset.

 

That is actually a good thing, not a bad thing. You want to be able to use a scripter script, adjust the parameter values and save the preset or save the project and when you recall that project have the slider values be where they were the last time you used the project. You would NOT want the script to force the default script values every time you load the project.

 

And then later on hitting Run Script again will recompile the script, which resets all the script vars, but does not reset the parameter values, which are linked to the host daw's automation, etc.

 

Alright so what can you do to force it to reset?

 

First check out the following setting in your script which does in fact cause all the parameter values to be reset if that is what you want to do:

 

ResetParameterDefaults = true;

 

The above setting changes the behavior of Scripter in some way so that it will always reset the parameter values to the defaults whenever you load that script. Maybe this will be what you want, but see above what I said about the fact that if you save the project and reload it later...then the slider values will be reset back to the defaults...which is probably not what you want most of the time.

 

what else can you do?

 

You can use the SetParameter command to use script code to push data values into the parameter list at any time. Well almost any time. It turns out you cannot call SetParameter during the initial run of the script, its not available to work until the script has completely initialized. But you can use the Reset() function and force values in there:

 

function Reset() {
   SetParameter(0, 43);
}

 

The above Reset function will be called whenever you bypass or unbypass the plugin and also when you hit PLAY on the transport. That is according to the Scripter API manual. So in the above example, the value of 43 is pushed into the first parameter (identified by zero). But again, you may not want the default value always pushed into it every time you hit PLAY. So I find that hard to deal with.

 

There is an undocumented Initialize function, which might work, I can't remember at the moment if you can call SetParameter yet inside that function, but it is called only once while running your script the first time... its worth a try if you want to make sure that every time you hit RunScript, you can force a certain value into the parameter. But again note this may interfere with when you try to reload a project later and you want the last known slider value to be loaded with it.

 

function Initialize() {
   SetParameter(0,43);
}

 

The reality is that once you have finished coding your script, you will want to have the saved parameter values the last known slider value, always loaded with your script and functioning that way, as all plugins do. However, while you are writing the script and tweaking it and trying things, you may rather wish that it would reload the defaultValue each time, in which case use the ResetParameterDefaults setting I mentioned above while you're working on the script and then turn that off later when you're done coding and just want the script to behave more like a normal plugin that remembers your slider settings when you reload the project.

 

I realize this can be a little overwhelming and confusing to think about and I get it..I have spent a lot of time trying to figure out clever ways to bootstrap values into the parameter list or to use the parameter list to save a lot to detailed data..and in general it has been a big rabbit hole of complexity that wasn't worth it. I generally just try to use normal javascript variables to hard code values that I want to always start out the same way every time the script is executed with RunScript. I use Parameters to store values that I think I want the user to set, to be saved with the preset, saved with the project and appear on the GUI..and remembered from their last setting EVEN IF the runScript button is clicked again, which most users don't do anyway...its just you while you're working on the script.

 

Then if you need to get tricky you can use SetParameter to force some values into the parameter list under certain circumstances as you see fit.

  • Like 1
Link to comment
Share on other sites

  • 1 year later...

Hi,

I was led to this thread by a problem in my script.

Using the included script in Logic "MIDI to Plugin Parameters" I needed to duplicate input to all outgoing CC's. I altered the script to use the "INPUT_MENU_NAMES" array when building the output targets to set the default in the drop down list to each CC (search for "CreateNewTargetGroup" in the script below).

However the target drop down list is always set to "off" even though I added "ResetParameterDefaults = true;". I notice "Drumkit Designer Remapper" has presets in its drop down lists (ie. not just "off") so this must be possible.

Any ideas ?

//_________________________________________________________________
/*   MIDI to Plugin Parameters

This script allows an incoming MIDI message to control multiple plugin parameters. It has a few notable features:
   - Use "Learn MIDI Input" to easy assign the next incoming MIDI message as your MIDI control source. This could
     be a Continous Controller, Pitchbend, Velocity, or even Note value.
   - Select the dropdown menu for a target and choose "Learn plugin parameter", then move a control on your 
     plugin. This will assign the output target to that control.
   - Set the Target Min and Max sliders to set the range of control over the plugin parameter. You can even
     set the min value higher than the max value as a way of inverting the mapping.

*/

ResetParameterDefaults = true;

/*------------------------------------------------------------------------------------------------
  *
  *   GLOBALS
  *
  *------------------------------------------------------------------------------------------------*/

// -------- SETTINGS

// Change this to change how many targets are created.
var TOTAL_TARGETS = 128;


// -------- CONTROL GATES

// True if learn mode activated for input signal
var LEARN_MODE_ACTIVE = false;

// -------- COUNTERS

// Used when building Target Groups
var NUMBER_OF_TARGET_CONTROLS = 3;


/*------------------------------------------------------------------------------------------------
  *
  *   UI HANDLING
  *
  *------------------------------------------------------------------------------------------------*/

// -------- INPUT SELECTION MENU

/*
* Build set of Non-CC MIDI types
*/
const MIDI_TYPES = {
    off:0,
    note:1,
    velocity:2,
    pitchbend: 3,
    pressure: 4,
    controller: 5,
};

// get CC names from CC #0 to CC#127 and store in array
var INPUT_MENU_NAMES = MIDI._ccNames.slice();

// add CC numbers in front of names
for (var i = 0; i < 128; i++ ) 
{
        INPUT_MENU_NAMES[i] = i + " - " +  INPUT_MENU_NAMES[i];
}

// add Aftertouch to the Menu
INPUT_MENU_NAMES.unshift("Channel Pressure");

// add Pitch to the Menu
INPUT_MENU_NAMES.unshift("Pitchbend");

// add Velocity
INPUT_MENU_NAMES.unshift("Velocity");

// add MIDI Pitch to the Menu
INPUT_MENU_NAMES.unshift("Note");

// add OFF to the menu
INPUT_MENU_NAMES.unshift("-- OFF --");

// -------- SETUP INITIAL UI

var PluginParameters = [{
        name:"------- Input Signal -------",
        type:"text"
},    {
        name:"Learn MIDI Input",
        type:"checkbox", defaultValue:0
},    {    
        name:"Input Type",
        type:"menu",
        valueStrings:INPUT_MENU_NAMES,
        defaultValue:6
},    {        
        name:"----- Output Targets -----",
        type:"text"
}];        

// Create Target groups for the total number of requested targets
for (var i = 1; i <= TOTAL_TARGETS; i++){
    CreateNewTargetGroup(i);
}

//_______________________________ CreateNewTargetGroup () ________________________________
/**
* CreateNewTargetGroup() adds a new UI mapping for a target target, including
* all needed parameters at their default values.
*/
function CreateNewTargetGroup(targetNumber){

    PluginParameters.push({name:"Target " + targetNumber,type:"target",defaultValue:INPUT_MENU_NAMES[targetNumber]});    
    PluginParameters.push({name:"Min " + targetNumber,type:"lin",minValue:0,maxValue:100,defaultValue:0,unit:"%",numberOfSteps:100});
    PluginParameters.push({name:"Max " + targetNumber,type:"lin",minValue:0,maxValue:100,defaultValue:100,unit:"%",numberOfSteps:100});
}

//----------------------------- ParameterChanged() ------------------------------
/*
        ParameterChanged() is called whenever a UI element is changed.
*/

function ParameterChanged(param, value) {

    var paramName = PluginParameters[param].name;

    if (paramName == "Learn MIDI Input" && value == 1) {
        LEARN_MODE_ACTIVE = true;
    }
}

/*------------------------------------------------------------------------------------------------
  *
  *    DUPLICATING AND SENDING THE VALUE TO MULTIPLE TARGETS
  *
  *------------------------------------------------------------------------------------------------*/


//_______________________________ HandleMIDI () ________________________________
/**
* HandleMIDI()  is a predefined Scripter function that is called once for every
* incoming  MIDI event. Use if/else statements to handle the different types of
* MIDI  events
*
* @param event is the incoming MIDI event
*/

function HandleMIDI (event){

    // Handle valid learn assignments
    if (LEARN_MODE_ACTIVE){
        
        var learnSuccessful = false;

        if (event instanceof NoteOn){
            SetParameter("Input Type",MIDI_TYPES.velocity)
            learnSuccessful = true;
        }

        if (event instanceof ChannelPressure){
            SetParameter("Input Type",MIDI_TYPES.pressure)
            learnSuccessful = true;
        }

        if (event instanceof PitchBend){
            SetParameter("Input Type",MIDI_TYPES.pitchbend)
            learnSuccessful = true;
        }

        if (event instanceof ControlChange){
            SetParameter("Input Type",MIDI_TYPES.controller + event.number);
            learnSuccessful = true;
        }
        
        if (learnSuccessful){
            // Learn mode completed so reset flag and UI
            LEARN_MODE_ACTIVE = false;
            SetParameter("Learn MIDI Input",0);
        }    
    }    

    // If the incoming MIDI event matches our Input Type, send to targets

    var currentInputType = GetParameter("Input Type");

    if (event instanceof NoteOn && currentInputType == MIDI_TYPES.note){
        
        SendValueToAllTargets(event.pitch, MIDI_TYPES.note);
    }

    if (event instanceof NoteOn && currentInputType == MIDI_TYPES.velocity){
        
        SendValueToAllTargets(event.velocity, MIDI_TYPES.velocity);
    }

    if ((event instanceof ChannelPressure && currentInputType == MIDI_TYPES.pressure) ||
        (event instanceof ControlChange && currentInputType == MIDI_TYPES.controller + event.number)){
        
        SendValueToAllTargets(event.value, MIDI_TYPES.controller);
    }

    if (event instanceof PitchBend && currentInputType == MIDI_TYPES.pitchbend){
        
        SendValueToAllTargets(event.value, MIDI_TYPES.pitchbend);
    }

    // also pass through the original event and all non-matching events.
    event.send();
}

//_______________________________ SendValueToAllTargets ( value, midiType ) ________________________________
/**
* SendValueToAllTargets forwards the incoming MIDI value to all currently active
* targets, adjusting the math for either 8bit or 14bit messages.
* 
* @value is the value to be sent
* @midiType is the value's MIDI message type, needed in the case of pitchbend, which is 14bit.
*/

function SendValueToAllTargets(value, midiType){

    // setup input min/max values based on whether this is 8bit or 14bit message
    var minInput = 0;
    var maxInput = 127;
    if (midiType == MIDI_TYPES.pitchbend){
        minInput = -8192;
        maxInput = 8191;
    }

    // Cycle through all targets and send the scaled value
    for (var i = 1; i <= TOTAL_TARGETS; i++){
        var minOutput = GetParameter("Min " + i);
        var maxOutput = GetParameter("Max " + i);
        minOutput /= 100.0;                    //Divide by 100 convert from % to 0.0-1.0 scale
        maxOutput /= 100.0;
        
        var scaledValue = ScaleValue(value, minInput, maxInput, minOutput, maxOutput);
        var thisTargetName = "Target " + i;
        var event = new TargetEvent();
        event.target = thisTargetName;
        event.value = scaledValue;
        event.send();
    }
}

/*------------------------------------------------------------------------------------------------
  *
  *    HELPER & MATH FUNCTIONS
  *
  *------------------------------------------------------------------------------------------------*/

//_______________________________ ScaleValue() ________________________________
/**
* ScaleValue() takes a value with known minimum and maximum values and scales
* it to the desired output minimum and maximum.
*
* Returns the scaled value as a float.
*
* @inputValue is the value to be scaled
* @inputMin is the minimum expected value of the input signal
* @inputMax is the maximum expected value of the input signal
* @outputMin is the bottom of the scaled range
* @outputMax is the top of the scaled range
*/
function ScaleValue (inputValue, inputMin, inputMax, outputMin, outputMax) {
    return (((outputMax - outputMin) * (inputValue - inputMin)) / (inputMax - inputMin)) + outputMin;
}
Link to comment
Share on other sites

The reset is working for me, always comes up as the 6th item of the array every time I press the Runscript button.   However if you save the project and reopen it, it does not reset to the defaultValue unless you hit the RunScript button again.  I believe that is expected behavior.

That feature is a little confusing, but I believe the expected behavior is thus:

when a Script is first loaded for the first time, it does a number or things as its first executing the script the first time:

  1. scans through the script for all the variable and function names
  2. executes code at the global level
  3. Initializes the Parameters internally with whatever you have configured in PluginParameters

Once the script has been executed that first time, it keeps the values in the PluginParameters internal structure independently of the script.  That is so that when you close a project and reopen it again, it will remember the last setting you had set the GUI to when you were using it last.  

Normally if you hit the RunScript button, then the defaultValue is not re-loaded into the PluginParameters cache, it continues to keep whatever the project is currently using.

Unless you set ResetParameterDefaults=true, in which case when you hit the RunScript button again, it will reset the PluginParameters cache value back to the default every time.

But even with that setting, when you save the project and reopen it again, the stored value will be retained.  Likewise if you save an actual scriptter preset, it remembers the current cached value of each parameter also and restores them again...regardless of the value of ResetParameterDefaults.  That only affects what happens when you hit the RunScript button again to reload the script, as I understand it.

If you want your script when called up from a preset to always use the desired defaultValue, then you need to make sure to save the preset with that value selected.  then the preset itself will call it up with that default value intact.

If you want something more elaborate, then you will have to find a way to load the PluginParameter values using hard coded variable or const values everytime the script is loaded regardless of whether its during project load or while loading the script as a preset, to override any saved Parameter values in the project or preset.

 

Link to comment
Share on other sites

That's just a long winded way of saying, the Parameter Values are something separate from the script and LogicPro treats them as sacred..  Only with that reset enabled can they be stomped over and only when you hit the RunScript button to completely reload the script.  Otherwise without that enabled, the RunScript will only reload the script without actually resetting the various Plugin parameter values.  They are stored outside of the script in their own internal data structure.

Link to comment
Share on other sites

On 12/15/2023 at 4:50 PM, michaelzfreeman said:

However the target drop down list is always set to "off" even though I added "ResetParameterDefaults = true;". I notice "Drumkit Designer Remapper" has presets in its drop down lists (ie. not just "off") so this must be possible.

Any ideas ?

The TargetEvent Object's menu ("target" type) does not have a defaultValue property like the menu ("menu" type) used in the "Drumkit Designer Remapper" script. 

You'll have to find a way to make it work with SetParameter like @Dewdman42 says.

J.

Link to comment
Share on other sites

Yes, right, thanks ! I ended up manually setting all CC controls only to find that a Software Instrument plugin does not have its controls all set to default CC's 🤣. So back to square one. I resorted to manually setting all plugin controls to a single "super knob" on my keyboard. This produces interesting effects, however it's not ultimately what I was trying to achieve. I was aiming at registering all control positions in a plugin in automation per preset so I could interpolate between plugin presets to produce a sort of "morph" effect. This appears to be not even possible with OSC. Control positions can be "dumped" to a python script but controls are "paged" onto the actual plugin meaning only one subset can be active at any one time. No live changing of all the controls, only one page at a time.

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