fix crash when copy'ing latent plugins
[ardour.git] / libs / ardour / midi_patch_manager.cc
index f2d964bb77ba0acb2554a40401c5ea11ee76843e..8a6d8dfd100a5a88be14a8bfc47b6cb076b5e250 100644 (file)
 #include "pbd/file_utils.h"
 #include "pbd/error.h"
 
-#include "ardour/session.h"
-#include "ardour/session_directory.h"
 #include "ardour/midi_patch_manager.h"
 
-#include "ardour/midi_patch_search_path.h"
+#include "ardour/search_paths.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
@@ -43,108 +41,153 @@ MidiPatchManager* MidiPatchManager::_manager = 0;
 
 MidiPatchManager::MidiPatchManager ()
 {
-       refresh ();
+       add_search_path(midi_patch_search_path ());
 }
 
 void
-MidiPatchManager::set_session (Session* s)
+MidiPatchManager::add_search_path (const Searchpath& search_path)
 {
-       SessionHandlePtr::set_session (s);
-       add_session_patches ();
+       for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
+
+               if (_search_path.contains(*i)) {
+                       // already processed files from this path
+                       continue;
+               }
+
+               if (!Glib::file_test (*i, Glib::FILE_TEST_EXISTS)) {
+                       continue;
+               }
+
+               if (!Glib::file_test (*i, Glib::FILE_TEST_IS_DIR)) {
+                       continue;
+               }
+
+               add_midnam_files_from_directory (*i);
+
+               _search_path.add_directory (*i);
+       }
 }
 
 void
-MidiPatchManager::add_session_patches ()
+MidiPatchManager::add_midnam_files_from_directory(const std::string& directory_path)
 {
-       if (!_session) {
-               return;
-       }
-       
-       std::string path_to_patches = _session->session_directory().midi_patch_path();
+       vector<std::string> result;
+       find_files_matching_pattern (result, directory_path, "*.midnam");
 
-       if (!Glib::file_test (path_to_patches, Glib::FILE_TEST_EXISTS)) {
-               return;
-       }
+       info << string_compose(
+                       P_("Loading %1 MIDI patch from %2", "Loading %1 MIDI patches from %2", result.size()),
+                       result.size(), directory_path)
+            << endmsg;
 
-       assert (Glib::file_test (path_to_patches, Glib::FILE_TEST_IS_DIR));
+       for (vector<std::string>::const_iterator i = result.begin(); i != result.end(); ++i) {
+               add_midi_name_document (*i);
+       }
+}
 
-       Glib::PatternSpec pattern(string("*.midnam"));
-       vector<std::string> result;
+void
+MidiPatchManager::remove_search_path (const Searchpath& search_path)
+{
+       for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
 
-       find_matching_files_in_directory (path_to_patches, pattern, result);
-
-       info << "Loading " << result.size() << " MIDI patches from " << path_to_patches << endmsg;
-
-       for (vector<std::string>::iterator i = result.begin(); i != result.end(); ++i) {
-               boost::shared_ptr<MIDINameDocument> document(new MIDINameDocument(*i));
-               for (MIDINameDocument::MasterDeviceNamesList::const_iterator device =
-                                       document->master_device_names_by_model().begin();
-                               device != document->master_device_names_by_model().end();
-                               ++device) {
-                       //cerr << "got model " << device->first << endl;
-                       // have access to the documents by model name
-                       _documents[device->first] = document;
-                       // build a list of all master devices from all documents
-                       _master_devices_by_model[device->first] = device->second;
-                       _all_models.insert(device->first);
-
-                       // make sure there are no double model names
-                       // TODO: handle this gracefully.
-                       assert(_documents.count(device->first) == 1);
-                       assert(_master_devices_by_model.count(device->first) == 1);
+               if (!_search_path.contains(*i)) {
+                       continue;
                }
+
+               remove_midnam_files_from_directory(*i);
+
+               _search_path.remove_directory (*i);
        }
 }
 
 void
-MidiPatchManager::refresh()
+MidiPatchManager::remove_midnam_files_from_directory(const std::string& directory_path)
 {
-       _documents.clear();
-       _master_devices_by_model.clear();
-       _all_models.clear();
-
-       Searchpath search_path = midi_patch_search_path ();
-       Glib::PatternSpec pattern (string("*.midnam"));
        vector<std::string> result;
+       find_files_matching_pattern (result, directory_path, "*.midnam");
 
-       find_matching_files_in_search_path (search_path, pattern, result);
+       info << string_compose(
+                       P_("Unloading %1 MIDI patch from %2", "Unloading %1 MIDI patches from %2", result.size()),
+                       result.size(), directory_path)
+            << endmsg;
 
-       info << "Loading " << result.size() << " MIDI patches from " << search_path.to_string() << endmsg;
+       for (vector<std::string>::const_iterator i = result.begin(); i != result.end(); ++i) {
+               remove_midi_name_document (*i);
+       }
+}
 
-       for (vector<std::string>::iterator i = result.begin(); i != result.end(); ++i) {
-               boost::shared_ptr<MIDINameDocument> document;
-               try {
-                       document = boost::shared_ptr<MIDINameDocument>(new MIDINameDocument(*i));
-               } catch (...) {
-                       error << "Error parsing MIDI patch file " << *i << endmsg;
+bool
+MidiPatchManager::add_midi_name_document (const std::string& file_path)
+{
+       boost::shared_ptr<MIDINameDocument> document;
+       try {
+               document = boost::shared_ptr<MIDINameDocument>(new MIDINameDocument(file_path));
+       }
+       catch (...) {
+               error << string_compose(_("Error parsing MIDI patch file %1"), file_path)
+                     << endmsg;
+               return false;
+       }
+       for (MIDINameDocument::MasterDeviceNamesList::const_iterator device =
+                document->master_device_names_by_model().begin();
+            device != document->master_device_names_by_model().end();
+            ++device) {
+               if (_documents.find(device->first) != _documents.end()) {
+                       warning << string_compose(_("Duplicate MIDI device `%1' in `%2' ignored"),
+                                                 device->first,
+                                                 file_path) << endmsg;
                        continue;
                }
-               for (MIDINameDocument::MasterDeviceNamesList::const_iterator device =
-                            document->master_device_names_by_model().begin();
-                    device != document->master_device_names_by_model().end();
-                    ++device) {
-                       if (_documents.find(device->first) != _documents.end()) {
-                               warning << string_compose(_("Duplicate MIDI device `%1' in `%2' ignored"),
-                                                         device->first, *i)
-                                       << endmsg;
-                               continue;
-                       }
-                                                     
-                       _documents[device->first]               = document;
-                       _master_devices_by_model[device->first] = device->second;
 
-                       _all_models.insert(device->first);
+               _documents[device->first] = document;
+               _master_devices_by_model[device->first] = device->second;
+
+               _all_models.insert(device->first);
+               const std::string& manufacturer = device->second->manufacturer();
+               if (_devices_by_manufacturer.find(manufacturer) ==
+                   _devices_by_manufacturer.end()) {
+                       MIDINameDocument::MasterDeviceNamesList empty;
+                       _devices_by_manufacturer.insert(std::make_pair(manufacturer, empty));
                }
-       }
+               _devices_by_manufacturer[manufacturer].insert(
+                   std::make_pair(device->first, device->second));
 
-       if (_session) {
-               add_session_patches ();
+               // TODO: handle this gracefully.
+               assert(_documents.count(device->first) == 1);
+               assert(_master_devices_by_model.count(device->first) == 1);
        }
+       return true;
 }
 
-void
-MidiPatchManager::session_going_away ()
+bool
+MidiPatchManager::remove_midi_name_document (const std::string& file_path)
 {
-       SessionHandlePtr::session_going_away ();
-       refresh ();
+       bool removed = false;
+       for (MidiNameDocuments::iterator i = _documents.begin(); i != _documents.end();) {
+               if (i->second->file_path() == file_path) {
+
+                       boost::shared_ptr<MIDINameDocument> document = i->second;
+
+                       info << string_compose(_("Removing MIDI patch file %1"), file_path) << endmsg;
+
+                       _documents.erase(i++);
+
+                       for (MIDINameDocument::MasterDeviceNamesList::const_iterator device =
+                                document->master_device_names_by_model().begin();
+                            device != document->master_device_names_by_model().end();
+                            ++device) {
+
+                               _master_devices_by_model.erase(device->first);
+
+                               _all_models.erase(device->first);
+
+                               const std::string& manufacturer = device->second->manufacturer();
+
+                               _devices_by_manufacturer[manufacturer].erase(device->first);
+                       }
+                       removed = true;
+               } else {
+                       ++i;
+               }
+       }
+       return removed;
 }