The sound component is Computronics' programmable sound card. It exposes a real instruction queue, eight channels, several wave generators, volume control, delays, and simple modulation features.
Use it when you need more than short beeps or basic tones. Scripts build a queue of audio instructions and then call process() to submit that queue for playback.
- Repository:
computronics - Component name:
sound - Typical host: devices equipped with the Computronics sound card
local component = require("component")
local sound = component.sound
if not sound then
error("sound component not installed")
endYou can also access a specific device with component.proxy(address).
- The card provides
8channels by default. - Channel numbers in Lua start at
1. - Most methods add instructions to an internal build queue instead of taking effect immediately.
- The build queue can hold up to
1024instructions by default. - Delays in the queued program are counted in milliseconds, and the total queued delay may not exceed
5000ms by default. - You must call
sound.process()to submit the queued instructions for playback.
Wave modes returned by sound.modes():
1 = square2 = sine3 = triangle4 = sawtooth"noise" = -1and-1 = "noise"for white noise
- Syntax:
sound.channel_count() - Returns:
number - Purpose: Returns the number of available channels.
Example:
print("Sound channels:", sound.channel_count())- Syntax:
sound.modes() - Returns:
table - Purpose: Returns a bidirectional table of supported waveform modes.
Example:
local modes = sound.modes()
print("Sine mode id:", modes.sine)
print("Mode 4 name:", modes[4])
print("Noise mode id:", modes.noise)- Syntax:
sound.setTotalVolume(volume) - Returns: nothing
- Purpose: Sets the overall output volume of the card immediately.
Parameters:
volume:number: target volume. Values below0are clamped to0, values above1are clamped to1.
This is not a queued instruction. It affects the whole card directly.
Example:
sound.setTotalVolume(0.5)- Syntax:
sound.clear() - Returns: nothing
- Purpose: Clears the current build queue before it is processed.
This does not stop audio that has already been submitted with process(). It only removes instructions waiting in the build queue.
Example:
sound.clear()- Syntax:
sound.open(channel) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues an instruction that opens a channel gate so the channel can generate sound.
Parameters:
channel:number: channel index, starting at1.
If the build queue is already full, the call returns false, "too many instructions".
Example:
assert(sound.open(1))- Syntax:
sound.close(channel) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues an instruction that closes a channel gate and stops further output from that channel.
Parameters:
channel:number: channel index, starting at1.
Example:
assert(sound.close(1))- Syntax:
sound.setWave(channel, type) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues a waveform change for a channel.
Parameters:
channel:number: channel index, starting at1.type:number: waveform mode id fromsound.modes().
Special values:
1square2sine3triangle4sawtooth-1white noise
Errors:
- Invalid channel numbers raise an error.
- Invalid mode ids raise
invalid mode: <value>.
Example:
sound.setWave(1, sound.modes().sine)- Syntax:
sound.setFrequency(channel, frequency) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues a frequency change for a channel.
Parameters:
channel:number: channel index, starting at1.frequency:number: frequency in hertz.
The method stores the frequency exactly as given. Unlike the simpler beep and noise interfaces, this callback does not clamp the frequency in the Lua wrapper.
Example:
sound.setFrequency(1, 440)- Syntax:
sound.setLFSR(channel, initial, mask) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues an LFSR noise generator for a channel.
Parameters:
channel:number: channel index, starting at1.initial:number: initial register state.mask:number: feedback mask.
Use this when you want retro-style pseudo-random noise rather than periodic waveforms.
Example:
sound.setLFSR(2, 1, 0xB400)- Syntax:
sound.delay(duration) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues a pause inside the sound program.
Parameters:
duration:number: delay in milliseconds.
Behavior:
durationmust be between0and5000ms by default.- If the total queued delay would exceed the configured maximum, the call returns
false, "too many delays in queue".
Errors:
- Invalid values raise
invalid duration. must be between 0 and 5000.
Example:
sound.delay(250)- Syntax:
sound.setFM(channel, modIndex, intensity) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues frequency modulation for a channel.
Parameters:
channel:number: channel to be modulated.modIndex:number: channel acting as the modulator.intensity:number: modulation strength.
The modulator channel index also uses 1-based numbering from Lua.
Example:
sound.setFM(1, 2, 0.5)- Syntax:
sound.resetFM(channel) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues removal of frequency modulation from a channel.
Parameters:
channel:number: target channel.
Example:
sound.resetFM(1)- Syntax:
sound.setAM(channel, modIndex) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues amplitude modulation for a channel.
Parameters:
channel:number: channel to be modulated.modIndex:number: channel acting as the amplitude modulator.
Example:
sound.setAM(1, 2)- Syntax:
sound.resetAM(channel) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues removal of amplitude modulation from a channel.
Parameters:
channel:number: target channel.
Example:
sound.resetAM(1)- Syntax:
sound.setADSR(channel, attack, decay, attenuation, release) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues an ADSR envelope for a channel.
Parameters:
channel:number: target channel.attack:number: attack duration in milliseconds.decay:number: decay duration in milliseconds.attenuation:number: sustain attenuation, normally between0and1.release:number: release duration in milliseconds.
The implementation keeps the previous envelope progress if the channel already had one, allowing smoother updates.
Example:
sound.setADSR(1, 20, 80, 0.6, 120)- Syntax:
sound.resetEnvelope(channel) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues removal of the ADSR envelope from a channel.
Parameters:
channel:number: target channel.
Example:
sound.resetEnvelope(1)- Syntax:
sound.setVolume(channel, volume) - Returns:
- Success:
true - Failure:
false, reason
- Success:
- Purpose: Queues a per-channel volume change.
Parameters:
channel:number: target channel.volume:number: desired channel volume.
Behavior:
- The queued volume is clamped internally to the range
0through1.
Example:
sound.setVolume(1, 0.75)- Syntax:
sound.process() - Returns:
- Success:
true - Failure:
false, reasonOrTime
- Success:
- Purpose: Submits the queued instruction program for playback.
Behavior:
- If the queue is empty, it still returns
true. - Energy cost depends on the total queued delay time.
- On success, the current build queue is moved into the playback queue.
- If the previous playback queue is still active, the call returns
false, elapsedMilliseconds, where the second value is how long ago the internal timeout point was crossed. - If the component network does not have enough energy, the call returns
false, "not enough energy".
Example: play a short note.
sound.clear()
sound.open(1)
sound.setWave(1, sound.modes().square)
sound.setFrequency(1, 440)
sound.setVolume(1, 0.8)
sound.delay(200)
sound.close(1)
local ok, reason = sound.process()
if not ok then
io.stderr:write("Sound process failed: " .. tostring(reason) .. "\n")
endExample: a two-channel chord.
sound.clear()
sound.open(1)
sound.open(2)
sound.setWave(1, sound.modes().sine)
sound.setWave(2, sound.modes().sine)
sound.setFrequency(1, 523.25)
sound.setFrequency(2, 659.25)
sound.setVolume(1, 0.6)
sound.setVolume(2, 0.6)
sound.delay(300)
sound.close(1)
sound.close(2)
assert(sound.process())- Most callbacks only enqueue instructions. Nothing is heard until
process()succeeds. - If you need one-shot tones without queue programming,
beepornoisemay be easier to use.
componentbeepnoise