Forward port LV2 BPM and freewheeling port stuff from 2.0-ongoing.

Fix worker implementation to preserve error codes.

git-svn-id: svn://localhost/ardour2/branches/3.0@11877 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2012-04-10 20:46:32 +00:00
parent 99ba7de591
commit 96a8a64536
4 changed files with 71 additions and 20 deletions

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2008-2011 Paul Davis
Copyright (C) 2008-2012 Paul Davis
Author: David Robillard
This program is free software; you can redistribute it and/or modify
@ -132,8 +132,8 @@ class LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
Worker* worker() { return _worker; }
void work(uint32_t size, const void* data);
void work_response(uint32_t size, const void* data);
int work(uint32_t size, const void* data);
int work_response(uint32_t size, const void* data);
static URIMap _uri_map;
@ -155,7 +155,9 @@ class LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
float* _shadow_data;
float* _defaults;
LV2_Evbuf** _ev_buffers;
float* _latency_control_port;
float* _bpm_control_port; ///< Special input set by ardour
float* _freewheel_control_port; ///< Special input set by ardour
float* _latency_control_port; ///< Special output set by ardour
PBD::ID _insert_id;
typedef enum {

View File

@ -39,12 +39,12 @@ public:
/**
Do some work in the worker thread.
*/
virtual void work(uint32_t size, const void* data) = 0;
virtual int work(uint32_t size, const void* data) = 0;
/**
Handle a response from the worker thread in the audio thread.
*/
virtual void work_response(uint32_t size, const void* data) = 0;
virtual int work_response(uint32_t size, const void* data) = 0;
};
/**

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2008-2011 Paul Davis
Copyright (C) 2008-2012 Paul Davis
Author: David Robillard
This program is free software; you can redistribute it and/or modify
@ -43,6 +43,7 @@
#include "ardour/debug.h"
#include "ardour/lv2_plugin.h"
#include "ardour/session.h"
#include "ardour/tempo.h"
#include "ardour/worker.h"
#include "i18n.h"
@ -124,7 +125,7 @@ work_schedule(LV2_Worker_Schedule_Handle handle,
LV2Plugin* plugin = (LV2Plugin*)handle;
if (plugin->session().engine().freewheeling()) {
// Freewheeling, do the work immediately in this (audio) thread
plugin->work(size, data);
return (LV2_Worker_Status)plugin->work(size, data);
} else {
// Enqueue message for the worker thread
return plugin->worker()->schedule(size, data) ?
@ -141,7 +142,7 @@ work_respond(LV2_Worker_Respond_Handle handle,
LV2Plugin* plugin = (LV2Plugin*)handle;
if (plugin->session().engine().freewheeling()) {
// Freewheeling, respond immediately in this (audio) thread
plugin->work_response(size, data);
return (LV2_Worker_Status)plugin->work_response(size, data);
} else {
// Enqueue response for the worker
return plugin->worker()->respond(size, data) ?
@ -156,6 +157,12 @@ struct LV2Plugin::Impl {
, state(0)
#endif
{}
/** Find the LV2 input port with the given designation.
* If found, bufptrs[port_index] will be set to bufptr.
*/
LilvPort* designated_input (const char* uri, void** bufptrs[], void** bufptr);
LilvPlugin* plugin;
const LilvUI* ui;
const LilvNode* ui_type;
@ -326,17 +333,27 @@ LV2Plugin::init(void* c_plugin, framecnt_t rate)
_port_flags.push_back(flags);
}
const bool latent = lilv_plugin_has_latency(plugin);
const uint32_t latency_port = (latent)
? lilv_plugin_get_latency_port_index(plugin)
: 0;
_control_data = new float[num_ports];
_shadow_data = new float[num_ports];
_defaults = new float[num_ports];
_ev_buffers = new LV2_Evbuf*[num_ports];
memset(_ev_buffers, 0, sizeof(LV2_Evbuf*) * num_ports);
const bool latent = lilv_plugin_has_latency(plugin);
const uint32_t latency_index = (latent)
? lilv_plugin_get_latency_port_index(plugin)
: 0;
#define NS_TIME "http://lv2plug.in/ns/ext/time#"
// Build an array of pointers to special parameter buffers
void*** params = new void**[num_ports];
for (uint32_t i = 0; i < num_ports; ++i) {
params[i] = NULL;
}
_impl->designated_input (NS_TIME "beatsPerMinute", params, (void**)&_bpm_control_port);
_impl->designated_input (LILV_NS_LV2 "freeWheeling", params, (void**)&_freewheel_control_port);
for (uint32_t i = 0; i < num_ports; ++i) {
const LilvPort* port = lilv_plugin_get_port_by_index(plugin, i);
const LilvNode* sym = lilv_port_get_symbol(plugin, port);
@ -356,19 +373,24 @@ LV2Plugin::init(void* c_plugin, framecnt_t rate)
lilv_instance_connect_port(_impl->instance, i, &_control_data[i]);
if (latent && ( i == latency_port) ) {
if (latent && i == latency_index) {
_latency_control_port = &_control_data[i];
*_latency_control_port = 0;
}
if (parameter_is_input(i)) {
_shadow_data[i] = default_value(i);
if (params[i]) {
*params[i] = (void*)&_shadow_data[i];
}
}
} else {
_defaults[i] = 0.0f;
}
}
delete[] params;
LilvUIs* uis = lilv_plugin_get_uis(plugin);
if (lilv_uis_size(uis) > 0) {
#ifdef HAVE_SUIL
@ -948,17 +970,18 @@ LV2Plugin::emit_to_ui(void* controller, UIMessageSink sink)
}
}
void
int
LV2Plugin::work(uint32_t size, const void* data)
{
_impl->work_iface->work(
return _impl->work_iface->work(
_impl->instance->lv2_handle, work_respond, this, size, data);
}
void
int
LV2Plugin::work_response(uint32_t size, const void* data)
{
_impl->work_iface->work_response(_impl->instance->lv2_handle, size, data);
return _impl->work_iface->work_response(
_impl->instance->lv2_handle, size, data);
}
void
@ -1170,6 +1193,16 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
cycles_t then = get_cycles();
if (_freewheel_control_port) {
*_freewheel_control_port = _session.engine().freewheeling ();
}
if (_bpm_control_port) {
TempoMap& tmap (_session.tempo_map ());
Tempo tempo = tmap.tempo_at (_session.transport_frame () + offset);
*_bpm_control_port = tempo.beats_per_minute ();
}
ChanCount bufs_count;
bufs_count.set(DataType::AUDIO, 1);
bufs_count.set(DataType::MIDI, 1);
@ -1421,6 +1454,22 @@ LV2Plugin::latency_compute_run()
deactivate();
}
LilvPort*
LV2Plugin::Impl::designated_input (const char* uri, void** bufptrs[], void** bufptr)
{
LilvPort* port = NULL;
#ifdef HAVE_NEW_LILV
LilvNode* designation = lilv_new_uri(_world.world, uri);
port = lilv_plugin_get_port_by_designation(
plugin, _world.lv2_InputPort, designation);
lilv_node_free(designation);
if (port) {
bufptrs[lilv_port_get_index(plugin, port)] = bufptr;
}
#endif
return port;
}
LV2World::LV2World()
: world(lilv_world_new())
{

View File

@ -261,7 +261,7 @@ def configure(conf):
autowaf.check_pkg(conf, 'lilv-0', uselib_store='LILV',
atleast_version='0.0.0', mandatory=False)
autowaf.check_pkg(conf, 'lilv-0', uselib_store='NEW_LILV',
atleast_version='0.11.0', mandatory=False)
atleast_version='0.14.0', mandatory=False)
if conf.is_defined('HAVE_LILV'):
autowaf.check_pkg(conf, 'suil-0', uselib_store='SUIL',
atleast_version='0.2.0', mandatory=False)