Lua scripting with modules

TILT!Audio features a lua runtime 5.2 to control additional extensions like shakers, LED-lights and also servos.

To make this possible TILT!Audio firmware embeds a lua runtime (lua virtual machine) and loads a “init.lua” script from the sound directory.

The init.lua script already has access to all core lua language features and also the TILT!Audio bindings see lua reference. The binding allows access to the sound engine, communicate via i2c, logging messages and get information about the current installation.

Lua in its language ecosystem also offers modules and package managers that allows installing and managing modules that extend lua features. One of this package managers is luarocks.


Using luarocks as package manager to install a new module together with TILT!Audio is not so straight forward as you can read it on most websites, because the linux running on a TILT!Audio card is tailored down to a minimum to run as efficient as it should to produce sound and nothing else.

What is missing for example is a c compiler that most lua modules require as they come as a combination of lua code and c code.

Also luarocks requires a certain directory structure that is aware of the different lua versions and different places in the system where the lua runtime should look for “modules” (which is *.so and *.lua files).

The TILT!Audio start script does set the required environment variables to let lua runtime find modules, but still not in that way that a module installed by luarocks would expect.

Continue reading “Lua scripting with modules”

Lua Reference

Important notes

Please make sure you did not switch lua off in the config otherwise it will not work.

Also if you already have a license make sure it includes the lua runtime. Check the logfile and look out init.lua gets searched and loaded and for your lua functions being called when you trigger tests.

See the lua example videos on my youtube channel: e.g.

Global variabels

config: all the main config parameters from the raspisound.ini file as lua table. That means you can access it like config.say_version.

version: the version of the TILT!Audion firmware as string. e.g. “1.29”

musicPlayingId: the number of the currently playing background music (or 0 if none).

effectiveVolume: the effectiveVolume (overall volume).


playSound(id, volume, index): play a sound effect (or background music) from sound pack.
id: the sound effect id.
volume (optional): if set (0-30) override the standard volume from sound pack and play with given volume.
index (optional): if set, use a specfic sound file for the effect. This is only relevant, when the sound pack defines more than one sound file for this effect.

getSound( id ): returns a lua table (or nil) for the sound effect with given id. the lua table contains the properties:
name: the name of the sound effect.
samples: number if sound files for the effect (normally 1).
type: 1-6 depending on sound type: music, voice, effect ..
command: string if the effect has an command attached

getCurrentSoundPack(): returns the current sound pack as lua table.

port( pinNumber, value): set port to high or low. pinNumber is one of the valid Raspberry Pi pins the can be used for output (basically the shaker pin) or 100-115 for port extender pins. value = 0 -> LOW output, value != 0 -> HIGH output.

portseq( pinNumber, time1, time2, … ): queue a sequence of HIGH, LOW changes for a GPIO pin. pinNumber see above. time1, time2 … define the intervals in milliseconds, that will make the output go HIGH-LOW-HIGH …

send( command ): send a string command to attached device (either serial or via TCP, depending on config). Can be used with the serial media server.

sendI2C( deviceAdress, reg, data): send a command to an attached i2c device. deviceAddress is 1 Byte device address on i2c bus. reg is 1 byte register number, data is one byte data to write to register.

sendI2CW( deviceAdress, reg, data): send a command to an attached i2c device. deviceAddress is 1 Byte device address on i2c bus. reg is 1 byte register number, data is two byte data to write to register.

readI2C( deviceAdress, reg): read data from an n I2C device and returns an int.

log( logLevel, message ): logs a message into main logfile. logLevel: 1=ERROR up to 4=DEBUG, message a string with log message. NOTE: normal print output will also go to the logfile if DEBUG is switched on.

setVolume( newVolume ): set a new volume, value 0-100

decVolume(): decrease volume

incVolume(): increase volume

nextSoundSet(): cycle through installed sound packs

restart(): restart TILT!Audio firmware

reboot(): reboot the raspberry pi completely

pauseMusic(): pause background music

resumeMusic( ms ): resume pause background music and fade back in ms = milli seconds

stopMusic(): stops background music

fadeMusic( milliSeconds ): fades background music in milliSeconds

fadeOutSfx( milliSeconds): fades out sfx sounds in milliSeconds

fadeOutVoice( milliSeconds): fades out voice sounds in milliSeconds

fadeOutAllEffects( milliSeconds): fades out both woice and sfx in milliSeconds

stopAllSamples(): stops all running sound effects other than background music

omx player commands (beta)

omxPause(): pause player playback

omxAction( action ): perform an action on player. action numbers see OMXControl.h

omxSetPos( pos ): set playback position absolute in milli seconds

omxStop(): stop player playback

omxPlay( file ): play a new file

omxGetPos(): get the current playing pos in milli seconds.

omxGetStatus(): return current player status: 0 = pause, 1 = playing

Handlers (beta)

There are two special lua functions in your script recognized at startup. They are called handlers. Just put a function named timer or eventHandler and it will be called like described:

timer( millis ): this function gets called every milli second (approximately). It is run in the main loop of TILT!Audio firmware (will be changed maybe), so don’t block anything and keep the function short and fast.

eventHander( stringMessage): it the event handler feature is enabled with TILT!Audio, every time the firmware receives an event, the function gets called.

New firmware 1.29 with lua scripting

The new version of TILT!Audio firmware features better support for altsound sound packs and lua scripting support.

What is lua scripting?

In previous version there were already some command attached to a sound effect, either to control an attached shaker or the new port extender starting with 1.28 to control up to 16 additional GPIO ports directly with the TILT!Audio board.

Now lua scripting takes this to the next level. A command attached to a sound effect is per default simply passed to a lua script interpreter (see Lua script is a super easy to learn script language that lets you “program” what should happen when a certain sound effect gets played.

So everything you can do with special commands (control shaker, control GPIO, control serial media server, control various i2c devices e.g. ProMiniExtender) you can now also do with lua functions. Addtionally you can play additional sound effects or change volume all controlled by your lua script.

In order to make this work, TILT!Audio loads a lua script at startup (init.lua) that is located at the root directory of your sound pack, where you define all functions your going to use with your sound effects.


Lets make an example:

Now in the webUI choose the sound effect that should trigger the shaking …

As you can see the shakeOnMultiball checks which background music is playing and activates the shaker only if a certain music is playing. But this is just an example.

From lua you also can control custom sound playback:

Example: use a dummy sound file that actually contains only a second silence, but triggers a lua function:

In this example we use addtional sound effect ids 1000-1004 and 1010 that the game normally don’t use (choose an arbitray high number). We create a matching row in altsound.csv (or directory in classic dir structure) and put the WAV files there.

The we call the lua functions like shown above and we will hear a random sound with the first function while the drain ball counter is increased. If playLooser sound triggers we play a “looser” sound if the was to many drained balls.

Of course this example requires the game to send the right trigger sounds when ball passes e.g. the outlane.

Tutorial video

I recorded a short video to demonstrate, what you can do with lua scripting. This will also be shown with light controller in my MSF later this month.

Tutorial video for lua scripting

Lua reference (all TILT!Audio lua functions and variables) can be found here.