fix crash when trying to send MMC of timecode > 255 hours
[ardour.git] / libs / midi++2 / midi++ / midnam_patch.h
index 18100cf9be60a32a0deb0b95d9609a2e4ca4fd3f..9b2a611d9e82a76e0231594bba3fa16a01f90a0e 100644 (file)
@@ -1,13 +1,38 @@
+/*
+    Copyright (C) 2012 Paul Davis
+    Author: 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
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
 #ifndef MIDNAM_PATCH_H_
 #define MIDNAM_PATCH_H_
 
-#include "pbd/stateful.h"
-#include "midi++/event.h"
-#include "pbd/xml++.h"
-
+#include <algorithm>
+#include <iostream>
 #include <string>
 #include <list>
 #include <set>
+#include <map>
+#include <vector>
+
+#include <stdint.h>
+
+#include "midi++/libmidi_visibility.h"
+#include "midi++/event.h"
+#include "pbd/xml++.h"
 
 namespace MIDI
 {
@@ -15,158 +40,457 @@ namespace MIDI
 namespace Name
 {
 
-class Patch : public PBD::Stateful
+struct LIBMIDIPP_API PatchPrimaryKey
 {
 public:
-       typedef std::list<Evoral::Event> PatchMidiCommands;
+       int bank_number;
+       int program_number;
 
-       Patch() {};
-       Patch(string a_number, string a_name) : _number(a_number), _name(a_name) {};
-       ~Patch() {};
+       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() const {  
+               return ((bank_number >= 0) && (bank_number <= 16384) && 
+                       (program_number >=0 ) && (program_number <= 127));
+       }
+       
+       inline PatchPrimaryKey& operator=(const PatchPrimaryKey& id) {
+               bank_number = id.bank_number;
+               program_number = id.program_number;
+               return *this;
+       }
+       
+       inline bool operator==(const PatchPrimaryKey& id) const {
+               return (bank_number == id.bank_number && program_number == id.program_number);
+       }
+       
+       /**
+        * obey strict weak ordering or crash in STL containers
+        */
+       inline bool operator<(const PatchPrimaryKey& id) const {
+               if (bank_number < id.bank_number) {
+                       return true;
+               } else if (bank_number == id.bank_number && program_number < id.program_number) {
+                       return true;
+               }
+               
+               return false;
+       }
+};
+
+class PatchBank;
+       
+class LIBMIDIPP_API Patch 
+{
+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& name) { _name = name; }
+       
+       const std::string& note_list_name() const  { return _note_list_name; }
 
-       const string& name() const               { return _name; }
-       void set_name(const string a_name)       { _name = a_name; }
+       uint8_t program_number() const     { return _id.program_number; }
+       void set_program_number(uint8_t n) { _id.program_number = n; }
 
-       const string& number() const             { return _number; }
-       void set_number(const string a_number)   { _number = a_number; }
+       uint16_t bank_number() const      { return _id.bank_number; }
+       void set_bank_number (uint16_t n) { _id.bank_number = n; }
 
-       const PatchMidiCommands& patch_midi_commands() const { return _patch_midi_commands; }
+       const PatchPrimaryKey&   patch_primary_key()   const { return _id; }
 
        XMLNode& get_state (void);
-       int      set_state (const XMLNode& a_node);
+       int      set_state (const XMLTree&, const XMLNode&);
 
 private:
-       string _number;
-       string _name;
-       PatchMidiCommands _patch_midi_commands;
+       std::string     _name;
+       PatchPrimaryKey _id;
+       std::string     _note_list_name;
 };
 
-class PatchBank : public PBD::Stateful
+typedef std::list<boost::shared_ptr<Patch> > PatchNameList;
+
+class LIBMIDIPP_API PatchBank 
 {
 public:
-       typedef std::list<Patch> PatchNameList;
+       PatchBank (uint16_t n = 0, std::string a_name = std::string()) : _name(a_name), _number (n) {};
+       virtual ~PatchBank() { }
 
-       PatchBank() {};
-       virtual ~PatchBank() {};
-       PatchBank(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 string& name() const               { return _name; }
-       void set_name(const string a_name)       { _name = a_name; }
+       int number() const { return _number; }
 
        const PatchNameList& patch_name_list() const { return _patch_name_list; }
+       const std::string& patch_list_name() const { return _patch_list_name; }
+
+       int set_patch_name_list (const PatchNameList&);
 
        XMLNode& get_state (void);
-       int      set_state (const XMLNode& a_node);
+       int      set_state (const XMLTree&, const XMLNode&);
 
 private:
-       string        _name;
-       PatchNameList _patch_name_list;
+       std::string       _name;
+       uint16_t          _number;
+       PatchNameList     _patch_name_list;
+       std::string       _patch_list_name;
 };
 
-class ChannelNameSet : public PBD::Stateful
+class LIBMIDIPP_API ChannelNameSet
 {
 public:
-       typedef std::set<uint8_t>    AvailableForChannels;
-       typedef std::list<PatchBank> PatchBanks;
+       typedef std::set<uint8_t>                                    AvailableForChannels;
+       typedef std::list<boost::shared_ptr<PatchBank> >             PatchBanks;
+       typedef std::map<PatchPrimaryKey, boost::shared_ptr<Patch> > PatchMap;
+       typedef std::list<PatchPrimaryKey>                           PatchList;
 
        ChannelNameSet() {};
        virtual ~ChannelNameSet() {};
-       ChannelNameSet(string a_name) : _name(a_name) {};
+       ChannelNameSet(std::string& name) : _name(name) {};
 
-       const string& name() const               { return _name; }
-       void set_name(const string a_name)       { _name = a_name; }
+       const std::string& name() const        { return _name; }
+       void set_name(const std::string& name) { _name = name; }
+       
+       const PatchBanks& patch_banks() const    { return _patch_banks; }
 
-       const AvailableForChannels& available_for_channels() const { return _available_for_channels; }
-       const PatchBanks&           patch_banks()            const { return _patch_banks; }
+       bool available_for_channel(uint8_t channel) const { 
+               return _available_for_channels.find(channel) != _available_for_channels.end(); 
+       }
+       
+       boost::shared_ptr<Patch> find_patch(const PatchPrimaryKey& key) {
+               assert(key.is_sane());
+               return _patch_map[key];
+       }
+       
+       boost::shared_ptr<Patch> previous_patch(const PatchPrimaryKey& key) {
+               assert(key.is_sane());
+               for (PatchList::const_iterator i = _patch_list.begin();
+                        i != _patch_list.end();
+                        ++i) {
+                       if ((*i) == key) {
+                               if (i != _patch_list.begin()) {
+                                       --i;
+                                       return  _patch_map[*i];
+                               } 
+                       }
+               }
+                       
+               return boost::shared_ptr<Patch>();
+       }
+       
+       boost::shared_ptr<Patch> next_patch(const PatchPrimaryKey& key) {
+               assert(key.is_sane());
+               for (PatchList::const_iterator i = _patch_list.begin();
+                        i != _patch_list.end();
+                        ++i) {
+                       if ((*i) == key) {
+                               if (++i != _patch_list.end()) {
+                                       return  _patch_map[*i];
+                               } else {
+                                       --i;
+                               }
+                       }
+               }
+                       
+               return boost::shared_ptr<Patch>();
+       }
+
+       const std::string& note_list_name()    const { return _note_list_name; }
+       const std::string& control_list_name() const { return _control_list_name; }
 
        XMLNode& get_state (void);
-       int      set_state (const XMLNode& a_node);
+       int      set_state (const XMLTree&, const XMLNode&);
+
+       void set_patch_banks (const PatchBanks&);
+       void use_patch_name_list (const PatchNameList&);
 
 private:
-       string _name;
+       friend std::ostream& operator<< (std::ostream&, const ChannelNameSet&);
+
+       std::string          _name;
        AvailableForChannels _available_for_channels;
        PatchBanks           _patch_banks;
+       PatchMap             _patch_map;
+       PatchList            _patch_list;
+       std::string          _patch_list_name;
+       std::string          _note_list_name;
+       std::string          _control_list_name;
 };
 
-class Note : public PBD::Stateful
+std::ostream& operator<< (std::ostream&, const ChannelNameSet&);
+
+class LIBMIDIPP_API Note
 {
 public:
-       Note() {};
-       Note(string a_number, string a_name) : _number(a_number), _name(a_name) {};
-       ~Note() {};
+       Note() {}
+       Note(uint8_t number, const std::string& name) : _number(number), _name(name) {}
 
-       const string& name() const               { return _name; }
-       void set_name(const string a_name)       { _name = a_name; }
+       const std::string& name() const        { return _name; }
+       void set_name(const std::string& name) { _name = name; }
 
-       const string& number() const             { return _number; }
-       void set_number(const 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 XMLNode& a_node);
+       int      set_state (const XMLTree&, const XMLNode&);
+
+private:
+       uint8_t     _number;
+       std::string _name;
+};
+
+class LIBMIDIPP_API NoteNameList 
+{
+public:
+       typedef std::vector< boost::shared_ptr<Note> > Notes;
+
+       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; }
+
+       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;
+};
+
+class LIBMIDIPP_API Value
+{
+public:
+       Value() {}
+       Value(const uint16_t     number,
+             const std::string& name)
+               : _number(number)
+               , _name(name)
+       {}
+
+       uint16_t           number() const { return _number; }
+       const std::string& name()   const { return _name; }
+
+       void set_number(uint16_t number)       { _number = number; }
+       void set_name(const std::string& name) { _name = name; }
+
+       XMLNode& get_state(void);
+       int      set_state(const XMLTree&, const XMLNode&);
+
+private:
+       uint16_t    _number;
+       std::string _name;
+};
+
+class LIBMIDIPP_API ValueNameList
+{
+public:
+       typedef std::map<uint16_t, boost::shared_ptr<Value> > Values;
+
+       ValueNameList() {}
+       ValueNameList(const std::string& name) : _name(name) {}
+
+       const std::string& name() const { return _name; }
+
+       void set_name(const std::string& name) { _name = name; }
+
+       boost::shared_ptr<const Value> value(uint16_t num) const;
+       boost::shared_ptr<const Value> max_value_below(uint16_t num) const;
+
+       const Values& values() const { return _values; }
+
+       XMLNode& get_state(void);
+       int      set_state(const XMLTree&, const XMLNode&);
+
+private:
+       std::string _name;
+       Values      _values;
+};
+
+class LIBMIDIPP_API Control
+{
+public:
+       Control() {}
+       Control(const std::string& type,
+               const uint16_t     number,
+               const std::string& name)
+               : _type(type)
+               , _number(number)
+               , _name(name)
+       {}
+
+       const std::string& type()   const { return _type; }
+       uint16_t           number() const { return _number; }
+       const std::string& name()   const { return _name; }
+
+       const std::string&                     value_name_list_name() const { return _value_name_list_name; }
+       boost::shared_ptr<const ValueNameList> value_name_list()      const { return _value_name_list; }
+
+       void set_type(const std::string& type) { _type = type; }
+       void set_number(uint16_t number)       { _number = number; }
+       void set_name(const std::string& name) { _name = name; }
+
+       XMLNode& get_state(void);
+       int      set_state(const XMLTree&, const XMLNode&);
+
+private:
+       std::string _type;
+       uint16_t    _number;
+       std::string _name;
+
+       std::string                      _value_name_list_name;  ///< Global, UsesValueNameList
+       boost::shared_ptr<ValueNameList> _value_name_list;       ///< Local, ValueNameList
+};
+
+class LIBMIDIPP_API ControlNameList 
+{
+public:
+       typedef std::map<uint16_t, boost::shared_ptr<Control> > Controls;
+
+       ControlNameList() {}
+       ControlNameList(const std::string& name) : _name(name) {}
+
+       const std::string& name() const { return _name; }
+
+       void set_name(const std::string& name) { _name = name; }
+
+       boost::shared_ptr<const Control> control(uint16_t num) const;
+
+       const Controls& controls() const { return _controls; }
+
+       XMLNode& get_state(void);
+       int      set_state(const XMLTree&, const XMLNode&);
 
 private:
-       string _number;
-       string _name;
+       std::string _name;
+       Controls    _controls;
 };
 
-class CustomDeviceMode : public PBD::Stateful
+class LIBMIDIPP_API CustomDeviceMode
 {
 public:
        CustomDeviceMode() {};
        virtual ~CustomDeviceMode() {};
 
-       const string& name() const               { return _name; }
-       void set_name(const string a_name)       { _name = a_name; }
+       const std::string& name() const        { return _name; }
+       void set_name(const std::string& name) { _name = name; }
 
        
        XMLNode& get_state (void);
-       int      set_state (const XMLNode& a_node);
+       int      set_state (const XMLTree&, const XMLNode&);
+       
+       /// Note: channel here is 0-based while in the MIDNAM-file it's 1-based
+       const std::string& channel_name_set_name_by_channel(uint8_t channel) {
+               assert(channel <= 15);
+               return _channel_name_set_assignments[channel]; 
+       }
        
 private:
        /// array index = channel number
        /// string contents = name of channel name set 
-       string _name;
-       string _channel_name_set_assignments[16];
+       std::string _name;
+       std::string _channel_name_set_assignments[16];
 };
 
-class MasterDeviceNames : public PBD::Stateful
+class LIBMIDIPP_API MasterDeviceNames
 {
 public:
-       typedef std::list<ChannelNameSet> ChannelNameSets;
-       typedef std::list<std::string> Models;
+       typedef std::set<std::string>                                       Models;
+       /// maps name to CustomDeviceMode
+       typedef std::map<std::string, boost::shared_ptr<CustomDeviceMode> > CustomDeviceModes;
+       typedef std::list<std::string>                                      CustomDeviceModeNames;
+       /// maps name to ChannelNameSet
+       typedef std::map<std::string, boost::shared_ptr<ChannelNameSet> >   ChannelNameSets;
+       typedef std::map<std::string, boost::shared_ptr<NoteNameList> >     NoteNameLists;
+       typedef std::map<std::string, boost::shared_ptr<ControlNameList> >  ControlNameLists;
+       typedef std::map<std::string, boost::shared_ptr<ValueNameList> >    ValueNameLists;
+       typedef std::map<std::string, PatchNameList>                        PatchNameLists;
        
        MasterDeviceNames() {};
        virtual ~MasterDeviceNames() {};
        
-       const string& manufacturer() const { return _manufacturer; }
-       void set_manufacturer(const string a_manufacturer) { _manufacturer = a_manufacturer; }
+       const std::string& manufacturer() const { return _manufacturer; }
+       void set_manufacturer(const std::string& manufacturer) { _manufacturer = manufacturer; }
        
        const Models& models() const { return _models; }
        void set_models(const Models some_models) { _models = some_models; }
+
+       const ControlNameLists& controls() const { return _control_name_lists; }
+       const ValueNameLists&   values()   const { return _value_name_lists; }
+
+       boost::shared_ptr<const ValueNameList> value_name_list_by_control(
+               const std::string& mode,
+               uint8_t            channel,
+               uint8_t            number);
+
+       const CustomDeviceModeNames& custom_device_mode_names() const { return _custom_device_mode_names; }
        
+       boost::shared_ptr<CustomDeviceMode> custom_device_mode_by_name(const std::string& mode_name);
+       boost::shared_ptr<ChannelNameSet> channel_name_set_by_channel(const std::string& mode, uint8_t channel);
+       boost::shared_ptr<Patch> find_patch(const std::string& mode, uint8_t channel, const PatchPrimaryKey& key);
+
+       boost::shared_ptr<ControlNameList> control_name_list(const std::string& name);
+       boost::shared_ptr<ValueNameList>   value_name_list(const std::string& name);
+       boost::shared_ptr<NoteNameList>    note_name_list(const std::string& name);
+       boost::shared_ptr<ChannelNameSet>  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 XMLNode& a_node);
+       int      set_state (const XMLTree&, const XMLNode&);
        
 private:
-       string _manufacturer;
-       Models _models;
-       ChannelNameSets _channel_name_sets;
+       std::string           _manufacturer;
+       Models                _models;
+       CustomDeviceModes     _custom_device_modes;
+       CustomDeviceModeNames _custom_device_mode_names;
+       ChannelNameSets       _channel_name_sets;
+       NoteNameLists         _note_name_lists;
+       PatchNameLists        _patch_name_lists;
+       ControlNameLists      _control_name_lists;
+       ValueNameLists        _value_name_lists;
 };
 
-class MIDINameDocument : public PBD::Stateful
+class LIBMIDIPP_API MIDINameDocument
 {
 public:
-       MIDINameDocument() {};
+       // Maps Model names to MasterDeviceNames
+       typedef std::map<std::string, boost::shared_ptr<MasterDeviceNames> > MasterDeviceNamesList;
+       
+       MIDINameDocument() {}
+       MIDINameDocument(const std::string& filename);
        virtual ~MIDINameDocument() {};
 
+       const std::string& author() const { return _author; }
+       void set_author(const std::string& author) { _author = author; }
+       
+       boost::shared_ptr<MasterDeviceNames> master_device_names(const std::string& model);
+
+       const MasterDeviceNamesList& master_device_names_by_model() const { return _master_device_names_list; }
+       
+       const MasterDeviceNames::Models& all_models() const { return _all_models; }
+               
        XMLNode& get_state (void);
-       int      set_state (const XMLNode& a_node);
+       int      set_state (const XMLTree&, const XMLNode&);
 
 private:
-       string _author;
-
+       std::string                   _author;
+       MasterDeviceNamesList         _master_device_names_list;
+       XMLTree                       _document;
+       MasterDeviceNames::Models     _all_models;
 };
 
+LIBMIDIPP_API extern const char* general_midi_program_names[128]; /* 0 .. 127 */
+
 }
 
 }