From 88de45b7ccc933ee46a13d4e4e21caf9e5fb379e Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 20 Jan 2013 00:46:55 +0000 Subject: Support note names from midnam files (tested with the DM5). Do this via a simple MasterDeviceNames::note_name() function. The same really needs to be done for program names, this stuff is absolutely brutal to use. Store note names in a vector indexed by number instead of a list with string "numbers" for reasonable lookup time. Make some references const that should be. git-svn-id: svn://localhost/ardour2/branches/3.0@13908 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/midi++2/midi++/midnam_patch.h | 70 +++++++++++++++++------------- libs/midi++2/midnam_patch.cc | 89 ++++++++++++++++++++++++++++++++++---- 2 files changed, 122 insertions(+), 37 deletions(-) (limited to 'libs') diff --git a/libs/midi++2/midi++/midnam_patch.h b/libs/midi++2/midi++/midnam_patch.h index e218eeeedd..54d36735e5 100644 --- a/libs/midi++2/midi++/midnam_patch.h +++ b/libs/midi++2/midi++/midnam_patch.h @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -44,12 +45,12 @@ public: int bank_number; int program_number; - PatchPrimaryKey (uint8_t a_program_number = 0, uint16_t a_bank_number = 0) { + PatchPrimaryKey (uint8_t a_program_number = 0, uint16_t a_bank_number = 0) { bank_number = std::min (a_bank_number, (uint16_t) 16384); program_number = std::min (a_program_number, (uint8_t) 127); } - bool is_sane() { + bool is_sane() const { return ((bank_number >= 0) && (bank_number <= 16384) && (program_number >=0 ) && (program_number <= 127)); } @@ -87,13 +88,15 @@ public: Patch (std::string a_name = std::string(), uint8_t a_number = 0, uint16_t bank_number = 0); virtual ~Patch() {}; - const std::string& name() const { return _name; } - void set_name(const std::string a_name) { _name = a_name; } + const std::string& name() const { return _name; } + void set_name(const std::string a_name) { _name = a_name; } + + const std::string& note_list_name() const { return _note_list_name; } - uint8_t program_number() const { return _id.program_number; } - void set_program_number(uint8_t n) { _id.program_number = n; } + uint8_t program_number() const { return _id.program_number; } + void set_program_number(uint8_t n) { _id.program_number = n; } - uint16_t bank_number() const { return _id.bank_number; } + uint16_t bank_number() const { return _id.bank_number; } void set_bank_number (uint16_t n) { _id.bank_number = n; } const PatchPrimaryKey& patch_primary_key() const { return _id; } @@ -104,6 +107,7 @@ public: private: std::string _name; PatchPrimaryKey _id; + std::string _note_list_name; }; class PatchBank @@ -155,12 +159,12 @@ public: return _available_for_channels.find(channel) != _available_for_channels.end(); } - boost::shared_ptr find_patch(PatchPrimaryKey& key) { + boost::shared_ptr find_patch(const PatchPrimaryKey& key) { assert(key.is_sane()); return _patch_map[key]; } - boost::shared_ptr previous_patch(PatchPrimaryKey& key) { + boost::shared_ptr previous_patch(const PatchPrimaryKey& key) { assert(key.is_sane()); for (PatchList::const_iterator i = _patch_list.begin(); i != _patch_list.end(); @@ -176,7 +180,7 @@ public: return boost::shared_ptr(); } - boost::shared_ptr next_patch(PatchPrimaryKey& key) { + boost::shared_ptr next_patch(const PatchPrimaryKey& key) { assert(key.is_sane()); for (PatchList::const_iterator i = _patch_list.begin(); i != _patch_list.end(); @@ -214,43 +218,42 @@ std::ostream& operator<< (std::ostream&, const ChannelNameSet&); class Note { public: - Note() {}; - Note(std::string a_number, std::string a_name) : _number(a_number), _name(a_name) {}; - ~Note() {}; + Note() {} + Note(uint8_t number, const std::string& name) : _number(number), _name(name) {} - const std::string& name() const { return _name; } - void set_name(const std::string a_name) { _name = a_name; } + const std::string& name() const { return _name; } + void set_name(const std::string& name) { _name = name; } - const std::string& number() const { return _number; } - void set_number(const std::string a_number) { _number = a_number; } + uint8_t number() const { return _number; } + void set_number(uint8_t number) { _number = number; } XMLNode& get_state (void); int set_state (const XMLTree&, const XMLNode&); private: - std::string _number; + uint8_t _number; std::string _name; }; class NoteNameList { public: - typedef std::list > Notes; - NoteNameList() {}; - NoteNameList (std::string a_name) : _name(a_name) {}; - ~NoteNameList() {}; + typedef std::vector< boost::shared_ptr > Notes; - const std::string& name() const { return _name; } - void set_name(const std::string a_name) { _name = a_name; } + NoteNameList() { _notes.resize(128); } + NoteNameList (const std::string& name) : _name(name) { _notes.resize(128); } + + const std::string& name() const { return _name; } + const Notes& notes() const { return _notes; } - const Notes& notes() const { return _notes; } + void set_name(const std::string& name) { _name = name; } XMLNode& get_state (void); int set_state (const XMLTree&, const XMLNode&); private: std::string _name; - Notes _notes; + Notes _notes; }; class Control @@ -339,7 +342,7 @@ public: typedef std::list CustomDeviceModeNames; /// maps name to ChannelNameSet typedef std::map > ChannelNameSets; - typedef std::list > NoteNameLists; + typedef std::map > NoteNameLists; typedef std::list > ControlNameLists; typedef std::map PatchNameLists; @@ -358,8 +361,17 @@ public: boost::shared_ptr custom_device_mode_by_name(std::string mode_name); boost::shared_ptr channel_name_set_by_device_mode_and_channel(std::string mode, uint8_t channel); - boost::shared_ptr find_patch(std::string mode, uint8_t channel, PatchPrimaryKey& key); - + boost::shared_ptr find_patch(std::string mode, uint8_t channel, const PatchPrimaryKey& key); + + boost::shared_ptr note_name_list(const std::string& name); + boost::shared_ptr channel_name_set(const std::string& name); + + std::string note_name(const std::string& mode_name, + uint8_t channel, + uint16_t bank, + uint8_t program, + uint8_t number); + XMLNode& get_state (void); int set_state (const XMLTree&, const XMLNode&); diff --git a/libs/midi++2/midnam_patch.cc b/libs/midi++2/midnam_patch.cc index 39238114c7..1e21d602e3 100644 --- a/libs/midi++2/midnam_patch.cc +++ b/libs/midi++2/midnam_patch.cc @@ -128,6 +128,11 @@ Patch::set_state (const XMLTree&, const XMLNode& node) assert(program_change.length()); _id.program_number = PBD::atoi(program_change); } + + XMLNode* use_note_name_list = node.child("UsesNoteNameList"); + if (use_note_name_list) { + _note_list_name = use_note_name_list->property ("Name")->value(); + } return 0; } @@ -146,7 +151,12 @@ int Note::set_state (const XMLTree&, const XMLNode& node) { assert(node.name() == "Note"); - _number = node.property("Number")->value(); + + /* If the note number is junk, this will pull a number from the start, or + return zero if there isn't one. Better error detection would be a good + idea, but the duplicate check in NoteNameList::set_state() will probably + catch really broken files anyway. */ + _number = atoi(node.property("Number")->value().c_str()); _name = node.property("Name")->value(); return 0; @@ -156,7 +166,7 @@ XMLNode& NoteNameList::get_state (void) { XMLNode* node = new XMLNode("NoteNameList"); - node->add_property("Name", _name); + node->add_property("Name", _name); return *node; } @@ -165,13 +175,29 @@ int NoteNameList::set_state (const XMLTree& tree, const XMLNode& node) { assert(node.name() == "NoteNameList"); - _name = node.property("Name")->value(); + _name = node.property("Name")->value(); + _notes.clear(); + _notes.resize(128); - boost::shared_ptr notes = tree.find("//Note"); - for (XMLSharedNodeList::const_iterator i = notes->begin(); i != notes->end(); ++i) { + for (XMLNodeList::const_iterator i = node.children().begin(); + i != node.children().end(); ++i) { + if ((*i)->name() != "Note") { + continue; + } boost::shared_ptr note(new Note()); note->set_state (tree, *(*i)); - _notes.push_back(note); + if (note->number() > 127) { + PBD::warning << string_compose("Note number %1 in %3 out of range", + (int)note->number(), tree.filename()) + << endmsg; + } else if (_notes[note->number()]) { + PBD::warning << + string_compose("Duplicate note number %1 name %2 in %3 ignored", + (int)note->number(), note->name(), tree.filename()) + << endmsg; + } else { + _notes[note->number()] = note; + } } return 0; @@ -465,11 +491,58 @@ MasterDeviceNames::channel_name_set_by_device_mode_and_channel(std::string mode, } boost::shared_ptr -MasterDeviceNames::find_patch(std::string mode, uint8_t channel, PatchPrimaryKey& key) +MasterDeviceNames::find_patch(std::string mode, uint8_t channel, const PatchPrimaryKey& key) { return channel_name_set_by_device_mode_and_channel(mode, channel)->find_patch(key); } +boost::shared_ptr +MasterDeviceNames::channel_name_set(const std::string& name) +{ + ChannelNameSets::const_iterator i = _channel_name_sets.find(name); + if (i != _channel_name_sets.end()) { + return i->second; + } + return boost::shared_ptr(); +} + +boost::shared_ptr +MasterDeviceNames::note_name_list(const std::string& name) +{ + NoteNameLists::const_iterator i = _note_name_lists.find(name); + if (i != _note_name_lists.end()) { + return i->second; + } + return boost::shared_ptr(); +} + +std::string +MasterDeviceNames::note_name(const std::string& mode_name, + uint8_t channel, + uint16_t bank, + uint8_t program, + uint8_t number) +{ + if (number > 127) { + return ""; + } + + boost::shared_ptr patch( + find_patch(mode_name, channel, PatchPrimaryKey(program, bank))); + if (!patch) { + return ""; + } + + boost::shared_ptr note_names( + note_name_list(patch->note_list_name())); + if (!note_names) { + return ""; + } + + boost::shared_ptr note(note_names->notes()[number]); + return note ? note->name() : ""; +} + int MasterDeviceNames::set_state(const XMLTree& tree, const XMLNode&) { @@ -520,7 +593,7 @@ MasterDeviceNames::set_state(const XMLTree& tree, const XMLNode&) ++i) { boost::shared_ptr note_name_list(new NoteNameList()); note_name_list->set_state (tree, *(*i)); - _note_name_lists.push_back(note_name_list); + _note_name_lists[(*i)->property ("Name")->value()] = note_name_list; } // ControlNameLists -- cgit v1.2.3