Skip to content

API Audio and Sound

Audio output, including simple tones and full sample/file playback.

Simple tone generation via PWM. Useful for beeps, alerts, and simple sound effects.

picocalc.audio.playTone(freq [, duration])

Section titled “picocalc.audio.playTone(freq [, duration])”

Plays a tone at the specified frequency.

  • Parameters:
    • freq (number): Frequency in Hz (e.g., 440 for concert A)
    • duration (number, optional): Duration in milliseconds. If 0 or omitted, the tone plays indefinitely until stopTone() is called.
  • Returns: None
picocalc.audio.playTone(440, 200) -- beep for 200ms
picocalc.audio.playTone(880) -- start continuous tone

Stops any currently playing tone immediately.

  • Parameters: None
  • Returns: None
picocalc.audio.stopTone()

Sets the audio output volume.

  • Parameters:
    • volume (number): Volume level (0–100, where 0 is muted and 100 is maximum; larger values clamp to 100)
  • Returns: None
picocalc.audio.setVolume(128) -- 50% volume

Initialize PCM audio streaming at the specified sample rate.

  • Parameters:
    • sampleRate (number): Sample rate in Hz (e.g. 44100)
  • Returns: None
picocalc.audio.startStream(44100)

Stop the active PCM audio stream.

  • Parameters: None
  • Returns: None
picocalc.audio.stopStream()

Push audio samples to the streaming buffer. Samples are interleaved stereo pairs (left, right, left, right…).

  • Parameters:
    • samples (table): Array of int16 sample values (max 512 values = 256 stereo pairs)
  • Returns: None
local samples = {}
for i = 1, 512 do
samples[i] = math.floor(math.sin(i * 0.1) * 16000)
end
picocalc.audio.pushSamples(samples)

Get the number of free slots available in the audio ring buffer. Use this to avoid pushing more samples than the buffer can hold.

  • Parameters: None
  • Returns: (number) Free buffer slots
local free = picocalc.audio.ringFree()
if free >= 512 then
picocalc.audio.pushSamples(samples)
end

Full audio playback system supporting WAV samples and MP3 files. Provides three player types:

  • SamplePlayer — plays a pre-loaded WAV sample from memory
  • FilePlayer — streams a WAV file from the SD card
  • MP3Player — streams an MP3 file from the SD card

Returns the current audio clock time in milliseconds since the last resetTime() call.

  • Returns: (number) Milliseconds

Resets the audio clock to zero.

  • Returns: None

Returns the number of audio sources currently playing across all player types.

  • Returns: (number) Count of active audio sources
local n = picocalc.sound.playingSources()
picocalc.sys.log("Active sources: " .. n)

A Sample holds raw PCM audio data loaded from a WAV file.

Creates a new Sample object, optionally loading a WAV file immediately.

WAVs must be 8- or 16-bit PCM with 1-2 channels (float, 24/32-bit, ADPCM and more channels are refused); only the first 64 KB of sample data is kept.

  • Parameters:
    • path (string, optional): Absolute path to a WAV file
  • Returns: (userdata) Sample object, or nil, errstr on failure
local s = picocalc.sound.sample("/apps/myapp/beep.wav")

Loads a WAV file into the sample.

WAVs must be 8- or 16-bit PCM with 1-2 channels (float, 24/32-bit, ADPCM and more channels are refused); only the first 64 KB of sample data is kept.

  • Parameters:
    • path (string): Absolute path to a WAV file
  • Returns: true on success, or nil, errstr on failure

Returns the number of PCM samples (frames).

  • Returns: (number)

Returns the sample rate in Hz (e.g., 44100).

  • Returns: (number)

Returns the audio format of the sample as a table.

  • Returns: (table) With fields:
    • bits (number): Bits per sample (e.g. 8, 16)
    • channels (number): Number of channels (1=mono, 2=stereo)
    • sampleRate (number): Sample rate in Hz
local fmt = sample:getFormat()
picocalc.sys.log(fmt.bits .. "bit, " .. fmt.channels .. "ch, " .. fmt.sampleRate .. "Hz")

Returns the sample itself (no-op). Provided for API compatibility with engines that distinguish compressed and decompressed sample data. On PicoDeck, samples are always stored decompressed.

  • Returns: (userdata) The same Sample object

Creates a new Sample containing a slice of the original sample’s PCM data.

  • Parameters:
    • start (number): Start offset in PCM frames
    • end (number): End offset in PCM frames
  • Returns: (userdata) New Sample object, or nil, errstr on failure
local clip = sample:getSubsample(0, 22050) -- first second at 44100 Hz

Creates a temporary SamplePlayer, starts playback, and returns the player. Convenience method.

  • Parameters:
    • repeatCount (number, optional): Number of times to play (default 1)
    • rate (number, optional): Playback rate multiplier (default 1.0)
  • Returns: (userdata) SamplePlayer object
local s = picocalc.sound.sample("/apps/myapp/beep.wav")
s:play() -- play once at normal speed
s:play(3, 1.5) -- play 3 times at 150% speed

sample:playAt(when [, vol [, rightvol [, rate]]])

Section titled “sample:playAt(when [, vol [, rightvol [, rate]]])”

Creates a temporary SamplePlayer and starts playback. The when parameter is accepted for API compatibility but ignored on this hardware (playback starts immediately).

  • Parameters:
    • when (number): Ignored (accepted for API compatibility)
    • vol (number, optional): Volume 0–100 (default 100; larger values clamp)
    • rightvol (number, optional): Ignored (mono PWM output)
    • rate (number, optional): Playback rate multiplier (default 1.0)
  • Returns: (userdata) SamplePlayer object
local s = picocalc.sound.sample("/apps/myapp/beep.wav")
local player = s:playAt(0, 200) -- play at volume 200
local player = s:playAt(0, 128, 0, 2.0) -- play at double speed

Writes the sample data to a WAV file on the SD card.

  • Parameters:
    • filename (string): Path to write
  • Returns: true on success, or false, errstr on failure
local clip = sample:getSubsample(0, 22050)
clip:save("/data/com.myapp/clip.wav")

Plays a Sample from memory. Supports looping and volume control.

picocalc.sound.sampleplayer([sample_or_path])

Section titled “picocalc.sound.sampleplayer([sample_or_path])”

Creates a SamplePlayer, optionally pre-loading a sample.

A SamplePlayer keeps its Sample alive (you may drop your own reference). sampleplayer(path) and sample:play() create a Sample of their own. Dropping the player returned by sample:play() stops that sound when it is collected.

  • Parameters:
    • sample_or_path (userdata or string, optional): A Sample object or a WAV file path
  • Returns: (userdata) SamplePlayer object, or nil, errstr on failure
local player = picocalc.sound.sampleplayer("/apps/myapp/beep.wav")
player:play()

Sets the sample to play.

  • Parameters:
    • sample (userdata): A Sample object
  • Returns: true on success, or nil, errstr

Starts playback.

  • Parameters:
    • repeat (number, optional): Number of times to repeat. 0 loops indefinitely.
  • Returns: true if started

Stops playback.


  • Returns: (boolean)

player:setVolume(vol) / player:getVolume()

Section titled “player:setVolume(vol) / player:getVolume()”

Volume range 0–100 (larger values clamp to 100).


Returns the Sample object currently assigned to this player.

  • Returns: (userdata) the Sample object, or nil if no sample is set

Pauses or unpauses playback without resetting the playback position.

  • Parameters:
    • paused (boolean): true to pause, false to resume
player:setPaused(true) -- pause
player:setPaused(false) -- resume

Sets the playback range in PCM frames. Playback will only play samples within this range.

  • Parameters:
    • start (number): Start frame offset
    • end (number): End frame offset
player:setPlayRange(0, 44100) -- play only the first second

Returns the length of the loaded sample in PCM frames.

  • Returns: (number) Frame count, or 0 if no sample is set

Seeks to a position in seconds.

  • Parameters:
    • seconds (number): Playback position in seconds (fractions allowed)
  • Returns: None
player:setOffset(1.5) -- seek to 1.5 seconds

Returns the current playback position in seconds.

  • Returns: (number) Position in seconds

Sets or gets the playback rate multiplier. 1.0 is normal speed, 2.0 is double speed, 0.5 is half speed.

  • Parameters:
    • rate (number): Playback rate multiplier
  • Returns: (number) Current rate (for getRate)
player:setRate(1.5) -- play at 150% speed

Sets a callback fired when playback finishes (all repeats completed). Maximum 4 callbacks across all SamplePlayer instances. The callback fires on Core 0 via the Lua instruction hook (slight delay of up to ~256 opcodes).

  • Parameters:
    • fn (function): Callback function (called with no arguments)
player:setFinishCallback(function()
picocalc.sys.log("Sample playback finished")
end)

Sets a callback fired each time the player loops back to the start. Same cross-core delivery mechanism as setFinishCallback.

  • Parameters:
    • fn (function): Callback function (called with no arguments)
player:setLoopCallback(function()
picocalc.sys.log("Sample looped")
end)

Streams a WAV file from the SD card without loading it fully into memory.

Creates a FilePlayer.

  • Parameters:
    • bufferSize (number, optional): Internal streaming buffer size in bytes
  • Returns: (userdata) FilePlayer object, or nil, errstr on failure

Opens a WAV file for streaming.

Streams 16-bit PCM only: an 8-bit WAV is refused here (a Sample accepts it).

  • Parameters:
    • path (string): Absolute path to a WAV file
  • Returns: true on success, or nil, errstr

player:play([repeat]) / player:stop() / player:pause() / player:resume() / player:isPlaying()

Section titled “player:play([repeat]) / player:stop() / player:pause() / player:resume() / player:isPlaying()”

Standard playback controls. repeat works the same as SamplePlayer. pause() halts playback keeping the position; resume() continues from the paused position.


player:getLength() / player:getOffset() / player:setOffset(seconds)

Section titled “player:getLength() / player:getOffset() / player:setOffset(seconds)”

Returns or seeks to a position in seconds.


player:setVolume(left [, right]) / player:getVolume()

Section titled “player:setVolume(left [, right]) / player:getVolume()”

Sets the volume (0–100, clamped). right is accepted for compatibility but ignored: both channels use left. getVolume() returns the volume twice.


Sets the loop region in seconds. Omit both to loop the whole file.


Returns whether the streaming buffer underran since the last check. An underrun means the SD card could not supply audio data fast enough.

  • Returns: (boolean) true if an underrun occurred
if player:didUnderrun() then
picocalc.sys.log("Audio buffer underrun!")
end

Sets a callback function to be called when playback finishes. Maximum 2 finish callbacks across all FilePlayer instances.

  • Parameters:
    • fn (function): Callback function (called with no arguments)
player:setFinishCallback(function()
picocalc.sys.log("Playback finished")
end)

Sets a callback fired each time the file loops back to the start. Maximum 2 loop callbacks across all FilePlayer instances.

  • Parameters:
    • fn (function): Callback function (called with no arguments)
player:setLoopCallback(function()
picocalc.sys.log("File looped")
end)

Sets or gets the playback rate. Rate is clamped to 0.1–4.0. Uses nearest-neighbor resampling.

  • Parameters:
    • rate (number): Playback rate multiplier (1.0 = normal, 2.0 = double speed, 0.5 = half speed)
  • Returns: (number) Current rate (for getRate)
player:setRate(2.0) -- double speed
local r = player:getRate() -- returns 2.0

Controls whether the player automatically stops when a buffer underrun occurs.

  • Parameters:
    • flag (boolean): true to stop on underrun, false to continue
player:setStopOnUnderrun(true)

Streams an MP3 file from the SD card.

Creates an MP3Player.

picocalc.sound.mp3player() returns the one live MP3 player handle (there is a single MP3 decoder).

  • Returns: (userdata) MP3Player object, or nil, errstr on failure
local mp3 = picocalc.sound.mp3player()
mp3:load("/apps/myapp/music.mp3")
mp3:play()

Opens an MP3 file for streaming.

  • Returns: true on success, or nil, errstr

player:play([repeat]) / player:stop() / player:pause() / player:resume() / player:isPlaying()

Section titled “player:play([repeat]) / player:stop() / player:pause() / player:resume() / player:isPlaying()”

Standard playback controls.


Returns current playback position or total duration in seconds.


Returns the sample rate of the MP3 file in Hz.

  • Returns: (number)

player:setVolume(vol) / player:getVolume()

Section titled “player:setVolume(vol) / player:getVolume()”

Volume range 0–100 (larger values clamp to 100).


  • Parameters:
    • loop (boolean): true to loop continuously