From 0e084fe9c9df9bc55f68b204a4f81d9eb16a057a Mon Sep 17 00:00:00 2001 From: Nikolaus Gullotta Date: Wed, 24 Jun 2020 08:16:28 -0500 Subject: [PATCH] Re-add mixer_snapshot_manager --- libs/ardour/ardour/mixer_snapshot_manager.h | 85 +++++ libs/ardour/mixer_snapshot_manager.cc | 341 ++++++++++++++++++++ libs/ardour/wscript | 1 + 3 files changed, 427 insertions(+) create mode 100644 libs/ardour/ardour/mixer_snapshot_manager.h create mode 100644 libs/ardour/mixer_snapshot_manager.cc diff --git a/libs/ardour/ardour/mixer_snapshot_manager.h b/libs/ardour/ardour/mixer_snapshot_manager.h new file mode 100644 index 0000000000..3e0afd1e4c --- /dev/null +++ b/libs/ardour/ardour/mixer_snapshot_manager.h @@ -0,0 +1,85 @@ +/* + Copyright (C) 2019 Nikolaus Gullotta + + 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. +*/ + +#ifndef __ardour_mixer_snapshot_manager_h__ +#define __ardour_mixer_snapshot_manager_h__ + +#include +#include +#include + +#include + +#include "ardour/mixer_snapshot.h" +#include "ardour/session.h" +#include "ardour/template_utils.h" + +#include "pbd/signals.h" + +namespace ARDOUR { +typedef std::set SnapshotList; + +class LIBARDOUR_API MixerSnapshotManager : public boost::noncopyable +{ +public: + + MixerSnapshotManager (ARDOUR::Session*); + ~MixerSnapshotManager() {} + + void create_snapshot(const std::string& label, const std::string& desc, RouteList& rl, bool global); + void create_snapshot(const std::string& label, const std::string& desc, const std::string& from_path, bool global); + + void find_templates(std::vector&, bool); + + bool rename(MixerSnapshot*, const std::string&); + bool remove(MixerSnapshot*); + + bool erase(ARDOUR::MixerSnapshot*); + bool move(ARDOUR::MixerSnapshot*, const std::string&); + + bool promote(ARDOUR::MixerSnapshot*); + bool demote(ARDOUR::MixerSnapshot*); + + MixerSnapshot* get_snapshot_by_name(const std::string&, bool); + + std::string get_global_path() {return _global_path;} + std::string get_local_path() {return _local_path;} + + ARDOUR::SnapshotList get_global_snapshots() {return _global_snapshots;} + ARDOUR::SnapshotList get_local_snapshots() {return _local_snapshots;} + + void refresh(); + void clear() { _global_snapshots.clear(); _local_snapshots.clear(); }; + + PBD::Signal1 PromotedSnapshot; + PBD::Signal1 CreatedSnapshot; + PBD::Signal0 RemovedSnapshot; + PBD::Signal0 RenamedSnapshot; +private: + void ensure_snapshot_dir(bool global); + std::string _global_path; + std::string _local_path; + + ARDOUR::SnapshotList _global_snapshots; + ARDOUR::SnapshotList _local_snapshots; + + ARDOUR::Session* _session; +}; +} /* namespace ARDOUR */ + +#endif /* __ardour_mixer_snapshot_manager_h__ */ \ No newline at end of file diff --git a/libs/ardour/mixer_snapshot_manager.cc b/libs/ardour/mixer_snapshot_manager.cc new file mode 100644 index 0000000000..e6c885429f --- /dev/null +++ b/libs/ardour/mixer_snapshot_manager.cc @@ -0,0 +1,341 @@ +/* + Copyright (C) 2019 Nikolaus Gullotta + + 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. +*/ + +#include +#include +#include + +#include "ardour/directory_names.h" +#include "ardour/filename_extensions.h" +#include "ardour/filesystem_paths.h" +#include "ardour/mixer_snapshot_manager.h" +#include "ardour/search_paths.h" +#include "ardour/session_directory.h" + +#include "pbd/basename.h" +#include "pbd/file_utils.h" +#include "pbd/gstdio_compat.h" + +using namespace ARDOUR; +using namespace PBD; +using namespace std; + +MixerSnapshotManager::MixerSnapshotManager (Session* s) +{ + if(!s) { + throw failed_constructor(); + } + + _session = s; + + _global_path = user_route_template_directory(); + _local_path = Glib::build_filename(_session->session_directory().root_path(), route_templates_dir_name); + + refresh(); +} + +void MixerSnapshotManager::ensure_snapshot_dir(bool global) +{ + const string path = global ? _global_path : _local_path; + if(!Glib::file_test(path.c_str(), Glib::FILE_TEST_EXISTS & Glib::FILE_TEST_IS_DIR)) { + ::g_mkdir(path.c_str(), 0775); + } +} + +void MixerSnapshotManager::find_templates(vector& template_info, bool global) +{ + if(!_session) { + return; + } + + if(!global) { + Searchpath searchpath (_session->session_directory().root_path()); + searchpath.add_subdirectory_to_paths(route_templates_dir_name); + + vector files; + const string pattern = "*" + string(template_suffix); + find_files_matching_pattern(files, searchpath, pattern); + + if(!files.empty()) { + for(vector::const_iterator it = files.begin(); it != files.end(); it++) { + const string path = (*it); + const string name = basename_nosuffix(path); + + MixerSnapshot* snapshot = new MixerSnapshot(path); + const string description = snapshot->get_description(); + const string modified = snapshot->get_last_modified_with(); + + TemplateInfo info {name, path, description, modified}; + template_info.push_back(info); + delete snapshot; + } + } + } else if(global) { + find_route_templates(template_info); + } +} + +void MixerSnapshotManager::refresh() +{ + clear(); + + vector global_templates, local_templates; + find_templates(global_templates, true); + find_templates(local_templates, false); + + vector::const_iterator it; + if(!global_templates.empty()) { + for(it = global_templates.begin(); it != global_templates.end(); it++) { + TemplateInfo info = (*it); + + MixerSnapshot* snap = new MixerSnapshot(info.path); + _global_snapshots.insert(snap); + } + } + + if(!local_templates.empty()) { + for(it = local_templates.begin(); it != local_templates.end(); it++) { + TemplateInfo info = (*it); + + MixerSnapshot* snap = new MixerSnapshot(info.path); + _local_snapshots.insert(snap); + } + } +} + +bool MixerSnapshotManager::erase(MixerSnapshot* snapshot) { + if(!snapshot) { + return false; + } + + set::const_iterator iter; + + iter = _global_snapshots.find(snapshot); + if(iter != _global_snapshots.end()) { + delete (*iter); + _global_snapshots.erase(iter); + return true; + } + + iter = _local_snapshots.find(snapshot); + if(iter != _local_snapshots.end()) { + delete (*iter); + _local_snapshots.erase(iter); + return true; + } + return false; +} + +bool MixerSnapshotManager::move(MixerSnapshot* snapshot, const string& to_path) { + if(!snapshot) { + return false; + } + + const string path = snapshot->get_path(); + if(Glib::file_test(path.c_str(), Glib::FILE_TEST_EXISTS)) { + const string dir = Glib::path_get_dirname(path); + + const string file = snapshot->get_label() + string(template_suffix); + const string new_path = Glib::build_filename(to_path, file); + + //already there + if (Glib::file_test(new_path.c_str(), Glib::FILE_TEST_EXISTS)) { + return false; + } + + //local snapshots have no description + if(to_path == _local_path) { + snapshot->set_description(""); + } + //write this to the new path + snapshot->write(to_path); + + snapshot->set_path(new_path); + return true; + } + return false; +} + +bool MixerSnapshotManager::promote(MixerSnapshot* snapshot) { + if(!snapshot) { + return false; + } + + //build the new file path + const string file = snapshot->get_label() + string(template_suffix); + const string path = Glib::build_filename(_global_path, file); + + //write the snapshot to the new path, and erase the old one + if(move(snapshot, _global_path) && erase(snapshot)) { + //insert the new snapshot + _global_snapshots.insert(new MixerSnapshot(path)); + PromotedSnapshot(*_global_snapshots.end()); /* EMIT SIGNAL */ + return true; + } + + return false; +} + +bool MixerSnapshotManager::demote(MixerSnapshot* snapshot) { + if(!snapshot) { + return false; + } + + //build the new file path + const string file = snapshot->get_label() + string(template_suffix); + const string path = Glib::build_filename(_local_path, file); + + //write the snapshot to the new path, and erase the old one + if(move(snapshot, _local_path) && erase(snapshot)) { + //insert the new snapshot + _local_snapshots.insert(new MixerSnapshot(path)); + return true; + } + + return false; +} + +bool MixerSnapshotManager::rename(MixerSnapshot* snapshot, const string& new_name) { + if(!snapshot) { + return false; + } + + if(new_name.empty()) { + return false; + } + + snapshot->set_label(new_name); + + const string path = snapshot->get_path(); + const string dir = Glib::path_get_dirname(path); + + if (move(snapshot, dir)) { + RenamedSnapshot(); /* EMIT SIGNAL */ + ::g_remove(path.c_str()); + //remove the old file + return true; + } + + return false; +} + +bool MixerSnapshotManager::remove(MixerSnapshot* snapshot) { + if(!snapshot) { + return false; + } + + const string path = snapshot->get_path(); + if (Glib::file_test(path.c_str(), Glib::FILE_TEST_EXISTS)) { + if(erase(snapshot)) { + ::g_remove(path.c_str()); + RemovedSnapshot(); /* EMIT SIGNAL */ + return true; + } + } + + return false; +} + +MixerSnapshot* MixerSnapshotManager::get_snapshot_by_name(const string& name, bool global) +{ + set snapshots_list = global ? _global_snapshots : _local_snapshots; + MixerSnapshot* snapshot; + + set::iterator it; + for(it = snapshots_list.begin(); it != snapshots_list.end(); it++) { + if((*it)->get_label() == name) { + snapshot = (*it); + break; + } + } + return snapshot; +} + +void MixerSnapshotManager::create_snapshot(const string& label, const string& desc, RouteList& rl, bool global) +{ + ensure_snapshot_dir(global); + const string path = global ? _global_path : _local_path; + MixerSnapshot* snapshot = new MixerSnapshot(); + + snapshot->set_description(desc); + + if(!rl.empty()) { + //just this routelist + snapshot->snap(rl); + } else { + //the whole session + snapshot->snap(); + } + + //is this even possible? either way, sanity check + if(snapshot->empty()) { + delete snapshot; + return; + } + + snapshot->set_label(label); + snapshot->write(path); + + const string full_path = Glib::build_filename(path, snapshot->get_label() + string(template_suffix)); + snapshot->set_path(full_path); + + MixerSnapshot* old_snapshot = get_snapshot_by_name(snapshot->get_label(), global); + set& snapshots_list = global ? _global_snapshots : _local_snapshots; + set::iterator iter = snapshots_list.find(old_snapshot); + + //remove it from it's set + if(iter != snapshots_list.end()) { + delete (*iter); + snapshots_list.erase(iter); + } + //and insert the new one + snapshots_list.insert(snapshot); + CreatedSnapshot(snapshot); /* EMIT SIGNAL */ +} + +void MixerSnapshotManager::create_snapshot(const string& label, const string& desc, const string& from_path, bool global) +{ + ensure_snapshot_dir(global); + const string path = global ? _global_path : _local_path; + MixerSnapshot* snapshot = new MixerSnapshot(from_path); + + //clearly from_path doesn't point to a parsable state file + if(snapshot->empty()) { + delete snapshot; + return; + } + + snapshot->set_label(label); + snapshot->write(path); + + const string full_path = Glib::build_filename(path, snapshot->get_label() + string(template_suffix)); + snapshot->set_path(full_path); + + MixerSnapshot* old_snapshot = get_snapshot_by_name(snapshot->get_label(), global); + set& snapshots_list = global ? _global_snapshots : _local_snapshots; + set::iterator iter = snapshots_list.find(old_snapshot); + + //remove it from it's set + if(iter != snapshots_list.end()) { + delete (*iter); + snapshots_list.erase(iter); + } + //and insert the new one + snapshots_list.insert(snapshot); + CreatedSnapshot(snapshot); /* EMIT SIGNAL */ +} diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 515215525c..2c0ffd4cfc 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -147,6 +147,7 @@ libardour_sources = [ 'midiport_manager.cc', 'mix.cc', 'mixer_snapshot.cc', + 'mixer_snapshot_manager.cc', 'mode.cc', 'monitor_control.cc', 'monitor_processor.cc',