API Audio and Sound
Audio output, including simple tones and full sample/file playback.
picocalc.audio
Section titled “picocalc.audio”Simple tone generation via PWM. Useful for beeps, alerts, and simple sound effects.
Functions
Section titled “Functions”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.,440for concert A)duration(number, optional): Duration in milliseconds. If0or omitted, the tone plays indefinitely untilstopTone()is called.
- Returns: None
picocalc.audio.playTone(440, 200) -- beep for 200mspicocalc.audio.playTone(880) -- start continuous tonepicocalc.audio.stopTone()
Section titled “picocalc.audio.stopTone()”Stops any currently playing tone immediately.
- Parameters: None
- Returns: None
picocalc.audio.stopTone()picocalc.audio.setVolume(volume)
Section titled “picocalc.audio.setVolume(volume)”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% volumePCM Streaming
Section titled “PCM Streaming”picocalc.audio.startStream(sampleRate)
Section titled “picocalc.audio.startStream(sampleRate)”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)picocalc.audio.stopStream()
Section titled “picocalc.audio.stopStream()”Stop the active PCM audio stream.
- Parameters: None
- Returns: None
picocalc.audio.stopStream()picocalc.audio.pushSamples(samples)
Section titled “picocalc.audio.pushSamples(samples)”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)endpicocalc.audio.pushSamples(samples)picocalc.audio.ringFree()
Section titled “picocalc.audio.ringFree()”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)endpicocalc.sound
Section titled “picocalc.sound”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
Top-Level Functions
Section titled “Top-Level Functions”picocalc.sound.getCurrentTime()
Section titled “picocalc.sound.getCurrentTime()”Returns the current audio clock time in milliseconds since the last resetTime() call.
- Returns: (number) Milliseconds
picocalc.sound.resetTime()
Section titled “picocalc.sound.resetTime()”Resets the audio clock to zero.
- Returns: None
picocalc.sound.playingSources()
Section titled “picocalc.sound.playingSources()”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)Sample
Section titled “Sample”A Sample holds raw PCM audio data loaded from a WAV file.
picocalc.sound.sample([path])
Section titled “picocalc.sound.sample([path])”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, errstron failure
local s = picocalc.sound.sample("/apps/myapp/beep.wav")sample:load(path)
Section titled “sample:load(path)”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:
trueon success, ornil, errstron failure
sample:getLength()
Section titled “sample:getLength()”Returns the number of PCM samples (frames).
- Returns: (number)
sample:getSampleRate()
Section titled “sample:getSampleRate()”Returns the sample rate in Hz (e.g., 44100).
- Returns: (number)
sample:getFormat()
Section titled “sample:getFormat()”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")sample:decompress()
Section titled “sample:decompress()”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
sample:getSubsample(start, end)
Section titled “sample:getSubsample(start, end)”Creates a new Sample containing a slice of the original sample’s PCM data.
- Parameters:
start(number): Start offset in PCM framesend(number): End offset in PCM frames
- Returns: (userdata) New Sample object, or
nil, errstron failure
local clip = sample:getSubsample(0, 22050) -- first second at 44100 Hzsample:play([repeatCount [, rate]])
Section titled “sample:play([repeatCount [, rate]])”Creates a temporary SamplePlayer, starts playback, and returns the player. Convenience method.
- Parameters:
repeatCount(number, optional): Number of times to play (default1)rate(number, optional): Playback rate multiplier (default1.0)
- Returns: (userdata) SamplePlayer object
local s = picocalc.sound.sample("/apps/myapp/beep.wav")s:play() -- play once at normal speeds:play(3, 1.5) -- play 3 times at 150% speedsample: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 (default100; larger values clamp)rightvol(number, optional): Ignored (mono PWM output)rate(number, optional): Playback rate multiplier (default1.0)
- Returns: (userdata) SamplePlayer object
local s = picocalc.sound.sample("/apps/myapp/beep.wav")local player = s:playAt(0, 200) -- play at volume 200local player = s:playAt(0, 128, 0, 2.0) -- play at double speedsample:save(filename)
Section titled “sample:save(filename)”Writes the sample data to a WAV file on the SD card.
- Parameters:
filename(string): Path to write
- Returns:
trueon success, orfalse, errstron failure
local clip = sample:getSubsample(0, 22050)clip:save("/data/com.myapp/clip.wav")SamplePlayer
Section titled “SamplePlayer”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): ASampleobject or a WAV file path
- Returns: (userdata) SamplePlayer object, or
nil, errstron failure
local player = picocalc.sound.sampleplayer("/apps/myapp/beep.wav")player:play()player:setSample(sample)
Section titled “player:setSample(sample)”Sets the sample to play.
- Parameters:
sample(userdata): ASampleobject
- Returns:
trueon success, ornil, errstr
player:play([repeat])
Section titled “player:play([repeat])”Starts playback.
- Parameters:
repeat(number, optional): Number of times to repeat.0loops indefinitely.
- Returns:
trueif started
player:stop()
Section titled “player:stop()”Stops playback.
player:isPlaying()
Section titled “player:isPlaying()”- Returns: (boolean)
player:setVolume(vol) / player:getVolume()
Section titled “player:setVolume(vol) / player:getVolume()”Volume range 0–100 (larger values clamp to 100).
player:getSample()
Section titled “player:getSample()”Returns the Sample object currently assigned to this player.
- Returns: (userdata) the Sample object, or
nilif no sample is set
player:setPaused(paused)
Section titled “player:setPaused(paused)”Pauses or unpauses playback without resetting the playback position.
- Parameters:
paused(boolean):trueto pause,falseto resume
player:setPaused(true) -- pauseplayer:setPaused(false) -- resumeplayer:setPlayRange(start, end)
Section titled “player:setPlayRange(start, end)”Sets the playback range in PCM frames. Playback will only play samples within this range.
- Parameters:
start(number): Start frame offsetend(number): End frame offset
player:setPlayRange(0, 44100) -- play only the first secondplayer:getLength()
Section titled “player:getLength()”Returns the length of the loaded sample in PCM frames.
- Returns: (number) Frame count, or
0if no sample is set
player:setOffset(seconds)
Section titled “player:setOffset(seconds)”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 secondsplayer:getOffset()
Section titled “player:getOffset()”Returns the current playback position in seconds.
- Returns: (number) Position in seconds
player:setRate(rate) / player:getRate()
Section titled “player:setRate(rate) / player:getRate()”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% speedplayer:setFinishCallback(fn)
Section titled “player:setFinishCallback(fn)”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)player:setLoopCallback(fn)
Section titled “player:setLoopCallback(fn)”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)FilePlayer
Section titled “FilePlayer”Streams a WAV file from the SD card without loading it fully into memory.
picocalc.sound.fileplayer([bufferSize])
Section titled “picocalc.sound.fileplayer([bufferSize])”Creates a FilePlayer.
- Parameters:
bufferSize(number, optional): Internal streaming buffer size in bytes
- Returns: (userdata) FilePlayer object, or
nil, errstron failure
player:load(path)
Section titled “player:load(path)”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:
trueon success, ornil, 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.
player:setLoopRange([start [, end]])
Section titled “player:setLoopRange([start [, end]])”Sets the loop region in seconds. Omit both to loop the whole file.
player:didUnderrun()
Section titled “player:didUnderrun()”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)
trueif an underrun occurred
if player:didUnderrun() then picocalc.sys.log("Audio buffer underrun!")endplayer:setFinishCallback(fn)
Section titled “player:setFinishCallback(fn)”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)player:setLoopCallback(fn)
Section titled “player:setLoopCallback(fn)”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)player:setRate(rate) / player:getRate()
Section titled “player:setRate(rate) / player:getRate()”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 speedlocal r = player:getRate() -- returns 2.0player:setStopOnUnderrun(flag)
Section titled “player:setStopOnUnderrun(flag)”Controls whether the player automatically stops when a buffer underrun occurs.
- Parameters:
flag(boolean):trueto stop on underrun,falseto continue
player:setStopOnUnderrun(true)MP3Player
Section titled “MP3Player”Streams an MP3 file from the SD card.
picocalc.sound.mp3player()
Section titled “picocalc.sound.mp3player()”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, errstron failure
local mp3 = picocalc.sound.mp3player()mp3:load("/apps/myapp/music.mp3")mp3:play()player:load(path)
Section titled “player:load(path)”Opens an MP3 file for streaming.
- Returns:
trueon success, ornil, 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.
player:getPosition() / player:getLength()
Section titled “player:getPosition() / player:getLength()”Returns current playback position or total duration in seconds.
player:getSampleRate()
Section titled “player:getSampleRate()”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).
player:setLoop(loop)
Section titled “player:setLoop(loop)”- Parameters:
loop(boolean):trueto loop continuously