Enable Lv2 Atom ports
All Atom ports are now being created and connected. Currently only MIDI input ports are supplied with data. Major contribution to #562 ("lv2 support").
This commit is contained in:
committed by
Johannes Lorenz
parent
acd0e4d430
commit
8b2902c27a
@@ -100,8 +100,12 @@ protected:
|
||||
/*
|
||||
utils for the run thread
|
||||
*/
|
||||
//! Copy values from all connected models into the respective ports
|
||||
//! Copy values from the LMMS core (connected models, MIDI events, ...) into
|
||||
//! the respective ports
|
||||
void copyModelsFromLmms();
|
||||
//! Bring values from all ports to the LMMS core
|
||||
void copyModelsToLmms() const;
|
||||
|
||||
//! Copy buffer passed by LMMS into our ports
|
||||
void copyBuffersFromLmms(const sampleFrame *buf, fpp_t frames);
|
||||
//! Copy our ports into buffers passed by LMMS
|
||||
@@ -123,6 +127,9 @@ protected:
|
||||
*/
|
||||
std::size_t controlCount() const;
|
||||
QString nodeName() const { return "lv2controls"; }
|
||||
bool hasNoteInput() const;
|
||||
void handleMidiInputEvent(const class MidiEvent &event,
|
||||
const class MidiTime &time, f_cnt_t offset);
|
||||
|
||||
private:
|
||||
//! Return the DataFile settings type
|
||||
|
||||
149
include/Lv2Evbuf.h
Normal file
149
include/Lv2Evbuf.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* lv2_evbuf.h - Lv2 event buffer definitions
|
||||
*
|
||||
* Copyright (c) 2019-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* 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 (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* The original code was written by David Robillard <http://drobilla.net>
|
||||
* Original version: 6f22ee0 from https://github.com/drobilla/jalv.git
|
||||
* Minor changes have been done, but no functional changes.
|
||||
* Considering this as an "external library", the identifiers do not need to
|
||||
* match the LMMS coding conventions.
|
||||
*/
|
||||
|
||||
#ifndef LV2_EVBUF_H
|
||||
#define LV2_EVBUF_H
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
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.
|
||||
URIDs for atom:Chunk and atom:Sequence must be passed for LV2_EVBUF_ATOM.
|
||||
*/
|
||||
LV2_Evbuf*
|
||||
lv2_evbuf_new(uint32_t capacity, uint32_t atom_Chunk, uint32_t atom_Sequence);
|
||||
|
||||
/**
|
||||
Free an event buffer allocated with lv2_evbuf_new.
|
||||
*/
|
||||
void
|
||||
lv2_evbuf_free(LV2_Evbuf* evbuf);
|
||||
|
||||
/**
|
||||
Clear and initialize an existing event buffer.
|
||||
The contents of buf are ignored entirely and overwritten, except capacity
|
||||
which is unmodified.
|
||||
If input is false and this is an atom buffer, the buffer will be prepared
|
||||
for writing by the plugin. This MUST be called before every run cycle.
|
||||
*/
|
||||
void
|
||||
lv2_evbuf_reset(LV2_Evbuf* evbuf, bool input);
|
||||
|
||||
/**
|
||||
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 `evbuf`.
|
||||
*/
|
||||
LV2_Evbuf_Iterator
|
||||
lv2_evbuf_begin(LV2_Evbuf* evbuf);
|
||||
|
||||
/**
|
||||
Return an iterator to the end of `evbuf`.
|
||||
*/
|
||||
LV2_Evbuf_Iterator
|
||||
lv2_evbuf_end(LV2_Evbuf* evbuf);
|
||||
|
||||
/**
|
||||
Check if `iter` is valid.
|
||||
@return True if `iter` is valid, otherwise false (past end of buffer)
|
||||
*/
|
||||
bool
|
||||
lv2_evbuf_is_valid(LV2_Evbuf_Iterator iter);
|
||||
|
||||
/**
|
||||
Advance `iter` forward one event.
|
||||
`iter` must be valid.
|
||||
@return True if `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).
|
||||
`iter` must be valid.
|
||||
`type` Set to the type of the event.
|
||||
`size` Set to the size of the event.
|
||||
`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* type,
|
||||
uint32_t* size,
|
||||
uint8_t** data);
|
||||
|
||||
/**
|
||||
Write an event at `iter`.
|
||||
The event (if any) pointed to by `iter` will be overwritten, and `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 type,
|
||||
uint32_t size,
|
||||
const uint8_t* data);
|
||||
|
||||
#endif // LMMS_HAVE_LV2
|
||||
|
||||
#endif // LV2_EVBUF_H
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "PluginIssue.h"
|
||||
|
||||
struct ConnectPortVisitor;
|
||||
typedef struct LV2_Evbuf_Impl LV2_Evbuf;
|
||||
|
||||
namespace Lv2Ports {
|
||||
|
||||
@@ -53,7 +54,7 @@ enum class Type {
|
||||
Unknown,
|
||||
Control,
|
||||
Audio,
|
||||
Event, //!< TODO: unused, describe
|
||||
AtomSeq,
|
||||
Cv //!< TODO: unused, describe
|
||||
};
|
||||
|
||||
@@ -74,6 +75,7 @@ struct ControlPortBase;
|
||||
struct Control;
|
||||
struct Audio;
|
||||
struct Cv;
|
||||
struct AtomSeq;
|
||||
struct Unknown;
|
||||
|
||||
struct ConstVisitor
|
||||
@@ -82,6 +84,7 @@ struct ConstVisitor
|
||||
virtual void visit(const Lv2Ports::Control& ) {}
|
||||
virtual void visit(const Lv2Ports::Audio& ) {}
|
||||
virtual void visit(const Lv2Ports::Cv& ) {}
|
||||
virtual void visit(const Lv2Ports::AtomSeq& ) {}
|
||||
virtual void visit(const Lv2Ports::Unknown& ) {}
|
||||
|
||||
virtual ~ConstVisitor();
|
||||
@@ -93,6 +96,7 @@ struct Visitor
|
||||
virtual void visit(Lv2Ports::Control& ) {}
|
||||
virtual void visit(Lv2Ports::Audio& ) {}
|
||||
virtual void visit(Lv2Ports::Cv& ) {}
|
||||
virtual void visit(Lv2Ports::AtomSeq& ) {}
|
||||
virtual void visit(Lv2Ports::Unknown& ) {}
|
||||
|
||||
virtual ~Visitor();
|
||||
@@ -192,6 +196,23 @@ private:
|
||||
friend struct ::ConnectPortVisitor;
|
||||
};
|
||||
|
||||
struct AtomSeq : public VisitablePort<AtomSeq, PortBase>
|
||||
{
|
||||
enum FlagType
|
||||
{
|
||||
None = 0,
|
||||
Midi = 1
|
||||
};
|
||||
unsigned flags = FlagType::None;
|
||||
|
||||
struct Lv2EvbufDeleter
|
||||
{
|
||||
void operator()(LV2_Evbuf* n);
|
||||
};
|
||||
using AutoLv2Evbuf = std::unique_ptr<LV2_Evbuf, Lv2EvbufDeleter>;
|
||||
AutoLv2Evbuf m_buf;
|
||||
};
|
||||
|
||||
struct Unknown : public VisitablePort<Unknown, PortBase>
|
||||
{
|
||||
};
|
||||
|
||||
@@ -36,15 +36,18 @@
|
||||
#include "Lv2Basics.h"
|
||||
#include "Lv2Features.h"
|
||||
#include "LinkedModelGroups.h"
|
||||
#include "MidiEvent.h"
|
||||
#include "MidiTime.h"
|
||||
#include "Plugin.h"
|
||||
#include "PluginIssue.h"
|
||||
|
||||
#include "../src/3rdparty/ringbuffer/include/ringbuffer/ringbuffer.h"
|
||||
|
||||
// forward declare port structs/enums
|
||||
namespace Lv2Ports
|
||||
{
|
||||
struct Audio;
|
||||
struct PortBase;
|
||||
struct AtomSeq;
|
||||
|
||||
enum class Type;
|
||||
enum class Flow;
|
||||
@@ -106,8 +109,11 @@ public:
|
||||
/*
|
||||
utils for the run thread
|
||||
*/
|
||||
//! Copy values from all connected models into the respective ports
|
||||
//! Copy values from the LMMS core (connected models, MIDI events, ...) into
|
||||
//! the respective ports
|
||||
void copyModelsFromCore();
|
||||
//! Bring values from all ports to the LMMS core
|
||||
void copyModelsToCore();
|
||||
/**
|
||||
* Copy buffer passed by the core into our ports
|
||||
* @param buf buffer of sample frames, each sample frame is something like
|
||||
@@ -137,11 +143,15 @@ public:
|
||||
//! Run the Lv2 plugin instance for @param frames frames
|
||||
void run(fpp_t frames);
|
||||
|
||||
void handleMidiInputEvent(const class MidiEvent &event,
|
||||
const MidiTime &time, f_cnt_t offset);
|
||||
|
||||
/*
|
||||
misc
|
||||
*/
|
||||
class AutomatableModel *modelAtPort(const QString &uri); // unused currently
|
||||
std::size_t controlCount() const { return LinkedModelGroup::modelNum(); }
|
||||
bool hasNoteInput() const;
|
||||
|
||||
protected:
|
||||
/*
|
||||
@@ -159,8 +169,25 @@ private:
|
||||
LilvInstance* m_instance;
|
||||
Lv2Features m_features;
|
||||
|
||||
// full list of ports
|
||||
std::vector<std::unique_ptr<Lv2Ports::PortBase>> m_ports;
|
||||
// quick reference to specific, unique ports
|
||||
StereoPortRef m_inPorts, m_outPorts;
|
||||
Lv2Ports::AtomSeq *m_midiIn = nullptr, *m_midiOut = nullptr;
|
||||
|
||||
// MIDI
|
||||
// many things here may be moved into the `Instrument` class
|
||||
constexpr const static std::size_t m_maxMidiInputEvents = 1024;
|
||||
//! spinlock for the MIDI ringbuffer (for MIDI events going to the plugin)
|
||||
std::atomic_flag m_ringLock = ATOMIC_FLAG_INIT;
|
||||
|
||||
//! MIDI ringbuffer (for MIDI events going to the plugin)
|
||||
ringbuffer_t<struct MidiInputEvent> m_midiInputBuf;
|
||||
//! MIDI ringbuffer reader
|
||||
ringbuffer_reader_t<struct MidiInputEvent> m_midiInputReader;
|
||||
|
||||
// other
|
||||
static std::size_t minimumEvbufSize() { return 1 << 15; /* ardour uses this*/ }
|
||||
|
||||
//! models for the controls, sorted by port symbols
|
||||
std::map<std::string, AutomatableModel *> m_connectedModels;
|
||||
|
||||
@@ -37,7 +37,7 @@ class Lv2UridCache
|
||||
public:
|
||||
enum class Id //!< ID for m_uridCache array
|
||||
{
|
||||
midi_MidiEvent, //!< just an example, unused yet
|
||||
midi_MidiEvent,
|
||||
size
|
||||
};
|
||||
//! Return URID for a cache ID
|
||||
|
||||
Reference in New Issue
Block a user