1 //========================================================= 2 // MusE 3 // Linux Music Editor 4 // $Id: minstrument.h,v 1.3.2.3 2009/03/09 02:05:18 terminator356 Exp $ 5 // 6 // (C) Copyright 2000 Werner Schweer (ws@seh.de) 7 // (C) Copyright 2016 Tim E. Real (terminator356 on users dot sourceforge dot net) 8 // 9 // This program is free software; you can redistribute it and/or 10 // modify it under the terms of the GNU General Public License 11 // as published by the Free Software Foundation; version 2 of 12 // the License, or (at your option) any later version. 13 // 14 // This program is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with this program; if not, write to the Free Software 21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 // 23 //========================================================= 24 25 #ifndef __MINSTRUMENT_H__ 26 #define __MINSTRUMENT_H__ 27 28 #include "globaldefs.h" 29 #include <map> 30 #include <list> 31 #include <vector> 32 #include <string> 33 #include <QString> 34 #include <QList> 35 36 #include "midiedit/drummap.h" 37 38 #include "config.h" 39 #ifdef MIDNAM_SUPPORT 40 #include "midnam.h" 41 #endif 42 43 #include "midictrl_consts.h" 44 45 // REMOVE Tim. newdrums. Added. 46 // Adds the ability to override at instrument level. 47 // But it just makes things too complex for the user. 48 // And in a way is unnecessary and overkill, since we 49 // already allow modifying an instrument. 50 //#define _USE_INSTRUMENT_OVERRIDES_ 51 52 53 // Forward declarations: 54 namespace MusEGui { 55 class PopupMenu; 56 } 57 58 namespace MusECore { 59 class EventList; 60 class MidiControllerList; 61 class MidiPlayEvent; 62 class Xml; 63 64 //--------------------------------------------------------- 65 // Patch 66 //--------------------------------------------------------- 67 68 struct Patch { 69 signed char hbank, lbank, program; 70 QString name; 71 bool drum; 72 patchPatch73 inline int patch() const { return (((unsigned int)hbank & 0xff) << 16) | (((unsigned int)lbank & 0xff) << 8) | ((unsigned int)program & 0xff); } dontCarePatch74 inline bool dontCare() const { return hbankDontCare() && lbankDontCare() && programDontCare(); } hbankDontCarePatch75 inline bool hbankDontCare() const { return hbank < 0; } lbankDontCarePatch76 inline bool lbankDontCare() const { return lbank < 0; } programDontCarePatch77 inline bool programDontCare() const { return program < 0; } 78 79 void read(Xml&); 80 void write(int level, Xml&); 81 }; 82 83 class PatchList : public std::list<Patch*> { 84 public: 85 iterator find(int patch, bool drum, bool includeDefault); 86 const_iterator find(int patch, bool drum, bool includeDefault) const; 87 }; 88 89 typedef PatchList::iterator iPatch; 90 typedef PatchList::const_iterator ciPatch; 91 92 //--------------------------------------------------------- 93 // PatchGroup 94 //--------------------------------------------------------- 95 96 struct PatchGroup { 97 QString name; 98 PatchList patches; 99 void read(Xml&); 100 }; 101 102 class PatchGroupList : public std::vector<PatchGroup*> { 103 public: 104 Patch* findPatch(int patch, bool drum, bool includeDefault); 105 Patch* findPatch(int patch, bool drum, bool includeDefault) const; 106 }; 107 108 typedef PatchGroupList::iterator iPatchGroup; 109 typedef PatchGroupList::const_iterator ciPatchGroup; 110 111 struct SysEx { 112 QString name; 113 QString comment; 114 int dataLen; 115 unsigned char* data; 116 bool read(Xml&); 117 void write(int level, Xml&); 118 119 SysEx(); 120 SysEx(const SysEx& src); 121 ~SysEx(); 122 }; 123 124 struct dumb_patchlist_entry_t 125 { 126 int prog; 127 int lbank; 128 int hbank; // "-1" means "unused" 129 dumb_patchlist_entry_tdumb_patchlist_entry_t130 dumb_patchlist_entry_t(int p, int l, int h) 131 { 132 prog=p; 133 lbank=l; 134 hbank=h; 135 } 136 137 bool operator<(const dumb_patchlist_entry_t& other) const 138 { 139 if (hbank < other.hbank) return true; 140 if (hbank > other.hbank) return false; 141 if (lbank < other.lbank) return true; 142 if (lbank > other.lbank) return false; 143 return (prog < other.prog); 144 } 145 146 bool operator>(const dumb_patchlist_entry_t& other) const 147 { 148 return other < *this; 149 } 150 151 bool operator==(const dumb_patchlist_entry_t& other) const 152 { 153 return (prog==other.prog && lbank==other.lbank && hbank==other.hbank); 154 } 155 156 bool operator!=(const dumb_patchlist_entry_t& other) const 157 { 158 return (!(*this==other)); 159 } 160 }; 161 162 struct WorkingDrumMapEntry { 163 #ifdef _USE_INSTRUMENT_OVERRIDES_ 164 enum OverrideType { NoOverride = 0x0, TrackDefaultOverride = 0x1, TrackOverride = 0x2, InstrumentDefaultOverride = 0x4, InstrumentOverride = 0x8, 165 AllOverrides = InstrumentDefaultOverride | InstrumentOverride | TrackDefaultOverride | TrackOverride }; 166 #else 167 enum OverrideType { NoOverride = 0x0, TrackDefaultOverride = 0x1, TrackOverride = 0x2, 168 AllOverrides = TrackDefaultOverride | TrackOverride }; 169 #endif 170 171 enum Field { NoField = 0x0, NameField = 0x1, VolField = 0x2, QuantField = 0x4, LenField = 0x8, ChanField = 0x10, PortField = 0x20, 172 Lv1Field = 0x40, Lv2Field = 0x80, Lv3Field = 0x100, Lv4Field = 0x200, ENoteField = 0x400, ANoteField = 0x800, 173 MuteField = 0x1000, HideField = 0x2000, 174 AllFields = NameField | VolField | QuantField | LenField | ChanField | PortField | Lv1Field | Lv2Field | Lv3Field | Lv4Field | 175 ENoteField | ANoteField | MuteField | HideField}; 176 // OR'd Fields. 177 typedef int override_t; 178 typedef int fields_t; 179 180 DrumMap _mapItem; 181 fields_t _fields; 182 183 // Starts with null _mapItem. 184 WorkingDrumMapEntry(); 185 // Allocates _mapItem and copies dm to it. 186 WorkingDrumMapEntry(const DrumMap& dm, fields_t fields); 187 // Copy ctor. 188 WorkingDrumMapEntry(const WorkingDrumMapEntry&); 189 WorkingDrumMapEntry& operator=(const WorkingDrumMapEntry&); 190 }; 191 192 typedef std::map < int /*index*/, WorkingDrumMapEntry, std::less<int> > WorkingDrumMapList_t; 193 typedef WorkingDrumMapList_t::iterator iWorkingDrumMapPatch_t; 194 typedef WorkingDrumMapList_t::const_iterator ciWorkingDrumMapPatch_t; 195 typedef std::pair<iWorkingDrumMapPatch_t, bool> WorkingDrumMapPatchInsertResult_t; 196 typedef std::pair<int, WorkingDrumMapEntry> WorkingDrumMapPatchInsertPair_t; 197 typedef std::pair<iWorkingDrumMapPatch_t, iWorkingDrumMapPatch_t> WorkingDrumMapPatchRangePair_t; 198 199 class WorkingDrumMapList : public WorkingDrumMapList_t { 200 201 public: 202 void add(int index,const WorkingDrumMapEntry& item); 203 // Returns the requested fields that were NOT removed. 204 int remove(int index, const WorkingDrumMapEntry& item); 205 // Returns the requested fields that were NOT removed. 206 int remove(int index, int fields); 207 // If fillUnused is true it will fill any unused fields. 208 void read(Xml&, bool fillUnused, int defaultIndex = -1); 209 void write(int level, Xml&) const; 210 }; 211 212 213 typedef std::map < int /*patch*/, WorkingDrumMapList, std::less<int> > WorkingDrumMapPatchList_t; 214 typedef WorkingDrumMapPatchList_t::iterator iWorkingDrumMapPatchList_t; 215 typedef WorkingDrumMapPatchList_t::const_iterator ciWorkingDrumMapPatchList_t; 216 typedef std::pair<iWorkingDrumMapPatchList_t, bool> WorkingDrumMapPatchListInsertResult_t; 217 typedef std::pair<int, WorkingDrumMapList> WorkingDrumMapPatchListInsertPair_t; 218 219 class WorkingDrumMapPatchList : public WorkingDrumMapPatchList_t { 220 221 public: 222 void add(const WorkingDrumMapPatchList& other); 223 void add(int patch, const WorkingDrumMapList& list); 224 void add(int patch, int index, const WorkingDrumMapEntry& item); 225 void remove(int patch, int index, const WorkingDrumMapEntry& item, bool includeDefault); 226 void remove(int patch, int index, int fields, bool includeDefault); 227 void remove(int patch, bool includeDefault); 228 WorkingDrumMapList* find(int patch, bool includeDefault); 229 const WorkingDrumMapList* find(int patch, bool includeDefault) const; 230 WorkingDrumMapEntry* find(int patch, int index, bool includeDefault); 231 const WorkingDrumMapEntry* find(int patch, int index, bool includeDefault) const; 232 233 // If fillUnused is true it will fill any unused items to ensure that all 128 items are filled. 234 void read(Xml&, bool fillUnused); 235 void write(int level, Xml&) const; 236 }; 237 238 239 typedef std::map < std::string /*instrument name*/, WorkingDrumMapPatchList > WorkingDrumMapInstrumentList_t; 240 typedef WorkingDrumMapInstrumentList_t::iterator iWorkingDrumMapInstrumentList_t; 241 typedef WorkingDrumMapInstrumentList_t::const_iterator ciWorkingDrumMapInstrumentList_t; 242 typedef std::pair<iWorkingDrumMapInstrumentList_t, bool> WorkingDrumMapInstrumentListInsertResult_t; 243 typedef std::pair<std::string, WorkingDrumMapPatchList> WorkingDrumMapInstrumentListInsertPair_t; 244 245 246 class WorkingDrumMapInstrumentList : public WorkingDrumMapInstrumentList_t { 247 public: 248 void read(Xml&); 249 }; 250 251 struct patch_drummap_mapping_t 252 { 253 int _patch; 254 DrumMap* drummap; 255 int drum_in_map[128]; 256 257 #ifdef _USE_INSTRUMENT_OVERRIDES_ 258 // A list of user-altered drum map items. 259 WorkingDrumMapList _workingDrumMapList; 260 #endif 261 262 // A NULL drummap is allowed, it means invalid (ie. invalid() returns true). 263 patch_drummap_mapping_t(DrumMap* d, int patch = 0xffffff) 264 { 265 drummap = d; 266 _patch = patch; 267 update_drum_in_map(); 268 } 269 270 patch_drummap_mapping_t(const patch_drummap_mapping_t& that); 271 patch_drummap_mapping_t(); 272 ~patch_drummap_mapping_t(); 273 274 patch_drummap_mapping_t& operator=(const patch_drummap_mapping_t& that); 275 276 #ifdef _USE_INSTRUMENT_OVERRIDES_ 277 void addWorkingDrumMapEntry(int index,const WorkingDrumMapEntry& item); 278 void removeWorkingDrumMapEntry(int index, const WorkingDrumMapEntry& item); 279 void removeWorkingDrumMapEntry(int index, int fields); 280 #endif 281 map_drum_inpatch_drummap_mapping_t282 int map_drum_in(int enote) { return drum_in_map[enote]; } 283 void update_drum_in_map(); 284 hbankpatch_drummap_mapping_t285 inline int hbank() const { return (_patch >> 16) & 0xff; } lbankpatch_drummap_mapping_t286 inline int lbank() const { return (_patch >> 8) & 0xff; } progpatch_drummap_mapping_t287 inline int prog() const { return _patch & 0xff; } setHBankpatch_drummap_mapping_t288 inline void setHBank(int v) { _patch = (_patch & 0x00ffff) | ((v & 0xff) << 16); } setLBankpatch_drummap_mapping_t289 inline void setLBank(int v) { _patch = (_patch & 0xff00ff) | ((v & 0xff) << 8); } setProgpatch_drummap_mapping_t290 inline void setProg(int v) { _patch = (_patch & 0xffff00) | (v & 0xff); } dontCarepatch_drummap_mapping_t291 inline bool dontCare() const { return hbankDontCare() && lbankDontCare() && programDontCare(); } hbankDontCarepatch_drummap_mapping_t292 inline bool hbankDontCare() const { const int hb = hbank(); return hb < 0 || hb > 127; } lbankDontCarepatch_drummap_mapping_t293 inline bool lbankDontCare() const { const int lb = lbank(); return lb < 0 || lb > 127; } programDontCarepatch_drummap_mapping_t294 inline bool programDontCare() const { const int pr = prog(); return pr < 0 || pr > 127; } 295 296 bool isPatchInRange(int patch, bool includeDefault) const; 297 298 bool isValid() const; 299 300 QString to_string(); 301 }; 302 303 class patch_drummap_mapping_list_t : public std::list<patch_drummap_mapping_t> 304 { 305 public: 306 void add(const patch_drummap_mapping_list_t& other); 307 void add(const patch_drummap_mapping_t& pdm); 308 iterator find(int patch, bool includeDefault); 309 const_iterator find(int patch, bool includeDefault) const; 310 void read(Xml& xml); 311 void write(int level, Xml&) const; 312 #ifdef _USE_INSTRUMENT_OVERRIDES_ 313 void writeDrummapOverrides(int level, Xml& xml) const; 314 #endif 315 }; 316 317 typedef patch_drummap_mapping_list_t::iterator iPatchDrummapMapping_t; 318 typedef patch_drummap_mapping_list_t::const_iterator ciPatchDrummapMapping_t; 319 320 321 // NOTE: Channel == -1 (default) is legal. 322 typedef std::map < int /*channel*/, patch_drummap_mapping_list_t, std::less<int> > ChannelDrumMappingList_t; 323 typedef ChannelDrumMappingList_t::iterator iChannelDrumMappingList_t; 324 typedef ChannelDrumMappingList_t::const_iterator ciChannelDrumMappingList_t; 325 typedef std::pair<iChannelDrumMappingList_t, bool> ChannelDrumMappingListInsertResult_t; 326 typedef std::pair<int, patch_drummap_mapping_list_t> ChannelDrumMappingListInsertPair_t; 327 328 class ChannelDrumMappingList : public ChannelDrumMappingList_t { 329 public: 330 ChannelDrumMappingList(); 331 332 void add(const ChannelDrumMappingList& other); 333 void add(int channel, const patch_drummap_mapping_list_t& list); 334 //void add(int patch, int index, const WorkingDrumMapEntry& item); 335 //void remove(int patch, int index, const WorkingDrumMapEntry& item, bool includeDefault); 336 //void remove(int patch, int index, int fields, bool includeDefault); 337 //void remove(int patch, bool includeDefault); 338 patch_drummap_mapping_list_t* find(int channel, bool includeDefault); 339 const patch_drummap_mapping_list_t* find(int channel, bool includeDefault) const; 340 //WorkingDrumMapEntry* find(int patch, int index, bool includeDefault); 341 //const WorkingDrumMapEntry* find(int patch, int index, bool includeDefault) const; 342 343 // If fillUnused is true it will fill any unused items to ensure that all 128 items are filled. 344 void read(Xml&); 345 void write(int level, Xml&) const; 346 }; 347 348 349 //--------------------------------------------------------- 350 // MidiInstrument 351 //--------------------------------------------------------- 352 353 class MidiInstrument { 354 public: 355 // NoteOffAll = Use all note offs. 356 // NoteOffNone = Do not use any note offs. 357 // NoteOffConvertToZVNoteOn = Convert all note offs to zero-velocity note ons. 358 enum NoteOffMode { NoteOffAll=0, NoteOffNone, NoteOffConvertToZVNoteOn }; 359 360 private: 361 PatchGroupList pg; 362 MidiControllerList* _controller; 363 QList<SysEx*> _sysex; 364 ChannelDrumMappingList _channelDrumMapping; 365 bool _dirty; 366 bool _waitForLSB; // Whether 14-bit controllers wait for LSB, or MSB and LSB are separate. 367 NoteOffMode _noteOffMode; 368 369 void init(); 370 371 protected: 372 EventList* _midiInit; 373 EventList* _midiReset; 374 EventList* _midiState; 375 // Set when loading midi state in SynthI::read, to indicate version 376 // to SynthI::initInstance, which is called later. 377 int _tmpMidiStateVersion; 378 char* _initScript; 379 QString _name; 380 QString _filePath; 381 382 #ifdef MIDNAM_SUPPORT 383 MidNamMIDIName _midnamDocument; 384 #endif 385 386 void writeDrummaps(int level, Xml& xml) const; 387 void readDrummaps(Xml& xml); 388 389 public: 390 MidiInstrument(); 391 virtual ~MidiInstrument(); 392 MidiInstrument(const QString& txt); iname()393 const QString& iname() const { return _name; } setIName(const QString & txt)394 void setIName(const QString& txt) { _name = txt; } 395 MType midiType() const; isSynti()396 virtual bool isSynti() const { return false; } 397 398 // Assign will 'delete' all existing patches and groups from the instrument. 399 MidiInstrument& assign(const MidiInstrument&); filePath()400 QString filePath() const { return _filePath; } setFilePath(const QString & s)401 void setFilePath(const QString& s) { _filePath = s; } dirty()402 bool dirty() const { return _dirty; } setDirty(bool v)403 void setDirty(bool v) { _dirty = v; } 404 sysex()405 const QList<SysEx*>& sysex() const { return _sysex; } removeSysex(SysEx * sysex)406 void removeSysex(SysEx* sysex) { _sysex.removeAll(sysex); } addSysex(SysEx * sysex)407 void addSysex(SysEx* sysex) { _sysex.append(sysex); } 408 409 410 QList<dumb_patchlist_entry_t> getPatches(int channel, bool drum); 411 unsigned getNextPatch(int channel, unsigned patch, bool drum); 412 unsigned getPrevPatch(int channel, unsigned patch, bool drum); 413 #ifdef _USE_INSTRUMENT_OVERRIDES_ 414 bool setWorkingDrumMapItem(int patch, int index, const WorkingDrumMapEntry&, bool isReset); 415 // Returns OR'd WorkingDrumMapEntry::OverrideType flags indicating whether a map item's members, 416 // given by 'fields' (OR'd WorkingDrumMapEntry::Fields), are either the original or working map item. 417 // Here in MidiInstrument the flags can be NoOverride and InstrumentOverride. See corresponding function 418 // in MidiTrack for additional TrackOverride flag use. 419 int isWorkingMapItem(int patch, int index, int fields) const; 420 void clearDrumMapOverrides(); 421 #endif 422 // Returns a map item with members filled from either the original or working map item, 423 // depending on which Field flags are set. The returned map includes any requested 424 // WorkingDrumMapEntry::OverrideType instrument overrides. Channel can be -1 meaning default. 425 virtual void getMapItem(int channel, int patch, int index, DrumMap& dest_map, 426 int overrideType = WorkingDrumMapEntry::AllOverrides) const; 427 midiInit()428 EventList* midiInit() const { return _midiInit; } midiReset()429 EventList* midiReset() const { return _midiReset; } midiState()430 EventList* midiState() const { return _midiState; } initScript()431 const char* initScript() const { return _initScript; } controller()432 MidiControllerList* controller() const { return _controller; } waitForLSB()433 bool waitForLSB() { return _waitForLSB; } setWaitForLSB(bool v)434 void setWaitForLSB(bool v) { _waitForLSB = v; } 435 436 // Finds a controller. By default it looks in this instrument's MidiControllerList map 437 // just like calling the map's find(). But if channel or patch are given (not default), 438 // it looks in BOTH the midnam's MidiControllerList and the instrument's MidiControllerList. 439 // In other words, the instrument's list acts as a default for all channels and patches, 440 // and has no 'channel' or 'patch number'. The midnam's list takes priority if used. 441 // Like find() which finds a verbose ctl number, but this version also finds a per-note 442 // controller if there is one for the given ctl number, if no verbose one was found. The ctl 443 // number can be the 'real' controller number, ie the low byte can be the actual note number 444 // and does not have to be 0xff. 445 // Returns null if no such specific controller OR suitable default is found. 446 MidiController* findController(int num, int channel = -1, int patch = CTRL_PROGRAM_VAL_DONT_CARE) const; 447 // Fills a given MidiControllerList with all available controllers for a given channel and patch. 448 // By default it gathers from this instrument's MidiControllerList map just like calling controller(). 449 // But if channel or patch are given (not default), it gathers from BOTH the midnam's MidiControllerList 450 // and the instrument's MidiControllerList. 451 // This would not be suitable for realtime code since it may allocate. And it copies all the items to dest. 452 void getControllers(MidiControllerList* dest, int channel = -1, int patch = CTRL_PROGRAM_VAL_DONT_CARE) const; 453 454 // Virtual so that inheriters (synths etc) can return whatever they want. noteOffMode()455 virtual NoteOffMode noteOffMode() const { return _noteOffMode; } 456 // For non-synths, users can set this value. setNoteOffMode(NoteOffMode mode)457 void setNoteOffMode(NoteOffMode mode) { _noteOffMode = mode; } 458 459 void readMidiState(Xml& xml); 460 virtual void reset(int); 461 virtual QString getPatchName(int channel, int prog, bool drum, bool includeDefault) const; 462 virtual void populatePatchPopup(MusEGui::PopupMenu*, int, bool); 463 static void populateInstrPopup(MusEGui::PopupMenu*, int port, bool show_synths = false); // Static 464 void read(Xml&); 465 void write(int level, Xml&); 466 #ifdef _USE_INSTRUMENT_OVERRIDES_ 467 void writeDrummapOverrides(int level, Xml&) const; 468 #endif 469 470 #ifdef MIDNAM_SUPPORT midnamDocument()471 MidNamMIDIName& midnamDocument() { return _midnamDocument; } midnamDocument()472 const MidNamMIDIName& midnamDocument() const { return _midnamDocument; } 473 // Possible plan: Use this INSTEAD of a direct call to MidNamMIDIName::read() 474 // so that we can catch it and update some stuff here afterwards (controllers). 475 bool readMidnamDocument(Xml&); 476 #endif 477 groups()478 PatchGroupList* groups() { return &pg; } 479 patch_drummap_mapping_list_t* get_patch_drummap_mapping(int channel, bool includeDefault); getChannelDrumMapping()480 ChannelDrumMappingList* getChannelDrumMapping() { return &_channelDrumMapping; } 481 }; 482 483 //--------------------------------------------------------- 484 // MidiInstrumentList 485 //--------------------------------------------------------- 486 487 class MidiInstrumentList : public std::list<MidiInstrument*> { 488 489 public: MidiInstrumentList()490 MidiInstrumentList() {} 491 iterator find(const MidiInstrument* instr); 492 #ifdef _USE_INSTRUMENT_OVERRIDES_ 493 void writeDrummapOverrides(int level, Xml&) const; 494 #endif 495 }; 496 497 typedef MidiInstrumentList::iterator iMidiInstrument; 498 typedef MidiInstrumentList::const_iterator ciMidiInstrument; 499 500 extern MidiInstrumentList midiInstruments; 501 extern MidiInstrument* genericMidiInstrument; 502 extern void initMidiInstruments(); 503 extern MidiInstrument* registerMidiInstrument(const QString&); 504 extern void removeMidiInstrument(const QString& name); 505 extern void removeMidiInstrument(const MidiInstrument* instr); 506 507 } // namespace MusECore 508 509 #ifdef _USE_INSTRUMENT_OVERRIDES_ 510 namespace MusEGlobal { 511 extern MusECore::WorkingDrumMapInstrumentList workingDrumMapInstrumentList; 512 } 513 #endif 514 515 #endif 516 517