Skip to content

Learning LX: Parameters

Mark Slee edited this page Nov 24, 2020 · 1 revision

Overview

One of the most fundamental concepts in LX is the LXParameter interface. An LXParameter can be thought of as a smart variable. Like a variable, it holds a value which can be set and retrieved. But an LXParameter has some important additional features:

  • A path that identifies this parameter in the larger LX program structure
  • A label, description, and options that specify how it should function in a UI
  • The ability to notify registered listeners to changes in value (LXListenableParameter)
  • A well-defined bounded range (LXNormalizedParameter)
  • The ability to be easily mapped to UI components, MIDI controllers, or OSC messages

The following sections describe the most important parameter types and the main ways of working with parameters.

Common Parameter Types

BoundedParameter

The BoundedParameter is a common and basic type of parameter which has a double-precision floating point value and a designated range.

// Create a parameter with initial value of 50 and range from 0-100
BoundedParameter parameter = new BoundedParameter("Label", 50, 0, 100);

// All parameter types have a description field
parameter.setDescription("A helpful description that tells the user what this parameter does");

// Values may be set and retrieved either in absolute range...
parameter.getValue();
parameter.setValue(100);

// ...or in a normalized range, from 0-1
parameter.getNormalized();
parameter.setNormalized(.4);

BooleanParameter

The BooleanParameter is a very basic parameter which stores a true or false value. They have a special property that specifies how they are expected to behave in a UI when represented as a button or switch.

BooleanParameter parameter = new BooleanParameter("Bool", false);

// The parameter flips between true and false state
parameter.setMode(BooleanParameter.Mode.TOGGLE);

// The parameter is true when actively engaged
parameter.setMode(BooleanParameter.Mode.MOMENTARY);

DiscreteParameter

A DiscreteParameter has a bounded range, but values are discrete integers.

// Discrete parameter with an initial value of 4 and range from [0,7]
DiscreteParameter parameter = new DiscreteParameter("Discrete", 4, 8);

// Values may be retrieved as integers
parameter.getValuei();

CompoundParameter

Perhaps the most important parameter type, the CompoundParameter is very similar to a BoundedParameter, with the special ability to have its value automated by a Modulator. The name of the class refers to the parameter's ability to combine values in this way. When writing a pattern, you should almost always use CompoundParameter instead of BoundedParameter, as this opens up interesting modulation possibilities.

// Syntax looks just like other bounded parameters
CompoundParameter parameter = new CompoundParameter("Label", 50, 0, 100);

FunctionalParameter

The FunctionalParameter may be used in situations where a parameter needs to compute its value dynamically. In this situation, you should take care to note that the computation is not cached and will be performed every time the parameter's value is requested.

FunctionalParameter parameter = new FunctionalParameter() {
  public double getValue() {
    // Compute the parameter value dynamically
  }
};

Listening to Parameters

Any parameter which implements the LXListenableParameter interface may be easily registered for callbacks. Callbacks are only triggered when the value actually changes. A special method may be used to force notification.

BoundedParameter parameter = new BoundedParameter("test", 0);

parameter.addListener(new LXParameterListener() {
  public void onParameterChanged(LXParameter p) {
    // Take action based upon change to p
  }
});

// Parameter is given a new value, listener is triggered
parameter.setValue(1.);

// Parameter already has this value, listener not triggered
parameter.setValue(1.);

// Listener is explicitly triggered, even though no change is value
parameter.bang();

Registering Parameters

Parameters should be registered with the component they belong to in the component's constructor. A path is specified, unique to the scope of this component, that controls storage of the parameter. A parameter may not be registered to more than one component.

public class MyPattern extends LXPattern {

  public final CompoundParameter value = new CompoundParameter("Val", 5, 0, 10)
    .setDescription("An arbitrary value used by this pattern.");
  
  public MyPattern(LX lx) {
    super(lx);
    addParameter("value", this.value);
  }
  ...
}

Specifying Parameter UI

The key advantages of using parameters to hold program state is that LX Studio can automatically create UI for them, display their values in human-readable fashion, store them in project files, and map them to MIDI controllers or OSC messages.

Description

// All parameters should have a helpful description set to educate the user
parameter.setDescription("Useful text that explains the parameter");

Units

// Customize display of the value in common units
parameter.setUnits(LXParameter.Units.MILLISECONDS);
parameter.setUnits(LXParameter.Units.DECIBELS);
parameter.setUnits(LXParameter.Units.HERTZ);

Polarity

// A knob for this parameter fills itself up from low to hi (e.g. Volume)
parameter.setPolarity(LXParameter.Polarity.UNIPOLAR);

// A knob for this parameter draws with a center point (e.g. Left/Right)
parameter.setPolarity(LXParameter.Polarity.BIPOLAR);

Formatter

// Use a custom formatter to display the parameter's value
parameter.setFormatter(new LXParameter.Formatter() {
  public String format(double value) {
    // Render the value for the UI
  }
});