mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-20 21:56:30 +01:00
Support LV2 atom sequence ports alongside old event ports.
git-svn-id: svn://localhost/ardour2/branches/3.0@11517 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
4f96a1006b
commit
f122504784
12 changed files with 1772 additions and 344 deletions
|
|
@ -37,15 +37,16 @@ struct _VstMidiEvent;
|
|||
typedef struct _VstMidiEvent VstMidiEvent;
|
||||
#endif
|
||||
|
||||
#ifdef LV2_SUPPORT
|
||||
typedef struct LV2_Evbuf_Impl LV2_Evbuf;
|
||||
#endif
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Buffer;
|
||||
class AudioBuffer;
|
||||
class MidiBuffer;
|
||||
class PortSet;
|
||||
#ifdef LV2_SUPPORT
|
||||
class LV2EventBuffer;
|
||||
#endif
|
||||
|
||||
/** A set of buffers of various types.
|
||||
*
|
||||
|
|
@ -113,8 +114,11 @@ public:
|
|||
#ifdef LV2_SUPPORT
|
||||
/** Get a MIDI buffer translated into an LV2 MIDI buffer for use with plugins.
|
||||
* The index here corresponds directly to MIDI buffer numbers (i.e. the index
|
||||
* passed to get_midi), translation back and forth will happen as needed */
|
||||
LV2EventBuffer& get_lv2_midi(bool input, size_t i);
|
||||
* passed to get_midi), translation back and forth will happen as needed.
|
||||
* If atom_type is 0 the returned buffer will be in the old event API
|
||||
* format. Otherwise, atom_type must be the URID for atom:Sequence.
|
||||
*/
|
||||
LV2_Evbuf* get_lv2_midi(bool input, size_t i, uint32_t atom_type);
|
||||
|
||||
/** Flush modified LV2 event output buffers back to Ardour buffers */
|
||||
void flush_lv2_midi(bool input, size_t i);
|
||||
|
|
@ -175,7 +179,7 @@ private:
|
|||
|
||||
#ifdef LV2_SUPPORT
|
||||
/// LV2 MIDI buffers (for conversion to/from MIDI buffers)
|
||||
typedef std::vector< std::pair<bool, LV2EventBuffer*> > LV2Buffers;
|
||||
typedef std::vector< std::pair<bool, LV2_Evbuf*> > LV2Buffers;
|
||||
LV2Buffers _lv2_buffers;
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2009 Paul Davis
|
||||
Author: David Robillard
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ardour_lv2_event_buffer_h__
|
||||
#define __ardour_lv2_event_buffer_h__
|
||||
|
||||
#include "lv2/lv2plug.in/ns/ext/event/event.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/event/event-helpers.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
|
||||
class LV2EventBuffer {
|
||||
public:
|
||||
LV2EventBuffer(size_t capacity);
|
||||
~LV2EventBuffer();
|
||||
|
||||
inline LV2_Event_Buffer* data() { return _data; }
|
||||
inline const LV2_Event_Buffer* data() const { return _data; }
|
||||
|
||||
inline void rewind() const { lv2_event_begin(&_iter, _data); }
|
||||
|
||||
inline void reset() {
|
||||
_latest_frames = 0;
|
||||
_latest_subframes = 0;
|
||||
_data->event_count = 0;
|
||||
_data->size = 0;
|
||||
rewind();
|
||||
}
|
||||
|
||||
inline size_t event_count() const { return _data->event_count; }
|
||||
inline uint32_t capacity() const { return _data->capacity; }
|
||||
inline uint32_t size() const { return _data->size; }
|
||||
inline uint32_t latest_frames() const { return _latest_frames; }
|
||||
inline uint32_t latest_subframes() const { return _latest_subframes; }
|
||||
|
||||
bool increment() const;
|
||||
|
||||
bool is_valid() const;
|
||||
|
||||
bool get_event(uint32_t* frames,
|
||||
uint32_t* subframes,
|
||||
uint16_t* type,
|
||||
uint16_t* size,
|
||||
uint8_t** data) const;
|
||||
|
||||
bool append(uint32_t frames,
|
||||
uint32_t subframes,
|
||||
uint16_t type,
|
||||
uint16_t size,
|
||||
const uint8_t* data);
|
||||
|
||||
bool append(const LV2_Event_Buffer* buf);
|
||||
|
||||
private:
|
||||
LV2_Event_Buffer* _data; ///< Contents
|
||||
mutable LV2_Event_Iterator _iter; ///< Iterator into _data
|
||||
uint32_t _latest_frames; ///< Latest time of all events (frames)
|
||||
uint32_t _latest_subframes; ///< Latest time of all events (subframes)
|
||||
};
|
||||
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif // __ardour_lv2_event_buffer_h__
|
||||
|
|
@ -98,7 +98,10 @@ class LV2Plugin : public ARDOUR::Plugin
|
|||
boost::shared_ptr<Plugin::ScalePoints>
|
||||
get_scale_points(uint32_t port_index) const;
|
||||
|
||||
static uint32_t midi_event_type () { return _midi_event_type; }
|
||||
/// Return the URID of midi:MidiEvent
|
||||
static uint32_t midi_event_type (bool event_api) {
|
||||
return event_api ? _midi_event_type_ev : _midi_event_type;
|
||||
}
|
||||
|
||||
void set_insert_info(const PluginInsert* insert);
|
||||
|
||||
|
|
@ -125,9 +128,10 @@ class LV2Plugin : public ARDOUR::Plugin
|
|||
typedef enum {
|
||||
PORT_INPUT = 1,
|
||||
PORT_OUTPUT = 1 << 1,
|
||||
PORT_EVENT = 1 << 2,
|
||||
PORT_AUDIO = 1 << 3,
|
||||
PORT_CONTROL = 1 << 4
|
||||
PORT_AUDIO = 1 << 2,
|
||||
PORT_CONTROL = 1 << 3,
|
||||
PORT_EVENT = 1 << 4,
|
||||
PORT_MESSAGE = 1 << 5
|
||||
} PortFlag;
|
||||
|
||||
typedef unsigned PortFlags;
|
||||
|
|
@ -150,7 +154,9 @@ class LV2Plugin : public ARDOUR::Plugin
|
|||
bool _has_state_interface;
|
||||
|
||||
static URIMap _uri_map;
|
||||
static uint32_t _midi_event_type_ev;
|
||||
static uint32_t _midi_event_type;
|
||||
static uint32_t _sequence_type;
|
||||
static uint32_t _state_path_type;
|
||||
|
||||
const std::string plugin_dir () const;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
#include "ardour/audioengine.h"
|
||||
#ifdef LV2_SUPPORT
|
||||
#include "ardour/lv2_plugin.h"
|
||||
#include "ardour/lv2_event_buffer.h"
|
||||
#include "lv2_evbuf.h"
|
||||
#endif
|
||||
#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT
|
||||
#include "ardour/vestige/aeffectx.h"
|
||||
|
|
@ -189,7 +189,9 @@ BufferSet::ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capac
|
|||
// in both directions (input & output, out-of-place)
|
||||
if (type == DataType::MIDI && _lv2_buffers.size() < _buffers[type].size() * 2 + 1) {
|
||||
while (_lv2_buffers.size() < _buffers[type].size() * 2) {
|
||||
_lv2_buffers.push_back(std::make_pair(false, new LV2EventBuffer(buffer_capacity)));
|
||||
_lv2_buffers.push_back(
|
||||
std::make_pair(false,
|
||||
lv2_evbuf_new(buffer_capacity, LV2_EVBUF_EVENT, 0)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -248,50 +250,61 @@ BufferSet::get(DataType type, size_t i) const
|
|||
|
||||
#ifdef LV2_SUPPORT
|
||||
|
||||
LV2EventBuffer&
|
||||
BufferSet::get_lv2_midi(bool input, size_t i)
|
||||
LV2_Evbuf*
|
||||
BufferSet::get_lv2_midi(bool input, size_t i, uint32_t atom_type)
|
||||
{
|
||||
assert (count().get(DataType::MIDI) > i);
|
||||
assert(count().get(DataType::MIDI) > i);
|
||||
|
||||
MidiBuffer& mbuf = get_midi(i);
|
||||
LV2Buffers::value_type b = _lv2_buffers.at(i * 2 + (input ? 0 : 1));
|
||||
LV2EventBuffer* ebuf = b.second;
|
||||
MidiBuffer& mbuf = get_midi(i);
|
||||
LV2Buffers::value_type b = _lv2_buffers.at(i * 2 + (input ? 0 : 1));
|
||||
LV2_Evbuf* evbuf = b.second;
|
||||
lv2_evbuf_set_type(evbuf,
|
||||
atom_type ? LV2_EVBUF_ATOM : LV2_EVBUF_EVENT,
|
||||
atom_type);
|
||||
|
||||
ebuf->reset();
|
||||
lv2_evbuf_reset(evbuf);
|
||||
if (input) {
|
||||
DEBUG_TRACE (PBD::DEBUG::LV2, string_compose ("%1 bytes of MIDI waiting @ %2\n", mbuf.size(), (void*) mbuf.data()));
|
||||
DEBUG_TRACE(PBD::DEBUG::LV2,
|
||||
string_compose("%1 bytes of MIDI waiting @ %2\n",
|
||||
mbuf.size(), (void*) mbuf.data()));
|
||||
|
||||
LV2_Evbuf_Iterator i = lv2_evbuf_begin(evbuf);
|
||||
const uint32_t type = LV2Plugin::midi_event_type(atom_type == 0);
|
||||
for (MidiBuffer::iterator e = mbuf.begin(); e != mbuf.end(); ++e) {
|
||||
const Evoral::MIDIEvent<framepos_t> ev(*e, false);
|
||||
uint32_t type = LV2Plugin::midi_event_type();
|
||||
#ifndef NDEBUG
|
||||
DEBUG_TRACE (PBD::DEBUG::LV2, string_compose ("\tMIDI event of size %1 @ %2\n", ev.size(), ev.time()));
|
||||
DEBUG_TRACE(PBD::DEBUG::LV2,
|
||||
string_compose("\tMIDI event of size %1 @ %2\n",
|
||||
ev.size(), ev.time()));
|
||||
for (uint16_t x = 0; x < ev.size(); ++x) {
|
||||
std::stringstream ss;
|
||||
ss << "\t\tByte[" << x << "] = " << std::hex << (int) ev.buffer()[x] << std::dec << std::endl;
|
||||
ss << "\t\tev[" << x << "] = " << std::hex << (int) ev.buffer()[x] << std::dec << std::endl;
|
||||
DEBUG_TRACE (PBD::DEBUG::LV2, ss.str());
|
||||
}
|
||||
#endif
|
||||
ebuf->append(ev.time(), 0, type, ev.size(), ev.buffer());
|
||||
lv2_evbuf_write(&i, ev.time(), 0, type, ev.size(), ev.buffer());
|
||||
}
|
||||
}
|
||||
return *ebuf;
|
||||
return evbuf;
|
||||
}
|
||||
|
||||
void
|
||||
BufferSet::flush_lv2_midi(bool input, size_t i)
|
||||
{
|
||||
MidiBuffer& mbuf = get_midi(i);
|
||||
LV2Buffers::value_type b = _lv2_buffers.at(i * 2 + (input ? 0 : 1));
|
||||
LV2EventBuffer* ebuf = b.second;
|
||||
MidiBuffer& mbuf = get_midi(i);
|
||||
LV2Buffers::value_type b = _lv2_buffers.at(i * 2 + (input ? 0 : 1));
|
||||
LV2_Evbuf* evbuf = b.second;
|
||||
|
||||
mbuf.silence(0, 0);
|
||||
for (ebuf->rewind(); ebuf->is_valid(); ebuf->increment()) {
|
||||
for (LV2_Evbuf_Iterator i = lv2_evbuf_begin(evbuf);
|
||||
lv2_evbuf_is_valid(i);
|
||||
i = lv2_evbuf_next(i)) {
|
||||
uint32_t frames;
|
||||
uint32_t subframes;
|
||||
uint16_t type;
|
||||
uint16_t size;
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
uint8_t* data;
|
||||
ebuf->get_event(&frames, &subframes, &type, &size, &data);
|
||||
lv2_evbuf_get(i, &frames, &subframes, &type, &size, &data);
|
||||
#ifndef NDEBUG
|
||||
DEBUG_TRACE (PBD::DEBUG::LV2, string_compose ("(FLUSH) MIDI event of size %1\n", size));
|
||||
for (uint16_t x = 0; x < size; ++x) {
|
||||
|
|
|
|||
259
libs/ardour/lv2/lv2plug.in/ns/ext/atom/atom.h
Normal file
259
libs/ardour/lv2/lv2plug.in/ns/ext/atom/atom.h
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
Copyright 2008-2012 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@file atom.h C header for the LV2 Atom extension
|
||||
<http://lv2plug.in/ns/ext/atom>.
|
||||
*/
|
||||
|
||||
#ifndef LV2_ATOM_H
|
||||
#define LV2_ATOM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define LV2_ATOM_URI "http://lv2plug.in/ns/ext/atom"
|
||||
|
||||
#define LV2_ATOM__Atom LV2_ATOM_URI "#Atom"
|
||||
#define LV2_ATOM__AtomPort LV2_ATOM_URI "#AtomPort"
|
||||
#define LV2_ATOM__AudioFrames LV2_ATOM_URI "#AudioFrames"
|
||||
#define LV2_ATOM__Beats LV2_ATOM_URI "#Beats"
|
||||
#define LV2_ATOM__Blank LV2_ATOM_URI "#Blank"
|
||||
#define LV2_ATOM__Bool LV2_ATOM_URI "#Bool"
|
||||
#define LV2_ATOM__Double LV2_ATOM_URI "#Double"
|
||||
#define LV2_ATOM__Event LV2_ATOM_URI "#Event"
|
||||
#define LV2_ATOM__Float LV2_ATOM_URI "#Float"
|
||||
#define LV2_ATOM__Int32 LV2_ATOM_URI "#Int32"
|
||||
#define LV2_ATOM__Int64 LV2_ATOM_URI "#Int64"
|
||||
#define LV2_ATOM__Literal LV2_ATOM_URI "#Literal"
|
||||
#define LV2_ATOM__MessagePort LV2_ATOM_URI "#MessagePort"
|
||||
#define LV2_ATOM__Number LV2_ATOM_URI "#Number"
|
||||
#define LV2_ATOM__Object LV2_ATOM_URI "#Object"
|
||||
#define LV2_ATOM__Path LV2_ATOM_URI "#Path"
|
||||
#define LV2_ATOM__Property LV2_ATOM_URI "#Property"
|
||||
#define LV2_ATOM__Resource LV2_ATOM_URI "#Resource"
|
||||
#define LV2_ATOM__Sequence LV2_ATOM_URI "#Sequence"
|
||||
#define LV2_ATOM__String LV2_ATOM_URI "#String"
|
||||
#define LV2_ATOM__TimeUnit LV2_ATOM_URI "#TimeUnit"
|
||||
#define LV2_ATOM__Tuple LV2_ATOM_URI "#Tuple"
|
||||
#define LV2_ATOM__URI LV2_ATOM_URI "#URI"
|
||||
#define LV2_ATOM__URID LV2_ATOM_URI "#URID"
|
||||
#define LV2_ATOM__ValuePort LV2_ATOM_URI "#ValuePort"
|
||||
#define LV2_ATOM__Vector LV2_ATOM_URI "#Vector"
|
||||
#define LV2_ATOM__beatTime LV2_ATOM_URI "#beatTime"
|
||||
#define LV2_ATOM__bufferType LV2_ATOM_URI "#bufferType"
|
||||
#define LV2_ATOM__eventTransfer LV2_ATOM_URI "#eventTransfer"
|
||||
#define LV2_ATOM__frameTime LV2_ATOM_URI "#frameTime"
|
||||
#define LV2_ATOM__supports LV2_ATOM_URI "#supports"
|
||||
#define LV2_ATOM__timeUnit LV2_ATOM_URI "#timeUnit"
|
||||
|
||||
#define LV2_ATOM_REFERENCE_TYPE 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** This expression will fail to compile if double does not fit in 64 bits. */
|
||||
typedef char lv2_atom_assert_double_fits_in_64_bits[
|
||||
((sizeof(double) <= sizeof(uint64_t)) * 2) - 1];
|
||||
|
||||
/**
|
||||
Return a pointer to the contents of an Atom. The "contents" of an atom
|
||||
is the data past the complete type-specific header.
|
||||
@param type The type of the atom, e.g. LV2_Atom_String.
|
||||
@param atom A variable-sized atom.
|
||||
*/
|
||||
#define LV2_ATOM_CONTENTS(type, atom) \
|
||||
((void*)((uint8_t*)(atom) + sizeof(type)))
|
||||
|
||||
/**
|
||||
Return a pointer to the body of an Atom. The "body" of an atom is the
|
||||
data just past the LV2_Atom head (i.e. the same offset for all types).
|
||||
*/
|
||||
#define LV2_ATOM_BODY(atom) LV2_ATOM_CONTENTS(LV2_Atom, atom)
|
||||
|
||||
/** The header of an atom:Atom. */
|
||||
typedef struct {
|
||||
uint32_t size; /**< Size in bytes, not including type and size. */
|
||||
uint32_t type; /**< Type of this atom (mapped URI). */
|
||||
} LV2_Atom;
|
||||
|
||||
/** An atom:Int32 or atom:Bool. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
int32_t body; /**< Integer value. */
|
||||
} LV2_Atom_Int32;
|
||||
|
||||
/** An atom:Int64. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
int64_t body; /**< Integer value. */
|
||||
} LV2_Atom_Int64;
|
||||
|
||||
/** An atom:Float. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
float body; /**< Floating point value. */
|
||||
} LV2_Atom_Float;
|
||||
|
||||
/** An atom:Double. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
double body; /**< Floating point value. */
|
||||
} LV2_Atom_Double;
|
||||
|
||||
/** An atom:Bool. May be cast to LV2_Atom. */
|
||||
typedef LV2_Atom_Int32 LV2_Atom_Bool;
|
||||
|
||||
/** An atom:URID. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
uint32_t body; /**< URID. */
|
||||
} LV2_Atom_URID;
|
||||
|
||||
/** An atom:String. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
/* Contents (a null-terminated UTF-8 string) follow here. */
|
||||
} LV2_Atom_String;
|
||||
|
||||
/** The body of an atom:Literal. */
|
||||
typedef struct {
|
||||
uint32_t datatype; /**< Datatype URID. */
|
||||
uint32_t lang; /**< Language URID. */
|
||||
/* Contents (a null-terminated UTF-8 string) follow here. */
|
||||
} LV2_Atom_Literal_Body;
|
||||
|
||||
/** An atom:Literal. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
LV2_Atom_Literal_Body body; /**< Body. */
|
||||
} LV2_Atom_Literal;
|
||||
|
||||
/** An atom:Tuple. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
/* Contents (a series of complete atoms) follow here. */
|
||||
} LV2_Atom_Tuple;
|
||||
|
||||
/** The body of an atom:Vector. */
|
||||
typedef struct {
|
||||
uint32_t elem_count; /**< The number of elements in the vector */
|
||||
uint32_t elem_type; /**< The type of each element in the vector */
|
||||
/* Contents (a series of packed atom bodies) follow here. */
|
||||
} LV2_Atom_Vector_Body;
|
||||
|
||||
/** An atom:Vector. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
LV2_Atom_Vector_Body body; /**< Body. */
|
||||
} LV2_Atom_Vector;
|
||||
|
||||
/** The body of an atom:Property (e.g. in an atom:Object). */
|
||||
typedef struct {
|
||||
uint32_t key; /**< Key (predicate) (mapped URI). */
|
||||
uint32_t context; /**< Context URID (may be, and generally is, 0). */
|
||||
LV2_Atom value; /**< Value atom header. */
|
||||
/* Value atom body follows here. */
|
||||
} LV2_Atom_Property_Body;
|
||||
|
||||
/** An atom:Property. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
LV2_Atom_Property_Body body; /**< Body. */
|
||||
} LV2_Atom_Property;
|
||||
|
||||
/** The body of an atom:Object. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
uint32_t id; /**< URID (atom:Resource) or blank ID (atom:Blank). */
|
||||
uint32_t otype; /**< Type URID (same as rdf:type, for fast dispatch). */
|
||||
/* Contents (a series of property bodies) follow here. */
|
||||
} LV2_Atom_Object_Body;
|
||||
|
||||
/** An atom:Object. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
LV2_Atom_Object_Body body; /**< Body. */
|
||||
} LV2_Atom_Object;
|
||||
|
||||
/** The header of an atom:Event. Note this type is NOT an LV2_Atom. */
|
||||
typedef struct {
|
||||
/** Time stamp. Which type is valid is determined by context. */
|
||||
union {
|
||||
int64_t frames; /**< Time in audio frames. */
|
||||
double beats; /**< Time in beats. */
|
||||
} time;
|
||||
LV2_Atom body; /**< Event body atom header. */
|
||||
/* Body atom contents follow here. */
|
||||
} LV2_Atom_Event;
|
||||
|
||||
/**
|
||||
The body of an atom:Sequence (a sequence of events).
|
||||
|
||||
The unit field is either a URID that described an appropriate time stamp
|
||||
type, or may be 0 where a default stamp type is known. For
|
||||
LV2_Descriptor::run(), the default stamp type is atom:AudioFrames, i.e.
|
||||
LV2_Atom_Audio_Time.
|
||||
|
||||
The contents of a sequence is a series of LV2_Atom_Event, each aligned
|
||||
to 64-bits, e.g.:
|
||||
<pre>
|
||||
| Event 1 (size 6) | Event 2
|
||||
| | | | | | | | |
|
||||
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
|FRAMES |SUBFRMS|TYPE |SIZE |DATADATADATAPAD|FRAMES |SUBFRMS|...
|
||||
</pre>
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t unit; /**< URID of unit of event time stamps. */
|
||||
uint32_t pad; /**< Currently unused. */
|
||||
/* Contents (a series of events) follow here. */
|
||||
} LV2_Atom_Sequence_Body;
|
||||
|
||||
/** An atom:Sequence. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
LV2_Atom_Literal_Body body; /**< Body. */
|
||||
} LV2_Atom_Sequence;
|
||||
|
||||
/**
|
||||
The contents of an atom:AtomPort buffer.
|
||||
|
||||
This contains a pointer to an Atom, which is the data to be
|
||||
processed/written, as well as additional metadata. This struct may be
|
||||
augmented in the future to add more metadata fields as they become
|
||||
necessary. The initial version of this struct contains data, size, and
|
||||
capacity. Implementations MUST check that any other fields they wish to use
|
||||
are actually present by comparing the size with the offset of that field,
|
||||
e.g.:
|
||||
|
||||
@code
|
||||
if (offsetof(LV2_Atom_Port_Buffer, field) < buf->size) {
|
||||
do_stuff_with(buf->field);
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
typedef struct {
|
||||
LV2_Atom* data; /** Pointer to data. */
|
||||
uint32_t size; /** Total size of this struct. */
|
||||
uint32_t capacity; /** Available space for data body. */
|
||||
} LV2_Atom_Port_Buffer;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV2_ATOM_H */
|
||||
544
libs/ardour/lv2/lv2plug.in/ns/ext/atom/forge.h
Normal file
544
libs/ardour/lv2/lv2plug.in/ns/ext/atom/forge.h
Normal file
|
|
@ -0,0 +1,544 @@
|
|||
/*
|
||||
Copyright 2008-2012 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@file forge.h An API for constructing LV2 atoms.
|
||||
|
||||
This file provides an API for constructing Atoms which makes it relatively
|
||||
simple to build nested atoms of arbitrary complexity without requiring
|
||||
dynamic memory allocation.
|
||||
|
||||
The API is based on successively appending the appropriate pieces to build a
|
||||
complete Atom. The size of containers is automatically updated. Functions
|
||||
that begin a container return (via their frame argument) a stack frame which
|
||||
must be popped when the container is finished.
|
||||
|
||||
All output is written to a user-provided buffer or sink function. This
|
||||
makes it popssible to create create atoms on the stack, on the heap, in LV2
|
||||
port buffers, in a ringbuffer, or elsewhere, all using the same API.
|
||||
|
||||
This entire API is realtime safe if used with a buffer or a realtime safe
|
||||
sink, except lv2_atom_forge_init() which is only realtime safe if the URI
|
||||
map function is.
|
||||
|
||||
Note these functions are all static inline, do not take their address.
|
||||
|
||||
This header is non-normative, it is provided for convenience.
|
||||
*/
|
||||
|
||||
#ifndef LV2_ATOM_FORGE_H
|
||||
#define LV2_ATOM_FORGE_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/atom/util.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#else
|
||||
# include <stdbool.h>
|
||||
#endif
|
||||
|
||||
/** Handle for LV2_Atom_Forge_Sink. */
|
||||
typedef void* LV2_Atom_Forge_Sink_Handle;
|
||||
|
||||
/** Sink function for writing output. See lv2_atom_forge_set_sink(). */
|
||||
typedef void* (*LV2_Atom_Forge_Sink)(LV2_Atom_Forge_Sink_Handle handle,
|
||||
const void* buf,
|
||||
uint32_t size);
|
||||
|
||||
/** A stack frame used for keeping track of nested Atom containers. */
|
||||
typedef struct _LV2_Atom_Forge_Frame {
|
||||
struct _LV2_Atom_Forge_Frame* parent;
|
||||
LV2_Atom* atom;
|
||||
} LV2_Atom_Forge_Frame;
|
||||
|
||||
/** A "forge" for creating atoms by appending to a buffer. */
|
||||
typedef struct {
|
||||
uint8_t* buf;
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
|
||||
LV2_Atom_Forge_Sink sink;
|
||||
LV2_Atom_Forge_Sink_Handle handle;
|
||||
|
||||
LV2_Atom_Forge_Frame* stack;
|
||||
|
||||
LV2_URID Blank;
|
||||
LV2_URID Bool;
|
||||
LV2_URID Double;
|
||||
LV2_URID Float;
|
||||
LV2_URID Int32;
|
||||
LV2_URID Int64;
|
||||
LV2_URID Literal;
|
||||
LV2_URID Path;
|
||||
LV2_URID Property;
|
||||
LV2_URID Resource;
|
||||
LV2_URID Sequence;
|
||||
LV2_URID String;
|
||||
LV2_URID Tuple;
|
||||
LV2_URID URI;
|
||||
LV2_URID URID;
|
||||
LV2_URID Vector;
|
||||
} LV2_Atom_Forge;
|
||||
|
||||
/**
|
||||
Push a stack frame.
|
||||
This is done automatically by container functions (which take a stack frame
|
||||
pointer), but may be called by the user to push the top level container when
|
||||
writing to an existing Atom.
|
||||
*/
|
||||
static inline LV2_Atom*
|
||||
lv2_atom_forge_push(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Frame* frame,
|
||||
LV2_Atom* atom)
|
||||
{
|
||||
frame->parent = forge->stack;
|
||||
frame->atom = atom;
|
||||
forge->stack = frame;
|
||||
return atom;
|
||||
}
|
||||
|
||||
/** Pop a stack frame. This must be called when a container is finished. */
|
||||
static inline void
|
||||
lv2_atom_forge_pop(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
|
||||
{
|
||||
assert(frame == forge->stack);
|
||||
forge->stack = frame->parent;
|
||||
}
|
||||
|
||||
/** Set the output buffer where @p forge will write atoms. */
|
||||
static inline void
|
||||
lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size)
|
||||
{
|
||||
forge->buf = buf;
|
||||
forge->size = size;
|
||||
forge->offset = 0;
|
||||
forge->sink = NULL;
|
||||
forge->handle = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
Set the sink function where @p forge will write output.
|
||||
|
||||
The return value of forge functions is a pointer to the written data, which
|
||||
is used for updating parent sizes. To enable this, the sink function must
|
||||
return a valid pointer to a contiguous LV2_Atom header. For ringbuffers,
|
||||
this should be possible as long as the size of the buffer is a multiple of
|
||||
sizeof(LV2_Atom), since atoms are always aligned. When using a ringbuffer,
|
||||
the returned pointers may not point to a complete atom (including body).
|
||||
The user must take care to only use these return values in a way compatible
|
||||
with the sink used.
|
||||
*/
|
||||
static inline void
|
||||
lv2_atom_forge_set_sink(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Sink sink,
|
||||
LV2_Atom_Forge_Sink_Handle handle)
|
||||
{
|
||||
forge->buf = NULL;
|
||||
forge->size = forge->offset = 0;
|
||||
forge->sink = sink;
|
||||
forge->handle = handle;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialise @p forge.
|
||||
|
||||
URIs will be mapped using @p map and stored, a reference to @p map itself is
|
||||
not held.
|
||||
*/
|
||||
static inline void
|
||||
lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map)
|
||||
{
|
||||
lv2_atom_forge_set_buffer(forge, NULL, 0);
|
||||
forge->stack = NULL;
|
||||
forge->Blank = map->map(map->handle, LV2_ATOM_URI "#Blank");
|
||||
forge->Bool = map->map(map->handle, LV2_ATOM_URI "#Bool");
|
||||
forge->Double = map->map(map->handle, LV2_ATOM_URI "#Double");
|
||||
forge->Float = map->map(map->handle, LV2_ATOM_URI "#Float");
|
||||
forge->Int32 = map->map(map->handle, LV2_ATOM_URI "#Int32");
|
||||
forge->Int64 = map->map(map->handle, LV2_ATOM_URI "#Int64");
|
||||
forge->Literal = map->map(map->handle, LV2_ATOM_URI "#Literal");
|
||||
forge->Path = map->map(map->handle, LV2_ATOM_URI "#Path");
|
||||
forge->Property = map->map(map->handle, LV2_ATOM_URI "#Property");
|
||||
forge->Resource = map->map(map->handle, LV2_ATOM_URI "#Resource");
|
||||
forge->Sequence = map->map(map->handle, LV2_ATOM_URI "#Sequence");
|
||||
forge->String = map->map(map->handle, LV2_ATOM_URI "#String");
|
||||
forge->Tuple = map->map(map->handle, LV2_ATOM_URI "#Tuple");
|
||||
forge->URI = map->map(map->handle, LV2_ATOM_URI "#URI");
|
||||
forge->URID = map->map(map->handle, LV2_ATOM_URI "#URID");
|
||||
forge->Vector = map->map(map->handle, LV2_ATOM_URI "#Vector");
|
||||
}
|
||||
|
||||
/**
|
||||
Write raw output. This is used internally, but is also useful for writing
|
||||
atom types not explicitly supported by the forge API. Note the caller is
|
||||
responsible for ensuring the output is approriately padded.
|
||||
*/
|
||||
static inline void*
|
||||
lv2_atom_forge_raw(LV2_Atom_Forge* forge, const void* data, uint32_t size)
|
||||
{
|
||||
uint8_t* out = NULL;
|
||||
if (forge->sink) {
|
||||
out = forge->sink(forge->handle, data, size);
|
||||
} else {
|
||||
out = forge->buf + forge->offset;
|
||||
if (forge->offset + size > forge->size) {
|
||||
return NULL;
|
||||
}
|
||||
forge->offset += size;
|
||||
memcpy(out, data, size);
|
||||
}
|
||||
if (out) {
|
||||
for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) {
|
||||
f->atom->size += size;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Pad output accordingly so next write is 64-bit aligned. */
|
||||
static inline void
|
||||
lv2_atom_forge_pad(LV2_Atom_Forge* forge, uint32_t written)
|
||||
{
|
||||
const uint64_t pad = 0;
|
||||
const uint32_t pad_size = lv2_atom_pad_size(written) - written;
|
||||
lv2_atom_forge_raw(forge, &pad, pad_size);
|
||||
}
|
||||
|
||||
/** Write raw output, padding to 64-bits as necessary. */
|
||||
static inline void*
|
||||
lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size)
|
||||
{
|
||||
void* out = lv2_atom_forge_raw(forge, data, size);
|
||||
if (out) {
|
||||
lv2_atom_forge_pad(forge, size);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Write an atom:Atom header. */
|
||||
static inline LV2_Atom*
|
||||
lv2_atom_forge_atom(LV2_Atom_Forge* forge, uint32_t size, uint32_t type)
|
||||
{
|
||||
const LV2_Atom a = { size, type };
|
||||
return (LV2_Atom*)lv2_atom_forge_raw(forge, &a, sizeof(a));
|
||||
}
|
||||
|
||||
/** Write an atom:Int32. */
|
||||
static inline LV2_Atom_Int32*
|
||||
lv2_atom_forge_int32(LV2_Atom_Forge* forge, int32_t val)
|
||||
{
|
||||
const LV2_Atom_Int32 a = { { sizeof(val), forge->Int32 }, val };
|
||||
return (LV2_Atom_Int32*)lv2_atom_forge_write(forge, &a, sizeof(a));
|
||||
}
|
||||
|
||||
/** Write an atom:Int64. */
|
||||
static inline LV2_Atom_Int64*
|
||||
lv2_atom_forge_int64(LV2_Atom_Forge* forge, int64_t val)
|
||||
{
|
||||
const LV2_Atom_Int64 a = { { sizeof(val), forge->Int64 }, val };
|
||||
return (LV2_Atom_Int64*)lv2_atom_forge_write(forge, &a, sizeof(a));
|
||||
}
|
||||
|
||||
/** Write an atom:Float. */
|
||||
static inline LV2_Atom_Float*
|
||||
lv2_atom_forge_float(LV2_Atom_Forge* forge, float val)
|
||||
{
|
||||
const LV2_Atom_Float a = { { sizeof(val), forge->Float }, val };
|
||||
return (LV2_Atom_Float*)lv2_atom_forge_write(forge, &a, sizeof(a));
|
||||
}
|
||||
|
||||
/** Write an atom:Double. */
|
||||
static inline LV2_Atom_Double*
|
||||
lv2_atom_forge_double(LV2_Atom_Forge* forge, double val)
|
||||
{
|
||||
const LV2_Atom_Double a = { { sizeof(val), forge->Double }, val };
|
||||
return (LV2_Atom_Double*)lv2_atom_forge_write(
|
||||
forge, &a, sizeof(a));
|
||||
}
|
||||
|
||||
/** Write an atom:Bool. */
|
||||
static inline LV2_Atom_Bool*
|
||||
lv2_atom_forge_bool(LV2_Atom_Forge* forge, bool val)
|
||||
{
|
||||
const LV2_Atom_Bool a = { { sizeof(val), forge->Bool }, val };
|
||||
return (LV2_Atom_Bool*)lv2_atom_forge_write(forge, &a, sizeof(a));
|
||||
}
|
||||
|
||||
/** Write an atom:URID. */
|
||||
static inline LV2_Atom_URID*
|
||||
lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id)
|
||||
{
|
||||
const LV2_Atom_URID a = { { sizeof(id), forge->URID }, id };
|
||||
return (LV2_Atom_URID*)lv2_atom_forge_write(forge, &a, sizeof(a));
|
||||
}
|
||||
|
||||
/** Write a string body. Used internally. */
|
||||
static inline uint8_t*
|
||||
lv2_atom_forge_string_body(LV2_Atom_Forge* forge,
|
||||
const uint8_t* str,
|
||||
uint32_t len)
|
||||
{
|
||||
uint8_t* out = NULL;
|
||||
if ( (out = lv2_atom_forge_raw(forge, str, len))
|
||||
&& (out = lv2_atom_forge_raw(forge, "", 1))) {
|
||||
lv2_atom_forge_pad(forge, len + 1);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Write an atom compatible with atom:String. Used internally. */
|
||||
static inline LV2_Atom_String*
|
||||
lv2_atom_forge_typed_string(LV2_Atom_Forge* forge,
|
||||
uint32_t type,
|
||||
const uint8_t* str,
|
||||
uint32_t len)
|
||||
{
|
||||
const LV2_Atom_String a = { { len + 1, type } };
|
||||
LV2_Atom_String* out = (LV2_Atom_String*)
|
||||
lv2_atom_forge_raw(forge, &a, sizeof(a));
|
||||
if (out) {
|
||||
if (!lv2_atom_forge_string_body(forge, str, len)) {
|
||||
out->atom.size = out->atom.type = 0;
|
||||
out = NULL;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Write an atom:String. Note that @p str need not be NULL terminated. */
|
||||
static inline LV2_Atom_String*
|
||||
lv2_atom_forge_string(LV2_Atom_Forge* forge, const uint8_t* str, uint32_t len)
|
||||
{
|
||||
return lv2_atom_forge_typed_string(forge, forge->String, str, len);
|
||||
}
|
||||
|
||||
/**
|
||||
Write an atom:URI. Note that @p uri need not be NULL terminated.
|
||||
This does not map the URI, but writes the complete URI string. To write
|
||||
a mapped URI, use lv2_atom_forge_urid().
|
||||
*/
|
||||
static inline LV2_Atom_String*
|
||||
lv2_atom_forge_uri(LV2_Atom_Forge* forge, const uint8_t* uri, uint32_t len)
|
||||
{
|
||||
return lv2_atom_forge_typed_string(forge, forge->URI, uri, len);
|
||||
}
|
||||
|
||||
/** Write an atom:Path. Note that @p path need not be NULL terminated. */
|
||||
static inline LV2_Atom_String*
|
||||
lv2_atom_forge_path(LV2_Atom_Forge* forge, const uint8_t* path, uint32_t len)
|
||||
{
|
||||
return lv2_atom_forge_typed_string(forge, forge->Path, path, len);
|
||||
}
|
||||
|
||||
/** Write an atom:Literal. */
|
||||
static inline LV2_Atom_Literal*
|
||||
lv2_atom_forge_literal(LV2_Atom_Forge* forge,
|
||||
const uint8_t* str,
|
||||
uint32_t len,
|
||||
uint32_t datatype,
|
||||
uint32_t lang)
|
||||
{
|
||||
const LV2_Atom_Literal a = {
|
||||
{ sizeof(LV2_Atom_Literal) - sizeof(LV2_Atom) + len + 1,
|
||||
forge->Literal },
|
||||
{ datatype,
|
||||
lang }
|
||||
};
|
||||
LV2_Atom_Literal* out = (LV2_Atom_Literal*)
|
||||
lv2_atom_forge_raw(forge, &a, sizeof(a));
|
||||
if (out) {
|
||||
if (!lv2_atom_forge_string_body(forge, str, len)) {
|
||||
out->atom.size = out->atom.type = 0;
|
||||
out = NULL;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Write an atom:Vector header, but not the vector body. */
|
||||
static inline LV2_Atom_Vector*
|
||||
lv2_atom_forge_vector_head(LV2_Atom_Forge* forge,
|
||||
uint32_t elem_count,
|
||||
uint32_t elem_type,
|
||||
uint32_t elem_size)
|
||||
{
|
||||
const uint32_t size = sizeof(LV2_Atom_Vector) + (elem_size * elem_count);
|
||||
const LV2_Atom_Vector a = {
|
||||
{ size - sizeof(LV2_Atom), forge->Vector },
|
||||
{ elem_count, elem_type }
|
||||
};
|
||||
return (LV2_Atom_Vector*)lv2_atom_forge_write(forge, &a, sizeof(a));
|
||||
}
|
||||
|
||||
/** Write a complete atom:Vector. */
|
||||
static inline LV2_Atom_Vector*
|
||||
lv2_atom_forge_vector(LV2_Atom_Forge* forge,
|
||||
uint32_t elem_count,
|
||||
uint32_t elem_type,
|
||||
uint32_t elem_size,
|
||||
void* elems)
|
||||
{
|
||||
LV2_Atom_Vector* out = lv2_atom_forge_vector_head(
|
||||
forge, elem_count, elem_type, elem_size);
|
||||
if (out) {
|
||||
lv2_atom_forge_write(forge, elems, elem_size * elem_count);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
Write the header of an atom:Tuple.
|
||||
|
||||
The passed frame will be initialised to represent this tuple. To complete
|
||||
the tuple, write a sequence of atoms, then pop the frame with
|
||||
lv2_atom_forge_pop().
|
||||
|
||||
For example:
|
||||
@code
|
||||
// Write tuple (1, 2.0)
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
LV2_Atom* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, &frame);
|
||||
lv2_atom_forge_int32(forge, 1);
|
||||
lv2_atom_forge_float(forge, 2.0);
|
||||
lv2_atom_forge_pop(forge, &frame);
|
||||
@endcode
|
||||
*/
|
||||
static inline LV2_Atom_Tuple*
|
||||
lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
|
||||
{
|
||||
const LV2_Atom_Tuple a = { { 0, forge->Tuple } };
|
||||
LV2_Atom* atom = lv2_atom_forge_write(forge, &a, sizeof(a));
|
||||
return (LV2_Atom_Tuple*)lv2_atom_forge_push(forge, frame, atom);
|
||||
}
|
||||
|
||||
/**
|
||||
Write the header of an atom:Resource.
|
||||
|
||||
The passed frame will be initialised to represent this object. To complete
|
||||
the object, write a sequence of properties, then pop the frame with
|
||||
lv2_atom_forge_pop().
|
||||
|
||||
For example:
|
||||
@code
|
||||
LV2_URID eg_Cat = map("http://example.org/Cat");
|
||||
LV2_URID eg_name = map("http://example.org/name");
|
||||
|
||||
// Write object header
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
LV2_Atom* obj = (LV2_Atom*)lv2_atom_forge_resource(forge, &frame, 1, eg_Cat);
|
||||
|
||||
// Write property: eg:name = "Hobbes"
|
||||
lv2_atom_forge_property_head(forge, eg_name, 0);
|
||||
lv2_atom_forge_string(forge, "Hobbes", strlen("Hobbes"));
|
||||
|
||||
// Finish object
|
||||
lv2_atom_forge_pop(forge, &frame);
|
||||
@endcode
|
||||
*/
|
||||
static inline LV2_Atom_Object*
|
||||
lv2_atom_forge_resource(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Frame* frame,
|
||||
LV2_URID id,
|
||||
LV2_URID otype)
|
||||
{
|
||||
const LV2_Atom_Object a = {
|
||||
{ sizeof(LV2_Atom_Object) - sizeof(LV2_Atom), forge->Resource },
|
||||
{ id, otype }
|
||||
};
|
||||
LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a));
|
||||
return (LV2_Atom_Object*)lv2_atom_forge_push(forge, frame, atom);
|
||||
}
|
||||
|
||||
/**
|
||||
The same as lv2_atom_forge_resource(), but for object:Blank.
|
||||
*/
|
||||
static inline LV2_Atom_Object*
|
||||
lv2_atom_forge_blank(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Frame* frame,
|
||||
uint32_t id,
|
||||
LV2_URID otype)
|
||||
{
|
||||
const LV2_Atom_Object a = {
|
||||
{ sizeof(LV2_Atom_Object) - sizeof(LV2_Atom), forge->Blank },
|
||||
{ id, otype }
|
||||
};
|
||||
LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a));
|
||||
return (LV2_Atom_Object*)lv2_atom_forge_push(forge, frame, atom);
|
||||
}
|
||||
|
||||
/**
|
||||
Write the header for a property body (likely in an Object).
|
||||
See lv2_atom_forge_object() documentation for an example.
|
||||
*/
|
||||
static inline LV2_Atom_Property_Body*
|
||||
lv2_atom_forge_property_head(LV2_Atom_Forge* forge,
|
||||
LV2_URID key,
|
||||
LV2_URID context)
|
||||
{
|
||||
const LV2_Atom_Property_Body a = { key, context, { 0, 0 } };
|
||||
return (LV2_Atom_Property_Body*)lv2_atom_forge_write(
|
||||
forge, &a, 2 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
/**
|
||||
Write the header for a Sequence.
|
||||
The size of the returned sequence will be 0, so passing it as the parent
|
||||
parameter to other forge methods will do the right thing.
|
||||
*/
|
||||
static inline LV2_Atom_Sequence*
|
||||
lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Frame* frame,
|
||||
uint32_t unit)
|
||||
{
|
||||
const LV2_Atom_Sequence a = {
|
||||
{ sizeof(LV2_Atom_Sequence) - sizeof(LV2_Atom), forge->Sequence },
|
||||
{ unit, 0 }
|
||||
};
|
||||
LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a));
|
||||
return (LV2_Atom_Sequence*)lv2_atom_forge_push(forge, frame, atom);
|
||||
}
|
||||
|
||||
/**
|
||||
Write the time stamp header of an Event (in a Sequence) in audio frames.
|
||||
After this, call the appropriate forge method(s) to write the body, passing
|
||||
the same @p parent parameter. Note the returned LV2_Event is NOT an Atom.
|
||||
*/
|
||||
static inline int64_t*
|
||||
lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames)
|
||||
{
|
||||
return (int64_t*)lv2_atom_forge_write(forge, &frames, sizeof(frames));
|
||||
}
|
||||
|
||||
/**
|
||||
Write the time stamp header of an Event (in a Sequence) in beats.
|
||||
After this, call the appropriate forge method(s) to write the body, passing
|
||||
the same @p parent parameter. Note the returned LV2_Event is NOT an Atom.
|
||||
*/
|
||||
static inline double*
|
||||
lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, double beats)
|
||||
{
|
||||
return (double*)lv2_atom_forge_write(forge, &beats, sizeof(beats));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV2_ATOM_FORGE_H */
|
||||
424
libs/ardour/lv2/lv2plug.in/ns/ext/atom/util.h
Normal file
424
libs/ardour/lv2/lv2plug.in/ns/ext/atom/util.h
Normal file
|
|
@ -0,0 +1,424 @@
|
|||
/*
|
||||
Copyright 2008-2012 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@file util.h Helper functions for the LV2 Atom extension.
|
||||
|
||||
Note these functions are all static inline, do not take their address.
|
||||
|
||||
This header is non-normative, it is provided for convenience.
|
||||
*/
|
||||
|
||||
#ifndef LV2_ATOM_UTIL_H
|
||||
#define LV2_ATOM_UTIL_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#else
|
||||
# include <stdbool.h>
|
||||
#endif
|
||||
|
||||
/** Pad a size to 64 bits. */
|
||||
static inline uint32_t
|
||||
lv2_atom_pad_size(uint32_t size)
|
||||
{
|
||||
return (size + 7) & (~7);
|
||||
}
|
||||
|
||||
/** Return the total size of @p atom, including the header. */
|
||||
static inline uint32_t
|
||||
lv2_atom_total_size(const LV2_Atom* atom)
|
||||
{
|
||||
return sizeof(LV2_Atom) + atom->size;
|
||||
}
|
||||
|
||||
/** Return true iff @p atom is null. */
|
||||
static inline bool
|
||||
lv2_atom_is_null(const LV2_Atom* atom)
|
||||
{
|
||||
return !atom || (atom->type == 0 && atom->size == 0);
|
||||
}
|
||||
|
||||
/** Return true iff @p a is equal to @p b. */
|
||||
static inline bool
|
||||
lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b)
|
||||
{
|
||||
return (a == b) || ((a->type == b->type) &&
|
||||
(a->size == b->size) &&
|
||||
!memcmp(a + 1, b + 1, a->size));
|
||||
}
|
||||
|
||||
/**
|
||||
@name Sequence Iterator
|
||||
@{
|
||||
*/
|
||||
|
||||
/** An iterator over the elements of an LV2_Atom_Sequence. */
|
||||
typedef LV2_Atom_Event* LV2_Atom_Sequence_Iter;
|
||||
|
||||
/** Get an iterator pointing to the first element in a Sequence body. */
|
||||
static inline LV2_Atom_Sequence_Iter
|
||||
lv2_sequence_body_begin(const LV2_Atom_Sequence_Body* body)
|
||||
{
|
||||
return (LV2_Atom_Sequence_Iter)(body + 1);
|
||||
}
|
||||
|
||||
/** Get an iterator pointing to the first element in a Sequence. */
|
||||
static inline LV2_Atom_Sequence_Iter
|
||||
lv2_sequence_begin(const LV2_Atom_Sequence* seq)
|
||||
{
|
||||
return (LV2_Atom_Sequence_Iter)(seq + 1);
|
||||
}
|
||||
|
||||
/** Return true iff @p i has reached the end of @p body. */
|
||||
static inline bool
|
||||
lv2_sequence_body_is_end(const LV2_Atom_Sequence_Body* body,
|
||||
uint32_t size,
|
||||
LV2_Atom_Sequence_Iter i)
|
||||
{
|
||||
return (uint8_t*)i >= ((uint8_t*)body + size);
|
||||
}
|
||||
|
||||
/** Return true iff @p i has reached the end of @p seq. */
|
||||
static inline bool
|
||||
lv2_sequence_is_end(const LV2_Atom_Sequence* seq, LV2_Atom_Sequence_Iter i)
|
||||
{
|
||||
return (uint8_t*)i >= ((uint8_t*)seq + sizeof(LV2_Atom) + seq->atom.size);
|
||||
}
|
||||
|
||||
/** Return an iterator to the element following @p i. */
|
||||
static inline LV2_Atom_Sequence_Iter
|
||||
lv2_sequence_iter_next(const LV2_Atom_Sequence_Iter i)
|
||||
{
|
||||
return (LV2_Atom_Sequence_Iter)((uint8_t*)i
|
||||
+ sizeof(LV2_Atom_Event)
|
||||
+ lv2_atom_pad_size(i->body.size));
|
||||
}
|
||||
|
||||
/** Return the element pointed to by @p i. */
|
||||
static inline LV2_Atom_Event*
|
||||
lv2_sequence_iter_get(LV2_Atom_Sequence_Iter i)
|
||||
{
|
||||
return (LV2_Atom_Event*)i;
|
||||
}
|
||||
|
||||
/**
|
||||
A macro for iterating over all events in a Sequence.
|
||||
@param sequence The sequence to iterate over
|
||||
@param iter The name of the iterator
|
||||
|
||||
This macro is used similarly to a for loop (which it expands to), e.g.:
|
||||
@code
|
||||
LV2_SEQUENCE_FOREACH(sequence, i) {
|
||||
LV2_Atom_Event* ev = lv2_sequence_iter_get(i);
|
||||
// Do something with ev here...
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
#define LV2_SEQUENCE_FOREACH(sequence, iter) \
|
||||
for (LV2_Atom_Sequence_Iter (iter) = lv2_sequence_begin(sequence); \
|
||||
!lv2_sequence_is_end(sequence, (iter)); \
|
||||
(iter) = lv2_sequence_iter_next(iter))
|
||||
|
||||
/** A version of LV2_SEQUENCE_FOREACH for when only the body is available. */
|
||||
#define LV2_SEQUENCE_BODY_FOREACH(body, size, iter) \
|
||||
for (LV2_Atom_Sequence_Iter (iter) = lv2_sequence_body_begin(body); \
|
||||
!lv2_sequence_body_is_end(body, size, (iter)); \
|
||||
(iter) = lv2_sequence_iter_next(iter))
|
||||
|
||||
/**
|
||||
@}
|
||||
@name Tuple Iterator
|
||||
@{
|
||||
*/
|
||||
|
||||
/** An iterator over the elements of an LV2_Atom_Tuple. */
|
||||
typedef LV2_Atom* LV2_Atom_Tuple_Iter;
|
||||
|
||||
/** Get an iterator pointing to the first element in @p tup. */
|
||||
static inline LV2_Atom_Tuple_Iter
|
||||
lv2_tuple_begin(const LV2_Atom_Tuple* tup)
|
||||
{
|
||||
return (LV2_Atom_Tuple_Iter)(LV2_ATOM_BODY(tup));
|
||||
}
|
||||
|
||||
/** Return true iff @p i has reached the end of @p body. */
|
||||
static inline bool
|
||||
lv2_atom_tuple_body_is_end(const void* body,
|
||||
uint32_t size,
|
||||
LV2_Atom_Tuple_Iter i)
|
||||
{
|
||||
return (uint8_t*)i >= ((uint8_t*)body + size);
|
||||
}
|
||||
|
||||
/** Return true iff @p i has reached the end of @p tup. */
|
||||
static inline bool
|
||||
lv2_tuple_is_end(const LV2_Atom_Tuple* tup, LV2_Atom_Tuple_Iter i)
|
||||
{
|
||||
return lv2_atom_tuple_body_is_end(LV2_ATOM_BODY(tup), tup->atom.size, i);
|
||||
}
|
||||
|
||||
/** Return an iterator to the element following @p i. */
|
||||
static inline LV2_Atom_Tuple_Iter
|
||||
lv2_tuple_iter_next(const LV2_Atom_Tuple_Iter i)
|
||||
{
|
||||
return (LV2_Atom_Tuple_Iter)(
|
||||
(uint8_t*)i + sizeof(LV2_Atom) + lv2_atom_pad_size(i->size));
|
||||
}
|
||||
|
||||
/** Return the element pointed to by @p i. */
|
||||
static inline LV2_Atom*
|
||||
lv2_tuple_iter_get(LV2_Atom_Tuple_Iter i)
|
||||
{
|
||||
return (LV2_Atom*)i;
|
||||
}
|
||||
|
||||
/**
|
||||
A macro for iterating over all properties of a Tuple.
|
||||
@param tuple The tuple to iterate over
|
||||
@param iter The name of the iterator
|
||||
|
||||
This macro is used similarly to a for loop (which it expands to), e.g.:
|
||||
@code
|
||||
LV2_TUPLE_FOREACH(tuple, i) {
|
||||
LV2_Atom* elem = lv2_tuple_iter_get(i);
|
||||
// Do something with elem here...
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
#define LV2_TUPLE_FOREACH(tuple, iter) \
|
||||
for (LV2_Atom_Tuple_Iter (iter) = lv2_tuple_begin(tuple); \
|
||||
!lv2_tuple_is_end(tuple, (iter)); \
|
||||
(iter) = lv2_tuple_iter_next(iter))
|
||||
|
||||
/** A version of LV2_TUPLE_FOREACH for when only the body is available. */
|
||||
#define LV2_TUPLE_BODY_FOREACH(body, size, iter) \
|
||||
for (LV2_Atom_Tuple_Iter (iter) = (LV2_Atom_Tuple_Iter)body; \
|
||||
!lv2_atom_tuple_body_is_end(body, size, (iter)); \
|
||||
(iter) = lv2_tuple_iter_next(iter))
|
||||
|
||||
/**
|
||||
@}
|
||||
@name Object Iterator
|
||||
@{
|
||||
*/
|
||||
|
||||
/** An iterator over the properties of an LV2_Atom_Object. */
|
||||
typedef LV2_Atom_Property_Body* LV2_Atom_Object_Iter;
|
||||
|
||||
static inline LV2_Atom_Object_Iter
|
||||
lv2_object_body_begin(const LV2_Atom_Object_Body* body)
|
||||
{
|
||||
return (LV2_Atom_Object_Iter)(body + 1);
|
||||
}
|
||||
|
||||
/** Get an iterator pointing to the first property in @p obj. */
|
||||
static inline LV2_Atom_Object_Iter
|
||||
lv2_object_begin(const LV2_Atom_Object* obj)
|
||||
{
|
||||
return (LV2_Atom_Object_Iter)(obj + 1);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
lv2_atom_object_body_is_end(const LV2_Atom_Object_Body* body,
|
||||
uint32_t size,
|
||||
LV2_Atom_Object_Iter i)
|
||||
{
|
||||
return (uint8_t*)i >= ((uint8_t*)body + size);
|
||||
}
|
||||
|
||||
/** Return true iff @p i has reached the end of @p obj. */
|
||||
static inline bool
|
||||
lv2_object_is_end(const LV2_Atom_Object* obj, LV2_Atom_Object_Iter i)
|
||||
{
|
||||
return (uint8_t*)i >= ((uint8_t*)obj + sizeof(LV2_Atom) + obj->atom.size);
|
||||
}
|
||||
|
||||
/** Return an iterator to the property following @p i. */
|
||||
static inline LV2_Atom_Object_Iter
|
||||
lv2_object_iter_next(const LV2_Atom_Object_Iter i)
|
||||
{
|
||||
const LV2_Atom* const value = (LV2_Atom*)((uint8_t*)i + sizeof(i));
|
||||
return (LV2_Atom_Object_Iter)((uint8_t*)i
|
||||
+ sizeof(LV2_Atom_Property_Body)
|
||||
+ lv2_atom_pad_size(value->size));
|
||||
}
|
||||
|
||||
/** Return the property pointed to by @p i. */
|
||||
static inline LV2_Atom_Property_Body*
|
||||
lv2_object_iter_get(LV2_Atom_Object_Iter i)
|
||||
{
|
||||
return (LV2_Atom_Property_Body*)i;
|
||||
}
|
||||
|
||||
/**
|
||||
A macro for iterating over all properties of an Object.
|
||||
@param object The object to iterate over
|
||||
@param iter The name of the iterator
|
||||
|
||||
This macro is used similarly to a for loop (which it expands to), e.g.:
|
||||
@code
|
||||
LV2_OBJECT_FOREACH(object, i) {
|
||||
LV2_Atom_Property_Body* prop = lv2_object_iter_get(i);
|
||||
// Do something with prop here...
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
#define LV2_OBJECT_FOREACH(object, iter) \
|
||||
for (LV2_Atom_Object_Iter (iter) = lv2_object_begin(object); \
|
||||
!lv2_object_is_end(object, (iter)); \
|
||||
(iter) = lv2_object_iter_next(iter))
|
||||
|
||||
/** A version of LV2_OBJECT_FOREACH for when only the body is available. */
|
||||
#define LV2_OBJECT_BODY_FOREACH(body, size, iter) \
|
||||
for (LV2_Atom_Object_Iter (iter) = lv2_object_body_begin(body); \
|
||||
!lv2_atom_object_body_is_end(body, size, (iter)); \
|
||||
(iter) = lv2_object_iter_next(iter))
|
||||
|
||||
/**
|
||||
@}
|
||||
@name Object Query
|
||||
@{
|
||||
*/
|
||||
|
||||
/** A single entry in an Object query. */
|
||||
typedef struct {
|
||||
uint32_t key; /**< Key to query (input set by user) */
|
||||
const LV2_Atom** value; /**< Found value (output set by query function) */
|
||||
} LV2_Atom_Object_Query;
|
||||
|
||||
static const LV2_Atom_Object_Query LV2_OBJECT_QUERY_END = { 0, NULL };
|
||||
|
||||
/**
|
||||
Get an object's values for various keys.
|
||||
|
||||
The value pointer of each item in @p query will be set to the location of
|
||||
the corresponding value in @p object. Every value pointer in @p query MUST
|
||||
be initialised to NULL. This function reads @p object in a single linear
|
||||
sweep. By allocating @p query on the stack, objects can be "queried"
|
||||
quickly without allocating any memory. This function is realtime safe.
|
||||
|
||||
This function can only do "flat" queries, it is not smart enough to match
|
||||
variables in nested objects.
|
||||
|
||||
For example:
|
||||
@code
|
||||
const LV2_Atom* name = NULL;
|
||||
const LV2_Atom* age = NULL;
|
||||
LV2_Atom_Object_Query q[] = {
|
||||
{ urids.eg_name, &name },
|
||||
{ urids.eg_age, &age },
|
||||
LV2_OBJECT_QUERY_END
|
||||
};
|
||||
lv2_object_query(obj, q);
|
||||
// name and age are now set to the appropriate values in obj, or NULL.
|
||||
@endcode
|
||||
*/
|
||||
static inline int
|
||||
lv2_object_query(const LV2_Atom_Object* object, LV2_Atom_Object_Query* query)
|
||||
{
|
||||
int matches = 0;
|
||||
int n_queries = 0;
|
||||
|
||||
/* Count number of query keys so we can short-circuit when done */
|
||||
for (LV2_Atom_Object_Query* q = query; q->key; ++q) {
|
||||
++n_queries;
|
||||
}
|
||||
|
||||
LV2_OBJECT_FOREACH(object, o) {
|
||||
const LV2_Atom_Property_Body* prop = lv2_object_iter_get(o);
|
||||
for (LV2_Atom_Object_Query* q = query; q->key; ++q) {
|
||||
if (q->key == prop->key && !*q->value) {
|
||||
*q->value = &prop->value;
|
||||
if (++matches == n_queries) {
|
||||
return matches;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
Variable argument version of lv2_object_get().
|
||||
|
||||
This is nicer-looking in code, but a bit more error-prone since it is not
|
||||
type safe and the argument list must be terminated.
|
||||
|
||||
The arguments should be a series of uint32_t key and const LV2_Atom** value
|
||||
pairs, terminated by a zero key. The value pointers MUST be initialized to
|
||||
NULL. For example:
|
||||
|
||||
@code
|
||||
const LV2_Atom* name = NULL;
|
||||
const LV2_Atom* age = NULL;
|
||||
lv2_object_get(obj,
|
||||
uris.name_key, &name,
|
||||
uris.age_key, &age,
|
||||
0);
|
||||
@endcode
|
||||
*/
|
||||
static inline int
|
||||
lv2_object_get(const LV2_Atom_Object* object, ...)
|
||||
{
|
||||
int matches = 0;
|
||||
int n_queries = 0;
|
||||
|
||||
/* Count number of keys so we can short-circuit when done */
|
||||
va_list args;
|
||||
va_start(args, object);
|
||||
for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) {
|
||||
if (!va_arg(args, const LV2_Atom**)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
LV2_OBJECT_FOREACH(object, o) {
|
||||
const LV2_Atom_Property_Body* prop = lv2_object_iter_get(o);
|
||||
va_start(args, object);
|
||||
for (int i = 0; i < n_queries; ++i) {
|
||||
uint32_t qkey = va_arg(args, uint32_t);
|
||||
const LV2_Atom** qval = va_arg(args, const LV2_Atom**);
|
||||
if (qkey == prop->key && !*qval) {
|
||||
*qval = &prop->value;
|
||||
if (++matches == n_queries) {
|
||||
return matches;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV2_ATOM_UTIL_H */
|
||||
264
libs/ardour/lv2_evbuf.c
Normal file
264
libs/ardour/lv2_evbuf.c
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
Copyright 2008-2012 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/event/event.h"
|
||||
|
||||
#include "lv2_evbuf.h"
|
||||
|
||||
struct LV2_Evbuf_Impl {
|
||||
LV2_Evbuf_Type type;
|
||||
uint32_t capacity;
|
||||
union {
|
||||
LV2_Event_Buffer event;
|
||||
LV2_Atom_Port_Buffer atom;
|
||||
} buf;
|
||||
};
|
||||
|
||||
static inline uint32_t
|
||||
lv2_evbuf_pad_size(uint32_t size)
|
||||
{
|
||||
return (size + 7) & (~7);
|
||||
}
|
||||
|
||||
LV2_Evbuf*
|
||||
lv2_evbuf_new(uint32_t capacity, LV2_Evbuf_Type type, uint32_t atom_type)
|
||||
{
|
||||
// FIXME: memory must be 64-bit aligned
|
||||
LV2_Evbuf* evbuf = (LV2_Evbuf*)malloc(
|
||||
sizeof(LV2_Evbuf) + sizeof(LV2_Atom_Sequence) + capacity);
|
||||
evbuf->capacity = capacity;
|
||||
lv2_evbuf_set_type(evbuf, type, atom_type);
|
||||
lv2_evbuf_reset(evbuf);
|
||||
return evbuf;
|
||||
}
|
||||
|
||||
void
|
||||
lv2_evbuf_free(LV2_Evbuf* evbuf)
|
||||
{
|
||||
free(evbuf);
|
||||
}
|
||||
|
||||
void
|
||||
lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type, uint32_t atom_type)
|
||||
{
|
||||
evbuf->type = type;
|
||||
switch (type) {
|
||||
case LV2_EVBUF_EVENT:
|
||||
evbuf->buf.event.data = (uint8_t*)(evbuf + 1);
|
||||
evbuf->buf.event.capacity = evbuf->capacity;
|
||||
break;
|
||||
case LV2_EVBUF_ATOM:
|
||||
evbuf->buf.atom.data = (LV2_Atom*)(evbuf + 1);
|
||||
evbuf->buf.atom.size = sizeof(LV2_Atom_Port_Buffer);
|
||||
evbuf->buf.atom.capacity = evbuf->capacity;
|
||||
evbuf->buf.atom.data->type = atom_type;
|
||||
evbuf->buf.atom.data->size = 0;
|
||||
break;
|
||||
}
|
||||
lv2_evbuf_reset(evbuf);
|
||||
}
|
||||
|
||||
void
|
||||
lv2_evbuf_reset(LV2_Evbuf* evbuf)
|
||||
{
|
||||
switch (evbuf->type) {
|
||||
case LV2_EVBUF_EVENT:
|
||||
evbuf->buf.event.header_size = sizeof(LV2_Event_Buffer);
|
||||
evbuf->buf.event.stamp_type = LV2_EVENT_AUDIO_STAMP;
|
||||
evbuf->buf.event.event_count = 0;
|
||||
evbuf->buf.event.size = 0;
|
||||
break;
|
||||
case LV2_EVBUF_ATOM:
|
||||
evbuf->buf.atom.data->size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
lv2_evbuf_get_size(LV2_Evbuf* evbuf)
|
||||
{
|
||||
switch (evbuf->type) {
|
||||
case LV2_EVBUF_EVENT:
|
||||
return evbuf->buf.event.size;
|
||||
case LV2_EVBUF_ATOM:
|
||||
return evbuf->buf.atom.data->size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
lv2_evbuf_get_buffer(LV2_Evbuf* evbuf)
|
||||
{
|
||||
switch (evbuf->type) {
|
||||
case LV2_EVBUF_EVENT:
|
||||
return &evbuf->buf.event;
|
||||
case LV2_EVBUF_ATOM:
|
||||
return &evbuf->buf.atom;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LV2_Evbuf_Iterator
|
||||
lv2_evbuf_begin(LV2_Evbuf* evbuf)
|
||||
{
|
||||
LV2_Evbuf_Iterator iter = { evbuf, 0 };
|
||||
return iter;
|
||||
}
|
||||
|
||||
LV2_Evbuf_Iterator
|
||||
lv2_evbuf_end(LV2_Evbuf* evbuf)
|
||||
{
|
||||
const size_t size = lv2_evbuf_get_size(evbuf);
|
||||
const LV2_Evbuf_Iterator iter = { evbuf, lv2_evbuf_pad_size(size) };
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool
|
||||
lv2_evbuf_is_valid(LV2_Evbuf_Iterator iter)
|
||||
{
|
||||
return iter.offset < lv2_evbuf_get_size(iter.evbuf);
|
||||
}
|
||||
|
||||
LV2_Evbuf_Iterator
|
||||
lv2_evbuf_next(LV2_Evbuf_Iterator iter)
|
||||
{
|
||||
if (!lv2_evbuf_is_valid(iter)) {
|
||||
return iter;
|
||||
}
|
||||
|
||||
LV2_Evbuf* evbuf = iter.evbuf;
|
||||
uint32_t offset = iter.offset;
|
||||
uint32_t size;
|
||||
switch (evbuf->type) {
|
||||
case LV2_EVBUF_EVENT:
|
||||
size = ((LV2_Event*)(evbuf->buf.event.data + offset))->size;
|
||||
offset += lv2_evbuf_pad_size(sizeof(LV2_Event) + size);
|
||||
break;
|
||||
case LV2_EVBUF_ATOM:
|
||||
size = ((LV2_Atom_Event*)
|
||||
((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, evbuf->buf.atom.data)
|
||||
+ offset))->body.size;
|
||||
offset += lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
|
||||
break;
|
||||
}
|
||||
|
||||
LV2_Evbuf_Iterator next = { evbuf, offset };
|
||||
return next;
|
||||
}
|
||||
|
||||
bool
|
||||
lv2_evbuf_get(LV2_Evbuf_Iterator iter,
|
||||
uint32_t* frames,
|
||||
uint32_t* subframes,
|
||||
uint32_t* type,
|
||||
uint32_t* size,
|
||||
uint8_t** data)
|
||||
{
|
||||
*frames = *subframes = *type = *size = 0;
|
||||
*data = NULL;
|
||||
|
||||
if (!lv2_evbuf_is_valid(iter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LV2_Event_Buffer* ebuf;
|
||||
LV2_Event* ev;
|
||||
LV2_Atom_Port_Buffer* abuf;
|
||||
LV2_Atom_Event* aev;
|
||||
switch (iter.evbuf->type) {
|
||||
case LV2_EVBUF_EVENT:
|
||||
ebuf = &iter.evbuf->buf.event;
|
||||
ev = (LV2_Event*)ebuf->data + iter.offset;
|
||||
*frames = ev->frames;
|
||||
*subframes = ev->subframes;
|
||||
*type = ev->type;
|
||||
*size = ev->size;
|
||||
*data = (uint8_t*)ev + sizeof(LV2_Event);
|
||||
break;
|
||||
case LV2_EVBUF_ATOM:
|
||||
abuf = &iter.evbuf->buf.atom;
|
||||
aev = (LV2_Atom_Event*)(
|
||||
(char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, abuf->data)
|
||||
+ iter.offset);
|
||||
*frames = aev->time.frames;
|
||||
*subframes = 0;
|
||||
*type = aev->body.type;
|
||||
*size = aev->body.size;
|
||||
*data = LV2_ATOM_BODY(&aev->body);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
|
||||
uint32_t frames,
|
||||
uint32_t subframes,
|
||||
uint32_t type,
|
||||
uint32_t size,
|
||||
const uint8_t* data)
|
||||
{
|
||||
LV2_Event_Buffer* ebuf;
|
||||
LV2_Event* ev;
|
||||
LV2_Atom_Port_Buffer* abuf;
|
||||
LV2_Atom_Event* aev;
|
||||
switch (iter->evbuf->type) {
|
||||
case LV2_EVBUF_EVENT:
|
||||
ebuf = &iter->evbuf->buf.event;
|
||||
if (ebuf->capacity - ebuf->size < sizeof(LV2_Event) + size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ev = (LV2_Event*)(ebuf->data + iter->offset);
|
||||
ev->frames = frames;
|
||||
ev->subframes = subframes;
|
||||
ev->type = type;
|
||||
ev->size = size;
|
||||
memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size);
|
||||
|
||||
size = lv2_evbuf_pad_size(sizeof(LV2_Event) + size);
|
||||
ebuf->size += size;
|
||||
ebuf->event_count += 1;
|
||||
iter->offset += size;
|
||||
break;
|
||||
case LV2_EVBUF_ATOM:
|
||||
abuf = &iter->evbuf->buf.atom;
|
||||
if (abuf->capacity - abuf->data->size < sizeof(LV2_Atom_Event) + size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aev = (LV2_Atom_Event*)(
|
||||
(char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, abuf->data)
|
||||
+ iter->offset);
|
||||
aev->time.frames = frames;
|
||||
aev->body.type = type;
|
||||
aev->body.size = size;
|
||||
memcpy(LV2_ATOM_BODY(&aev->body), data, size);
|
||||
|
||||
size = lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
|
||||
abuf->data->size += size;
|
||||
iter->offset += size;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
161
libs/ardour/lv2_evbuf.h
Normal file
161
libs/ardour/lv2_evbuf.h
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
Copyright 2008-2012 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LV2_EVBUF_H
|
||||
#define LV2_EVBUF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Format of actual buffer.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
An (old) ev:EventBuffer (LV2_Event_Buffer).
|
||||
*/
|
||||
LV2_EVBUF_EVENT,
|
||||
|
||||
/**
|
||||
A (new) atom:Sequence (LV2_Atom_Sequence).
|
||||
*/
|
||||
LV2_EVBUF_ATOM
|
||||
} LV2_Evbuf_Type;
|
||||
|
||||
/**
|
||||
An abstract/opaque LV2 event buffer.
|
||||
*/
|
||||
typedef struct LV2_Evbuf_Impl LV2_Evbuf;
|
||||
|
||||
/**
|
||||
An iterator over an LV2_Evbuf.
|
||||
*/
|
||||
typedef struct {
|
||||
LV2_Evbuf* evbuf;
|
||||
uint32_t offset;
|
||||
} LV2_Evbuf_Iterator;
|
||||
|
||||
/**
|
||||
Allocate a new, empty event buffer.
|
||||
The URID for atom:Sequence must be passed for atom_Sequence if type is
|
||||
LV2_EVBUF_ATOM.
|
||||
*/
|
||||
LV2_Evbuf*
|
||||
lv2_evbuf_new(uint32_t capacity, LV2_Evbuf_Type type, uint32_t atom_type);
|
||||
|
||||
/**
|
||||
Free an event buffer allocated with lv2_evbuf_new.
|
||||
*/
|
||||
void
|
||||
lv2_evbuf_free(LV2_Evbuf* evbuf);
|
||||
|
||||
/**
|
||||
Change the type of an existing event buffer. This will clear and reset the
|
||||
buffer, it is not possible to change the type and preserve the buffer
|
||||
contents since the formats differ. The URID for atom:Sequence must be
|
||||
passed for atom_Sequence if type is LV2_EVBUF_ATOM.
|
||||
*/
|
||||
void
|
||||
lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type, uint32_t atom_type);
|
||||
|
||||
/**
|
||||
Clear and initialize an existing event buffer.
|
||||
The contents of buf are ignored entirely and overwritten, except capacity
|
||||
which is unmodified.
|
||||
*/
|
||||
void
|
||||
lv2_evbuf_reset(LV2_Evbuf* evbuf);
|
||||
|
||||
/**
|
||||
Return the total padded size of the events stored in the buffer.
|
||||
*/
|
||||
uint32_t
|
||||
lv2_evbuf_get_size(LV2_Evbuf* evbuf);
|
||||
|
||||
/**
|
||||
Return the actual buffer implementation.
|
||||
The format of the buffer returned depends on the buffer type.
|
||||
*/
|
||||
void*
|
||||
lv2_evbuf_get_buffer(LV2_Evbuf* evbuf);
|
||||
|
||||
/**
|
||||
Return an iterator to the start of @p buf.
|
||||
*/
|
||||
LV2_Evbuf_Iterator
|
||||
lv2_evbuf_begin(LV2_Evbuf* evbuf);
|
||||
|
||||
/**
|
||||
Return an iterator to the end of @a buf.
|
||||
*/
|
||||
LV2_Evbuf_Iterator
|
||||
lv2_evbuf_end(LV2_Evbuf* evbuf);
|
||||
|
||||
/**
|
||||
Check if @p iter is valid.
|
||||
@return True if @p iter is valid, otherwise false (past end of buffer)
|
||||
*/
|
||||
bool
|
||||
lv2_evbuf_is_valid(LV2_Evbuf_Iterator iter);
|
||||
|
||||
/**
|
||||
Advance @p iter forward one event.
|
||||
@p iter must be valid.
|
||||
@return True if @p iter is valid, otherwise false (reached end of buffer)
|
||||
*/
|
||||
LV2_Evbuf_Iterator
|
||||
lv2_evbuf_next(LV2_Evbuf_Iterator iter);
|
||||
|
||||
/**
|
||||
Dereference an event iterator (i.e. get the event currently pointed to).
|
||||
@p iter must be valid.
|
||||
@p type Set to the type of the event.
|
||||
@p size Set to the size of the event.
|
||||
@p data Set to the contents of the event.
|
||||
@return True on success.
|
||||
*/
|
||||
bool
|
||||
lv2_evbuf_get(LV2_Evbuf_Iterator iter,
|
||||
uint32_t* frames,
|
||||
uint32_t* subframes,
|
||||
uint32_t* type,
|
||||
uint32_t* size,
|
||||
uint8_t** data);
|
||||
|
||||
/**
|
||||
Write an event at @p iter.
|
||||
The event (if any) pointed to by @p iter will be overwritten, and @p iter
|
||||
incremented to point to the following event (i.e. several calls to this
|
||||
function can be done in sequence without twiddling iter in-between).
|
||||
@return True if event was written, otherwise false (buffer is full).
|
||||
*/
|
||||
bool
|
||||
lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
|
||||
uint32_t frames,
|
||||
uint32_t subframes,
|
||||
uint32_t type,
|
||||
uint32_t size,
|
||||
const uint8_t* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LV2_EVBUF_H */
|
||||
|
|
@ -1,196 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2009 Paul Davis
|
||||
Author: David Robillard
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <iostream>
|
||||
#include "lv2/lv2plug.in/ns/ext/event/event.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/event/event-helpers.h"
|
||||
#include "ardour/lv2_event_buffer.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
|
||||
/** Allocate a new event buffer.
|
||||
* \a capacity is in bytes (not number of events).
|
||||
*/
|
||||
LV2EventBuffer::LV2EventBuffer(size_t capacity)
|
||||
: _latest_frames(0)
|
||||
, _latest_subframes(0)
|
||||
{
|
||||
if (capacity > UINT32_MAX) {
|
||||
cerr << "Event buffer size " << capacity << " too large, aborting." << endl;
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
if (capacity == 0) {
|
||||
cerr << "ERROR: LV2 event buffer of size 0 created." << endl;
|
||||
capacity = 1024;
|
||||
}
|
||||
|
||||
#ifdef NO_POSIX_MEMALIGN
|
||||
_data = (LV2_Event_Buffer*)malloc(sizeof(LV2_Event_Buffer) + capacity);
|
||||
int ret = (_data != NULL) ? 0 : -1;
|
||||
#else
|
||||
int ret = posix_memalign((void**)&_data, 16, sizeof(LV2_Event_Buffer) + capacity);
|
||||
#endif
|
||||
|
||||
if (ret != 0) {
|
||||
cerr << "Failed to allocate event buffer. Aborting." << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
_data->event_count = 0;
|
||||
_data->capacity = (uint32_t)capacity;
|
||||
_data->size = 0;
|
||||
_data->data = reinterpret_cast<uint8_t*>(_data + 1);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
LV2EventBuffer::~LV2EventBuffer()
|
||||
{
|
||||
free(_data);
|
||||
}
|
||||
|
||||
|
||||
/** Increment the read position by one event.
|
||||
*
|
||||
* \return true if increment was successful, or false if end of buffer reached.
|
||||
*/
|
||||
bool
|
||||
LV2EventBuffer::increment() const
|
||||
{
|
||||
if (lv2_event_is_valid(&_iter)) {
|
||||
lv2_event_increment(&_iter);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** \return true iff the cursor is valid (ie get_event is safe)
|
||||
*/
|
||||
bool
|
||||
LV2EventBuffer::is_valid() const
|
||||
{
|
||||
return lv2_event_is_valid(&_iter);
|
||||
}
|
||||
|
||||
|
||||
/** Read an event from the current position in the buffer
|
||||
*
|
||||
* \return true if read was successful, or false if end of buffer reached
|
||||
*/
|
||||
bool
|
||||
LV2EventBuffer::get_event(uint32_t* frames,
|
||||
uint32_t* subframes,
|
||||
uint16_t* type,
|
||||
uint16_t* size,
|
||||
uint8_t** data) const
|
||||
{
|
||||
if (lv2_event_is_valid(&_iter)) {
|
||||
LV2_Event* ev = lv2_event_get(&_iter, data);
|
||||
*frames = ev->frames;
|
||||
*subframes = ev->subframes;
|
||||
*type = ev->type;
|
||||
*size = ev->size;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Append an event to the buffer.
|
||||
*
|
||||
* \a timestamp must be >= the latest event in the buffer.
|
||||
*
|
||||
* \return true on success
|
||||
*/
|
||||
bool
|
||||
LV2EventBuffer::append(uint32_t frames,
|
||||
uint32_t subframes,
|
||||
uint16_t type,
|
||||
uint16_t size,
|
||||
const uint8_t* data)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (lv2_event_is_valid(&_iter)) {
|
||||
LV2_Event* last_event = lv2_event_get(&_iter, NULL);
|
||||
assert(last_event->frames < frames
|
||||
|| (last_event->frames == frames && last_event->subframes <= subframes));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*cout << "Appending event type " << type << ", size " << size
|
||||
<< " @ " << frames << "." << subframes << endl;
|
||||
cout << "Buffer capacity " << _data->capacity << ", size " << _data->size << endl;*/
|
||||
|
||||
if (!lv2_event_write(&_iter, frames, subframes, type, size, data)) {
|
||||
cerr << "ERROR: Failed to write event." << endl;
|
||||
return false;
|
||||
} else {
|
||||
_latest_frames = frames;
|
||||
_latest_subframes = subframes;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Append a buffer of events to the buffer.
|
||||
*
|
||||
* \a timestamp must be >= the latest event in the buffer.
|
||||
*
|
||||
* \return true on success
|
||||
*/
|
||||
bool
|
||||
LV2EventBuffer::append(const LV2_Event_Buffer* /*buf*/)
|
||||
{
|
||||
uint8_t** data = NULL;
|
||||
bool ret = true;
|
||||
|
||||
LV2_Event_Iterator iter;
|
||||
for (lv2_event_begin(&iter, _data); lv2_event_is_valid(&iter); lv2_event_increment(&iter)) {
|
||||
LV2_Event* ev = lv2_event_get(&iter, data);
|
||||
|
||||
#ifndef NDEBUG
|
||||
assert((ev->frames > _latest_frames)
|
||||
|| (ev->frames == _latest_frames
|
||||
&& ev->subframes >= _latest_subframes));
|
||||
#endif
|
||||
|
||||
if (!(ret = append(ev->frames, ev->subframes, ev->type, ev->size, *data))) {
|
||||
cerr << "ERROR: Failed to write event." << endl;
|
||||
break;
|
||||
}
|
||||
|
||||
_latest_frames = ev->frames;
|
||||
_latest_subframes = ev->subframes;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
|
|
@ -41,7 +41,6 @@
|
|||
#include "ardour/audio_buffer.h"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/lv2_event_buffer.h"
|
||||
#include "ardour/lv2_plugin.h"
|
||||
#include "ardour/session.h"
|
||||
|
||||
|
|
@ -50,8 +49,11 @@
|
|||
|
||||
#include <lilv/lilv.h>
|
||||
|
||||
#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/state/state.h"
|
||||
#include "rdff.h"
|
||||
|
||||
#include "lv2_evbuf.h"
|
||||
|
||||
#ifdef HAVE_SUIL
|
||||
#include <suil/suil.h>
|
||||
#endif
|
||||
|
|
@ -66,11 +68,16 @@ using namespace ARDOUR;
|
|||
using namespace PBD;
|
||||
|
||||
URIMap LV2Plugin::_uri_map;
|
||||
uint32_t LV2Plugin::_midi_event_type_ev = _uri_map.uri_to_id(
|
||||
"http://lv2plug.in/ns/ext/event",
|
||||
"http://lv2plug.in/ns/ext/midi#MidiEvent");
|
||||
uint32_t LV2Plugin::_midi_event_type = _uri_map.uri_to_id(
|
||||
"http://lv2plug.in/ns/ext/event",
|
||||
"http://lv2plug.in/ns/ext/midi#MidiEvent");
|
||||
NULL,
|
||||
"http://lv2plug.in/ns/ext/midi#MidiEvent");
|
||||
uint32_t LV2Plugin::_sequence_type = _uri_map.uri_to_id(
|
||||
NULL, LV2_ATOM__Sequence);
|
||||
uint32_t LV2Plugin::_state_path_type = _uri_map.uri_to_id(
|
||||
NULL, LV2_STATE_PATH_URI);
|
||||
NULL, LV2_STATE_PATH_URI);
|
||||
|
||||
class LV2World : boost::noncopyable {
|
||||
public:
|
||||
|
|
@ -84,6 +91,9 @@ public:
|
|||
LilvNode* control_class; ///< Control port
|
||||
LilvNode* event_class; ///< Event port
|
||||
LilvNode* midi_class; ///< MIDI event
|
||||
LilvNode* message_port_class;
|
||||
LilvNode* buffer_type;
|
||||
LilvNode* sequence_class;
|
||||
LilvNode* in_place_broken;
|
||||
LilvNode* integer;
|
||||
LilvNode* toggled;
|
||||
|
|
@ -220,6 +230,13 @@ LV2Plugin::init(void* c_plugin, framecnt_t rate)
|
|||
flags |= PORT_AUDIO;
|
||||
} else if (lilv_port_is_a(_impl->plugin, port, _world.event_class)) {
|
||||
flags |= PORT_EVENT;
|
||||
} else if (lilv_port_is_a(_impl->plugin, port, _world.message_port_class)) {
|
||||
LilvNodes* buffer_types = lilv_port_get_value(
|
||||
_impl->plugin, port, _world.buffer_type);
|
||||
if (lilv_nodes_contains(buffer_types, _world.sequence_class)) {
|
||||
flags |= PORT_MESSAGE;
|
||||
}
|
||||
lilv_nodes_free(buffer_types);
|
||||
} else {
|
||||
error << string_compose(
|
||||
"LV2: \"%1\" port %2 has no known data type",
|
||||
|
|
@ -953,37 +970,41 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||
uint32_t midi_out_index = 0;
|
||||
bool valid;
|
||||
for (uint32_t port_index = 0; port_index < num_ports; ++port_index) {
|
||||
void* buf = NULL;
|
||||
uint32_t index = 0;
|
||||
if (parameter_is_audio(port_index)) {
|
||||
if (parameter_is_input(port_index)) {
|
||||
void* buf = NULL;
|
||||
uint32_t index = 0;
|
||||
PortFlags flags = _port_flags[port_index];
|
||||
if (flags & PORT_AUDIO) {
|
||||
if (flags & PORT_INPUT) {
|
||||
index = in_map.get(DataType::AUDIO, audio_in_index++, &valid);
|
||||
buf = (valid)
|
||||
? bufs.get_audio(index).data(offset)
|
||||
: silent_bufs.get_audio(0).data(offset);
|
||||
} else if (parameter_is_output(port_index)) {
|
||||
} else {
|
||||
index = out_map.get(DataType::AUDIO, audio_out_index++, &valid);
|
||||
buf = (valid)
|
||||
? bufs.get_audio(index).data(offset)
|
||||
: scratch_bufs.get_audio(0).data(offset);
|
||||
}
|
||||
} else if (parameter_is_event(port_index)) {
|
||||
} else if (flags & (PORT_EVENT|PORT_MESSAGE)) {
|
||||
/* FIXME: The checks here for bufs.count().n_midi() > index shouldn't
|
||||
be necessary, but the mapping is illegal in some cases. Ideally
|
||||
that should be fixed, but this is easier...
|
||||
*/
|
||||
if (parameter_is_input(port_index)) {
|
||||
const uint32_t atom_type = (flags & PORT_MESSAGE) ? _sequence_type : 0;
|
||||
if (flags & PORT_INPUT) {
|
||||
index = in_map.get(DataType::MIDI, midi_in_index++, &valid);
|
||||
buf = (valid && bufs.count().n_midi() > index)
|
||||
? bufs.get_lv2_midi(true, index).data()
|
||||
: silent_bufs.get_lv2_midi(true, 0).data();
|
||||
} else if (parameter_is_output(port_index)) {
|
||||
? lv2_evbuf_get_buffer(bufs.get_lv2_midi(true, index, atom_type))
|
||||
: lv2_evbuf_get_buffer(silent_bufs.get_lv2_midi(true, 0, atom_type));
|
||||
} else {
|
||||
index = out_map.get(DataType::MIDI, midi_out_index++, &valid);
|
||||
buf = (valid && bufs.count().n_midi() > index)
|
||||
? bufs.get_lv2_midi(false, index).data()
|
||||
: scratch_bufs.get_lv2_midi(true, 0).data();
|
||||
? lv2_evbuf_get_buffer(bufs.get_lv2_midi(false, index, atom_type))
|
||||
: lv2_evbuf_get_buffer(scratch_bufs.get_lv2_midi(false, 0, atom_type));
|
||||
}
|
||||
} // else port is optional (or we shouldn't have made it this far)
|
||||
} else {
|
||||
continue; // Control port, leave buffer alone
|
||||
}
|
||||
lilv_instance_connect_port(_impl->instance, port_index, buf);
|
||||
}
|
||||
|
||||
|
|
@ -1138,19 +1159,22 @@ LV2World::LV2World()
|
|||
: world(lilv_world_new())
|
||||
{
|
||||
lilv_world_load_all(world);
|
||||
input_class = lilv_new_uri(world, LILV_URI_INPUT_PORT);
|
||||
output_class = lilv_new_uri(world, LILV_URI_OUTPUT_PORT);
|
||||
control_class = lilv_new_uri(world, LILV_URI_CONTROL_PORT);
|
||||
audio_class = lilv_new_uri(world, LILV_URI_AUDIO_PORT);
|
||||
event_class = lilv_new_uri(world, LILV_URI_EVENT_PORT);
|
||||
midi_class = lilv_new_uri(world, LILV_URI_MIDI_EVENT);
|
||||
in_place_broken = lilv_new_uri(world, LILV_NS_LV2 "inPlaceBroken");
|
||||
integer = lilv_new_uri(world, LILV_NS_LV2 "integer");
|
||||
toggled = lilv_new_uri(world, LILV_NS_LV2 "toggled");
|
||||
srate = lilv_new_uri(world, LILV_NS_LV2 "sampleRate");
|
||||
gtk_gui = lilv_new_uri(world, NS_UI "GtkUI");
|
||||
external_gui = lilv_new_uri(world, NS_UI "external");
|
||||
logarithmic = lilv_new_uri(world, "http://lv2plug.in/ns/dev/extportinfo#logarithmic");
|
||||
input_class = lilv_new_uri(world, LILV_URI_INPUT_PORT);
|
||||
output_class = lilv_new_uri(world, LILV_URI_OUTPUT_PORT);
|
||||
control_class = lilv_new_uri(world, LILV_URI_CONTROL_PORT);
|
||||
audio_class = lilv_new_uri(world, LILV_URI_AUDIO_PORT);
|
||||
event_class = lilv_new_uri(world, LILV_URI_EVENT_PORT);
|
||||
midi_class = lilv_new_uri(world, LILV_URI_MIDI_EVENT);
|
||||
message_port_class = lilv_new_uri(world, LV2_ATOM__MessagePort);
|
||||
buffer_type = lilv_new_uri(world, LV2_ATOM__bufferType);
|
||||
sequence_class = lilv_new_uri(world, LV2_ATOM__Sequence);
|
||||
in_place_broken = lilv_new_uri(world, LILV_NS_LV2 "inPlaceBroken");
|
||||
integer = lilv_new_uri(world, LILV_NS_LV2 "integer");
|
||||
toggled = lilv_new_uri(world, LILV_NS_LV2 "toggled");
|
||||
srate = lilv_new_uri(world, LILV_NS_LV2 "sampleRate");
|
||||
gtk_gui = lilv_new_uri(world, NS_UI "GtkUI");
|
||||
external_gui = lilv_new_uri(world, NS_UI "external");
|
||||
logarithmic = lilv_new_uri(world, "http://lv2plug.in/ns/dev/extportinfo#logarithmic");
|
||||
}
|
||||
|
||||
LV2World::~LV2World()
|
||||
|
|
@ -1161,6 +1185,9 @@ LV2World::~LV2World()
|
|||
lilv_node_free(audio_class);
|
||||
lilv_node_free(event_class);
|
||||
lilv_node_free(midi_class);
|
||||
lilv_node_free(message_port_class);
|
||||
lilv_node_free(buffer_type);
|
||||
lilv_node_free(sequence_class);
|
||||
lilv_node_free(in_place_broken);
|
||||
}
|
||||
|
||||
|
|
@ -1230,14 +1257,18 @@ LV2PluginInfo::discover()
|
|||
p, _world.input_class, _world.audio_class, NULL));
|
||||
info->n_inputs.set_midi(
|
||||
lilv_plugin_get_num_ports_of_class(
|
||||
p, _world.input_class, _world.event_class, NULL));
|
||||
p, _world.input_class, _world.event_class, NULL)
|
||||
+ lilv_plugin_get_num_ports_of_class(
|
||||
p, _world.input_class, _world.message_port_class, NULL));
|
||||
|
||||
info->n_outputs.set_audio(
|
||||
lilv_plugin_get_num_ports_of_class(
|
||||
p, _world.output_class, _world.audio_class, NULL));
|
||||
info->n_outputs.set_midi(
|
||||
lilv_plugin_get_num_ports_of_class(
|
||||
p, _world.output_class, _world.event_class, NULL));
|
||||
p, _world.output_class, _world.event_class, NULL)
|
||||
+ lilv_plugin_get_num_ports_of_class(
|
||||
p, _world.output_class, _world.message_port_class, NULL));
|
||||
|
||||
info->unique_id = lilv_node_as_uri(lilv_plugin_get_uri(p));
|
||||
info->index = 0; // Meaningless for LV2
|
||||
|
|
|
|||
|
|
@ -379,8 +379,7 @@ def build(bld):
|
|||
#obj.add_objects = 'default/libs/surfaces/control_protocol/smpte_1.o'
|
||||
|
||||
if bld.is_defined('HAVE_LILV') :
|
||||
obj.source += [ 'lv2_plugin.cc', 'lv2_event_buffer.cc',
|
||||
'uri_map.cc', 'rdff.c' ]
|
||||
obj.source += ['lv2_plugin.cc', 'lv2_evbuf.c', 'uri_map.cc']
|
||||
obj.uselib += ['LILV']
|
||||
if bld.is_defined('HAVE_SUIL'):
|
||||
obj.uselib += ['SUIL']
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue