Glue concepts

Target value sequence

A target value sequence represents a list of possible target values. It can be entered using into the Value sequence field.

The mapping will set the target only to values contained in that sequence. Such a sequence doesn’t just support single values but also ranges with customizable step sizes. All values are entered comma-separated using the target unit specified with the Display unit button.

Example 1. Single values

Enter this sequence for a volume target with target unit switched to dB:

-20, -14, -12, -6, -3.5, 0

When you move your knob or rotary encoder or press a button using Incremental button mode, ReaLearn will step through the entered dB values for you.

Example 2. Value ranges

Enter this sequence for a target with a continuous value range and target unit switched to %:

10 - 30, 50 - 70 (5), 80 - 90 (2)

It will first step in 1% steps from 10% to 30%, then in 2% steps from 50% to 70% and finally from 80% to 90% in 2% steps. It’s important that the numbers and the range dash are separated by spaces!

Example 3. Non-monotonic or non-strict-monotonic sequences

Let’s look at this sequence:

20, 10, 10, -5, 8

It’s non-monotonic: It decreases, and then increases again. Even if it would just decrease, it would be non-strict monotonic because it contains duplicates (value 10).

When using Absolute control, it’s no problem stepping through such sequences.

However, Relative control only supports strictly increasing or strictly decreasing sequences. So if you control this sequence e.g. via Rotary endless encoder or via Incremental button mode, the sequence will be stepped through like this: -5, 8, 10, 20.

Alternative: Use Make absolute!

Feedback type

The feedback type determines whether to send numeric, text or dynamic feedback to the source. It can be set using the Feedback type controls.

Numeric feedback: EEL transformation

Sends numeric feedback to the source. This is the default.

Numeric feedback can be combined with an EEL feedback transformation formula. This is similar to Control transformation (EEL) field but used for translating a target value back to a source value for feedback purposes.

Be aware: Here x is the desired source value (= output value) and y is the current target value (= input value), so you must assign the desired source value to x.

Example 4. Simple feedback transformation formula

x = y * 2

ReaLearn’s feedback processing order is:

  1. Apply target interval.

  2. Apply reverse.

  3. Apply transformation.

  4. Apply source interval.

Text feedback: Text expression

With this option, ReaLearn will send text feedback values to the source. This only works with sources that are capable of displaying text: That is any Source "OSC" with argument type String, Source "Display" and Source "MIDI Script".

Text feedback can be combined with a text expression, which lets you define which text is going to be sent to the source whenever the target value changes and immediately when entering the text. Whatever text you enter here, will be sent verbatim to the source.

Of course, entering a fixed text here is not very exciting. Most likely you want to display dynamic text such as the name of the currently selected track or the current target value, nicely formatted! You can do that by using placeholders, delimited by double braces.

Example 5. Simple text expression

{{target.text_value}}

See Target property for a list of properties that you can use in placeholders.

Dynamic feedback: Lua script

This feedback type puts you fully in charge about which feedback to send to the source. It does so by letting you define a Luau script that builds numeric, textual or even arbitrarily structured feedback.

General mechanics

ReaLearn executes your script whenever one of the ReaLearn-provided properties used in your script might have changed its value.

The script receives an input and must produce an output.

Script input
  • The input is a function context.prop which you can use to query arbitrary properties, e.g. target or mapping properties. Those properties are the very same properties that you can use in textual feedback.

    Example 6. How to use context.prop()
    local preset_name = context.prop("target.preset.name")
    local param_name = context.prop("target.fx_parameter.name")
  • Values returned by this function can be nil! E.g. target-related properties return a nil value whenever the mapping or target turns inactive, which is a very common situation. So it’s important to prepare your Luau code for that, otherwise script execution fails and no feedback will be sent. One way to deal with a nil value returned by context.prop is to also return nil as value (see below).

Script output
  • The output that the script is supposed to return is a table which looks as in the following example.

    Example 7. Result table structure
    return {
        feedback_event = {
            -- The feedback value (1)
            value = "Arbitrary text",
            -- An optional color (2)
            color = { r = 0, g = 255, b = 0 },
            -- An optional background color (3)
            background_color = nil,
        }
    }
    1 In this example it’s a text value, but it can be anything!
    2 Has the same effect as color in Feedback style menu (…​)
    3 Has the same effect as background color in Feedback style menu (…​)
  • The most important thing here is value. It can either be …​

    • …​ a string (ideal for display sources)

    • …​ a number (ideal for LEDs and motor faders)

    • …​ nil (which means "turn the source off", e.g. turn off the LED, turn down the motorfader, clear the display text)

    • …​ or anything else (true, false or an arbitrary table …​ at the moment, this is only useful for the Source "MIDI Script" because other sources don’t know how to deal with it)

Example 8. global.realearn.time

Displays the number of milliseconds passed since ReaLearn was loaded:

local millis = context.prop("global.realearn.time")
return {
    feedback_event = {
        value = "" .. millis .. "ms"
    },
}
Example 9. Animation

Creates an animation to make a long FX name visible on a tiny screen:

function create_left_right_animation(global_millis, max_char_count, frame_length, text)
    if text == nil then
        return nil
    end
    if #text > max_char_count then
        local frame_count = #text - max_char_count
        local frame_index = math.floor(global_millis / frame_length) % (frame_count * 2)
        local text_offset
        if frame_index < frame_count then
            text_offset = frame_index
        else
            local distance = frame_index - frame_count
            text_offset = frame_count - distance
        end
        return text:sub(text_offset + 1, text_offset + max_char_count)
    else
        return text
    end
end

-- The maximum number of characters we want to display at once
local max_char_count = 10
-- How many milliseconds to remain in one position
local frame_length = 150
local millis = context.prop("global.realearn.time")
local fx_name = context.prop("target.fx.name")
local animation = create_left_right_animation(millis, 10, frame_length, fx_name)
return {
    feedback_event = {
        value = animation
    },
}
Example 10. Structured feedback values

Returns a structured feedback value …​

return {
    feedback_event = {
        value = {
            available = context.prop("target.available"),
            more_info = {
                index = context.prop("target.discrete_value"),
                count = context.prop("target.discrete_value_count"),
            },
        }
    },
}

... which can then be processed by a Source "MIDI Script":

return {
    address = 0x4bb0,
    messages = {
        { 0xb0, 0x4b, y.more_info.index, y.more_info.count }
    }
}

This example is not realistic, it just shows how you can access the value table returned by the glue section feedback script.

You can share code between multiple feedback scripts by using Compartment-wide Lua code, with the following limitations (which hopefully will be lifted over time):

  • The shared code is not yet available to the Lua code editor window. That means writing require("compartment") will evaluate to nil in the editor. You might see a corresponding error message when the editor tries to compile your code.

  • When ReaLearn queries the script in advance to know which target properties it needs, the shared code is also not available yet. Currently, you need to make sure that the target properties are queried even if require("compartment") evaluates to nil.