From 2a6dcddcc513fa3ebc1aad4b2e5fede62277aba5 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 25 Nov 2010 22:12:03 +0000 Subject: Stub implementation of LV2 persist extension. git-svn-id: svn://localhost/ardour2/branches/3.0@8087 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/lv2_plugin.h | 2 + libs/ardour/ardour/session.h | 118 ++++++++++++++++++++-------------------- libs/ardour/ardour/uri_map.h | 2 +- libs/ardour/lv2_plugin.cc | 49 ++++++++++++++++- libs/ardour/session_state.cc | 13 +++++ libs/ardour/uri_map.cc | 35 ++++++------ 6 files changed, 141 insertions(+), 78 deletions(-) diff --git a/libs/ardour/ardour/lv2_plugin.h b/libs/ardour/ardour/lv2_plugin.h index 329af1151f..4335d65539 100644 --- a/libs/ardour/ardour/lv2_plugin.h +++ b/libs/ardour/ardour/lv2_plugin.h @@ -136,6 +136,7 @@ class LV2Plugin : public ARDOUR::Plugin float* _defaults; float* _latency_control_port; bool _was_activated; + bool _supports_persist; std::vector _port_is_input; std::map _port_indices; @@ -143,6 +144,7 @@ class LV2Plugin : public ARDOUR::Plugin LV2_DataAccess _data_access_extension_data; LV2_Feature _data_access_feature; LV2_Feature _instance_access_feature; + LV2_Feature _persist_feature; static URIMap _uri_map; static uint32_t _midi_event_type; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index d6dab480a7..ff69a9ebdf 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -128,24 +128,24 @@ extern void setup_enum_writer (); class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionList, public SessionEventManager { public: - enum RecordState { + enum RecordState { Disabled = 0, Enabled = 1, Recording = 2 }; - /* a new session might have non-empty mix_template, an existing session should always have an empty one. - the bus profile can be null if no master out bus is required. - */ + /* a new session might have non-empty mix_template, an existing session should always have an empty one. + the bus profile can be null if no master out bus is required. + */ Session (AudioEngine&, - const std::string& fullpath, - const std::string& snapshot_name, - BusProfile* bus_profile = 0, - std::string mix_template = ""); + const std::string& fullpath, + const std::string& snapshot_name, + BusProfile* bus_profile = 0, + std::string mix_template = ""); virtual ~Session (); - + std::string path() const { return _path; } std::string name() const { return _name; } std::string snap_name() const { return _current_snapshot_name; } @@ -175,10 +175,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi std::string dead_sound_dir () const; std::string automation_dir () const; std::string analysis_dir() const; - + std::string plugins_dir() const; + int ensure_subdirs (); - std::string peak_path (std::string) const; + std::string peak_path (std::string) const; std::string change_source_path_by_name (std::string oldpath, std::string oldname, std::string newname, bool destructive); @@ -233,7 +234,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi template void foreach_route (T *obj, void (T::*func)(boost::shared_ptr)); template void foreach_route (T *obj, void (T::*func)(Route&, A), A arg); - bool io_name_is_legal (const std::string&); + bool io_name_is_legal (const std::string&); boost::shared_ptr route_by_name (std::string); boost::shared_ptr route_by_id (PBD::ID); boost::shared_ptr route_by_remote_id (uint32_t id); @@ -282,8 +283,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi /** Emitted when anything about any of our route groups changes */ PBD::Signal0 RouteGroupChanged; - /* Step Editing status changed */ - PBD::Signal1 StepEditStatusChange; + /* Step Editing status changed */ + PBD::Signal1 StepEditStatusChange; void queue_event (SessionEvent*); @@ -395,7 +396,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void remove_route_group (RouteGroup&); RouteGroup* route_group_by_name (std::string); - RouteGroup& all_route_group() const; + RouteGroup& all_route_group() const; PBD::Signal1 route_group_added; PBD::Signal0 route_group_removed; @@ -429,7 +430,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi /* Time */ - framepos_t transport_frame () const {return _transport_frame; } + framepos_t transport_frame () const {return _transport_frame; } framepos_t audible_frame () const; framepos_t requested_return_frame() const { return _requested_return_frame; } @@ -468,9 +469,9 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi static PBD::Signal1 EndTimeChanged; static PBD::Signal0 TimecodeOffsetChanged; - std::vector get_available_sync_options() const; + std::vector get_available_sync_options() const; void request_sync_source (Slave*); - bool synced_to_jack() const { return config.get_external_sync() && config.get_sync_source() == JACK; } + bool synced_to_jack() const { return config.get_external_sync() && config.get_sync_source() == JACK; } double transport_speed() const { return _transport_speed; } bool transport_stopped() const { return _transport_speed == 0.0f; } @@ -535,10 +536,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi */ static PBD::Signal0 AskAboutPendingState; - boost::shared_ptr create_audio_source_for_session (size_t, std::string const &, uint32_t, - bool destructive, bool as_stub = false); - - boost::shared_ptr create_midi_source_for_session (Track*, std::string const &, bool as_stub = false); + boost::shared_ptr create_audio_source_for_session ( + size_t, std::string const &, uint32_t, bool destructive, bool as_stub = false); + + boost::shared_ptr create_midi_source_for_session ( + Track*, std::string const &, bool as_stub = false); boost::shared_ptr source_by_id (const PBD::ID&); boost::shared_ptr source_by_path_and_channel (const std::string&, uint16_t); @@ -586,7 +588,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi bool soloing() const { return _non_soloed_outs_muted; } bool listening() const { return _listen_cnt > 0; } - bool solo_isolated() const { return _solo_isolated_cnt > 0; } + bool solo_isolated() const { return _solo_isolated_cnt > 0; } static const SessionEvent::RTeventCallback rt_cleanup; @@ -595,11 +597,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void set_mute (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); void set_listen (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); void set_record_enabled (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); - void set_solo_isolated (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); + void set_solo_isolated (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); PBD::Signal1 SoloActive; PBD::Signal0 SoloChanged; - PBD::Signal0 IsolatedChanged; + PBD::Signal0 IsolatedChanged; /* control/master out */ @@ -724,9 +726,9 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi static PBD::Signal0 SendFeedback; - /* Speakers */ + /* Speakers */ - VBAPSpeakers& get_speakers (); + VBAPSpeakers& get_speakers (); /* Controllables */ @@ -785,24 +787,24 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi PBD::Signal0 RouteOrderKeyChanged; - bool step_editing() const { return (_step_editors > 0); } + bool step_editing() const { return (_step_editors > 0); } void request_suspend_timecode_transmission (); void request_resume_timecode_transmission (); bool timecode_transmission_suspended () const; - std::string source_search_path(DataType) const; - void ensure_search_path_includes (const std::string& path, DataType type); - - /* handlers can return an integer value: - 0: config.set_audio_search_path() or config.set_midi_search_path() was used - to modify the search path and we should try to find it again. - 1: quit entire session load - 2: as 0, but don't ask about other missing files - 3: don't ask about other missing files, and just mark this one missing - -1: just mark this one missing - any other value: as -1 - */ + std::string source_search_path(DataType) const; + void ensure_search_path_includes (const std::string& path, DataType type); + + /* handlers can return an integer value: + 0: config.set_audio_search_path() or config.set_midi_search_path() was used + to modify the search path and we should try to find it again. + 1: quit entire session load + 2: as 0, but don't ask about other missing files + 3: don't ask about other missing files, and just mark this one missing + -1: just mark this one missing + any other value: as -1 + */ static PBD::Signal3 MissingFile; /** Emitted when the session wants Ardour to quit */ @@ -893,8 +895,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void unblock_processing() { g_atomic_int_set (&processing_prohibited, 0); } bool processing_blocked() const { return g_atomic_int_get (&processing_prohibited); } - Glib::Mutex process_thread_lock; - std::list process_threads; + Glib::Mutex process_thread_lock; + std::list process_threads; /* slave tracking */ @@ -914,11 +916,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void track_slave_state(float slave_speed, nframes_t slave_transport_frame, nframes_t this_delta); void follow_slave_silently(nframes_t nframes, float slave_speed); - void switch_to_sync_source (SyncSource); /* !RT context */ - void drop_sync_source (); /* !RT context */ - void use_sync_source (Slave*); /* RT context */ + void switch_to_sync_source (SyncSource); /* !RT context */ + void drop_sync_source (); /* !RT context */ + void use_sync_source (Slave*); /* RT context */ - bool post_export_sync; + bool post_export_sync; nframes_t post_export_position; bool _exporting; @@ -967,7 +969,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi std::string _path; std::string _name; - bool _is_new; + bool _is_new; bool session_send_mtc; bool session_midi_feedback; bool play_loop; @@ -1039,8 +1041,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void set_post_transport_work (PostTransportWork ptw) { g_atomic_int_set (&_post_transport_work, (gint) ptw); } void add_post_transport_work (PostTransportWork ptw); - void schedule_playback_buffering_adjustment (); - void schedule_capture_buffering_adjustment (); + void schedule_playback_buffering_adjustment (); + void schedule_capture_buffering_adjustment (); uint32_t cumulative_rf_motion; uint32_t rf_scale; @@ -1170,11 +1172,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void overwrite_some_buffers (Track *); void flush_all_inserts (); int micro_locate (nframes_t distance); - void locate (framepos_t, bool with_roll, bool with_flush, bool with_loop=false, bool force=false, bool with_mmc=true); - void start_locate (framepos_t, bool with_roll, bool with_flush, bool with_loop=false, bool force=false); + void locate (framepos_t, bool with_roll, bool with_flush, bool with_loop=false, bool force=false, bool with_mmc=true); + void start_locate (framepos_t, bool with_roll, bool with_flush, bool with_loop=false, bool force=false); void force_locate (framepos_t frame, bool with_roll = false); void set_track_speed (Track *, double speed); - void set_transport_speed (double speed, bool abort = false, bool clear_state = false); + void set_transport_speed (double speed, bool abort = false, bool clear_state = false); void stop_transport (bool abort = false, bool clear_state = false); void start_transport (); void realtime_stop (bool abort, bool clear_state); @@ -1195,7 +1197,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi int load_route_groups (const XMLNode&, int); std::list _route_groups; - RouteGroup* _all_route_group; + RouteGroup* _all_route_group; /* routes stuff */ @@ -1330,7 +1332,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi uint32_t _total_free_4k_blocks; Glib::Mutex space_lock; - bool no_questions_about_missing_files; + bool no_questions_about_missing_files; std::string get_best_session_directory_for_new_source (); @@ -1453,12 +1455,12 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void add_session_range_location (nframes_t, nframes_t); void setup_midi_machine_control (); - void cleanup_stubfiles (); + void cleanup_stubfiles (); void route_order_key_changed (); - void step_edit_status_change (bool); - uint32_t _step_editors; + void step_edit_status_change (bool); + uint32_t _step_editors; /** true if timecode transmission by the transport is suspended, otherwise false */ mutable gint _suspend_timecode_transmission; @@ -1468,7 +1470,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void start_time_changed (framepos_t); void end_time_changed (framepos_t); - VBAPSpeakers* _speakers; + VBAPSpeakers* _speakers; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/uri_map.h b/libs/ardour/ardour/uri_map.h index c62ec6bfc4..59de9b3dfd 100644 --- a/libs/ardour/ardour/uri_map.h +++ b/libs/ardour/ardour/uri_map.h @@ -1,6 +1,6 @@ /* Copyright (C) 2009 Paul Davis - Author: Dave Robillard + Author: David Robillard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index b6349d012f..0bee37d2be 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -25,6 +25,8 @@ #include #include +#include + #include "pbd/compose.h" #include "pbd/error.h" #include "pbd/pathscanner.h" @@ -42,6 +44,8 @@ #include "i18n.h" #include +#include "lv2ext/lv2_persist.h" + using namespace std; using namespace ARDOUR; using namespace PBD; @@ -83,14 +87,21 @@ LV2Plugin::init (LV2World& world, SLV2Plugin plugin, nframes_t rate) _latency_control_port = 0; _was_activated = false; + SLV2Value persist_uri = slv2_value_new_uri(_world.world, "http://lv2plug.in/ns/ext/persist"); + _supports_persist = slv2_plugin_has_feature(plugin, persist_uri); + slv2_value_free(persist_uri); + _instance_access_feature.URI = "http://lv2plug.in/ns/ext/instance-access"; _data_access_feature.URI = "http://lv2plug.in/ns/ext/data-access"; + _persist_feature.URI = "http://lv2plug.in/ns/ext/persist"; + _persist_feature.data = NULL; - _features = (LV2_Feature**)malloc(sizeof(LV2_Feature*) * 4); + _features = (LV2_Feature**)malloc(sizeof(LV2_Feature*) * 5); _features[0] = &_instance_access_feature; _features[1] = &_data_access_feature; - _features[2] = _uri_map.feature(); - _features[3] = NULL; + _features[2] = &_persist_feature; + _features[3] = _uri_map.feature(); + _features[4] = NULL; _instance = slv2_plugin_instantiate(plugin, rate, _features); _name = slv2_plugin_get_name(plugin); @@ -271,6 +282,19 @@ LV2Plugin::nth_parameter (uint32_t n, bool& ok) const return 0; } +struct LV2Value { void* value; uint32_t type; }; +typedef std::map< std::string, LV2Value > LV2State; + +static void +lv2_persist_store_callback(void* callback_data, + const char* key, + const void* value, + size_t size, + uint32_t type) +{ + cout << "LV2 PERSIST STORE " << key << " = " << value << " :: " << type << endl; +} + XMLNode& LV2Plugin::get_state() { @@ -296,6 +320,25 @@ LV2Plugin::get_state() } } + if (_supports_persist) { + // Create state directory for this plugin instance + const std::string state_path = Glib::build_filename(_session.plugins_dir(), _id.to_s()); + cout << "LV2 plugin state path " << state_path << endl; + + // Get LV2 Persist extension data from plugin instance + LV2_Persist* persist = (LV2_Persist*)slv2_instance_get_extension_data( + _instance, "http://lv2plug.in/ns/ext/persist"); + if (!persist) { + warning << string_compose( + _("Plugin \"%1\% failed to return LV2 persist data"), + unique_id()); + return *root; // FIXME: Possibly inconsistent state + } + + LV2State state; + persist->save(_instance, lv2_persist_store_callback, &state); + } + return *root; } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index cdb1af9596..6ceeeb599c 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -500,6 +500,13 @@ Session::ensure_subdirs () return -1; } + dir = plugins_dir (); + + if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) { + error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg; + return -1; + } + return 0; } @@ -2177,6 +2184,12 @@ Session::analysis_dir () const return Glib::build_filename (_path, "analysis"); } +string +Session::plugins_dir () const +{ + return Glib::build_filename (_path, "plugins"); +} + int Session::load_bundles (XMLNode const & node) { diff --git a/libs/ardour/uri_map.cc b/libs/ardour/uri_map.cc index 2c2861e385..a551a5b5a4 100644 --- a/libs/ardour/uri_map.cc +++ b/libs/ardour/uri_map.cc @@ -1,19 +1,22 @@ -/* This file is part of Ingen. - * Copyright (C) 2008 Dave Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ +/* + Copyright (C) 2008-2010 Paul Davis + Author: David Robillard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ #include #include -- cgit v1.2.3