Lua logo

Preface

This is the reference manual of MoonSndFile, which is a Lua binding library for Erik de Castro Lopo’s libsndfile. [1]

It is assumed that the reader is familiar with both libsndfile and the Lua programming language.

For convenience of reference, this document contains external (deep) links to the Lua Reference Manual and to the libsndfile API documentation.

Getting and installing

For installation intructions, refer to the README file in the MoonSndFile official repository on GitHub.

Module organization

The MoonSndFile module is loaded using Lua’s require() and returns a table containing the functions it provides (as usual with Lua modules). This manual assumes that such table is named sf, i.e. that it is loaded with:

 sf = require("moonsndfile")

but nothing forbids the use of a different name.

Examples

Complete examples can be found in the examples/ directory of the release package.

License

MoonSndFile is released under the MIT/X11 license (same as Lua, and with the same only requirement to give proper credits to the original author). The copyright notice is in the LICENSE file in the base directory of the official repository on GitHub.

See also

MoonSndFile is part of MoonLibs, a collection of Lua libraries for graphics and audio programming.

Introduction

MoonSndFile is an (almost) one-to-one Lua binding library to libsndfile. It provides means to implement scripted libsndfile-based applications using Lua instead of C or C++, with all its pros and cons.

This section gives a brief overview, while the details of the bindings are given in the sections that follow.

As a general rule, libsndfile API functions are bound to by MoonSndFile functions with almost the same names of the original ones, apart from being members of the sf table (for example, sf_open( ) is bound to by sf.open( )).

Libsndfile commands are mapped to functions with names that usually are derived from the command name (e.g. sf_command(SFC_SET_NORM_FLOAT) is mapped to the Lua function sf.set_norm_float( )).

If not stated otherwise, on error MoonSndFile functions raise a Lua error. If needed, this behaviour can be overridden by wrapping function calls in the standard Lua pcall( ).

MoonSndFile binds SNDFILE objects (the only object type in this library) to Lua userdata, which are returned by the opening function (e.g. sf.open( )) and are then used to refer to sndfile objects in Lua in the same way as one would use SNDFILE handles in C.

sndfile objects are garbage collected at exit (which includes on error), and automatically closed at the libsndfile level, so there is no need to explicitly invoke sf.close( ) at exit for cleanup.

Apart from at exit, however, sndfile objects are not automatically garbage collected [2] and one must close and delete them explicitly when needed, e.g. to release resources when the application is not exiting and the some sndfile objects are no longer needed.

Libsndfile structs (and lists, and arrays) used to pass parameters and results across the libsndfile API are mapped in MoonSndFile to tables, having more or less the same contents as their C counterparts, while enumerations are mapped to/from sets of string literals. More details are given in the respective sections of this document (structs, enums).

In addition to the bindings to the libsndfile API, which are described in the sections that follow, MoonSndFile also provides a few other utilities. These are described mainly in the 'Miscellanea' subsections.

Bindings

Open and close

  • sndfile, fileinfo = open(path, openmode, [fileinfo])
    Returns the newly created sndfile object followed by its updated fileinfo.
    The fileinfo argument is required for the 'raw' format and/or if openmode='w' (write) to specify the file format, the sample rate, and the number of channels. The format may be specified either:
    1) by setting the fileinfo.code field to a valid integer encoding the major format, the subformat, and the endianness, or
    2) by setting separately the fileinfo.format, the fileinfo.subformat and optionally the fileinfo.endianness fields with valid literal values.
    In the first case, the fields listed in the second case are not needed, but if present they must match the values encoded in the code field.
    In both cases, all other fields apart from fileinfo.samplerate and fileinfo.channels are ignored.
    The fileinfo argument must not be passed when opening a non-raw file in 'r' or 'rw' mode.
    Rfr: sf_open.

  • sndfile, fileinfo = open_fd(fd|fh, openmode, [fileinfo], [closedesc])
    Same as open( ), but loads the sound file from an already open file instead of opening one.
    The file can be specified either by passing a valid integer file descriptor (fd), or by passing a valid Lua file handle (fh).
    The optional closedesc parameter (close the file descriptor) deafults to false.
    Rfr: sf_open_fd.

The current, updated, fileinfo (SF_INFO) table for a sndfile object can be retrieved at any time with the following function:

Alternatively, the individual fileinfo attributes can be retrieved with the following methods of the sndfile object:

  • format = sndfile:format( )

  • subformat = sndfile:subformat( )

  • endianness = sndfile:endianness( )

  • integer = sndfile:code( )

  • integer = sndfile:samplerate( )

  • integer = sndfile:channels( )

  • integer = sndfile:frames( )

  • integer = sndfile:sections( )

  • boolean = sndfile:seekable( )

Seek

  • offset = seek(sndfile, frames, whence)
    Returns nil followed by a string error message if a seek error occurred, i.e. if sf_seek( ) returned -1.
    Rfr: sf_seek.

Write sync

Read and write

  • data, nframes = read(sndfile, type, frames)
    frames: integer (number of frames to read).
    Returns the frame data as a binary string, followed by the number of frames actually read.
    Returns nil, 0 if no data was read (end of file).
    Rfr: sf_readf_xxx.

  • nframes, frames = write(sndfile, type, data)
    data: binary string (frame data to write).
    The length of data must be an integer multiple of the length of a frame (sizeof(type) times the no. of channels).
    Returns the number of frames actually written, followed by the number of frames that were contained in data.
    Rfr: sf_writef_xxx.

R/W control

  • boolean = get_clipping(sndfile)
    set_clipping(sndfile, boolean)
    Rfr: SFC_SET_CLIPPING.

  • boolean = get_norm_float(sndfile)
    set_norm_float(sndfile, boolean)
    Rfr: SFC_SET_NORM_FLOAT.

  • boolean = get_norm_double(sndfile)
    set_norm_double(sndfile, boolean)
    Rfr: SFC_SET_NORM_DOUBLE.

Raw R/W

  • data = read_raw(sndfile, bytes)
    Returns the read data as a binary string.
    Rfr: sf_read_raw.

  • bytes = write_raw(sndfile, data)
    data: binary string (data to write)
    Returns the number of bytes actually written (may be less than the length of data).
    Rfr: sf_write_raw.

Format info

Note
In libsndfile, the SF_FORMAT_INFO struct is used to convey information about formats as well as subformats and simple formats. In MoonSndFile, instead, three different structs are used: formatinfo, subformatinfo, and simpleformat, respectively.

All three structs contain an integer code field, which is the format code as defined in sndfile.h (in particular, the code of a simpleformat encodes major format, subformat, and endianness and thus can be used in the fileinfo.code field when opening a file).

The formatinfo struct is enhanced with the subformats field which is a list of all the subformats supported by the format it refers to.

Signal info

Metadata

  • set_chunk(sndfile, chunk)
    {chunk} = get_chunks(sndfile, [id])
    Rfr: sf_set_chunk, get_chunk_iterator.

  • {channelmap} = get_channel_map_info(sndfile)
    set_channel_map_info(sndfile, {channelmap})
    Rfr: SFC_GET_CHANNEL_MAP_INFO, SFC_SET_CHANNEL_MAP_INFO.

Structs

fileinfo = {
code: integer,
format: format,
subformat: subformat,
endianness: endianness,
samplerate: integer,
channels: integer,
frames: integer,
sections: integer,
seekable: boolean,
} (Rfr: SF_INFO).

formatinfo = {
format: format,
code: integer,
name: string,
extension: string,
subformats: {subformatinfo},
} (Rfr: SF_FORMAT_INFO).

subformatinfo = {
subformat: subformat,
code: integer,
name: string,
} (Rfr: SF_FORMAT_INFO).

simpleformat = {
code: integer,
name: string,
extension: string,
} (Rfr: SF_FORMAT_INFO).

chunk = {
id: binary string (length ⇐64),
data: binary string,
} (Rfr: SF_CHUNK_INFO).

Enums

LibSndFile enums are mapped in MoonSndFile to sets of string literals (as is customary in Lua). Admitted literals are available in the sf table (e.g. sf.FORMAT_XXX for SF_FORMAT_XXX), and can also be inferred from the corresponding C enum names. For example, given the sf.FORMAT_XXX hint for the format enum type, the literals it admits are obtained by lowercasing the XXX part of the name and replacing any underscore with a space.

If needed, the following function can be used to obtain the list of literals admitted by a particular enum type.

  • {literal} = sf.enum(enumtype)
    Returns a table listing the literals admitted by enumtype (given as a string, e.g. 'format', 'subformat', etc).

Below is the list of the enum types, each with its hint, the list of string values it admits.

bitratemode: sf.BITRATE_MODE_XXX
Values: 'constant', 'average', 'variable'.

channelmap: sf.CHANNEL_MAP_XXX
Values: 'invalid', 'mono', 'left', 'right', 'center', 'front left', 'front right', 'front center', 'rear center', 'rear left', 'rear right', 'lfe', 'front left of center', 'front right of center', 'side left', 'side right', 'top center', 'top front left', 'top front right', 'top front center', 'top rear left', 'top rear right', 'top rear center', 'ambisonic b w', 'ambisonic b x', 'ambisonic b y', 'ambisonic b z'.

endianness: sf.ENDIAN_XXX
Values: 'file', 'little', 'big', 'cpu'.

format: sf.FORMAT_XXX
Values: 'wav', 'aiff', 'au', 'raw', 'paf', 'svx', 'nist', 'voc', 'ircam', 'w64', 'mat4', 'mat5', 'pvf', 'xi', 'htk', 'sds', 'avr', 'wavex', 'sd2', 'flac', 'caf', 'wve', 'ogg', 'mpc2k', 'rf64', 'mpeg'.

loopmode: sf.LOOP_XXX
Values: 'none', 'forward', 'backward', 'alternating'.

openmode: sf.SFM_XXX
Values: 'r', 'w', 'rw'.

stringtype: sf.STR_XXX
Values: 'title', 'copyright', 'software', 'artist', 'comment', 'date', 'album', 'license', 'tracknumber', 'genre'.

subformat: sf.FORMAT_XXX
Values: 'pcm s8', 'pcm 16', 'pcm 24', 'pcm 32', 'pcm u8', 'float', 'double', 'ulaw', 'alaw', 'ima adpcm', 'ms adpcm', 'gsm610', 'vox adpcm', 'g721 32', 'g723 24', 'g723 40', 'dwvw 12', 'dwvw 16', 'dwvw 24', 'dwvw n', 'dpcm 8', 'dpcm 16', 'vorbis', 'alac 16', 'alac 20', 'alac 24', 'alac 32', 'nms adpcm 16', 'nms adpcm 24', 'nms adpcm 32', 'opus', 'mpeg layer i', 'mpeg layer ii', 'mpeg layer iii'.

type: -
Values: 'short', 'int', 'float', 'double'.

whence: sf.SEEK_XXX
Values: 'set', 'cur', 'end', 'set r', 'cur r', 'end r', 'set w', 'cur w', 'end w'.

Miscellanea

Version handling

The sf table contains the following version related information:

  • sf._VERSION: MoonSndFile version (a string).

To retrieve the version of the libsndfile runtime (libsndfile.so) use the following functions:

  • version = version_string( )
    major, minor, patch = version_number( )
    Rfr: sf_version_string.

Data handling

This section describes additional utilities that can be used to encode data from Lua variables to binary strings and viceversa.

  • val1, …​, valN = flatten(table)
    Flattens out the given table and returns the terminal elements in the order they are found.
    Similar to Lua’s table.unpack( ), but it also unpacks any nested table. Only the array part of the table and of nested tables is considered.

  • {val1, …​, valN} = flatten_table(table)
    Same as flatten( ), but returns the values in a flat table. Unlike flatten( ), this function can be used also with very large tables.

  • size = sizeof(type)
    Returns the size in bytes of the given type.

  • data = pack(type, val1, …​, valN)
    data = pack(type, table)
    Packs the numbers val1, …​, valN, encoding them according to the given type, and returns the resulting binary string.
    The values may also be passed in a (possibly nested) table. Only the array part of the table (and of nested tables) is considered.

  • {val1, …​, valN} = unpack(type, data)
    Unpacks the binary string data, interpreting it as a sequence of values of the given type, and returns the extracted values in a flat table.
    The length of data must be a multiple of sizeof(type).

Tracing utilities

  • trace_objects(boolean)
    Enable/disable tracing of objects creation and destruction (which by default is disabled).
    If enabled, a printf is generated whenever an object is created or deleted, indicating the object type and the value of its raw LibSndFile handle.


1. This manual is written in AsciiDoc, rendered with AsciiDoctor and a CSS from the AsciiDoctor Stylesheet Factory.
2. Objects are anchored to the Lua registry at their creation, so even if the script does not have references to an object, a reference always exists on the registry and this prevents the GC to collect it.