Jump to content

Lua modulation API

From SimTX Wiki

A modulation registration receives a context object named ctx. The same object is passed to the optional start and stop callbacks and to every process callback. Indices are zero-based.

Lifecycle[edit | edit source]

simtx.modulation {
  name = "Example",
  start = function(ctx)
    -- Prepare state for this transmission.
  end,
  process = function(ctx)
    -- Produce one complete output block.
  end,
  stop = function(ctx)
    -- Release script state if necessary.
  end,
}

Each transmission receives an isolated copy of the script state. Control values remain live and may change between blocks. Every output sample must be finite.

Stream information[edit | edit source]

Method Result
ctx:n() Number of samples in the current block.
ctx:blockSize() Alias of n().
ctx:rate() Stream sample rate in hertz.
ctx:sampleRate() Alias of rate().
ctx:time() Time in seconds at the start of the block.
ctx:sessionTime() Alias of time().
ctx:samplePosition() Absolute sample position at the start of the block.

Reading audio and writing output[edit | edit source]

Method Effect
ctx:audio(index) Returns an incoming mono audio sample, normally in the range -1 to 1.
ctx:iq(index, i, q) Writes one complex output sample.
ctx:map(function(audio, index, time) ... end) Maps every input audio sample. The callback returns I and optional Q.
ctx:generate(function(index, time) ... end) Generates every sample without using audio. The callback returns I and optional Q.
ctx:passthrough() Copies incoming mono audio to the output.
ctx:gain(amount) Copies incoming audio to the output with a constant linear gain.
ctx:limit(peak) Limits both output components to the symmetric positive peak.
ctx:mixTone(frequencyHz, level) Mixes a sine tone with incoming audio and reserves headroom for it.
ctx:mixTone(frequencyHz, level, reserveHeadroom) Mixes a sine tone and selects whether the input is reduced by the tone level.
ctx:fill(value) Fills an audio block, or the I component of an IQ block, with a constant value.
ctx:fill(i, q) Fills the block with a constant complex sample.
ctx:silence() Fills the block with zeroes.

map and generate callbacks receive absolute sample time, not merely time within the current block. This permits phase-continuous generators. Omitting the Q return value sets Q to zero.

process = function(ctx)
  local gain = ctx:control("gain")
  ctx:map(function(audio)
    return audio * gain
  end)
  ctx:limit(1)
end

Block operations such as gain, mixTone, and fill are preferable when they express the required operation because they avoid a Lua callback for every sample.

Controls and inputs[edit | edit source]

Method Result
ctx:control(id) Current value of one control, or nil for an unknown ID.
ctx:controls() Snapshot table containing all current control values.
ctx:input(id) Decoded image, video, or file input, or nil.
ctx:inputs() Snapshot table containing all supplied non-audio inputs.
ctx:hasInput(id) Whether a non-audio input was supplied.
ctx:finish() Requests a clean end after the current block.

Audio is accessed through audio, map, and the block operations rather than through input.

Image objects[edit | edit source]

Image coordinates are zero-based. Channel and luminance values are normalized from 0 to 1.

Method Result
image:name() Original filename.
image:width(), image:height() Dimensions in pixels.
image:red(x,y), green, blue, alpha One normalized channel.
image:luma(x,y) Rec. 709 luminance.
image:pixel(x,y) Table with r, g, b, a, and luma fields.
image:argb(x,y) Packed ARGB integer.
image:resize(width,height) High-quality resized image object.

An image side may contain at most 8,192 pixels, and an image may contain at most 16,777,216 pixels.

Video objects[edit | edit source]

Video frame indices are zero-based.

Method Result
video:name() Original filename.
video:width(), video:height() Frame dimensions.
video:frames() Number of frames.
video:duration() Duration in seconds.
video:frameRate() Average frames per second.
video:frame(index) Decoded frame as an image object.
video:frameAt(seconds) Frame at the requested time as an image object. Times outside the duration are clamped.

Video decoding supports MP4 and MOV-family files accepted by the picker. A script should normally obtain one frame per logical video frame and reuse it while producing the corresponding samples.

File objects[edit | edit source]

Method Result
file:name() Original filename.
file:size() Size in bytes.
file:byteAt(index) Unsigned byte from 0 to 255 at a zero-based index.
file:text() Entire payload decoded as UTF-8 text.

A generic file input may contain at most 64 MiB.