diff options
| author | Florian Jung <flo@windfisch.org> | 2011-12-30 17:55:58 +0000 | 
|---|---|---|
| committer | Florian Jung <flo@windfisch.org> | 2011-12-30 17:55:58 +0000 | 
| commit | 6f35a1b2b84ab6cfc5d77fd46d5e31887a1590e1 (patch) | |
| tree | adece0e0c4fbe63659741539296df9fd32bfcaab /muse2/muse | |
| parent | 4d8477ab60093fc4c1f6190a931d0c2fdc65384c (diff) | |
instruments can load their patch'es drummaps
automatic setting of drummap according to patch
this is turned off when the user manually changes the drummap
TODO: let him turn it on again
moved MidiTrack::read/writeOurDrummap out to helper.cpp
extended xg.idf and gs.idf to ship the drummaps
still work in progress, but should be usable and stable, though incomplete
Diffstat (limited to 'muse2/muse')
| -rw-r--r-- | muse2/muse/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | muse2/muse/app.cpp | 2 | ||||
| -rw-r--r-- | muse2/muse/helper.cpp | 199 | ||||
| -rw-r--r-- | muse2/muse/helper.h | 12 | ||||
| -rw-r--r-- | muse2/muse/instruments/minstrument.cpp | 188 | ||||
| -rw-r--r-- | muse2/muse/instruments/minstrument.h | 47 | ||||
| -rw-r--r-- | muse2/muse/midiedit/dcanvas.cpp | 21 | ||||
| -rw-r--r-- | muse2/muse/midiedit/dlist.cpp | 2 | ||||
| -rw-r--r-- | muse2/muse/midiedit/drumedit.cpp | 2 | ||||
| -rw-r--r-- | muse2/muse/midiedit/drummap.cpp | 73 | ||||
| -rw-r--r-- | muse2/muse/midiedit/drummap.h | 7 | ||||
| -rw-r--r-- | muse2/muse/midiedit/scoreedit.cpp | 4 | ||||
| -rw-r--r-- | muse2/muse/song.cpp | 1 | ||||
| -rw-r--r-- | muse2/muse/track.cpp | 246 | ||||
| -rw-r--r-- | muse2/muse/track.h | 10 | ||||
| -rw-r--r-- | muse2/muse/trackdrummapupdater.cpp | 61 | ||||
| -rw-r--r-- | muse2/muse/trackdrummapupdater.h | 43 | 
17 files changed, 743 insertions, 177 deletions
| diff --git a/muse2/muse/CMakeLists.txt b/muse2/muse/CMakeLists.txt index 187bd41e..36645db4 100644 --- a/muse2/muse/CMakeLists.txt +++ b/muse2/muse/CMakeLists.txt @@ -65,6 +65,7 @@ QT4_WRAP_CPP ( muse_moc_headers        plugin.h         song.h         transport.h  +      trackdrummapupdater.h        value.h         steprec.h         ) @@ -132,6 +133,7 @@ file (GLOB core_source_files        thread.cpp        ticksynth.cpp         track.cpp +      trackdrummapupdater.cpp        transport.cpp        undo.cpp        value.cpp diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp index f63eb6e2..6a4e7c06 100644 --- a/muse2/muse/app.cpp +++ b/muse2/muse/app.cpp @@ -81,6 +81,7 @@  #include "tools.h"  #include "widgets/unusedwavefiles.h"  #include "functions.h" +#include "trackdrummapupdater.h"  namespace MusECore {  extern void initMidiSynth(); @@ -346,6 +347,7 @@ MusE::MusE(int /*argc*/, char** /*argv*/) : QMainWindow()        MusEGlobal::heartBeatTimer->setObjectName("timer");        connect(MusEGlobal::heartBeatTimer, SIGNAL(timeout()), MusEGlobal::song, SLOT(beat()));        connect(this, SIGNAL(activeTopWinChanged(MusEGui::TopWin*)), SLOT(activeTopWinChangedSlot(MusEGui::TopWin*))); +      new MusECore::TrackDrummapUpdater(); // no need for keeping the reference, the thing autoconnects on its own.  #ifdef ENABLE_PYTHON        //--------------------------------------------------- diff --git a/muse2/muse/helper.cpp b/muse2/muse/helper.cpp index 05cecc08..7d07a6ce 100644 --- a/muse2/muse/helper.cpp +++ b/muse2/muse/helper.cpp @@ -116,15 +116,12 @@ bool any_event_selected(const set<Part*>& parts, bool in_range)    return !get_events(parts, in_range ? 3 : 1).empty();  } -bool drummaps_almost_equal(DrumMap* one, DrumMap* two, int len) +bool drummaps_almost_equal(const DrumMap* one, const DrumMap* two, int len)  {    for (int i=0; i<len; i++) -  { -    DrumMap tmp = one[i]; -    tmp.mute=two[i].mute; -    if (tmp!=two[i]) +    if (!one[i].almost_equals(two[i]))        return false; -  } +    return true;  } @@ -164,6 +161,196 @@ QSet<Part*> parts_at_tick(unsigned tick, const QSet<Track*>& tracks)    return result;  } +bool parse_range(const QString& str, int* from, int* to) +{ +  int idx = str.indexOf("-"); +  if (idx<0) // no "-" in str +  { +    bool ok; +    int i = str.toInt(&ok); +    if (!ok) +    { +      *from=-1; *to=-1; +      return false; +    } +    else +    { +      *from=i; *to=i; +      return true; +    } +  } +  else // there is a "-" in str +  { +    QString str1=str.mid(0,idx); +    QString str2=str.mid(idx+1); +     +    bool ok; +    int i = str1.toInt(&ok); +    if (!ok) +    { +      *from=-1; *to=-1; +      return false; +    } +    else +    { +      *from=i; +       +      i = str2.toInt(&ok); +      if (!ok) +      { +        *from=-1; *to=-1; +        return false; +      } +      else +      { +        *to=i; +        return true; +      } +    } +  } +} + +void write_new_style_drummap(int level, Xml& xml, const char* tagname, +                             DrumMap* drummap, bool* drummap_hidden, bool full) +{ +  xml.tag(level++, tagname); +   +  for (int i=0;i<128;i++) +  { +    DrumMap* dm = &drummap[i]; +    const DrumMap* idm = &iNewDrumMap[i]; +   +    if ( (dm->name != idm->name) || (dm->vol != idm->vol) || +         (dm->quant != idm->quant) || (dm->len != idm->len) || +         (dm->lv1 != idm->lv1) || (dm->lv2 != idm->lv2) || +         (dm->lv3 != idm->lv3) || (dm->lv4 != idm->lv4) || +         (dm->enote != idm->enote) || (dm->mute != idm->mute) || +         (drummap_hidden && drummap_hidden[i]) || full) +    { +      xml.tag(level++, "entry pitch=\"%d\"", i); +       +      // when any of these "if"s changes, also update the large "if" +      // above (this scope's parent) +      if (full || dm->name != idm->name)   xml.strTag(level, "name", dm->name); +      if (full || dm->vol != idm->vol)     xml.intTag(level, "vol", dm->vol); +      if (full || dm->quant != idm->quant) xml.intTag(level, "quant", dm->quant); +      if (full || dm->len != idm->len)     xml.intTag(level, "len", dm->len); +      if (full || dm->lv1 != idm->lv1)     xml.intTag(level, "lv1", dm->lv1); +      if (full || dm->lv2 != idm->lv2)     xml.intTag(level, "lv2", dm->lv2); +      if (full || dm->lv3 != idm->lv3)     xml.intTag(level, "lv3", dm->lv3); +      if (full || dm->lv4 != idm->lv4)     xml.intTag(level, "lv4", dm->lv4); +      if (full || dm->enote != idm->enote) xml.intTag(level, "enote", dm->enote); +      if (full || dm->mute != idm->mute)   xml.intTag(level, "mute", dm->mute); +      if (drummap_hidden &&  +             (full || drummap_hidden[i]))  xml.intTag(level, "hide", drummap_hidden[i]); +       +      // anote is ignored anyway, as dm->anote == i, and this is +      // already stored in the begin tag (pitch=...) +       +      // channel and port are ignored as well, as they're not used +      // in new-style-drum-mode +       +      xml.tag(level--, "/entry"); +    } +  } + +  xml.etag(level, tagname); +} + +void read_new_style_drummap(Xml& xml, const char* tagname, +                            DrumMap* drummap, bool* drummap_hidden) +{ +	for (;;) +	{ +		Xml::Token token = xml.parse(); +		if (token == Xml::Error || token == Xml::End) +			break; +		const QString& tag = xml.s1(); +		switch (token) +		{ +			case Xml::TagStart: +				if (tag == "entry")  // then read that entry with a nested loop +        { +					DrumMap* dm=NULL; +          bool* hidden=NULL; +          for (;;) // nested loop +          { +            Xml::Token token = xml.parse(); +            const QString& tag = xml.s1(); +            switch (token) +            { +              case Xml::Error: +              case Xml::End: +                goto end_of_nested_for; +               +              case Xml::Attribut: +                if (tag == "pitch") +                { +                  int pitch = xml.s2().toInt() & 0x7f; +                  if (pitch < 0 || pitch > 127) +                    printf("ERROR: THIS SHOULD NEVER HAPPEN: invalid pitch in read_new_style_drummap()!\n"); +                  else +                  { +                    dm = &drummap[pitch]; +                    hidden = drummap_hidden ? &drummap_hidden[pitch] : NULL; +                  } +                } +                break; +               +              case Xml::TagStart: +                if (dm==NULL) +                  printf("ERROR: THIS SHOULD NEVER HAPPEN: no valid 'pitch' attribute in <entry> tag, but sub-tags follow in read_new_style_drummap()!\n"); +                else if (tag == "name") +                  dm->name = xml.parse(QString("name")); +                else if (tag == "vol") +                  dm->vol = (unsigned char)xml.parseInt(); +                else if (tag == "quant") +                  dm->quant = xml.parseInt(); +                else if (tag == "len") +                  dm->len = xml.parseInt(); +                else if (tag == "lv1") +                  dm->lv1 = xml.parseInt(); +                else if (tag == "lv2") +                  dm->lv2 = xml.parseInt(); +                else if (tag == "lv3") +                  dm->lv3 = xml.parseInt(); +                else if (tag == "lv4") +                  dm->lv4 = xml.parseInt(); +                else if (tag == "enote") +                  dm->enote = xml.parseInt(); +                else if (tag == "mute") +                  dm->mute = xml.parseInt(); +                else if (tag == "hide") +                { +                  if (hidden) *hidden = xml.parseInt(); +                } +                else +                  xml.unknown("read_new_style_drummap"); +                break; +               +              case Xml::TagEnd: +                if (tag == "entry") +                  goto end_of_nested_for; +               +              default: +                break; +            } +          } // end of nested loop +          end_of_nested_for: ; +        } // end of 'if (tag == "entry")' +				else +					xml.unknown("read_new_style_drummap"); +				break; + +			case Xml::TagEnd: +				if (tag == tagname) +					return; + +			default: +				break; +		} +	}   +}  } // namespace MusECore diff --git a/muse2/muse/helper.h b/muse2/muse/helper.h index 8ef39346..2a26c08e 100644 --- a/muse2/muse/helper.h +++ b/muse2/muse/helper.h @@ -44,11 +44,21 @@ QString pitch2string(int v);  Part* partFromSerialNumber(int serial);  bool any_event_selected(const std::set<Part*>&, bool in_range=false); -bool drummaps_almost_equal(DrumMap* one, DrumMap* two, int drummap_size=128); +bool drummaps_almost_equal(const DrumMap* one, const DrumMap* two, int drummap_size=128); + +// drummap_hidden may be NULL. +void write_new_style_drummap(int level, Xml& xml, const char* tagname, +                             DrumMap* drummap, bool* drummap_hidden=NULL, bool full=false); +void read_new_style_drummap(Xml& xml, const char* tagname, +                            DrumMap* drummap, bool* drummap_hidden=NULL); +                              QSet<Part*> parts_at_tick(unsigned tick);  QSet<Part*> parts_at_tick(unsigned tick, const Track* track);  QSet<Part*> parts_at_tick(unsigned tick, const QSet<Track*>& tracks); + +bool parse_range(const QString& str, int* from, int* to); // returns true if successful, false on error +  }  namespace MusEGui { diff --git a/muse2/muse/instruments/minstrument.cpp b/muse2/muse/instruments/minstrument.cpp index a01903ae..3876fb28 100644 --- a/muse2/muse/instruments/minstrument.cpp +++ b/muse2/muse/instruments/minstrument.cpp @@ -41,6 +41,8 @@  #include "midictrl.h"  #include "gconfig.h"  #include "popupmenu.h" +#include "drummap.h" +#include "helper.h"  namespace MusECore { @@ -364,6 +366,7 @@ void MidiInstrument::init()        MidiController* prog = new MidiController("Program", CTRL_PROGRAM, 0, 0xffffff, 0);        _controller->add(prog);        _dirty = false; +              }  MidiInstrument::MidiInstrument() @@ -408,8 +411,20 @@ MidiInstrument::~MidiInstrument()        if (_initScript)              delete _initScript; +       +      clear_delete_patch_drummap_mapping();        } +void MidiInstrument::clear_delete_patch_drummap_mapping() +{ +  for (std::list<patch_drummap_mapping_t>::iterator it = patch_drummap_mapping.begin(); +       it!=patch_drummap_mapping.end(); it++) +    delete[] it->drummap; +   +  patch_drummap_mapping.clear(); +} + +  /*  //---------------------------------------------------------  //   uniqueCopy @@ -515,7 +530,20 @@ MidiInstrument& MidiInstrument::assign(const MidiInstrument& ins)    _name = ins._name;    _filePath = ins._filePath; -     +   +  clear_delete_patch_drummap_mapping(); +  // do a deep copy +  for (std::list<patch_drummap_mapping_t>::const_iterator it = ins.patch_drummap_mapping.begin(); +       it!=ins.patch_drummap_mapping.end(); it++) +  { +    patch_drummap_mapping_t temp = *it; +    temp.drummap=new DrumMap[128]; +    for (int i=0;i<128;i++) +      temp.drummap[i]=it->drummap[i]; +  } +   +   +      // Hmm, dirty, yes? But init sets it to false...    //_dirty = ins._dirty;    //_dirty = false; @@ -733,6 +761,123 @@ void MidiInstrument::readMidiState(Xml& xml)    }  } +void MidiInstrument::readDrummaps(Xml& xml) +{ +  clear_delete_patch_drummap_mapping(); +   +  for (;;) +  { +    Xml::Token token = xml.parse(); +    const QString& tag = xml.s1(); +    switch (token) +    { +      case Xml::Error: +      case Xml::End: +        return; +         +      case Xml::TagStart: +        if (tag == "entry") +          patch_drummap_mapping.push_back(readDrummapsEntry(xml)); +        else +          xml.unknown("MidiInstrument::readDrummaps"); +        break; + +      case Xml::TagEnd: +        if (tag == "Drummaps") +          return; + +      default: +        break; +    } +  } +  printf("ERROR: THIS CANNOT HAPPEN: exited infinite loop in MidiInstrument::readDrummaps()!\n" +         "                           not returning anything. expect undefined behaviour or even crashes.\n"); +} + +patch_drummap_mapping_t MidiInstrument::readDrummapsEntry(Xml& xml) +{ +  using std::list; +   +  list<patch_collection_t> collection; +  DrumMap* drummap=new DrumMap[128]; +  for (int i=0;i<128;i++) +    drummap[i]=iNewDrumMap[i]; +   +  for (;;) +  { +    Xml::Token token = xml.parse(); +    const QString& tag = xml.s1(); +    switch (token) +    { +      case Xml::Error: +      case Xml::End: +        return patch_drummap_mapping_t(collection, drummap); +         +      case Xml::TagStart: +        if (tag == "patch_collection") +          collection.push_back(readDrummapsEntryPatchCollection(xml)); +        else if (tag == "drummap") +          read_new_style_drummap(xml, "drummap", drummap); +        else +          xml.unknown("MidiInstrument::readDrummapsEntry"); +        break; + +      case Xml::TagEnd: +        if (tag == "entry") +          return patch_drummap_mapping_t(collection, drummap); + +      default: +        break; +    } +  } +  printf("ERROR: THIS CANNOT HAPPEN: exited infinite loop in MidiInstrument::readDrummapsEntry()!\n" +         "                           not returning anything. expect undefined behaviour or even crashes.\n"); +  return patch_drummap_mapping_t(); +} + +patch_collection_t MidiInstrument::readDrummapsEntryPatchCollection(Xml& xml) +{ +  int first_prog=0, last_prog=256;   // this means: +  int first_lbank=0, last_lbank=256; // "does not matter" +  int first_hbank=0, last_hbank=256; +   +  for (;;) +  { +    Xml::Token token = xml.parse(); +    const QString& tag = xml.s1(); +    switch (token) +    { +      case Xml::Error: +      case Xml::End: +        return patch_collection_t(-1,-1,-1,-1,-1,-1); // an invalid collection +         +      case Xml::TagStart: +        xml.unknown("MidiInstrument::readDrummapsEntryPatchCollection"); +        break; + +      case Xml::Attribut: +        if (tag == "prog") +          parse_range(xml.s2(), &first_prog, &last_prog); +        else if (tag == "lbank") +          parse_range(xml.s2(), &first_lbank, &last_lbank); +        else if (tag == "hbank") +          parse_range(xml.s2(), &first_hbank, &last_hbank); +        break; + +      case Xml::TagEnd: +        if (tag == "patch_collection") +          return patch_collection_t(first_prog, last_prog, first_lbank, last_lbank, first_hbank, last_hbank); + +      default: +        break; +    } +  } + +  printf("ERROR: THIS CANNOT HAPPEN: exited infinite loop in MidiInstrument::readDrummapsEntryPatchCollection()!\n" +         "                           not returning anything. expect undefined behaviour or even crashes.\n"); +} + +  //---------------------------------------------------------  //   read  //--------------------------------------------------------- @@ -785,6 +930,9 @@ void MidiInstrument::read(Xml& xml)                                _controller->add(mc);                                } +                        else if (tag == "Drummaps") { +                              readDrummaps(xml); +                              }                          else if (tag == "Init")                                readEventList(xml, _midiInit, "Init");                          else if (tag == "Reset") @@ -794,7 +942,7 @@ void MidiInstrument::read(Xml& xml)                          else if (tag == "InitScript") {                                if (_initScript)                                      delete _initScript; -			      QByteArray ba = xml.parse1().toLatin1(); +                              QByteArray ba = xml.parse1().toLatin1();                                const char* istr = ba.constData();                                int len = strlen(istr) +1;                                if (len > 1) { @@ -998,4 +1146,40 @@ void MidiInstrument::populatePatchPopup(MusEGui::PopupMenu* menu, int chan, MTyp      } +const DrumMap* MidiInstrument::drummap_for_patch(int patch) const +{ +  using std::list; +   +  int program = (patch & 0x0000FF); +  int lbank =   (patch & 0x00FF00) >> 8; +  int hbank =   (patch & 0xFF0000) >> 16; +   +  for (list<patch_drummap_mapping_t>::const_iterator it=patch_drummap_mapping.begin(); +       it!=patch_drummap_mapping.end(); it++) +  { +    for (list<patch_collection_t>::const_iterator it2=it->affected_patches.begin(); +         it2!=it->affected_patches.end(); it2++) +    { +      // if the entry matches our patch +      if ( (program >= it2->first_program && program <= it2->last_program) && +           (hbank >= it2->first_hbank && hbank <= it2->last_hbank) && +           (lbank >= it2->first_lbank && lbank <= it2->last_lbank) ) +      { +        return it->drummap; +      } +    } +  } +   +  // if nothing was found +  return iNewDrumMap; +} + +patch_drummap_mapping_t::patch_drummap_mapping_t() +{ +  drummap=new DrumMap[128]; +  for (int i=0;i<128;i++) +    drummap[i]=iNewDrumMap[i]; +} + +  } // namespace MusECore diff --git a/muse2/muse/instruments/minstrument.h b/muse2/muse/instruments/minstrument.h index 385e67b4..9a65598b 100644 --- a/muse2/muse/instruments/minstrument.h +++ b/muse2/muse/instruments/minstrument.h @@ -40,6 +40,7 @@ class MidiControllerList;  class MidiPort;  class MidiPlayEvent;  class Xml; +class DrumMap;  //--------------------------------------------------------- @@ -80,6 +81,43 @@ struct SysEx {        unsigned char* data;        }; + + +struct patch_collection_t +{ +  int first_program; +  int last_program; +  int first_hbank; +  int last_hbank; +  int first_lbank; +  int last_lbank; +   +  patch_collection_t(int p1=0, int p2=127, int l1=0, int l2=127, int h1=0, int h2=127) +  { +    first_program=p1; +    last_program=p2; +    first_lbank=l1; +    last_lbank=l2; +    first_hbank=h1; +    last_hbank=h2; +  } + +}; + +struct patch_drummap_mapping_t +{ +  std::list<patch_collection_t> affected_patches; +  DrumMap* drummap; +   +  patch_drummap_mapping_t(const std::list<patch_collection_t>& a, DrumMap* d) +  { +    affected_patches=a; +    drummap=d; +  } +   +  patch_drummap_mapping_t(); +}; +  //---------------------------------------------------------  //   MidiInstrument  //--------------------------------------------------------- @@ -88,6 +126,7 @@ class MidiInstrument {        PatchGroupList pg;        MidiControllerList* _controller;        QList<SysEx*> _sysex; +      std::list<patch_drummap_mapping_t> patch_drummap_mapping;        bool _dirty;        int _nullvalue; @@ -103,6 +142,12 @@ class MidiInstrument {        char* _initScript;        QString _name;        QString _filePath; +       +      void clear_delete_patch_drummap_mapping(); +       +      void readDrummaps(Xml& xml); +      patch_drummap_mapping_t readDrummapsEntry(Xml& xml); +      patch_collection_t readDrummapsEntryPatchCollection(Xml& xml);     public:        MidiInstrument(); @@ -123,6 +168,8 @@ class MidiInstrument {        void removeSysex(SysEx* sysex)         { _sysex.removeAll(sysex); }        void addSysex(SysEx* sysex)            { _sysex.append(sysex); } +      const DrumMap* drummap_for_patch(int patch) const; +              EventList* midiInit() const            { return _midiInit; }        EventList* midiReset() const           { return _midiReset; }        EventList* midiState() const           { return _midiState; } diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index 4c033946..ad0226da 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -1008,6 +1008,19 @@ void DrumCanvas::mapChanged(int spitch, int dpitch)          using MusEGlobal::global_drum_ordering_t;          using MusEGlobal::global_drum_ordering; +        for (QSet<MusECore::Track*>::iterator it=instrument_map[spitch].tracks.begin(); +                                             it!=instrument_map[spitch].tracks.end(); it++) +        { +          if (dynamic_cast<MusECore::MidiTrack*>(*it)) +          dynamic_cast<MusECore::MidiTrack*>(*it)->set_drummap_ordering_tied_to_patch(false); +        } +        for (QSet<MusECore::Track*>::iterator it=instrument_map[dpitch].tracks.begin(); +                                             it!=instrument_map[dpitch].tracks.end(); it++) +        { +          if (dynamic_cast<MusECore::MidiTrack*>(*it)) +          dynamic_cast<MusECore::MidiTrack*>(*it)->set_drummap_ordering_tied_to_patch(false); +        } +                  MusECore::DrumMap dm_temp = ourDrumMap[spitch];          instrument_number_mapping_t im_temp = instrument_map[spitch]; @@ -1450,9 +1463,13 @@ void DrumCanvas::propagate_drummap_change(int instr, bool update_druminmap)    for (QSet<MusECore::Track*>::const_iterator it = tracks.begin(); it != tracks.end(); it++)    { -    dynamic_cast<MusECore::MidiTrack*>(*it)->drummap()[index] = ourDrumMap[instr]; +    MusECore::MidiTrack* mt=dynamic_cast<MusECore::MidiTrack*>(*it); +    // if we're not only changing "mute" state... +    if (!mt->drummap()[index].almost_equals(ourDrumMap[instr])) +      mt->set_drummap_tied_to_patch(false); +    mt->drummap()[index] = ourDrumMap[instr];      if (update_druminmap) -      dynamic_cast<MusECore::MidiTrack*>(*it)->update_drum_in_map(); +      mt->update_drum_in_map();    }  } diff --git a/muse2/muse/midiedit/dlist.cpp b/muse2/muse/midiedit/dlist.cpp index 2eb5e64a..fc6384f7 100644 --- a/muse2/muse/midiedit/dlist.cpp +++ b/muse2/muse/midiedit/dlist.cpp @@ -401,6 +401,7 @@ void DList::viewMousePressEvent(QMouseEvent* ev)                        {                          MusECore::MidiTrack* mt = dynamic_cast<MusECore::MidiTrack*>(*it);                          mt->drummap()[mt->map_drum_in(val)].enote=dm->enote; +                        mt->set_drummap_tied_to_patch(false);                        }                        // propagating this is unneccessary as it's already done.                        // updating the drumInmap is unneccessary, as the propagate call below @@ -900,6 +901,7 @@ void DList::pitchEdited()                        {                          MusECore::MidiTrack* mt = dynamic_cast<MusECore::MidiTrack*>(*it);                          mt->drummap()[mt->map_drum_in(val)].enote=editEntry->enote; +                        mt->set_drummap_tied_to_patch(false);                        }                        // propagating this is unneccessary as it's already done.                        // updating the drumInmap is unneccessary, as the propagate call below diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp index 3bb48705..1f159d1a 100644 --- a/muse2/muse/midiedit/drumedit.cpp +++ b/muse2/muse/midiedit/drumedit.cpp @@ -644,7 +644,7 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un  void DrumEdit::songChanged1(int bits)        { -        if(_isDeleting)  // Ignore while while deleting to prevent crash. +        if(_isDeleting)  // Ignore while deleting to prevent crash.            return;          if (bits & SC_SOLO) diff --git a/muse2/muse/midiedit/drummap.cpp b/muse2/muse/midiedit/drummap.cpp index 2705a252..d86bcd65 100644 --- a/muse2/muse/midiedit/drummap.cpp +++ b/muse2/muse/midiedit/drummap.cpp @@ -43,15 +43,13 @@ namespace MusECore {  const DrumMap blankdm = { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 127, 127, false }; -// this map must have 128 entries, as it's used for initalising new-style-drummaps as well. -// new-style-drummaps only have 128 entries. also, the every "out-note" ("anote") must be -// represented exactly once in that map, and there may be no duplicate or unused "out-notes". -// reason: the track's drummap are inited as follows: iterate through the full idrumMap[], -//         tracks_drummap[ idrumMap[i].anote ] = idrumMap[i] -// if you ever want to change this, you will need to go through track.cpp/.h and  -// {dlist,dcanvas,drumedit,drummap}{.cpp,.h} (and possibly some more) and find every usage -// of idrumMap by new style drummaps, and fix the problem. a possible fix would be duplicating -// idrumMap, change idrumMap, and use the duplicate for the new style stuff instead. +// this map should have 128 entries, as it's used for initalising iNewDrumMap as well. +// iNewDrumMap only has 128 entries. also, the every "out-note" ("anote") should be +// represented exactly once in idrumMap, and there shall be no duplicate or unused +// "out-notes". +// reason: iNewDrumMap is inited as follows: iterate through the full idrumMap[], +//         iNewDrumMap[ idrumMap[i].anote ] = idrumMap[i] +// if you ever want to change this, you will need to fix the initNewDrumMap() function.  const DrumMap idrumMap[DRUM_MAPSIZE] = {        { QString("Acoustic Bass Drum"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 35, 35, false },        { QString("Bass Drum 1"),        100, 16, 32, 9, 0, 70, 90, 127, 110, 36, 36, false }, @@ -261,6 +259,55 @@ const DrumMap idrumMap[DRUM_MAPSIZE] = {        { QString(""),                   100, 16, 32, 9, 0, 70, 90, 127, 110, 34, 34, false }        }; +DrumMap iNewDrumMap[128]; + +void initNewDrumMap() +{ +  bool done[128]; +  for (int i=0;i<128;i++) done[i]=false; +   +  for (int i=0;i<DRUM_MAPSIZE;i++) +  { +    int idx=idrumMap[i].anote; +    if (idx < 0 || idx >= 128) +      printf("ERROR: THIS SHOULD NEVER HAPPEN: idrumMap[%i].anote is not within 0..127!\n", idx); +    else +    { +      if (done[idx]==true) +      { +        printf("ERROR: iNewDrumMap[%i] is already initalized!\n" +               "       this will be probably not a problem, but some programmer didn't read\n" +               "       flo's comment at drummap.cpp, above idrumMap[].\n", idx); +      } +      else +      { +        iNewDrumMap[idx]=idrumMap[i]; +        done[idx]=true; +      } +    } +  } +   +  for (int i=0;i<128;i++) +  { +    if (done[i]==false) +    { +      printf("ERROR: iNewDrumMap[%i] is uninitalized!\n" +             "       this will be probably not a problem, but some programmer didn't read\n" +             "       flo's comment at drummap.cpp, above idrumMap[].\n", i); +      iNewDrumMap[i].name=""; +      iNewDrumMap[i].vol=100; +      iNewDrumMap[i].quant=16; +      iNewDrumMap[i].len=32; +      iNewDrumMap[i].lv1=70; +      iNewDrumMap[i].lv2=90; +      iNewDrumMap[i].lv3=127; +      iNewDrumMap[i].lv4=110; +      iNewDrumMap[i].enote=i; +      iNewDrumMap[i].anote=i; +    } +  } +} +  //---------------------------------------------------------  //   initDrumMap @@ -332,6 +379,14 @@ bool DrumMap::operator==(const DrumMap& map) const           && mute == map.mute;        } +bool DrumMap::almost_equals(const DrumMap& map) const +{ +  DrumMap tmp=map; +  tmp.mute=this->mute; +  return tmp==*this; +} + +  //---------------------------------------------------------  //   writeDrumMap  //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/drummap.h b/muse2/muse/midiedit/drummap.h index 3b6ffaf3..7f28b068 100644 --- a/muse2/muse/midiedit/drummap.h +++ b/muse2/muse/midiedit/drummap.h @@ -49,12 +49,15 @@ struct DrumMap {        bool operator==(const DrumMap& map) const;        bool operator!=(const DrumMap& map) const { return !operator==(map); } +      bool almost_equals(const DrumMap& map) const;        }; -// please let this at "128". idrumMap must have length 128 (see drummap.cpp for details) +// please let this at "128". idrumMap should have length 128 (see drummap.cpp for details)  #define DRUM_MAPSIZE  128 -extern const DrumMap idrumMap[DRUM_MAPSIZE]; //FINDMICH dummy! +extern DrumMap iNewDrumMap[128]; +extern void initNewDrumMap(); +  extern void initDrumMap();  extern void writeDrumMap(int level, Xml& xml, bool external);  extern void readDrumMap(Xml& xml, bool external); diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index c10adafd..055134e2 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -4686,8 +4686,8 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo   *     ("BUGGY! problem is: while changing entries, ourDrumMap   *      may be reallocated which causes abort()s and/or bugs.")   *      [ seems to work now, needs further testing! ] - * > o my record flag handling - *   o once, using super glue while a score editor displaying the glued  + *   x my record flag handling + *   * once, using super glue while a score editor displaying the glued    *     parts is open let muse segfault. this may or may not be fixed   *     now. check!   *     state of revision #1337: no segfaults, but the score editors diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp index 484e2d42..69900bbc 100644 --- a/muse2/muse/song.cpp +++ b/muse2/muse/song.cpp @@ -2074,6 +2074,7 @@ void Song::clear(bool signal, bool clear_all)        // _tempo      = 500000;      // default tempo 120        dirty          = false;        initDrumMap(); +      initNewDrumMap();        if (signal) {              emit loopChanged(false);              recordChanged(false); diff --git a/muse2/muse/track.cpp b/muse2/muse/track.cpp index 4dd2e0c5..595a25e7 100644 --- a/muse2/muse/track.cpp +++ b/muse2/muse/track.cpp @@ -34,6 +34,8 @@  #include "globaldefs.h"  #include "route.h"  #include "drummap.h" +#include "midictrl.h" +#include "helper.h"  namespace MusECore { @@ -618,19 +620,28 @@ void MidiTrack::init()        _recEcho       = true;        } +void MidiTrack::init_drum_ordering() +{ +  // first display entries with non-empty names, then with empty names. + +  remove_ourselves_from_drum_ordering(); + +  for (int i=0;i<128;i++) +    if (_drummap[i].name!="" && _drummap[i].name!="?") // non-empty name? +      MusEGlobal::global_drum_ordering.push_back(std::pair<MidiTrack*,int>(this,i)); + +  for (int i=0;i<128;i++) +    if (!(_drummap[i].name!="" && _drummap[i].name!="?")) // empty name? +      MusEGlobal::global_drum_ordering.push_back(std::pair<MidiTrack*,int>(this,i)); +} +  void MidiTrack::init_drummap(bool write_ordering)  {    for (int i=0;i<128;i++) -  { -    int idx=idrumMap[i].anote; -    if (idx < 0 || idx >= 128) -      printf ("ERROR: THIS SHOULD NEVER HAPPEN: idrumMap[%i].anote is not within 0..127!\n", idx); -    else -      _drummap[idx]=idrumMap[i]; -     -    if (write_ordering) -      MusEGlobal::global_drum_ordering.push_back(std::pair<MidiTrack*,int>(this,idx)); -  } +    _drummap[i]=iNewDrumMap[i]; + +  if (write_ordering) +    init_drum_ordering();    update_drum_in_map(); @@ -638,6 +649,7 @@ void MidiTrack::init_drummap(bool write_ordering)      _drummap_hidden[i]=false;    _drummap_tied_to_patch=true; +  _drummap_ordering_tied_to_patch=true;  }  void MidiTrack::update_drum_in_map() @@ -945,62 +957,14 @@ void MidiTrack::writeOurDrumSettings(int level, Xml& xml) const    writeOurDrumMap(level, xml, false);    xml.intTag(level, "tied", _drummap_tied_to_patch); +  xml.intTag(level, "ordering_tied", _drummap_ordering_tied_to_patch);    xml.etag(level, "our_drum_settings");  }  void MidiTrack::writeOurDrumMap(int level, Xml& xml, bool full) const  { -  xml.tag(level++, "our_drummap"); -   -  for (int i=0;i<128;i++) -  { -    int j; -    for (j=0;j<128;j++) -      if (idrumMap[j].anote == i) break; -     -    if (j==128) -      printf("THIS SHOULD NEVER HAPPEN: couldn't find initial drum map entry in MidiTrack::writeOurDrumMap()\n"); -    else -    { -      DrumMap* dm = &_drummap[i]; -      const DrumMap* idm = &idrumMap[j]; -     -      if ( (dm->name != idm->name) || (dm->vol != idm->vol) || -           (dm->quant != idm->quant) || (dm->len != idm->len) || -           (dm->lv1 != idm->lv1) || (dm->lv2 != idm->lv2) || -           (dm->lv3 != idm->lv3) || (dm->lv4 != idm->lv4) || -           (dm->enote != idm->enote) || (dm->mute != idm->mute) || -           _drummap_hidden[i] || full) -      { -        xml.tag(level++, "entry pitch=\"%d\"", i); -         -        // when any of these "if"s changes, also update the large "if" -        // above (this scope's parent) -        if (full || dm->name != idm->name)   xml.strTag(level, "name", dm->name); -        if (full || dm->vol != idm->vol)     xml.intTag(level, "vol", dm->vol); -        if (full || dm->quant != idm->quant) xml.intTag(level, "quant", dm->quant); -        if (full || dm->len != idm->len)     xml.intTag(level, "len", dm->len); -        if (full || dm->lv1 != idm->lv1)     xml.intTag(level, "lv1", dm->lv1); -        if (full || dm->lv2 != idm->lv2)     xml.intTag(level, "lv2", dm->lv2); -        if (full || dm->lv3 != idm->lv3)     xml.intTag(level, "lv3", dm->lv3); -        if (full || dm->lv4 != idm->lv4)     xml.intTag(level, "lv4", dm->lv4); -        if (full || dm->enote != idm->enote) xml.intTag(level, "enote", dm->enote); -        if (full || dm->mute != idm->mute)   xml.intTag(level, "mute", dm->mute); -        if (full || _drummap_hidden[i])      xml.intTag(level, "hide", _drummap_hidden[i]); -         -        // anote is ignored anyway, as dm->anote == i, and this is -        // already stored in the begin tag (pitch=...) -         -        // channel and port are ignored as well, as they're not used -        // in new-style-drum-mode -         -        xml.tag(level--, "/entry"); -      } -    } -  } -   -  xml.etag(level, "our_drummap"); +  write_new_style_drummap(level, xml, "our_drummap", _drummap, _drummap_hidden, full);  }  //--------------------------------------------------------- @@ -1095,6 +1059,8 @@ void MidiTrack::readOurDrumSettings(Xml& xml)  			case Xml::TagStart:  				if (tag == "tied")   					_drummap_tied_to_patch = xml.parseInt(); +				else if (tag == "ordering_tied")  +					_drummap_ordering_tied_to_patch = xml.parseInt();  				else if (tag == "our_drummap")  					readOurDrumMap(xml);  				else @@ -1115,98 +1081,9 @@ void MidiTrack::readOurDrumMap(Xml& xml, bool dont_init)  {    if (!dont_init) init_drummap(false);    _drummap_tied_to_patch=false; -   -	for (;;) -	{ -		Xml::Token token = xml.parse(); -		if (token == Xml::Error || token == Xml::End) -			break; -		const QString& tag = xml.s1(); -		switch (token) -		{ -			case Xml::TagStart: -				if (tag == "entry")  // then read that entry with a nested loop -        { -					DrumMap* dm=NULL; -          bool* hidden=NULL; -          for (;;) // nested loop -          { -            Xml::Token token = xml.parse(); -            const QString& tag = xml.s1(); -            switch (token) -            { -              case Xml::Error: -              case Xml::End: -                goto end_of_nested_for; -               -              case Xml::Attribut: -                if (tag == "pitch") -                { -                  int pitch = xml.s2().toInt() & 0x7f; -                  if (pitch < 0 || pitch > 127) -                    printf("ERROR: THIS SHOULD NEVER HAPPEN: invalid pitch in MidiTrack::readOurDrumMap()!\n"); -                  else -                  { -                    dm = &_drummap[pitch]; -                    hidden = &_drummap_hidden[pitch]; -                  } -                } -                break; -               -              case Xml::TagStart: -                if (dm==NULL) -                  printf("ERROR: THIS SHOULD NEVER HAPPEN: no valid 'pitch' attribute in <entry> tag, but sub-tags follow in MidiTrack::readOurDrumMap()!\n"); -                else if (tag == "name") -                  dm->name = xml.parse(QString("name")); -                else if (tag == "vol") -                  dm->vol = (unsigned char)xml.parseInt(); -                else if (tag == "quant") -                  dm->quant = xml.parseInt(); -                else if (tag == "len") -                  dm->len = xml.parseInt(); -                else if (tag == "lv1") -                  dm->lv1 = xml.parseInt(); -                else if (tag == "lv2") -                  dm->lv2 = xml.parseInt(); -                else if (tag == "lv3") -                  dm->lv3 = xml.parseInt(); -                else if (tag == "lv4") -                  dm->lv4 = xml.parseInt(); -                else if (tag == "enote") -                  dm->enote = xml.parseInt(); -                else if (tag == "mute") -                  dm->mute = xml.parseInt(); -                else if (tag == "hide") -                  *hidden = xml.parseInt(); -                else -                  xml.unknown("MidiTrack::readOurDrumMap"); -                break; -               -              case Xml::TagEnd: -                if (tag == "entry") -                  goto end_of_nested_for; -               -              default: -                break; -            } -          } // end of nested loop -          end_of_nested_for: ; -        } // end of 'if (tag == "entry")' -				else -					xml.unknown("MidiTrack::readOurDrumMap"); -				break; - -			case Xml::TagEnd: -				if (tag == "our_drummap") -        { -          update_drum_in_map(); -					return; -        } - -			default: -				break; -		} -	} +  _drummap_ordering_tied_to_patch=false; +  read_new_style_drummap(xml, "our_drummap", _drummap, _drummap_hidden); +  update_drum_in_map();  } @@ -1395,4 +1272,69 @@ void Track::writeRouting(int level, Xml& xml) const        }  } +int MidiTrack::getFirstControllerValue(int ctrl, int def) +{ +  int val=def; +  unsigned tick=-1; // maximum integer +   +  for (iPart pit=parts()->begin(); pit!=parts()->end(); pit++) +  { +    Part* part=pit->second; +    if (part->tick() > tick) break; // ignore this and the rest. we won't find anything new. +    for (iEvent eit=part->events()->begin(); eit!=part->events()->end(); eit++) +    { +      if (eit->first+part->tick() >= tick) break; +      // else if (eit->first+part->tick() < tick) and +      if (eit->second.type()==Controller && eit->second.dataA()==ctrl) +      { +        val = eit->second.dataB(); +        tick = eit->first+part->tick(); +        break; +      } +    } +  } + +  return val; +} + + +// returns true if the autoupdate changed something +bool MidiTrack::auto_update_drummap() +{ +  if (_drummap_tied_to_patch) +  { +    int patch = getFirstControllerValue(CTRL_PROGRAM,0); +    const DrumMap* new_drummap = MusEGlobal::midiPorts[_outPort].instrument()->drummap_for_patch(patch); +     +    if (!drummaps_almost_equal(new_drummap, this->drummap(), 128)) +    { +      for (int i=0;i<128;i++) +      { +        bool temp_mute=_drummap[i].mute; +        _drummap[i]=new_drummap[i]; +        _drummap[i].mute=temp_mute; +      } +       +      if (_drummap_ordering_tied_to_patch) +        init_drum_ordering(); +       +      return true; +    } +  } +   +  return false; +} + +void MidiTrack::set_drummap_tied_to_patch(bool val) +{ +  _drummap_tied_to_patch=val; +  if (val) auto_update_drummap(); +} + +void MidiTrack::set_drummap_ordering_tied_to_patch(bool val) +{ +  _drummap_ordering_tied_to_patch=val; +  if (val && _drummap_tied_to_patch) init_drum_ordering(); +} +  } // namespace MusECore diff --git a/muse2/muse/track.h b/muse2/muse/track.h index f2e12e3a..1df8cad0 100644 --- a/muse2/muse/track.h +++ b/muse2/muse/track.h @@ -236,11 +236,13 @@ class MidiTrack : public Track {        DrumMap* _drummap; // _drummap[foo].anote is always equal to foo        bool* _drummap_hidden; // _drummap und _drummap_hidden will be an array[128]        bool _drummap_tied_to_patch; //if true, changing patch also changes drummap +      bool _drummap_ordering_tied_to_patch; //if true, changing patch also changes drummap-ordering        int drum_in_map[128];        void init();        void init_drummap(bool write_ordering); // function without argument in public        void remove_ourselves_from_drum_ordering(); +      void init_drum_ordering();        void writeOurDrumSettings(int level, Xml& xml) const;        void readOurDrumSettings(Xml& xml); @@ -310,6 +312,8 @@ class MidiTrack : public Track {        virtual bool canRecord() const  { return true; }        static void setVisible(bool t) { _isVisible = t; }        static bool visible() { return _isVisible; } +       +      int getFirstControllerValue(int ctrl, int def=-1);        void setClef(clefTypes i) { clefType = i; }        clefTypes getClef() { return clefType; } @@ -320,6 +324,12 @@ class MidiTrack : public Track {        void update_drum_in_map();        void init_drummap() { init_drummap(false); } // function with argument in private +       +      bool auto_update_drummap(); +      void set_drummap_tied_to_patch(bool); +      bool drummap_tied_to_patch() { return _drummap_tied_to_patch; } +      void set_drummap_ordering_tied_to_patch(bool); +      bool drummap_ordering_tied_to_patch() { return _drummap_ordering_tied_to_patch; }        //void writeOurDrumSettings(int level, Xml& xml) const; // above in private:        //void readOurDrumSettings(Xml& xml); // above in private: diff --git a/muse2/muse/trackdrummapupdater.cpp b/muse2/muse/trackdrummapupdater.cpp new file mode 100644 index 00000000..35d5c056 --- /dev/null +++ b/muse2/muse/trackdrummapupdater.cpp @@ -0,0 +1,61 @@ +//========================================================= +//  MusE +//  Linux Music Editor +//  $Id: trackdrummapupdater.cpp,v 1.59.2.52 2011/12/27 20:25:58 flo93 Exp $ +// +//  (C) Copyright 2011 Florian Jung (florian.a.jung (at) web.de) +// +//  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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. +// +//========================================================= + +#include "trackdrummapupdater.h" +#include "song.h" +#include "globals.h" + +namespace MusECore { + +using MusEGlobal::song; + +TrackDrummapUpdater::TrackDrummapUpdater() +{ +  connect(song,SIGNAL(songChanged(int)), this, SLOT(songChanged(int))); +} + +void TrackDrummapUpdater::songChanged(int flags) +{ +  if (flags & (SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED | +               SC_PART_INSERTED  | SC_PART_REMOVED  | SC_PART_MODIFIED  | +               SC_EVENT_INSERTED | SC_EVENT_REMOVED | SC_EVENT_MODIFIED ) ) +  { +    bool changed=false; +    for (iTrack t=song->tracks()->begin(); t!=song->tracks()->end(); t++) +    { +      MidiTrack* track=dynamic_cast<MidiTrack*>(*t); +      if (track && track->auto_update_drummap()) +        changed=true; +    } +     +    if (changed) +    { +      // allow recursion. there will be no more recursion, because this +      // is only executed when something other than SC_DRUMMAP happens +      song->update(SC_DRUMMAP, true);  +    } +     +  } +} + +} //namespace MusECore diff --git a/muse2/muse/trackdrummapupdater.h b/muse2/muse/trackdrummapupdater.h new file mode 100644 index 00000000..caa2ac28 --- /dev/null +++ b/muse2/muse/trackdrummapupdater.h @@ -0,0 +1,43 @@ +//========================================================= +//  MusE +//  Linux Music Editor +//  $Id: trackdrummapupdater.h,v 1.59.2.52 2011/12/27 20:25:58 flo93 Exp $ +// +//  (C) Copyright 2011 Florian Jung (florian.a.jung (at) web.de) +// +//  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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. +// +//========================================================= + +#ifndef __TRACKDRUMMAPUPDATER_H__ +#define __TRACKDRUMMAPUPDATER_H__ + +#include <QObject> + +namespace MusECore { + +class TrackDrummapUpdater : public QObject +{ +  Q_OBJECT + +  public: +    TrackDrummapUpdater(); +     +  private slots: +    void songChanged(int flags); +}; + +} //namespace MusECore +#endif | 
