use condvar and exception-proof mutex for chain swaps in graph
[ardour.git] / libs / midi++2 / midnam_patch.cc
index c23901d7213ebb4ba66d9a9a6abb3d678b2349c7..b9a810ba588a7b03f0edd47a7140cbca909db099 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2008 Hans Baier 
+    Copyright (C) 2008 Hans Baier
 
     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
     $Id$
 */
 
-#include "midi++/midnam_patch.h"
 #include <algorithm>
-
 #include <iostream>
 
+#include "midi++/midnam_patch.h"
+#include "pbd/convert.h"
+
 using namespace std;
 
 namespace MIDI
@@ -37,29 +38,70 @@ Patch::get_state (void)
        XMLNode* node = new XMLNode("Patch");
        node->add_property("Number", _number);
        node->add_property("Name",   _name);
+       /*
+       typedef std::list< boost::shared_ptr< Evoral::MIDIEvent<double> > > PatchMidiCommands;
        XMLNode* commands = node->add_child("PatchMIDICommands");
        for (PatchMidiCommands::const_iterator event = _patch_midi_commands.begin();
            event != _patch_midi_commands.end();
            ++event) {
                commands->add_child_copy(*((((Evoral::MIDIEvent&)*event)).to_xml()));
        }
+       */
 
        return *node;
 }
 
+void initialize_primary_key_from_commands (PatchPrimaryKey& id, const XMLNode* node)
+{
+       const XMLNodeList events = node->children();
+       for (XMLNodeList::const_iterator i = events.begin(); i != events.end(); ++i) {
+               XMLNode* node = *i;
+               if (node->name() == "ControlChange") {
+                       string control = node->property("Control")->value();
+                       assert(control != "");
+                       string value = node->property("Value")->value();
+                       assert(value != "");
+
+                       if (control == "0") {
+                               id.msb = PBD::atoi(value);
+                       } else if (control == "32") {
+                               id.lsb = PBD::atoi(value);
+                       }
+               } else if (node->name() == "ProgramChange") {
+                       string number = node->property("Number")->value();
+                       assert(number != "");
+                       id.program_number = PBD::atoi(number);
+               }
+       }
+}
+
+
 int
-Patch::set_state (const XMLNode& node)
+Patch::set_state (const XMLNode& node, int /*version*/)
 {
        assert(node.name() == "Patch");
        _number = node.property("Number")->value();
        _name   = node.property("Name")->value();
        XMLNode* commands = node.child("PatchMIDICommands");
-       assert(commands);
-       const XMLNodeList events = commands->children();
-       for (XMLNodeList::const_iterator i = events.begin(); i != events.end(); ++i) {
-               _patch_midi_commands.push_back(*(new Evoral::MIDIEvent(*(*i))));
+
+       if (commands) {
+               initialize_primary_key_from_commands(_id, commands);
+       } else {
+               string program_change = node.property("ProgramChange")->value();
+               assert(program_change.length());
+               assert(_bank);
+               assert(_bank->patch_primary_key());
+               if ( _bank && _bank->patch_primary_key() ) {
+                       _id.msb = _bank->patch_primary_key()->msb;
+                       _id.lsb = _bank->patch_primary_key()->lsb;
+                       _id.program_number = PBD::atoi(program_change);
+               }
        }
 
+       cerr << "deserialized Patch: name: " <<  _name << " msb: " << _id.msb << " lsb: " << _id.lsb << " program " << _id.program_number << endl;
+       // TODO: handle that more gracefully
+       assert(_id.is_sane());
+
        return 0;
 }
 
@@ -74,7 +116,7 @@ Note::get_state (void)
 }
 
 int
-Note::set_state (const XMLNode& node)
+Note::set_state (const XMLNode& node, int /*version*/)
 {
        assert(node.name() == "Note");
        _number = node.property("Number")->value();
@@ -93,7 +135,7 @@ NoteNameList::get_state (void)
 }
 
 int
-NoteNameList::set_state (const XMLNode& node)
+NoteNameList::set_state (const XMLNode& node, int version)
 {
        assert(node.name() == "NoteNameList");
        _name   = node.property("Name")->value();
@@ -101,11 +143,11 @@ NoteNameList::set_state (const XMLNode& node)
        boost::shared_ptr<XMLSharedNodeList> notes =
                                        node.find("//Note");
        for (XMLSharedNodeList::const_iterator i = notes->begin(); i != notes->end(); ++i) {
-               Note* note = new Note();
-               note->set_state(*(*i));
-               _notes.push_back(*note);
+               boost::shared_ptr<Note> note(new Note());
+               note->set_state(*(*i), version);
+               _notes.push_back(note);
        }
-       
+
        return 0;
 }
 
@@ -119,24 +161,31 @@ PatchBank::get_state (void)
        for (PatchNameList::iterator patch = _patch_name_list.begin();
            patch != _patch_name_list.end();
            ++patch) {
-               patch_name_list->add_child_nocopy(patch->get_state());
+               patch_name_list->add_child_nocopy((*patch)->get_state());
        }
 
        return *node;
 }
 
 int
-PatchBank::set_state (const XMLNode& node)
+PatchBank::set_state (const XMLNode& node, int version)
 {
        assert(node.name() == "PatchBank");
        _name   = node.property("Name")->value();
+
+       XMLNode* commands = node.child("MIDICommands");
+       if (commands) {
+               _id = new PatchPrimaryKey();
+               initialize_primary_key_from_commands(*_id, commands);
+       }
+
        XMLNode* patch_name_list = node.child("PatchNameList");
        assert(patch_name_list);
        const XMLNodeList patches = patch_name_list->children();
        for (XMLNodeList::const_iterator i = patches.begin(); i != patches.end(); ++i) {
-               Patch* patch = new Patch();
-               patch->set_state(*(*i));
-               _patch_name_list.push_back(*patch);
+               boost::shared_ptr<Patch> patch(new Patch(this));
+               patch->set_state(*(*i), version);
+               _patch_name_list.push_back(patch);
        }
 
        return 0;
@@ -167,14 +216,14 @@ ChannelNameSet::get_state (void)
        for (PatchBanks::iterator patch_bank = _patch_banks.begin();
            patch_bank != _patch_banks.end();
            ++patch_bank) {
-               node->add_child_nocopy(patch_bank->get_state());
+               node->add_child_nocopy((*patch_bank)->get_state());
        }
 
        return *node;
 }
 
 int
-ChannelNameSet::set_state (const XMLNode& node)
+ChannelNameSet::set_state (const XMLNode& node, int version)
 {
        assert(node.name() == "ChannelNameSet");
        _name   = node.property("Name")->value();
@@ -196,27 +245,37 @@ ChannelNameSet::set_state (const XMLNode& node)
                                // cerr << "AvailableForChannels after insert" << endl;
                        }
                }
-               
+
                // cerr << "before PatchBank" << endl;
 
                if (node->name() == "PatchBank") {
                        // cerr << "got PatchBank" << endl;
-                       PatchBank* bank = new PatchBank();
-                       bank->set_state(*node);
-                       _patch_banks.push_back(*bank);
+                       boost::shared_ptr<PatchBank> bank(new PatchBank());
+                       bank->set_state(*node, version);
+                       _patch_banks.push_back(bank);
+                       const PatchBank::PatchNameList& patches = bank->patch_name_list();
+                       for (PatchBank::PatchNameList::const_iterator patch = patches.begin();
+                            patch != patches.end();
+                            ++patch) {
+                               _patch_map[(*patch)->patch_primary_key()] = *patch;
+                               _patch_list.push_back((*patch)->patch_primary_key());
+                       }
                        // cerr << "after PatchBank pushback" << endl;
                }
        }
-       
+
        // cerr << "ChannelnameSet done" << endl;
 
        return 0;
 }
 
 int
-CustomDeviceMode::set_state(const XMLNode& a_node)
+CustomDeviceMode::set_state(const XMLNode& a_node, int /*version*/)
 {
        assert(a_node.name() == "CustomDeviceMode");
+
+       _name = a_node.property("Name")->value();
+
        boost::shared_ptr<XMLSharedNodeList> channel_name_set_assignments =
                a_node.find("//ChannelNameSetAssign");
        for(XMLSharedNodeList::const_iterator i = channel_name_set_assignments->begin();
@@ -225,7 +284,7 @@ CustomDeviceMode::set_state(const XMLNode& a_node)
                int channel = atoi((*i)->property("Channel")->value().c_str());
                string name_set = (*i)->property("NameSet")->value();
                assert( 1 <= channel && channel <= 16 );
-               _channel_name_set_assignments[channel -1] = name_set;
+               _channel_name_set_assignments[channel - 1] = name_set;
        }
        return 0;
 }
@@ -235,20 +294,20 @@ CustomDeviceMode::get_state(void)
 {
        XMLNode* custom_device_mode = new XMLNode("CustomDeviceMode");
        custom_device_mode->add_property("Name",   _name);
-       XMLNode* channel_name_set_assignments = 
+       XMLNode* channel_name_set_assignments =
                custom_device_mode->add_child("ChannelNameSetAssignments");
        for (int i = 0; i < 15 && !_channel_name_set_assignments[i].empty(); i++) {
-               XMLNode* channel_name_set_assign = 
+               XMLNode* channel_name_set_assign =
                        channel_name_set_assignments->add_child("ChannelNameSetAssign");
                channel_name_set_assign->add_property("Channel", i + 1);
                channel_name_set_assign->add_property("NameSet", _channel_name_set_assignments[i]);
        }
-       
+
        return *custom_device_mode;
 }
 
 int
-MasterDeviceNames::set_state(const XMLNode& a_node)
+MasterDeviceNames::set_state(const XMLNode& a_node, int version)
 {
        // cerr << "MasterDeviceNames::set_state Manufacturer" << endl;
        // Manufacturer
@@ -276,9 +335,11 @@ MasterDeviceNames::set_state(const XMLNode& a_node)
        for (XMLSharedNodeList::iterator i = custom_device_modes->begin();
             i != custom_device_modes->end();
             ++i) {
-               CustomDeviceMode* custom_device_mode = new CustomDeviceMode();
-               custom_device_mode->set_state(*(*i));
-               _custom_device_modes.push_back(*custom_device_mode);
+               boost::shared_ptr<CustomDeviceMode> custom_device_mode(new CustomDeviceMode());
+               custom_device_mode->set_state(*(*i), version);
+
+               _custom_device_modes[custom_device_mode->name()] = custom_device_mode;
+               _custom_device_mode_names.push_back(custom_device_mode->name());
        }
 
        // cerr << "MasterDeviceNames::set_state ChannelNameSets" << endl;
@@ -287,10 +348,10 @@ MasterDeviceNames::set_state(const XMLNode& a_node)
        for (XMLSharedNodeList::iterator i = channel_name_sets->begin();
             i != channel_name_sets->end();
             ++i) {
-               ChannelNameSet* channel_name_set = new ChannelNameSet();
+               boost::shared_ptr<ChannelNameSet> channel_name_set(new ChannelNameSet());
                // cerr << "MasterDeviceNames::set_state ChannelNameSet before set_state" << endl;
-               channel_name_set->set_state(*(*i));
-               _channel_name_sets.push_back(*channel_name_set);
+               channel_name_set->set_state(*(*i), version);
+               _channel_name_sets[channel_name_set->name()] = channel_name_set;
        }
 
        // cerr << "MasterDeviceNames::set_state NoteNameLists" << endl;
@@ -299,9 +360,9 @@ MasterDeviceNames::set_state(const XMLNode& a_node)
        for (XMLSharedNodeList::iterator i = note_name_lists->begin();
             i != note_name_lists->end();
             ++i) {
-               NoteNameList* note_name_list = new NoteNameList();
-               note_name_list->set_state(*(*i));
-               _note_name_lists.push_back(*note_name_list);
+               boost::shared_ptr<NoteNameList> note_name_list(new NoteNameList());
+               note_name_list->set_state(*(*i), version);
+               _note_name_lists.push_back(note_name_list);
        }
 
        return 0;
@@ -314,14 +375,20 @@ MasterDeviceNames::get_state(void)
        return nothing;
 }
 
+MIDINameDocument::MIDINameDocument (const string& filename)
+       : _document(XMLTree(filename))
+{
+       set_state(*_document.root(), 0);
+}
+
 int
-MIDINameDocument::set_state(const XMLNode& a_node)
+MIDINameDocument::set_state(const XMLNode& a_node, int version)
 {
        // Author
        boost::shared_ptr<XMLSharedNodeList> author = a_node.find("//Author");
        assert(author->size() == 1);
        _author = author->front()->content();
-       
+
        // cerr << "MIDINameDocument::set_state befor masterdevicenames" << endl;
        // MasterDeviceNames
        boost::shared_ptr<XMLSharedNodeList> master_device_names_list = a_node.find("//MasterDeviceNames");
@@ -330,9 +397,9 @@ MIDINameDocument::set_state(const XMLNode& a_node)
             ++i) {
                boost::shared_ptr<MasterDeviceNames> master_device_names(new MasterDeviceNames());
                // cerr << "MIDINameDocument::set_state before masterdevicenames->set_state" << endl;
-               master_device_names->set_state(*(*i));
+               master_device_names->set_state(*(*i), version);
                // cerr << "MIDINameDocument::set_state after masterdevicenames->set_state" << endl;
-               
+
                for (MasterDeviceNames::Models::const_iterator model = master_device_names->models().begin();
                     model != master_device_names->models().end();
                     ++model) {
@@ -340,21 +407,13 @@ MIDINameDocument::set_state(const XMLNode& a_node)
                                _master_device_names_list.insert(
                                                std::pair<std::string, boost::shared_ptr<MasterDeviceNames> >
                                                         (*model,      master_device_names));
-                               
+
                                _all_models.push_back(*model);
                }
        }
-       
-       return 0;
-}
 
-/*
-const MasterDeviceNames::Models&
-MIDINameDocument::models(void)
-{
-       ;
+       return 0;
 }
-*/
 
 XMLNode&
 MIDINameDocument::get_state(void)