Library Lua Scripts
The floe.lua
file is the most important part of a Floe sample library. This page serves as documentation for all of the functions that you can use in your script to create and configure the library and its instruments.
Floe runs your script using Lua v5.4, providing you with access to these standard libraries: math
, string
, table
and utf8
. The other standard libraries are not available - including the require
function. This is to minimise security risks.
If there are any errors in your script, Floe will show them on the GUI along with a line number and a description of the problem.
Multiple files
dofile()
is available, so you can split your script into multiple files if you want to. Floe’s dofile
implementation is the same as the standard Lua version except that you can only specify files relative to the library folder — that is, the folder that contains the floe.lua
file.
For example, you could have a folder next to floe.lua
called Lua
and put a file in there called data.lua
. You could then load that file with dofile("Lua/data.lua")
.
To pass data between files, you would typically use the “module” pattern (except using dofile instead of require).
Library Functions
Use these functions to create your sample library. Take note of the [required]
annotations - omitting fields marked with these will cause an error.
floe.new_library
Creates a new library. It takes one parameter: a table of configuration. It returns a new library object. You should only create one library in your script. Return the library at the end of your script.
The library is the top-level object. It contains all the instruments, regions, and impulse responses.
-- Creates a new library. You should only create one library in your script.
-- Return the library at the end of your script.
local library = floe.new_library({
-- The name of the library. Keep it short and use tagline for more details.
-- [required]
name = "Iron Vibrations",
-- A few words to describe the library. [required]
tagline = "Organic sounds from resonating metal objects",
-- The URL for this Floe library.
-- [optional, default: no url]
library_url = "https://example.com/iron-vibrations",
-- A description of the library. You can be verbose and use newlines (\n).
-- [optional, default: no description]
description = "A collection of resonating metal objects sampled using a handheld stereo recorder.",
-- Who created this library. Keep it short, use the description for more
-- details. [required]
author = "Found-sound Labs",
-- URL relating to the author or their work.
-- [optional, default: ]
author_url = "https://example.com",
-- The minor version of this library - backwards-compatible changes are
-- allowed on a library; this field represents that. Non-backwards-compatibile
-- changes are not allowed: you'd need to create a new library such as:
-- "Strings 2".
-- [optional, default: 1]
minor_version = 1,
-- Path relative to this script for the background image. It should be a jpg
-- or png.
-- [optional, default: ]
background_image_path = "Images/background.jpg",
-- Path relative to this script for the icon image. It should be a square jpg
-- or png.
-- [optional, default: ]
icon_image_path = "Images/icon.png",
})
floe.new_instrument
Creates a new instrument on the library. It takes 2 parameters: the library object and a table of configuration. It returns a new instrument object. You can call this function multiple times to create multiple instruments.
An instrument is like a musical instrument. It is a sound-producing entity that consists of one or more samples (samples are specified in regions). Each library can have multiple instruments.
You can use Floe’s Tag Builder GUI to generate tag tables.
-- Creates a new instrument on the library. You can call this multiple times to
-- create multiple instruments.
local instrument = floe.new_instrument(library, {
-- The name of the instrument. Must be unique. [required]
name = "Metal Fence Strike",
-- Specify a folder to group instruments under a common heading. It may
-- contain slashes to represent a hierarchy. See
-- https://floe.audio/develop/tags-and-folders.html for more information.
-- [optional, default: no folders]
folder = "Fences/Steel",
-- A description of the instrument. Start with a capital letter an end with a
-- period.
-- [optional, default: no description]
description = "Tonal pluck metallic pluck made from striking a steel fence.",
-- An array of strings to denote properties of the instrument. See
-- https://floe.audio/develop/tags-and-folders.html for more information.
-- [optional, default: no tags]
tags = { "found sounds", "tonal percussion", "metal", "keys", "cold", "ambient", "IDM", "cinematic" },
-- Path to an audio file relative to this script that should be used as the
-- waveform on Floe's GUI.
-- [optional, default: first region path]
waveform_audio_path = "Samples/file1.flac",
})
floe.add_region
Adds a region to an instrument. It takes 2 parameters: the instrument object and a table of configuration. Doesn’t return anything. You can call this function multiple times to create multiple regions.
A region is a part of an instrument. It defines an audio file and the conditions under which it will be played. For example, you might have a region that plays the audio file Piano_C3.flac
when the note C3 is played. Each instrument must have one or more regions.
-- Adds a region to an instrument. You can call this multiple times to create
-- multiple regions. Each instrument must have one or more regions.
floe.add_region(instrument, {
-- A path to an audio file, relative to this current lua file. [required]
path = "Samples/One-shots/Resonating String.flac",
-- The pitch of the audio file as a number from 0 to 127 (a MIDI note number).
-- On a range from 0 to 127. [required]
root_key = 60,
-- How this region should be triggered.
-- [optional, default: defaults]
trigger_criteria = {
-- What event triggers this region. Must be one of: "note-on" or
-- "note-off".
-- [optional, default: note-on]
trigger_event = "note-on",
-- The pitch range of the keyboard that this region is mapped to. These
-- should be MIDI note numbers, from 0 to 128. The start number is
-- inclusive, the end is exclusive.
-- [optional, default: { 60, 64 }]
key_range = { 60, 64 },
-- The velocity range of the keyboard that this region is mapped to. This
-- should be an array of 2 numbers ranging from 0 to 100. The start number
-- is inclusive, the end is exclusive.
-- [optional, default: { 0, 100 }]
velocity_range = { 0, 100 },
-- Trigger this region only on this round-robin index. For example, if
-- this index is 0 and there are 2 other groups with round-robin indices
-- of 1 and 2 with the same round_robin_sequencing_group and
-- trigger_event, then this region will trigger on every third press of a
-- key only. round_robin_index should begin at 0 and be consecutive. The
-- total number of round-robins is calculated automatically.
-- [optional, default: no round-robin]
round_robin_index = 0,
-- Group together regions that have this same string, so that their
-- round_robin_index is part of a separate sequence to other
-- round_robin_sequencing_groups. Use this when you have multiple sets of
-- regions that have a different number of round-robins with the same
-- trigger_event.
-- [optional, default: instrument-wide group]
round_robin_sequencing_group = "group1",
-- If another region in this instrument is triggered at the same time as
-- this one and is overlapping this, and also has this option enabled,
-- then both regions will play crossfaded in a proportional amount for the
-- overlapping area, creating a smooth transition between velocity layers.
-- Only works if there's exactly 2 overlapping layers.
-- [optional, default: false]
feather_overlapping_velocity_layers = false,
-- For every region that has this same string, automatically set the start
-- and end values for each region's key range based on its root key.
-- [optional, default: no auto-map]
auto_map_key_range_group = "group1",
},
-- Loop configuration.
-- [optional, default: defaults]
loop = {
-- Define a built-in loop.
-- [optional, default: no built-in loop]
builtin_loop = {
-- The start of the loop in frames. Inclusive. It can be negative
-- meaning index the file from the end rather than the start.
-- [required]
start_frame = 24,
-- The end of the loop in frames. Exclusive. It can be negative
-- meaning index the file from the end rather than the start. 0 means
-- the end of the file. [required]
end_frame = 6600,
-- The number of frames to crossfade. [required]
crossfade = 100,
-- The mode of the loop. Must be one of: "standard" or "ping-pong".
-- [optional, default: standard]
mode = "standard",
-- If true, the start, end and crossfade values cannot be overriden by
-- a custom loop from Floe's GUI.
-- [optional, default: ]
lock_loop_points = false,
-- If true, the loop mode value cannot be overriden by a custom mode
-- from Floe's GUI.
-- [optional, default: ]
lock_mode = false,
},
-- The requirement for this region to loop. Must be one of:
-- "default" => Default looping behaviour.
-- "always-loop" => This region will always loop - either using the built
-- in loop, a user defined loop, or a default built-in loop.
-- "never-loop" => This region will never loop even if there is a
-- user-defined loop. Set all regions of an instrument to this to entirely
-- disable looping for the instrument.
-- [optional, default: default]
loop_requirement = "always-loop",
},
-- Timbre layering configuration.
-- [optional, default: no timbre layering]
timbre_layering = {
-- The start and end point, from 0 to 100, of the Timbre knob on Floe's
-- GUI that this region should be heard. You should overlap this range
-- with other timbre layer ranges. Floe will create an even crossfade of
-- all overlapping sounds. The start number is inclusive, end is
-- exclusive. This region's velocity_range should be 0-100.
-- [optional, default: no timbre layering]
layer_range = { 0, 50 },
},
-- Audio properties.
-- [optional, default: defaults]
audio_properties = {
-- Apply a gain to the audio data in decibels.
-- [optional, default: 0]
gain_db = -3,
-- The number of frames to skip at the start of the audio data.
-- [optional, default: 0]
start_offset_frames = 0,
-- Tune the audio data in cents.
-- [optional, default: 0]
tune_cents = 0,
-- The number of frames to fade in the audio data.
-- [optional, default: 0]
fade_in_frames = 0,
},
-- Playback configuration.
-- [optional, default: defaults]
playback = {
-- The requirement for keytracking. Must be one of: "default", "always" or
-- "never".
-- [optional, default: default]
keytrack_requirement = "default",
},
})
floe.add_ir
Adds an reverb impulse response to the library. It takes 2 parameters: the library object and a table of configuration. Doesn’t return anything. You can call this function multiple times to create multiple impulse responses.
-- Adds a reverb impulse response to the library. You can call this multiple times
-- to create multiple impulse responses.
floe.add_ir(library, {
-- The name of the IR. Must be unique. [required]
name = "Cathedral",
-- File path to the impulse response file, relative to this script. [required]
path = "irs/cathedral.flac",
-- Specify a folder to group IRs under a common heading. It may contain
-- slashes to represent a hierarchy. See
-- https://floe.audio/develop/tags-and-folders.html for more information.
-- [optional, default: no folders]
folder = "Cathedrals",
-- An array of strings to denote properties of the IR. See
-- https://floe.audio/develop/tags-and-folders.html for more information.
-- [optional, default: no tags]
tags = { "acoustic", "cathedral" },
-- A description of the IR. Start with a capital letter an end with a period.
-- [optional, default: no description]
description = "Sine sweep in St. Paul's Cathedral.",
})
floe.set_attribution_requirement
Sets the attribution information for a particular audio file or folder. It takes 2 parameters: a path to the file or folder whose license information you want to set, and a table of configuration. If the path is a folder, the attribution requirement will be applied to all audio files in that folder and its subfolders.
-- Sets the attribution information for a particular audio file or folder. If the
-- path is a folder, the attribution requirement will be applied to all audio
-- files in that folder and its subfolders.
floe.set_attribution_requirement("Samples/bell.flac", {
-- The title of the work. [required]
title = "Bell Strike",
-- Name of the license. [required]
license_name = "CC-BY-4.0",
-- URL to the license. [required]
license_url = "https://creativecommons.org/licenses/by/4.0/",
-- The name/identification of the persons or entities to attribute the work
-- to. [required]
attributed_to = "John Doe",
-- URL to the original work if possible.
-- [optional, default: ]
attribution_url = "https://example.com",
})
floe.set_required_floe_version
Sets the minimum required version of Floe for this library. It takes one parameter: a string representing the version number (a semantic version).
It’s best to set this at the top of your floe.lua
file so that Floe can check the version before running the script.
Calling this function is recommended so that older versions of Floe behave predictably when trying to load an unsupported library.
-- Sets the required Floe version for this library. If the current Floe version is
-- lower than the required version, an error will be raised.
floe.set_required_floe_version("0.10.3-beta+ff021fdc")
Support Function
Floe provides some additional functions to make developing libraries easier.
floe.extend_table
Extends a table with another table, including all sub-tables. It takes 2 parameters: the base table and the table to extend it with. The base table is not modified. The extension table is modified and returned. It has all the keys of the base table plus all the keys of the extended table. If a key exists in both tables, the value from the extension table is used.
Floe doesn’t have the concept of ‘groups’ like other formats like SFZ or Kontakt have. Instead, this function offers a way to apply a similar configuration to multiple regions. Alternatively, you can use functions and loops in Lua to add regions in a more dynamic way.
local group1 = {
trigger_criteria = {
trigger_event = "note-on",
velocity_range = { 0, 100 },
auto_map_key_range_group = "group1",
feather_overlapping_velocity_regions = false,
},
}
floe.add_region(instrument, floe.extend_table(group1, {
path = "One-shots/Resonating String 2.flac",
root_key = 65,
}))
floe.add_region(instrument, floe.extend_table(group1, {
path = "One-shots/Resonating String 3.flac",
root_key = 68,
}))
Lua Language Server
If you are using the Lua Language Server, you can get autocompletion and diagnostics for Floe’s Lua API by using the following configuration.
- Open Floe, and click on the 3-dot menu at the top of the window. Click “Library Developer Panel” and open the “Utilities” tab.
- Click on the “Install Lua definitions” button. This will generate the necessary file on your system.
- For the Lua LSP to find the definitions, you need to create a
.luarc.json
file in the same folder as yourfloe.lua
file. - Paste the following code into the
.luarc.json
file:
{
"workspace": {
"library": [
"<< paste definitions file path >>"
]
},
}
- Replace the string with the path that is copied to your clipboard when you click the “Copy Lua definitions path” button in the Library Developer Panel.
- Done.
Lua LSP Definitions
This file is also generated by the “Install Lua definitions” button in the Library Developer Panel.
---@meta FloeAPI
---@class FloeLibraryConfig
---@field name string The name of the library. Keep it short and use tagline for more details.
---@field tagline string A few words to describe the library.
---@field library_url? string The URL for this Floe library.
---@field description? string A description of the library. You can be verbose and use newlines (\n).
---@field author string Who created this library. Keep it short, use the description for more details.
---@field author_url? string URL relating to the author or their work.
---@field minor_version? number The minor version of this library - backwards-compatible changes are allowed on a library; this field represents that. Non-backwards-compatibile changes are not allowed: you'd need to create a new library such as: "Strings 2".
---@field background_image_path? string Path relative to this script for the background image. It should be a jpg or png.
---@field icon_image_path? string Path relative to this script for the icon image. It should be a square jpg or png.
---@class FloeInstrumentConfig
---@field name string The name of the instrument. Must be unique.
---@field folder? string Specify a folder to group instruments under a common heading. It may contain slashes to represent a hierarchy. See https://floe.audio/develop/tags-and-folders.html for more information.
---@field description? string A description of the instrument. Start with a capital letter an end with a period.
---@field tags? string[] An array of strings to denote properties of the instrument. See https://floe.audio/develop/tags-and-folders.html for more information.
---@field waveform_audio_path? string Path to an audio file relative to this script that should be used as the waveform on Floe's GUI.
---@class FloeImpulseResponseConfig
---@field name string The name of the IR. Must be unique.
---@field path string File path to the impulse response file, relative to this script.
---@field folder? string Specify a folder to group IRs under a common heading. It may contain slashes to represent a hierarchy. See https://floe.audio/develop/tags-and-folders.html for more information.
---@field tags? string[] An array of strings to denote properties of the IR. See https://floe.audio/develop/tags-and-folders.html for more information.
---@field description? string A description of the IR. Start with a capital letter an end with a period.
---@class FloeBuiltinLoopConfig
---@field start_frame number The start of the loop in frames. Inclusive. It can be negative meaning index the file from the end rather than the start.
---@field end_frame number The end of the loop in frames. Exclusive. It can be negative meaning index the file from the end rather than the start. 0 means the end of the file.
---@field crossfade number The number of frames to crossfade.
---@field mode? "standard"|"ping-pong" The mode of the loop.
---@field lock_loop_points? boolean If true, the start, end and crossfade values cannot be overriden by a custom loop from Floe's GUI.
---@field lock_mode? boolean If true, the loop mode value cannot be overriden by a custom mode from Floe's GUI.
---@class FloeRegionLoopConfig
---@field builtin_loop? FloeBuiltinLoopConfig Define a built-in loop.
---@field loop_requirement? "default"|"always-loop"|"never-loop" The requirement for this region to loop.
---@class FloeRegionAudioPropsConfig
---@field gain_db? number Apply a gain to the audio data in decibels.
---@field start_offset_frames? number The number of frames to skip at the start of the audio data.
---@field tune_cents? number Tune the audio data in cents.
---@field fade_in_frames? number The number of frames to fade in the audio data.
---@class FloeRegionTimbreLayeringConfig
---@field layer_range? number[] The start and end point, from 0 to 100, of the Timbre knob on Floe's GUI that this region should be heard. You should overlap this range with other timbre layer ranges. Floe will create an even crossfade of all overlapping sounds. The start number is inclusive, end is exclusive. This region's velocity_range should be 0-100.
---@class FloeRegionPlaybackConfig
---@field keytrack_requirement? "default"|"always"|"never" The requirement for keytracking.
---@class FloeTriggerCriteriaConfig
---@field trigger_event? "note-on"|"note-off" What event triggers this region.
---@field key_range? number[] The pitch range of the keyboard that this region is mapped to. These should be MIDI note numbers, from 0 to 128. The start number is inclusive, the end is exclusive.
---@field velocity_range? number[] The velocity range of the keyboard that this region is mapped to. This should be an array of 2 numbers ranging from 0 to 100. The start number is inclusive, the end is exclusive.
---@field round_robin_index? number Trigger this region only on this round-robin index. For example, if this index is 0 and there are 2 other groups with round-robin indices of 1 and 2 with the same round_robin_sequencing_group and trigger_event, then this region will trigger on every third press of a key only. round_robin_index should begin at 0 and be consecutive. The total number of round-robins is calculated automatically.
---@field round_robin_sequencing_group? string Group together regions that have this same string, so that their round_robin_index is part of a separate sequence to other round_robin_sequencing_groups. Use this when you have multiple sets of regions that have a different number of round-robins with the same trigger_event.
---@field feather_overlapping_velocity_layers? boolean If another region in this instrument is triggered at the same time as this one and is overlapping this, and also has this option enabled, then both regions will play crossfaded in a proportional amount for the overlapping area, creating a smooth transition between velocity layers. Only works if there's exactly 2 overlapping layers.
---@field auto_map_key_range_group? string For every region that has this same string, automatically set the start and end values for each region's key range based on its root key.
---@class FloeFileAttributionConfig
---@field title string The title of the work.
---@field license_name string Name of the license.
---@field license_url string URL to the license.
---@field attributed_to string The name/identification of the persons or entities to attribute the work to.
---@field attribution_url? string URL to the original work if possible.
---@class FloeRegionConfig
---@field path string A path to an audio file, relative to this current lua file.
---@field root_key number The pitch of the audio file as a number from 0 to 127 (a MIDI note number).
---@field trigger_criteria? FloeTriggerCriteriaConfig How this region should be triggered.
---@field loop? FloeRegionLoopConfig Loop configuration.
---@field timbre_layering? FloeRegionTimbreLayeringConfig Timbre layering configuration.
---@field audio_properties? FloeRegionAudioPropsConfig Audio properties.
---@field playback? FloeRegionPlaybackConfig Playback configuration.
---@class floe
floe = {}
-- Creates a new library. You should only create one library in your script.
-- Return the library at the end of your script.
---@param config FloeLibraryConfig
---@return lightuserdata library
function floe.new_library(config) end
-- Creates a new instrument on the library. You can call this multiple times to
-- create multiple instruments.
---@param library lightuserdata
---@param config FloeInstrumentConfig
---@return lightuserdata instrument
function floe.new_instrument(library, config) end
-- Adds a region to an instrument. You can call this multiple times to create
-- multiple regions. Each instrument must have one or more regions.
---@param instrument lightuserdata
---@param config FloeRegionConfig
function floe.add_region(instrument, config) end
-- Adds a reverb impulse response to the library. You can call this multiple times
-- to create multiple impulse responses.
---@param library lightuserdata
---@param config FloeImpulseResponseConfig
function floe.add_ir(library, config) end
-- Sets the attribution information for a particular audio file or folder. If the
-- path is a folder, the attribution requirement will be applied to all audio
-- files in that folder and its subfolders.
---@param file_path string
---@param config FloeFileAttributionConfig
function floe.set_attribution_requirement(file_path, config) end
-- Sets the required Floe version for this library. If the current Floe version is
-- lower than the required version, an error will be raised.
---@param version_string string
function floe.set_required_floe_version(version_string) end
-- Extends a table with another table, including all sub-tables. The base table is
-- not modified. The extension table is modified and returned with all keys from
-- both tables. If a key exists in both, the extension table value is used.
---@param base_table table
---@param t table
---@return table extended_table
function floe.extend_table(base_table, t) end
_G.floe = floe