Library Lua Scripts

This document describes the functions you can use in your sample library’s floe.lua script to create and configure the library and its instruments.

Floe runs your script using Lua v5.4. You have access to some of Lua’s 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.

Library Functions

Use these functions to create your sample library. Take note of the [required] annotations - omitting these fields 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.

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.
    -- [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.

local instrument = floe.new_instrument(library, {
    -- The name of the instrument. Must be unique. [required]
    name = "Metal Fence Strike",

    -- Words separated by slashes used to hierarchically categorise the 
    -- instrument.
    -- [optional, default: no folders]
    folders = "Fences/Steel",

    -- A description of the instrument.
    -- [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.
    -- [optional, default: no tags]
    tags = { "Pluck", "Metallic", "Organic" },

    -- 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.

floe.add_region(instrument, {
    -- The file for this region. [required]
    file = {
        -- 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,

        -- The region of the file that can be looped. It should be an array: 3 
        -- integers and 1 boolean: { start, end, crossfade, is_ping_pong boolean 
        -- }. Note that the end number is not inclusive. The start and end numbers 
        -- can be negative meaning they index the file from the end rather than 
        -- the start. For example, -1 == number_frames_in_file, -2 == 
        -- (number_frames_in_file - 1), etc.
        -- [optional, default: no loop]
        loop = { 24, 6600, 100, false },
    },

    -- 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 127. Note that the end number is 
        -- not inclusive.
        -- [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 first number 
        -- represents the start of the velocity range and the second number 
        -- represents 1-past the end of the range.
        -- [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, then this region will trigger on every third press of a key 
        -- only.
        -- [optional, default: no round-robin]
        round_robin_index = 0,
    },

    -- Additional options for this region.
    -- [optional, default: defaults]
    options = {
        -- 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 overlay this range 
        -- with other timbre_crossfade_regions. Floe will create an even crossfade 
        -- of all overlapping sounds. Note that the end number is not inclusive.
        -- [optional, default: no timbre-crossfade]
        timbre_crossfade_region = { 0, 50 },

        -- For every region that matches this group, automatically set the start 
        -- and end values for each region's key range based on its root key. Only 
        -- works if all region's velocity range are the same.
        -- [optional, default: no auto-map]
        auto_map_key_range_group = "group1",

        -- If another region is triggered at the same time as this one and is 
        -- overlapping this, then both regions will play crossfaded together. This 
        -- smooths the transitions between velocity layers.
        -- [optional, default: false]
        feather_overlapping_velocity_regions = false,
    },
})

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.

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",

    -- An array of strings to denote properties of the IR.
    -- [optional, default: no tags]
    tags = { "Cathedral", "Bright" },
})

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. This is necessary if your library contains samples created by different people (licensed under CC BY, for example). 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",
})

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 },
    },
    options = {
        auto_map_key_range_group = "group1",
        feather_overlapping_velocity_regions = false,
    },
}

floe.add_region(instrument, floe.extend_table(group1, {
    file = {
        path = "One-shots/Resonating String 2.flac",
        root_key = 65,
    },
}))

floe.add_region(instrument, floe.extend_table(group1, {
    file = {
        path = "One-shots/Resonating String 3.flac",
        root_key = 68,
    },
}))