LV2 Atoms: a Data Model for Real-Time Audio Plugins
Total Page:16
File Type:pdf, Size:1020Kb
LV2 Atoms: A Data Model for Real-Time Audio Plugins David E. Robillard School of Computer Science, Carleton University 1125 Colonel By Drive Ottawa ON K1S 5B6 Canada [email protected] Abstract still designed around flat commands, which limits This paper introduces the LV2 Atom extension, a simple their ability to express structured data. yet powerful data model designed for advanced control This paper introduces the LV2 Atom extension, of audio plugins or other real-time applications. At the a simple yet powerful data model designed for ad- most basic level, an atom is a standard header followed vanced control of LV2 plugins or other real-time ap- by a sequence of bytes. A standard type model can be plications. Atoms serve both as a model for repre- used for representing structured data which is meaning- senting state, and a protocol for accessing or ma- ful across projects. Atoms are currently used by sev- nipulating it. This includes simple values such as eral projects for various applications including state per- numeric controllers or sample file names, but the sistence, time synchronisation, and network-transparent plugin control. Atoms are intended to form the basis model-based approach allows developers to work of future standard protocols to increase the power of with more sophisticated data as well. host:plugin, plugin:plugin, and UI:plugin interfaces. The key distinction between atoms and MIDI or OSC messages is that atoms are not just com- Keywords mands, but a general data format. This paper aims to show that building on the foundation of a solid data LV2, plugin, data, state, protocol model is more elegant and powerful than command- based protocols like MIDI or OSC. The idea is 1 Introduction conceptually similar to the popular use of JSON LV2 is a portable plugin standard for audio systems, [Crawford, 2006] in the web community: define similar in scope to LADSPA, VST, AU, and others. a simple data model for representing information, It defines a C API for code and a format for data then construct messages within that data model. files which collectively describe a plugin. The core However, atoms are not introduced to the exclu- LV2 API is similar in power to LADSPA, but exten- sion of other protocols. In fact, MIDI messages sions can support more advanced functionality. This are transmitted to and from plugins as a particular allows the interface to evolve and accommodate the type of atom. At the lowest level, atoms are sim- needs of real software as they arise. ply a binary blob with a standard header. On top of LV2 is supported by many applications, in- this, a type model is defined which allows complex cluding Digital Audio Workstations like Ardour structures to be built from a few standard primitive [Davis and others, 2014], hardware effects proces- and container types. This model has several advan- sors like MOD [Ceccolini and Germani, 2013], and tages, including extensibility, support for round-trip signal processing languages like Faust [Graf,¨ 2013]. portable serialisation, and natural expression in plu- One key piece of functionality LV2 adds to gin data files. LADSPA is the ability to transmit events. This There are two aspects to the LV2 atom specifica- is most commonly used to communicate via MIDI tion: the low-level mechanics (Section 2) define the [MID, 1983] for playing notes, selecting programs, binary format of atoms and how they may be used, etc. MIDI is nearly ubiquitous in musical equip- while the high-level semantics (Section 3) define a ment, but has significant limitations [Moore, 1988]. type model built upon this simple binary format. Many applications require a more powerful model Using this model, projects can communicate mean- to both express and manipulate state. To take a sim- ingful structures at a conceptually high level, while ple yet common example, MIDI has no standard the actual mechanics involved are simply the copy- way to express “load sample /media/bonk.wav”. ing of small binary blobs. This approach to plugin Other protocols like OSC [Wright, 1997] have at- control has many applications (Section 4) in cur- tempted to address the limitations of MIDI, but are rent projects, which typically use the provided con- venience APIs for reading and writing atoms (Sec- Input logistics are straightforward: the host con- tion 5) with ease. Ultimately, atoms are intended to nects the input to an atom before calling the plugin’s form the basis of future work (Section 6) designing process() method. standard protocols for advanced plugin control. Outputs are slightly trickier since the plugin must know how much space is available for writing, but 2 Mechanics atom types may have variable size. To resolve this, the host initialises the size field in the output 2.1 Atom Definition buffer to the amount of available space before call- An LV2 atom is a 64-bit aligned chunk of memory ing process(). Plugins read this value, then write that begins with a 32-bit size and type: a complete atom (including size and type) to the buffer before returning. typedef struct{ Thus far, atoms have been described without re- uint32_t size; ferring to specific types. An AtomPort can be con- uint32_t type; nected to any value, but since plugins process sig- } LV2_Atom; nals over a block of time, it is usually more use- ful for ports to contain many time-stamped atoms, atom header This is immediately followed by the or events. To achieve this, ports are connected to a body which is size bytes long. Atoms are, by defi- Sequence atom. This is the mechanism commonly nition, Plain Old Data (POD): contiguous chunks of 1 used by LV2 plugins to process streams of sample- memory that can safely be copied bytewise. At the accurate MIDI messages alongside audio. The fol- most basic level, this is all there is to atoms. lowing section describes the set of standard atom Types are assigned dynamically and not restricted types, which includes simple types like Int and to any fixed set. Developers can define new atom containers like Sequence. types, though all types are required to be POD. Any atom can thus be copied or stored, even by an im- 3 Semantics plementation which does not understand its type. 3.1 Atom Types Among other advantages, this makes it possible for The structure of the atom type model is hosts to transmit atoms between plugins without ex- similar to JSON values or ERLANG terms plicitly supporting each type used. Developers are [Virding et al., 1996]: a few primitive types, and free to send complex data between plugins, or be- collections which can be used to build larger tween UIs and plugins, without being held back by structures. The hierarchy of standard types defined lacking standards or host support. Section 3.3 ex- in the atom extension2 is shown in Figure 1. plains in detail how this decentralised extensibility Primitives represent a single value, and do not is achieved. contain other atoms. The simplest types are prim- Note, however, that atoms are only POD by defi- itives with fixed size, like Int. These types have nition, not necessarily portable: atoms may contain a corresponding C struct defined in atom.h which architecture-specific data like integers with native completely describes their binary format, for exam- endianness. The atom specification includes a set ple: of standard types which should be used when per- sistence or interoperability are important (see Sec- typedef struct{ tion 3.1). LV2_Atom atom; int32_t body; 2.2 Communication via Ports } LV2_Atom_Int; Plugins can send or receive atoms via an AtomPort A URID is a URI which has been mapped to a which (like any LV2 port) is either an input or an 32-bit integer by the host. This facility allows URIs output. An AtomPort is connected directly to an to be used conceptually, but with the performance of LV2 Atom (just as a standard LADSPA or LV2 con- fixed-size integers (Section 3.3 explains the purpose trol port is connected directly to a float). of URIDs in more detail). An AtomPort can be used with any atom type. Other primitive types have variable size. String Plugins specify which types are supported using the and Literal represent raw strings and string lit- atom:bufferType property in their data files. Sev- erals with a datatype or language, respectively. A eral types may be supported by a single port. Chunk contains an opaque binary blob of data. 1 Type 0 has been reserved for a special reference type, in 2 There is also a standard type for MIDI messages defined case a need for non-POD communication arises in the future. in the separate LV2 MIDI extension. Atom 3.2 Portable Serialisation Bool In addition to a binary format, each atom type has a portable serialisation. This allows implementa- Chunk tions (typically hosts) to convert atoms to and from text for portable storage, network transmission, or Literal human readability. This format is used to describe URID atoms in the following sections, but it is important to keep in mind that plugins work with atoms in their Number native binary form. Double Most primitive types are associated with XSD [W3C, 2004b] datatypes which define their textual Float format. Table 1 shows this mapping along with an Int example string. URID is omitted since the portable serialisation of a URID is a URI. Long Atom XSD Example String Bool boolean true Chunk base64Binary vu/erQ== URI Double double 2.99e8 Path Float float 0.6180 Int int -42 Object Long long 4294967296 Sequence String string hello URI anyURI http://lv2plug.in/ Tuple Path anyURI /home/drobilla/ Vector Table 1: Text serialisation for primitives.