2011-11-18 19:39:35 -05:00
/*
2019-08-02 22:01:25 -04:00
* Copyright ( C ) 2008 - 2012 Carl Hetherington < carl @ carlh . net >
* Copyright ( C ) 2008 - 2017 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2008 - 2019 David Robillard < d @ drobilla . net >
* Copyright ( C ) 2012 - 2019 Robin Gareus < robin @ gareus . org >
* Copyright ( C ) 2013 - 2018 John Emmas < john @ creativepost . co . uk >
* Copyright ( C ) 2013 Michael R . Fisher < mfisher @ bketech . com >
* Copyright ( C ) 2014 - 2016 Tim Mayberry < mojofunk @ gmail . com >
* Copyright ( C ) 2016 - 2017 Damien Zammit < damien @ zamaudio . com >
* Copyright ( C ) 2016 Nick Mainsbridge < mainsbridge @ gmail . com >
* Copyright ( C ) 2017 Johannes Mueller < github @ johannes - mueller . org >
*
* 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 . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2011-05-15 19:10:13 -04:00
2016-06-01 13:19:09 -04:00
# include <cctype>
2011-05-15 19:10:13 -04:00
# include <string>
# include <vector>
2012-11-17 13:41:19 -05:00
# include <limits>
2011-05-15 19:10:13 -04:00
# include <cmath>
# include <cstdlib>
# include <cstring>
2015-10-05 16:10:58 -04:00
# include "pbd/gstdio_compat.h"
2012-08-16 23:05:06 -04:00
# include <glib/gprintf.h>
# include <glibmm.h>
2011-05-15 19:10:13 -04:00
# include <boost/utility.hpp>
2014-06-17 07:41:29 -04:00
# include "pbd/file_utils.h"
2014-06-14 22:09:48 -04:00
# include "pbd/stl_delete.h"
2011-05-15 19:10:13 -04:00
# include "pbd/compose.h"
# include "pbd/error.h"
2016-09-04 20:22:39 -04:00
# include "pbd/locale_guard.h"
2018-12-18 07:30:31 -05:00
# include "pbd/pthread_utils.h"
2016-07-03 14:51:10 -04:00
# include "pbd/replace_all.h"
2011-05-15 19:10:13 -04:00
# include "pbd/xml++.h"
2017-08-11 11:19:45 -04:00
# ifdef PLATFORM_WINDOWS
# include <shlobj.h> // CSIDL_*
# include "pbd/windows_special_dirs.h"
# endif
2018-02-03 08:55:37 -05:00
# ifdef WAF_BUILD
2011-05-15 19:10:13 -04:00
# include "libardour-config.h"
2018-02-03 08:55:37 -05:00
# endif
2011-05-15 19:10:13 -04:00
# include "ardour/audio_buffer.h"
# include "ardour/audioengine.h"
2018-07-09 18:57:04 -04:00
# include "ardour/directory_names.h"
2011-05-15 19:10:13 -04:00
# include "ardour/debug.h"
# include "ardour/lv2_plugin.h"
2016-10-29 13:21:48 -04:00
# include "ardour/midi_patch_manager.h"
2011-05-15 19:10:13 -04:00
# include "ardour/session.h"
2012-04-10 16:46:32 -04:00
# include "ardour/tempo.h"
2013-03-17 12:52:49 -04:00
# include "ardour/types.h"
# include "ardour/utils.h"
2012-04-04 20:15:54 -04:00
# include "ardour/worker.h"
2014-03-10 10:42:45 -04:00
# include "ardour/search_paths.h"
2011-05-15 19:10:13 -04:00
2016-07-14 14:44:52 -04:00
# include "pbd/i18n.h"
2011-05-15 19:10:13 -04:00
# include <locale.h>
# include <lilv/lilv.h>
2012-02-24 23:16:42 -05:00
# include "lv2/lv2plug.in/ns/ext/atom/atom.h"
2012-11-17 13:41:19 -05:00
# include "lv2/lv2plug.in/ns/ext/atom/forge.h"
2012-08-16 23:05:06 -04:00
# include "lv2/lv2plug.in/ns/ext/log/log.h"
2012-11-17 13:41:19 -05:00
# include "lv2/lv2plug.in/ns/ext/midi/midi.h"
2012-04-20 21:40:17 -04:00
# include "lv2/lv2plug.in/ns/ext/port-props/port-props.h"
# include "lv2/lv2plug.in/ns/ext/presets/presets.h"
2011-11-11 17:54:45 -05:00
# include "lv2/lv2plug.in/ns/ext/state/state.h"
2012-04-20 21:40:17 -04:00
# include "lv2/lv2plug.in/ns/ext/time/time.h"
2012-04-04 20:15:54 -04:00
# include "lv2/lv2plug.in/ns/ext/worker/worker.h"
2013-06-02 18:48:17 -04:00
# include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h"
2012-04-20 21:40:17 -04:00
# include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
2014-11-02 01:29:33 -05:00
# include "lv2/lv2plug.in/ns/extensions/units/units.h"
2014-10-30 22:26:47 -04:00
# include "lv2/lv2plug.in/ns/ext/patch/patch.h"
2016-11-09 18:09:38 -05:00
# include "lv2/lv2plug.in/ns/ext/port-groups/port-groups.h"
2019-04-09 18:19:39 -04:00
# include "lv2/lv2plug.in/ns/ext/parameters/parameters.h"
2012-08-07 20:16:30 -04:00
# include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
2012-08-29 21:23:39 -04:00
# include "lv2/lv2plug.in/ns/ext/options/options.h"
2012-02-24 23:16:42 -05:00
# include "lv2_evbuf.h"
2011-05-15 19:10:13 -04:00
# ifdef HAVE_SUIL
# include <suil/suil.h>
# endif
2014-11-03 11:54:35 -05:00
// Compatibility for old LV2
2014-10-31 20:44:02 -04:00
# ifndef LV2_ATOM_CONTENTS_CONST
# define LV2_ATOM_CONTENTS_CONST(type, atom) \
( ( const void * ) ( ( const uint8_t * ) ( atom ) + sizeof ( type ) ) )
# endif
# ifndef LV2_ATOM_BODY_CONST
# define LV2_ATOM_BODY_CONST(atom) LV2_ATOM_CONTENTS_CONST(LV2_Atom, atom)
# endif
2014-11-03 11:54:35 -05:00
# ifndef LV2_PATCH__property
# define LV2_PATCH__property LV2_PATCH_PREFIX "property"
# endif
# ifndef LV2_PATCH__value
# define LV2_PATCH__value LV2_PATCH_PREFIX "value"
# endif
# ifndef LV2_PATCH__writable
# define LV2_PATCH__writable LV2_PATCH_PREFIX "writable"
# endif
2014-10-31 20:44:02 -04:00
2012-11-17 20:30:53 -05:00
/** The number of MIDI buffers that will fit in a UI/worker comm buffer.
This needs to be roughly the number of cycles the UI will get around to
actually processing the traffic . Lower values are flakier but save memory .
*/
static const size_t NBUFS = 4 ;
2011-05-15 19:10:13 -04:00
using namespace std ;
using namespace ARDOUR ;
using namespace PBD ;
2020-06-30 10:45:14 -04:00
bool LV2Plugin : : force_state_save = false ;
2021-02-02 16:41:43 -05:00
int32_t LV2Plugin : : _ui_style_flat = 0 ;
int32_t LV2Plugin : : _ui_style_boxy = 0 ;
2020-06-30 10:45:14 -04:00
uint32_t LV2Plugin : : _ui_background_color = 0x000000ff ; // RGBA
uint32_t LV2Plugin : : _ui_foreground_color = 0xffffffff ; // RGBA
uint32_t LV2Plugin : : _ui_contrasting_color = 0x33ff33ff ; // RGBA
float LV2Plugin : : _ui_scale_factor = 1.0 ;
unsigned long LV2Plugin : : _ui_transient_win_id = 0 ;
2016-09-20 21:45:57 -04:00
2011-05-15 19:10:13 -04:00
class LV2World : boost : : noncopyable {
public :
LV2World ( ) ;
~ LV2World ( ) ;
2014-09-10 14:44:17 -04:00
void load_bundled_plugins ( bool verbose = false ) ;
2013-07-14 22:19:59 -04:00
2011-05-15 19:10:13 -04:00
LilvWorld * world ;
2012-02-25 00:01:24 -05:00
2012-03-25 13:17:40 -04:00
LilvNode * atom_AtomPort ;
2012-02-28 22:21:37 -05:00
LilvNode * atom_Chunk ;
2012-02-25 00:01:24 -05:00
LilvNode * atom_Sequence ;
LilvNode * atom_bufferType ;
2012-02-25 03:43:23 -05:00
LilvNode * atom_eventTransfer ;
2012-11-17 13:41:19 -05:00
LilvNode * atom_supports ;
2012-02-25 00:01:24 -05:00
LilvNode * ev_EventPort ;
LilvNode * ext_logarithmic ;
2013-05-25 03:06:06 -04:00
LilvNode * ext_notOnGUI ;
2016-06-05 08:45:24 -04:00
LilvNode * ext_expensive ;
LilvNode * ext_causesArtifacts ;
LilvNode * ext_notAutomatic ;
2016-07-05 10:21:09 -04:00
LilvNode * ext_rangeSteps ;
2020-11-20 00:03:49 -05:00
LilvNode * ext_displayPriority ;
2016-11-09 18:09:38 -05:00
LilvNode * groups_group ;
LilvNode * groups_element ;
2012-02-25 00:01:24 -05:00
LilvNode * lv2_AudioPort ;
LilvNode * lv2_ControlPort ;
LilvNode * lv2_InputPort ;
LilvNode * lv2_OutputPort ;
2016-11-09 18:09:38 -05:00
LilvNode * lv2_designation ;
2012-03-25 13:17:40 -04:00
LilvNode * lv2_enumeration ;
2013-06-14 11:33:29 -04:00
LilvNode * lv2_freewheeling ;
2012-02-25 00:01:24 -05:00
LilvNode * lv2_inPlaceBroken ;
2016-04-03 12:28:59 -04:00
LilvNode * lv2_isSideChain ;
2016-11-09 18:09:38 -05:00
LilvNode * lv2_index ;
2012-02-25 00:01:24 -05:00
LilvNode * lv2_integer ;
2014-11-01 23:29:10 -04:00
LilvNode * lv2_default ;
LilvNode * lv2_minimum ;
LilvNode * lv2_maximum ;
2013-05-25 03:06:06 -04:00
LilvNode * lv2_reportsLatency ;
2012-02-25 00:01:24 -05:00
LilvNode * lv2_sampleRate ;
LilvNode * lv2_toggled ;
LilvNode * midi_MidiEvent ;
2012-04-19 21:24:07 -04:00
LilvNode * rdfs_comment ;
2014-10-31 20:44:02 -04:00
LilvNode * rdfs_label ;
LilvNode * rdfs_range ;
2013-06-02 18:48:17 -04:00
LilvNode * rsz_minimumSize ;
2012-11-17 13:41:19 -05:00
LilvNode * time_Position ;
2019-05-08 15:59:22 -04:00
LilvNode * time_beatsPerMin ;
2012-02-25 00:01:24 -05:00
LilvNode * ui_GtkUI ;
2019-10-28 11:00:48 -04:00
LilvNode * ui_X11UI ;
2012-02-25 00:01:24 -05:00
LilvNode * ui_external ;
2013-08-25 10:20:27 -04:00
LilvNode * ui_externalkx ;
2014-11-03 17:29:11 -05:00
LilvNode * units_hz ;
2014-11-02 01:29:33 -05:00
LilvNode * units_db ;
2013-10-22 11:26:30 -04:00
LilvNode * units_unit ;
2014-11-02 01:59:18 -05:00
LilvNode * units_render ;
2013-10-22 11:26:30 -04:00
LilvNode * units_midiNote ;
2014-10-30 22:26:47 -04:00
LilvNode * patch_writable ;
LilvNode * patch_Message ;
2019-04-09 18:19:39 -04:00
LilvNode * opts_requiredOptions ;
2015-08-14 11:49:47 -04:00
LilvNode * bufz_powerOf2BlockLength ;
LilvNode * bufz_fixedBlockLength ;
2015-09-09 18:55:28 -04:00
LilvNode * bufz_nominalBlockLength ;
2016-09-18 13:06:59 -04:00
LilvNode * bufz_coarseBlockLength ;
2013-07-14 22:19:59 -04:00
2016-03-13 18:20:45 -04:00
# ifdef HAVE_LV2_1_10_0
LilvNode * atom_int ;
LilvNode * atom_float ;
LilvNode * atom_object ; // new in 1.8
LilvNode * atom_vector ;
# endif
# ifdef LV2_EXTENDED
LilvNode * lv2_noSampleAccurateCtrl ;
2019-08-19 14:19:38 -04:00
LilvNode * routing_connectAllOutputs ; // lv2:optionalFeature
2016-03-13 18:20:45 -04:00
LilvNode * auto_can_write_automatation ; // lv2:optionalFeature
LilvNode * auto_automation_control ; // atom:supports
LilvNode * auto_automation_controlled ; // lv2:portProperty
2016-06-05 08:44:54 -04:00
LilvNode * auto_automation_controller ; // lv2:portProperty
2020-12-30 12:50:02 -05:00
LilvNode * inline_display_interface ; // lv2:extensionData
2017-07-23 15:10:07 -04:00
LilvNode * inline_display_in_gui ; // lv2:optionalFeature
2019-12-14 09:00:34 -05:00
LilvNode * inline_mixer_control ; // lv2:PortProperty
2016-03-13 18:20:45 -04:00
# endif
2013-07-14 22:19:59 -04:00
private :
bool _bundle_checked ;
2011-05-15 19:10:13 -04:00
} ;
static LV2World _world ;
2012-08-16 23:05:06 -04:00
/* worker extension */
2012-04-04 20:15:54 -04:00
/** Called by the plugin to schedule non-RT work. */
static LV2_Worker_Status
work_schedule ( LV2_Worker_Schedule_Handle handle ,
uint32_t size ,
const void * data )
{
2016-07-31 21:59:21 -04:00
return ( ( ( Worker * ) handle ) - > schedule ( size , data )
? LV2_WORKER_SUCCESS
: LV2_WORKER_ERR_UNKNOWN ) ;
2012-04-04 20:15:54 -04:00
}
/** Called by the plugin to respond to non-RT work. */
static LV2_Worker_Status
work_respond ( LV2_Worker_Respond_Handle handle ,
uint32_t size ,
const void * data )
{
2016-07-31 21:59:21 -04:00
return ( ( ( Worker * ) handle ) - > respond ( size , data )
? LV2_WORKER_SUCCESS
: LV2_WORKER_ERR_UNKNOWN ) ;
2012-04-04 20:15:54 -04:00
}
2019-09-18 12:40:02 -04:00
static void
set_port_value ( const char * port_symbol ,
void * user_data ,
const void * value ,
uint32_t /*size*/ ,
uint32_t type )
{
LV2Plugin * self = ( LV2Plugin * ) user_data ;
if ( type ! = 0 & & type ! = URIMap : : instance ( ) . urids . atom_Float ) {
return ; // TODO: Support non-float ports
}
const uint32_t port_index = self - > port_index ( port_symbol ) ;
if ( port_index ! = ( uint32_t ) - 1 ) {
2020-08-07 16:02:56 -04:00
self - > set_parameter ( port_index , * ( const float * ) value , 0 ) ;
2019-09-18 12:40:02 -04:00
self - > PresetPortSetValue ( port_index , * ( const float * ) value ) ; /* EMIT SIGNAL */
}
}
2016-03-16 14:39:13 -04:00
# ifdef LV2_EXTENDED
2016-03-13 18:52:48 -04:00
/* inline display extension */
2017-09-08 13:26:08 -04:00
void
LV2Plugin : : queue_draw ( LV2_Inline_Display_Handle handle )
2016-03-13 18:52:48 -04:00
{
LV2Plugin * plugin = ( LV2Plugin * ) handle ;
plugin - > QueueDraw ( ) ; /* EMIT SIGNAL */
}
2016-10-29 13:21:48 -04:00
2017-09-08 13:26:08 -04:00
void
LV2Plugin : : midnam_update ( LV2_Midnam_Handle handle )
2016-10-29 13:21:48 -04:00
{
LV2Plugin * plugin = ( LV2Plugin * ) handle ;
2017-09-08 21:07:01 -04:00
plugin - > _midnam_dirty = true ;
2016-10-29 13:21:48 -04:00
plugin - > UpdateMidnam ( ) ; /* EMIT SIGNAL */
}
2017-09-08 13:26:08 -04:00
void
LV2Plugin : : bankpatch_notify ( LV2_BankPatch_Handle handle , uint8_t chn , uint32_t bank , uint8_t pgm )
{
LV2Plugin * plugin = ( LV2Plugin * ) handle ;
if ( chn > 15 ) {
return ;
}
plugin - > seen_bankpatch = true ;
if ( pgm > 127 | | bank > 16383 ) {
plugin - > _bankpatch [ chn ] = UINT32_MAX ;
} else {
plugin - > _bankpatch [ chn ] = ( bank < < 7 ) | pgm ;
}
plugin - > BankPatchChange ( chn ) ; /* EMIT SIGNAL */
}
2016-03-16 14:39:13 -04:00
# endif
2016-03-13 18:52:48 -04:00
2012-08-16 23:05:06 -04:00
/* log extension */
static int
2013-01-08 16:36:42 -05:00
log_vprintf ( LV2_Log_Handle /*handle*/ ,
2012-08-16 23:05:06 -04:00
LV2_URID type ,
const char * fmt ,
va_list args )
{
char * str = NULL ;
const int ret = g_vasprintf ( & str , fmt , args ) ;
2016-06-01 13:01:13 -04:00
/* strip trailing whitespace */
2016-06-01 13:19:09 -04:00
while ( strlen ( str ) > 0 & & isspace ( str [ strlen ( str ) - 1 ] ) ) {
2016-06-01 13:01:13 -04:00
str [ strlen ( str ) - 1 ] = ' \0 ' ;
}
if ( strlen ( str ) = = 0 ) {
return 0 ;
}
2014-11-01 23:29:10 -04:00
if ( type = = URIMap : : instance ( ) . urids . log_Error ) {
2012-08-16 23:05:06 -04:00
error < < str < < endmsg ;
2014-11-01 23:29:10 -04:00
} else if ( type = = URIMap : : instance ( ) . urids . log_Warning ) {
2012-08-16 23:05:06 -04:00
warning < < str < < endmsg ;
2014-11-01 23:29:10 -04:00
} else if ( type = = URIMap : : instance ( ) . urids . log_Note ) {
2012-08-16 23:05:06 -04:00
info < < str < < endmsg ;
2016-07-31 20:58:47 -04:00
} else if ( type = = URIMap : : instance ( ) . urids . log_Trace ) {
DEBUG_TRACE ( DEBUG : : LV2 , str ) ;
2012-08-16 23:05:06 -04:00
}
return ret ;
}
static int
log_printf ( LV2_Log_Handle handle ,
LV2_URID type ,
const char * fmt , . . . )
{
va_list args ;
va_start ( args , fmt ) ;
const int ret = log_vprintf ( handle , type , fmt , args ) ;
va_end ( args ) ;
return ret ;
}
2011-05-15 19:10:13 -04:00
struct LV2Plugin : : Impl {
2012-01-27 20:45:15 -05:00
Impl ( ) : plugin ( 0 ) , ui ( 0 ) , ui_type ( 0 ) , name ( 0 ) , author ( 0 ) , instance ( 0 )
2012-04-05 22:42:19 -04:00
, work_iface ( 0 )
2015-09-09 18:55:28 -04:00
, opts_iface ( 0 )
2012-01-27 20:45:15 -05:00
, state ( 0 )
2015-09-09 18:55:28 -04:00
, block_length ( 0 )
2015-09-25 13:43:43 -04:00
, options ( 0 )
2016-03-13 18:52:48 -04:00
# ifdef LV2_EXTENDED
, queue_draw ( 0 )
2016-10-29 13:21:48 -04:00
, midnam ( 0 )
2015-10-26 08:32:51 -04:00
# endif
2012-01-27 20:45:15 -05:00
{ }
2012-08-07 20:21:05 -04:00
2012-04-10 16:46:32 -04:00
/** Find the LV2 input port with the given designation.
* If found , bufptrs [ port_index ] will be set to bufptr .
*/
2013-01-16 03:01:30 -05:00
const LilvPort * designated_input ( const char * uri , void * * bufptrs [ ] , void * * bufptr ) ;
2012-04-10 16:46:32 -04:00
2015-09-09 18:55:28 -04:00
const LilvPlugin * plugin ;
const LilvUI * ui ;
const LilvNode * ui_type ;
LilvNode * name ;
LilvNode * author ;
LilvInstance * instance ;
const LV2_Worker_Interface * work_iface ;
const LV2_Options_Interface * opts_iface ;
LilvState * state ;
LV2_Atom_Forge forge ;
LV2_Atom_Forge ui_forge ;
int32_t block_length ;
2015-09-25 13:43:43 -04:00
LV2_Options_Option * options ;
2016-03-13 18:52:48 -04:00
# ifdef LV2_EXTENDED
LV2_Inline_Display * queue_draw ;
2016-10-29 13:21:48 -04:00
LV2_Midnam * midnam ;
2017-09-08 13:26:08 -04:00
LV2_BankPatch * bankpatch ;
2016-03-13 18:52:48 -04:00
# endif
2011-05-15 19:10:13 -04:00
} ;
LV2Plugin : : LV2Plugin ( AudioEngine & engine ,
Session & session ,
2012-08-18 11:56:48 -04:00
const void * c_plugin ,
2019-04-08 12:29:04 -04:00
samplecnt_t rate )
2012-05-02 16:29:46 -04:00
: Plugin ( engine , session )
, Workee ( )
2011-05-15 19:10:13 -04:00
, _impl ( new Impl ( ) )
, _features ( NULL )
2012-04-05 22:42:19 -04:00
, _worker ( NULL )
2016-07-31 21:59:21 -04:00
, _state_worker ( NULL )
2011-05-15 19:10:13 -04:00
, _insert_id ( " 0 " )
2019-05-08 16:01:07 -04:00
, _bpm_control_port_index ( ( uint32_t ) - 1 )
2014-10-31 20:44:02 -04:00
, _patch_port_in_index ( ( uint32_t ) - 1 )
, _patch_port_out_index ( ( uint32_t ) - 1 )
2014-11-01 23:29:10 -04:00
, _uri_map ( URIMap : : instance ( ) )
2015-12-06 07:49:16 -05:00
, _no_sample_accurate_ctrl ( false )
2019-08-19 14:19:38 -04:00
, _connect_all_audio_outputs ( false )
2011-05-15 19:10:13 -04:00
{
init ( c_plugin , rate ) ;
2019-02-27 22:17:54 -05:00
latency_compute_run ( ) ;
2011-05-15 19:10:13 -04:00
}
LV2Plugin : : LV2Plugin ( const LV2Plugin & other )
2012-05-02 16:29:46 -04:00
: Plugin ( other )
, Workee ( )
2011-05-15 19:10:13 -04:00
, _impl ( new Impl ( ) )
, _features ( NULL )
2012-04-05 22:42:19 -04:00
, _worker ( NULL )
2016-07-31 21:59:21 -04:00
, _state_worker ( NULL )
2011-05-15 19:10:13 -04:00
, _insert_id ( other . _insert_id )
2019-05-08 16:01:07 -04:00
, _bpm_control_port_index ( ( uint32_t ) - 1 )
2014-10-31 20:44:02 -04:00
, _patch_port_in_index ( ( uint32_t ) - 1 )
, _patch_port_out_index ( ( uint32_t ) - 1 )
2014-11-01 23:29:10 -04:00
, _uri_map ( URIMap : : instance ( ) )
2015-12-06 07:49:16 -05:00
, _no_sample_accurate_ctrl ( false )
2019-08-19 14:19:38 -04:00
, _connect_all_audio_outputs ( false )
2011-05-15 19:10:13 -04:00
{
init ( other . _impl - > plugin , other . _sample_rate ) ;
2019-02-27 22:17:54 -05:00
XMLNode root ( other . state_node_name ( ) ) ;
other . add_state ( & root ) ;
set_state ( root , Stateful : : loading_state_version ) ;
2011-05-15 19:10:13 -04:00
for ( uint32_t i = 0 ; i < parameter_count ( ) ; + + i ) {
_control_data [ i ] = other . _shadow_data [ i ] ;
_shadow_data [ i ] = other . _shadow_data [ i ] ;
}
2019-02-27 22:17:54 -05:00
latency_compute_run ( ) ;
2011-05-15 19:10:13 -04:00
}
void
2017-09-18 12:39:17 -04:00
LV2Plugin : : init ( const void * c_plugin , samplecnt_t rate )
2011-05-15 19:10:13 -04:00
{
DEBUG_TRACE ( DEBUG : : LV2 , " init \n " ) ;
2012-08-18 11:56:48 -04:00
_impl - > plugin = ( const LilvPlugin * ) c_plugin ;
2012-04-11 00:00:27 -04:00
_impl - > ui = NULL ;
_impl - > ui_type = NULL ;
_to_ui = NULL ;
_from_ui = NULL ;
_control_data = 0 ;
_shadow_data = 0 ;
2012-08-28 11:42:38 -04:00
_atom_ev_buffers = 0 ;
2012-04-11 00:00:27 -04:00
_ev_buffers = 0 ;
_bpm_control_port = 0 ;
_freewheel_control_port = 0 ;
_latency_control_port = 0 ;
2017-09-18 12:39:17 -04:00
_next_cycle_start = std : : numeric_limits < samplepos_t > : : max ( ) ;
2012-11-17 13:41:19 -05:00
_next_cycle_speed = 1.0 ;
2019-11-14 14:03:22 -05:00
_next_cycle_beat = 0.0 ;
_current_bpm = 0.0 ;
2019-11-14 15:15:30 -05:00
_prev_time_scale = 0.0 ;
2012-08-29 16:22:18 -04:00
_seq_size = _engine . raw_buffer_size ( DataType : : MIDI ) ;
2012-04-11 00:00:27 -04:00
_state_version = 0 ;
_was_activated = false ;
_has_state_interface = false ;
2016-03-13 18:20:45 -04:00
_can_write_automation = false ;
2017-10-23 13:21:04 -04:00
# ifdef LV2_EXTENDED
2020-12-30 12:50:02 -05:00
_display_interface = 0 ;
2017-07-23 15:10:07 -04:00
_inline_display_in_gui = false ;
2017-10-23 13:21:04 -04:00
# endif
2016-04-08 12:16:01 -04:00
_max_latency = 0 ;
_current_latency = 0 ;
2015-09-09 18:55:28 -04:00
_impl - > block_length = _session . get_block_size ( ) ;
2012-02-24 17:09:30 -05:00
2019-08-26 17:30:21 -04:00
_sample_rate = rate ;
_fsample_rate = rate ;
2011-11-23 01:39:45 -05:00
_instance_access_feature . URI = " http://lv2plug.in/ns/ext/instance-access " ;
_data_access_feature . URI = " http://lv2plug.in/ns/ext/data-access " ;
2012-03-30 19:32:48 -04:00
_make_path_feature . URI = LV2_STATE__makePath ;
2012-08-16 23:05:06 -04:00
_log_feature . URI = LV2_LOG__log ;
2012-04-04 20:15:54 -04:00
_work_schedule_feature . URI = LV2_WORKER__schedule ;
2012-04-20 21:21:24 -04:00
_work_schedule_feature . data = NULL ;
2013-01-26 21:42:56 -05:00
_def_state_feature . URI = LV2_STATE_PREFIX " loadDefaultState " ; // Post LV2-1.2.0
_def_state_feature . data = NULL ;
2011-05-15 19:10:13 -04:00
2012-08-18 11:56:48 -04:00
const LilvPlugin * plugin = _impl - > plugin ;
2011-05-15 19:10:13 -04:00
2012-03-30 19:32:48 -04:00
LilvNode * state_iface_uri = lilv_new_uri ( _world . world , LV2_STATE__interface ) ;
2012-01-27 20:45:15 -05:00
LilvNode * state_uri = lilv_new_uri ( _world . world , LV2_STATE_URI ) ;
_has_state_interface =
// What plugins should have (lv2:extensionData state:Interface)
lilv_plugin_has_extension_data ( plugin , state_iface_uri )
// What some outdated/incorrect ones have
| | lilv_plugin_has_feature ( plugin , state_uri ) ;
lilv_node_free ( state_uri ) ;
2011-11-11 17:54:45 -05:00
lilv_node_free ( state_iface_uri ) ;
2011-05-15 19:10:13 -04:00
2017-09-08 13:26:08 -04:00
_features = ( LV2_Feature * * ) calloc ( 14 , sizeof ( LV2_Feature * ) ) ;
2011-05-15 19:10:13 -04:00
_features [ 0 ] = & _instance_access_feature ;
_features [ 1 ] = & _data_access_feature ;
2012-01-27 20:45:15 -05:00
_features [ 2 ] = & _make_path_feature ;
2020-07-08 14:53:37 -04:00
_features [ 3 ] = _uri_map . urid_map_feature ( ) ;
_features [ 4 ] = _uri_map . urid_unmap_feature ( ) ;
_features [ 5 ] = & _log_feature ;
2013-01-27 16:25:34 -05:00
2020-07-08 14:53:37 -04:00
unsigned n_features = 6 ;
2013-01-27 16:25:34 -05:00
_features [ n_features + + ] = & _def_state_feature ;
2012-08-07 20:16:30 -04:00
2012-11-17 13:41:19 -05:00
lv2_atom_forge_init ( & _impl - > forge , _uri_map . urid_map ( ) ) ;
2014-10-31 20:44:02 -04:00
lv2_atom_forge_init ( & _impl - > ui_forge , _uri_map . urid_map ( ) ) ;
2012-11-17 13:41:19 -05:00
2016-03-13 18:52:48 -04:00
# ifdef LV2_EXTENDED
_impl - > queue_draw = ( LV2_Inline_Display * )
malloc ( sizeof ( LV2_Inline_Display ) ) ;
_impl - > queue_draw - > handle = this ;
_impl - > queue_draw - > queue_draw = queue_draw ;
_queue_draw_feature . URI = LV2_INLINEDISPLAY__queue_draw ;
_queue_draw_feature . data = _impl - > queue_draw ;
_features [ n_features + + ] = & _queue_draw_feature ;
2016-10-29 13:21:48 -04:00
_impl - > midnam = ( LV2_Midnam * )
malloc ( sizeof ( LV2_Midnam ) ) ;
_impl - > midnam - > handle = this ;
_impl - > midnam - > update = midnam_update ;
_midnam_feature . URI = LV2_MIDNAM__update ;
_midnam_feature . data = _impl - > midnam ;
_features [ n_features + + ] = & _midnam_feature ;
2017-09-08 13:26:08 -04:00
_impl - > bankpatch = ( LV2_BankPatch * )
malloc ( sizeof ( LV2_BankPatch ) ) ;
_impl - > bankpatch - > handle = this ;
_impl - > bankpatch - > notify = bankpatch_notify ;
_bankpatch_feature . URI = LV2_BANKPATCH__notify ;
_bankpatch_feature . data = _impl - > bankpatch ;
_features [ n_features + + ] = & _bankpatch_feature ;
2016-03-13 18:52:48 -04:00
# endif
2019-08-26 12:57:47 -04:00
LV2_URID atom_Int = _uri_map . uri_to_id ( LV2_ATOM__Int ) ;
2020-06-30 10:45:14 -04:00
LV2_URID atom_Bool = _uri_map . uri_to_id ( LV2_ATOM__Bool ) ;
2019-11-22 14:01:32 -05:00
LV2_URID atom_Long = _uri_map . uri_to_id ( LV2_ATOM__Long ) ;
2019-08-26 12:57:47 -04:00
LV2_URID atom_Float = _uri_map . uri_to_id ( LV2_ATOM__Float ) ;
2015-08-04 18:02:31 -04:00
static const int32_t _min_block_length = 1 ; // may happen during split-cycles
static const int32_t _max_block_length = 8192 ; // max possible (with all engines and during export)
2018-12-18 07:30:31 -05:00
static const int32_t rt_policy = PBD_SCHED_FIFO ;
2021-06-10 08:37:50 -04:00
static const int32_t rt_priority = pbd_absolute_rt_priority ( PBD_SCHED_FIFO , AudioEngine : : instance ( ) - > client_real_time_priority ( ) - 1 ) ;
2015-08-16 18:07:32 -04:00
/* Consider updating max-block-size whenever the buffersize changes.
* It requires re - instantiating the plugin ( which is a non - realtime operation ) ,
* so it should be done lightly and only for plugins that require it .
*
* given that the block - size can change at any time ( split - cycles ) ardour currently
* does not support plugins that require bufz_fixedBlockLength .
2015-08-04 18:02:31 -04:00
*/
2012-08-29 16:22:18 -04:00
LV2_Options_Option options [ ] = {
2012-09-16 13:01:23 -04:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( LV2_BUF_SIZE__minBlockLength ) ,
2015-08-04 18:02:31 -04:00
sizeof ( int32_t ) , atom_Int , & _min_block_length } ,
2012-09-16 13:01:23 -04:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( LV2_BUF_SIZE__maxBlockLength ) ,
2015-08-04 18:02:31 -04:00
sizeof ( int32_t ) , atom_Int , & _max_block_length } ,
2012-09-16 13:01:23 -04:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( LV2_BUF_SIZE__sequenceSize ) ,
2012-08-29 16:22:18 -04:00
sizeof ( int32_t ) , atom_Int , & _seq_size } ,
2019-08-26 17:30:21 -04:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( LV2_PARAMETERS__sampleRate ) ,
sizeof ( float ) , atom_Float , & _fsample_rate } ,
2015-09-09 18:55:28 -04:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( " http://lv2plug.in/ns/ext/buf-size#nominalBlockLength " ) ,
sizeof ( int32_t ) , atom_Int , & _impl - > block_length } ,
2018-12-18 07:30:31 -05:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( " http://ardour.org/lv2/threads/#schedPolicy " ) ,
sizeof ( int32_t ) , atom_Int , & rt_policy } ,
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( " http://ardour.org/lv2/threads/#schedPriority " ) ,
sizeof ( int32_t ) , atom_Int , & rt_priority } ,
2019-08-26 12:57:47 -04:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( " http://lv2plug.in/ns/extensions/ui#backgroundColor " ) ,
sizeof ( int32_t ) , atom_Int , & _ui_background_color } ,
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( " http://lv2plug.in/ns/extensions/ui#foregroundColor " ) ,
sizeof ( int32_t ) , atom_Int , & _ui_foreground_color } ,
2020-06-30 10:45:14 -04:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( " http://lv2plug.in/ns/extensions/ui#contrastingColor " ) ,
sizeof ( int32_t ) , atom_Int , & _ui_contrasting_color } ,
2019-08-26 12:57:47 -04:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( " http://lv2plug.in/ns/extensions/ui#scaleFactor " ) ,
2019-08-26 17:12:46 -04:00
sizeof ( float ) , atom_Float , & _ui_scale_factor } ,
2020-06-30 10:45:14 -04:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( " http://ardour.org/lv2/theme/#styleBoxy " ) ,
2021-02-02 16:41:43 -05:00
sizeof ( int32_t ) , atom_Bool , & _ui_style_boxy } ,
2020-06-30 10:45:14 -04:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( " http://ardour.org/lv2/theme/#styleFlat " ) ,
2021-02-02 16:41:43 -05:00
sizeof ( int32_t ) , atom_Bool , & _ui_style_flat } ,
2019-11-22 14:01:32 -05:00
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( " http://kxstudio.sf.net/ns/lv2ext/props#TransientWindowId " ) ,
sizeof ( int32_t ) , atom_Long , & _ui_transient_win_id } ,
2012-09-16 13:01:23 -04:00
{ LV2_OPTIONS_INSTANCE , 0 , 0 , 0 , 0 , NULL }
2012-08-29 16:22:18 -04:00
} ;
2015-09-25 13:43:43 -04:00
_impl - > options = ( LV2_Options_Option * ) malloc ( sizeof ( options ) ) ;
memcpy ( ( void * ) _impl - > options , ( void * ) options , sizeof ( options ) ) ;
2012-08-29 16:22:18 -04:00
_options_feature . URI = LV2_OPTIONS__options ;
2015-09-25 13:43:43 -04:00
_options_feature . data = _impl - > options ;
2012-08-29 16:22:18 -04:00
_features [ n_features + + ] = & _options_feature ;
2011-05-15 19:10:13 -04:00
2017-09-08 13:26:08 -04:00
# ifdef LV2_EXTENDED
seen_bankpatch = false ;
for ( uint32_t chn = 0 ; chn < 16 ; + + chn ) {
_bankpatch [ chn ] = UINT32_MAX ;
}
# endif
2011-11-23 01:39:45 -05:00
LV2_State_Make_Path * make_path = ( LV2_State_Make_Path * ) malloc (
sizeof ( LV2_State_Make_Path ) ) ;
make_path - > handle = this ;
make_path - > path = & lv2_state_make_path ;
_make_path_feature . data = make_path ;
2011-05-15 19:10:13 -04:00
2012-08-16 23:05:06 -04:00
LV2_Log_Log * log = ( LV2_Log_Log * ) malloc ( sizeof ( LV2_Log_Log ) ) ;
log - > handle = this ;
log - > printf = & log_printf ;
log - > vprintf = & log_vprintf ;
_log_feature . data = log ;
2016-07-31 21:59:21 -04:00
const size_t ring_size = _session . engine ( ) . raw_buffer_size ( DataType : : MIDI ) * NBUFS ;
2012-04-04 20:15:54 -04:00
LilvNode * worker_schedule = lilv_new_uri ( _world . world , LV2_WORKER__schedule ) ;
if ( lilv_plugin_has_feature ( plugin , worker_schedule ) ) {
LV2_Worker_Schedule * schedule = ( LV2_Worker_Schedule * ) malloc (
sizeof ( LV2_Worker_Schedule ) ) ;
2016-07-31 21:59:21 -04:00
_worker = new Worker ( this , ring_size ) ;
schedule - > handle = _worker ;
2012-04-04 20:15:54 -04:00
schedule - > schedule_work = work_schedule ;
_work_schedule_feature . data = schedule ;
2012-08-07 20:16:30 -04:00
_features [ n_features + + ] = & _work_schedule_feature ;
2012-04-04 20:15:54 -04:00
}
lilv_node_free ( worker_schedule ) ;
2016-07-31 21:59:21 -04:00
if ( _has_state_interface ) {
// Create a non-threaded worker for use by state restore
_state_worker = new Worker ( this , ring_size , false ) ;
}
2011-05-15 19:10:13 -04:00
_impl - > instance = lilv_plugin_instantiate ( plugin , rate , _features ) ;
_impl - > name = lilv_plugin_get_name ( plugin ) ;
_impl - > author = lilv_plugin_get_author_name ( plugin ) ;
if ( _impl - > instance = = 0 ) {
error < < _ ( " LV2: Failed to instantiate plugin " ) < < uri ( ) < < endmsg ;
throw failed_constructor ( ) ;
}
_instance_access_feature . data = ( void * ) _impl - > instance - > lv2_handle ;
_data_access_extension_data . extension_data = _impl - > instance - > lv2_descriptor - > extension_data ;
_data_access_feature . data = & _data_access_extension_data ;
2013-01-04 13:46:39 -05:00
LilvNode * worker_iface_uri = lilv_new_uri ( _world . world , LV2_WORKER__interface ) ;
if ( lilv_plugin_has_extension_data ( plugin , worker_iface_uri ) ) {
_impl - > work_iface = ( const LV2_Worker_Interface * ) extension_data (
LV2_WORKER__interface ) ;
}
lilv_node_free ( worker_iface_uri ) ;
2012-04-04 20:15:54 -04:00
2015-09-09 18:55:28 -04:00
LilvNode * options_iface_uri = lilv_new_uri ( _world . world , LV2_OPTIONS__interface ) ;
if ( lilv_plugin_has_extension_data ( plugin , options_iface_uri ) ) {
_impl - > opts_iface = ( const LV2_Options_Interface * ) extension_data (
LV2_OPTIONS__interface ) ;
}
lilv_node_free ( options_iface_uri ) ;
2016-03-13 18:52:48 -04:00
# ifdef LV2_EXTENDED
2016-10-29 13:21:48 -04:00
_midname_interface = ( const LV2_Midnam_Interface * )
extension_data ( LV2_MIDNAM__interface ) ;
if ( _midname_interface ) {
2017-09-08 21:07:01 -04:00
_midnam_dirty = true ;
2016-10-29 23:51:31 -04:00
read_midnam ( ) ;
2016-10-29 13:21:48 -04:00
}
2016-03-13 18:52:48 -04:00
# endif
2012-02-25 00:01:24 -05:00
if ( lilv_plugin_has_feature ( plugin , _world . lv2_inPlaceBroken ) ) {
2011-05-15 19:10:13 -04:00
error < < string_compose (
2015-08-14 12:12:05 -04:00
_ ( " LV2: \" %1 \" cannot be used, since it cannot do inplace processing. " ) ,
2011-05-15 19:10:13 -04:00
lilv_node_as_string ( _impl - > name ) ) < < endmsg ;
lilv_node_free ( _impl - > name ) ;
lilv_node_free ( _impl - > author ) ;
throw failed_constructor ( ) ;
}
2015-08-14 13:24:40 -04:00
2015-12-06 07:49:16 -05:00
LilvNodes * optional_features = lilv_plugin_get_optional_features ( plugin ) ;
2016-09-18 13:06:59 -04:00
if ( lilv_nodes_contains ( optional_features , _world . bufz_coarseBlockLength ) ) {
_no_sample_accurate_ctrl = true ;
}
2019-03-31 13:19:21 -04:00
2016-09-18 13:06:59 -04:00
# ifdef LV2_EXTENDED
2015-12-06 07:49:16 -05:00
if ( lilv_nodes_contains ( optional_features , _world . lv2_noSampleAccurateCtrl ) ) {
2016-09-18 13:06:59 -04:00
/* deprecated 2016-Sep-18 in favor of bufz_coarseBlockLength */
2015-12-06 07:49:16 -05:00
_no_sample_accurate_ctrl = true ;
}
2019-08-19 14:19:38 -04:00
if ( lilv_nodes_contains ( optional_features , _world . routing_connectAllOutputs ) ) {
_connect_all_audio_outputs = true ;
}
2016-03-13 18:20:45 -04:00
if ( lilv_nodes_contains ( optional_features , _world . auto_can_write_automatation ) ) {
_can_write_automation = true ;
}
2020-12-30 12:50:02 -05:00
if ( lilv_plugin_has_extension_data ( plugin , _world . inline_display_interface ) ) {
_display_interface = ( const LV2_Inline_Display_Interface * ) extension_data ( LV2_INLINEDISPLAY__interface ) ;
}
# ifndef NDEBUG
else if ( extension_data ( LV2_INLINEDISPLAY__interface ) ) {
warning < < string_compose ( _ ( " LV2: Plugin '%1' has inline-display extension without lv2:extensionData meta-data " ) , name ( ) ) < < endmsg ;
}
# endif
2017-07-23 15:10:07 -04:00
if ( lilv_nodes_contains ( optional_features , _world . inline_display_in_gui ) ) {
_inline_display_in_gui = true ;
}
2015-12-06 07:49:16 -05:00
lilv_nodes_free ( optional_features ) ;
2015-08-14 16:42:35 -04:00
# endif
2011-05-15 19:10:13 -04:00
2019-09-18 12:40:02 -04:00
/* Snapshot default state -- http://lv2plug.in/ns/ext/state/#loadDefaultState */
2013-01-26 21:42:56 -05:00
LilvState * state = lilv_state_new_from_world (
_world . world , _uri_map . urid_map ( ) , lilv_plugin_get_uri ( _impl - > plugin ) ) ;
2012-02-24 17:09:30 -05:00
const uint32_t num_ports = this - > num_ports ( ) ;
2012-01-23 13:02:22 -05:00
for ( uint32_t i = 0 ; i < num_ports ; + + i ) {
2012-02-24 17:09:30 -05:00
const LilvPort * port = lilv_plugin_get_port_by_index ( _impl - > plugin , i ) ;
PortFlags flags = 0 ;
2013-06-02 18:48:17 -04:00
size_t minimumSize = 0 ;
2012-02-28 22:21:37 -05:00
if ( lilv_port_is_a ( _impl - > plugin , port , _world . lv2_OutputPort ) ) {
flags | = PORT_OUTPUT ;
} else if ( lilv_port_is_a ( _impl - > plugin , port , _world . lv2_InputPort ) ) {
flags | = PORT_INPUT ;
} else {
error < < string_compose (
" LV2: \" %1 \" port %2 is neither input nor output " ,
lilv_node_as_string ( _impl - > name ) , i ) < < endmsg ;
throw failed_constructor ( ) ;
}
2012-02-25 00:01:24 -05:00
if ( lilv_port_is_a ( _impl - > plugin , port , _world . lv2_ControlPort ) ) {
2012-02-24 17:09:30 -05:00
flags | = PORT_CONTROL ;
2012-02-25 00:01:24 -05:00
} else if ( lilv_port_is_a ( _impl - > plugin , port , _world . lv2_AudioPort ) ) {
2012-02-24 17:09:30 -05:00
flags | = PORT_AUDIO ;
2012-03-25 13:17:40 -04:00
} else if ( lilv_port_is_a ( _impl - > plugin , port , _world . atom_AtomPort ) ) {
2012-02-24 23:16:42 -05:00
LilvNodes * buffer_types = lilv_port_get_value (
2012-02-25 00:01:24 -05:00
_impl - > plugin , port , _world . atom_bufferType ) ;
2012-08-27 00:08:45 -04:00
LilvNodes * atom_supports = lilv_port_get_value (
_impl - > plugin , port , _world . atom_supports ) ;
2012-11-17 13:41:19 -05:00
if ( lilv_nodes_contains ( buffer_types , _world . atom_Sequence ) ) {
2012-11-17 23:35:31 -05:00
flags | = PORT_SEQUENCE ;
2012-11-17 13:41:19 -05:00
if ( lilv_nodes_contains ( atom_supports , _world . midi_MidiEvent ) ) {
2012-11-17 23:35:31 -05:00
flags | = PORT_MIDI ;
2012-02-28 22:21:37 -05:00
}
2012-11-17 13:41:19 -05:00
if ( lilv_nodes_contains ( atom_supports , _world . time_Position ) ) {
2012-11-17 23:35:31 -05:00
flags | = PORT_POSITION ;
2012-11-17 13:41:19 -05:00
}
2016-03-13 18:20:45 -04:00
# ifdef LV2_EXTENDED
if ( lilv_nodes_contains ( atom_supports , _world . auto_automation_control ) ) {
flags | = PORT_AUTOCTRL ;
}
# endif
2014-10-30 22:26:47 -04:00
if ( lilv_nodes_contains ( atom_supports , _world . patch_Message ) ) {
flags | = PORT_PATCHMSG ;
2014-10-31 20:44:02 -04:00
if ( flags & PORT_INPUT ) {
_patch_port_in_index = i ;
} else {
_patch_port_out_index = i ;
}
2014-10-30 22:26:47 -04:00
}
2012-11-17 13:41:19 -05:00
}
2013-06-03 13:34:14 -04:00
LilvNodes * min_size_v = lilv_port_get_value ( _impl - > plugin , port , _world . rsz_minimumSize ) ;
LilvNode * min_size = min_size_v ? lilv_nodes_get_first ( min_size_v ) : NULL ;
2013-06-02 18:48:17 -04:00
if ( min_size & & lilv_node_is_int ( min_size ) ) {
minimumSize = lilv_node_as_int ( min_size ) ;
}
2013-06-03 13:34:14 -04:00
lilv_nodes_free ( min_size_v ) ;
2012-02-24 23:16:42 -05:00
lilv_nodes_free ( buffer_types ) ;
2012-08-27 00:08:45 -04:00
lilv_nodes_free ( atom_supports ) ;
2012-02-24 17:09:30 -05:00
} else {
error < < string_compose (
" LV2: \" %1 \" port %2 has no known data type " ,
lilv_node_as_string ( _impl - > name ) , i ) < < endmsg ;
throw failed_constructor ( ) ;
}
2012-02-28 22:21:37 -05:00
2016-06-05 08:45:24 -04:00
if ( ( flags & PORT_INPUT ) & & ( flags & PORT_CONTROL ) ) {
if ( lilv_port_has_property ( _impl - > plugin , port , _world . ext_causesArtifacts ) ) {
flags | = PORT_NOAUTO ;
}
if ( lilv_port_has_property ( _impl - > plugin , port , _world . ext_notAutomatic ) ) {
flags | = PORT_NOAUTO ;
}
if ( lilv_port_has_property ( _impl - > plugin , port , _world . ext_expensive ) ) {
flags | = PORT_NOAUTO ;
}
}
2016-03-13 18:20:45 -04:00
# ifdef LV2_EXTENDED
if ( lilv_port_has_property ( _impl - > plugin , port , _world . auto_automation_controlled ) ) {
if ( ( flags & PORT_INPUT ) & & ( flags & PORT_CONTROL ) ) {
flags | = PORT_CTRLED ;
}
}
2016-06-05 08:44:54 -04:00
if ( lilv_port_has_property ( _impl - > plugin , port , _world . auto_automation_controller ) ) {
if ( ( flags & PORT_INPUT ) & & ( flags & PORT_CONTROL ) ) {
flags | = PORT_CTRLER ;
}
}
2016-03-13 18:20:45 -04:00
# endif
2012-02-24 17:09:30 -05:00
_port_flags . push_back ( flags ) ;
2013-06-02 18:48:17 -04:00
_port_minimumSize . push_back ( minimumSize ) ;
2016-04-28 06:27:53 -04:00
DEBUG_TRACE ( DEBUG : : LV2 , string_compose ( " port %1 buffer %2 bytes \n " , i , minimumSize ) ) ;
2012-01-23 13:02:22 -05:00
}
2012-02-24 17:09:30 -05:00
2011-05-15 19:10:13 -04:00
_control_data = new float [ num_ports ] ;
_shadow_data = new float [ num_ports ] ;
_defaults = new float [ num_ports ] ;
2012-02-25 03:43:23 -05:00
_ev_buffers = new LV2_Evbuf * [ num_ports ] ;
memset ( _ev_buffers , 0 , sizeof ( LV2_Evbuf * ) * num_ports ) ;
2011-05-15 19:10:13 -04:00
2012-04-10 16:46:32 -04:00
const bool latent = lilv_plugin_has_latency ( plugin ) ;
const uint32_t latency_index = ( latent )
? lilv_plugin_get_latency_port_index ( plugin )
: 0 ;
// 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 ;
}
2012-04-20 21:40:17 -04:00
_impl - > designated_input ( LV2_TIME__beatsPerMinute , params , ( void * * ) & _bpm_control_port ) ;
_impl - > designated_input ( LV2_CORE__freeWheeling , params , ( void * * ) & _freewheel_control_port ) ;
2012-04-10 16:46:32 -04:00
2019-05-08 16:01:07 -04:00
const LilvPort * bpmport = lilv_plugin_get_port_by_designation ( plugin , _world . lv2_InputPort , _world . time_beatsPerMin ) ;
if ( bpmport ) {
_bpm_control_port_index = lilv_port_get_index ( plugin , bpmport ) ;
}
2011-05-15 19:10:13 -04:00
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 ) ;
// Store index in map so we can look up index by symbol
_port_indices . insert ( std : : make_pair ( lilv_node_as_string ( sym ) , i ) ) ;
// Get range and default value if applicable
if ( parameter_is_control ( i ) ) {
LilvNode * def ;
lilv_port_get_range ( plugin , port , & def , NULL , NULL ) ;
_defaults [ i ] = def ? lilv_node_as_float ( def ) : 0.0f ;
2012-02-25 00:01:24 -05:00
if ( lilv_port_has_property ( plugin , port , _world . lv2_sampleRate ) ) {
2017-09-18 12:39:17 -04:00
_defaults [ i ] * = _session . sample_rate ( ) ;
2011-07-12 16:30:02 -04:00
}
2011-05-15 19:10:13 -04:00
lilv_node_free ( def ) ;
lilv_instance_connect_port ( _impl - > instance , i , & _control_data [ i ] ) ;
2012-04-10 16:46:32 -04:00
if ( latent & & i = = latency_index ) {
2016-04-08 12:16:01 -04:00
LilvNode * max ;
lilv_port_get_range ( _impl - > plugin , port , NULL , NULL , & max ) ;
_max_latency = max ? lilv_node_as_float ( max ) : .02 * _sample_rate ;
2011-05-15 19:10:13 -04:00
_latency_control_port = & _control_data [ i ] ;
* _latency_control_port = 0 ;
}
if ( parameter_is_input ( i ) ) {
_shadow_data [ i ] = default_value ( i ) ;
2012-04-10 16:46:32 -04:00
if ( params [ i ] ) {
* params [ i ] = ( void * ) & _shadow_data [ i ] ;
}
2019-02-27 22:17:54 -05:00
} else {
_shadow_data [ i ] = 0 ;
2011-05-15 19:10:13 -04:00
}
2019-11-08 15:01:28 -05:00
_control_data [ i ] = _shadow_data [ i ] ;
2011-05-15 19:10:13 -04:00
} else {
_defaults [ i ] = 0.0f ;
}
}
2012-04-10 16:46:32 -04:00
delete [ ] params ;
2011-05-15 19:10:13 -04:00
LilvUIs * uis = lilv_plugin_get_uis ( plugin ) ;
2019-10-28 11:12:58 -04:00
2011-05-15 19:10:13 -04:00
if ( lilv_uis_size ( uis ) > 0 ) {
# ifdef HAVE_SUIL
2019-10-28 11:00:48 -04:00
const LilvUI * this_ui = NULL ;
const LilvNode * this_ui_type = NULL ;
2019-10-28 11:14:30 -04:00
# if ! (defined(__APPLE__) || defined(PLATFORM_WINDOWS))
2019-10-28 11:00:48 -04:00
// Always prefer X11 UIs...
LILV_FOREACH ( uis , i , uis ) {
const LilvUI * ui = lilv_uis_get ( uis , i ) ;
2019-10-28 12:23:33 -04:00
if ( lilv_ui_is_a ( ui , _world . ui_X11UI ) & &
lilv_ui_is_supported ( ui ,
suil_ui_supported ,
2019-10-28 12:31:03 -04:00
_world . ui_GtkUI ,
2019-10-28 12:23:33 -04:00
& this_ui_type ) ) {
this_ui = ui ;
2011-05-15 19:10:13 -04:00
break ;
2011-06-01 12:50:12 -04:00
}
2011-05-15 19:10:13 -04:00
}
2019-10-28 11:14:30 -04:00
# endif
2019-10-28 12:23:33 -04:00
// Then anything else...
if ( this_ui = = NULL ) {
2019-10-28 11:00:48 -04:00
LILV_FOREACH ( uis , i , uis ) {
const LilvUI * ui = lilv_uis_get ( uis , i ) ;
2019-10-28 11:12:58 -04:00
if ( lilv_ui_is_supported ( ui ,
suil_ui_supported ,
_world . ui_GtkUI ,
& this_ui_type ) ) {
2019-10-28 11:00:48 -04:00
this_ui = ui ;
break ;
}
}
}
// Found one that is supported by SUIL?...
2019-10-28 12:23:33 -04:00
if ( this_ui ! = NULL ) {
2019-10-28 11:00:48 -04:00
_impl - > ui = this_ui ;
_impl - > ui_type = this_ui_type ;
}
2011-05-15 19:10:13 -04:00
# else
// Look for Gtk native UI
LILV_FOREACH ( uis , i , uis ) {
const LilvUI * ui = lilv_uis_get ( uis , i ) ;
2012-03-01 14:24:13 -05:00
if ( lilv_ui_is_a ( ui , _world . ui_GtkUI ) ) {
2011-05-15 19:10:13 -04:00
_impl - > ui = ui ;
2012-03-01 14:24:13 -05:00
_impl - > ui_type = _world . ui_GtkUI ;
2011-05-15 19:10:13 -04:00
break ;
}
}
# endif
// If Gtk UI is not available, try to find external UI
if ( ! _impl - > ui ) {
LILV_FOREACH ( uis , i , uis ) {
const LilvUI * ui = lilv_uis_get ( uis , i ) ;
2013-08-25 10:20:27 -04:00
if ( lilv_ui_is_a ( ui , _world . ui_externalkx ) ) {
2011-05-15 19:10:13 -04:00
_impl - > ui = ui ;
2012-02-25 00:01:24 -05:00
_impl - > ui_type = _world . ui_external ;
2011-05-15 19:10:13 -04:00
break ;
}
2013-08-25 10:20:27 -04:00
if ( lilv_ui_is_a ( ui , _world . ui_external ) ) {
_impl - > ui = ui ;
_impl - > ui_type = _world . ui_external ;
}
2011-05-15 19:10:13 -04:00
}
}
}
2014-11-01 23:29:10 -04:00
load_supported_properties ( _property_descriptors ) ;
2012-08-28 11:42:40 -04:00
allocate_atom_event_buffers ( ) ;
2019-09-18 12:40:02 -04:00
/* Load default state */
if ( _worker ) {
/* immediately schedule any work,
* so that state restore later will not find a busy
* worker . latency_compute_run ( ) flushes any replies
*/
_worker - > set_synchronous ( true ) ;
}
if ( state ) {
lilv_state_restore ( state , _impl - > instance , set_port_value , this , 0 , _features ) ;
lilv_state_free ( state ) ;
}
2011-05-15 19:10:13 -04:00
}
2015-09-09 18:55:28 -04:00
int
LV2Plugin : : set_block_size ( pframes_t nframes )
{
if ( _impl - > opts_iface ) {
LV2_URID atom_Int = _uri_map . uri_to_id ( LV2_ATOM__Int ) ;
_impl - > block_length = nframes ;
2020-07-16 09:57:42 -04:00
LV2_Options_Option block_size_option [ ] = {
{ LV2_OPTIONS_INSTANCE , 0 , _uri_map . uri_to_id ( " http://lv2plug.in/ns/ext/buf-size#nominalBlockLength " ) ,
sizeof ( int32_t ) , atom_Int , ( void * ) & _impl - > block_length } ,
{ LV2_OPTIONS_INSTANCE , 0 , 0 , 0 , 0 , NULL }
2015-09-09 18:55:28 -04:00
} ;
2020-07-16 09:57:42 -04:00
_impl - > opts_iface - > set ( _impl - > instance - > lv2_handle , block_size_option ) ;
2015-09-09 18:55:28 -04:00
}
2019-03-31 13:19:21 -04:00
2015-09-09 18:55:28 -04:00
return 0 ;
}
2015-12-06 07:49:16 -05:00
bool
LV2Plugin : : requires_fixed_sized_buffers ( ) const
{
/* This controls if Ardour will split the plugin's run()
* on automation events in order to pass sample - accurate automation
* via standard control - ports .
*
* When returning true Ardour will * not * sub - divide the process - cycle .
* Automation events that happen between cycle - start and cycle - end will be
* ignored ( ctrl values are interpolated to cycle - start ) .
* NB . Atom Sequences are still sample accurate .
*
* Note : This does not guarantee a fixed block - size .
* e . g The process cycle may be split when looping , also
* the period - size may change any time : see set_block_size ( )
*/
2016-02-21 16:19:08 -05:00
if ( get_info ( ) - > n_inputs . n_midi ( ) > 0 ) {
/* we don't yet implement midi buffer offsets (for split cycles).
2017-09-18 12:39:17 -04:00
* Also connect_and_run ( ) also uses _session . transport_sample ( ) directly
2016-02-21 16:19:08 -05:00
* ( for BBT ) which is not offset for plugin cycle split .
*/
return true ;
}
2015-12-06 07:49:16 -05:00
return _no_sample_accurate_ctrl ;
}
2019-08-19 14:19:38 -04:00
bool
LV2Plugin : : connect_all_audio_outputs ( ) const
{
return _connect_all_audio_outputs ;
}
2011-05-15 19:10:13 -04:00
LV2Plugin : : ~ LV2Plugin ( )
{
DEBUG_TRACE ( DEBUG : : LV2 , string_compose ( " %1 destroy \n " , name ( ) ) ) ;
deactivate ( ) ;
cleanup ( ) ;
2016-10-29 13:21:48 -04:00
# ifdef LV2_EXTENDED
if ( has_midnam ( ) ) {
std : : stringstream ss ;
ss < < ( void * ) this ;
ss < < unique_id ( ) ;
MIDI : : Name : : MidiPatchManager : : instance ( ) . remove_custom_midnam ( ss . str ( ) ) ;
}
# endif
2011-05-15 19:10:13 -04:00
lilv_instance_free ( _impl - > instance ) ;
2015-09-27 08:07:04 -04:00
lilv_state_free ( _impl - > state ) ;
2011-05-15 19:10:13 -04:00
lilv_node_free ( _impl - > name ) ;
lilv_node_free ( _impl - > author ) ;
2015-09-25 13:43:43 -04:00
free ( _impl - > options ) ;
2016-03-13 18:52:48 -04:00
# ifdef LV2_EXTENDED
free ( _impl - > queue_draw ) ;
2016-10-29 13:21:48 -04:00
free ( _impl - > midnam ) ;
2017-09-08 13:26:08 -04:00
free ( _impl - > bankpatch ) ;
2016-03-13 18:52:48 -04:00
# endif
2011-05-15 19:10:13 -04:00
2012-04-04 20:15:54 -04:00
free ( _features ) ;
2016-04-24 08:41:07 -04:00
free ( _log_feature . data ) ;
2012-04-04 20:15:54 -04:00
free ( _make_path_feature . data ) ;
free ( _work_schedule_feature . data ) ;
2012-02-25 03:43:23 -05:00
delete _to_ui ;
delete _from_ui ;
2012-08-27 00:08:48 -04:00
delete _worker ;
2016-07-31 21:59:21 -04:00
delete _state_worker ;
2012-02-25 03:43:23 -05:00
2012-08-28 11:42:38 -04:00
if ( _atom_ev_buffers ) {
LV2_Evbuf * * b = _atom_ev_buffers ;
while ( * b ) {
free ( * b ) ;
b + + ;
}
free ( _atom_ev_buffers ) ;
}
2011-05-15 19:10:13 -04:00
delete [ ] _control_data ;
delete [ ] _shadow_data ;
2015-09-12 14:05:25 -04:00
delete [ ] _defaults ;
2012-02-25 03:43:23 -05:00
delete [ ] _ev_buffers ;
2016-04-24 08:41:07 -04:00
delete _impl ;
2011-05-15 19:10:13 -04:00
}
bool
LV2Plugin : : is_external_ui ( ) const
{
2019-03-31 13:25:24 -04:00
return _impl - > ui & & ( lilv_ui_is_a ( _impl - > ui , _world . ui_external ) | |
lilv_ui_is_a ( _impl - > ui , _world . ui_externalkx ) ) ;
2011-05-15 19:10:13 -04:00
}
2013-08-29 07:05:11 -04:00
bool
LV2Plugin : : is_external_kx ( ) const
{
2019-03-31 13:25:24 -04:00
return _impl - > ui & & lilv_ui_is_a ( _impl - > ui , _world . ui_externalkx ) ;
2011-05-15 19:10:13 -04:00
}
2012-03-25 13:17:40 -04:00
bool
LV2Plugin : : ui_is_resizable ( ) const
{
const LilvNode * s = lilv_ui_get_uri ( _impl - > ui ) ;
2012-04-20 21:40:17 -04:00
LilvNode * p = lilv_new_uri ( _world . world , LV2_CORE__optionalFeature ) ;
LilvNode * fs = lilv_new_uri ( _world . world , LV2_UI__fixedSize ) ;
LilvNode * nrs = lilv_new_uri ( _world . world , LV2_UI__noUserResize ) ;
2012-03-25 13:17:40 -04:00
LilvNodes * fs_matches = lilv_world_find_nodes ( _world . world , s , p , fs ) ;
LilvNodes * nrs_matches = lilv_world_find_nodes ( _world . world , s , p , nrs ) ;
lilv_nodes_free ( nrs_matches ) ;
lilv_nodes_free ( fs_matches ) ;
lilv_node_free ( nrs ) ;
lilv_node_free ( fs ) ;
lilv_node_free ( p ) ;
return ! fs_matches & & ! nrs_matches ;
}
2016-03-13 18:52:48 -04:00
# ifdef LV2_EXTENDED
bool
LV2Plugin : : has_inline_display ( ) {
return _display_interface ? true : false ;
}
2017-07-21 08:51:57 -04:00
bool
LV2Plugin : : inline_display_in_gui ( ) {
2017-07-23 15:10:07 -04:00
return _inline_display_in_gui ;
2017-07-21 08:51:57 -04:00
}
2016-03-14 11:44:20 -04:00
Plugin : : Display_Image_Surface *
2016-03-13 18:52:48 -04:00
LV2Plugin : : render_inline_display ( uint32_t w , uint32_t h ) {
if ( _display_interface ) {
2016-03-14 11:44:20 -04:00
/* Plugin::Display_Image_Surface is identical to
* LV2_Inline_Display_Image_Surface */
return ( Plugin : : Display_Image_Surface * ) _display_interface - > render ( ( void * ) _impl - > instance - > lv2_handle , w , h ) ;
2016-03-13 18:52:48 -04:00
}
return NULL ;
}
2016-10-29 13:21:48 -04:00
bool
LV2Plugin : : has_midnam ( ) {
return _midname_interface ? true : false ;
}
bool
LV2Plugin : : read_midnam ( ) {
bool rv = false ;
2017-09-08 21:07:01 -04:00
if ( ! _midname_interface | | ! _midnam_dirty ) {
2016-10-29 13:21:48 -04:00
return rv ;
}
char * midnam = _midname_interface - > midnam ( ( void * ) _impl - > instance - > lv2_handle ) ;
if ( midnam ) {
2020-02-06 16:40:18 -05:00
rv = MIDI : : Name : : MidiPatchManager : : instance ( ) . update_custom_midnam ( midnam_model ( ) , midnam ) ;
2016-10-30 16:24:26 -04:00
}
# ifndef NDEBUG
if ( rv ) {
info < < string_compose ( _ ( " LV2: update midnam for plugin '%1' " ) , name ( ) ) < < endmsg ;
} else {
warning < < string_compose ( _ ( " LV2: Failed to parse midnam of plugin '%1' " ) , name ( ) ) < < endmsg ;
2016-10-29 13:21:48 -04:00
}
2016-10-30 16:24:26 -04:00
# endif
2016-10-30 12:38:24 -04:00
_midname_interface - > free ( midnam ) ;
2017-09-08 21:07:01 -04:00
if ( rv ) {
UpdatedMidnam ( ) ;
_midnam_dirty = false ;
}
2016-10-29 13:21:48 -04:00
return rv ;
}
std : : string
LV2Plugin : : midnam_model ( ) {
std : : string rv ;
if ( ! _midname_interface ) {
return rv ;
}
char * model = _midname_interface - > model ( ( void * ) _impl - > instance - > lv2_handle ) ;
if ( model ) {
rv = model ;
}
2016-10-30 12:38:24 -04:00
_midname_interface - > free ( model ) ;
2016-10-29 13:21:48 -04:00
return rv ;
}
2016-03-13 18:52:48 -04:00
# endif
2011-05-15 19:10:13 -04:00
string
LV2Plugin : : unique_id ( ) const
{
return lilv_node_as_uri ( lilv_plugin_get_uri ( _impl - > plugin ) ) ;
}
const char *
LV2Plugin : : uri ( ) const
{
return lilv_node_as_uri ( lilv_plugin_get_uri ( _impl - > plugin ) ) ;
}
const char *
LV2Plugin : : label ( ) const
{
return lilv_node_as_string ( _impl - > name ) ;
}
const char *
LV2Plugin : : name ( ) const
{
return lilv_node_as_string ( _impl - > name ) ;
}
const char *
LV2Plugin : : maker ( ) const
{
return _impl - > author ? lilv_node_as_string ( _impl - > author ) : " Unknown " ;
}
uint32_t
LV2Plugin : : num_ports ( ) const
{
return lilv_plugin_get_num_ports ( _impl - > plugin ) ;
}
uint32_t
LV2Plugin : : parameter_count ( ) const
{
return lilv_plugin_get_num_ports ( _impl - > plugin ) ;
}
float
LV2Plugin : : default_value ( uint32_t port )
{
return _defaults [ port ] ;
}
const char *
LV2Plugin : : port_symbol ( uint32_t index ) const
{
const LilvPort * port = lilv_plugin_get_port_by_index ( _impl - > plugin , index ) ;
if ( ! port ) {
error < < name ( ) < < " : Invalid port index " < < index < < endmsg ;
}
const LilvNode * sym = lilv_port_get_symbol ( _impl - > plugin , port ) ;
return lilv_node_as_string ( sym ) ;
}
2012-04-11 00:00:27 -04:00
uint32_t
LV2Plugin : : port_index ( const char * symbol ) const
{
const map < string , uint32_t > : : const_iterator i = _port_indices . find ( symbol ) ;
if ( i ! = _port_indices . end ( ) ) {
return i - > second ;
} else {
warning < < string_compose ( _ ( " LV2: Unknown port %1 " ) , symbol ) < < endmsg ;
return ( uint32_t ) - 1 ;
}
}
2011-05-15 19:10:13 -04:00
void
2020-08-07 16:02:56 -04:00
LV2Plugin : : set_parameter ( uint32_t which , float val , sampleoffset_t when )
2011-05-15 19:10:13 -04:00
{
DEBUG_TRACE ( DEBUG : : LV2 , string_compose (
" %1 set parameter %2 to %3 \n " , name ( ) , which , val ) ) ;
if ( which < lilv_plugin_get_num_ports ( _impl - > plugin ) ) {
2012-07-12 17:16:20 -04:00
if ( get_parameter ( which ) = = val ) {
return ;
}
2012-08-07 20:21:05 -04:00
_shadow_data [ which ] = val ;
2011-05-15 19:10:13 -04:00
} else {
warning < < string_compose (
_ ( " Illegal parameter number used with plugin \" %1 \" . "
" This is a bug in either %2 or the LV2 plugin <%3> " ) ,
name ( ) , PROGRAM_NAME , unique_id ( ) ) < < endmsg ;
}
2020-08-07 16:02:56 -04:00
Plugin : : set_parameter ( which , val , when ) ;
2011-05-15 19:10:13 -04:00
}
float
LV2Plugin : : get_parameter ( uint32_t which ) const
{
if ( parameter_is_input ( which ) ) {
return ( float ) _shadow_data [ which ] ;
} else {
return ( float ) _control_data [ which ] ;
}
return 0.0f ;
}
2012-04-19 22:12:29 -04:00
std : : string
LV2Plugin : : get_docs ( ) const
{
LilvNodes * comments = lilv_plugin_get_value ( _impl - > plugin , _world . rdfs_comment ) ;
if ( comments ) {
const std : : string docs ( lilv_node_as_string ( lilv_nodes_get_first ( comments ) ) ) ;
lilv_nodes_free ( comments ) ;
return docs ;
}
return " " ;
}
2012-08-07 20:21:05 -04:00
2012-04-19 21:24:07 -04:00
std : : string
LV2Plugin : : get_parameter_docs ( uint32_t which ) const
{
LilvNodes * comments = lilv_port_get_value (
_impl - > plugin ,
lilv_plugin_get_port_by_index ( _impl - > plugin , which ) ,
_world . rdfs_comment ) ;
if ( comments ) {
const std : : string docs ( lilv_node_as_string ( lilv_nodes_get_first ( comments ) ) ) ;
lilv_nodes_free ( comments ) ;
return docs ;
}
return " " ;
}
2011-05-15 19:10:13 -04:00
uint32_t
LV2Plugin : : nth_parameter ( uint32_t n , bool & ok ) const
{
ok = false ;
for ( uint32_t c = 0 , x = 0 ; x < lilv_plugin_get_num_ports ( _impl - > plugin ) ; + + x ) {
if ( parameter_is_control ( x ) ) {
if ( c + + = = n ) {
ok = true ;
return x ;
}
}
}
return 0 ;
}
const void *
2012-09-08 14:18:47 -04:00
LV2Plugin : : extension_data ( const char * uri ) const
2011-05-15 19:10:13 -04:00
{
return lilv_instance_get_extension_data ( _impl - > instance , uri ) ;
}
2012-08-18 11:56:48 -04:00
const void *
2012-09-08 14:18:47 -04:00
LV2Plugin : : c_plugin ( )
2011-05-15 19:10:13 -04:00
{
return _impl - > plugin ;
}
2012-08-18 11:56:48 -04:00
const void *
2012-09-08 14:18:47 -04:00
LV2Plugin : : c_ui ( )
2011-05-15 19:10:13 -04:00
{
2012-08-18 11:56:48 -04:00
return ( const void * ) _impl - > ui ;
2011-05-15 19:10:13 -04:00
}
2012-08-18 11:56:48 -04:00
const void *
2012-09-08 14:18:47 -04:00
LV2Plugin : : c_ui_type ( )
2011-05-15 19:10:13 -04:00
{
2012-08-18 11:56:48 -04:00
return ( const void * ) _impl - > ui_type ;
2011-05-15 19:10:13 -04:00
}
2012-01-28 13:19:19 -05:00
/** Directory for all plugin state. */
const std : : string
LV2Plugin : : plugin_dir ( ) const
{
2015-12-18 08:27:15 -05:00
if ( ! _plugin_state_dir . empty ( ) ) {
return Glib : : build_filename ( _plugin_state_dir , _insert_id . to_s ( ) ) ;
} else {
return Glib : : build_filename ( _session . plugins_dir ( ) , _insert_id . to_s ( ) ) ;
}
2012-01-28 13:19:19 -05:00
}
2012-01-27 20:45:15 -05:00
/** Directory for files created by the plugin (except during save). */
2011-11-23 19:53:45 -05:00
const std : : string
2012-01-27 20:45:15 -05:00
LV2Plugin : : scratch_dir ( ) const
2011-11-23 19:53:45 -05:00
{
2012-01-28 13:19:19 -05:00
return Glib : : build_filename ( plugin_dir ( ) , " scratch " ) ;
2011-11-23 19:53:45 -05:00
}
2012-01-27 20:45:15 -05:00
/** Directory for snapshots of files in the scratch directory. */
const std : : string
LV2Plugin : : file_dir ( ) const
2011-05-15 19:10:13 -04:00
{
2012-01-28 13:19:19 -05:00
return Glib : : build_filename ( plugin_dir ( ) , " files " ) ;
2011-05-15 19:10:13 -04:00
}
2012-01-27 20:45:15 -05:00
/** Directory to save state snapshot version @c num into. */
const std : : string
LV2Plugin : : state_dir ( unsigned num ) const
2011-05-15 19:10:13 -04:00
{
2016-09-27 02:33:05 -04:00
return Glib : : build_filename ( plugin_dir ( ) , string ( " state " ) + PBD : : to_string ( num ) ) ;
2011-05-15 19:10:13 -04:00
}
2012-01-27 20:45:15 -05:00
/** Implementation of state:makePath for files created at instantiation time.
* Note this is not used for files created at save time ( Lilv deals with that ) .
*/
2011-05-15 19:10:13 -04:00
char *
2011-11-23 01:39:45 -05:00
LV2Plugin : : lv2_state_make_path ( LV2_State_Make_Path_Handle handle ,
const char * path )
2011-05-15 19:10:13 -04:00
{
2011-11-23 01:39:45 -05:00
LV2Plugin * me = ( LV2Plugin * ) handle ;
2011-05-15 19:10:13 -04:00
if ( me - > _insert_id = = PBD : : ID ( " 0 " ) ) {
2012-01-27 20:45:15 -05:00
warning < < string_compose (
" File path \" %1 \" requested but LV2 %2 has no insert ID " ,
path , me - > name ( ) ) < < endmsg ;
2011-11-23 01:39:45 -05:00
return g_strdup ( path ) ;
2011-05-15 19:10:13 -04:00
}
2012-01-27 20:45:15 -05:00
const std : : string abs_path = Glib : : build_filename ( me - > scratch_dir ( ) , path ) ;
2011-11-23 19:53:45 -05:00
const std : : string dirname = Glib : : path_get_dirname ( abs_path ) ;
2011-11-23 01:39:45 -05:00
g_mkdir_with_parents ( dirname . c_str ( ) , 0744 ) ;
2011-05-15 19:10:13 -04:00
DEBUG_TRACE ( DEBUG : : LV2 , string_compose ( " new file path %1 => %2 \n " ,
2011-11-23 01:39:45 -05:00
path , abs_path ) ) ;
2011-06-01 12:50:12 -04:00
2011-11-23 01:39:45 -05:00
return g_strndup ( abs_path . c_str ( ) , abs_path . length ( ) ) ;
2011-05-15 19:10:13 -04:00
}
void
LV2Plugin : : add_state ( XMLNode * root ) const
{
assert ( _insert_id ! = PBD : : ID ( " 0 " ) ) ;
XMLNode * child ;
2016-05-07 06:19:41 -04:00
LocaleGuard lg ;
2011-05-15 19:10:13 -04:00
for ( uint32_t i = 0 ; i < parameter_count ( ) ; + + i ) {
if ( parameter_is_input ( i ) & & parameter_is_control ( i ) ) {
child = new XMLNode ( " Port " ) ;
2016-08-25 01:55:51 -04:00
child - > set_property ( " symbol " , port_symbol ( i ) ) ;
child - > set_property ( " value " , _shadow_data [ i ] ) ;
2011-05-15 19:10:13 -04:00
root - > add_child_nocopy ( * child ) ;
}
}
2015-12-18 08:27:15 -05:00
if ( ! _plugin_state_dir . empty ( ) ) {
2016-08-25 01:55:51 -04:00
root - > set_property ( " template-dir " , _plugin_state_dir ) ;
2015-12-18 08:27:15 -05:00
}
2011-11-11 17:54:45 -05:00
if ( _has_state_interface ) {
2012-01-27 20:45:15 -05:00
// Provisionally increment state version and create directory
const std : : string new_dir = state_dir ( + + _state_version ) ;
2016-11-13 19:40:57 -05:00
// and keep track of it (for templates & archive)
unsigned int saved_state = _state_version ; ;
2012-01-27 20:45:15 -05:00
g_mkdir_with_parents ( new_dir . c_str ( ) , 0744 ) ;
2018-07-09 18:57:04 -04:00
std : : string xternal_dir = _session . externals_dir ( ) ;
if ( ! _plugin_state_dir . empty ( ) ) {
xternal_dir = Glib : : build_filename ( _plugin_state_dir , externals_dir_name ) ;
g_mkdir_with_parents ( xternal_dir . c_str ( ) , 0744 ) ;
}
2012-01-27 20:45:15 -05:00
LilvState * state = lilv_state_new_from_instance (
_impl - > plugin ,
_impl - > instance ,
_uri_map . urid_map ( ) ,
scratch_dir ( ) . c_str ( ) ,
file_dir ( ) . c_str ( ) ,
2018-07-09 18:57:04 -04:00
xternal_dir . c_str ( ) ,
2012-01-27 20:45:15 -05:00
new_dir . c_str ( ) ,
NULL ,
2012-11-17 13:41:19 -05:00
const_cast < LV2Plugin * > ( this ) ,
2012-01-27 20:45:15 -05:00
0 ,
NULL ) ;
2016-09-20 21:45:57 -04:00
if ( ! _plugin_state_dir . empty ( ) | | force_state_save
2016-01-15 07:44:17 -05:00
| | ! _impl - > state
| | ! lilv_state_equals ( state , _impl - > state ) ) {
2012-01-27 20:45:15 -05:00
lilv_state_save ( _world . world ,
2012-03-03 16:46:25 -05:00
_uri_map . urid_map ( ) ,
2012-01-27 20:45:15 -05:00
_uri_map . urid_unmap ( ) ,
state ,
NULL ,
new_dir . c_str ( ) ,
2012-03-03 16:46:25 -05:00
" state.ttl " ) ;
2012-01-27 20:45:15 -05:00
2016-09-20 21:45:57 -04:00
if ( force_state_save ) {
// archive or save-as
lilv_state_free ( state ) ;
- - _state_version ;
}
else if ( _plugin_state_dir . empty ( ) ) {
2016-01-15 07:44:17 -05:00
// normal session save
lilv_state_free ( _impl - > state ) ;
_impl - > state = state ;
} else {
// template save (dedicated state-dir)
lilv_state_free ( state ) ;
2018-07-09 18:57:04 -04:00
g_rmdir ( xternal_dir . c_str ( ) ) ; // try remove unused dir
2016-09-20 21:45:57 -04:00
- - _state_version ;
2016-01-15 07:44:17 -05:00
}
2012-01-27 20:45:15 -05:00
} else {
// State is identical, decrement version and nuke directory
lilv_state_free ( state ) ;
2014-03-22 12:40:43 -04:00
PBD : : remove_directory ( new_dir ) ;
2012-01-27 20:45:15 -05:00
- - _state_version ;
2016-11-13 19:40:57 -05:00
saved_state = _state_version ;
2011-05-15 19:10:13 -04:00
}
2016-09-27 05:57:26 -04:00
root - > set_property ( " state-dir " , string ( " state " ) + PBD : : to_string ( saved_state ) ) ;
2011-05-15 19:10:13 -04:00
}
}
2014-11-03 11:54:35 -05:00
static LilvNode *
2011-05-15 19:10:13 -04:00
get_value ( LilvWorld * world , const LilvNode * subject , const LilvNode * predicate )
{
2018-12-19 20:06:53 -05:00
return lilv_world_get ( world , subject , predicate , NULL ) ;
2011-05-15 19:10:13 -04:00
}
2012-04-12 20:43:01 -04:00
void
LV2Plugin : : find_presets ( )
2011-05-15 19:10:13 -04:00
{
2018-12-18 07:35:39 -05:00
/* see also LV2PluginInfo::get_presets */
2012-04-20 21:40:17 -04:00
LilvNode * lv2_appliesTo = lilv_new_uri ( _world . world , LV2_CORE__appliesTo ) ;
LilvNode * pset_Preset = lilv_new_uri ( _world . world , LV2_PRESETS__Preset ) ;
2012-04-12 20:43:01 -04:00
LilvNode * rdfs_label = lilv_new_uri ( _world . world , LILV_NS_RDFS " label " ) ;
2018-12-18 07:35:39 -05:00
LilvNode * rdfs_comment = lilv_new_uri ( _world . world , LILV_NS_RDFS " comment " ) ;
2012-04-12 20:43:01 -04:00
LilvNodes * presets = lilv_plugin_get_related ( _impl - > plugin , pset_Preset ) ;
2011-05-15 19:10:13 -04:00
LILV_FOREACH ( nodes , i , presets ) {
const LilvNode * preset = lilv_nodes_get ( presets , i ) ;
2012-04-12 20:43:01 -04:00
lilv_world_load_resource ( _world . world , preset ) ;
2014-11-03 11:54:35 -05:00
LilvNode * name = get_value ( _world . world , preset , rdfs_label ) ;
2018-12-18 07:35:39 -05:00
LilvNode * comment = get_value ( _world . world , preset , rdfs_comment ) ;
/* TODO properly identify user vs factory presets.
* here ' s an indirect condition : only factory presets can have comments
*/
bool userpreset = comment ? false : true ;
2011-05-15 19:10:13 -04:00
if ( name ) {
2012-04-12 20:43:01 -04:00
_presets . insert ( std : : make_pair ( lilv_node_as_string ( preset ) ,
Plugin : : PresetRecord (
lilv_node_as_string ( preset ) ,
2016-01-08 18:57:53 -05:00
lilv_node_as_string ( name ) ,
2018-12-18 07:35:39 -05:00
userpreset ,
comment ? lilv_node_as_string ( comment ) : " "
) ) ) ;
2014-11-03 11:54:35 -05:00
lilv_node_free ( name ) ;
2011-05-15 19:10:13 -04:00
} else {
warning < < string_compose (
2013-08-02 12:50:52 -04:00
_ ( " Plugin \" %1 \" preset \" %2 \" is missing a label \n " ) ,
2012-04-12 20:43:01 -04:00
lilv_node_as_string ( lilv_plugin_get_uri ( _impl - > plugin ) ) ,
2012-01-27 20:45:15 -05:00
lilv_node_as_string ( preset ) ) < < endmsg ;
2011-05-15 19:10:13 -04:00
}
2018-12-18 07:35:39 -05:00
if ( comment ) {
lilv_node_free ( comment ) ;
}
2011-05-15 19:10:13 -04:00
}
lilv_nodes_free ( presets ) ;
2018-12-18 07:35:39 -05:00
lilv_node_free ( rdfs_comment ) ;
2011-12-09 14:42:32 -05:00
lilv_node_free ( rdfs_label ) ;
2012-04-12 20:43:01 -04:00
lilv_node_free ( pset_Preset ) ;
lilv_node_free ( lv2_appliesTo ) ;
2011-05-15 19:10:13 -04:00
}
2013-03-24 18:44:18 -04:00
bool
LV2Plugin : : load_preset ( PresetRecord r )
{
LilvWorld * world = _world . world ;
LilvNode * pset = lilv_new_uri ( world , r . uri . c_str ( ) ) ;
LilvState * state = lilv_state_new_from_world ( world , _uri_map . urid_map ( ) , pset ) ;
2016-07-31 21:59:21 -04:00
const LV2_Feature * state_features [ 2 ] = { NULL , NULL } ;
LV2_Worker_Schedule schedule = { _state_worker , work_schedule } ;
const LV2_Feature state_sched_feature = { LV2_WORKER__schedule , & schedule } ;
if ( _state_worker ) {
2016-07-31 22:48:15 -04:00
state_features [ 0 ] = & state_sched_feature ;
2016-07-31 21:59:21 -04:00
}
2013-03-24 18:44:18 -04:00
if ( state ) {
2016-07-31 21:59:21 -04:00
lilv_state_restore ( state , _impl - > instance , set_port_value , this , 0 , state_features ) ;
2013-03-24 18:44:18 -04:00
lilv_state_free ( state ) ;
2014-01-23 07:14:25 -05:00
Plugin : : load_preset ( r ) ;
2013-03-24 18:44:18 -04:00
}
2013-03-24 20:10:11 -04:00
lilv_node_free ( pset ) ;
return state ;
2011-05-15 19:10:13 -04:00
}
2012-06-19 11:59:50 -04:00
const void *
ARDOUR : : lv2plugin_get_port_value ( const char * port_symbol ,
void * user_data ,
uint32_t * size ,
uint32_t * type )
{
LV2Plugin * plugin = ( LV2Plugin * ) user_data ;
uint32_t index = plugin - > port_index ( port_symbol ) ;
if ( index ! = ( uint32_t ) - 1 ) {
if ( plugin - > parameter_is_input ( index ) & & plugin - > parameter_is_control ( index ) ) {
float * value ;
* size = sizeof ( float ) ;
* type = plugin - > _uri_map . uri_to_id ( LV2_ATOM__Float ) ;
value = & plugin - > _shadow_data [ index ] ;
return value ;
}
}
* size = * type = 0 ;
return NULL ;
}
2011-05-15 19:10:13 -04:00
std : : string
2012-06-19 11:59:50 -04:00
LV2Plugin : : do_save_preset ( string name )
2011-05-15 19:10:13 -04:00
{
2015-03-07 14:54:03 -05:00
LilvNode * plug_name = lilv_plugin_get_name ( _impl - > plugin ) ;
const string prefix = legalize_for_uri ( lilv_node_as_string ( plug_name ) ) ;
2013-03-17 12:52:49 -04:00
const string base_name = legalize_for_uri ( name ) ;
const string file_name = base_name + " .ttl " ;
2017-08-11 10:54:39 -04:00
# ifdef PLATFORM_WINDOWS
/* http://lv2plug.in/pages/filesystem-hierarchy-standard.html */
std : : string appdata = PBD : : get_win_special_folder_path ( CSIDL_APPDATA ) ;
if ( appdata . empty ( ) ) {
// TODO consider a fallback location
return " " ;
}
const string bundle = Glib : : build_filename (
2017-08-11 11:33:44 -04:00
appdata , " LV2 " , prefix + " _ " + base_name + " .lv2 " ) ;
2017-08-11 10:54:39 -04:00
# else
/* while macOS/OSX user-specific path is
*
* $ HOME / Library / Audio / Plug - Ins / LV2 /
*
* liblilv ' s LV2 search path on all unices does include ~ / . lv2 /
* Ardour has been saving lv2 presets to ~ / . lv2 for along time ,
* so just keep them there .
*/
2013-03-17 12:52:49 -04:00
const string bundle = Glib : : build_filename (
2012-08-07 20:21:05 -04:00
Glib : : get_home_dir ( ) ,
2015-03-07 14:54:03 -05:00
Glib : : build_filename ( " .lv2 " , prefix + " _ " + base_name + " .lv2 " ) ) ;
2017-08-11 10:54:39 -04:00
# endif
2012-06-19 11:59:50 -04:00
2015-05-22 12:25:07 -04:00
/* delete reference to old preset (if any) */
2020-06-24 17:56:42 -04:00
#if 0 // prefer this when https://github.com/lv2/lilv/issues/37 is resolved
do_remove_preset ( name ) ;
# else
/* this works around https://github.com/lv2/lilv/issues/37
*
* do_remove_preset ( ) calls lilv_state_delete ( ) ; That
* deletes all mapped files without re - creating them .
* So for the time being we just leave them in place .
*/
2015-05-22 12:25:07 -04:00
const PresetRecord * r = preset_by_label ( name ) ;
if ( r ) {
LilvNode * pset = lilv_new_uri ( _world . world , r - > uri . c_str ( ) ) ;
if ( pset ) {
lilv_world_unload_resource ( _world . world , pset ) ;
lilv_node_free ( pset ) ;
}
}
2020-06-24 17:56:42 -04:00
# endif
2015-05-22 12:25:07 -04:00
2012-06-19 11:59:50 -04:00
LilvState * state = lilv_state_new_from_instance (
_impl - > plugin ,
_impl - > instance ,
_uri_map . urid_map ( ) ,
2013-03-17 12:52:49 -04:00
scratch_dir ( ) . c_str ( ) , // file_dir
bundle . c_str ( ) , // copy_dir
bundle . c_str ( ) , // link_dir
bundle . c_str ( ) , // save_dir
lv2plugin_get_port_value , // get_value
( void * ) this , // user_data
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE , // flags
_features // features
2012-06-19 11:59:50 -04:00
) ;
lilv_state_set_label ( state , name . c_str ( ) ) ;
lilv_state_save (
2012-08-07 20:21:05 -04:00
_world . world , // world
2013-03-17 12:52:49 -04:00
_uri_map . urid_map ( ) , // map
_uri_map . urid_unmap ( ) , // unmap
2012-08-07 20:21:05 -04:00
state , // state
2013-03-17 12:52:49 -04:00
NULL , // uri (NULL = use file URI)
bundle . c_str ( ) , // dir
file_name . c_str ( ) // filename
2012-06-19 11:59:50 -04:00
) ;
lilv_state_free ( state ) ;
2013-03-17 12:52:49 -04:00
2014-01-05 07:07:31 -05:00
std : : string uri = Glib : : filename_to_uri ( Glib : : build_filename ( bundle , file_name ) ) ;
2014-01-12 11:14:14 -05:00
LilvNode * node_bundle = lilv_new_uri ( _world . world , Glib : : filename_to_uri ( Glib : : build_filename ( bundle , " / " ) ) . c_str ( ) ) ;
LilvNode * node_preset = lilv_new_uri ( _world . world , uri . c_str ( ) ) ;
2014-07-15 15:49:47 -04:00
lilv_world_unload_resource ( _world . world , node_preset ) ;
lilv_world_unload_bundle ( _world . world , node_bundle ) ;
2014-01-12 11:14:14 -05:00
lilv_world_load_bundle ( _world . world , node_bundle ) ;
lilv_world_load_resource ( _world . world , node_preset ) ;
lilv_node_free ( node_bundle ) ;
lilv_node_free ( node_preset ) ;
2015-03-07 14:54:03 -05:00
lilv_node_free ( plug_name ) ;
2014-01-05 07:07:31 -05:00
return uri ;
2011-05-15 19:10:13 -04:00
}
void
2012-06-19 11:59:50 -04:00
LV2Plugin : : do_remove_preset ( string name )
{
2015-03-07 14:54:03 -05:00
/* Look up preset record by label (FIXME: ick, label as ID) */
const PresetRecord * r = preset_by_label ( name ) ;
if ( ! r ) {
return ;
}
/* Load a LilvState for the preset. */
LilvWorld * world = _world . world ;
LilvNode * pset = lilv_new_uri ( world , r - > uri . c_str ( ) ) ;
LilvState * state = lilv_state_new_from_world ( world , _uri_map . urid_map ( ) , pset ) ;
if ( ! state ) {
lilv_node_free ( pset ) ;
return ;
}
2015-05-22 00:24:37 -04:00
/* Unload preset from world. */
lilv_world_unload_resource ( world , pset ) ;
2015-03-07 14:54:03 -05:00
/* Delete it from the file system. This will remove the preset file and the entry
from the manifest . If this results in an empty manifest ( i . e . the
preset is the only thing in the bundle ) , then the bundle is removed . */
lilv_state_delete ( world , state ) ;
lilv_state_free ( state ) ;
lilv_node_free ( pset ) ;
2012-06-19 11:59:50 -04:00
}
2011-05-15 19:10:13 -04:00
bool
LV2Plugin : : has_editor ( ) const
{
return _impl - > ui ! = NULL ;
}
2012-02-25 15:43:14 -05:00
bool
LV2Plugin : : has_message_output ( ) const
{
for ( uint32_t i = 0 ; i < num_ports ( ) ; + + i ) {
2012-11-17 23:35:31 -05:00
if ( ( _port_flags [ i ] & PORT_SEQUENCE ) & &
( _port_flags [ i ] & PORT_OUTPUT ) ) {
2012-02-25 15:43:14 -05:00
return true ;
}
}
return false ;
}
2012-11-17 20:30:53 -05:00
bool
2012-02-25 03:43:23 -05:00
LV2Plugin : : write_to ( RingBuffer < uint8_t > * dest ,
uint32_t index ,
uint32_t protocol ,
uint32_t size ,
2012-08-21 15:29:19 -04:00
const uint8_t * body )
2012-02-25 03:43:23 -05:00
{
2013-08-04 10:17:19 -04:00
const uint32_t buf_size = sizeof ( UIMessage ) + size ;
vector < uint8_t > buf ( buf_size ) ;
2012-02-25 03:43:23 -05:00
2013-08-04 10:17:19 -04:00
UIMessage * msg = ( UIMessage * ) & buf [ 0 ] ;
2012-02-25 03:43:23 -05:00
msg - > index = index ;
msg - > protocol = protocol ;
msg - > size = size ;
memcpy ( msg + 1 , body , size ) ;
2013-08-04 10:17:19 -04:00
return ( dest - > write ( & buf [ 0 ] , buf_size ) = = buf_size ) ;
2012-02-25 03:43:23 -05:00
}
2012-11-17 20:30:53 -05:00
bool
2012-08-21 15:29:19 -04:00
LV2Plugin : : write_from_ui ( uint32_t index ,
uint32_t protocol ,
uint32_t size ,
const uint8_t * body )
2012-02-25 03:43:23 -05:00
{
if ( ! _from_ui ) {
2013-08-11 09:10:41 -04:00
size_t rbs = _session . engine ( ) . raw_buffer_size ( DataType : : MIDI ) * NBUFS ;
/* buffer data communication from plugin UI to plugin instance.
* this buffer needs to potentially hold
* ( port ' s minimumSize ) * ( audio - periods ) / ( UI - periods )
* bytes .
*
* e . g 48 kSPS / 128f pp - > audio - periods = 375 Hz
* ui - periods = 25 Hz ( SuperRapidScreenUpdate )
* default minimumSize = 32 K ( see LV2Plugin : : allocate_atom_event_buffers ( )
2013-12-12 08:40:45 -05:00
*
* it is NOT safe to overflow ( msg . size will be misinterpreted )
2013-08-11 09:10:41 -04:00
*/
2013-12-12 08:40:45 -05:00
uint32_t bufsiz = 32768 ;
if ( _atom_ev_buffers & & _atom_ev_buffers [ 0 ] ) {
bufsiz = lv2_evbuf_get_capacity ( _atom_ev_buffers [ 0 ] ) ;
}
2017-09-18 12:39:17 -04:00
int fact = ceilf ( _session . sample_rate ( ) / 3000.f ) ;
2017-01-19 15:07:22 -05:00
rbs = max ( ( size_t ) bufsiz * std : : max ( 8 , fact ) , rbs ) ;
2013-08-11 09:10:41 -04:00
_from_ui = new RingBuffer < uint8_t > ( rbs ) ;
2012-02-25 03:43:23 -05:00
}
2012-11-17 20:30:53 -05:00
if ( ! write_to ( _from_ui , index , protocol , size , body ) ) {
2020-01-21 16:18:37 -05:00
error < < string_compose ( _ ( " LV2<%1>: Error writing from UI to plugin " ) , name ( ) ) < < endmsg ;
2012-11-17 20:30:53 -05:00
return false ;
}
return true ;
2012-02-25 03:43:23 -05:00
}
2012-11-17 20:30:53 -05:00
bool
2012-08-21 15:29:19 -04:00
LV2Plugin : : write_to_ui ( uint32_t index ,
uint32_t protocol ,
uint32_t size ,
const uint8_t * body )
2012-02-25 15:54:38 -05:00
{
2012-11-17 20:30:53 -05:00
if ( ! write_to ( _to_ui , index , protocol , size , body ) ) {
2020-01-21 16:18:37 -05:00
error < < string_compose ( _ ( " LV2<%1>: Error writing from plugin to UI " ) , name ( ) ) < < endmsg ;
2012-11-17 20:30:53 -05:00
return false ;
}
return true ;
2012-02-25 15:54:38 -05:00
}
2014-10-31 20:44:02 -04:00
static void
forge_variant ( LV2_Atom_Forge * forge , const Variant & value )
{
switch ( value . type ( ) ) {
2014-11-07 17:21:43 -05:00
case Variant : : NOTHING :
2014-10-31 23:48:27 -04:00
break ;
2014-12-31 17:16:28 -05:00
case Variant : : BEATS :
// No atom type for this, just forge a double
lv2_atom_forge_double ( forge , value . get_beats ( ) . to_double ( ) ) ;
break ;
2014-10-31 20:44:02 -04:00
case Variant : : BOOL :
lv2_atom_forge_bool ( forge , value . get_bool ( ) ) ;
break ;
case Variant : : DOUBLE :
lv2_atom_forge_double ( forge , value . get_double ( ) ) ;
break ;
case Variant : : FLOAT :
lv2_atom_forge_float ( forge , value . get_float ( ) ) ;
break ;
case Variant : : INT :
lv2_atom_forge_int ( forge , value . get_int ( ) ) ;
break ;
case Variant : : LONG :
lv2_atom_forge_long ( forge , value . get_long ( ) ) ;
break ;
case Variant : : PATH :
lv2_atom_forge_path (
forge , value . get_path ( ) . c_str ( ) , value . get_path ( ) . size ( ) ) ;
break ;
case Variant : : STRING :
lv2_atom_forge_string (
forge , value . get_string ( ) . c_str ( ) , value . get_string ( ) . size ( ) ) ;
break ;
case Variant : : URI :
lv2_atom_forge_uri (
forge , value . get_uri ( ) . c_str ( ) , value . get_uri ( ) . size ( ) ) ;
break ;
}
}
/** Get a variant type from a URI, return false iff no match found. */
static bool
uri_to_variant_type ( const std : : string & uri , Variant : : Type & type )
{
if ( uri = = LV2_ATOM__Bool ) {
type = Variant : : BOOL ;
} else if ( uri = = LV2_ATOM__Double ) {
type = Variant : : DOUBLE ;
} else if ( uri = = LV2_ATOM__Float ) {
type = Variant : : FLOAT ;
} else if ( uri = = LV2_ATOM__Int ) {
type = Variant : : INT ;
} else if ( uri = = LV2_ATOM__Long ) {
type = Variant : : LONG ;
} else if ( uri = = LV2_ATOM__Path ) {
type = Variant : : PATH ;
} else if ( uri = = LV2_ATOM__String ) {
type = Variant : : STRING ;
} else if ( uri = = LV2_ATOM__URI ) {
type = Variant : : URI ;
} else {
return false ;
}
return true ;
}
void
LV2Plugin : : set_property ( uint32_t key , const Variant & value )
{
if ( _patch_port_in_index = = ( uint32_t ) - 1 ) {
2020-01-21 16:18:37 -05:00
error < < string_compose ( _ ( " LV2<1>: set_property called with unset patch_port_in_index " ) , name ( ) ) < < endmsg ;
2014-10-31 20:44:02 -04:00
return ;
2014-11-07 17:21:43 -05:00
} else if ( value . type ( ) = = Variant : : NOTHING ) {
2020-01-21 16:18:37 -05:00
error < < string_compose ( _ ( " LV2<1>: set_property called with void value " ) , name ( ) ) < < endmsg ;
2014-10-31 23:48:27 -04:00
return ;
2014-10-31 20:44:02 -04:00
}
// Set up forge to write to temporary buffer on the stack
LV2_Atom_Forge * forge = & _impl - > ui_forge ;
2019-04-08 12:32:09 -04:00
LV2_Atom_Forge_Frame frame ;
2014-10-31 20:44:02 -04:00
uint8_t buf [ PATH_MAX ] ; // Ought to be enough for anyone...
lv2_atom_forge_set_buffer ( forge , buf , sizeof ( buf ) ) ;
// Serialize patch:Set message to set property
# ifdef HAVE_LV2_1_10_0
2019-04-08 12:32:09 -04:00
lv2_atom_forge_object ( forge , & frame , 0 , _uri_map . urids . patch_Set ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_key ( forge , _uri_map . urids . patch_property ) ;
2014-10-31 20:44:02 -04:00
lv2_atom_forge_urid ( forge , key ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_key ( forge , _uri_map . urids . patch_value ) ;
2014-10-31 20:44:02 -04:00
# else
2019-04-08 12:32:09 -04:00
lv2_atom_forge_blank ( forge , & frame , 0 , _uri_map . urids . patch_Set ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_property_head ( forge , _uri_map . urids . patch_property , 0 ) ;
2014-10-31 20:44:02 -04:00
lv2_atom_forge_urid ( forge , key ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_property_head ( forge , _uri_map . urids . patch_value , 0 ) ;
2014-10-31 20:44:02 -04:00
# endif
forge_variant ( forge , value ) ;
// Write message to UI=>Plugin ring
const LV2_Atom * const atom = ( const LV2_Atom * ) buf ;
write_from_ui ( _patch_port_in_index ,
2014-11-01 23:29:10 -04:00
_uri_map . urids . atom_eventTransfer ,
2014-10-31 20:44:02 -04:00
lv2_atom_total_size ( atom ) ,
( const uint8_t * ) atom ) ;
}
2014-11-01 23:29:10 -04:00
const ParameterDescriptor &
LV2Plugin : : get_property_descriptor ( uint32_t id ) const
{
PropertyDescriptors : : const_iterator p = _property_descriptors . find ( id ) ;
if ( p ! = _property_descriptors . end ( ) ) {
return p - > second ;
}
return Plugin : : get_property_descriptor ( id ) ;
}
2014-11-02 01:59:18 -05:00
static void
load_parameter_descriptor_units ( LilvWorld * lworld , ParameterDescriptor & desc , const LilvNodes * units )
{
if ( lilv_nodes_contains ( units , _world . units_midiNote ) ) {
desc . unit = ParameterDescriptor : : MIDI_NOTE ;
} else if ( lilv_nodes_contains ( units , _world . units_db ) ) {
desc . unit = ParameterDescriptor : : DB ;
2014-11-03 17:29:11 -05:00
} else if ( lilv_nodes_contains ( units , _world . units_hz ) ) {
desc . unit = ParameterDescriptor : : HZ ;
2014-11-03 20:52:14 -05:00
}
if ( lilv_nodes_size ( units ) > 0 ) {
2014-11-02 01:59:18 -05:00
const LilvNode * unit = lilv_nodes_get_first ( units ) ;
2014-11-03 11:54:35 -05:00
LilvNode * render = get_value ( lworld , unit , _world . units_render ) ;
2014-11-02 01:59:18 -05:00
if ( render ) {
desc . print_fmt = lilv_node_as_string ( render ) ;
2017-06-29 19:56:49 -04:00
/* override lilv's default "%f" format */
if ( desc . integer_step ) {
2017-07-01 12:31:55 -04:00
replace_all ( desc . print_fmt , " %f " , " %.0f " ) ;
2017-06-29 19:56:49 -04:00
} else if ( desc . upper - desc . lower > = 1000 ) {
replace_all ( desc . print_fmt , " %f " , " %.1f " ) ;
} else if ( desc . upper - desc . lower > = 100 ) {
replace_all ( desc . print_fmt , " %f " , " %.2f " ) ;
} else {
replace_all ( desc . print_fmt , " %f " , " %.3f " ) ;
}
2014-11-02 01:59:18 -05:00
lilv_node_free ( render ) ;
}
}
}
2014-11-01 23:29:10 -04:00
static void
2014-11-02 01:29:33 -05:00
load_parameter_descriptor ( LV2World & world ,
ParameterDescriptor & desc ,
Variant : : Type datatype ,
const LilvNode * subject )
2014-11-01 23:29:10 -04:00
{
LilvWorld * lworld = _world . world ;
2014-11-03 11:54:35 -05:00
LilvNode * label = get_value ( lworld , subject , _world . rdfs_label ) ;
LilvNode * def = get_value ( lworld , subject , _world . lv2_default ) ;
LilvNode * minimum = get_value ( lworld , subject , _world . lv2_minimum ) ;
LilvNode * maximum = get_value ( lworld , subject , _world . lv2_maximum ) ;
2014-11-02 01:59:18 -05:00
LilvNodes * units = lilv_world_find_nodes ( lworld , subject , _world . units_unit , NULL ) ;
2014-11-01 23:29:10 -04:00
if ( label ) {
desc . label = lilv_node_as_string ( label ) ;
}
2016-12-19 18:10:36 -05:00
if ( def ) {
if ( lilv_node_is_float ( def ) ) {
desc . normal = lilv_node_as_float ( def ) ;
} else if ( lilv_node_is_int ( def ) ) {
desc . normal = lilv_node_as_int ( def ) ;
}
2014-11-01 23:29:10 -04:00
}
2016-12-19 18:10:36 -05:00
if ( minimum ) {
if ( lilv_node_is_float ( minimum ) ) {
desc . lower = lilv_node_as_float ( minimum ) ;
} else if ( lilv_node_is_int ( minimum ) ) {
desc . lower = lilv_node_as_int ( minimum ) ;
}
2014-11-01 23:29:10 -04:00
}
2016-12-19 18:10:36 -05:00
if ( maximum ) {
if ( lilv_node_is_float ( maximum ) ) {
desc . upper = lilv_node_as_float ( maximum ) ;
} else if ( lilv_node_is_int ( maximum ) ) {
desc . upper = lilv_node_as_int ( maximum ) ;
}
2014-11-01 23:29:10 -04:00
}
2014-11-02 01:59:18 -05:00
load_parameter_descriptor_units ( lworld , desc , units ) ;
2014-11-01 23:29:10 -04:00
desc . datatype = datatype ;
desc . toggled | = datatype = = Variant : : BOOL ;
desc . integer_step | = datatype = = Variant : : INT | | datatype = = Variant : : LONG ;
2014-11-02 01:29:33 -05:00
desc . update_steps ( ) ;
2014-11-02 01:59:18 -05:00
lilv_nodes_free ( units ) ;
lilv_node_free ( label ) ;
lilv_node_free ( def ) ;
lilv_node_free ( minimum ) ;
lilv_node_free ( maximum ) ;
2014-11-01 23:29:10 -04:00
}
2014-10-31 20:44:02 -04:00
void
2014-11-01 23:29:10 -04:00
LV2Plugin : : load_supported_properties ( PropertyDescriptors & descs )
2014-10-31 20:44:02 -04:00
{
LilvWorld * lworld = _world . world ;
const LilvNode * subject = lilv_plugin_get_uri ( _impl - > plugin ) ;
LilvNodes * properties = lilv_world_find_nodes (
lworld , subject , _world . patch_writable , NULL ) ;
LILV_FOREACH ( nodes , p , properties ) {
// Get label and range
const LilvNode * prop = lilv_nodes_get ( properties , p ) ;
2014-11-03 11:54:35 -05:00
LilvNode * range = get_value ( lworld , prop , _world . rdfs_range ) ;
2014-11-01 23:29:10 -04:00
if ( ! range ) {
2020-01-21 16:18:37 -05:00
warning < < string_compose ( _ ( " LV2<%1>: property <%2> has no range datatype, ignoring " ) ,
name ( ) , lilv_node_as_uri ( prop ) ) < < endmsg ;
2014-11-01 23:29:10 -04:00
continue ;
}
2014-10-31 20:44:02 -04:00
// Convert range to variant type (TODO: support for multiple range types)
Variant : : Type datatype ;
if ( ! uri_to_variant_type ( lilv_node_as_uri ( range ) , datatype ) ) {
2020-01-21 16:18:37 -05:00
error < < string_compose ( _ ( " LV2<%1>: property <%2> has unsupported datatype <%3> " ) ,
name ( ) , lilv_node_as_uri ( prop ) , lilv_node_as_uri ( range ) ) < < endmsg ;
2014-10-31 20:44:02 -04:00
continue ;
}
// Add description to result
ParameterDescriptor desc ;
2014-11-01 23:29:10 -04:00
desc . key = _uri_map . uri_to_id ( lilv_node_as_uri ( prop ) ) ;
desc . datatype = datatype ;
2014-11-02 01:29:33 -05:00
load_parameter_descriptor ( _world , desc , datatype , prop ) ;
2014-11-01 23:29:10 -04:00
descs . insert ( std : : make_pair ( desc . key , desc ) ) ;
2020-06-23 14:21:09 -04:00
_property_values [ desc . key ] = Variant ( ) ;
2014-10-31 20:44:02 -04:00
lilv_node_free ( range ) ;
}
lilv_nodes_free ( properties ) ;
}
2018-11-22 08:58:44 -05:00
Variant
LV2Plugin : : get_property_value ( uint32_t prop_id ) const
{
std : : map < uint32_t , Variant > : : const_iterator it ;
if ( ( it = _property_values . find ( prop_id ) ) = = _property_values . end ( ) ) {
return Variant ( ) ;
}
return it - > second ;
}
2014-10-31 20:44:02 -04:00
void
LV2Plugin : : announce_property_values ( )
{
if ( _patch_port_in_index = = ( uint32_t ) - 1 ) {
return ;
}
// Set up forge to write to temporary buffer on the stack
LV2_Atom_Forge * forge = & _impl - > ui_forge ;
2019-04-08 12:32:09 -04:00
LV2_Atom_Forge_Frame frame ;
2014-10-31 20:44:02 -04:00
uint8_t buf [ PATH_MAX ] ; // Ought to be enough for anyone...
lv2_atom_forge_set_buffer ( forge , buf , sizeof ( buf ) ) ;
// Serialize patch:Get message with no subject (implicitly plugin instance)
2014-10-31 21:03:12 -04:00
# ifdef HAVE_LV2_1_10_0
2019-04-08 12:32:09 -04:00
lv2_atom_forge_object ( forge , & frame , 0 , _uri_map . urids . patch_Get ) ;
2014-10-31 21:03:12 -04:00
# else
2019-04-08 12:32:09 -04:00
lv2_atom_forge_blank ( forge , & frame , 0 , _uri_map . urids . patch_Get ) ;
2014-10-31 21:03:12 -04:00
# endif
2014-10-31 20:44:02 -04:00
// Write message to UI=>Plugin ring
const LV2_Atom * const atom = ( const LV2_Atom * ) buf ;
write_from_ui ( _patch_port_in_index ,
2014-11-01 23:29:10 -04:00
_uri_map . urids . atom_eventTransfer ,
2014-10-31 20:44:02 -04:00
lv2_atom_total_size ( atom ) ,
( const uint8_t * ) atom ) ;
}
2012-02-25 15:54:38 -05:00
void
2014-10-31 03:29:26 -04:00
LV2Plugin : : enable_ui_emission ( )
2012-02-25 03:43:23 -05:00
{
if ( ! _to_ui ) {
2013-08-11 09:10:41 -04:00
/* see note in LV2Plugin::write_from_ui() */
2013-12-12 08:40:45 -05:00
uint32_t bufsiz = 32768 ;
if ( _atom_ev_buffers & & _atom_ev_buffers [ 0 ] ) {
bufsiz = lv2_evbuf_get_capacity ( _atom_ev_buffers [ 0 ] ) ;
}
2013-08-11 09:10:41 -04:00
size_t rbs = _session . engine ( ) . raw_buffer_size ( DataType : : MIDI ) * NBUFS ;
2013-12-12 08:40:45 -05:00
rbs = max ( ( size_t ) bufsiz * 8 , rbs ) ;
2013-08-11 09:10:41 -04:00
_to_ui = new RingBuffer < uint8_t > ( rbs ) ;
2012-02-25 03:43:23 -05:00
}
}
void
LV2Plugin : : emit_to_ui ( void * controller , UIMessageSink sink )
{
if ( ! _to_ui ) {
return ;
}
uint32_t read_space = _to_ui - > read_space ( ) ;
while ( read_space > sizeof ( UIMessage ) ) {
UIMessage msg ;
if ( _to_ui - > read ( ( uint8_t * ) & msg , sizeof ( msg ) ) ! = sizeof ( msg ) ) {
2020-01-21 16:18:37 -05:00
error < < string_compose ( _ ( " LV2<%1>: Error reading message header from Plugin => UI RingBuffer " ) , name ( ) ) < < endmsg ;
2012-02-25 03:43:23 -05:00
break ;
}
2013-08-04 10:17:19 -04:00
vector < uint8_t > body ( msg . size ) ;
if ( _to_ui - > read ( & body [ 0 ] , msg . size ) ! = msg . size ) {
2020-01-21 16:18:37 -05:00
error < < string_compose ( _ ( " LV2<%1>: Error reading message body from Plugin => UI RingBuffer " ) , name ( ) ) < < endmsg ;
2012-02-25 03:43:23 -05:00
break ;
}
2013-08-04 10:17:19 -04:00
sink ( controller , msg . index , msg . size , msg . protocol , & body [ 0 ] ) ;
2012-02-25 03:43:23 -05:00
read_space - = sizeof ( msg ) + msg . size ;
}
}
2012-04-10 16:46:32 -04:00
int
2016-07-31 21:59:21 -04:00
LV2Plugin : : work ( Worker & worker , uint32_t size , const void * data )
2012-04-04 20:15:54 -04:00
{
2016-07-31 21:59:21 -04:00
Glib : : Threads : : Mutex : : Lock lm ( _work_mutex ) ;
2012-04-10 16:46:32 -04:00
return _impl - > work_iface - > work (
2016-07-31 21:59:21 -04:00
_impl - > instance - > lv2_handle , work_respond , & worker , size , data ) ;
2012-04-04 20:15:54 -04:00
}
2012-04-10 16:46:32 -04:00
int
2012-04-04 20:15:54 -04:00
LV2Plugin : : work_response ( uint32_t size , const void * data )
{
2012-04-10 16:46:32 -04:00
return _impl - > work_iface - > work_response (
_impl - > instance - > lv2_handle , size , data ) ;
2012-04-04 20:15:54 -04:00
}
2011-05-15 19:10:13 -04:00
void
2014-11-03 13:40:50 -05:00
LV2Plugin : : set_insert_id ( PBD : : ID id )
2011-05-15 19:10:13 -04:00
{
2015-12-10 13:31:00 -05:00
if ( _insert_id = = " 0 " ) {
_insert_id = id ;
} else if ( _insert_id ! = id ) {
lilv_state_free ( _impl - > state ) ;
_impl - > state = NULL ;
_insert_id = id ;
}
2011-05-15 19:10:13 -04:00
}
2015-12-18 08:27:15 -05:00
void
LV2Plugin : : set_state_dir ( const std : : string & d )
{
_plugin_state_dir = d ;
}
2011-05-15 19:10:13 -04:00
int
LV2Plugin : : set_state ( const XMLNode & node , int version )
{
XMLNodeList nodes ;
XMLNodeConstIterator iter ;
XMLNode * child ;
2016-05-07 09:38:17 -04:00
LocaleGuard lg ;
2011-05-15 19:10:13 -04:00
if ( node . name ( ) ! = state_node_name ( ) ) {
2020-01-21 16:18:37 -05:00
error < < string_compose ( _ ( " LV2<%1>: Bad node sent to LV2Plugin::set_state " ) , name ( ) ) < < endmsg ;
2011-05-15 19:10:13 -04:00
return - 1 ;
}
if ( version < 3000 ) {
nodes = node . children ( " port " ) ;
} else {
nodes = node . children ( " Port " ) ;
}
for ( iter = nodes . begin ( ) ; iter ! = nodes . end ( ) ; + + iter ) {
child = * iter ;
2016-08-25 01:55:51 -04:00
std : : string sym ;
if ( ! child - > get_property ( " symbol " , sym ) ) {
2020-01-21 16:18:37 -05:00
warning < < string_compose ( _ ( " LV2<%1>: port has no symbol '%2', ignored " ) , name ( ) , sym ) < < endmsg ;
2011-05-15 19:10:13 -04:00
continue ;
}
map < string , uint32_t > : : iterator i = _port_indices . find ( sym ) ;
2016-08-25 01:55:51 -04:00
uint32_t port_id ;
2011-05-15 19:10:13 -04:00
if ( i ! = _port_indices . end ( ) ) {
port_id = i - > second ;
} else {
2020-01-21 16:18:37 -05:00
warning < < string_compose ( _ ( " LV2<%1>: port '%2' has known index, ignored " ) , name ( ) , sym ) < < endmsg ;
2011-05-15 19:10:13 -04:00
continue ;
}
2016-08-25 01:55:51 -04:00
float val ;
if ( ! child - > get_property ( " value " , val ) ) {
2020-01-21 16:18:37 -05:00
warning < < string_compose ( _ ( " LV2<%1>: port no value, ignored " ) , name ( ) , sym ) < < endmsg ;
2011-05-15 19:10:13 -04:00
continue ;
}
2020-08-07 16:02:56 -04:00
set_parameter ( port_id , val , 0 ) ;
2011-05-15 19:10:13 -04:00
}
2016-08-25 01:55:51 -04:00
std : : string template_dir ;
if ( node . get_property ( " template-dir " , template_dir ) ) {
set_state_dir ( template_dir ) ;
2015-12-18 08:27:15 -05:00
}
2012-01-27 20:45:15 -05:00
_state_version = 0 ;
2016-08-25 01:55:51 -04:00
std : : string state_dir ;
if ( node . get_property ( " state-dir " , state_dir ) ! = 0 ) {
if ( sscanf ( state_dir . c_str ( ) , " state%u " , & _state_version ) ! = 1 ) {
2012-01-27 20:45:15 -05:00
error < < string_compose (
" LV2: failed to parse state version from \" %1 \" " ,
2016-08-25 01:55:51 -04:00
state_dir ) < < endmsg ;
2011-05-15 19:10:13 -04:00
}
2012-01-27 20:45:15 -05:00
2012-01-28 13:19:19 -05:00
std : : string state_file = Glib : : build_filename (
plugin_dir ( ) ,
2016-08-25 01:55:51 -04:00
Glib : : build_filename ( state_dir , " state.ttl " ) ) ;
2012-01-27 20:45:15 -05:00
2015-07-28 12:58:17 -04:00
LilvState * state = lilv_state_new_from_file (
_world . world , _uri_map . urid_map ( ) , NULL , state_file . c_str ( ) ) ;
2015-07-27 11:11:35 -04:00
2015-07-28 12:58:17 -04:00
lilv_state_restore ( state , _impl - > instance , NULL , NULL , 0 , NULL ) ;
2015-09-27 08:07:04 -04:00
lilv_state_free ( _impl - > state ) ;
_impl - > state = state ;
2011-05-15 19:10:13 -04:00
}
2015-12-18 08:27:15 -05:00
if ( ! _plugin_state_dir . empty ( ) ) {
// force save with session, next time (increment counter)
lilv_state_free ( _impl - > state ) ;
_impl - > state = NULL ;
set_state_dir ( " " ) ;
}
2019-03-22 09:09:03 -04:00
/* Do not call latency_compute_run() concurrently with connect_and_run().
* So far this can only guarnteed when the session is loading ,
* and the plugin has not been added to the processor chain .
*
* Ideally this would clso be called when copying a plugin from another track ,
* but NOT when copying the state from a plugin to another ( active ) plugin
* instance .
*/
if ( _session . loading ( ) ) {
latency_compute_run ( ) ;
}
2011-05-15 19:10:13 -04:00
return Plugin : : set_state ( node , version ) ;
}
int
LV2Plugin : : get_parameter_descriptor ( uint32_t which , ParameterDescriptor & desc ) const
{
const LilvPort * port = lilv_plugin_get_port_by_index ( _impl - > plugin , which ) ;
2014-11-01 23:29:10 -04:00
if ( ! port ) {
2020-01-21 16:18:37 -05:00
error < < string_compose ( " LV2<%1>: get descriptor of non-existent port %2 " , name ( ) , which )
2014-11-01 23:29:10 -04:00
< < endmsg ;
return 1 ;
}
2011-05-15 19:10:13 -04:00
2013-10-22 11:26:30 -04:00
LilvNodes * portunits ;
2011-05-15 19:10:13 -04:00
LilvNode * def , * min , * max ;
lilv_port_get_range ( _impl - > plugin , port , & def , & min , & max ) ;
2013-10-22 11:26:30 -04:00
portunits = lilv_port_get_value ( _impl - > plugin , port , _world . units_unit ) ;
2011-05-15 19:10:13 -04:00
2020-11-20 00:03:49 -05:00
LilvNode * steps = lilv_port_get ( _impl - > plugin , port , _world . ext_rangeSteps ) ;
LilvNode * display_priority = lilv_port_get ( _impl - > plugin , port , _world . ext_displayPriority ) ;
2016-07-05 10:21:09 -04:00
2014-11-02 01:29:33 -05:00
// TODO: Once we can rely on lilv 0.18.0 being present,
// load_parameter_descriptor() can be used for ports as well
2012-02-25 00:01:24 -05:00
desc . integer_step = lilv_port_has_property ( _impl - > plugin , port , _world . lv2_integer ) ;
desc . toggled = lilv_port_has_property ( _impl - > plugin , port , _world . lv2_toggled ) ;
desc . logarithmic = lilv_port_has_property ( _impl - > plugin , port , _world . ext_logarithmic ) ;
desc . sr_dependent = lilv_port_has_property ( _impl - > plugin , port , _world . lv2_sampleRate ) ;
2011-05-15 19:10:13 -04:00
desc . label = lilv_node_as_string ( lilv_port_get_name ( _impl - > plugin , port ) ) ;
2014-11-29 16:24:24 -05:00
desc . normal = def ? lilv_node_as_float ( def ) : 0.0f ;
2011-05-15 19:10:13 -04:00
desc . lower = min ? lilv_node_as_float ( min ) : 0.0f ;
desc . upper = max ? lilv_node_as_float ( max ) : 1.0f ;
2014-11-02 01:59:18 -05:00
load_parameter_descriptor_units ( _world . world , desc , portunits ) ;
2013-10-22 11:26:30 -04:00
2020-11-20 00:03:49 -05:00
2011-07-12 16:30:02 -04:00
if ( desc . sr_dependent ) {
2017-09-18 12:39:17 -04:00
desc . lower * = _session . sample_rate ( ) ;
desc . upper * = _session . sample_rate ( ) ;
2011-07-12 16:30:02 -04:00
}
2012-01-27 20:45:15 -05:00
2012-03-21 12:43:01 -04:00
desc . enumeration = lilv_port_has_property ( _impl - > plugin , port , _world . lv2_enumeration ) ;
2014-10-31 22:20:24 -04:00
desc . scale_points = get_scale_points ( which ) ;
2012-03-21 12:43:01 -04:00
2019-12-14 09:00:34 -05:00
# ifdef LV2_EXTENDED
desc . inline_ctrl = lilv_port_has_property ( _impl - > plugin , port , _world . inline_mixer_control ) ;
# endif
2016-07-05 10:21:09 -04:00
if ( steps ) {
2017-06-21 08:41:40 -04:00
desc . rangesteps = lilv_node_as_float ( steps ) ;
2016-07-05 10:21:09 -04:00
}
2020-11-20 00:03:49 -05:00
if ( display_priority ) {
desc . display_priority = lilv_node_as_int ( display_priority ) ;
}
2016-07-05 10:21:09 -04:00
2017-06-21 08:41:40 -04:00
desc . update_steps ( ) ;
2016-07-05 10:21:09 -04:00
2011-05-15 19:10:13 -04:00
lilv_node_free ( def ) ;
lilv_node_free ( min ) ;
lilv_node_free ( max ) ;
2016-07-05 10:21:09 -04:00
lilv_node_free ( steps ) ;
2020-11-20 00:03:49 -05:00
lilv_node_free ( display_priority ) ;
2013-10-22 11:26:30 -04:00
lilv_nodes_free ( portunits ) ;
2011-05-15 19:10:13 -04:00
return 0 ;
}
2016-04-03 12:28:59 -04:00
Plugin : : IOPortDescription
2016-04-15 11:57:40 -04:00
LV2Plugin : : describe_io_port ( ARDOUR : : DataType dt , bool input , uint32_t id ) const
2016-04-03 12:28:59 -04:00
{
PortFlags match = 0 ;
switch ( dt ) {
case DataType : : AUDIO :
match = PORT_AUDIO ;
break ;
case DataType : : MIDI :
2020-07-08 15:19:30 -04:00
match = PORT_SEQUENCE | PORT_MIDI ;
2016-04-03 12:28:59 -04:00
break ;
default :
return Plugin : : IOPortDescription ( " ? " ) ;
break ;
}
if ( input ) {
match | = PORT_INPUT ;
} else {
match | = PORT_OUTPUT ;
}
uint32_t p = 0 ;
uint32_t idx = UINT32_MAX ;
uint32_t const num_ports = parameter_count ( ) ;
for ( uint32_t port_index = 0 ; port_index < num_ports ; + + port_index ) {
PortFlags flags = _port_flags [ port_index ] ;
if ( ( flags & match ) = = match ) {
if ( p = = id ) {
idx = port_index ;
}
+ + p ;
}
}
if ( idx = = UINT32_MAX ) {
return Plugin : : IOPortDescription ( " ? " ) ;
}
2016-11-09 18:09:38 -05:00
const LilvPort * pport = lilv_plugin_get_port_by_index ( _impl - > plugin , idx ) ;
LilvNode * name = lilv_port_get_name ( _impl - > plugin , pport ) ;
2016-04-03 12:28:59 -04:00
Plugin : : IOPortDescription iod ( lilv_node_as_string ( name ) ) ;
lilv_node_free ( name ) ;
2016-11-09 19:45:00 -05:00
/* get the port's pg:group */
2016-11-09 18:09:38 -05:00
LilvNodes * groups = lilv_port_get_value ( _impl - > plugin , pport , _world . groups_group ) ;
if ( lilv_nodes_size ( groups ) > 0 ) {
const LilvNode * group = lilv_nodes_get_first ( groups ) ;
LilvNodes * grouplabel = lilv_world_find_nodes ( _world . world , group , _world . rdfs_label , NULL ) ;
2016-11-09 19:45:00 -05:00
/* get the name of the port-group */
2016-11-09 18:09:38 -05:00
if ( lilv_nodes_size ( grouplabel ) > 0 ) {
const LilvNode * grpname = lilv_nodes_get_first ( grouplabel ) ;
iod . group_name = lilv_node_as_string ( grpname ) ;
}
lilv_nodes_free ( grouplabel ) ;
2016-11-09 19:45:00 -05:00
/* get all port designations.
* we ' re interested in e . g . lv2 : designation pg : right */
2016-11-09 18:09:38 -05:00
LilvNodes * designations = lilv_port_get_value ( _impl - > plugin , pport , _world . lv2_designation ) ;
2016-11-09 19:45:00 -05:00
if ( lilv_nodes_size ( designations ) > 0 ) {
/* get all pg:elements of the pg:group */
2016-11-09 18:09:38 -05:00
LilvNodes * group_childs = lilv_world_find_nodes ( _world . world , group , _world . groups_element , NULL ) ;
if ( lilv_nodes_size ( group_childs ) > 0 ) {
2016-11-09 19:45:00 -05:00
/* iterate over all port designations .. */
2016-11-09 18:09:38 -05:00
LILV_FOREACH ( nodes , i , designations ) {
const LilvNode * designation = lilv_nodes_get ( designations , i ) ;
2016-11-09 19:45:00 -05:00
/* match the lv2:designation's element against the port-group's element */
2016-11-09 18:09:38 -05:00
LILV_FOREACH ( nodes , j , group_childs ) {
const LilvNode * group_element = lilv_nodes_get ( group_childs , j ) ;
LilvNodes * elem = lilv_world_find_nodes ( _world . world , group_element , _world . lv2_designation , designation ) ;
2016-11-09 19:45:00 -05:00
/* found it. Now look up the index (channel-number) of the pg:Element */
2016-11-09 18:09:38 -05:00
if ( lilv_nodes_size ( elem ) > 0 ) {
LilvNodes * idx = lilv_world_find_nodes ( _world . world , lilv_nodes_get_first ( elem ) , _world . lv2_index , NULL ) ;
if ( lilv_node_is_int ( lilv_nodes_get_first ( idx ) ) ) {
iod . group_channel = lilv_node_as_int ( lilv_nodes_get_first ( idx ) ) ;
}
}
}
}
}
}
lilv_nodes_free ( groups ) ;
lilv_nodes_free ( designations ) ;
}
if ( lilv_port_has_property ( _impl - > plugin , pport , _world . lv2_isSideChain ) ) {
2016-04-03 12:28:59 -04:00
iod . is_sidechain = true ;
}
return iod ;
}
2011-05-15 19:10:13 -04:00
string
LV2Plugin : : describe_parameter ( Evoral : : Parameter which )
{
if ( ( which . type ( ) = = PluginAutomation ) & & ( which . id ( ) < parameter_count ( ) ) ) {
2013-05-25 03:06:06 -04:00
2018-06-09 08:40:46 -04:00
const LilvPort * port = lilv_plugin_get_port_by_index ( _impl - > plugin , which . id ( ) ) ;
if ( lilv_port_has_property ( _impl - > plugin , port , _world . ext_notOnGUI ) ) {
return X_ ( " hidden " ) ;
}
const LilvPort * fwport = lilv_plugin_get_port_by_designation ( _impl - > plugin , _world . lv2_InputPort , _world . lv2_freewheeling ) ;
if ( fwport & & fwport = = port ) {
2013-05-25 03:06:06 -04:00
return X_ ( " hidden " ) ;
}
2013-06-14 11:33:29 -04:00
2019-05-08 15:59:22 -04:00
const LilvPort * bpmport = lilv_plugin_get_port_by_designation ( _impl - > plugin , _world . lv2_InputPort , _world . time_beatsPerMin ) ;
if ( bpmport & & bpmport = = port ) {
return X_ ( " hidden " ) ;
}
2018-06-09 08:40:46 -04:00
if ( lilv_port_has_property ( _impl - > plugin , port , _world . lv2_freewheeling ) ) {
2013-06-14 11:33:29 -04:00
return X_ ( " hidden " ) ;
}
2018-06-09 08:40:46 -04:00
if ( lilv_port_has_property ( _impl - > plugin , port , _world . lv2_reportsLatency ) ) {
2013-05-25 03:06:06 -04:00
return X_ ( " latency " ) ;
}
2011-05-15 19:10:13 -04:00
LilvNode * name = lilv_port_get_name ( _impl - > plugin ,
lilv_plugin_get_port_by_index ( _impl - > plugin , which . id ( ) ) ) ;
string ret ( lilv_node_as_string ( name ) ) ;
lilv_node_free ( name ) ;
return ret ;
} else {
return " ?? " ;
}
}
2017-09-18 12:39:17 -04:00
samplecnt_t
2016-04-08 12:16:01 -04:00
LV2Plugin : : max_latency ( ) const
{
return _max_latency ;
}
2017-09-18 12:39:17 -04:00
samplecnt_t
2019-02-16 19:51:29 -05:00
LV2Plugin : : plugin_latency ( ) const
2011-05-15 19:10:13 -04:00
{
if ( _latency_control_port ) {
2017-09-18 12:39:17 -04:00
return ( samplecnt_t ) floor ( * _latency_control_port ) ;
2011-05-15 19:10:13 -04:00
} else {
return 0 ;
}
}
set < Evoral : : Parameter >
LV2Plugin : : automatable ( ) const
{
set < Evoral : : Parameter > ret ;
for ( uint32_t i = 0 ; i < parameter_count ( ) ; + + i ) {
2016-06-05 13:04:33 -04:00
if ( parameter_is_input ( i ) & & parameter_is_control ( i ) & & ! ( _port_flags [ i ] & PORT_NOAUTO ) ) {
2011-05-15 19:10:13 -04:00
ret . insert ( ret . end ( ) , Evoral : : Parameter ( PluginAutomation , 0 , i ) ) ;
}
}
2014-11-01 23:29:10 -04:00
for ( PropertyDescriptors : : const_iterator p = _property_descriptors . begin ( ) ;
p ! = _property_descriptors . end ( ) ;
+ + p ) {
ret . insert ( ret . end ( ) , Evoral : : Parameter ( PluginPropertyAutomation , 0 , p - > first ) ) ;
}
2011-05-15 19:10:13 -04:00
return ret ;
}
2016-03-13 18:20:45 -04:00
void
LV2Plugin : : set_automation_control ( uint32_t i , boost : : shared_ptr < AutomationControl > c )
{
2016-06-05 08:44:54 -04:00
if ( ( _port_flags [ i ] & ( PORT_CTRLED | PORT_CTRLER ) ) ) {
DEBUG_TRACE ( DEBUG : : LV2Automate , string_compose ( " Ctrl Port %1 \n " , i ) ) ;
2016-03-13 18:20:45 -04:00
_ctrl_map [ i ] = AutomationCtrlPtr ( new AutomationCtrl ( c ) ) ;
}
2019-05-08 16:01:07 -04:00
else if ( i = = _bpm_control_port_index ) {
_ctrl_map [ i ] = AutomationCtrlPtr ( new AutomationCtrl ( c ) ) ;
}
2016-03-13 18:20:45 -04:00
}
LV2Plugin : : AutomationCtrlPtr
LV2Plugin : : get_automation_control ( uint32_t i )
{
if ( _ctrl_map . find ( i ) = = _ctrl_map . end ( ) ) {
return AutomationCtrlPtr ( ) ;
}
return _ctrl_map [ i ] ;
}
2011-05-15 19:10:13 -04:00
void
LV2Plugin : : activate ( )
{
DEBUG_TRACE ( DEBUG : : LV2 , string_compose ( " %1 activate \n " , name ( ) ) ) ;
if ( ! _was_activated ) {
lilv_instance_activate ( _impl - > instance ) ;
_was_activated = true ;
}
}
void
LV2Plugin : : deactivate ( )
{
DEBUG_TRACE ( DEBUG : : LV2 , string_compose ( " %1 deactivate \n " , name ( ) ) ) ;
if ( _was_activated ) {
lilv_instance_deactivate ( _impl - > instance ) ;
_was_activated = false ;
}
}
void
LV2Plugin : : cleanup ( )
{
DEBUG_TRACE ( DEBUG : : LV2 , string_compose ( " %1 cleanup \n " , name ( ) ) ) ;
deactivate ( ) ;
lilv_instance_free ( _impl - > instance ) ;
_impl - > instance = NULL ;
}
2012-08-28 11:42:40 -04:00
void
2012-09-08 14:18:47 -04:00
LV2Plugin : : allocate_atom_event_buffers ( )
{
2012-08-28 11:42:38 -04:00
/* reserve local scratch buffers for ATOM event-queues */
const LilvPlugin * p = _impl - > plugin ;
/* count non-MIDI atom event-ports
* TODO : nicely ask drobilla to make a lilv_ call for that
*/
int count_atom_out = 0 ;
int count_atom_in = 0 ;
2013-06-02 18:48:17 -04:00
int minimumSize = 32768 ; // TODO use a per-port minimum-size
2012-08-28 11:42:38 -04:00
for ( uint32_t i = 0 ; i < lilv_plugin_get_num_ports ( p ) ; + + i ) {
const LilvPort * port = lilv_plugin_get_port_by_index ( p , i ) ;
if ( lilv_port_is_a ( p , port , _world . atom_AtomPort ) ) {
LilvNodes * buffer_types = lilv_port_get_value (
p , port , _world . atom_bufferType ) ;
LilvNodes * atom_supports = lilv_port_get_value (
p , port , _world . atom_supports ) ;
2016-04-27 08:45:40 -04:00
if ( lilv_nodes_contains ( buffer_types , _world . atom_Sequence ) ) {
2012-08-28 11:42:38 -04:00
if ( lilv_port_is_a ( p , port , _world . lv2_InputPort ) ) {
count_atom_in + + ;
}
if ( lilv_port_is_a ( p , port , _world . lv2_OutputPort ) ) {
count_atom_out + + ;
}
2013-06-03 13:34:14 -04:00
LilvNodes * min_size_v = lilv_port_get_value ( _impl - > plugin , port , _world . rsz_minimumSize ) ;
LilvNode * min_size = min_size_v ? lilv_nodes_get_first ( min_size_v ) : NULL ;
2013-06-02 18:48:17 -04:00
if ( min_size & & lilv_node_is_int ( min_size ) ) {
minimumSize = std : : max ( minimumSize , lilv_node_as_int ( min_size ) ) ;
}
2013-06-03 13:34:14 -04:00
lilv_nodes_free ( min_size_v ) ;
2012-08-28 11:42:38 -04:00
}
lilv_nodes_free ( buffer_types ) ;
lilv_nodes_free ( atom_supports ) ;
}
}
DEBUG_TRACE ( DEBUG : : LV2 , string_compose ( " %1 need buffers for %2 atom-in and %3 atom-out event-ports \n " ,
name ( ) , count_atom_in , count_atom_out ) ) ;
const int total_atom_buffers = ( count_atom_in + count_atom_out ) ;
if ( _atom_ev_buffers | | total_atom_buffers = = 0 ) {
2012-08-28 11:42:40 -04:00
return ;
2012-08-28 11:42:38 -04:00
}
2016-04-27 08:45:40 -04:00
DEBUG_TRACE ( DEBUG : : LV2 , string_compose ( " allocate %1 atom_ev_buffers of %2 bytes \n " , total_atom_buffers , minimumSize ) ) ;
2012-08-28 11:42:38 -04:00
_atom_ev_buffers = ( LV2_Evbuf * * ) malloc ( ( total_atom_buffers + 1 ) * sizeof ( LV2_Evbuf * ) ) ;
for ( int i = 0 ; i < total_atom_buffers ; + + i ) {
2020-07-08 15:19:30 -04:00
_atom_ev_buffers [ i ] = lv2_evbuf_new ( minimumSize ,
_uri_map . urids . atom_Chunk ,
_uri_map . urids . atom_Sequence ) ;
2012-08-28 11:42:38 -04:00
}
_atom_ev_buffers [ total_atom_buffers ] = 0 ;
2012-08-28 11:42:40 -04:00
return ;
2012-08-28 11:42:38 -04:00
}
2012-11-17 13:41:19 -05:00
/** Write an ardour position/time/tempo/meter as an LV2 event.
* @ return true on success .
*/
static bool
write_position ( LV2_Atom_Forge * forge ,
LV2_Evbuf * buf ,
const TempoMetric & t ,
Timecode : : BBT_Time & bbt ,
double speed ,
2019-11-14 15:15:30 -05:00
double time_scale ,
2016-08-17 11:02:56 -04:00
double bpm ,
2019-04-08 12:29:04 -04:00
samplepos_t position ,
samplecnt_t offset )
2012-11-17 13:41:19 -05:00
{
2014-11-01 23:29:10 -04:00
const URIMap : : URIDs & urids = URIMap : : instance ( ) . urids ;
2012-11-17 13:41:19 -05:00
uint8_t pos_buf [ 256 ] ;
lv2_atom_forge_set_buffer ( forge , pos_buf , sizeof ( pos_buf ) ) ;
2019-04-08 12:32:09 -04:00
LV2_Atom_Forge_Frame frame ;
2014-10-31 20:44:02 -04:00
# ifdef HAVE_LV2_1_10_0
2019-04-08 12:32:09 -04:00
lv2_atom_forge_object ( forge , & frame , 0 , urids . time_Position ) ;
2019-04-07 21:46:02 -04:00
lv2_atom_forge_key ( forge , urids . time_frame ) ;
2014-10-31 20:44:02 -04:00
lv2_atom_forge_long ( forge , position ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_key ( forge , urids . time_speed ) ;
2014-10-31 20:44:02 -04:00
lv2_atom_forge_float ( forge , speed ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_key ( forge , urids . time_barBeat ) ;
2014-10-31 20:44:02 -04:00
lv2_atom_forge_float ( forge , bbt . beats - 1 +
( bbt . ticks / Timecode : : BBT_Time : : ticks_per_beat ) ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_key ( forge , urids . time_bar ) ;
2014-10-31 20:44:02 -04:00
lv2_atom_forge_long ( forge , bbt . bars - 1 ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_key ( forge , urids . time_beatUnit ) ;
2014-10-31 20:44:02 -04:00
lv2_atom_forge_int ( forge , t . meter ( ) . note_divisor ( ) ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_key ( forge , urids . time_beatsPerBar ) ;
2014-10-31 20:44:02 -04:00
lv2_atom_forge_float ( forge , t . meter ( ) . divisions_per_bar ( ) ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_key ( forge , urids . time_beatsPerMinute ) ;
2016-08-17 11:02:56 -04:00
lv2_atom_forge_float ( forge , bpm ) ;
2019-11-14 15:15:30 -05:00
lv2_atom_forge_key ( forge , urids . time_scale ) ;
lv2_atom_forge_float ( forge , time_scale ) ;
2014-10-31 20:44:02 -04:00
# else
2019-04-08 12:32:09 -04:00
lv2_atom_forge_blank ( forge , & frame , 1 , urids . time_Position ) ;
2019-04-07 21:46:02 -04:00
lv2_atom_forge_property_head ( forge , urids . time_frame , 0 ) ;
2012-11-17 13:41:19 -05:00
lv2_atom_forge_long ( forge , position ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_property_head ( forge , urids . time_speed , 0 ) ;
2012-11-17 13:41:19 -05:00
lv2_atom_forge_float ( forge , speed ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_property_head ( forge , urids . time_barBeat , 0 ) ;
2012-11-17 13:41:19 -05:00
lv2_atom_forge_float ( forge , bbt . beats - 1 +
( bbt . ticks / Timecode : : BBT_Time : : ticks_per_beat ) ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_property_head ( forge , urids . time_bar , 0 ) ;
2013-01-05 16:09:41 -05:00
lv2_atom_forge_long ( forge , bbt . bars - 1 ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_property_head ( forge , urids . time_beatUnit , 0 ) ;
2013-01-05 16:09:41 -05:00
lv2_atom_forge_int ( forge , t . meter ( ) . note_divisor ( ) ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_property_head ( forge , urids . time_beatsPerBar , 0 ) ;
2012-11-17 13:41:19 -05:00
lv2_atom_forge_float ( forge , t . meter ( ) . divisions_per_bar ( ) ) ;
2014-11-01 23:29:10 -04:00
lv2_atom_forge_property_head ( forge , urids . time_beatsPerMinute , 0 ) ;
2016-08-17 11:02:56 -04:00
lv2_atom_forge_float ( forge , bpm ) ;
2019-11-14 15:15:30 -05:00
lv2_atom_forge_key ( forge , urids . time_scale ) ;
lv2_atom_forge_float ( forge , time_scale ) ;
2014-10-31 20:44:02 -04:00
# endif
2012-11-17 13:41:19 -05:00
LV2_Evbuf_Iterator end = lv2_evbuf_end ( buf ) ;
const LV2_Atom * const atom = ( const LV2_Atom * ) pos_buf ;
return lv2_evbuf_write ( & end , offset , 0 , atom - > type , atom - > size ,
( const uint8_t * ) ( atom + 1 ) ) ;
}
2011-05-15 19:10:13 -04:00
int
LV2Plugin : : connect_and_run ( BufferSet & bufs ,
2017-09-18 12:39:17 -04:00
samplepos_t start , samplepos_t end , double speed ,
2018-11-03 21:15:28 -04:00
ChanMapping const & in_map , ChanMapping const & out_map ,
2017-09-18 12:39:17 -04:00
pframes_t nframes , samplecnt_t offset )
2011-05-15 19:10:13 -04:00
{
DEBUG_TRACE ( DEBUG : : LV2 , string_compose ( " %1 run %2 offset %3 \n " , name ( ) , nframes , offset ) ) ;
2016-06-24 20:23:56 -04:00
Plugin : : connect_and_run ( bufs , start , end , speed , in_map , out_map , nframes , offset ) ;
2011-05-15 19:10:13 -04:00
cycles_t then = get_cycles ( ) ;
2020-09-06 10:00:20 -04:00
/* remain at zero during pre-roll at zero */
speed = end > 0 ? speed : 0 ;
samplepos_t start0 = std : : max ( samplepos_t ( 0 ) , start ) ;
2012-11-17 13:41:19 -05:00
TempoMap & tmap = _session . tempo_map ( ) ;
Metrics : : const_iterator metric_i = tmap . metrics_end ( ) ;
2020-09-06 10:00:20 -04:00
TempoMetric tmetric = tmap . metric_at ( start0 , & metric_i ) ;
2012-11-17 13:41:19 -05:00
2012-04-10 16:46:32 -04:00
if ( _freewheel_control_port ) {
2015-07-27 13:08:29 -04:00
* _freewheel_control_port = _session . engine ( ) . freewheeling ( ) ? 1.f : 0.f ;
2012-04-10 16:46:32 -04:00
}
if ( _bpm_control_port ) {
2020-09-06 10:00:20 -04:00
float bpm = tmap . tempo_at_sample ( start0 ) . note_types_per_minute ( ) ;
2019-05-08 16:01:07 -04:00
if ( * _bpm_control_port ! = bpm ) {
AutomationCtrlPtr c = get_automation_control ( _bpm_control_port_index ) ;
if ( c & & c - > ac ) {
/* may be NULL for replicated instances - only one custom UI/ctrl */
c - > ac - > Changed ( false , Controllable : : NoGroup ) ; /* EMIT SIGNAL */
}
}
* _bpm_control_port = bpm ;
2012-04-10 16:46:32 -04:00
}
2016-03-13 18:20:45 -04:00
# ifdef LV2_EXTENDED
2016-06-24 20:23:56 -04:00
if ( _can_write_automation & & start ! = _next_cycle_start ) {
2016-03-13 18:20:45 -04:00
// add guard-points after locating
for ( AutomationCtrlMap : : iterator i = _ctrl_map . begin ( ) ; i ! = _ctrl_map . end ( ) ; + + i ) {
i - > second - > guard = true ;
}
}
# endif
2011-10-21 00:51:04 -04:00
ChanCount bufs_count ;
bufs_count . set ( DataType : : AUDIO , 1 ) ;
bufs_count . set ( DataType : : MIDI , 1 ) ;
BufferSet & silent_bufs = _session . get_silent_buffers ( bufs_count ) ;
2012-08-27 00:08:45 -04:00
BufferSet & scratch_bufs = _session . get_scratch_buffers ( bufs_count ) ;
2012-01-23 13:17:09 -05:00
uint32_t const num_ports = parameter_count ( ) ;
2012-11-17 23:35:31 -05:00
uint32_t const nil_index = std : : numeric_limits < uint32_t > : : max ( ) ;
2011-10-21 00:51:04 -04:00
2011-05-15 19:10:13 -04:00
uint32_t audio_in_index = 0 ;
uint32_t audio_out_index = 0 ;
uint32_t midi_in_index = 0 ;
uint32_t midi_out_index = 0 ;
2012-08-28 11:42:38 -04:00
uint32_t atom_port_index = 0 ;
2012-01-23 13:17:09 -05:00
for ( uint32_t port_index = 0 ; port_index < num_ports ; + + port_index ) {
2012-02-24 23:16:42 -05:00
void * buf = NULL ;
2012-11-17 23:35:31 -05:00
uint32_t index = nil_index ;
2012-02-24 23:16:42 -05:00
PortFlags flags = _port_flags [ port_index ] ;
2012-11-17 23:35:31 -05:00
bool valid = false ;
2012-02-24 23:16:42 -05:00
if ( flags & PORT_AUDIO ) {
if ( flags & PORT_INPUT ) {
2012-02-24 17:09:30 -05:00
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 ) ;
2012-02-24 23:16:42 -05:00
} else {
2012-02-24 17:09:30 -05:00
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 ) ;
2011-05-15 19:10:13 -04:00
}
2020-07-08 15:19:30 -04:00
} else if ( flags & PORT_SEQUENCE ) {
2012-02-24 17:09:30 -05:00
/* FIXME: The checks here for bufs.count().n_midi() > index shouldn't
2011-10-21 00:51:04 -04:00
be necessary , but the mapping is illegal in some cases . Ideally
that should be fixed , but this is easier . . .
*/
2012-11-17 23:35:31 -05:00
if ( flags & PORT_MIDI ) {
if ( flags & PORT_INPUT ) {
index = in_map . get ( DataType : : MIDI , midi_in_index + + , & valid ) ;
} else {
index = out_map . get ( DataType : : MIDI , midi_out_index + + , & valid ) ;
}
if ( valid & & bufs . count ( ) . n_midi ( ) > index ) {
2013-06-02 18:48:17 -04:00
/* Note, ensure_lv2_bufsize() is not RT safe!
* However free ( ) / alloc ( ) is only called if a
* plugin requires a rsz : minimumSize buffersize
* and the existing buffer if smaller .
*/
bufs . ensure_lv2_bufsize ( ( flags & PORT_INPUT ) , index , _port_minimumSize [ port_index ] ) ;
2012-11-17 23:35:31 -05:00
_ev_buffers [ port_index ] = bufs . get_lv2_midi (
2020-07-08 15:19:30 -04:00
( flags & PORT_INPUT ) , index ) ;
2012-11-17 23:35:31 -05:00
}
} else if ( ( flags & PORT_POSITION ) & & ( flags & PORT_INPUT ) ) {
2012-08-28 11:42:38 -04:00
lv2_evbuf_reset ( _atom_ev_buffers [ atom_port_index ] , true ) ;
_ev_buffers [ port_index ] = _atom_ev_buffers [ atom_port_index + + ] ;
2012-11-17 23:35:31 -05:00
valid = true ;
}
2012-11-17 13:41:19 -05:00
2012-11-17 23:35:31 -05:00
if ( valid & & ( flags & PORT_INPUT ) ) {
if ( ( flags & PORT_POSITION ) ) {
2020-09-06 10:00:20 -04:00
Timecode : : BBT_Time bbt ( tmap . bbt_at_sample ( start0 ) ) ;
2019-11-14 15:15:30 -05:00
double time_scale = Port : : speed_ratio ( ) ;
2020-09-06 10:00:20 -04:00
double bpm = tmap . tempo_at_sample ( start0 ) . note_types_per_minute ( ) ;
2016-08-16 07:11:49 -04:00
double beatpos = ( bbt . bars - 1 ) * tmetric . meter ( ) . divisions_per_bar ( )
+ ( bbt . beats - 1 )
+ ( bbt . ticks / Timecode : : BBT_Time : : ticks_per_beat ) ;
beatpos * = tmetric . meter ( ) . note_divisor ( ) / 4.0 ;
2016-06-24 20:23:56 -04:00
if ( start ! = _next_cycle_start | |
2016-08-16 07:11:49 -04:00
speed ! = _next_cycle_speed | |
2019-11-14 15:15:30 -05:00
time_scale ! = _prev_time_scale | |
2019-11-14 15:37:14 -05:00
rint ( 100 * beatpos ) ! = rint ( 100 * _next_cycle_beat ) | |
2016-08-16 07:11:49 -04:00
bpm ! = _current_bpm ) {
// Transport or Tempo has changed, write position at cycle start
2012-11-17 13:41:19 -05:00
write_position ( & _impl - > forge , _ev_buffers [ port_index ] ,
2020-09-06 10:00:20 -04:00
tmetric , bbt , speed , time_scale , bpm , start , 0 ) ;
2012-11-17 13:41:19 -05:00
}
2012-11-17 23:35:31 -05:00
}
2012-11-17 13:41:19 -05:00
2012-11-17 23:35:31 -05:00
// Get MIDI iterator range (empty range if no MIDI)
MidiBuffer : : iterator m = ( index ! = nil_index )
? bufs . get_midi ( index ) . begin ( )
: silent_bufs . get_midi ( 0 ) . end ( ) ;
MidiBuffer : : iterator m_end = ( index ! = nil_index )
? bufs . get_midi ( index ) . end ( )
: m ;
// Now merge MIDI and any transport events into the buffer
2014-11-01 23:29:10 -04:00
const uint32_t type = _uri_map . urids . midi_MidiEvent ;
2019-04-08 12:29:04 -04:00
const samplepos_t tend = end ;
2012-11-17 23:35:31 -05:00
+ + metric_i ;
while ( m ! = m_end | | ( metric_i ! = tmap . metrics_end ( ) & &
2017-09-18 12:39:17 -04:00
( * metric_i ) - > sample ( ) < tend ) ) {
2012-11-17 23:35:31 -05:00
MetricSection * metric = ( metric_i ! = tmap . metrics_end ( ) )
? * metric_i : NULL ;
2017-09-18 12:39:17 -04:00
if ( m ! = m_end & & ( ! metric | | metric - > sample ( ) > ( * m ) . time ( ) ) ) {
const Evoral : : Event < samplepos_t > ev ( * m , false ) ;
2016-02-16 12:17:13 -05:00
if ( ev . time ( ) < nframes ) {
LV2_Evbuf_Iterator eend = lv2_evbuf_end ( _ev_buffers [ port_index ] ) ;
lv2_evbuf_write ( & eend , ev . time ( ) , 0 , type , ev . size ( ) , ev . buffer ( ) ) ;
}
2012-11-17 23:35:31 -05:00
+ + m ;
} else {
2019-08-22 23:15:17 -04:00
assert ( metric ) ;
2012-11-17 23:35:31 -05:00
tmetric . set_metric ( metric ) ;
2016-08-16 07:11:49 -04:00
Timecode : : BBT_Time bbt ;
2017-09-18 12:39:17 -04:00
bbt = tmap . bbt_at_sample ( metric - > sample ( ) ) ;
2020-09-06 10:00:20 -04:00
double bpm = tmap . tempo_at_sample ( start0 /*XXX metric->sample() */ ) . note_types_per_minute ( ) ;
2012-11-17 13:41:19 -05:00
write_position ( & _impl - > forge , _ev_buffers [ port_index ] ,
2019-11-14 15:15:30 -05:00
tmetric , bbt , speed , Port : : speed_ratio ( ) ,
bpm , metric - > sample ( ) ,
2020-09-06 10:00:20 -04:00
metric - > sample ( ) - start0 ) ;
2012-11-17 23:35:31 -05:00
+ + metric_i ;
2012-11-17 13:41:19 -05:00
}
}
2012-11-17 23:35:31 -05:00
} else if ( ! valid ) {
// Nothing we understand or care about, connect to scratch
2013-11-16 18:33:32 -05:00
// see note for midi-buffer size above
scratch_bufs . ensure_lv2_bufsize ( ( flags & PORT_INPUT ) ,
0 , _port_minimumSize [ port_index ] ) ;
2013-07-31 08:45:02 -04:00
_ev_buffers [ port_index ] = scratch_bufs . get_lv2_midi (
2020-07-08 15:19:30 -04:00
( flags & PORT_INPUT ) , 0 ) ;
2012-08-27 00:08:45 -04:00
}
2014-10-30 22:26:47 -04:00
2012-08-28 11:42:40 -04:00
buf = lv2_evbuf_get_buffer ( _ev_buffers [ port_index ] ) ;
2012-02-24 23:16:42 -05:00
} else {
continue ; // Control port, leave buffer alone
}
2012-02-24 17:09:30 -05:00
lilv_instance_connect_port ( _impl - > instance , port_index , buf ) ;
2011-05-15 19:10:13 -04:00
}
2012-02-25 03:43:23 -05:00
// Read messages from UI and push into appropriate buffers
if ( _from_ui ) {
uint32_t read_space = _from_ui - > read_space ( ) ;
while ( read_space > sizeof ( UIMessage ) ) {
UIMessage msg ;
if ( _from_ui - > read ( ( uint8_t * ) & msg , sizeof ( msg ) ) ! = sizeof ( msg ) ) {
2020-01-21 16:18:37 -05:00
error < < string_compose ( _ ( " LV2<%1>: Error reading message header from UI => Plugin RingBuffer " ) , name ( ) ) < < endmsg ;
2012-02-25 03:43:23 -05:00
break ;
}
2013-08-04 10:17:19 -04:00
vector < uint8_t > body ( msg . size ) ;
if ( _from_ui - > read ( & body [ 0 ] , msg . size ) ! = msg . size ) {
2020-01-21 16:18:37 -05:00
error < < string_compose ( _ ( " LV2<%1>: Error reading message body from UI => Plugin RingBuffer " ) , name ( ) ) < < endmsg ;
2012-02-25 03:43:23 -05:00
break ;
}
2014-11-01 23:29:10 -04:00
if ( msg . protocol = = URIMap : : instance ( ) . urids . atom_eventTransfer ) {
2012-08-18 11:56:48 -04:00
LV2_Evbuf * buf = _ev_buffers [ msg . index ] ;
2012-02-25 03:43:23 -05:00
LV2_Evbuf_Iterator i = lv2_evbuf_end ( buf ) ;
2013-08-04 10:17:19 -04:00
const LV2_Atom * const atom = ( const LV2_Atom * ) & body [ 0 ] ;
2015-02-05 17:37:17 -05:00
if ( ! lv2_evbuf_write ( & i , nframes - 1 , 0 , atom - > type , atom - > size ,
2012-08-27 00:08:45 -04:00
( const uint8_t * ) ( atom + 1 ) ) ) {
2012-11-17 20:48:28 -05:00
error < < " Failed to write data to LV2 event buffer \n " ;
2012-08-27 00:08:45 -04:00
}
2020-06-22 12:52:44 -04:00
/* Intercept patch:Set messages from GUIs (custom,
* or generic via LV2Plugin : : set_property ) .
*/
else if ( atom - > type = = _uri_map . urids . atom_Blank | |
atom - > type = = _uri_map . urids . atom_Object ) {
2020-07-08 14:53:37 -04:00
const LV2_Atom_Object * obj = ( const LV2_Atom_Object * ) atom ;
2020-06-22 12:52:44 -04:00
if ( obj - > body . otype = = _uri_map . urids . patch_Set ) {
const LV2_Atom * property = NULL ;
const LV2_Atom * value = NULL ;
lv2_atom_object_get ( obj ,
_uri_map . urids . patch_property , & property ,
_uri_map . urids . patch_value , & value ,
0 ) ;
2020-06-23 14:21:09 -04:00
if ( property & & value & & property - > type = = _uri_map . urids . atom_URID ) {
/* check if it's a property we know or care about */
const uint32_t prop_id = ( ( const LV2_Atom_URID * ) property ) - > body ;
if ( _property_values . find ( prop_id ) ! = _property_values . end ( ) ) {
Plugin : : state_changed ( ) ;
}
2020-06-22 12:52:44 -04:00
}
}
}
2012-02-25 03:43:23 -05:00
} else {
2020-01-21 16:18:37 -05:00
error < < string_compose ( _ ( " LV2<%1>: Received unknown message type from UI " ) , name ( ) ) < < endmsg ;
2012-02-25 03:43:23 -05:00
}
read_space - = sizeof ( UIMessage ) + msg . size ;
}
}
2011-05-15 19:10:13 -04:00
run ( nframes ) ;
midi_out_index = 0 ;
2012-01-23 13:17:09 -05:00
for ( uint32_t port_index = 0 ; port_index < num_ports ; + + port_index ) {
2012-02-25 03:43:23 -05:00
PortFlags flags = _port_flags [ port_index ] ;
2012-11-17 23:35:31 -05:00
bool valid = false ;
2012-02-25 03:43:23 -05:00
2013-05-19 11:19:01 -04:00
/* TODO ask drobilla about comment
* " Make Ardour event buffers generic so plugins can communicate "
* in libs / ardour / buffer_set . cc : 310
*
* ideally the user could choose which of the following two modes
* to use ( e . g . instrument / effect chains MIDI OUT vs MIDI TRHU ) .
*
* This implementation follows the discussion on IRC Mar 16 2013 16 : 47 UTC
* 16 : 51 < drobilla > rgareus : [ . . ] i . e always replace with MIDI output [ of LV2 plugin ] if it ' s there
* 16 : 52 < drobilla > rgareus : That would probably be good enough [ . . ] to make users not complain
* for quite a while at least ; )
*/
// copy output of LV2 plugin's MIDI port to Ardour MIDI buffers -- MIDI OUT
2020-07-08 15:19:30 -04:00
if ( ( flags & PORT_OUTPUT ) & & ( flags & ( PORT_SEQUENCE | PORT_MIDI ) ) ) {
2013-05-19 11:19:01 -04:00
const uint32_t buf_index = out_map . get (
DataType : : MIDI , midi_out_index + + , & valid ) ;
if ( valid ) {
bufs . forward_lv2_midi ( _ev_buffers [ port_index ] , buf_index ) ;
}
}
// Flush MIDI (write back to Ardour MIDI buffers) -- MIDI THRU
2020-07-08 15:19:30 -04:00
else if ( ( flags & PORT_OUTPUT ) & & ( flags & PORT_SEQUENCE ) ) {
2012-02-24 17:09:30 -05:00
const uint32_t buf_index = out_map . get (
DataType : : MIDI , midi_out_index + + , & valid ) ;
2011-10-21 00:51:04 -04:00
if ( valid ) {
bufs . flush_lv2_midi ( true , buf_index ) ;
}
2011-05-15 19:10:13 -04:00
}
2012-02-25 03:43:23 -05:00
// Write messages to UI
2016-03-13 18:20:45 -04:00
if ( ( _to_ui | | _can_write_automation | | _patch_port_out_index ! = ( uint32_t ) - 1 ) & &
2020-07-08 15:19:30 -04:00
( flags & PORT_OUTPUT ) & & ( flags & PORT_SEQUENCE ) ) {
2012-02-25 03:43:23 -05:00
LV2_Evbuf * buf = _ev_buffers [ port_index ] ;
for ( LV2_Evbuf_Iterator i = lv2_evbuf_begin ( buf ) ;
lv2_evbuf_is_valid ( i ) ;
i = lv2_evbuf_next ( i ) ) {
2017-09-18 12:39:17 -04:00
uint32_t samples , subframes , type , size ;
2012-02-25 03:43:23 -05:00
uint8_t * data ;
2017-09-18 12:39:17 -04:00
lv2_evbuf_get ( i , & samples , & subframes , & type , & size , & data ) ;
2014-10-30 22:26:47 -04:00
2016-03-13 18:20:45 -04:00
# ifdef LV2_EXTENDED
// Intercept Automation Write Events
if ( ( flags & PORT_AUTOCTRL ) ) {
LV2_Atom * atom = ( LV2_Atom * ) ( data - sizeof ( LV2_Atom ) ) ;
if ( atom - > type = = _uri_map . urids . atom_Blank | |
atom - > type = = _uri_map . urids . atom_Object ) {
LV2_Atom_Object * obj = ( LV2_Atom_Object * ) atom ;
if ( obj - > body . otype = = _uri_map . urids . auto_event ) {
// only if transport_rolling ??
const LV2_Atom * parameter = NULL ;
const LV2_Atom * value = NULL ;
lv2_atom_object_get ( obj ,
_uri_map . urids . auto_parameter , & parameter ,
_uri_map . urids . auto_value , & value ,
0 ) ;
if ( parameter & & value ) {
const uint32_t p = ( ( const LV2_Atom_Int * ) parameter ) - > body ;
const float v = ( ( const LV2_Atom_Float * ) value ) - > body ;
// -> add automation event..
2016-06-05 08:44:54 -04:00
DEBUG_TRACE ( DEBUG : : LV2Automate ,
2017-09-18 12:39:17 -04:00
string_compose ( " Event p: %1 t: %2 v: %3 \n " , p , samples , v ) ) ;
2016-03-13 18:20:45 -04:00
AutomationCtrlPtr c = get_automation_control ( p ) ;
2016-06-05 08:44:54 -04:00
if ( c & &
( c - > ac - > automation_state ( ) = = Touch | | c - > ac - > automation_state ( ) = = Write )
) {
2017-09-18 12:39:17 -04:00
samplepos_t when = std : : max ( ( samplepos_t ) 0 , start + samples - _current_latency ) ;
assert ( start + samples - _current_latency > = 0 ) ;
2016-03-13 18:20:45 -04:00
if ( c - > guard ) {
c - > guard = false ;
2016-06-03 17:09:08 -04:00
c - > ac - > list ( ) - > add ( when , v , true , true ) ;
2016-03-13 18:20:45 -04:00
} else {
2016-06-03 17:09:08 -04:00
c - > ac - > set_double ( v , when , true ) ;
2016-03-13 18:20:45 -04:00
}
}
}
}
else if ( obj - > body . otype = = _uri_map . urids . auto_setup ) {
// TODO optional arguments, for now we assume the plugin
// writes automation for its own inputs
// -> put them in "touch" mode (preferably "exclusive plugin touch(TM)"
for ( AutomationCtrlMap : : iterator i = _ctrl_map . begin ( ) ; i ! = _ctrl_map . end ( ) ; + + i ) {
2016-06-05 08:44:54 -04:00
if ( _port_flags [ i - > first ] & PORT_CTRLED ) {
DEBUG_TRACE ( DEBUG : : LV2Automate ,
string_compose ( " Setup p: %1 \n " , i - > first ) ) ;
i - > second - > ac - > set_automation_state ( Touch ) ;
}
2016-03-13 18:20:45 -04:00
}
}
else if ( obj - > body . otype = = _uri_map . urids . auto_finalize ) {
// set [touched] parameters to "play" ??
2016-06-05 08:44:54 -04:00
// allow plugin to change its mode (from analyze to apply)
const LV2_Atom * parameter = NULL ;
const LV2_Atom * value = NULL ;
lv2_atom_object_get ( obj ,
_uri_map . urids . auto_parameter , & parameter ,
_uri_map . urids . auto_value , & value ,
0 ) ;
if ( parameter & & value ) {
const uint32_t p = ( ( const LV2_Atom_Int * ) parameter ) - > body ;
const float v = ( ( const LV2_Atom_Float * ) value ) - > body ;
AutomationCtrlPtr c = get_automation_control ( p ) ;
DEBUG_TRACE ( DEBUG : : LV2Automate ,
string_compose ( " Finalize p: %1 v: %2 \n " , p , v ) ) ;
if ( c & & _port_flags [ p ] & PORT_CTRLER ) {
c - > ac - > set_value ( v , Controllable : : NoGroup ) ;
}
} else {
DEBUG_TRACE ( DEBUG : : LV2Automate , " Finalize \n " ) ;
}
for ( AutomationCtrlMap : : iterator i = _ctrl_map . begin ( ) ; i ! = _ctrl_map . end ( ) ; + + i ) {
// guard will be false if an event was written
if ( ( _port_flags [ i - > first ] & PORT_CTRLED ) & & ! i - > second - > guard ) {
DEBUG_TRACE ( DEBUG : : LV2Automate ,
string_compose ( " Thin p: %1 \n " , i - > first ) ) ;
i - > second - > ac - > alist ( ) - > thin ( 20 ) ;
}
}
2016-03-13 18:20:45 -04:00
}
else if ( obj - > body . otype = = _uri_map . urids . auto_start ) {
const LV2_Atom * parameter = NULL ;
lv2_atom_object_get ( obj ,
_uri_map . urids . auto_parameter , & parameter ,
0 ) ;
if ( parameter ) {
const uint32_t p = ( ( const LV2_Atom_Int * ) parameter ) - > body ;
AutomationCtrlPtr c = get_automation_control ( p ) ;
2016-06-05 08:44:54 -04:00
DEBUG_TRACE ( DEBUG : : LV2Automate , string_compose ( " Start Touch p: %1 \n " , p ) ) ;
2016-03-13 18:20:45 -04:00
if ( c ) {
2017-09-18 12:39:17 -04:00
c - > ac - > start_touch ( std : : max ( ( samplepos_t ) 0 , start - _current_latency ) ) ;
2016-03-13 18:20:45 -04:00
c - > guard = true ;
}
}
}
else if ( obj - > body . otype = = _uri_map . urids . auto_end ) {
const LV2_Atom * parameter = NULL ;
lv2_atom_object_get ( obj ,
_uri_map . urids . auto_parameter , & parameter ,
0 ) ;
if ( parameter ) {
const uint32_t p = ( ( const LV2_Atom_Int * ) parameter ) - > body ;
AutomationCtrlPtr c = get_automation_control ( p ) ;
2016-06-05 08:44:54 -04:00
DEBUG_TRACE ( DEBUG : : LV2Automate , string_compose ( " End Touch p: %1 \n " , p ) ) ;
2016-03-13 18:20:45 -04:00
if ( c ) {
2017-09-18 12:39:17 -04:00
c - > ac - > stop_touch ( std : : max ( ( samplepos_t ) 0 , start - _current_latency ) ) ;
2016-03-13 18:20:45 -04:00
}
}
}
}
}
2016-10-19 13:45:35 -04:00
# endif
2016-10-13 10:04:28 -04:00
// Intercept state dirty message
if ( _has_state_interface /* && (flags & PORT_DIRTYMSG)*/ ) {
LV2_Atom * atom = ( LV2_Atom * ) ( data - sizeof ( LV2_Atom ) ) ;
if ( atom - > type = = _uri_map . urids . atom_Blank | |
atom - > type = = _uri_map . urids . atom_Object ) {
LV2_Atom_Object * obj = ( LV2_Atom_Object * ) atom ;
2016-11-06 20:27:55 -05:00
if ( obj - > body . otype = = _uri_map . urids . state_StateChanged ) {
2020-06-21 11:36:01 -04:00
Plugin : : state_changed ( ) ;
2016-10-13 10:04:28 -04:00
}
}
}
2016-03-13 18:20:45 -04:00
2014-10-31 20:44:02 -04:00
// Intercept patch change messages to emit PropertyChanged signal
if ( ( flags & PORT_PATCHMSG ) ) {
2014-10-30 22:26:47 -04:00
LV2_Atom * atom = ( LV2_Atom * ) ( data - sizeof ( LV2_Atom ) ) ;
2014-11-01 23:29:10 -04:00
if ( atom - > type = = _uri_map . urids . atom_Blank | |
atom - > type = = _uri_map . urids . atom_Object ) {
2014-10-30 22:26:47 -04:00
LV2_Atom_Object * obj = ( LV2_Atom_Object * ) atom ;
2014-11-01 23:29:10 -04:00
if ( obj - > body . otype = = _uri_map . urids . patch_Set ) {
2014-10-30 22:26:47 -04:00
const LV2_Atom * property = NULL ;
2014-10-31 20:44:02 -04:00
const LV2_Atom * value = NULL ;
lv2_atom_object_get ( obj ,
2014-11-01 23:29:10 -04:00
_uri_map . urids . patch_property , & property ,
_uri_map . urids . patch_value , & value ,
2014-10-31 20:44:02 -04:00
0 ) ;
2020-06-23 14:21:09 -04:00
if ( property & & value & & property - > type = = _uri_map . urids . atom_URID ) {
const uint32_t prop_id = ( ( const LV2_Atom_URID * ) property ) - > body ;
if ( _property_values . find ( prop_id ) ! = _property_values . end ( ) ) {
if ( value - > type = = _uri_map . urids . atom_Path ) {
const char * path = ( const char * ) LV2_ATOM_BODY_CONST ( value ) ;
_property_values [ prop_id ] = Variant ( Variant : : PATH , path ) ;
}
if ( value - > type = = _uri_map . urids . atom_Float ) {
2020-07-08 14:53:37 -04:00
const float * val = ( const float * ) LV2_ATOM_BODY_CONST ( value ) ;
2020-06-23 14:21:09 -04:00
_property_values [ prop_id ] = Variant ( Variant : : FLOAT , * val ) ;
}
// TODO add support for other props (Int, Bool, ..)
2016-03-17 18:01:33 -04:00
2020-06-23 14:21:09 -04:00
// TODO: This should emit the control's Changed signal
PropertyChanged ( prop_id , _property_values [ prop_id ] ) ;
} else {
std : : cerr < < " warning: patch:Set for unknown property " < < std : : endl ;
}
2016-03-17 18:01:33 -04:00
} else {
2020-06-23 14:21:09 -04:00
std : : cerr < < " warning: patch:Set for unsupported property " < < std : : endl ;
2014-10-30 22:26:47 -04:00
}
}
}
}
if ( ! _to_ui ) continue ;
2014-11-01 23:29:10 -04:00
write_to_ui ( port_index , URIMap : : instance ( ) . urids . atom_eventTransfer ,
2012-02-25 03:43:23 -05:00
size + sizeof ( LV2_Atom ) ,
data - sizeof ( LV2_Atom ) ) ;
}
}
2011-05-15 19:10:13 -04:00
}
cycles_t now = get_cycles ( ) ;
set_cycles ( ( uint32_t ) ( now - then ) ) ;
2012-11-17 13:41:19 -05:00
// Update expected transport information for next cycle so we can detect changes
2016-06-24 20:23:56 -04:00
_next_cycle_speed = speed ;
2020-09-06 10:00:20 -04:00
_next_cycle_start = end + ( start - start0 ) ;
2019-11-14 15:15:30 -05:00
_prev_time_scale = Port : : speed_ratio ( ) ;
2012-11-17 13:41:19 -05:00
2016-08-16 07:11:49 -04:00
{
/* keep track of lv2:timePosition like plugins can do.
* Note : for no - midi plugins , we only ever send information at cycle - start ,
* so it needs to be realative to that .
*/
2020-09-06 10:00:20 -04:00
TempoMetric t = tmap . metric_at ( start0 ) ;
_current_bpm = tmap . tempo_at_sample ( start0 ) . note_types_per_minute ( ) ;
Timecode : : BBT_Time bbt ( tmap . bbt_at_sample ( start0 ) ) ;
2016-08-16 07:11:49 -04:00
double beatpos = ( bbt . bars - 1 ) * t . meter ( ) . divisions_per_bar ( )
+ ( bbt . beats - 1 )
+ ( bbt . ticks / Timecode : : BBT_Time : : ticks_per_beat ) ;
beatpos * = tmetric . meter ( ) . note_divisor ( ) / 4.0 ;
2017-09-18 12:39:17 -04:00
_next_cycle_beat = beatpos + nframes * speed * _current_bpm / ( 60.f * _session . sample_rate ( ) ) ;
2016-08-16 07:11:49 -04:00
}
2016-04-08 12:16:01 -04:00
if ( _latency_control_port ) {
2017-09-18 12:39:17 -04:00
samplecnt_t new_latency = signal_latency ( ) ;
2016-04-08 12:16:01 -04:00
_current_latency = new_latency ;
}
2011-05-15 19:10:13 -04:00
return 0 ;
}
bool
LV2Plugin : : parameter_is_control ( uint32_t param ) const
{
2012-02-24 17:09:30 -05:00
assert ( param < _port_flags . size ( ) ) ;
return _port_flags [ param ] & PORT_CONTROL ;
2011-05-15 19:10:13 -04:00
}
bool
LV2Plugin : : parameter_is_audio ( uint32_t param ) const
{
2012-02-24 17:09:30 -05:00
assert ( param < _port_flags . size ( ) ) ;
return _port_flags [ param ] & PORT_AUDIO ;
2011-05-15 19:10:13 -04:00
}
bool
LV2Plugin : : parameter_is_output ( uint32_t param ) const
{
2012-02-24 17:09:30 -05:00
assert ( param < _port_flags . size ( ) ) ;
return _port_flags [ param ] & PORT_OUTPUT ;
2011-05-15 19:10:13 -04:00
}
bool
LV2Plugin : : parameter_is_input ( uint32_t param ) const
{
2012-02-24 17:09:30 -05:00
assert ( param < _port_flags . size ( ) ) ;
return _port_flags [ param ] & PORT_INPUT ;
2011-05-15 19:10:13 -04:00
}
2016-07-05 13:14:25 -04:00
uint32_t
LV2Plugin : : designated_bypass_port ( )
{
const LilvPort * port = NULL ;
2016-09-18 13:06:59 -04:00
LilvNode * designation = lilv_new_uri ( _world . world , LV2_CORE_PREFIX " enabled " ) ;
port = lilv_plugin_get_port_by_designation (
_impl - > plugin , _world . lv2_InputPort , designation ) ;
lilv_node_free ( designation ) ;
if ( port ) {
return lilv_port_get_index ( _impl - > plugin , port ) ;
}
# ifdef LV2_EXTENDED
/* deprecated on 2016-Sep-18 in favor of lv2:enabled */
designation = lilv_new_uri ( _world . world , LV2_PROCESSING_URI__enable ) ;
2016-07-05 13:14:25 -04:00
port = lilv_plugin_get_port_by_designation (
_impl - > plugin , _world . lv2_InputPort , designation ) ;
lilv_node_free ( designation ) ;
if ( port ) {
return lilv_port_get_index ( _impl - > plugin , port ) ;
}
# endif
return UINT32_MAX ;
}
2014-10-31 23:48:27 -04:00
boost : : shared_ptr < ScalePoints >
2011-05-15 19:10:13 -04:00
LV2Plugin : : get_scale_points ( uint32_t port_index ) const
{
const LilvPort * port = lilv_plugin_get_port_by_index ( _impl - > plugin , port_index ) ;
LilvScalePoints * points = lilv_port_get_scale_points ( _impl - > plugin , port ) ;
2014-10-31 23:48:27 -04:00
boost : : shared_ptr < ScalePoints > ret ;
2011-05-15 19:10:13 -04:00
if ( ! points ) {
return ret ;
}
2014-10-31 23:48:27 -04:00
ret = boost : : shared_ptr < ScalePoints > ( new ScalePoints ( ) ) ;
2011-05-15 19:10:13 -04:00
LILV_FOREACH ( scale_points , i , points ) {
const LilvScalePoint * p = lilv_scale_points_get ( points , i ) ;
const LilvNode * label = lilv_scale_point_get_label ( p ) ;
const LilvNode * value = lilv_scale_point_get_value ( p ) ;
if ( label & & ( lilv_node_is_float ( value ) | | lilv_node_is_int ( value ) ) ) {
ret - > insert ( make_pair ( lilv_node_as_string ( label ) ,
lilv_node_as_float ( value ) ) ) ;
}
}
lilv_scale_points_free ( points ) ;
return ret ;
}
void
2016-08-23 07:40:42 -04:00
LV2Plugin : : run ( pframes_t nframes , bool sync_work )
2011-05-15 19:10:13 -04:00
{
2012-01-23 13:17:09 -05:00
uint32_t const N = parameter_count ( ) ;
for ( uint32_t i = 0 ; i < N ; + + i ) {
2011-05-15 19:10:13 -04:00
if ( parameter_is_control ( i ) & & parameter_is_input ( i ) ) {
_control_data [ i ] = _shadow_data [ i ] ;
}
}
2016-07-31 21:59:21 -04:00
if ( _worker ) {
// Execute work synchronously if we're freewheeling (export)
2016-08-23 07:40:42 -04:00
_worker - > set_synchronous ( sync_work | | session ( ) . engine ( ) . freewheeling ( ) ) ;
2016-07-31 21:59:21 -04:00
}
// Run the plugin for this cycle
2011-05-15 19:10:13 -04:00
lilv_instance_run ( _impl - > instance , nframes ) ;
2012-04-04 20:15:54 -04:00
2016-07-31 21:59:21 -04:00
// Emit any queued worker responses (calls a plugin callback)
if ( _state_worker ) {
_state_worker - > emit_responses ( ) ;
}
if ( _worker ) {
2012-04-05 22:42:19 -04:00
_worker - > emit_responses ( ) ;
2016-07-31 21:59:21 -04:00
}
// Notify the plugin that a work run cycle is complete
if ( _impl - > work_iface ) {
2012-04-04 20:15:54 -04:00
if ( _impl - > work_iface - > end_run ) {
_impl - > work_iface - > end_run ( _impl - > instance - > lv2_handle ) ;
}
}
2011-05-15 19:10:13 -04:00
}
void
LV2Plugin : : latency_compute_run ( )
{
if ( ! _latency_control_port ) {
return ;
}
// Run the plugin so that it can set its latency parameter
2014-07-16 11:08:25 -04:00
bool was_activated = _was_activated ;
2011-05-15 19:10:13 -04:00
activate ( ) ;
uint32_t port_index = 0 ;
uint32_t in_index = 0 ;
uint32_t out_index = 0 ;
2014-10-07 15:45:46 -04:00
// this is done in the main thread. non realtime.
2017-09-18 12:39:17 -04:00
const samplecnt_t bufsize = _engine . samples_per_cycle ( ) ;
2019-04-08 12:29:04 -04:00
float * buffer = ( float * ) malloc ( _engine . samples_per_cycle ( ) * sizeof ( float ) ) ;
2011-05-15 19:10:13 -04:00
memset ( buffer , 0 , sizeof ( float ) * bufsize ) ;
// FIXME: Ensure plugins can handle in-place processing
port_index = 0 ;
while ( port_index < parameter_count ( ) ) {
if ( parameter_is_audio ( port_index ) ) {
if ( parameter_is_input ( port_index ) ) {
lilv_instance_connect_port ( _impl - > instance , port_index , buffer ) ;
in_index + + ;
} else if ( parameter_is_output ( port_index ) ) {
lilv_instance_connect_port ( _impl - > instance , port_index , buffer ) ;
out_index + + ;
}
}
port_index + + ;
}
2016-08-23 07:40:42 -04:00
run ( bufsize , true ) ;
2011-05-15 19:10:13 -04:00
deactivate ( ) ;
2014-07-16 11:08:25 -04:00
if ( was_activated ) {
activate ( ) ;
}
2014-10-07 15:45:46 -04:00
free ( buffer ) ;
2011-05-15 19:10:13 -04:00
}
2013-01-16 03:01:30 -05:00
const LilvPort *
2012-04-10 16:46:32 -04:00
LV2Plugin : : Impl : : designated_input ( const char * uri , void * * bufptrs [ ] , void * * bufptr )
{
2013-01-16 03:01:30 -05:00
const LilvPort * port = NULL ;
2012-04-10 16:46:32 -04:00
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 ;
}
return port ;
}
2013-07-30 17:48:57 -04:00
static bool lv2_filter ( const string & str , void * /*arg*/ )
2013-07-10 08:31:25 -04:00
{
/* Not a dotfile, has a prefix before a period, suffix is "lv2" */
2015-10-05 10:17:49 -04:00
2013-07-10 08:31:25 -04:00
return str [ 0 ] ! = ' . ' & & ( str . length ( ) > 3 & & str . find ( " .lv2 " ) = = ( str . length ( ) - 4 ) ) ;
}
2011-05-15 19:10:13 -04:00
LV2World : : LV2World ( )
: world ( lilv_world_new ( ) )
2013-07-14 22:19:59 -04:00
, _bundle_checked ( false )
2011-05-15 19:10:13 -04:00
{
2012-03-25 13:17:40 -04:00
atom_AtomPort = lilv_new_uri ( world , LV2_ATOM__AtomPort ) ;
2012-02-28 22:21:37 -05:00
atom_Chunk = lilv_new_uri ( world , LV2_ATOM__Chunk ) ;
2012-02-25 03:43:23 -05:00
atom_Sequence = lilv_new_uri ( world , LV2_ATOM__Sequence ) ;
atom_bufferType = lilv_new_uri ( world , LV2_ATOM__bufferType ) ;
2012-08-27 00:08:45 -04:00
atom_supports = lilv_new_uri ( world , LV2_ATOM__supports ) ;
2012-02-25 03:43:23 -05:00
atom_eventTransfer = lilv_new_uri ( world , LV2_ATOM__eventTransfer ) ;
ev_EventPort = lilv_new_uri ( world , LILV_URI_EVENT_PORT ) ;
2012-04-20 21:40:17 -04:00
ext_logarithmic = lilv_new_uri ( world , LV2_PORT_PROPS__logarithmic ) ;
2013-05-25 03:06:06 -04:00
ext_notOnGUI = lilv_new_uri ( world , LV2_PORT_PROPS__notOnGUI ) ;
2016-06-05 08:45:24 -04:00
ext_expensive = lilv_new_uri ( world , LV2_PORT_PROPS__expensive ) ;
ext_causesArtifacts = lilv_new_uri ( world , LV2_PORT_PROPS__causesArtifacts ) ;
ext_notAutomatic = lilv_new_uri ( world , LV2_PORT_PROPS__notAutomatic ) ;
2016-07-05 10:21:09 -04:00
ext_rangeSteps = lilv_new_uri ( world , LV2_PORT_PROPS__rangeSteps ) ;
2020-11-20 00:03:49 -05:00
ext_displayPriority = lilv_new_uri ( world , LV2_PORT_PROPS__displayPriority ) ;
2016-11-09 18:09:38 -05:00
groups_group = lilv_new_uri ( world , LV2_PORT_GROUPS__group ) ;
groups_element = lilv_new_uri ( world , LV2_PORT_GROUPS__element ) ;
2012-02-25 03:43:23 -05:00
lv2_AudioPort = lilv_new_uri ( world , LILV_URI_AUDIO_PORT ) ;
lv2_ControlPort = lilv_new_uri ( world , LILV_URI_CONTROL_PORT ) ;
lv2_InputPort = lilv_new_uri ( world , LILV_URI_INPUT_PORT ) ;
lv2_OutputPort = lilv_new_uri ( world , LILV_URI_OUTPUT_PORT ) ;
2012-04-20 21:40:17 -04:00
lv2_inPlaceBroken = lilv_new_uri ( world , LV2_CORE__inPlaceBroken ) ;
2016-04-03 12:28:59 -04:00
lv2_isSideChain = lilv_new_uri ( world , LV2_CORE_PREFIX " isSideChain " ) ;
2016-11-09 18:09:38 -05:00
lv2_index = lilv_new_uri ( world , LV2_CORE__index ) ;
2012-04-20 21:40:17 -04:00
lv2_integer = lilv_new_uri ( world , LV2_CORE__integer ) ;
2014-11-01 23:29:10 -04:00
lv2_default = lilv_new_uri ( world , LV2_CORE__default ) ;
lv2_minimum = lilv_new_uri ( world , LV2_CORE__minimum ) ;
lv2_maximum = lilv_new_uri ( world , LV2_CORE__maximum ) ;
2013-05-25 03:06:06 -04:00
lv2_reportsLatency = lilv_new_uri ( world , LV2_CORE__reportsLatency ) ;
2012-04-20 21:40:17 -04:00
lv2_sampleRate = lilv_new_uri ( world , LV2_CORE__sampleRate ) ;
lv2_toggled = lilv_new_uri ( world , LV2_CORE__toggled ) ;
2016-11-09 18:09:38 -05:00
lv2_designation = lilv_new_uri ( world , LV2_CORE__designation ) ;
2012-04-20 21:40:17 -04:00
lv2_enumeration = lilv_new_uri ( world , LV2_CORE__enumeration ) ;
2013-06-14 11:33:29 -04:00
lv2_freewheeling = lilv_new_uri ( world , LV2_CORE__freeWheeling ) ;
2012-02-25 03:43:23 -05:00
midi_MidiEvent = lilv_new_uri ( world , LILV_URI_MIDI_EVENT ) ;
2012-04-19 21:24:07 -04:00
rdfs_comment = lilv_new_uri ( world , LILV_NS_RDFS " comment " ) ;
2014-10-31 20:44:02 -04:00
rdfs_label = lilv_new_uri ( world , LILV_NS_RDFS " label " ) ;
rdfs_range = lilv_new_uri ( world , LILV_NS_RDFS " range " ) ;
2013-06-02 18:48:17 -04:00
rsz_minimumSize = lilv_new_uri ( world , LV2_RESIZE_PORT__minimumSize ) ;
2012-11-17 13:41:19 -05:00
time_Position = lilv_new_uri ( world , LV2_TIME__Position ) ;
2019-05-08 15:59:22 -04:00
time_beatsPerMin = lilv_new_uri ( world , LV2_TIME__beatsPerMinute ) ;
2012-04-20 21:40:17 -04:00
ui_GtkUI = lilv_new_uri ( world , LV2_UI__GtkUI ) ;
2019-10-28 11:00:48 -04:00
ui_X11UI = lilv_new_uri ( world , LV2_UI__X11UI ) ;
2012-04-20 21:40:17 -04:00
ui_external = lilv_new_uri ( world , " http://lv2plug.in/ns/extensions/ui#external " ) ;
2013-08-25 10:20:27 -04:00
ui_externalkx = lilv_new_uri ( world , " http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget " ) ;
2014-11-02 01:29:33 -05:00
units_unit = lilv_new_uri ( world , LV2_UNITS__unit ) ;
2014-11-02 01:59:18 -05:00
units_render = lilv_new_uri ( world , LV2_UNITS__render ) ;
2014-11-03 17:29:11 -05:00
units_hz = lilv_new_uri ( world , LV2_UNITS__hz ) ;
2014-11-02 01:29:33 -05:00
units_midiNote = lilv_new_uri ( world , LV2_UNITS__midiNote ) ;
units_db = lilv_new_uri ( world , LV2_UNITS__db ) ;
2014-10-30 22:26:47 -04:00
patch_writable = lilv_new_uri ( world , LV2_PATCH__writable ) ;
patch_Message = lilv_new_uri ( world , LV2_PATCH__Message ) ;
2019-04-09 18:19:39 -04:00
opts_requiredOptions = lilv_new_uri ( world , LV2_OPTIONS__requiredOption ) ;
2016-03-13 18:20:45 -04:00
# ifdef LV2_EXTENDED
2016-09-18 13:06:59 -04:00
lv2_noSampleAccurateCtrl = lilv_new_uri ( world , " http://ardour.org/lv2/ext#noSampleAccurateControls " ) ; // deprecated 2016-09-18
2019-08-19 14:19:38 -04:00
routing_connectAllOutputs = lilv_new_uri ( world , LV2_ROUTING__connectAllOutputs ) ;
2016-03-13 18:20:45 -04:00
auto_can_write_automatation = lilv_new_uri ( world , LV2_AUTOMATE_URI__can_write ) ;
auto_automation_control = lilv_new_uri ( world , LV2_AUTOMATE_URI__control ) ;
auto_automation_controlled = lilv_new_uri ( world , LV2_AUTOMATE_URI__controlled ) ;
2016-06-05 08:44:54 -04:00
auto_automation_controller = lilv_new_uri ( world , LV2_AUTOMATE_URI__controller ) ;
2020-12-30 12:50:02 -05:00
inline_display_interface = lilv_new_uri ( world , LV2_INLINEDISPLAY__interface ) ;
2017-07-23 15:10:07 -04:00
inline_display_in_gui = lilv_new_uri ( world , LV2_INLINEDISPLAY__in_gui ) ;
2019-12-14 09:00:34 -05:00
inline_mixer_control = lilv_new_uri ( world , " http://ardour.org/lv2/ext#inlineMixerControl " ) ;
2016-03-13 18:20:45 -04:00
# endif
2015-08-14 11:49:47 -04:00
bufz_powerOf2BlockLength = lilv_new_uri ( world , LV2_BUF_SIZE__powerOf2BlockLength ) ;
bufz_fixedBlockLength = lilv_new_uri ( world , LV2_BUF_SIZE__fixedBlockLength ) ;
2015-09-09 18:55:28 -04:00
bufz_nominalBlockLength = lilv_new_uri ( world , " http://lv2plug.in/ns/ext/buf-size#nominalBlockLength " ) ;
2016-09-18 13:06:59 -04:00
bufz_coarseBlockLength = lilv_new_uri ( world , " http://lv2plug.in/ns/ext/buf-size#coarseBlockLength " ) ;
2011-05-15 19:10:13 -04:00
}
LV2World : : ~ LV2World ( )
{
2016-01-29 12:22:57 -05:00
if ( ! world ) {
return ;
}
2016-09-18 13:06:59 -04:00
lilv_node_free ( bufz_coarseBlockLength ) ;
2015-09-09 18:55:28 -04:00
lilv_node_free ( bufz_nominalBlockLength ) ;
2015-08-14 11:49:47 -04:00
lilv_node_free ( bufz_fixedBlockLength ) ;
lilv_node_free ( bufz_powerOf2BlockLength ) ;
2016-03-13 18:20:45 -04:00
# ifdef LV2_EXTENDED
2015-12-06 07:49:16 -05:00
lilv_node_free ( lv2_noSampleAccurateCtrl ) ;
2019-08-19 14:19:38 -04:00
lilv_node_free ( routing_connectAllOutputs ) ;
2016-03-13 18:20:45 -04:00
lilv_node_free ( auto_can_write_automatation ) ;
lilv_node_free ( auto_automation_control ) ;
lilv_node_free ( auto_automation_controlled ) ;
2016-06-05 08:44:54 -04:00
lilv_node_free ( auto_automation_controller ) ;
2020-12-30 12:50:02 -05:00
lilv_node_free ( inline_display_interface ) ;
2019-12-14 09:00:34 -05:00
lilv_node_free ( inline_display_in_gui ) ;
lilv_node_free ( inline_mixer_control ) ;
2016-03-13 18:20:45 -04:00
# endif
2014-10-30 22:26:47 -04:00
lilv_node_free ( patch_Message ) ;
2019-04-09 18:19:39 -04:00
lilv_node_free ( opts_requiredOptions ) ;
2014-10-30 22:26:47 -04:00
lilv_node_free ( patch_writable ) ;
2014-11-03 17:29:11 -05:00
lilv_node_free ( units_hz ) ;
2013-10-22 11:26:30 -04:00
lilv_node_free ( units_midiNote ) ;
2014-11-02 01:29:33 -05:00
lilv_node_free ( units_db ) ;
2013-10-22 11:26:30 -04:00
lilv_node_free ( units_unit ) ;
2014-11-02 01:59:18 -05:00
lilv_node_free ( units_render ) ;
2013-08-25 10:20:27 -04:00
lilv_node_free ( ui_externalkx ) ;
2012-02-25 00:01:24 -05:00
lilv_node_free ( ui_external ) ;
2019-10-28 11:00:48 -04:00
lilv_node_free ( ui_X11UI ) ;
2012-02-25 00:01:24 -05:00
lilv_node_free ( ui_GtkUI ) ;
2019-05-08 15:59:22 -04:00
lilv_node_free ( time_beatsPerMin ) ;
2013-06-02 18:51:34 -04:00
lilv_node_free ( time_Position ) ;
lilv_node_free ( rsz_minimumSize ) ;
lilv_node_free ( rdfs_comment ) ;
2014-10-31 20:44:02 -04:00
lilv_node_free ( rdfs_label ) ;
lilv_node_free ( rdfs_range ) ;
2012-02-25 00:01:24 -05:00
lilv_node_free ( midi_MidiEvent ) ;
2016-11-09 18:09:38 -05:00
lilv_node_free ( lv2_designation ) ;
2013-06-02 18:51:34 -04:00
lilv_node_free ( lv2_enumeration ) ;
2013-06-14 11:33:29 -04:00
lilv_node_free ( lv2_freewheeling ) ;
2012-02-25 00:01:24 -05:00
lilv_node_free ( lv2_toggled ) ;
lilv_node_free ( lv2_sampleRate ) ;
2013-05-25 03:06:06 -04:00
lilv_node_free ( lv2_reportsLatency ) ;
2016-11-09 18:09:38 -05:00
lilv_node_free ( lv2_index ) ;
2013-06-02 18:51:34 -04:00
lilv_node_free ( lv2_integer ) ;
2016-04-03 12:28:59 -04:00
lilv_node_free ( lv2_isSideChain ) ;
2012-02-25 00:01:24 -05:00
lilv_node_free ( lv2_inPlaceBroken ) ;
lilv_node_free ( lv2_OutputPort ) ;
lilv_node_free ( lv2_InputPort ) ;
lilv_node_free ( lv2_ControlPort ) ;
lilv_node_free ( lv2_AudioPort ) ;
2016-11-09 18:09:38 -05:00
lilv_node_free ( groups_group ) ;
lilv_node_free ( groups_element ) ;
2020-11-20 00:03:49 -05:00
lilv_node_free ( ext_displayPriority ) ;
2016-07-05 10:21:09 -04:00
lilv_node_free ( ext_rangeSteps ) ;
2016-06-05 08:45:24 -04:00
lilv_node_free ( ext_notAutomatic ) ;
lilv_node_free ( ext_causesArtifacts ) ;
lilv_node_free ( ext_expensive ) ;
2013-05-25 03:06:06 -04:00
lilv_node_free ( ext_notOnGUI ) ;
2013-06-02 18:51:34 -04:00
lilv_node_free ( ext_logarithmic ) ;
2012-02-25 00:01:24 -05:00
lilv_node_free ( ev_EventPort ) ;
2013-06-02 18:51:34 -04:00
lilv_node_free ( atom_supports ) ;
2012-02-25 03:43:23 -05:00
lilv_node_free ( atom_eventTransfer ) ;
2012-02-25 00:01:24 -05:00
lilv_node_free ( atom_bufferType ) ;
lilv_node_free ( atom_Sequence ) ;
2012-02-28 22:21:37 -05:00
lilv_node_free ( atom_Chunk ) ;
2012-03-25 13:17:40 -04:00
lilv_node_free ( atom_AtomPort ) ;
2014-09-09 21:31:03 -04:00
lilv_world_free ( world ) ;
2016-01-29 12:22:57 -05:00
world = NULL ;
2011-05-15 19:10:13 -04:00
}
2013-07-14 22:19:59 -04:00
void
2014-09-10 14:44:17 -04:00
LV2World : : load_bundled_plugins ( bool verbose )
2013-07-14 22:19:59 -04:00
{
if ( ! _bundle_checked ) {
2014-09-10 14:44:17 -04:00
if ( verbose ) {
cout < < " Scanning folders for bundled LV2s: " < < ARDOUR : : lv2_bundled_search_path ( ) . to_string ( ) < < endl ;
}
2014-06-16 06:39:45 -04:00
2014-06-17 07:41:29 -04:00
vector < string > plugin_objects ;
2014-06-21 23:20:25 -04:00
find_paths_matching_filter ( plugin_objects , ARDOUR : : lv2_bundled_search_path ( ) , lv2_filter , 0 , true , true , true ) ;
2014-06-16 06:39:45 -04:00
for ( vector < string > : : iterator x = plugin_objects . begin ( ) ; x ! = plugin_objects . end ( ) ; + + x ) {
2013-08-04 14:03:32 -04:00
# ifdef PLATFORM_WINDOWS
2014-06-16 06:39:45 -04:00
string uri = " file:/// " + * x + " / " ;
2013-07-14 22:19:59 -04:00
# else
2014-06-16 06:39:45 -04:00
string uri = " file:// " + * x + " / " ;
2013-07-14 22:19:59 -04:00
# endif
2014-06-16 06:39:45 -04:00
LilvNode * node = lilv_new_uri ( world , uri . c_str ( ) ) ;
lilv_world_load_bundle ( world , node ) ;
lilv_node_free ( node ) ;
2013-07-14 22:22:34 -04:00
}
2015-01-28 20:12:15 -05:00
lilv_world_load_all ( world ) ;
2013-07-14 22:22:34 -04:00
_bundle_checked = true ;
2013-07-14 22:19:59 -04:00
}
}
2014-09-09 21:31:03 -04:00
LV2PluginInfo : : LV2PluginInfo ( const char * plugin_uri )
2011-05-15 19:10:13 -04:00
{
type = ARDOUR : : LV2 ;
2014-09-09 21:31:03 -04:00
_plugin_uri = strdup ( plugin_uri ) ;
2011-05-15 19:10:13 -04:00
}
LV2PluginInfo : : ~ LV2PluginInfo ( )
2014-09-09 21:31:03 -04:00
{
free ( _plugin_uri ) ;
2014-09-10 07:11:22 -04:00
_plugin_uri = NULL ;
2014-09-09 21:31:03 -04:00
}
2011-05-15 19:10:13 -04:00
PluginPtr
LV2PluginInfo : : load ( Session & session )
{
try {
PluginPtr plugin ;
2014-09-09 21:31:03 -04:00
const LilvPlugins * plugins = lilv_world_get_all_plugins ( _world . world ) ;
LilvNode * uri = lilv_new_uri ( _world . world , _plugin_uri ) ;
if ( ! uri ) { throw failed_constructor ( ) ; }
const LilvPlugin * lp = lilv_plugins_get_by_uri ( plugins , uri ) ;
if ( ! lp ) { throw failed_constructor ( ) ; }
2017-09-18 12:39:17 -04:00
plugin . reset ( new LV2Plugin ( session . engine ( ) , session , lp , session . sample_rate ( ) ) ) ;
2014-09-09 21:31:03 -04:00
lilv_node_free ( uri ) ;
2014-09-10 20:28:57 -04:00
plugin - > set_info ( PluginInfoPtr ( shared_from_this ( ) ) ) ;
2011-05-15 19:10:13 -04:00
return plugin ;
} catch ( failed_constructor & err ) {
return PluginPtr ( ( Plugin * ) 0 ) ;
}
return PluginPtr ( ) ;
}
2016-01-07 11:10:35 -05:00
std : : vector < Plugin : : PresetRecord >
2016-01-09 09:22:16 -05:00
LV2PluginInfo : : get_presets ( bool /*user_only*/ ) const
2016-01-07 11:10:35 -05:00
{
std : : vector < Plugin : : PresetRecord > p ;
2019-09-29 12:00:23 -04:00
2016-01-07 11:10:35 -05:00
const LilvPlugin * lp = NULL ;
try {
PluginPtr plugin ;
const LilvPlugins * plugins = lilv_world_get_all_plugins ( _world . world ) ;
LilvNode * uri = lilv_new_uri ( _world . world , _plugin_uri ) ;
if ( ! uri ) { throw failed_constructor ( ) ; }
lp = lilv_plugins_get_by_uri ( plugins , uri ) ;
if ( ! lp ) { throw failed_constructor ( ) ; }
lilv_node_free ( uri ) ;
} catch ( failed_constructor & err ) {
return p ;
}
assert ( lp ) ;
// see LV2Plugin::find_presets
LilvNode * lv2_appliesTo = lilv_new_uri ( _world . world , LV2_CORE__appliesTo ) ;
LilvNode * pset_Preset = lilv_new_uri ( _world . world , LV2_PRESETS__Preset ) ;
LilvNode * rdfs_label = lilv_new_uri ( _world . world , LILV_NS_RDFS " label " ) ;
2018-12-18 07:35:39 -05:00
LilvNode * rdfs_comment = lilv_new_uri ( _world . world , LILV_NS_RDFS " comment " ) ;
2016-01-07 11:10:35 -05:00
LilvNodes * presets = lilv_plugin_get_related ( lp , pset_Preset ) ;
LILV_FOREACH ( nodes , i , presets ) {
const LilvNode * preset = lilv_nodes_get ( presets , i ) ;
lilv_world_load_resource ( _world . world , preset ) ;
LilvNode * name = get_value ( _world . world , preset , rdfs_label ) ;
2018-12-18 07:35:39 -05:00
LilvNode * comment = get_value ( _world . world , preset , rdfs_comment ) ;
/* TODO properly identify user vs factory presets.
* here ' s an indirect condition : only factory presets can have comments
*/
bool userpreset = comment ? false : true ;
2016-01-07 11:10:35 -05:00
if ( name ) {
2018-12-18 07:35:39 -05:00
p . push_back ( Plugin : : PresetRecord ( lilv_node_as_string ( preset ) , lilv_node_as_string ( name ) , userpreset , comment ? lilv_node_as_string ( comment ) : " " ) ) ;
2016-01-07 11:10:35 -05:00
lilv_node_free ( name ) ;
}
2018-12-18 07:35:39 -05:00
if ( comment ) {
lilv_node_free ( comment ) ;
}
2016-01-07 11:10:35 -05:00
}
lilv_nodes_free ( presets ) ;
2018-12-18 07:35:39 -05:00
lilv_node_free ( rdfs_comment ) ;
2016-01-07 11:10:35 -05:00
lilv_node_free ( rdfs_label ) ;
lilv_node_free ( pset_Preset ) ;
lilv_node_free ( lv2_appliesTo ) ;
2019-09-29 12:00:23 -04:00
2016-01-07 11:10:35 -05:00
return p ;
}
2011-05-15 19:10:13 -04:00
PluginInfoList *
2021-06-23 19:56:14 -04:00
LV2PluginInfo : : discover ( boost : : function < void ( std : : string const & , PluginScanLogEntry : : PluginScanResult , std : : string const & , bool ) > cb )
2011-05-15 19:10:13 -04:00
{
2014-09-09 21:31:03 -04:00
LV2World world ;
world . load_bundled_plugins ( ) ;
2014-09-10 14:44:17 -04:00
_world . load_bundled_plugins ( true ) ;
2013-07-14 22:19:59 -04:00
2011-05-15 19:10:13 -04:00
PluginInfoList * plugs = new PluginInfoList ;
2014-09-09 21:31:03 -04:00
const LilvPlugins * plugins = lilv_world_get_all_plugins ( world . world ) ;
2011-05-15 19:10:13 -04:00
LILV_FOREACH ( plugins , i , plugins ) {
const LilvPlugin * p = lilv_plugins_get ( plugins , i ) ;
2014-09-09 21:31:03 -04:00
const LilvNode * pun = lilv_plugin_get_uri ( p ) ;
if ( ! pun ) continue ;
2021-06-23 19:56:14 -04:00
std : : string const uri ( lilv_node_as_string ( pun ) ) ;
cb ( uri , PluginScanLogEntry : : OK , string_compose ( _ ( " URI: %1 " ) , uri ) , true ) ;
cb ( uri , PluginScanLogEntry : : OK , string_compose ( _ ( " Bundle: %1 " ) , lilv_node_as_uri ( lilv_plugin_get_bundle_uri ( p ) ) ) , false ) ;
2014-09-09 21:31:03 -04:00
LV2PluginInfoPtr info ( new LV2PluginInfo ( lilv_node_as_string ( pun ) ) ) ;
2011-05-15 19:10:13 -04:00
LilvNode * name = lilv_plugin_get_name ( p ) ;
2012-11-17 20:48:28 -05:00
if ( ! name | | ! lilv_plugin_get_port_by_index ( p , 0 ) ) {
2021-06-23 19:56:14 -04:00
cb ( uri , PluginScanLogEntry : : Error , _ ( " Ignoring invalid LV2 plugin (missing name, no ports) " ) , false ) ;
lilv_node_free ( name ) ;
2011-05-15 19:10:13 -04:00
continue ;
}
2015-08-14 12:12:05 -04:00
if ( lilv_plugin_has_feature ( p , world . lv2_inPlaceBroken ) ) {
2021-06-23 19:56:14 -04:00
cb ( uri , PluginScanLogEntry : : Error , _ ( " Ignoring LV2 plugin since it cannot do inplace processing. " ) , false ) ;
2015-08-14 12:12:05 -04:00
lilv_node_free ( name ) ;
continue ;
}
2019-04-09 18:19:39 -04:00
int err = 0 ;
LilvNodes * required_features = lilv_plugin_get_required_features ( p ) ;
LILV_FOREACH ( nodes , i , required_features ) {
const char * rf = lilv_node_as_uri ( lilv_nodes_get ( required_features , i ) ) ;
bool ok = false ;
2019-12-15 08:05:25 -05:00
if ( ! strcmp ( rf , " http://lv2plug.in/ns/lv2core#isLive " ) ) { ok = true ; }
2019-04-09 18:19:39 -04:00
if ( ! strcmp ( rf , " http://lv2plug.in/ns/ext/instance-access " ) ) { ok = true ; }
if ( ! strcmp ( rf , " http://lv2plug.in/ns/ext/data-access " ) ) { ok = true ; }
if ( ! strcmp ( rf , LV2_STATE__makePath ) ) { ok = true ; }
2019-12-15 08:05:25 -05:00
if ( ! strcmp ( rf , LV2_STATE__mapPath ) ) { ok = true ; }
if ( ! strcmp ( rf , " http://lv2plug.in/ns/ext/state#threadSafeRestore " ) ) { ok = true ; }
if ( ! strcmp ( rf , LV2_STATE_PREFIX " loadDefaultState " ) ) { ok = true ; }
2019-04-09 18:19:39 -04:00
if ( ! strcmp ( rf , LV2_LOG__log ) ) { ok = true ; }
if ( ! strcmp ( rf , LV2_WORKER__schedule ) ) { ok = true ; }
if ( ! strcmp ( rf , LV2_URID_MAP_URI ) ) { ok = true ; }
if ( ! strcmp ( rf , LV2_URID_UNMAP_URI ) ) { ok = true ; }
2019-05-03 14:02:26 -04:00
if ( ! strcmp ( rf , LV2_BUF_SIZE__boundedBlockLength ) ) { ok = true ; }
if ( ! strcmp ( rf , " http://lv2plug.in/ns/ext/buf-size#coarseBlockLength " /*LV2_BUF_SIZE__coarseBlockLength*/ ) ) { ok = true ; }
if ( ! strcmp ( rf , LV2_OPTIONS__options ) ) { ok = true ; }
# ifdef LV2_EXTENDED
if ( ! strcmp ( rf , LV2_INLINEDISPLAY__queue_draw ) ) { ok = true ; }
if ( ! strcmp ( rf , LV2_MIDNAM__update ) ) { ok = true ; }
if ( ! strcmp ( rf , LV2_BANKPATCH__notify ) ) { ok = true ; }
# endif
2019-04-09 18:19:39 -04:00
if ( ! ok ) {
2021-06-23 19:56:14 -04:00
cb ( uri , PluginScanLogEntry : : Error , string_compose ( _ ( " Unsupported required LV2 feature: '%1'. " ) , rf ) , false ) ;
2019-04-09 18:19:39 -04:00
err = 1 ;
}
}
2020-05-15 19:36:04 -04:00
lilv_nodes_free ( required_features ) ;
2019-04-09 18:19:39 -04:00
if ( err ) {
continue ;
}
LilvNodes * required_options = lilv_world_find_nodes ( world . world , lilv_plugin_get_uri ( p ) , world . opts_requiredOptions , NULL ) ;
if ( required_options ) {
LILV_FOREACH ( nodes , i , required_options ) {
const char * ro = lilv_node_as_uri ( lilv_nodes_get ( required_options , i ) ) ;
bool ok = false ;
if ( ! strcmp ( ro , LV2_PARAMETERS__sampleRate ) ) { ok = true ; }
if ( ! strcmp ( ro , LV2_BUF_SIZE__minBlockLength ) ) { ok = true ; }
if ( ! strcmp ( ro , LV2_BUF_SIZE__maxBlockLength ) ) { ok = true ; }
if ( ! strcmp ( ro , LV2_BUF_SIZE__sequenceSize ) ) { ok = true ; }
if ( ! ok ) {
2021-06-23 19:56:14 -04:00
cb ( uri , PluginScanLogEntry : : Error , string_compose ( _ ( " Unsupported required LV2 option: '%1'. " ) , ro ) , false ) ;
2019-04-09 18:19:39 -04:00
err = 1 ;
}
}
}
lilv_nodes_free ( required_options ) ;
if ( err ) {
2015-08-14 12:12:05 -04:00
continue ;
}
2011-05-15 19:10:13 -04:00
info - > type = LV2 ;
info - > name = string ( lilv_node_as_string ( name ) ) ;
lilv_node_free ( name ) ;
2014-02-25 08:52:57 -05:00
ARDOUR : : PluginScanMessage ( _ ( " LV2 " ) , info - > name , false ) ;
2011-05-15 19:10:13 -04:00
const LilvPluginClass * pclass = lilv_plugin_get_class ( p ) ;
const LilvNode * label = lilv_plugin_class_get_label ( pclass ) ;
2021-06-23 19:56:14 -04:00
2011-05-15 19:10:13 -04:00
info - > category = lilv_node_as_string ( label ) ;
2021-06-23 19:56:14 -04:00
cb ( uri , PluginScanLogEntry : : OK , string_compose ( _ ( " LV2 Category: '%1' " ) , info - > category ) , false ) ;
2020-09-15 13:32:14 -04:00
/* check main category */
const char * pcat = lilv_node_as_uri ( lilv_plugin_class_get_uri ( pclass ) ) ;
assert ( pcat ) ;
info - > _is_instrument = 0 = = strcmp ( pcat , LV2_CORE__InstrumentPlugin ) ;
info - > _is_utility = 0 = = strcmp ( pcat , LV2_CORE__UtilityPlugin ) ;
info - > _is_analyzer = 0 = = strcmp ( pcat , LV2_CORE__AnalyserPlugin ) ;
/* iterate over additional classes */
LilvPluginClasses * classes = lilv_plugin_class_get_children ( pclass ) ;
LILV_FOREACH ( plugin_classes , i , classes ) {
const char * pc = lilv_node_as_uri ( lilv_plugin_class_get_uri ( lilv_plugin_classes_get ( classes , i ) ) ) ;
assert ( pc ) ;
info - > _is_instrument | = 0 = = strcmp ( pc , LV2_CORE__InstrumentPlugin ) ;
info - > _is_utility | = 0 = = strcmp ( pc , LV2_CORE__UtilityPlugin ) ;
info - > _is_analyzer | = 0 = = strcmp ( pc , LV2_CORE__AnalyserPlugin ) ;
2021-06-23 19:56:14 -04:00
cb ( uri , PluginScanLogEntry : : OK , string_compose ( _ ( " LV2 Class: '%1' " ) , pc ) , false ) ;
2020-09-15 13:32:14 -04:00
}
lilv_plugin_classes_free ( classes ) ;
2011-05-15 19:10:13 -04:00
LilvNode * author_name = lilv_plugin_get_author_name ( p ) ;
info - > creator = author_name ? string ( lilv_node_as_string ( author_name ) ) : " Unknown " ;
lilv_node_free ( author_name ) ;
info - > path = " /NOPATH " ; // Meaningless for LV2
2012-08-27 00:08:45 -04:00
int count_midi_out = 0 ;
2021-06-23 19:56:14 -04:00
int count_midi_in = 0 ;
int count_atom_out = 0 ;
int count_atom_in = 0 ;
int count_ctrl_out = 0 ;
int count_ctrl_in = 0 ;
2012-08-27 00:08:45 -04:00
for ( uint32_t i = 0 ; i < lilv_plugin_get_num_ports ( p ) ; + + i ) {
const LilvPort * port = lilv_plugin_get_port_by_index ( p , i ) ;
2014-09-09 21:31:03 -04:00
if ( lilv_port_is_a ( p , port , world . atom_AtomPort ) ) {
2012-08-27 00:08:45 -04:00
LilvNodes * buffer_types = lilv_port_get_value (
2014-09-09 21:31:03 -04:00
p , port , world . atom_bufferType ) ;
2012-08-27 00:08:45 -04:00
LilvNodes * atom_supports = lilv_port_get_value (
2014-09-09 21:31:03 -04:00
p , port , world . atom_supports ) ;
2012-08-27 00:08:45 -04:00
2014-09-09 21:31:03 -04:00
if ( lilv_nodes_contains ( buffer_types , world . atom_Sequence )
& & lilv_nodes_contains ( atom_supports , world . midi_MidiEvent ) ) {
if ( lilv_port_is_a ( p , port , world . lv2_InputPort ) ) {
2012-08-27 00:08:45 -04:00
count_midi_in + + ;
2021-06-23 19:56:14 -04:00
count_atom_in + + ;
2012-08-27 00:08:45 -04:00
}
2014-09-09 21:31:03 -04:00
if ( lilv_port_is_a ( p , port , world . lv2_OutputPort ) ) {
2012-08-27 00:08:45 -04:00
count_midi_out + + ;
2021-06-23 19:56:14 -04:00
count_atom_out + + ;
}
} else {
if ( lilv_port_is_a ( p , port , world . lv2_InputPort ) ) {
count_atom_in + + ;
}
if ( lilv_port_is_a ( p , port , world . lv2_OutputPort ) ) {
count_atom_out + + ;
2012-08-27 00:08:45 -04:00
}
}
lilv_nodes_free ( buffer_types ) ;
lilv_nodes_free ( atom_supports ) ;
}
2021-06-23 19:56:14 -04:00
else if ( lilv_port_is_a ( p , port , world . lv2_ControlPort ) ) {
if ( lilv_port_is_a ( p , port , world . lv2_InputPort ) ) {
count_ctrl_in + + ;
}
if ( lilv_port_is_a ( p , port , world . lv2_OutputPort ) ) {
count_ctrl_out + + ;
}
}
}
if ( count_atom_out > 1 | | count_atom_in > 1 ) {
cb ( uri , PluginScanLogEntry : : Error , string_compose ( _ ( " Multiple Atom ports are not supported. Atom-in: %1, Atom-out: %2. " ) , count_atom_in , count_atom_out ) , false ) ;
continue ;
2012-08-27 00:08:45 -04:00
}
2011-05-15 19:10:13 -04:00
info - > n_inputs . set_audio (
lilv_plugin_get_num_ports_of_class (
2014-09-09 21:31:03 -04:00
p , world . lv2_InputPort , world . lv2_AudioPort , NULL ) ) ;
2011-05-15 19:10:13 -04:00
info - > n_inputs . set_midi (
lilv_plugin_get_num_ports_of_class (
2014-09-09 21:31:03 -04:00
p , world . lv2_InputPort , world . ev_EventPort , NULL )
2012-08-27 00:08:45 -04:00
+ count_midi_in ) ;
2011-05-15 19:10:13 -04:00
info - > n_outputs . set_audio (
lilv_plugin_get_num_ports_of_class (
2014-09-09 21:31:03 -04:00
p , world . lv2_OutputPort , world . lv2_AudioPort , NULL ) ) ;
2011-05-15 19:10:13 -04:00
info - > n_outputs . set_midi (
lilv_plugin_get_num_ports_of_class (
2014-09-09 21:31:03 -04:00
p , world . lv2_OutputPort , world . ev_EventPort , NULL )
2012-08-27 00:08:45 -04:00
+ count_midi_out ) ;
2011-05-15 19:10:13 -04:00
info - > unique_id = lilv_node_as_uri ( lilv_plugin_get_uri ( p ) ) ;
info - > index = 0 ; // Meaningless for LV2
2021-06-23 19:56:14 -04:00
cb ( uri , PluginScanLogEntry : : OK , string_compose (
_ ( " LV2 Ports: Atom-in: %1, Atom-out: %2, Audio-in: %3 Audio-out: %4 MIDI-in: %5 MIDI-out: %6 Ctrl-in: %7 Ctrl-out: %8 " ) ,
count_atom_in , count_atom_out ,
info - > n_inputs . n_audio ( ) , info - > n_outputs . n_audio ( ) ,
count_midi_in , count_midi_out ,
count_ctrl_in , count_ctrl_out ) , false ) ;
2011-05-15 19:10:13 -04:00
plugs - > push_back ( info ) ;
}
return plugs ;
}
2020-09-15 13:32:14 -04:00
bool
LV2PluginInfo : : is_instrument ( ) const
{
if ( _is_instrument ) {
return true ;
}
return PluginInfo : : is_instrument ( ) ;
}
bool
LV2PluginInfo : : is_utility ( ) const
{
if ( _is_utility ) {
return true ;
}
return PluginInfo : : is_utility ( ) ;
}
bool
LV2PluginInfo : : is_analyzer ( ) const
{
if ( _is_analyzer ) {
return true ;
}
return PluginInfo : : is_analyzer ( ) ;
}