View Issue Details

IDProjectCategoryView StatusLast Update
0007581ardourfeaturespublic2020-07-01 00:21
Reporterunfa Assigned Tox42  
PrioritynormalSeverityminorReproducibilityhave not tried
Status closedResolutionfixed 
Summary0007581: Track local plugins usage statistics and present a "most used" list to pick from
DescriptionI see that after a while of me using Ardour, my "Favorite" plugin list becomes really long. I don't really want to spend the time cleaning it up, but I'll have to at some point.

I thought that it'd be really useful if Ardour kept track of how frequently I use certain plugins and allowed me to sorry my plug-in list by that frequency.

It's greatly appreciate up the prices of me finding the plugins that I use body often - without me needing to manually organize such a list.

The two could be combined - it could sorry the favorites list by usage frequency.

I know that plugin lists departing places on thru own could be frustrating, but I've think I eager more time searching through my favourites list - I'm slowly stopping to use that at all because of faster to type the name in the plugin manager search box.
TagsNo tags attached.

Relationships

has duplicate 0008258 closedx42 recent plugins 

Activities

relascope

2018-03-23 23:00

reporter  

featurRecentPlugin.diff (6,758 bytes)   
diff --git a/gtk2_ardour/plugin_selector.cc b/gtk2_ardour/plugin_selector.cc
index 9796107f0..26d5e2f9f 100644
--- a/gtk2_ardour/plugin_selector.cc
+++ b/gtk2_ardour/plugin_selector.cc
@@ -796,6 +796,11 @@ PluginSelector::run ()
 				}
 			}
 			if (interested_object && !plugins.empty()) {
+				for  (vector<PluginPtr>::iterator j = plugins.begin(); j != plugins.end(); ++j) {
+					manager.add_recent((*j)->get_info());
+				}
+
+				_need_menu_rebuild = true;
 				finish = !interested_object->use_plugins (plugins);
 			}
 
@@ -1003,6 +1008,10 @@ PluginSelector::build_plugin_menu ()
 	items.push_back (MenuElem (_("Favorites"), *manage (favs)));
 
 	items.push_back (MenuElem (_("Plugin Manager..."), sigc::mem_fun (*this, &PluginSelector::show_manager)));
+
+	Gtk::Menu* recent = create_recent_menu(all_plugs);
+	items.push_back (MenuElem (_("Recent"), *manage (recent)));
+
 	items.push_back (SeparatorElem ());
 
 	Menu* by_creator = create_by_creator_menu(all_plugs);
@@ -1062,6 +1071,30 @@ PluginSelector::create_favs_menu (PluginInfoList& all_plugs)
 	return favs;
 }
 
+Gtk::Menu*
+PluginSelector::create_recent_menu(PluginInfoList& all_plugs)
+{
+	using namespace Menu_Helpers;
+
+	Menu* recents = new Menu();
+	recents->set_name("ArdourContextMenu");
+
+	PluginManager::RecentPluginList recent_plugs = manager.get_recents();
+
+	// plugins are sorted alphabetically to keep conformity with the Recent Session window
+	PluginMenuCompareByName cmp_by_name;
+	all_plugs.sort(cmp_by_name);
+	for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) {
+		if (std::find(recent_plugs.begin(), recent_plugs.end(), (*i)->unique_id) != recent_plugs.end()) {
+			string type = GetPluginTypeStr(*i);
+			MenuElem elem ((*i)->name + type, (sigc::bind (sigc::mem_fun (*this, &PluginSelector::plugin_chosen_from_menu), *i)));
+			elem.get_child()->set_use_underline (false);
+			recents->items().push_back (elem);
+		}
+	}
+	return recents;
+}
+
 Gtk::Menu*
 PluginSelector::create_by_creator_menu (ARDOUR::PluginInfoList& all_plugs)
 {
@@ -1170,6 +1203,8 @@ PluginSelector::plugin_chosen_from_menu (const PluginInfoPtr& pi)
 	if (p && interested_object) {
 		SelectedPlugins plugins;
 		plugins.push_back (p);
+		manager.add_recent(pi);
+		manager.PluginListChanged();
 		interested_object->use_plugins (plugins);
 	}
 
diff --git a/gtk2_ardour/plugin_selector.h b/gtk2_ardour/plugin_selector.h
index bba22950b..2dff879c2 100644
--- a/gtk2_ardour/plugin_selector.h
+++ b/gtk2_ardour/plugin_selector.h
@@ -180,6 +180,7 @@ private:
 	void plugin_status_changed ( ARDOUR::PluginType t, std::string unique_id, ARDOUR::PluginManager::PluginStatusType s );
 
 	Gtk::Menu* create_favs_menu (ARDOUR::PluginInfoList&);
+	Gtk::Menu* create_recent_menu (ARDOUR::PluginInfoList&);
 	Gtk::Menu* create_by_creator_menu (ARDOUR::PluginInfoList&);
 	Gtk::Menu* create_by_tags_menu (ARDOUR::PluginInfoList&);
 	void build_plugin_menu ();
diff --git a/libs/ardour/ardour/plugin_manager.h b/libs/ardour/ardour/plugin_manager.h
index a66e2d067..254d5f5de 100644
--- a/libs/ardour/ardour/plugin_manager.h
+++ b/libs/ardour/ardour/plugin_manager.h
@@ -24,6 +24,7 @@
 #include "libardour-config.h"
 #endif
 
+#include <deque>
 #include <list>
 #include <map>
 #include <string>
@@ -82,6 +83,11 @@ public:
 	void set_status (ARDOUR::PluginType type, std::string unique_id, PluginStatusType status);
 	PluginStatusType get_status (const PluginInfoPtr&) const;
 
+	typedef std::deque<std::string> RecentPluginList;
+
+	const RecentPluginList get_recents() const;
+	void add_recent(const PluginInfoPtr&);
+
 	void load_tags ();
 	void save_tags ();
 
@@ -167,6 +173,11 @@ private:
 	typedef std::set<PluginStatus> PluginStatusList;
 	PluginStatusList statuses;
 
+	void load_recents ();
+	void save_recents ();
+
+	RecentPluginList recents;
+
 	ARDOUR::PluginInfoList  _empty_plugin_info;
 	ARDOUR::PluginInfoList* _windows_vst_plugin_info;
 	ARDOUR::PluginInfoList*	_lxvst_plugin_info;
diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h
index 681c51a32..839467891 100644
--- a/libs/ardour/ardour/rc_configuration_vars.h
+++ b/libs/ardour/ardour/rc_configuration_vars.h
@@ -246,6 +246,7 @@ CONFIG_VARIABLE (int, vst_scan_timeout, "vst-scan-timeout", 1200) /* deciseconds
 CONFIG_VARIABLE (bool, discover_audio_units, "discover-audio-units", false)
 CONFIG_VARIABLE (bool, ask_replace_instrument, "ask-replace-instrument", true)
 CONFIG_VARIABLE (bool, ask_setup_instrument, "ask-setup-instrument", true)
+CONFIG_VARIABLE (uint32_t, max_recent_plugins, "max-recent-plugins", 10)
 
 /* custom user plugin paths */
 CONFIG_VARIABLE (std::string, plugin_path_vst, "plugin-path-vst", "@default@")
diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc
index 233f986a7..f42f821ec 100644
--- a/libs/ardour/plugin_manager.cc
+++ b/libs/ardour/plugin_manager.cc
@@ -176,6 +176,8 @@ PluginManager::PluginManager ()
 
 	load_tags ();
 
+	load_recents();
+
 	if ((s = getenv ("LADSPA_RDF_PATH"))){
 		lrdf_path = s;
 	}
@@ -1478,6 +1480,74 @@ PluginManager::set_status (PluginType t, string id, PluginStatusType status)
 	PluginStatusChanged (t, id, status); /* EMIT SIGNAL */
 }
 
+void
+PluginManager::load_recents()
+{
+	recents.clear();
+
+	std::string path;
+	find_file (plugin_metadata_search_path(), "plugin_recent", path);  //note: if no user folder is found, this will find the resources path
+	gchar *fbuf = NULL;
+	if (!g_file_get_contents (path.c_str(), &fbuf, NULL, NULL))  {
+		return;
+	}
+	stringstream ifs (fbuf);
+	g_free (fbuf);
+
+	std::string id;
+	char buf[1024];
+
+	while (ifs) {
+		ifs.getline (buf, sizeof (buf), '\n');
+		if (!ifs) {
+			break;
+		}
+
+		id = buf;
+		strip_whitespace_edges (id);
+
+		recents.push_back(id);
+	}
+}
+
+void
+PluginManager::save_recents()
+{
+	std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_recent");
+	stringstream ofs;
+
+	for (RecentPluginList::iterator i = recents.begin(); i != recents.end(); ++i) {
+		ofs << *i;
+		ofs << endl;
+	}
+	g_file_set_contents (path.c_str(), ofs.str().c_str(), -1, NULL);
+}
+
+void
+PluginManager::add_recent(const PluginInfoPtr & piptr)
+{
+	load_recents();
+
+	std::remove(recents.begin(), recents.end(), piptr->unique_id);
+
+	recents.push_front(piptr->unique_id);
+
+	// TODO ConfigValue
+	uint32_t max_recent_sessions = Config->get_max_recent_plugins();
+
+	if (recents.size() > max_recent_sessions) {
+		recents.erase(recents.begin()+max_recent_sessions, recents.end());
+	}
+
+	save_recents();
+}
+
+const PluginManager::RecentPluginList
+PluginManager::get_recents() const
+{
+	return recents;
+}
+
 PluginType
 PluginManager::to_generic_vst (const PluginType t)
 {
featurRecentPlugin.diff (6,758 bytes)   

relascope

2018-03-23 23:21

reporter   ~0020216

Attached an implementation (git diff) of the feature.



Implementation details:

Plugins sorted alphabetically to keep integrity with Recent-Session view. (stored per usage in the model).

New Configuration variable max-recent-plugins.

x42

2020-06-25 04:53

administrator   ~0024501

Ardour 6.0.169 now features a most-recently-used and a most-often-used list in the mixer-window's side-bar. Currently a Top-10.
The favorite plugin list there now also has a search/filter field (search by name or filter by tag).

Feedback is welcome, please test.

PS. The stats are saved in the config folder ~/config/ardour6/plugin_metadata/plugin_stats

unfa

2020-06-25 11:23

reporter   ~0024503

Awesome! Thank you!

x42

2020-06-25 21:10

administrator   ~0024507

Since 6.0-174 the "Top-10" is not also available in the context menu. Perhaps it should really be Top-25..

x42

2020-07-01 00:21

administrator   ~0024536

Since there is no further feedback, I'm marking this as resolved.

x42

2020-07-01 00:21

administrator   ~0024537

Issue has been closed automatically, by Trigger Close Plugin.
Feel free to re-open with additional information if you think the issue is not resolved.

Issue History

Date Modified Username Field Change
2018-03-01 16:45 unfa New Issue
2018-03-23 23:00 relascope File Added: featurRecentPlugin.diff
2018-03-23 23:21 relascope Note Added: 0020216
2020-06-23 20:11 x42 Relationship added has duplicate 0008258
2020-06-25 04:53 x42 Assigned To => x42
2020-06-25 04:53 x42 Status new => feedback
2020-06-25 04:53 x42 Note Added: 0024501
2020-06-25 11:23 unfa Note Added: 0024503
2020-06-25 11:23 unfa Status feedback => assigned
2020-06-25 21:10 x42 Note Added: 0024507
2020-07-01 00:21 x42 Status assigned => resolved
2020-07-01 00:21 x42 Resolution open => fixed
2020-07-01 00:21 x42 Note Added: 0024536
2020-07-01 00:21 x42 Note Added: 0024537
2020-07-01 00:21 x42 Status resolved => closed