diff options
| author | Florian Jung <flo@windfisch.org> | 2013-09-18 23:54:35 +0200 | 
|---|---|---|
| committer | Florian Jung <flo@windfisch.org> | 2013-09-18 23:54:35 +0200 | 
| commit | b3fc353a09496ee0aea7099d72e6963f4c2fc774 (patch) | |
| tree | 83ab91e988c59076d81ebddc09e8ff274dee8af5 /muse2/muse | |
| parent | 48a93993cfce160fb7d4cf0b67b4b77e22db19e5 (diff) | |
| parent | 85a51421d44f3893a1010f77e0418caf6be70235 (diff) | |
Merge branch 'audiomsg_overhaul' (nonshared eventlists and more)
This introduces the following changes:
 - Clone Parts no more share their eventlist. Instead, all changes
   made to one clone are replicated to the other clones' eventlists
 - audio/song->msg{Add,Delete,Change}{Part,Event,Track} have been
   replaced by the corresponding UndoOp operations.
 - Enforcing of const-correctness: No GUI code may ever gain
   writable access to audio/midi/song data structures. Access
   must *always* go through applyOperationGroup. This is now
   enforced.
 - Removed a bunch of DELETETHIS or REMOVE or otherwise commented
   out code
 - Removed dead code
 - Removed unused Audio Messages (that should go through applyOpGroup
   anyway.)
Diffstat (limited to 'muse2/muse')
64 files changed, 1787 insertions, 4054 deletions
diff --git a/muse2/muse/arranger/arrangerview.cpp b/muse2/muse/arranger/arrangerview.cpp index 7974369a..ecedd968 100644 --- a/muse2/muse/arranger/arrangerview.cpp +++ b/muse2/muse/arranger/arrangerview.cpp @@ -519,14 +519,14 @@ void ArrangerView::cmd(int cmd)                    arranger->cmd(Arranger::CMD_INSERT_EMPTYMEAS);                    break;              case CMD_DELETE: -                  if (!MusEGlobal::song->msgRemoveParts()) //automatically does undo if neccessary and returns true then +                  if (!MusECore::delete_selected_parts())                    {                        QMessageBox::StandardButton btn = QMessageBox::warning(                            this,tr("Remove track(s)"),tr("Are you sure you want to remove this track(s)?"),                            QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Ok);                        if (btn == QMessageBox::Cancel) -                          break;                            //msgRemoveParts() returned false -> no parts to remove? +                          break;                        MusEGlobal::song->startUndo();                        MusEGlobal::audio->msgRemoveTracks(); //TODO FINDME this could still be speeded up!                        MusEGlobal::song->endUndo(SC_TRACK_REMOVED); diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp index 646a9382..2c9c0f29 100644 --- a/muse2/muse/arranger/pcanvas.cpp +++ b/muse2/muse/arranger/pcanvas.cpp @@ -64,6 +64,10 @@  #include "utils.h"  #include "dialogs.h"  #include "widgets/pastedialog.h" +#include "undo.h" + +using MusECore::Undo; +using MusECore::UndoOp;  #define ABS(x) (abs(x)) @@ -189,12 +193,12 @@ void PartCanvas::returnPressed()        if (editMode) {            //this check is neccessary, because it returnPressed may be called            //twice. the second call would cause a crash, however! -          MusECore::Part* oldPart = editPart->part(); -          MusECore::Part* newPart = oldPart->clone(); -           -          newPart->setName(lineEditor->text()); +          MusECore::Part* part = editPart->part();            // Indicate do undo, and do port controller values but not clone parts.  -          MusEGlobal::audio->msgChangePart(oldPart, newPart, true, true, false); +           +          Undo operations; +          operations.push_back(UndoOp(UndoOp::ModifyPartName,part, part->name().toUtf8().data(), lineEditor->text().toUtf8().data())); // FIXME char sucks, better use QString directly. +          MusEGlobal::song->applyOperationGroup(operations);            editMode = false; @@ -314,7 +318,7 @@ void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp      bool result=moveItem(operations, ci, newpos, dtype);      if (result) -    	ci->move(newpos); +        ci->move(newpos);      if(moving.size() == 1) {            itemReleased(curItem, newpos); @@ -333,102 +337,80 @@ void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp  //---------------------------------------------------------  bool PartCanvas::moveItem(MusECore::Undo& operations, CItem* item, const QPoint& newpos, DragType t) -      { -      NPart* npart    = (NPart*) item; -      MusECore::Part* spart     = npart->part(); -      MusECore::Track* track    = npart->track(); -      MusECore::Track* dtrack=NULL; -      unsigned dtick  = newpos.x(); -      unsigned ntrack = y2pitch(item->mp().y()); -      MusECore::Track::TrackType type = track->type(); -      if (tracks->index(track) == ntrack && (dtick == spart->tick())) { -            return false; -            } -      if (ntrack >= tracks->size()) { -            ntrack = tracks->size(); -            if (MusEGlobal::debugMsg) -                printf("PartCanvas::moveItem - add new track\n"); -            dtrack = MusEGlobal::song->addTrack(operations, type);  // Add at end of list. - -            if (type == MusECore::Track::WAVE) { -                  MusECore::WaveTrack* st = (MusECore::WaveTrack*) track; -                  MusECore::WaveTrack* dt = (MusECore::WaveTrack*) dtrack; -                  dt->setChannels(st->channels()); -                  } -            emit tracklistChanged(); -            } -      else -      {       -            dtrack = tracks->index(ntrack); -            if (dtrack->type() != type) { -                  QMessageBox::critical(this, QString("MusE"), -                     tr("Cannot copy/move/clone to different Track-Type")); -                  return false; -                  } -            } -       -      MusECore::Part* dpart; -      bool clone = (t == MOVE_CLONE || (t == MOVE_COPY && spart->events()->arefCount() > 1)); -       -      if(t == MOVE_MOVE) -      { -        // This doesn't increment aref count, and doesn't chain clones. -        // It also gives the new part a new serial number, but it is  -        //  overwritten with the old one by Song::changePart(), from Audio::msgChangePart() below.  -        dpart = spart->clone(); +{ +    NPart* npart    = (NPart*) item; +    MusECore::Part* spart     = npart->part(); +    MusECore::Track* track    = npart->track(); +    MusECore::Track* dtrack=NULL; +    unsigned dtick  = newpos.x(); // FIXME TODO make subtick-compatible! +    unsigned ntrack = y2pitch(item->mp().y()); +    MusECore::Track::TrackType type = track->type(); +    int new_partend; +    if (tracks->index(track) == ntrack && (dtick == spart->tick())) { +        return false; +    } +    if (ntrack >= tracks->size()) { +        ntrack = tracks->size(); +        if (MusEGlobal::debugMsg) +            printf("PartCanvas::moveItem - add new track\n"); +        dtrack = MusEGlobal::song->addTrack(type);  // Add at end of list. Creates additional Undo entry. +         +        if (type == MusECore::Track::WAVE) { +            MusECore::WaveTrack* st = (MusECore::WaveTrack*) track; +            MusECore::WaveTrack* dt = (MusECore::WaveTrack*) dtrack; +            dt->setChannels(st->channels()); +        } +        emit tracklistChanged(); +    } +    else +    {       +        dtrack = tracks->index(ntrack); +        if (dtrack->type() != type) { +            QMessageBox::critical(this, QString("MusE"), +                                  tr("Cannot copy/move/clone to different Track-Type")); +                                  return false; +        } +    } +     +     +     +    if(t == MOVE_MOVE) +    { +        if (dtrack!=track) +           operations.push_back(MusECore::UndoOp(MusECore::UndoOp::MovePartToTrack,spart,dtrack,track)); +         +        operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyPartTick,spart,spart->tick(),dtick)); +         +        new_partend=(spart->lenTick() + dtick); +    }   +    else +    { +        MusECore::Part* dpart; +        bool clone = (t == MOVE_CLONE || (t == MOVE_COPY && spart->hasClones())); +         +        // Gives the new part a new serial number. +        if (clone) +            dpart = spart->createNewClone(); +        else +            dpart = spart->duplicate(); +         +        dpart->setTick(dtick);          dpart->setTrack(dtrack); -      }   -      else -        // This increments aref count if cloned, and chains clones. -        // It also gives the new part a new serial number. -        dpart = dtrack->newPart(spart, clone); - -      dpart->setTick(dtick); - -      if(t == MOVE_MOVE)  -        item->setPart(dpart); -      if (t == MOVE_COPY && !clone) { -            // Copy Events -            MusECore::EventList* se = spart->events(); -            MusECore::EventList* de = dpart->events(); -            for (MusECore::iEvent i = se->begin(); i != se->end(); ++i) { -                  MusECore::Event oldEvent = i->second; -                  MusECore::Event ev = oldEvent.clone(); -                  de->add(ev); -                  } -            } - - -      if (t == MOVE_COPY || t == MOVE_CLONE) { -            dpart->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it -                                          // so we must decrement it first :/ -            // These will not increment ref count, and will not chain clones...  -            // TODO DELETETHIS: is the above comment still correct (by flo93)? i doubt it! -            operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddPart,dpart)); -            } -      else if (t == MOVE_MOVE) { -            // In all cases found ev lists were same. So this is redundant - Redo incs then decs the same list. -            // But just in case we ever have two different lists... -            dpart->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it -                                          // so we must decrement it first :/ -            spart->events()->incARef(1);  // the later MusEGlobal::song->applyOperationGroup() will decrement it -                                          // so we must increment it first :/ -            dpart->setSelected(spart->selected()); -            // These will increment ref count if not a clone, and will chain clones... -            // TODO DELETETHIS: is the above comment still correct (by flo93)? i doubt it! -            operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyPart,spart, dpart, true, false)); -             -            spart->setSelected(false); -            } -      // else // will never happen -> operations will never be empty -       -      if (MusEGlobal::song->len() < (dpart->lenTick() + dpart->tick())) +         +        operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddPart,dpart)); +         +        new_partend=(dpart->lenTick() + dpart->tick()); +    } +     +    if (MusEGlobal::song->len() < new_partend) // FIXME this is buggy anyway.              operations.push_back(  MusECore::UndoOp(MusECore::UndoOp::ModifySongLen,  -                                                    dpart->lenTick() + dpart->tick(), +                                                    new_partend,                                                      MusEGlobal::song->len() )  ); -       -      return true; -      } +             +             +             +    return true; +}  //---------------------------------------------------------  //   raster @@ -504,15 +486,29 @@ void PartCanvas::partsChanged()  //---------------------------------------------------------  void PartCanvas::updateSelection() -      { +{ +      Undo operations; +      bool changed=false;        for (iCItem i = items.begin(); i != items.end(); ++i) {              NPart* part = (NPart*)(i->second); -            part->part()->setSelected(i->second->isSelected()); +            operations.push_back(UndoOp(UndoOp::SelectPart, part->part(), i->second->isSelected(), part->part()->selected())); +            if (i->second->isSelected() != part->part()->selected()) +                changed=true;        } -      emit selectionChanged(); -      redraw(); +       +      if (changed) +      { +            MusEGlobal::song->applyOperationGroup(operations); +            redraw();        } +      // TODO FIXME: this must be emitted always, because CItem is broken by design: +      //             CItems hold an Event smart-pointer which allows write access. +      //             This means, that items can (and will!) be selected bypassing the +      //             UndoOp::SelectEvent message! FIX THAT! (flo93) +      emit selectionChanged(); +} +  //---------------------------------------------------------  //   resizeItem  //--------------------------------------------------------- @@ -680,12 +676,11 @@ bool PartCanvas::deleteItem(CItem* i)  void PartCanvas::splitItem(CItem* item, const QPoint& pt)        {        NPart* np = (NPart*) item; -      MusECore::Track* t = np->track();        MusECore::Part*  p = np->part();        int x = pt.x();        if (x < 0)              x = 0; -      MusEGlobal::song->cmdSplitPart(t, p, AL::sigmap.raster(x, *_raster)); +      split_part(p,AL::sigmap.raster(x, *_raster));        }  //--------------------------------------------------------- @@ -695,9 +690,7 @@ void PartCanvas::splitItem(CItem* item, const QPoint& pt)  void PartCanvas::glueItem(CItem* item)        {        NPart* np = (NPart*) item; -      MusECore::Track* t = np->track(); -      MusECore::Part*  p = np->part(); -      MusEGlobal::song->cmdGluePart(t, p); +      merge_with_next_part(np->part());        }  //--------------------------------------------------------- @@ -722,7 +715,7 @@ QMenu* PartCanvas::genItemPopup(CItem* item)        act_copy->setShortcut(Qt::CTRL+Qt::Key_C);        partPopup->addSeparator(); -      int rc = npart->part()->events()->arefCount(); +      int rc = npart->part()->nClones();        QString st = QString(tr("s&elect "));        if(rc > 1)          st += (QString().setNum(rc) + QString(" ")); @@ -856,19 +849,12 @@ void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt)              case 15:    // declone                    {                    MusECore::Part* spart  = npart->part(); -                  MusECore::Track* track = npart->track(); -                  MusECore::Part* dpart  = track->newPart(spart, false); - -                  MusECore::EventList* se = spart->events(); -                  MusECore::EventList* de = dpart->events(); -                  for (MusECore::iEvent i = se->begin(); i != se->end(); ++i) { -                        MusECore::Event oldEvent = i->second; -                        MusECore::Event ev = oldEvent.clone(); -                        de->add(ev); -                        } -                  // Indicate undo, and do port controller values but not clone parts.  -                  // changed by flo93: removed start and endUndo, instead changed first bool to true -                  MusEGlobal::audio->msgChangePart(spart, dpart, true, true, false); +                  MusECore::Part* dpart  = spart->duplicate(); // dpart will not be member of any clone chain! + +                  Undo operations; +                  operations.push_back(UndoOp(UndoOp::DeletePart, spart)); +                  operations.push_back(UndoOp(UndoOp::AddPart, dpart)); +                  MusEGlobal::song->applyOperationGroup(operations);                    break;                    }              case 16: // Export to file @@ -892,9 +878,8 @@ void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt)              case 17: // File info                    {                      MusECore::Part* p = item->part(); -                    MusECore::EventList* el = p->events();                      QString str = tr("Part name: %1\nFiles:").arg(p->name()); -                    for (MusECore::iEvent e = el->begin(); e != el->end(); ++e)  +                    for (MusECore::ciEvent e = p->events().begin(); e != p->events().end(); ++e)                       {                        MusECore::Event event = e->second;                        MusECore::SndFileR f  = event.sndFile(); @@ -913,17 +898,15 @@ void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt)                      // Traverse and process the clone chain ring until we arrive at the same part again.                      // The loop is a safety net.                      MusECore::Part* p = part;  -                    int j = part->cevents()->arefCount(); -                    if(j > 0) +                     +                    Undo operations; +                    if(part->hasClones())                      { -                      for(int i = 0; i < j; ++i) -                      { -                        p->setSelected(true); -                        p = p->nextClone(); -                        if(p == part) -                          break; -                      } -                      MusEGlobal::song->update(SC_SELECTION); +                      operations.push_back(UndoOp(UndoOp::SelectPart, p, true, p->selected())); +                      for(MusECore::Part* it = p->nextClone(); it!=p; it=it->nextClone()) +                        operations.push_back(UndoOp(UndoOp::SelectPart, it, true, it->selected())); + +                      MusEGlobal::song->applyOperationGroup(operations);                      }                      break; @@ -1138,7 +1121,7 @@ void PartCanvas::keyPress(QKeyEvent* event)              if (getCurrentDrag())                    return; -            MusEGlobal::song->msgRemoveParts(); +            MusECore::delete_selected_parts();              return;              }        else if (key == shortcuts[SHRT_POS_DEC].key) { @@ -1492,13 +1475,11 @@ void PartCanvas::keyPress(QKeyEvent* event)  //    draws a part  //--------------------------------------------------------- -#if 0 // DELETETHIS 430 WHOA!  void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect)        {        int from   = rect.x();        int to     = from + rect.width(); -      //printf("from %d to %d\n", from,to);        MusECore::Part* part = ((NPart*)item)->part();        int pTick  = part->tick();        from      -= pTick; @@ -1508,427 +1489,6 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect)        if((unsigned int)to > part->lenTick())          to = part->lenTick();   -      // Item bounding box x is in tick coordinates, same as rectangle. -      if(item->bbox().intersect(rect).isNull()) -      { -        //printf("PartCanvas::drawItem rectangle is null\n"); -        return; -      } -       -      QRect r    = item->bbox(); -      bool clone = part->events()->arefCount() > 1; -      QBrush brush; -       -      //QRect rr = map(r); -      //QRect rr = p.transform().mapRect(r); -      //printf("PartCanvas::drawItem called map rx:%d rw:%d  rrx:%d rrw:%d\n", r.x(), r.width(), rr.x(), rr.width());   -      //printf("PartCanvas::drawItem called map rx:%d rw:%d\n", r.x(), r.width());   -      //p.save(); -      //p.setWorldMatrixEnabled(false); -       -      // NOTE: Optimization: For each item, hasHiddenEvents() is called once in Canvas::draw(), and we use cachedHasHiddenEvents(). -      // Not used for now. -      //int het = part->cachedHasHiddenEvents(); -      int het = part->hasHiddenEvents(); -         -      int y_1 = rmapyDev(1);  // Hack, try to replace. -      double xs_0 =  r.x(); -      double xe_0 =  xs_0 + r.width(); -      double xs_m0 = rmapx_f(xs_0); -      double xe_m0 = rmapx_f(xe_0); -      double xs_1 = rmapxDev_f(xs_m0 + 1.0); -      if(xs_1 > xe_0) -        xs_1 = xe_0; -      double xs_2 = rmapxDev_f(xs_m0 + 2.0); -      if(xs_2 > xe_0) -        xs_2 = xe_0; -      double xs_6 = rmapxDev_f(xs_m0 + 6.0); -      if(xs_6 > xe_0) -        xs_6 = xe_0; -       -      double xe_1 = rmapxDev_f(xe_m0 - 1.0); -      if(xe_1 < xs_0) -        xe_1 = xs_0; -      double xe_2 = rmapxDev_f(xe_m0 - 2.0); -      if(xe_2 < xs_0) -        xe_2 = xs_0; -      double xe_6 = rmapxDev_f(xe_m0 - 6.0); -      if(xe_6 < xs_0) -        xe_6 = xs_0; -       -      double ys_0 =  r.y(); -      double ye_0 =  ys_0 + r.height(); -      double ys_m0 = rmapy_f(ys_0); -      double ye_m0 = rmapy_f(ye_0); -      double ys_1 = rmapyDev_f(ys_m0 + 1.0); -      if(ys_1 > ye_0) -        ys_1 = ye_0; -      double ys_2 = rmapyDev_f(ys_m0 + 2.0); -      if(ys_2 > ye_0) -        ys_2 = ye_0; -       -      double ye_1 = rmapyDev_f(ye_m0 - 1.0); -      if(ye_1 < ys_0) -        ye_1 = ys_0; -      double ye_2 = rmapyDev_f(ye_m0 - 2.0); -      if(ye_2 < ys_0) -        ye_2 = ys_0; -       -      int cidx = part->colorIndex(); -      if (item->isMoving())  -      { -            QColor c(Qt::gray); -            c.setAlpha(MusEGlobal::config.globalAlphaBlend); -            QLinearGradient gradient(r.topLeft(), r.bottomLeft()); -            gradient.setColorAt(0, c); -            gradient.setColorAt(1, c.darker()); -            brush = QBrush(gradient); -      } -      else  -      if (part->selected())  -      { -          QColor c(Qt::black); -          c.setAlpha(MusEGlobal::config.globalAlphaBlend); -          QLinearGradient gradient(r.topLeft(), r.bottomLeft()); -          // Use a colour only about 20% lighter than black, rather than the 50% we use in MusECore::gGradientFromQColor -          //  and is used in darker()/lighter(), so that it is distinguished a bit better from grey non-part tracks. -          //c.setRgba(64, 64, 64, c.alpha());         -          gradient.setColorAt(0, QColor(51, 51, 51, MusEGlobal::config.globalAlphaBlend)); -          gradient.setColorAt(1, c); -          brush = QBrush(gradient); -      } -      else -      if (part->mute())  -      { -            QColor c(Qt::white); -            c.setAlpha(MusEGlobal::config.globalAlphaBlend); -            QLinearGradient gradient(r.topLeft(), r.bottomLeft()); -            gradient.setColorAt(0, c); -            gradient.setColorAt(1, c.darker()); -            brush = QBrush(gradient); -             -            // Not good. Aliasing missing lines happening at different mags.  -            // And it's too much. If notes + automation is displayed (by removing 'return' below), cross hatch interferes. -            // TODO: Maybe try to draw a nice gradient SINGLE cross (or STAR) from corner to corner instead.  -            // Then remove the 'return' below and let it draw the name and notes.  -            //brush.setStyle(Qt::DiagCrossPattern); -            //p.fillRect(rf, brush); -      } -      else -      { -            QColor c(MusEGlobal::config.partColors[cidx]); -            c.setAlpha(MusEGlobal::config.globalAlphaBlend); -            brush = QBrush(MusECore::gGradientFromQColor(c, r.topLeft(), r.bottomLeft())); -      }   -       -      double h = r.height(); -      double s = h / 4.0; -      double y0 = r.y(); -      double y1 = y0 + s; -      double y2 = y0 + s * 2.0; -      double y3 = y0 + s * 3.0; -      double y4 = y0 + h; -       -      QPointF points[16];    -      int pts; -       -      // -      // Fill the part rectangles, accounting for hidden events by using 'jagged' edges... -      // -       -      p.setBrush(brush); -      p.setPen(Qt::NoPen); -      if(het) -      { -        pts = 0; -        if(het == (MusECore::Part::LeftEventsHidden | MusECore::Part::RightEventsHidden)) -        { -          points[pts++] = QPointF(xs_0, y0); -          points[pts++] = QPointF(xe_0, y0); -          points[pts++] = QPointF(xe_6, y1); -          points[pts++] = QPointF(xe_0, y2); -          points[pts++] = QPointF(xe_6, y3); -          points[pts++] = QPointF(xe_0, y4); -          points[pts++] = QPointF(xs_0, y4); -          points[pts++] = QPointF(xs_6, y3); -          points[pts++] = QPointF(xs_0, y2); -          points[pts++] = QPointF(xs_6, y1); -          p.drawConvexPolygon(points, pts);   // Help says may be faster on some platforms (X11). -        } -        else -        if(het == MusECore::Part::LeftEventsHidden) -        { -          points[pts++] = QPointF(xs_0, y0); -          points[pts++] = QPointF(xe_0, y0); -          points[pts++] = QPointF(xe_0, y4); -          points[pts++] = QPointF(xs_0, y4); -          points[pts++] = QPointF(xs_6, y3); -          points[pts++] = QPointF(xs_0, y2); -          points[pts++] = QPointF(xs_6, y1); -          p.drawConvexPolygon(points, pts);    -        } -        else -        if(het == MusECore::Part::RightEventsHidden) -        { -          points[pts++] = QPointF(xs_0, y0); -          points[pts++] = QPointF(xe_0, y0); -           -          points[pts++] = QPointF(xe_6, y1); -          points[pts++] = QPointF(xe_0, y2); -          points[pts++] = QPointF(xe_6, y3); -          points[pts++] = QPointF(xe_0, y4); -          points[pts++] = QPointF(xs_0, y4); -          p.drawConvexPolygon(points, pts);    -        } -         -        // -        // Draw remaining 'hidden events' decorations with 'jagged' edges... -        // -                       -        int part_r, part_g, part_b, brightness, color_brightness; -        MusEGlobal::config.partColors[cidx].getRgb(&part_r, &part_g, &part_b); -        brightness =  part_r*29 + part_g*59 + part_b*12; -        //if ((brightness < 12000 || part->selected()) && !part->mute() && !item->isMoving()) -        //  color_brightness=223;   // too dark: use lighter color  -        //else -        //  color_brightness=32;  // otherwise use dark color  -        if ((brightness >= 12000 && !part->selected())) -          color_brightness=32;    // too light: use dark color  -        else -          color_brightness=223;   // too dark: use lighter color  -        QColor c(color_brightness,color_brightness,color_brightness, MusEGlobal::config.globalAlphaBlend); -        p.setBrush(QBrush(MusECore::gGradientFromQColor(c, r.topLeft(), r.bottomLeft()))); -        //p.setBrush(QBrush(c)); -        if(het & MusECore::Part::RightEventsHidden) -        { -          pts = 0; -          points[pts++] = QPointF(xe_0, y0); -          points[pts++] = QPointF(xe_0, y4); -          points[pts++] = QPointF(xe_6, y3); -          points[pts++] = QPointF(xe_0, y2); -          points[pts++] = QPointF(xe_6, y1); -          p.drawConvexPolygon(points, pts);    -        } -        if(het & MusECore::Part::LeftEventsHidden) -        { -          pts = 0; -          points[pts++] = QPointF(xs_0, y0); -          points[pts++] = QPointF(xs_6, y1); -          points[pts++] = QPointF(xs_0, y2); -          points[pts++] = QPointF(xs_6, y3); -          points[pts++] = QPointF(xs_0, y4); -          p.drawConvexPolygon(points, pts);    -        } -      }   -      else -      { -        p.fillRect(r, brush); -      } -           -      MusECore::MidiPart* mp = 0; -      MusECore::WavePart* wp = 0; -      MusECore::Track::TrackType type = part->track()->type(); -      if (type == MusECore::Track::WAVE) { -            wp =(MusECore::WavePart*)part; -            } -      else { -            mp = (MusECore::MidiPart*)part; -            } - -      if (wp) -          drawWavePart(p, rect, wp, r); -      else if (mp) -      { -          drawMidiPart(p, rect, mp->events(), (MusECore::MidiTrack*)part->track(), mp, r, mp->tick(), from, to);   -      } - -  #if 0 -        // -        // Now draw the borders... -        // Works great but requires clones be drawn with the highest priority on top of all other parts, in Canvas::draw. -        // -         -        QPen pen(part->selected() ? MusEGlobal::config.partColors[i] : Qt::black, 2.0, clone ? Qt::DotLine : Qt::SolidLine); -        pen.setCosmetic(true); -        p.setPen(pen);  -        p.setBrush(Qt::NoBrush); -        p.drawRect(r); -         -  #else  -        // -        // Now draw the borders, using custom segments... -        // -         -        // FIXME NOTE: For 1-pixel wide lines, setting pen style to anything other than solid didn't work out well.  -        // Much too screwy - the single-width lines kept getting shifted one pixel over intermittently.  -        // I tried EVERYTHING to make sure x is proper but the painter keeps shifting them over. -        // Meanwhile the fills are correct. Seems painter doesn't like line patterns, whether stock or custom. -        // Therefore I was forced to manually draw the left and right segments.  -        // It works. Which seems to be more proof that painter is handling line patterns and pen widths badly...  -        // DO NOT ERASE COMMENTED CODE BELOW for now, in case it can be fixed. Tim. p4.0.29 -         -        p.setBrush(Qt::NoBrush); -         -        QColor pc((part->mute() || item->isMoving())? Qt::white : MusEGlobal::config.partColors[cidx]); -        QPen penSelect1H(pc); -        QPen penSelect2H(pc, 2.0); -        QPen penSelect1V(pc); -        QPen penSelect2V(pc, 2.0); -        penSelect1H.setCosmetic(true); -        penSelect2H.setCosmetic(true); -        penSelect1V.setCosmetic(true); -        penSelect2V.setCosmetic(true); -         -        pc = Qt::black; -        QPen penNormal1H(pc); -        QPen penNormal2H(pc, 2.0); -        QPen penNormal1V(pc); -        QPen penNormal2V(pc, 2.0); -        penNormal1H.setCosmetic(true); -        penNormal2H.setCosmetic(true); -        penNormal1V.setCosmetic(true); -        penNormal2V.setCosmetic(true); -         -        QVector<qreal> customDashPattern; -        if(clone) -        { -          customDashPattern << 4.0 << 8.0; -          penSelect1H.setDashPattern(customDashPattern); -          penNormal1H.setDashPattern(customDashPattern); -          //penSelect1V.setDashPattern(customDashPattern); -          //penNormal1V.setDashPattern(customDashPattern); -          customDashPattern.clear(); -          customDashPattern << 2.0 << 4.0; -          penSelect2H.setDashPattern(customDashPattern); -          penNormal2H.setDashPattern(customDashPattern); -          //penSelect2V.setDashPattern(customDashPattern); -          //penNormal2V.setDashPattern(customDashPattern); -        }   -         -        pc = Qt::white; -        QPen penHidden1(pc); -        QPen penHidden2(pc, 2.0); -        penHidden2.setCosmetic(true); -        //customDashPattern.clear(); -        //customDashPattern << 2.0 << 10.0; -        //penHidden1.setDashPattern(customDashPattern); -        //customDashPattern.clear(); -        //customDashPattern << 1.0 << 5.0; -        //penHidden2.setDashPattern(customDashPattern); -         -        bool lbt = ((NPart*)item)->leftBorderTouches; -        bool rbt = ((NPart*)item)->rightBorderTouches; -         -        QLineF l1( lbt?xs_1:xs_0, ys_0,   rbt?xe_1:xe_0, ys_0);                     // Top  -        //QLineF l2(rbt?xe_1:xe_0,  r.y() + (rbt?y_1:y_2) - 1,       rbt?xe_1:xe_0, r.y() + r.height() - 1);        // Right  -        QLineF l3( lbt?xs_1:xs_0, ye_0,   rbt?xe_1:xe_0, ye_0);  // Bottom -        //QLineF l4(r.x(), r.y() + (lbt?y_1:y_2),            r.x(), r.y() + r.height() - (lbt?y_1:y_2));       // Left -         -        if(het & MusECore::Part::RightEventsHidden) -          p.setPen(((NPart*)item)->rightBorderTouches ? penHidden1 : penHidden2);  -        else   -        { -          if(((NPart*)item)->rightBorderTouches)               -            p.setPen(part->selected() ? penSelect1V : penNormal1V);  -          else   -            p.setPen(part->selected() ? penSelect2V : penNormal2V);  -        }   -        //p.drawLine(l2);        // Right line -         -        double xx = rbt?xe_1:xe_0;  -        if(clone) -        { -          double yinc = 7.0 * y_1; -          for(double yy = (rbt?ys_1:ys_2); yy < ye_2; yy += yinc) -          { -            double yi = (rbt?3.0:2.0) * y_1; -            if(yy + yi > ye_2) -              yi = ye_2 - yy; -            p.drawLine(QPointF(xx, yy), QPointF(xx, yy + yi));      // Right dashed line -          }    -        } -        else   -          p.drawLine(QPointF(xx, rbt?ys_1:ys_2), QPointF(xx, rbt?ye_1:ye_2));      // Right line -         -        if(het & MusECore::Part::LeftEventsHidden) -          p.setPen(((NPart*)item)->leftBorderTouches ? penHidden1 : penHidden2);  -        else   -        { -          if(((NPart*)item)->leftBorderTouches)               -            p.setPen(part->selected() ? penSelect1V : penNormal1V);  -          else   -            p.setPen(part->selected() ? penSelect2V : penNormal2V);  -        }   -        //p.drawLine(l4);        //  Left line -         -        xx = xs_0; -        if(clone) -        { -          double yinc = 7.0 * y_1; -          for(double yy = (lbt?ys_1:ys_2); yy < ye_2; yy += yinc) -          { -            double yi = (lbt?3.0:2.0) * y_1; -            if(yy + yi > ye_2) -              yi = ye_2 - yy; -            p.drawLine(QPointF(xx, yy), QPointF(xx, yy + yi));      // Left dashed line -          }    -        } -        else   -          p.drawLine(QPointF(xx, lbt?ys_1:ys_2), QPointF(xx, lbt?ye_1:ye_2));      // Left line -         -        p.setPen(part->selected() ? penSelect2H : penNormal2H);  -        p.drawLine(l1);  // Top line -        p.drawLine(l3);  // Bottom line -         -  #endif -  -      //p.restore(); -       -      if (MusEGlobal::config.canvasShowPartType & 1) {     // show names -            // draw name -            // FN: Set text color depending on part color (black / white) -            int part_r, part_g, part_b, brightness; -            // Since we'll draw the text on the bottom (to accommodate drum 'slivers'), -            //  get the lowest colour in the gradient used to draw the part. -            QRect rr = map(r); -            rr.setX(rr.x() + 3); -            MusECore::gGradientFromQColor(MusEGlobal::config.partColors[cidx], rr.topLeft(), rr.bottomLeft()).stops().last().second.getRgb(&part_r, &part_g, &part_b); -            brightness =  part_r*29 + part_g*59 + part_b*12; -            //bool rev = (brightness < 12000 || part->selected()) && !part->mute() && !item->isMoving(); -            bool rev = brightness >= 12000 && !part->selected(); -            p.save(); -            p.setFont(MusEGlobal::config.fonts[4]); -            p.setWorldMatrixEnabled(false); -            if (rev) -              p.setPen(Qt::white);  -            else -              p.setPen(Qt::black);    -            p.drawText(rr.translated(1, 1), Qt::AlignBottom|Qt::AlignLeft, part->name()); -            if (rev) -              p.setPen(Qt::black);   -            else -              p.setPen(Qt::white);    -            p.drawText(rr, Qt::AlignBottom|Qt::AlignLeft, part->name()); -            p.restore(); -            } -      } -#endif - -void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) -      { -      int from   = rect.x(); -      int to     = from + rect.width(); - -      MusECore::Part* part = ((NPart*)item)->part(); -      int pTick  = part->tick(); -      from      -= pTick; -      to        -= pTick; -      if(from < 0) -        from = 0; -      if((unsigned int)to > part->lenTick()) -        to = part->lenTick();   - -      bool clone = part->events()->arefCount() > 1;        QBrush brush;        QRect r    = item->bbox(); @@ -2142,23 +1702,18 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect)        MusECore::MidiPart* mp = 0;        MusECore::WavePart* wp = 0;        MusECore::Track::TrackType type = part->track()->type(); -      if (type == MusECore::Track::WAVE) { +      if (type == MusECore::Track::WAVE)              wp =(MusECore::WavePart*)part; -            } -      else { +      else              mp = (MusECore::MidiPart*)part; -            }        if (wp)            drawWavePart(p, rect, wp, r);        else if (mp) -      { -          drawMidiPart(p, rect, mp->events(), (MusECore::MidiTrack*)part->track(), mp, r, mp->tick(), from, to);   -      } +          drawMidiPart(p, rect, mp, r, from, to);        p.setWorldMatrixEnabled(false); -  #if 1 // DELETETHIS remove wrapping #if          //          // Now draw the borders, using custom segments...          // @@ -2186,7 +1741,7 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect)          penNormal2V.setCosmetic(true);          QVector<qreal> customDashPattern; -        if(clone) +        if(part->hasClones())          {            customDashPattern << 4.0 << 6.0;            penSelect1H.setDashPattern(customDashPattern); @@ -2249,8 +1804,6 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect)          QLine l3(lbx_c, ye_0, rbx_c, ye_0);          p.drawLine(l3);  // Bottom line -  #endif -              if (MusEGlobal::config.canvasShowPartType & 1) {     // show names              // draw name              // FN: Set text color depending on part color (black / white) @@ -2314,7 +1867,12 @@ void PartCanvas::drawMoving(QPainter& p, const CItem* item, const QRect&)  //    pr - part rectangle  //--------------------------------------------------------- -void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* events, MusECore::MidiTrack *mt, MusECore::MidiPart *pt, const QRect& r, int pTick, int from, int to) +void PartCanvas::drawMidiPart(QPainter& p, const QRect& rect, MusECore::MidiPart* midipart, const QRect& r, int from, int to) +{ +	drawMidiPart(p, rect, midipart->events(), midipart->track(), midipart, r, midipart->tick(), from, to); +} + +void PartCanvas::drawMidiPart(QPainter& p, const QRect&, const MusECore::EventList& events, MusECore::MidiTrack *mt, MusECore::MidiPart *pt, const QRect& r, int pTick, int from, int to)  {    int color_brightness;    QColor eventColor; @@ -2343,9 +1901,9 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* ev              // Do not allow this, causes segfault.              if(from <= to)              { -              MusECore::iEvent ito(events->lower_bound(to)); +              MusECore::ciEvent ito(events.lower_bound(to)); -              for (MusECore::iEvent i = events->lower_bound(from); i != ito; ++i) { +              for (MusECore::ciEvent i = events.lower_bound(from); i != ito; ++i) {                      MusECore::EventType type = i->second.type();                      int a = i->second.dataA() | 0xff;                      if ( @@ -2371,12 +1929,12 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* ev        using std::map;        using std::pair; -      MusECore::iEvent ito(events->lower_bound(to)); +      MusECore::ciEvent ito(events.lower_bound(to));        bool isdrum = (mt->type() == MusECore::Track::DRUM  ||  mt->type() == MusECore::Track::NEW_DRUM);        // draw controllers ------------------------------------------        p.setPen(QColor(192,192,color_brightness/2)); -      for (MusECore::iEvent i = events->begin(); i != ito; ++i) { // PITCH BEND +      for (MusECore::ciEvent i = events.begin(); i != ito; ++i) { // PITCH BEND              int t  = i->first + pTick;              MusECore::EventType type = i->second.type(); @@ -2393,7 +1951,7 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* ev        }        p.setPen(QColor(192,color_brightness/2,color_brightness/2)); -      for (MusECore::iEvent i = events->begin(); i != ito; ++i) { // PAN +      for (MusECore::ciEvent i = events.begin(); i != ito; ++i) { // PAN              int t  = i->first + pTick;              MusECore::EventType type = i->second.type(); @@ -2410,7 +1968,7 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* ev        }        p.setPen(QColor(color_brightness/2,192,color_brightness/2)); -      for (MusECore::iEvent i = events->begin(); i != ito; ++i) { // VOLUME +      for (MusECore::ciEvent i = events.begin(); i != ito; ++i) { // VOLUME              int t  = i->first + pTick;              MusECore::EventType type = i->second.type(); @@ -2427,7 +1985,7 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* ev        }        p.setPen(QColor(0,0,255)); -      for (MusECore::iEvent i = events->begin(); i != ito; ++i) { // PROGRAM CHANGE +      for (MusECore::ciEvent i = events.begin(); i != ito; ++i) { // PROGRAM CHANGE              int t  = i->first + pTick;              MusECore::EventType type = i->second.type(); @@ -2454,7 +2012,7 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* ev        if (MusEGlobal::config.canvasShowPartType & 4) //y-stretch?        { -        for (MusECore::iEvent i = events->begin(); i != events->end(); ++i) +        for (MusECore::ciEvent i = events.begin(); i != events.end(); ++i)          {            if (i->second.type()==MusECore::Note)            { @@ -2493,13 +2051,13 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* ev          if (MusEGlobal::heavyDebugMsg)          {              if (!isdrum) -                printf("DEBUG: arranger: cakewalk enabled, y-stretching from %i to %i. eventlist=%p\n",lowest_pitch, highest_pitch, events); +                printf("DEBUG: arranger: cakewalk enabled, y-stretching from %i to %i.\n",lowest_pitch, highest_pitch);              else              {                  printf("DEBUG: arranger: cakewalk enabled, y-stretching drums: ");;                  for (map<int,int>::iterator it=y_mapper.begin(); it!=y_mapper.end(); it++)                      printf("%i ", it->first); -                printf("; eventlist=%p\n",events);  +                printf("\n");               }          }        } @@ -2516,7 +2074,7 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* ev        }        p.setPen(eventColor); -      for (MusECore::iEvent i = events->begin(); i != ito; ++i) { +      for (MusECore::ciEvent i = events.begin(); i != ito; ++i) {              int t  = i->first + pTick;              int te = t + i->second.lenTick(); @@ -2570,8 +2128,7 @@ void PartCanvas::drawWavePart(QPainter& p,        int h  = hh/2;        int y  = pr.y() + h; -      MusECore::EventList* el = wp->events(); -      for (MusECore::iEvent e = el->begin(); e != el->end(); ++e) { +      for (MusECore::ciEvent e = wp->events().begin(); e != wp->events().end(); ++e) {              int cc = hh % 2 ? 0 : 1;              MusECore::Event event = e->second;              MusECore::SndFileR f  = event.sndFile(); @@ -2779,9 +2336,7 @@ void PartCanvas::copy_in_range(MusECore::PartList* pl_)            MusECore::Part* p1;            MusECore::Part* p2; -          track->splitPart(part, lpos, p1, p2); -          p1->events()->incARef(-1); -          p2->events()->incARef(-1); +          part->splitPart(lpos, p1, p2);            part=p2;          } @@ -2791,9 +2346,7 @@ void PartCanvas::copy_in_range(MusECore::PartList* pl_)            MusECore::Part* p1;            MusECore::Part* p2; -          track->splitPart(part, rpos, p1, p2); -          p1->events()->incARef(-1); -          p2->events()->incARef(-1); +          part->splitPart(rpos, p1, p2);            part=p1;          } @@ -2889,7 +2442,7 @@ MusECore::Undo PartCanvas::pasteAt(const QString& pt, MusECore::Track* track, un                          if (tag == "part") {                                                              // Read the part.                                MusECore::Part* p = 0; -                              p = readXmlPart(xml, track, clone, toTrack); +                              p = MusECore::Part::readFromXml(xml, track, clone, toTrack);                                // If it could not be created...                                if(!p) @@ -2899,9 +2452,6 @@ MusECore::Undo PartCanvas::pasteAt(const QString& pt, MusECore::Track* track, un                                  break;                                }  -                              p->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it -                                                        // so we must decrement it first :/ -                                                              // Increment the number of parts done.                                ++done; @@ -3210,13 +2760,9 @@ void PartCanvas::viewDropEvent(QDropEvent* event)                  if (!track) { // we need to create a track for this drop                      if (text.endsWith(".mpt", Qt::CaseInsensitive)) { -                        MusECore::Undo operations; -                        track = MusEGlobal::song->addTrack(operations, MusECore::Track::MIDI);    // Add at end of list. -                        MusEGlobal::song->applyOperationGroup(operations); +                        track = MusEGlobal::song->addTrack(MusECore::Track::MIDI);    // Add at end of list.                      } else { -                        MusECore::Undo operations; -                        track = MusEGlobal::song->addTrack(operations, MusECore::Track::WAVE);    // Add at end of list. -                        MusEGlobal::song->applyOperationGroup(operations); +                        track = MusEGlobal::song->addTrack(MusECore::Track::WAVE);    // Add at end of list.                      }                  }                  if (track->type() == MusECore::Track::WAVE && @@ -3475,10 +3021,9 @@ void PartCanvas::drawTopItem(QPainter& p, const QRect& rect)                 MusECore::MidiTrack *mt = (MusECore::MidiTrack*)track;                 QRect partRect(startPos,yPos, MusEGlobal::song->cpos()-startPos, track->height()); // probably the wrong rect                 MusECore::EventList myEventList; -	       MusECore::MPEventList *el = mt->mpevents(); -               if (el->size()) { +               if (mt->mpevents.size()) { -                 for (MusECore::ciMPEvent i = el->begin(); i != el->end(); ++i) { +                 for (MusECore::ciMPEvent i = mt->mpevents.begin(); i != mt->mpevents.end(); ++i) {                      MusECore::MidiPlayEvent pe = *i;                      if (pe.isNote() && !pe.isNoteOff()) { @@ -3501,7 +3046,7 @@ void PartCanvas::drawTopItem(QPainter& p, const QRect& rect)                      }                   }                 } -               drawMidiPart(p, rect, &myEventList, mt, 0, partRect,startPos,0,MusEGlobal::song->cpos()-startPos); +               drawMidiPart(p, rect, myEventList, mt, 0, partRect,startPos,0,MusEGlobal::song->cpos()-startPos);             }             yPos+=track->height();        } diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h index d34a26b6..f1d2b1a1 100644 --- a/muse2/muse/arranger/pcanvas.h +++ b/muse2/muse/arranger/pcanvas.h @@ -143,7 +143,8 @@ class PartCanvas : public Canvas {        void paste(bool clone = false, paste_mode_t paste_mode = PASTEMODE_MIX, bool to_single_track=false, int amount=1, int raster=1536);        MusECore::Undo pasteAt(const QString&, MusECore::Track*, unsigned int, bool clone = false, bool toTrack = true, int* finalPosPtr = NULL, std::set<MusECore::Track*>* affected_tracks = NULL);        void drawWavePart(QPainter&, const QRect&, MusECore::WavePart*, const QRect&); -      void drawMidiPart(QPainter&, const QRect& rect, MusECore::EventList* events, MusECore::MidiTrack*mt, MusECore::MidiPart*pt, const QRect& r, int pTick, int from, int to); +      void drawMidiPart(QPainter&, const QRect& rect, const MusECore::EventList& events, MusECore::MidiTrack* mt, MusECore::MidiPart* pt, const QRect& r, int pTick, int from, int to); +	  void drawMidiPart(QPainter&, const QRect& rect, MusECore::MidiPart* midipart, const QRect& r, int from, int to);        MusECore::Track* y2Track(int) const;        void drawAudioTrack(QPainter& p, const QRect& r, const QRect& bbox, MusECore::AudioTrack* track);        void drawAutomation(QPainter& p, const QRect& r, MusECore::AudioTrack* track); diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp index 5cea444d..7ebcad4d 100644 --- a/muse2/muse/arranger/tlist.cpp +++ b/muse2/muse/arranger/tlist.cpp @@ -75,6 +75,8 @@  #include "dssihost.h"  #endif +using MusECore::UndoOp; +  namespace MusEGui {  static const int MIN_TRACKHEIGHT = 20; @@ -599,13 +601,10 @@ void TList::returnPressed()                              }                        } -                MusEGlobal::song->startUndo(); -                MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyTrackName,  +                MusEGlobal::song->applyOperation(MusECore::UndoOp(MusECore::UndoOp::ModifyTrackName,                                                             editTrack,                                                             editTrack->name().toLatin1().constData(),                                                             editor->text().toLatin1().constData())); -                editTrack->setName(editor->text()); -                MusEGlobal::song->endUndo(-1);                   //uagh, why "-1", why no proper flags?                  }          }     @@ -640,16 +639,10 @@ void TList::chanValueFinished()            channel = 0;          if(channel != mt->outChannel())           { -              MusEGlobal::song->startUndo(); -              MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyTrackChannel,  +              MusEGlobal::song->applyOperation(MusECore::UndoOp(MusECore::UndoOp::ModifyTrackChannel,                                                             editTrack,                                                             mt->outChannel(),                                                             channel)); -              MusEGlobal::audio->msgIdle(true); -              mt->setOutChanAndUpdate(channel); -              MusEGlobal::audio->msgIdle(false); -              MusEGlobal::audio->msgUpdateSoloStates();                    -              MusEGlobal::song->endUndo(SC_MIDI_TRACK_PROP);          }              }      } @@ -667,13 +660,10 @@ void TList::chanValueFinished()                    n = 1;              if(n != at->channels())               { -                  MusEGlobal::song->startUndo(); -                  MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyTrackChannel,  +                  MusEGlobal::song->applyOperation(MusECore::UndoOp(MusECore::UndoOp::ModifyTrackChannel,                                                                 editTrack,                                                                 at->channels(),                                                                 n)); -                  MusEGlobal::audio->msgSetChannels(at, n); -                  MusEGlobal::song->endUndo(SC_CHANNELS);              }            }                 }          @@ -723,7 +713,7 @@ void TList::ctrlValueFinished()          {            if (p->second->tick()==0)            { -            for (MusECore::iEvent ev=p->second->events()->begin(); ev!=p->second->events()->end(); ev++) +            for (MusECore::ciEvent ev=p->second->events().begin(); ev!=p->second->events().end(); ev++)              {                if (ev->second.tick()!=0) break;                else if (ev->second.type()==MusECore::Controller && ev->second.dataA()==ctrl_num) @@ -1962,8 +1952,7 @@ void TList::mousePressEvent(QMouseEvent* ev)                                {                                  switch (n) {                                      case 1001:     // delete track -                                          MusEGlobal::song->removeTrack0(t); -                                          MusEGlobal::audio->msgUpdateSoloStates(); +                                          MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeleteTrack, MusEGlobal::song->tracks()->index(t), t));                                            break;                                      case 1002:     // show track comment @@ -2150,7 +2139,7 @@ void TList::mousePressEvent(QMouseEvent* ev)                            {                              if (p->second->tick()==0)                              { -                              for (MusECore::iEvent ev=p->second->events()->begin(); ev!=p->second->events()->end(); ev++) +                              for (MusECore::ciEvent ev=p->second->events().begin(); ev!=p->second->events().end(); ev++)                                {                                  if (ev->second.tick()!=0) break;                                  else if (ev->second.type()==MusECore::Controller && ev->second.dataA()==ctrl_num) @@ -2510,185 +2499,6 @@ void TList::mouseReleaseEvent(QMouseEvent* ev)  void TList::wheelEvent(QWheelEvent* ev)        {          emit redirectWheelEvent(ev); -             -// REMOVE Tim. Hate to just kill all this, so remove later if all tests OK. -//       int x           = ev->x(); -//       int y           = ev->y(); -//       MusECore::Track* t        = y2Track(y + ypos); -//       if (t == 0) { -//            emit redirectWheelEvent(ev); -//            return; -//             } -// -//       TrackColumn col = TrackColumn(header->logicalIndexAt(x)); -//       int delta       = ev->delta() / WHEEL_DELTA; -//       ev->accept(); -//  -//       switch (col) { -//             case COL_RECORD: -//             case COL_NONE: -//             case COL_CLASS: -//             case COL_NAME: -//             case COL_AUTOMATION: -//                   break; -//             case COL_MUTE: -//                   // p3.3.29 -//                   if (((QInputEvent*)ev)->modifiers() & Qt::ShiftModifier) -//                     t->setOff(!t->off()); -//                   else -//                   { -//                     if (t->off()) -//                           t->setOff(false); -//                     else -//                           t->setMute(!t->mute()); -//                   }         -//                   MusEGlobal::song->update(SC_MUTE); -//                   break; -//  -//             case COL_SOLO: -//                   MusEGlobal::audio->msgSetSolo(t, !t->solo()); -//                   MusEGlobal::song->update(SC_SOLO); -//                   break; -//  -//             case COL_TIMELOCK: -//                   t->setLocked(!t->locked()); -//                   break; -//  -//             case COL_OPORT: -//                   if (t->isMidiTrack()) { -//                         MusECore::MidiTrack* mt = (MusECore::MidiTrack*)t; -//                         int port = mt->outPort() + delta; -//  -//                         if (port >= MIDI_PORTS) -//                               port = MIDI_PORTS-1; -//                         else if (port < 0) -//                               port = 0; -//                         if (port != ((MusECore::MidiTrack*)t)->outPort()) { -//                               MusEGlobal::audio->msgIdle(true); -//                               mt->setOutPortAndUpdate(port); -//                               MusEGlobal::audio->msgIdle(false); -//                                -//                               MusEGlobal::audio->msgUpdateSoloStates();     // p4.0.14 -//                               MusEGlobal::song->update(SC_MIDI_TRACK_PROP); // p4.0.17 -//                               } -//                         } -//                   break; -//  -//             case COL_OCHANNEL: -//                   if (t->isMidiTrack()) { -//                         MusECore::MidiTrack* mt = (MusECore::MidiTrack*)t; -//                         if (mt && mt->type() == MusECore::Track::DRUM) -//                             break; -//  -//                         int channel = mt->outChannel() + delta; -//  -//                         if (channel >= MIDI_CHANNELS) -//                               channel = MIDI_CHANNELS-1; -//                         else if (channel < 0) -//                               channel = 0; -//                         if (channel != ((MusECore::MidiTrack*)t)->outChannel()) { -//                               MusEGlobal::audio->msgIdle(true); -//                               mt->setOutChanAndUpdate(channel); -//                               MusEGlobal::audio->msgIdle(false); -//                                -//                               // may result in adding/removing mixer strip: -//                               //MusEGlobal::song->update(-1); -//                               MusEGlobal::audio->msgUpdateSoloStates();         // p4.0.14 -//                               MusEGlobal::song->update(SC_MIDI_TRACK_PROP);      -//                               } -//                         } -//                   else { -//                         int n = t->channels() + delta; -//                         if (n > MAX_CHANNELS) -//                               n = MAX_CHANNELS; -//                         else if (n < 1) -//                               n = 1; -//                         if (n != t->channels()) { -//                               MusEGlobal::audio->msgSetChannels((MusECore::AudioTrack*)t, n); -//                               MusEGlobal::song->update(SC_CHANNELS); -//                               } -//                         } -//                   break; -//             default: -//                   if (col>=COL_CUSTOM_MIDICTRL_OFFSET) -//                   { -//                     mode = START_DRAG; -//  -//                     if (t->isMidiTrack())  -//                     { -//                       MusECore::MidiTrack* mt = dynamic_cast<MusECore::MidiTrack*>(t); -//                       if (mt == 0) -//                         break; -//                        -//                       int ctrl_num = Arranger::custom_columns[col-COL_CUSTOM_MIDICTRL_OFFSET].ctrl; -//                        -//                       MusECore::MidiPort* mp = &MusEGlobal::midiPorts[mt->outPort()]; -//                       MusECore::MidiController* mctl = mp->midiController(ctrl_num); -//                        -//                       int minval=mctl->minVal()+mctl->bias(); -//                       int maxval=mctl->maxVal()+mctl->bias(); -//  -//                       int val = mt->getControllerChangeAtTick(0,ctrl_num); -//                       int oldval=val; -//  -//                       if (ctrl_num!=MusECore::CTRL_PROGRAM) -//                       { -//                         val += delta; -//                         if(val > maxval) -//                           val = maxval; -//                         if(val < minval-1) // "-1" because of "off" -//                           val = minval-1; -//                       } -//                       else -//                       { -//                         MusECore::MidiInstrument* instr = mp->instrument(); -//                         if (delta>0) val=instr->getNextPatch(mt->outChannel(), val, false);  -//                         else if (delta<0) val=instr->getPrevPatch(mt->outChannel(), val, false); -//                       } -//  -//                       if (val != oldval) -//                       { -//                         if (val!=minval-1) -//                         { -//                           int at_tick; -//                           if (Arranger::custom_columns[col-COL_CUSTOM_MIDICTRL_OFFSET].affected_pos == -//                               Arranger::custom_col_t::AFFECT_BEGIN) -//                             at_tick=0; -//                           else -//                             at_tick=MusEGlobal::song->cpos(); -//                            -//                           record_controller_change_and_maybe_send(at_tick, ctrl_num, val, mt); -//                         } -//                         else -//                         { -//                           MusECore::Undo operations; -//                           for (MusECore::iPart p = mt->parts()->begin(); p!=mt->parts()->end(); p++) -//                           { -//                             if (p->second->tick()==0) -//                             { -//                               for (MusECore::iEvent ev=p->second->events()->begin(); ev!=p->second->events()->end(); ev++) -//                               { -//                                 if (ev->second.tick()!=0) break; -//                                 else if (ev->second.type()==MusECore::Controller && ev->second.dataA()==ctrl_num) -//                                 { -//                                   using MusECore::UndoOp; -//                                   operations.push_back(UndoOp(UndoOp::DeleteEvent, ev->second, p->second, false, false)); -//                                   break; -//                                 } -//                               } -//                             } -//                           } -//                           MusEGlobal::song->applyOperationGroup(operations); -//                         } -//                       } -//                     } -//                   } -//                   else -//                       mode = START_DRAG; -//  -//                   break; -//             } -                    } @@ -2729,8 +2539,7 @@ void TList::classesPopupMenu(MusECore::Track* t, int x, int y)              MusECore::PartList* pl = t->parts();              MusECore::MidiTrack* m = (MusECore::MidiTrack*) t;              for (MusECore::iPart ip = pl->begin(); ip != pl->end(); ++ip) { -                  MusECore::EventList* el = ip->second->events(); -                  for (MusECore::iEvent ie = el->begin(); ie != el->end(); ++ie) { +                  for (MusECore::ciEvent ie = ip->second->events().begin(); ie != ip->second->events().end(); ++ie) {                          MusECore::Event ev = ie->second;                          if(ev.type() == MusECore::Note)                          { @@ -2769,8 +2578,7 @@ void TList::classesPopupMenu(MusECore::Track* t, int x, int y)              MusECore::PartList* pl = t->parts();              MusECore::MidiTrack* m = (MusECore::MidiTrack*) t;              for (MusECore::iPart ip = pl->begin(); ip != pl->end(); ++ip) { -                  MusECore::EventList* el = ip->second->events(); -                  for (MusECore::iEvent ie = el->begin(); ie != el->end(); ++ie) { +                  for (MusECore::ciEvent ie = ip->second->events().begin(); ie != ip->second->events().end(); ++ie) {                          MusECore::Event ev = ie->second;                          if (ev.type() == MusECore::Note)                          { diff --git a/muse2/muse/audio.cpp b/muse2/muse/audio.cpp index 0c507fa2..f399a24c 100644 --- a/muse2/muse/audio.cpp +++ b/muse2/muse/audio.cpp @@ -76,36 +76,22 @@ void initAudio()  extern double curTime();  const char* seqMsgList[] = { -      "SEQM_ADD_TRACK", "SEQM_REMOVE_TRACK", //"SEQM_CHANGE_TRACK",   DELETETHIS -      "SEQM_MOVE_TRACK", -      "SEQM_ADD_PART", "SEQM_REMOVE_PART", "SEQM_CHANGE_PART", -      "SEQM_ADD_EVENT", "SEQM_REMOVE_EVENT", "SEQM_CHANGE_EVENT",        "SEQM_ADD_TEMPO", "SEQM_SET_TEMPO", "SEQM_REMOVE_TEMPO", "SEQM_ADD_SIG", "SEQM_REMOVE_SIG", +      "SEQM_ADD_KEY", "SEQM_REMOVE_KEY",        "SEQM_SET_GLOBAL_TEMPO", -      "SEQM_UNDO", "SEQM_REDO", +      "SEQM_REVERT_OPERATION_GROUP", "SEQM_EXECUTE_OPERATION_GROUP",        "SEQM_RESET_DEVICES", "SEQM_INIT_DEVICES", "SEQM_PANIC",        "SEQM_MIDI_LOCAL_OFF", -      "SEQM_SET_MIDI_DEVICE",        "SEQM_PLAY_MIDI_EVENT",        "SEQM_SET_HW_CTRL_STATE",        "SEQM_SET_HW_CTRL_STATES", -      "SEQM_SET_TRACK_OUT_PORT", -      "SEQM_SET_TRACK_OUT_CHAN",        "SEQM_SET_TRACK_AUTO_TYPE", -      "SEQM_REMAP_PORT_DRUM_CTL_EVS", -      "SEQM_CHANGE_ALL_PORT_DRUM_CTL_EVS", -      "SEQM_SCAN_ALSA_MIDI_PORTS",        "SEQM_SET_AUX",        "SEQM_UPDATE_SOLO_STATES", -      //"MIDI_SHOW_INSTR_GUI", DELETETHIS -      //"MIDI_SHOW_INSTR_NATIVE_GUI", DELETETHIS        "AUDIO_RECORD",        "AUDIO_ROUTEADD", "AUDIO_ROUTEREMOVE", "AUDIO_REMOVEROUTES", -      //"AUDIO_VOL", "AUDIO_PAN", DELETETHIS        "AUDIO_ADDPLUGIN", -      "AUDIO_SET_SEG_SIZE",        "AUDIO_SET_PREFADER", "AUDIO_SET_CHANNELS", -      //"AUDIO_SET_PLUGIN_CTRL_VAL", DELETETHIS        "AUDIO_SWAP_CONTROLLER_IDX",        "AUDIO_CLEAR_CONTROLLER_EVENTS",        "AUDIO_SEEK_PREV_AC_EVENT", @@ -688,17 +674,6 @@ void Audio::processMsg(AudioMsg* msg)                    MusEGlobal::midiLearnCtrl = -1;                    break; -            case AUDIO_SET_SEG_SIZE: -                  MusEGlobal::segmentSize = msg->ival; -                  MusEGlobal::sampleRate  = msg->iival; -#if 0 //TODO or DELETETHIS ? -                  audioOutput.MusEGlobal::segmentSizeChanged(); -                  for (int i = 0; i < mixerGroups; ++i) -                        audioGroups[i].MusEGlobal::segmentSizeChanged(); -                  for (iSynthI ii = synthiInstances.begin(); ii != synthiInstances.end();++ii) -                        (*ii)->MusEGlobal::segmentSizeChanged(); -#endif -                  break;              case SEQM_RESET_DEVICES:                    for (int i = 0; i < MIDI_PORTS; ++i)                          @@ -735,16 +710,6 @@ void Audio::processMsg(AudioMsg* msg)                    port->setHwCtrlStates(msg->a, msg->b, msg->c, msg->ival);                    }                    break; -            case SEQM_SCAN_ALSA_MIDI_PORTS: -                  alsaScanMidiPorts(); -                  break; -            //DELETETHIS 6 -            //case MIDI_SHOW_INSTR_GUI: -            //      MusEGlobal::midiSeq->msgUpdatePollFd(); -            //      break; -            //case MIDI_SHOW_INSTR_NATIVE_GUI:    -            //      MusEGlobal::midiSeq->msgUpdatePollFd(); -            //      break;              case SEQM_ADD_TEMPO:              case SEQM_REMOVE_TEMPO:              case SEQM_SET_GLOBAL_TEMPO: @@ -762,19 +727,6 @@ void Audio::processMsg(AudioMsg* msg)                          frameOffset   = syncFrame - samplePos;                          }                    break; -            // DELETETHIS 6 -            //case SEQM_ADD_TRACK: -            //case SEQM_REMOVE_TRACK: -            //case SEQM_CHANGE_TRACK: -            //case SEQM_ADD_PART: -            //case SEQM_REMOVE_PART: -            //case SEQM_CHANGE_PART: -            case SEQM_SET_TRACK_OUT_CHAN: -            case SEQM_SET_TRACK_OUT_PORT: -            case SEQM_REMAP_PORT_DRUM_CTL_EVS: -            case SEQM_CHANGE_ALL_PORT_DRUM_CTL_EVS: -                  MusEGlobal::midiSeq->sendMsg(msg); -                  break;              case SEQM_SET_TRACK_AUTO_TYPE:                    msg->track->setAutomationType(AutomationType(msg->ival)); @@ -1034,19 +986,17 @@ void Audio::recordStop()        MidiTrackList* ml = MusEGlobal::song->midis();        for (iMidiTrack it = ml->begin(); it != ml->end(); ++it) {              MidiTrack* mt     = *it; -            MPEventList* mpel = mt->mpevents(); -            EventList* el     = mt->events();              //---------------------------------------------------              //    resolve NoteOff events, Controller etc.              //---------------------------------------------------              // Do SysexMeta. Do loops. -            buildMidiEventList(el, mpel, mt, MusEGlobal::config.division, true, true); -            MusEGlobal::song->cmdAddRecordedEvents(mt, el,  +            buildMidiEventList(&mt->events, mt->mpevents, mt, MusEGlobal::config.division, true, true); +            MusEGlobal::song->cmdAddRecordedEvents(mt, mt->events,                    MusEGlobal::extSyncFlag.value() ? startExternalRecTick : startRecordPos.tick()); -            el->clear(); -            mpel->clear(); +            mt->events.clear(); +            mt->mpevents.clear();              }        // diff --git a/muse2/muse/audio.h b/muse2/muse/audio.h index a403e5bf..e1a90485 100644 --- a/muse2/muse/audio.h +++ b/muse2/muse/audio.h @@ -52,6 +52,7 @@ class Part;  class PluginI;  class SynthI;  class Track; +class Undo;  //---------------------------------------------------------  //   AudioMsgId @@ -60,37 +61,22 @@ class Track;  //---------------------------------------------------------  enum { -      SEQM_ADD_TRACK, SEQM_REMOVE_TRACK,   //SEQM_CHANGE_TRACK,   DELETETHIS -      SEQM_MOVE_TRACK, -      SEQM_ADD_PART, SEQM_REMOVE_PART, SEQM_CHANGE_PART, -      SEQM_ADD_EVENT, SEQM_REMOVE_EVENT, SEQM_CHANGE_EVENT,        SEQM_ADD_TEMPO, SEQM_SET_TEMPO, SEQM_REMOVE_TEMPO, SEQM_ADD_SIG, SEQM_REMOVE_SIG,        SEQM_ADD_KEY, SEQM_REMOVE_KEY,        SEQM_SET_GLOBAL_TEMPO, -      SEQM_UNDO, SEQM_REDO, +      SEQM_REVERT_OPERATION_GROUP, SEQM_EXECUTE_OPERATION_GROUP,        SEQM_RESET_DEVICES, SEQM_INIT_DEVICES, SEQM_PANIC,        SEQM_MIDI_LOCAL_OFF, -      SEQM_SET_MIDI_DEVICE,        SEQM_PLAY_MIDI_EVENT,        SEQM_SET_HW_CTRL_STATE,        SEQM_SET_HW_CTRL_STATES, -      SEQM_SET_TRACK_OUT_PORT, -      SEQM_SET_TRACK_OUT_CHAN,        SEQM_SET_TRACK_AUTO_TYPE, -      SEQM_REMAP_PORT_DRUM_CTL_EVS, -      SEQM_CHANGE_ALL_PORT_DRUM_CTL_EVS, -      SEQM_SCAN_ALSA_MIDI_PORTS,        SEQM_SET_AUX,        SEQM_UPDATE_SOLO_STATES, -      //MIDI_SHOW_INSTR_GUI,  DELETETHIS -      //MIDI_SHOW_INSTR_NATIVE_GUI, DELETETHIS        AUDIO_RECORD,        AUDIO_ROUTEADD, AUDIO_ROUTEREMOVE, AUDIO_REMOVEROUTES, -      //AUDIO_VOL, AUDIO_PAN,  DELETETHIS        AUDIO_ADDPLUGIN, -      AUDIO_SET_SEG_SIZE,        AUDIO_SET_PREFADER, AUDIO_SET_CHANNELS, -      //AUDIO_SET_PLUGIN_CTRL_VAL,  DELETETHIS        AUDIO_SWAP_CONTROLLER_IDX,        AUDIO_CLEAR_CONTROLLER_EVENTS,        AUDIO_SEEK_PREV_AC_EVENT, @@ -132,6 +118,7 @@ struct AudioMsg : public ThreadMsg {   // this should be an union        char port, channel, ctrl;        int a, b, c;        Pos pos; +      Undo* operations;        };  class AudioOutput; @@ -232,29 +219,27 @@ class Audio {        void msgSeek(const Pos&);        void msgPlay(bool val); -      void msgRemoveTrack(Track*, bool u = true); +      void msgExecuteOperationGroup(Undo&); // calls exe1, then calls exe2 in audio context, then calls exe3 +      void msgRevertOperationGroup(Undo&); // similar. +        void msgRemoveTracks(); -      //void msgChangeTrack(Track* oldTrack, Track* newTrack, bool u = true); DELETETHIS -      void msgMoveTrack(int idx1, int dx2, bool u = true); -      void msgAddPart(Part*, bool u = true); -      void msgRemovePart(Part*, bool u = true); -      void msgChangePart(Part* oldPart, Part* newPart, bool u = true, bool doCtrls = true, bool doClones = false); -      void msgAddEvent(Event&, Part*, bool u = true, bool doCtrls = true, bool doClones = false); -      void msgDeleteEvent(Event&, Part*, bool u = true, bool doCtrls = true, bool doClones = false); -      void msgChangeEvent(Event&, Event&, Part*, bool u = true, bool doCtrls = true, bool doClones = false); -      void msgScanAlsaMidiPorts(); -      void msgAddTempo(int tick, int tempo, bool doUndoFlag = true); -      void msgSetTempo(int tick, int tempo, bool doUndoFlag = true); -      void msgUpdateSoloStates(); +      void msgRemoveTrack(Track*, bool u = true); // only does applyOperation +      void msgMoveTrack(int idx1, int dx2, bool u = true); // only does applyOperation +      void msgAddPart(Part*, bool u = true); // only does applyOperation +      void msgRemovePart(Part*, bool u = true); // only does applyOperation +      void msgAddEvent(Event&, Part*, bool u = true, bool doCtrls = true, bool doClones = false); // only does applyOperation +      void msgDeleteEvent(Event&, Part*, bool u = true, bool doCtrls = true, bool doClones = false); // only does applyOperation +      void msgChangeEvent(Event&, Event&, Part*, bool u = true, bool doCtrls = true, bool doClones = false); // only does applyOperation +      void msgAddTempo(int tick, int tempo, bool doUndoFlag = true); // only does applyOperation +      void msgSetTempo(int tick, int tempo, bool doUndoFlag = true); // FIXME FINDMICHJETZT TODO! +      void msgDeleteTempo(int tick, int tempo, bool doUndoFlag = true); // only does applyOperation +      void msgUpdateSoloStates(); // TODO and below        void msgSetAux(AudioTrack*, int, double);        void msgSetGlobalTempo(int val); -      void msgDeleteTempo(int tick, int tempo, bool doUndoFlag = true);        void msgAddSig(int tick, int z, int n, bool doUndoFlag = true);        void msgRemoveSig(int tick, int z, int n, bool doUndoFlag = true);        void msgAddKey(int tick, int key, bool doUndoFlag = true);        void msgRemoveKey(int tick, int key, bool doUndoFlag = true); -      //void msgShowInstrumentGui(MidiInstrument*, bool);   DELETETHIS -      //void msgShowInstrumentNativeGui(MidiInstrument*, bool);  DELETETHIS        void msgPanic();        void sendMsg(AudioMsg*);        bool sendMessage(AudioMsg* m, bool doUndo); @@ -265,24 +250,14 @@ class Audio {        void msgAddRoute(Route, Route);        void msgAddRoute1(Route, Route);        void msgAddPlugin(AudioTrack*, int idx, PluginI* plugin); -      void msgSetMute(AudioTrack*, bool val); -      //void msgSetVolume(AudioTrack*, double val); DELETETHIS -      //void msgSetPan(AudioTrack*, double val);    DELETETHIS -      void msgAddSynthI(SynthI* synth); -      void msgRemoveSynthI(SynthI* synth); -      void msgSetSegSize(int, int);        void msgSetPrefader(AudioTrack*, int);        void msgSetChannels(AudioTrack*, int); -      void msgSetOff(AudioTrack*, bool);        void msgSetRecord(AudioTrack*, bool); -      void msgUndo(); -      void msgRedo();        void msgLocalOff();        void msgInitMidiDevices(bool force = true);        void msgResetMidiDevices();        void msgIdle(bool);        void msgBounce(); -      //void msgSetPluginCtrlVal(AudioTrack*, int /*param*/, double /*val*/);  DELETETHIS        void msgSwapControllerIDX(AudioTrack*, int, int);        void msgClearControllerEvents(AudioTrack*, int);        void msgSeekPrevACEvent(AudioTrack*, int); @@ -294,17 +269,11 @@ class Audio {        void msgSetSolo(Track*, bool);        void msgSetHwCtrlState(MidiPort*, int, int, int);        void msgSetHwCtrlStates(MidiPort*, int, int, int, int); -      void msgSetTrackOutChannel(MidiTrack*, int); -      void msgSetTrackOutPort(MidiTrack*, int);        void msgSetTrackAutomationType(Track*, int); -      void msgRemapPortDrumCtlEvents(int, int, int, int); -      void msgChangeAllPortDrumCtrlEvents(bool, bool);        void msgSetSendMetronome(AudioTrack*, bool);        void msgStartMidiLearn(); -        void msgPlayMidiEvent(const MidiPlayEvent* event); -      void rescanAlsaPorts(); - +              void midiPortsChanged();        const Pos& pos() const { return _pos; } diff --git a/muse2/muse/ctrl/ctrlcanvas.cpp b/muse2/muse/ctrl/ctrlcanvas.cpp index d5adbc4f..8dd7fa9a 100644 --- a/muse2/muse/ctrl/ctrlcanvas.cpp +++ b/muse2/muse/ctrl/ctrlcanvas.cpp @@ -608,14 +608,13 @@ void CtrlCanvas::updateItems()                if (filterTrack && part->track() != curTrack)                  continue; -              MusECore::EventList* el = part->events();                MusECore::MidiCtrlValList* mcvl;                partControllers(part, _cnum, 0, 0, 0, &mcvl);                unsigned len = part->lenTick(); -              for (MusECore::iEvent i = el->begin(); i != el->end(); ++i)  +              for (MusECore::ciEvent i = part->events().begin(); i != part->events().end(); ++i)                 { -                    MusECore::Event e = i->second; +                    const MusECore::Event& e = i->second;                      // Do not add events which are past the end of the part.                      if(e.tick() >= len)                        break; diff --git a/muse2/muse/event.cpp b/muse2/muse/event.cpp index 1a2d3c6e..32b72277 100644 --- a/muse2/muse/event.cpp +++ b/muse2/muse/event.cpp @@ -74,7 +74,7 @@ void EventBase::dump(int n) const  //   clone  //--------------------------------------------------------- -Event Event::clone() +Event Event::clone() const        {        #ifdef USE_SAMPLERATE        return Event(ev->clone(), _audConv); @@ -179,6 +179,10 @@ Event& Event::operator=(const Event& e) {  bool Event::operator==(const Event& e) const {              return ev == e.ev;              } +bool Event::isSimilarTo(const Event& other) const +{ +		return ev->isSimilarTo(*other.ev); +}  int Event::getRefCount() const    { return ev->getRefCount(); }  bool Event::selected() const      { return ev->_selected; } @@ -203,7 +207,7 @@ void Event::read(Xml& xml)  void Event::write(int a, Xml& xml, const Pos& o, bool forceWavePaths) const { ev->write(a, xml, o, forceWavePaths); }  void Event::dump(int n) const     { ev->dump(n); } -Event Event::mid(unsigned a, unsigned b) { return Event(ev->mid(a, b)); } +Event Event::mid(unsigned a, unsigned b) const { return Event(ev->mid(a, b)); }  bool Event::isNote() const                   { return ev->isNote();        }  bool Event::isNoteOff() const                { return ev->isNoteOff();     } diff --git a/muse2/muse/event.h b/muse2/muse/event.h index 8da37d4f..b2f5a50a 100644 --- a/muse2/muse/event.h +++ b/muse2/muse/event.h @@ -64,6 +64,7 @@ class Event {        void setType(EventType t);        Event& operator=(const Event& e);        bool operator==(const Event& e) const; +      bool isSimilarTo(const Event& other) const;        int getRefCount() const;        bool selected() const; @@ -73,8 +74,8 @@ class Event {        void read(Xml& xml);        void write(int a, Xml& xml, const Pos& offset, bool ForceWavePaths = false) const;        void dump(int n = 0) const; -      Event clone(); -      Event mid(unsigned a, unsigned b); +      Event clone() const; +      Event mid(unsigned a, unsigned b) const;        bool isNote() const;        bool isNoteOff() const; @@ -124,7 +125,7 @@ typedef std::multimap <unsigned, Event, std::less<unsigned> > EL;  typedef EL::iterator iEvent;  typedef EL::reverse_iterator riEvent;  typedef EL::const_iterator ciEvent; -typedef std::pair <iEvent, iEvent> EventRange; +typedef std::pair <ciEvent, ciEvent> EventRange;  //---------------------------------------------------------  //   EventList @@ -132,21 +133,14 @@ typedef std::pair <iEvent, iEvent> EventRange;  //---------------------------------------------------------  class EventList : public EL { -      int ref;          // number of references to this EventList -      int aref;         // number of active references (exclude undo list)        void deselect();     public: -      EventList()           { ref = 0; aref = 0;  } -      ~EventList()          {} - -      void incRef(int n)    { ref += n;    } -      int refCount() const  { return ref;  } -      void incARef(int n)   { aref += n;   } -      int arefCount() const { return aref; } - +      ciEvent find(const Event&) const;        iEvent find(const Event&); -      iEvent add(Event& event); +      ciEvent findSimilar(const Event&) const; +      iEvent findSimilar(const Event&); +      iEvent add(Event event);        void move(Event& event, unsigned tick);        void dump() const;        void read(Xml& xml, const char* name, bool midi); diff --git a/muse2/muse/eventbase.h b/muse2/muse/eventbase.h index 0cb960d9..92e91761 100644 --- a/muse2/muse/eventbase.h +++ b/muse2/muse/eventbase.h @@ -56,11 +56,13 @@ class EventBase : public PosLen {        void setSelected(bool val) { _selected = val; }        void move(int offset); +       +      virtual bool isSimilarTo(const EventBase& other) const = 0;        virtual void read(Xml&) = 0;        virtual void write(int, Xml&, const Pos& offset, bool forcePath = false) const = 0;        virtual void dump(int n = 0) const; -      virtual EventBase* mid(unsigned, unsigned) = 0; +      virtual EventBase* mid(unsigned, unsigned) const = 0;        friend class Event;        virtual bool isNote() const                   { return false; } @@ -95,7 +97,7 @@ class EventBase : public PosLen {        virtual void setSpos(int)                     { }        virtual SndFileR sndFile() const              { return 0;      }        virtual void setSndFile(SndFileR&)            { } -      virtual EventBase* clone() = 0; +      virtual EventBase* clone() const = 0;        virtual void readAudio(WavePart* /*part*/, unsigned /*offset*/,                                float** /*bpp*/, int /*channels*/, int /*nn*/, bool /*doSeek*/, bool /*overwrite*/) { } diff --git a/muse2/muse/eventlist.cpp b/muse2/muse/eventlist.cpp index 50ba2652..80180ab7 100644 --- a/muse2/muse/eventlist.cpp +++ b/muse2/muse/eventlist.cpp @@ -62,7 +62,7 @@ void EventList::read(Xml& xml, const char* name, bool midi)  //   add  //--------------------------------------------------------- -iEvent EventList::add(Event& event) +iEvent EventList::add(Event event)        {        // Changed by Tim. An event list containing wave events should be sorted by        //  frames. WaveTrack::fetchData() relies on the sorting order, and @@ -129,17 +129,51 @@ void EventList::move(Event& event, unsigned tick)  //---------------------------------------------------------  iEvent EventList::find(const Event& event) +{ +      std::pair<iEvent,iEvent> range = equal_range(event.type() == Wave ? event.frame() : event.tick()); + +      for (iEvent i = range.first; i != range.second; ++i) { +            if (i->second == event) +                  return i; +            } +      return end(); +} + +ciEvent EventList::find(const Event& event) const        {        EventRange range = equal_range(event.type() == Wave ? event.frame() : event.tick()); -      for (iEvent i = range.first; i != range.second; ++i) { +      for (ciEvent i = range.first; i != range.second; ++i) {              if (i->second == event)                    return i;              }        return end();        } +iEvent EventList::findSimilar(const Event& event) +{ +      std::pair<iEvent,iEvent> range = equal_range(event.type() == Wave ? event.frame() : event.tick()); + +      for (iEvent i = range.first; i != range.second; ++i) { +            if (i->second.isSimilarTo(event)) +                  return i; +            } +      return end(); +} + +ciEvent EventList::findSimilar(const Event& event) const +      { +      EventRange range = equal_range(event.type() == Wave ? event.frame() : event.tick()); + +       +      for (ciEvent i = range.first; i != range.second; ++i) { +            if (i->second.isSimilarTo(event)) +                  return i; +            } +      return end(); +      } +  //---------------------------------------------------------  //   dump  //--------------------------------------------------------- diff --git a/muse2/muse/exportmidi.cpp b/muse2/muse/exportmidi.cpp index e5cd74e1..34ac8983 100644 --- a/muse2/muse/exportmidi.cpp +++ b/muse2/muse/exportmidi.cpp @@ -131,11 +131,11 @@ static void addController(MPEventList* l, int tick, int port, int channel, int a  //     track can be NULL meaning no concept of drum notes is allowed in init sequences.  //--------------------------------------------------------- -static void addEventList(MusECore::EventList* evlist, MusECore::MPEventList* mpevlist, MusECore::MidiTrack* track, MusECore::Part* part, int port, int channel) +static void addEventList(const MusECore::EventList& evlist, MusECore::MPEventList* mpevlist, MusECore::MidiTrack* track, MusECore::Part* part, int port, int channel)  {       -  for (MusECore::iEvent i = evlist->begin(); i != evlist->end(); ++i)  +  for (MusECore::ciEvent i = evlist.begin(); i != evlist.end(); ++i)     { -    MusECore::Event ev = i->second; +    const MusECore::Event& ev = i->second;      int tick = ev.tick();      if(part)        tick += part->tick(); @@ -490,7 +490,7 @@ void MusE::exportMidi()                      {                        MusECore::EventList* el = instr->midiInit();                        if(!el->empty()) -                        MusECore::addEventList(el, l, NULL, NULL, port, channel); // No track or part passed for init sequences +                        MusECore::addEventList(*el, l, NULL, NULL, port, channel); // No track or part passed for init sequences                      }                      //-------------------------- @@ -519,8 +519,7 @@ void MusE::exportMidi()              MusECore::PartList* parts = track->parts();              for (MusECore::iPart p = parts->begin(); p != parts->end(); ++p) {                    MusECore::MidiPart* part    = (MusECore::MidiPart*) (p->second); -                  MusECore::EventList* evlist = part->events(); -                  MusECore::addEventList(evlist, l, track, part, port, channel);  +                  MusECore::addEventList(part->events(), l, track, part, port, channel);                     }              ++i;   @@ -529,12 +528,7 @@ void MusE::exportMidi()        mf.setDivision(MusEGlobal::config.midiDivision);        mf.setTrackList(mtl, i);        mf.write(); -       -      // DELETETHIS 4 ??? or is this still an issue? -      // TESTING: Cleanup. I did not valgrind this feature in last memleak fixes, but I suspect it leaked.  -      //for(MusECore::iMidiFileTrack imft = mtl->begin(); imft != mtl->end(); ++imft) -      //  delete *imft; -      //delete mtl; +        }  } // namespace MusEGui diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index fa53f5d4..7569cc95 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -2,7 +2,7 @@  //  MusE  //  Linux Music Editor  //    $Id: functions.cpp,v 1.20.2.19 2011/05/05 20:10 flo93 Exp $ -//  (C) Copyright 2011 Florian Jung (flo93@sourceforge.net) +//  (C) Copyright 2011,2013 Florian Jung (flo93@sourceforge.net)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -71,9 +71,9 @@ bool read_eventlist_and_part(Xml& xml, EventList* el, int* part_id); -set<Part*> partlist_to_set(PartList* pl) +set<const Part*> partlist_to_set(PartList* pl)  { -	set<Part*> result; +	set<const Part*> result;  	for (PartList::iterator it=pl->begin(); it!=pl->end(); it++)  		result.insert(it->second); @@ -81,16 +81,16 @@ set<Part*> partlist_to_set(PartList* pl)  	return result;  } -set<Part*> part_to_set(Part* p) +set<const Part*> part_to_set(const Part* p)  { -	set<Part*> result; +	set<const Part*> result;  	result.insert(p);  	return result;  } -set<Part*> get_all_parts() +set<const Part*> get_all_parts()  { -	set<Part*> result; +	set<const Part*> result;  	TrackList* tracks=MusEGlobal::song->tracks();  	for (TrackList::const_iterator t_it=tracks->begin(); t_it!=tracks->end(); t_it++) @@ -103,9 +103,9 @@ set<Part*> get_all_parts()  	return result;  } -set<Part*> get_all_selected_parts() +set<const Part*> get_all_selected_parts()  { -	set<Part*> result; +	set<const Part*> result;  	TrackList* tracks=MusEGlobal::song->tracks();  	for (TrackList::const_iterator t_it=tracks->begin(); t_it!=tracks->end(); t_it++) @@ -137,14 +137,14 @@ bool is_relevant(const Event& event, const Part* part, int range)  } -map<Event*, Part*> get_events(const set<Part*>& parts, int range) +map<const Event*, const Part*> get_events(const set<const Part*>& parts, int range)  { -	map<Event*, Part*> events; +	map<const Event*, const Part*> events; -	for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++) -		for (iEvent event=(*part)->events()->begin(); event!=(*part)->events()->end(); event++) +	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +		for (ciEvent event=(*part)->events().begin(); event!=(*part)->events().end(); event++)  			if (is_relevant(event->second, *part, range)) -				events.insert(pair<Event*, Part*>(&event->second, *part)); +				events.insert(pair<const Event*, const Part*>(&event->second, *part));  	return events;  } @@ -152,7 +152,7 @@ map<Event*, Part*> get_events(const set<Part*>& parts, int range) -bool modify_notelen(const set<Part*>& parts) +bool modify_notelen(const set<const Part*>& parts)  {  	if (!MusEGui::gatetime_dialog->exec())  		return false; @@ -162,7 +162,7 @@ bool modify_notelen(const set<Part*>& parts)  	return true;  } -bool modify_velocity(const set<Part*>& parts) +bool modify_velocity(const set<const Part*>& parts)  {  	if (!MusEGui::velocity_dialog->exec())  		return false; @@ -172,7 +172,7 @@ bool modify_velocity(const set<Part*>& parts)  	return true;  } -bool quantize_notes(const set<Part*>& parts) +bool quantize_notes(const set<const Part*>& parts)  {  	if (!MusEGui::quantize_dialog->exec())  		return false; @@ -185,7 +185,7 @@ bool quantize_notes(const set<Part*>& parts)  	return true;  } -bool erase_notes(const set<Part*>& parts) +bool erase_notes(const set<const Part*>& parts)  {  	if (!MusEGui::erase_dialog->exec())  		return false; @@ -196,7 +196,7 @@ bool erase_notes(const set<Part*>& parts)  	return true;  } -bool delete_overlaps(const set<Part*>& parts) +bool delete_overlaps(const set<const Part*>& parts)  {  	if (!MusEGui::del_overlaps_dialog->exec())  		return false; @@ -206,7 +206,7 @@ bool delete_overlaps(const set<Part*>& parts)  	return true;  } -bool set_notelen(const set<Part*>& parts) +bool set_notelen(const set<const Part*>& parts)  {  	if (!MusEGui::set_notelen_dialog->exec())  		return false; @@ -216,7 +216,7 @@ bool set_notelen(const set<Part*>& parts)  	return true;  } -bool move_notes(const set<Part*>& parts) +bool move_notes(const set<const Part*>& parts)  {  	if (!MusEGui::move_notes_dialog->exec())  		return false; @@ -226,7 +226,7 @@ bool move_notes(const set<Part*>& parts)  	return true;  } -bool transpose_notes(const set<Part*>& parts) +bool transpose_notes(const set<const Part*>& parts)  {  	if (!MusEGui::transpose_dialog->exec())  		return false; @@ -236,7 +236,7 @@ bool transpose_notes(const set<Part*>& parts)  	return true;  } -bool crescendo(const set<Part*>& parts) +bool crescendo(const set<const Part*>& parts)  {  	if (MusEGlobal::song->rpos() <= MusEGlobal::song->lpos())  	{ @@ -252,7 +252,7 @@ bool crescendo(const set<Part*>& parts)  	return true;  } -bool legato(const set<Part*>& parts) +bool legato(const set<const Part*>& parts)  {  	if (!MusEGui::legato_dialog->exec())  		return false; @@ -269,7 +269,7 @@ bool modify_notelen()  	if (!MusEGui::gatetime_dialog->exec())  		return false; -	set<Part*> parts; +	set<const Part*> parts;  	if (MusEGui::gatetime_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)  		parts=get_all_selected_parts();  	else @@ -285,7 +285,7 @@ bool modify_velocity()  	if (!MusEGui::velocity_dialog->exec())  		return false; -	set<Part*> parts; +	set<const Part*> parts;  	if (MusEGui::velocity_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)  		parts=get_all_selected_parts();  	else @@ -301,7 +301,7 @@ bool quantize_notes()  	if (!MusEGui::quantize_dialog->exec())  		return false; -	set<Part*> parts; +	set<const Part*> parts;  	if (MusEGui::quantize_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)  		parts=get_all_selected_parts();  	else @@ -320,7 +320,7 @@ bool erase_notes()  	if (!MusEGui::erase_dialog->exec())  		return false; -	set<Part*> parts; +	set<const Part*> parts;  	if (MusEGui::erase_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)  		parts=get_all_selected_parts();  	else @@ -337,7 +337,7 @@ bool delete_overlaps()  	if (!MusEGui::del_overlaps_dialog->exec())  		return false; -	set<Part*> parts; +	set<const Part*> parts;  	if (MusEGui::del_overlaps_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)  		parts=get_all_selected_parts();  	else @@ -353,7 +353,7 @@ bool set_notelen()  	if (!MusEGui::set_notelen_dialog->exec())  		return false; -	set<Part*> parts; +	set<const Part*> parts;  	if (MusEGui::set_notelen_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)  		parts=get_all_selected_parts();  	else @@ -369,7 +369,7 @@ bool move_notes()  	if (!MusEGui::move_notes_dialog->exec())  		return false; -	set<Part*> parts; +	set<const Part*> parts;  	if (MusEGui::move_notes_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)  		parts=get_all_selected_parts();  	else @@ -385,7 +385,7 @@ bool transpose_notes()  	if (!MusEGui::transpose_dialog->exec())  		return false; -	set<Part*> parts; +	set<const Part*> parts;  	if (MusEGui::transpose_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)  		parts=get_all_selected_parts();  	else @@ -407,7 +407,7 @@ bool crescendo()  	if (!MusEGui::crescendo_dialog->exec())  		return false; -	set<Part*> parts; +	set<const Part*> parts;  	if (MusEGui::crescendo_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)  		parts=get_all_selected_parts();  	else @@ -423,7 +423,7 @@ bool legato()  	if (!MusEGui::legato_dialog->exec())  		return false; -	set<Part*> parts; +	set<const Part*> parts;  	if (MusEGui::legato_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)  		parts=get_all_selected_parts();  	else @@ -439,17 +439,17 @@ bool legato() -bool modify_velocity(const set<Part*>& parts, int range, int rate, int offset) +bool modify_velocity(const set<const Part*>& parts, int range, int rate, int offset)  { -	map<Event*, Part*> events = get_events(parts, range); +	map<const Event*, const Part*> events = get_events(parts, range);  	Undo operations;  	if ( (!events.empty()) && ((rate!=100) || (offset!=0)) )  	{ -		for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) +		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)  		{ -			Event& event=*(it->first); -			Part* part=it->second; +			const Event& event=*(it->first); +			const Part* part=it->second;  			int velo = event.velo(); @@ -475,17 +475,17 @@ bool modify_velocity(const set<Part*>& parts, int range, int rate, int offset)  		return false;  } -bool modify_off_velocity(const set<Part*>& parts, int range, int rate, int offset) +bool modify_off_velocity(const set<const Part*>& parts, int range, int rate, int offset)  { -	map<Event*, Part*> events = get_events(parts, range); +	map<const Event*, const Part*> events = get_events(parts, range);  	Undo operations;  	if ( (!events.empty()) && ((rate!=100) || (offset!=0)) )  	{ -		for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) +		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)  		{ -			Event& event=*(it->first); -			Part* part=it->second; +			const Event& event=*(it->first); +			const Part* part=it->second;  			int velo = event.veloOff(); @@ -511,18 +511,18 @@ bool modify_off_velocity(const set<Part*>& parts, int range, int rate, int offse  		return false;  } -bool modify_notelen(const set<Part*>& parts, int range, int rate, int offset) +bool modify_notelen(const set<const Part*>& parts, int range, int rate, int offset)  { -	map<Event*, Part*> events = get_events(parts, range); +	map<const Event*, const Part*> events = get_events(parts, range);  	Undo operations; -	map<Part*, int> partlen; +	map<const Part*, int> partlen;  	if ( (!events.empty()) && ((rate!=100) || (offset!=0)) )  	{ -		for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) +		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)  		{ -			Event& event=*(it->first); -			Part* part=it->second; +			const Event& event=*(it->first); +			const Part* part=it->second;  			unsigned int len = event.lenTick(); //prevent compiler warning: comparison singed/unsigned @@ -543,7 +543,7 @@ bool modify_notelen(const set<Part*>& parts, int range, int rate, int offset)  			}  		} -		for (map<Part*, int>::iterator it=partlen.begin(); it!=partlen.end(); it++) +		for (map<const Part*, int>::iterator it=partlen.begin(); it!=partlen.end(); it++)  			schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);  		return MusEGlobal::song->applyOperationGroup(operations); @@ -552,7 +552,7 @@ bool modify_notelen(const set<Part*>& parts, int range, int rate, int offset)  		return false;  } -bool set_notelen(const set<Part*>& parts, int range, int len) +bool set_notelen(const set<const Part*>& parts, int range, int len)  {  	return modify_notelen(parts, range, 0, len);  } @@ -579,17 +579,17 @@ unsigned quantize_tick(unsigned tick, unsigned raster, int swing)  		return tick_dest1;  } -bool quantize_notes(const set<Part*>& parts, int range, int raster, bool quant_len, int strength, int swing, int threshold) +bool quantize_notes(const set<const Part*>& parts, int range, int raster, bool quant_len, int strength, int swing, int threshold)  { -	map<Event*, Part*> events = get_events(parts, range); +	map<const Event*, const Part*> events = get_events(parts, range);  	Undo operations;  	if (!events.empty())  	{ -		for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) +		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)  		{ -			Event& event=*(it->first); -			Part* part=it->second; +			const Event& event=*(it->first); +			const Part* part=it->second;  			unsigned begin_tick = event.tick() + part->tick();  			int begin_diff = quantize_tick(begin_tick, raster, swing) - begin_tick; @@ -625,17 +625,17 @@ bool quantize_notes(const set<Part*>& parts, int range, int raster, bool quant_l  		return false;  } -bool erase_notes(const set<Part*>& parts, int range, int velo_threshold, bool velo_thres_used, int len_threshold, bool len_thres_used) +bool erase_notes(const set<const Part*>& parts, int range, int velo_threshold, bool velo_thres_used, int len_threshold, bool len_thres_used)  { -	map<Event*, Part*> events = get_events(parts, range); +	map<const Event*, const Part*> events = get_events(parts, range);  	Undo operations;  	if (!events.empty())  	{ -		for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) +		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)  		{ -			Event& event=*(it->first); -			Part* part=it->second; +			const Event& event=*(it->first); +			const Part* part=it->second;  			if ( (!velo_thres_used && !len_thres_used) ||  			     (velo_thres_used && event.velo() < velo_threshold) || @@ -649,17 +649,17 @@ bool erase_notes(const set<Part*>& parts, int range, int velo_threshold, bool ve  		return false;  } -bool transpose_notes(const set<Part*>& parts, int range, signed int halftonesteps) +bool transpose_notes(const set<const Part*>& parts, int range, signed int halftonesteps)  { -	map<Event*, Part*> events = get_events(parts, range); +	map<const Event*, const Part*> events = get_events(parts, range);  	Undo operations;  	if ( (!events.empty()) && (halftonesteps!=0) )  	{ -		for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) +		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)  		{ -			Event& event=*(it->first); -			Part* part=it->second; +			const Event& event=*(it->first); +			const Part* part=it->second;  			Event newEvent = event.clone();  			int pitch = event.pitch()+halftonesteps; @@ -675,9 +675,9 @@ bool transpose_notes(const set<Part*>& parts, int range, signed int halftonestep  		return false;  } -bool crescendo(const set<Part*>& parts, int range, int start_val, int end_val, bool absolute) +bool crescendo(const set<const Part*>& parts, int range, int start_val, int end_val, bool absolute)  { -	map<Event*, Part*> events = get_events(parts, range); +	map<const Event*, const Part*> events = get_events(parts, range);  	Undo operations;  	int from=MusEGlobal::song->lpos(); @@ -685,10 +685,10 @@ bool crescendo(const set<Part*>& parts, int range, int start_val, int end_val, b  	if ( (!events.empty()) && (to>from) )  	{ -		for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) +		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)  		{ -			Event& event=*(it->first); -			Part* part=it->second; +			const Event& event=*(it->first); +			const Part* part=it->second;  			unsigned tick = event.tick() + part->tick();  			float curr_val= (float)start_val  +  (float)(end_val-start_val) * (tick-from) / (to-from); @@ -713,18 +713,18 @@ bool crescendo(const set<Part*>& parts, int range, int start_val, int end_val, b  		return false;  } -bool move_notes(const set<Part*>& parts, int range, signed int ticks) +bool move_notes(const set<const Part*>& parts, int range, signed int ticks)  { -	map<Event*, Part*> events = get_events(parts, range); +	map<const Event*, const Part*> events = get_events(parts, range);  	Undo operations; -	map<Part*, int> partlen; +	map<const Part*, int> partlen;  	if ( (!events.empty()) && (ticks!=0) )  	{ -		for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) +		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)  		{ -			Event& event=*(it->first); -			Part* part=it->second; +			const Event& event=*(it->first); +			const Part* part=it->second;  			bool del=false;  			Event newEvent = event.clone(); @@ -752,7 +752,7 @@ bool move_notes(const set<Part*>& parts, int range, signed int ticks)  				operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, false, false));  		} -		for (map<Part*, int>::iterator it=partlen.begin(); it!=partlen.end(); it++) +		for (map<const Part*, int>::iterator it=partlen.begin(); it!=partlen.end(); it++)  			schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);  		return MusEGlobal::song->applyOperationGroup(operations); @@ -762,29 +762,29 @@ bool move_notes(const set<Part*>& parts, int range, signed int ticks)  } -bool delete_overlaps(const set<Part*>& parts, int range) +bool delete_overlaps(const set<const Part*>& parts, int range)  { -	map<Event*, Part*> events = get_events(parts, range); +	map<const Event*, const Part*> events = get_events(parts, range);  	Undo operations; -	set<Event*> deleted_events; +	set<const Event*> deleted_events;  	if (!events.empty())  	{ -		for (map<Event*, Part*>::iterator it1=events.begin(); it1!=events.end(); it1++) +		for (map<const Event*, const Part*>::iterator it1=events.begin(); it1!=events.end(); it1++)  		{ -			Event& event1=*(it1->first); -			Part* part1=it1->second; +			const Event& event1=*(it1->first); +			const Part* part1=it1->second;  			// we may NOT optimize by letting it2 start at (it1 +1); this optimisation  			// is only allowed when events was sorted by time. it is, however, sorted  			// randomly by pointer. -			for (map<Event*, Part*>::iterator it2=events.begin(); it2!=events.end(); it2++) +			for (map<const Event*, const Part*>::iterator it2=events.begin(); it2!=events.end(); it2++)  			{ -				Event& event2=*(it2->first); -				Part* part2=it2->second; +				const Event& event2=*(it2->first); +				const Part* part2=it2->second; -				if ( (part1->events()==part2->events()) && // part1 and part2 are the same or are duplicates +				if ( (part1->isCloneOf(part2)) &&          // part1 and part2 are the same or are duplicates  				     (&event1 != &event2) &&               // and event1 and event2 aren't the same  				     (deleted_events.find(&event2) == deleted_events.end()) ) //and event2 hasn't been deleted before  				{ @@ -817,34 +817,34 @@ bool delete_overlaps(const set<Part*>& parts, int range)  		return false;  } -bool legato(const set<Part*>& parts, int range, int min_len, bool dont_shorten) +bool legato(const set<const Part*>& parts, int range, int min_len, bool dont_shorten)  { -	map<Event*, Part*> events = get_events(parts, range); +	map<const Event*, const Part*> events = get_events(parts, range);  	Undo operations;  	if (min_len<=0) min_len=1;  	if (!events.empty())  	{ -		for (map<Event*, Part*>::iterator it1=events.begin(); it1!=events.end(); it1++) +		for (map<const Event*, const Part*>::iterator it1=events.begin(); it1!=events.end(); it1++)  		{ -			Event& event1=*(it1->first); -			Part* part1=it1->second; +			const Event& event1=*(it1->first); +			const Part* part1=it1->second;  			unsigned len=INT_MAX;  			// we may NOT optimize by letting it2 start at (it1 +1); this optimisation  			// is only allowed when events was sorted by time. it is, however, sorted  			// randomly by pointer. -			for (map<Event*, Part*>::iterator it2=events.begin(); it2!=events.end(); it2++) +			for (map<const Event*, const Part*>::iterator it2=events.begin(); it2!=events.end(); it2++)  			{ -				Event& event2=*(it2->first); -				Part* part2=it2->second; +				const Event& event2=*(it2->first); +				const Part* part2=it2->second;  				bool relevant = (event2.tick() >= event1.tick() + min_len);  				if (dont_shorten)  					relevant = relevant && (event2.tick() >= event1.endTick()); -				if ( (part1->events()==part2->events()) &&  // part1 and part2 are the same or are duplicates +				if ( (part1->isCloneOf(part2)) &&           // part1 and part2 are the same or are duplicates  				      relevant &&                           // they're not too near (respect min_len and dont_shorten)  				     (event2.tick()-event1.tick() < len ) ) // that's the nearest relevant following note  					len=event2.tick()-event1.tick(); @@ -869,7 +869,7 @@ bool legato(const set<Part*>& parts, int range, int min_len, bool dont_shorten) -void copy_notes(const set<Part*>& parts, int range) +void copy_notes(const set<const Part*>& parts, int range)  {  	QMimeData* drag = selected_events_to_mime(parts,range); @@ -926,7 +926,7 @@ unsigned get_clipboard_len()  	return get_groupedevents_len(s);  } -bool paste_notes(Part* paste_into_part) +bool paste_notes(const Part* paste_into_part)  {  	unsigned temp_begin = AL::sigmap.raster1(MusEGlobal::song->cpos(),0);  	unsigned temp_end = AL::sigmap.raster2(temp_begin + get_clipboard_len(), 0); @@ -943,7 +943,7 @@ bool paste_notes(Part* paste_into_part)  	return true;  } -void paste_notes(int max_distance, bool always_new_part, bool never_new_part, Part* paste_into_part, int amount, int raster) +void paste_notes(int max_distance, bool always_new_part, bool never_new_part, const Part* paste_into_part, int amount, int raster)  {  	QString tmp="x-muse-groupedeventlists"; // QClipboard::text() expects a QString&, not a QString :(  	QString s = QApplication::clipboard()->text(tmp, QClipboard::Clipboard);  // TODO CHECK Tim. @@ -951,12 +951,12 @@ void paste_notes(int max_distance, bool always_new_part, bool never_new_part, Pa  }  // if nothing is selected/relevant, this function returns NULL -QMimeData* selected_events_to_mime(const set<Part*>& parts, int range) +QMimeData* selected_events_to_mime(const set<const Part*>& parts, int range)  {      unsigned start_tick = INT_MAX; //will be the tick of the first event or INT_MAX if no events are there -    for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++) -        for (iEvent ev=(*part)->events()->begin(); ev!=(*part)->events()->end(); ev++) +    for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +        for (ciEvent ev=(*part)->events().begin(); ev!=(*part)->events().end(); ev++)              if (is_relevant(ev->second, *part, range))                  if (ev->second.tick() < start_tick)                      start_tick=ev->second.tick(); @@ -978,10 +978,10 @@ QMimeData* selected_events_to_mime(const set<Part*>& parts, int range)      Xml xml(tmp);      int level = 0; -    for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +    for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++)      {          xml.tag(level++, "eventlist part_id=\"%d\"", (*part)->sn()); -        for (iEvent ev=(*part)->events()->begin(); ev!=(*part)->events()->end(); ev++) +        for (ciEvent ev=(*part)->events().begin(); ev!=(*part)->events().end(); ev++)              if (is_relevant(ev->second, *part, range))                  ev->second.write(level, xml, -start_tick);          xml.etag(--level, "eventlist"); @@ -993,7 +993,7 @@ QMimeData* selected_events_to_mime(const set<Part*>& parts, int range)  }  // if nothing is selected/relevant, this function returns NULL -QMimeData* parts_to_mime(const set<Part*>& parts) +QMimeData* parts_to_mime(const set<const Part*>& parts)  {  	//--------------------------------------------------- @@ -1012,7 +1012,7 @@ QMimeData* parts_to_mime(const set<Part*>& parts)      bool midi=false;      bool wave=false; -	for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++)  	{          if ((*part)->track()->type() == MusECore::Track::MIDI)              midi=true; @@ -1102,11 +1102,11 @@ bool read_eventlist_and_part(Xml& xml, EventList* el, int* part_id) // true on s  	}  } -void paste_at(const QString& pt, int pos, int max_distance, bool always_new_part, bool never_new_part, Part* paste_into_part, int amount, int raster) +void paste_at(const QString& pt, int pos, int max_distance, bool always_new_part, bool never_new_part, const Part* paste_into_part, int amount, int raster)  {  	Undo operations; -	map<Part*, unsigned> expand_map; -	map<Part*, set<Part*> > new_part_map; +	map<const Part*, unsigned> expand_map; +	map<const Part*, set<const Part*> > new_part_map;  	QByteArray pt_= pt.toLatin1();  	Xml xml(pt_.constData()); @@ -1128,9 +1128,9 @@ void paste_at(const QString& pt, int pos, int max_distance, bool always_new_part  					if (read_eventlist_and_part(xml, &el, &part_id))  					{ -						Part* dest_part; +						const Part* dest_part;  						Track* dest_track; -						Part* old_dest_part; +						const Part* old_dest_part;  						if (paste_into_part == NULL)  							dest_part = partFromSerialNumber(part_id); @@ -1157,13 +1157,12 @@ void paste_at(const QString& pt, int pos, int max_distance, bool always_new_part  								if (create_new_part)  								{ -									dest_part = dest_track->newPart(); -									dest_part->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it -																										// so we must decrement it first :/ -									dest_part->setTick(AL::sigmap.raster1(first_paste_tick, config.division)); +									Part* newpart = dest_track->newPart(); +									newpart->setTick(AL::sigmap.raster1(first_paste_tick, config.division));  									new_part_map[old_dest_part].insert(dest_part);  									operations.push_back(UndoOp(UndoOp::AddPart, dest_part)); +									dest_part = newpart;  								}  								for (iEvent i = el.begin(); i != el.end(); ++i) @@ -1218,7 +1217,7 @@ void paste_at(const QString& pt, int pos, int max_distance, bool always_new_part  	out_of_paste_at_for: -	for (map<Part*, unsigned>::iterator it = expand_map.begin(); it!=expand_map.end(); it++) +	for (map<const Part*, unsigned>::iterator it = expand_map.begin(); it!=expand_map.end(); it++)  		if (it->second != it->first->lenTick())  			schedule_resize_all_same_len_clone_parts(it->first, it->second, operations); @@ -1228,61 +1227,76 @@ void paste_at(const QString& pt, int pos, int max_distance, bool always_new_part  	MusEGlobal::song->update(SC_SELECTION);  } -void select_all(const std::set<Part*>& parts) +void select_all(const set<const Part*>& parts)  { -	for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++) -		for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++) +	Undo operations; +	operations.combobreaker=true; +	 +	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +		for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++)  		{ -			Event& event=ev_it->second; -			event.setSelected(true); +			const Event& event=ev_it->second; +			operations.push_back(UndoOp(UndoOp::SelectEvent,event, true, event.selected()));  		} -	MusEGlobal::song->update(SC_SELECTION); +	MusEGlobal::song->applyOperationGroup(operations);  } -void select_none(const std::set<Part*>& parts) +void select_none(const set<const Part*>& parts)  { -	for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++) -		for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++) +	Undo operations; +	operations.combobreaker=true; +	 +	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +		for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++)  		{ -			Event& event=ev_it->second; -			event.setSelected(false); +			const Event& event=ev_it->second; +			operations.push_back(UndoOp(UndoOp::SelectEvent,event, false, event.selected()));  		} -	MusEGlobal::song->update(SC_SELECTION); +	MusEGlobal::song->applyOperationGroup(operations);  } -void select_invert(const std::set<Part*>& parts) +void select_invert(const set<const Part*>& parts)  { -	for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++) -		for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++) +	Undo operations; +	operations.combobreaker=true; +	 +	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +		for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++)  		{ -			Event& event=ev_it->second; -			event.setSelected(!event.selected()); +			const Event& event=ev_it->second; +			operations.push_back(UndoOp(UndoOp::SelectEvent,event, !event.selected(), event.selected()));  		} -	MusEGlobal::song->update(SC_SELECTION); +	MusEGlobal::song->applyOperationGroup(operations);  } -void select_in_loop(const std::set<Part*>& parts) +void select_in_loop(const set<const Part*>& parts)  {  	select_none(parts); -	for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++) -		for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++) +	Undo operations; +	operations.combobreaker=true; +	 +	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +		for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++)  		{ -			Event& event=ev_it->second; -			event.setSelected((event.tick()>=MusEGlobal::song->lpos() && event.endTick()<=MusEGlobal::song->rpos())); +			const Event& event=ev_it->second; +			operations.push_back(UndoOp(UndoOp::SelectEvent,event, (event.tick()>=MusEGlobal::song->lpos() && event.endTick()<=MusEGlobal::song->rpos()), event.selected()));  		} -	MusEGlobal::song->update(SC_SELECTION); +	MusEGlobal::song->applyOperationGroup(operations);  } -void select_not_in_loop(const std::set<Part*>& parts) +void select_not_in_loop(const set<const Part*>& parts)  {  	select_none(parts); -	for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++) -		for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++) +	Undo operations; +	operations.combobreaker=true; +	 +	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +		for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++)  		{ -			Event& event=ev_it->second; -			event.setSelected(!(event.tick()>=MusEGlobal::song->lpos() && event.endTick()<=MusEGlobal::song->rpos())); +			const Event& event=ev_it->second; +			operations.push_back(UndoOp(UndoOp::SelectEvent,event, !(event.tick()>=MusEGlobal::song->lpos() && event.endTick()<=MusEGlobal::song->rpos()), event.selected()));  		} -	MusEGlobal::song->update(SC_SELECTION); +	MusEGlobal::song->applyOperationGroup(operations);  } @@ -1299,10 +1313,9 @@ void shrink_parts(int raster)  		for (iPart part = (*track)->parts()->begin(); part != (*track)->parts()->end(); part++)  			if (part->second->selected())  			{ -				EventList* events=part->second->events();  				unsigned len=0; -				for (iEvent ev=events->begin(); ev!=events->end(); ev++) +				for (ciEvent ev=part->second->events().begin(); ev!=part->second->events().end(); ev++)  					if (ev->second.endTick() > len)  						len=ev->second.endTick(); @@ -1310,46 +1323,36 @@ void shrink_parts(int raster)  				if (len<min_len) len=min_len;  				if (len < part->second->lenTick()) -				{ -					MidiPart* new_part = new MidiPart(*(MidiPart*)part->second); -					new_part->setLenTick(len); -					operations.push_back(UndoOp(UndoOp::ModifyPart, part->second, new_part, true, false)); -				} +					operations.push_back(UndoOp(UndoOp::ModifyPartLength, part->second, part->second->lenTick(), len, true, false));  			}  	MusEGlobal::song->applyOperationGroup(operations);  } -void schedule_resize_all_same_len_clone_parts(Part* part, unsigned new_len, Undo& operations) +void schedule_resize_all_same_len_clone_parts(const Part* part, unsigned new_len, Undo& operations)  {  	QSet<const Part*> already_done;  	for (Undo::iterator op_it=operations.begin(); op_it!=operations.end();op_it++) -		if (op_it->type==UndoOp::ModifyPart || op_it->type==UndoOp::DeletePart) -			already_done.insert(op_it->nPart); +		if (op_it->type==UndoOp::DeletePart) +			already_done.insert(op_it->part);  	unsigned old_len= part->type() == Pos::FRAMES ? part->lenFrame() : part->lenTick();  	if (old_len!=new_len)  	{ -		Part* part_it=part; +		const Part* part_it=part;  		do  		{  			if (part->type() == Pos::FRAMES)  			{  			  if (part_it->lenFrame()==old_len && !already_done.contains(part_it)) -			  { -				  WavePart* new_part = new WavePart(*(WavePart*)part_it); -				  new_part->setLenFrame(new_len); -				  operations.push_back(UndoOp(UndoOp::ModifyPart, part_it, new_part, true, false)); -			  } +				  operations.push_back(UndoOp(UndoOp::ModifyPartLengthFrames, part_it, part_it->lenFrame(), new_len, true, false)); // FIXME FINDMICH frames suck :(  			}  			else  			if (part_it->lenTick()==old_len && !already_done.contains(part_it))  			{ -				MidiPart* new_part = new MidiPart(*(MidiPart*)part_it); -				new_part->setLenTick(new_len); -				operations.push_back(UndoOp(UndoOp::ModifyPart, part_it, new_part, true, false)); +				operations.push_back(UndoOp(UndoOp::ModifyPartLength, part_it, part_it->lenTick(), new_len, true, false));  			}  			part_it=part_it->nextClone(); @@ -1370,10 +1373,9 @@ void expand_parts(int raster)  		for (iPart part = (*track)->parts()->begin(); part != (*track)->parts()->end(); part++)  			if (part->second->selected())  			{ -				EventList* events=part->second->events();  				unsigned len=part->second->lenTick(); -				for (iEvent ev=events->begin(); ev!=events->end(); ev++) +				for (ciEvent ev=part->second->events().begin(); ev!=part->second->events().end(); ev++)  					if (ev->second.endTick() > len)  						len=ev->second.endTick(); @@ -1381,11 +1383,7 @@ void expand_parts(int raster)  				if (len<min_len) len=min_len;  				if (len > part->second->lenTick()) -				{ -					MidiPart* new_part = new MidiPart(*(MidiPart*)part->second); -					new_part->setLenTick(len); -					operations.push_back(UndoOp(UndoOp::ModifyPart, part->second, new_part, true, false)); -				} +					operations.push_back(UndoOp(UndoOp::ModifyPartLength, part->second, part->second->lenTick(), len, true, false));  			}  	MusEGlobal::song->applyOperationGroup(operations); @@ -1394,7 +1392,7 @@ void expand_parts(int raster)  void clean_parts()  {  	Undo operations; -	set<Part*> already_processed; +	set<const Part*> already_processed;  	TrackList* tracks = MusEGlobal::song->tracks();  	for (iTrack track = tracks->begin(); track != tracks->end(); track++) @@ -1406,7 +1404,7 @@ void clean_parts()  				// multiple clones)  				unsigned len=0; -				Part* part_it=part->second; +				const Part* part_it=part->second;  				do  				{  					if (part_it->lenTick() > len) @@ -1419,8 +1417,7 @@ void clean_parts()  				// erase all events exceeding the longest clone of this part  				// (i.e., erase all hidden events) or shorten them -				EventList* el = part->second->events(); -				for (iEvent ev=el->begin(); ev!=el->end(); ev++) +				for (ciEvent ev=part->second->events().begin(); ev!=part->second->events().end(); ev++)  					if (ev->second.tick() >= len)  						operations.push_back(UndoOp(UndoOp::DeleteEvent, ev->second, part->second, true, true));  					else if (ev->second.endTick() > len) @@ -1435,33 +1432,67 @@ void clean_parts()  	MusEGlobal::song->applyOperationGroup(operations);  } + +bool merge_with_next_part(const Part* oPart) +{ +	const Track* track = oPart->track(); +	 +	if(track->type() != Track::WAVE && !track->isMidiTrack()) +		return false; +	 +	const PartList* pl   = track->cparts(); +	const Part* nextPart = 0; + +	for (ciPart ip = pl->begin(); ip != pl->end(); ++ip) +	{ +			if (ip->second == oPart) +			{ +				++ip; +				if (ip == pl->end()) +						return false; +				nextPart = ip->second; +				break; +				} +			} +	 +	if (nextPart) +	{ +		set<const Part*> parts; +		parts.insert(oPart); +		parts.insert(nextPart); +		return merge_parts(parts); +	} +	else +		return false; +} +  bool merge_selected_parts()  { -	set<Part*> temp = get_all_selected_parts(); +	set<const Part*> temp = get_all_selected_parts();  	return merge_parts(temp);  } -bool merge_parts(const set<Part*>& parts) +bool merge_parts(const set<const Part*>& parts)  { -	set<Track*> tracks; -	for (set<Part*>::iterator it=parts.begin(); it!=parts.end(); it++) +	set<const Track*> tracks; +	for (set<const Part*>::iterator it=parts.begin(); it!=parts.end(); it++)  		tracks.insert( (*it)->track() );  	Undo operations;  	// process tracks separately -	for (set<Track*>::iterator t_it=tracks.begin(); t_it!=tracks.end(); t_it++) +	for (set<const Track*>::iterator t_it=tracks.begin(); t_it!=tracks.end(); t_it++)  	{ -		Track* track=*t_it; +		const Track* track=*t_it;  		unsigned begin=INT_MAX, end=0; -		Part* first_part=NULL; +		const Part* first_part=NULL;  		// find begin of the first and end of the last part -		for (set<Part*>::iterator it=parts.begin(); it!=parts.end(); it++) +		for (set<const Part*>::iterator it=parts.begin(); it!=parts.end(); it++)  			if ((*it)->track()==track)  			{ -				Part* p=*it; +				const Part* p=*it;  				if (p->tick() < begin)  				{  					begin=p->tick(); @@ -1479,30 +1510,25 @@ bool merge_parts(const set<Part*>& parts)  		}  		// create and prepare the new part -		Part* new_part = track->newPart(first_part);  +		Part* new_part = first_part->duplicateEmpty();  		new_part->setTick(begin);  		new_part->setLenTick(end-begin); -		EventList* new_el = new_part->events(); -		new_el->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it -		                     // so we must decrement it first :/ -		new_el->clear(); -		  		// copy all events from the source parts into the new part -		for (set<Part*>::iterator p_it=parts.begin(); p_it!=parts.end(); p_it++) +		for (set<const Part*>::iterator p_it=parts.begin(); p_it!=parts.end(); p_it++)  			if ((*p_it)->track()==track)  			{ -				EventList* old_el= (*p_it)->events(); -				for (iEvent ev_it=old_el->begin(); ev_it!=old_el->end(); ev_it++) +				const EventList& old_el= (*p_it)->events(); +				for (ciEvent ev_it=old_el.begin(); ev_it!=old_el.end(); ev_it++)  				{ -					Event new_event=ev_it->second; +					Event new_event=ev_it->second.clone();  					new_event.setTick( new_event.tick() + (*p_it)->tick() - new_part->tick() ); -					new_el->add(new_event); +					new_part->nonconst_events().add(new_event);  				}  			}  		// delete all the source parts -		for (set<Part*>::iterator it=parts.begin(); it!=parts.end(); it++) +		for (set<const Part*>::iterator it=parts.begin(); it!=parts.end(); it++)  			if ((*it)->track()==track)  				operations.push_back( UndoOp(UndoOp::DeletePart, *it) );  		// and add the new one @@ -1512,4 +1538,49 @@ bool merge_parts(const set<Part*>& parts)  	return MusEGlobal::song->applyOperationGroup(operations);  } +bool split_part(const Part* part, int tick) +{ +	int l1 = tick - part->tick(); +	int l2 = part->lenTick() - l1; +	if (l1 <= 0 || l2 <= 0) +			return false; +	Part* p1; +	Part* p2; +	part->splitPart(tick, p1, p2); +	 +	MusEGlobal::song->informAboutNewParts(part, p1); +	MusEGlobal::song->informAboutNewParts(part, p2); + +	Undo operations; +	operations.push_back(UndoOp(UndoOp::DeletePart, part)); +	operations.push_back(UndoOp(UndoOp::AddPart, p1)); +	operations.push_back(UndoOp(UndoOp::AddPart, p2)); +	return MusEGlobal::song->applyOperationGroup(operations); +} + +bool delete_selected_parts() +{ +	Undo operations; +	bool partSelected = false; + +	TrackList* tl = MusEGlobal::song->tracks(); + +	for (iTrack it = tl->begin(); it != tl->end(); ++it) +	{ +		PartList* pl = (*it)->parts(); +		for (iPart ip = pl->begin(); ip != pl->end(); ++ip) +		{ +				if (ip->second->selected()) +				{ +					operations.push_back(UndoOp(UndoOp::DeletePart,ip->second)); +					partSelected = true; +					} +				} +		} +	 +	MusEGlobal::song->applyOperationGroup(operations); +	 +	return partSelected; +} +  } // namespace MusECore diff --git a/muse2/muse/functions.h b/muse2/muse/functions.h index 31c91fe4..28e178da 100644 --- a/muse2/muse/functions.h +++ b/muse2/muse/functions.h @@ -39,36 +39,36 @@ class QMimeData;  namespace MusECore {  class Undo; -std::set<Part*> partlist_to_set(PartList* pl); -std::set<Part*> part_to_set(Part* p); -std::map<Event*, Part*> get_events(const std::set<Part*>& parts, int range); +std::set<const Part*> partlist_to_set(PartList* pl); +std::set<const Part*> part_to_set(const Part* p); +std::map<const Event*, const Part*> get_events(const std::set<const Part*>& parts, int range);  //these functions simply do their job, non-interactively -bool modify_velocity(const std::set<Part*>& parts, int range, int rate, int offset=0); -bool modify_off_velocity(const std::set<Part*>& parts, int range, int rate, int offset=0); -bool modify_notelen(const std::set<Part*>& parts, int range, int rate, int offset=0); -bool quantize_notes(const std::set<Part*>& parts, int range, int raster, bool len=false, int strength=100, int swing=0, int threshold=0); -bool erase_notes(const std::set<Part*>& parts, int range, int velo_threshold=0, bool velo_thres_used=false, int len_threshold=0, bool len_thres_used=false); -bool delete_overlaps(const std::set<Part*>& parts, int range); -bool set_notelen(const std::set<Part*>& parts, int range, int len); -bool move_notes(const std::set<Part*>& parts, int range, signed int ticks); -bool transpose_notes(const std::set<Part*>& parts, int range, signed int halftonesteps); -bool crescendo(const std::set<Part*>& parts, int range, int start_val, int end_val, bool absolute); -bool legato(const std::set<Part*>& parts, int range, int min_len=1, bool dont_shorten=false); +bool modify_velocity(const std::set<const Part*>& parts, int range, int rate, int offset=0); +bool modify_off_velocity(const std::set<const Part*>& parts, int range, int rate, int offset=0); +bool modify_notelen(const std::set<const Part*>& parts, int range, int rate, int offset=0); +bool quantize_notes(const std::set<const Part*>& parts, int range, int raster, bool len=false, int strength=100, int swing=0, int threshold=0); +bool erase_notes(const std::set<const Part*>& parts, int range, int velo_threshold=0, bool velo_thres_used=false, int len_threshold=0, bool len_thres_used=false); +bool delete_overlaps(const std::set<const Part*>& parts, int range); +bool set_notelen(const std::set<const Part*>& parts, int range, int len); +bool move_notes(const std::set<const Part*>& parts, int range, signed int ticks); +bool transpose_notes(const std::set<const Part*>& parts, int range, signed int halftonesteps); +bool crescendo(const std::set<const Part*>& parts, int range, int start_val, int end_val, bool absolute); +bool legato(const std::set<const Part*>& parts, int range, int min_len=1, bool dont_shorten=false);  //the below functions automatically open the dialog  //they return true if you click "ok" and false if "abort" -bool modify_velocity(const std::set<Part*>& parts); -bool modify_notelen(const std::set<Part*>& parts); -bool quantize_notes(const std::set<Part*>& parts); -bool set_notelen(const std::set<Part*>& parts); -bool move_notes(const std::set<Part*>& parts); -bool transpose_notes(const std::set<Part*>& parts); -bool crescendo(const std::set<Part*>& parts); -bool erase_notes(const std::set<Part*>& parts); -bool delete_overlaps(const std::set<Part*>& parts); -bool legato(const std::set<Part*>& parts); +bool modify_velocity(const std::set<const Part*>& parts); +bool modify_notelen(const std::set<const Part*>& parts); +bool quantize_notes(const std::set<const Part*>& parts); +bool set_notelen(const std::set<const Part*>& parts); +bool move_notes(const std::set<const Part*>& parts); +bool transpose_notes(const std::set<const Part*>& parts); +bool crescendo(const std::set<const Part*>& parts); +bool erase_notes(const std::set<const Part*>& parts); +bool delete_overlaps(const std::set<const Part*>& parts); +bool legato(const std::set<const Part*>& parts);  //the below functions operate on selected parts  bool modify_velocity(); @@ -84,29 +84,32 @@ bool legato();  //functions for copy'n'paste -void copy_notes(const std::set<Part*>& parts, int range); -bool paste_notes(Part* paste_into_part=NULL); // shows a dialog -void paste_notes(int max_distance=3072, bool always_new_part=false, bool never_new_part=false, Part* paste_into_part=NULL, int amount=1, int raster=3072); -QMimeData* selected_events_to_mime(const std::set<Part*>& parts, int range); -QMimeData* parts_to_mime(const std::set<Part*>& parts); +void copy_notes(const std::set<const Part*>& parts, int range); +bool paste_notes(const Part* paste_into_part=NULL); // shows a dialog +void paste_notes(int max_distance=3072, bool always_new_part=false, bool never_new_part=false, const Part* paste_into_part=NULL, int amount=1, int raster=3072); +QMimeData* selected_events_to_mime(const std::set<const Part*>& parts, int range); +QMimeData* parts_to_mime(const std::set<const Part*>& parts); -void paste_at(const QString& pt, int pos, int max_distance=3072, bool always_new_part=false, bool never_new_part=false, Part* paste_into_part=NULL, int amount=1, int raster=3072); +void paste_at(const QString& pt, int pos, int max_distance=3072, bool always_new_part=false, bool never_new_part=false, const Part* paste_into_part=NULL, int amount=1, int raster=3072);  //functions for selections -void select_all(const std::set<Part*>& parts); -void select_none(const std::set<Part*>& parts); -void select_invert(const std::set<Part*>& parts); -void select_in_loop(const std::set<Part*>& parts); -void select_not_in_loop(const std::set<Part*>& parts); +void select_all(const std::set<const Part*>& parts); +void select_none(const std::set<const Part*>& parts); +void select_invert(const std::set<const Part*>& parts); +void select_in_loop(const std::set<const Part*>& parts); +void select_not_in_loop(const std::set<const Part*>& parts);  //functions for parts  void shrink_parts(int raster=-1); //negative values mean "config.division"  void expand_parts(int raster=-1); -void schedule_resize_all_same_len_clone_parts(Part* part, unsigned new_len, Undo& operations); +void schedule_resize_all_same_len_clone_parts(const Part* part, unsigned new_len, Undo& operations);  void clean_parts(); +bool merge_with_next_part(const Part* part);  bool merge_selected_parts(); -bool merge_parts(const std::set<Part*>& parts); +bool merge_parts(const std::set<const Part*>& parts); +bool split_part(const Part* part, int tick); +bool delete_selected_parts();  // internal  QMimeData* file_to_mimedata(FILE *datafile, QString mimeType); diff --git a/muse2/muse/helper.cpp b/muse2/muse/helper.cpp index efb4ec68..75cbce9f 100644 --- a/muse2/muse/helper.cpp +++ b/muse2/muse/helper.cpp @@ -108,7 +108,7 @@ Part* partFromSerialNumber(int serial)  	return NULL;  } -bool any_event_selected(const set<Part*>& parts, bool in_range) +bool any_event_selected(const set<const Part*>& parts, bool in_range)  {    return !get_events(parts, in_range ? 3 : 1).empty();  } @@ -941,9 +941,9 @@ int populateMidiCtrlMenu(PopupMenu* menu, MusECore::PartList* part_list, MusECor              if (i == sList.end()) {                    bool used = false;                    for (MusECore::iPart ip = part_list->begin(); ip != part_list->end(); ++ip) { -                        MusECore::EventList* el = ip->second->events(); -                        for (MusECore::iEvent ie = el->begin(); ie != el->end(); ++ie) { -                              MusECore::Event e = ie->second; +                        const MusECore::EventList& el = ip->second->events(); +                        for (MusECore::ciEvent ie = el.begin(); ie != el.end(); ++ie) { +                              const MusECore::Event& e = ie->second;                                if(e.type() != MusECore::Controller)                                  continue;                                int ctl_num = e.dataA(); diff --git a/muse2/muse/helper.h b/muse2/muse/helper.h index 33b2e9a0..b5763a4e 100644 --- a/muse2/muse/helper.h +++ b/muse2/muse/helper.h @@ -43,7 +43,7 @@ class PartList;  QString pitch2string(int v);  Part* partFromSerialNumber(int serial); -bool any_event_selected(const std::set<Part*>&, bool in_range=false); +bool any_event_selected(const std::set<const Part*>&, bool in_range=false);  bool drummaps_almost_equal(const DrumMap* one, const DrumMap* two, int drummap_size=128); diff --git a/muse2/muse/importmidi.cpp b/muse2/muse/importmidi.cpp index e22d865e..b0affa24 100644 --- a/muse2/muse/importmidi.cpp +++ b/muse2/muse/importmidi.cpp @@ -249,8 +249,8 @@ bool MusE::importMidi(const QString name, bool merge)        //    - calculate tick value for internal resolution        //        for (MusECore::iMidiFileTrack t = etl->begin(); t != etl->end(); ++t) { -            MusECore::MPEventList* el  = &((*t)->events); -            if (el->empty()) +            MusECore::MPEventList& el  = ((*t)->events); +            if (el.empty())                    continue;              //              // if we split the track, SYSEX and META events go into @@ -264,7 +264,7 @@ bool MusE::importMidi(const QString name, bool merge)              MusECore::iMPEvent ev;              set< pair<int,int> > already_processed; -            for (ev = el->begin(); ev != el->end(); ++ev) +            for (ev = el.begin(); ev != el.end(); ++ev)              {                if (ev->type() != MusECore::ME_SYSEX && ev->type() != MusECore::ME_META)                { @@ -288,9 +288,7 @@ bool MusE::importMidi(const QString name, bool merge)                          track->setOutPort(port);                          MusECore::MidiPort* mport = &MusEGlobal::midiPorts[port]; -                        //MusECore::MidiInstrument* instr = mport->instrument(); -                        MusECore::EventList* mel = track->events(); -                        buildMidiEventList(mel, el, track, division, first, false); // Don't do loops. +                        buildMidiEventList(&track->events, el, track, division, first, false); // Don't do loops.                          first = false;                          // Comment Added by T356. @@ -305,8 +303,7 @@ bool MusE::importMidi(const QString name, bool merge)                             {                                track->setType(MusECore::Track::DRUM);                                // remap drum pitch with drumOutmap (was: Inmap. flo93 thought this was wrong) -                              MusECore::EventList* tevents = track->events(); -                              for (MusECore::iEvent i = tevents->begin(); i != tevents->end(); ++i) { +                              for (MusECore::iEvent i = track->events.begin(); i != track->events.end(); ++i) {                                      MusECore::Event ev  = i->second;                                      if (ev.isNote()) {                                            int pitch = MusEGlobal::drumOutmap[ev.pitch()]; @@ -339,8 +336,7 @@ bool MusE::importMidi(const QString name, bool merge)                    MusECore::MidiTrack* track = new MusECore::MidiTrack();                    track->setOutChannel(0);                    track->setOutPort(0); -                  MusECore::EventList* mel = track->events(); -                  buildMidiEventList(mel, el, track, division, true, false); // Do SysexMeta. Don't do loops. +                  buildMidiEventList(&track->events, el, track, division, true, false); // Do SysexMeta. Don't do loops.                    processTrack(track);                    MusEGlobal::song->insertTrack0(track, -1);                    } @@ -383,8 +379,8 @@ bool MusE::importMidi(const QString name, bool merge)  void MusE::processTrack(MusECore::MidiTrack* track)        { -      MusECore::EventList* tevents = track->events(); -      if (tevents->empty()) +      MusECore::EventList& tevents = track->events; +      if (tevents.empty())              return;        //--------------------------------------------------- @@ -398,8 +394,8 @@ void MusE::processTrack(MusECore::MidiTrack* track)        MusECore::PartList* pl = track->parts();        int lastTick = 0; -      for (MusECore::iEvent i = tevents->begin(); i != tevents->end(); ++i) { -            MusECore::Event event = i->second; +      for (MusECore::ciEvent i = tevents.begin(); i != tevents.end(); ++i) { +            const MusECore::Event& event = i->second;              int epos = event.tick() + event.lenTick();              if (epos > lastTick)                    lastTick = epos; @@ -426,8 +422,8 @@ void MusE::processTrack(MusECore::MidiTrack* track)                if (lastOff > x2) {                              continue;                      } -              MusECore::iEvent i1 = tevents->lower_bound(x1); -              MusECore::iEvent i2 = tevents->lower_bound(x2); +              MusECore::iEvent i1 = tevents.lower_bound(x1); +              MusECore::iEvent i2 = tevents.lower_bound(x2);                if (i1 == i2) {   // empty?                      if (st != -1) { @@ -444,8 +440,8 @@ void MusE::processTrack(MusECore::MidiTrack* track)                            st = x1;    // begin new  part                      //HACK:                      //lastOff: -                    for (MusECore::iEvent i = i1; i != i2; ++i) { -                          MusECore::Event event = i->second; +                    for (MusECore::ciEvent i = i1; i != i2; ++i) { +                          const MusECore::Event& event = i->second;                            if (event.type() == MusECore::Note) {                                  int off = event.tick() + event.lenTick();                                  if (off > lastOff) @@ -480,28 +476,27 @@ void MusE::processTrack(MusECore::MidiTrack* track)              MusECore::MidiPart* part = (MusECore::MidiPart*)(p->second);              int stick = part->tick();              int etick = part->tick() + part->lenTick(); -            MusECore::iEvent r1 = tevents->lower_bound(stick); -            MusECore::iEvent r2 = tevents->lower_bound(etick); +            MusECore::iEvent r1 = tevents.lower_bound(stick); +            MusECore::iEvent r2 = tevents.lower_bound(etick);              int startTick = part->tick(); -            MusECore::EventList* el = part->events();              for (MusECore::iEvent i = r1; i != r2; ++i) { -                  MusECore::Event ev = i->second; +                  MusECore::Event& ev = i->second;                    int ntick = ev.tick() - startTick;                    ev.setTick(ntick); -                  el->add(ev); +                  part->nonconst_events().add(ev);                    } -            tevents->erase(r1, r2); +            tevents.erase(r1, r2);              } -      if (tevents->size()) -            printf("-----------events left: %zd\n", tevents->size()); -      for (MusECore::iEvent i = tevents->begin(); i != tevents->end(); ++i) { +      if (tevents.size()) +            printf("-----------events left: %zd\n", tevents.size()); +      for (MusECore::ciEvent i = tevents.begin(); i != tevents.end(); ++i) {              printf("%d===\n", i->first);              i->second.dump();              }        // all events should be processed: -      if (!tevents->empty()) +      if (!tevents.empty())          printf("THIS SHOULD NEVER HAPPEN: not all events processed at the end of MusE::processTrack()!\n");        } @@ -620,7 +615,7 @@ void MusE::importPartToTrack(QString& filename, unsigned tick, MusECore::Track*                    if (tag == "part") {                          // Read the part.                          MusECore::Part* p = 0; -                        p = readXmlPart(xml, track); +                        p = MusECore::Part::readFromXml(xml, track);                          // If it could not be created...                          if(!p)                          { diff --git a/muse2/muse/liste/listedit.cpp b/muse2/muse/liste/listedit.cpp index e1a49842..730ab5d8 100644 --- a/muse2/muse/liste/listedit.cpp +++ b/muse2/muse/liste/listedit.cpp @@ -247,8 +247,8 @@ void ListEdit::songChanged(MusECore::SongChangedFlags_t type)                          MusECore::MidiPart* part = (MusECore::MidiPart*) (p->second);                          if (part->sn() == curPartId)                                curPart  = part; -                        MusECore::EventList* el = part->events(); -                        for (MusECore::iEvent i = el->begin(); i != el->end(); ++i) { +                         +                        for (MusECore::ciEvent i = part->events().begin(); i != part->events().end(); ++i) {                                EventListItem* item = new EventListItem(liste, i->second, part);                                for (int col = 0; col < liste->columnCount(); ++col)                                      item->setText(col, item->text(col)); diff --git a/muse2/muse/midi.cpp b/muse2/muse/midi.cpp index 524329b1..d70b132c 100644 --- a/muse2/muse/midi.cpp +++ b/muse2/muse/midi.cpp @@ -198,7 +198,7 @@ QString nameSysex(unsigned int len, const unsigned char* buf)  //      generally: how to handle incomplete messages  //--------------------------------------------------------- -void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track, +void buildMidiEventList(EventList* del, const MPEventList& el, MidiTrack* track,     int div, bool addSysexMeta, bool doLoops)        {        int hbank    = 0xff; @@ -211,7 +211,7 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,        EventList mel; -      for (iMPEvent i = el->begin(); i != el->end(); ++i) { +      for (iMPEvent i = el.begin(); i != el.end(); ++i) {              MidiPlayEvent ev = *i;              if (!addSysexMeta && (ev.type() == ME_SYSEX || ev.type() == ME_META))                    continue; @@ -305,7 +305,7 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,                                      iMPEvent ii = i;                                      ++ii;                                      bool found = false; -                                    for (; ii != el->end(); ++ii) { +                                    for (; ii != el.end(); ++ii) {                                            MidiPlayEvent ev = *ii;                                            if (ev.type() == ME_CONTROLLER) {                                                  if (ev.dataA() == CTRL_LDATA) { @@ -471,7 +471,7 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,                    e.setTick(tick);                    mel.add(e);                    } -            }  // i != el->end() +            }  // i != el.end()        //--------------------------------------------------- @@ -625,7 +625,7 @@ void Audio::collectEvents(MusECore::MidiTrack* track, unsigned int cts, unsigned              // dont play muted parts              if (part->mute())                    continue; -            EventList* events = part->events(); +            const EventList& events = part->events();              unsigned partTick = part->tick();              unsigned partLen  = part->lenTick();              int delay         = track->delay; @@ -644,8 +644,8 @@ void Audio::collectEvents(MusECore::MidiTrack* track, unsigned int cts, unsigned              if(etick > partLen)                continue; -            iEvent ie   = events->lower_bound(stick); -            iEvent iend = events->lower_bound(etick); +            ciEvent ie   = events.lower_bound(stick); +            ciEvent iend = events.lower_bound(etick);              for (; ie != iend; ++ie) {                    Event ev = ie->second; @@ -1009,7 +1009,6 @@ void Audio::processMidi()              //              if (track->recordFlag())               { -                  MusECore::MPEventList* rl = track->mpevents();                    MusECore::MidiPort* tport = &MusEGlobal::midiPorts[port];                    RouteList* irl = track->inRoutes();                    for(ciRoute r = irl->begin(); r != irl->end(); ++r) @@ -1063,7 +1062,7 @@ void Audio::processMidi()                                  event.setTime(MusEGlobal::tempomap.frame2tick(event.time()));                                if(recording)  -                                rl->add(event); +                                track->mpevents.add(event);                              }                                    dev->setSysexFIFOProcessed(true);                            } @@ -1252,7 +1251,7 @@ void Audio::processMidi()                                              drumRecEvent.setB(preVelo);                                              drumRecEvent.setPort(port); //rec-event to current port                                              drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel -                                            rl->add(drumRecEvent); +                                            track->mpevents.add(drumRecEvent);                                          }                                          else                                          { @@ -1263,7 +1262,7 @@ void Audio::processMidi()                                              //  different port. That must have been wrong - buildMidiEventList would ignore that. Tim.                                              drumRecEvent.setPort(port);  //rec-event to current port                                              drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel -                                            rl->add(drumRecEvent); +                                            track->mpevents.add(drumRecEvent);                                          }                                            }                                        else  @@ -1277,7 +1276,7 @@ void Audio::processMidi()                                              recEvent.setPort(port);                                              recEvent.setChannel(track->outChannel()); -                                            rl->add(recEvent); +                                            track->mpevents.add(recEvent);                                        }                                  }                              } diff --git a/muse2/muse/midi.h b/muse2/muse/midi.h index 86b11c97..c0f6e07f 100644 --- a/muse2/muse/midi.h +++ b/muse2/muse/midi.h @@ -126,7 +126,7 @@ QString midiMetaName(int);  class MPEventList;  class MidiTrack; -extern void buildMidiEventList(EventList* mel, const MPEventList* el, MidiTrack* track, int division, bool addSysexMeta, bool doLoops); +extern void buildMidiEventList(EventList* mel, const MPEventList& el, MidiTrack* track, int division, bool addSysexMeta, bool doLoops);  } // namespace MusECore diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index ebe3a6c8..ba18d8a3 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -80,7 +80,7 @@ DEvent::DEvent(MusECore::Event e, MusECore::Part* p, int instr)  //   addItem  //--------------------------------------------------------- -CItem* DrumCanvas::addItem(MusECore::Part* part, MusECore::Event& event) +CItem* DrumCanvas::addItem(MusECore::Part* part, const MusECore::Event& event)        {        if (signed(event.tick())<0) {              printf("ERROR: trying to add event before current part!\n"); @@ -516,11 +516,10 @@ void DrumCanvas::newItem(CItem* item, bool noSnap, bool replace)      event.setPitch(npitch);      // check for existing event      //    if found change command semantic from insert to delete -    MusECore::EventList* el = part->events(); -    MusECore::iEvent lower  = el->lower_bound(event.tick()); -    MusECore::iEvent upper  = el->upper_bound(event.tick()); +    MusECore::ciEvent lower  = part->events().lower_bound(event.tick()); +    MusECore::ciEvent upper  = part->events().upper_bound(event.tick()); -    for (MusECore::iEvent i = lower; i != upper; ++i) { +    for (MusECore::ciEvent i = lower; i != upper; ++i) {            MusECore::Event ev = i->second;            if(!ev.isNote())              continue; @@ -1027,10 +1026,10 @@ void DrumCanvas::mapChanged(int spitch, int dpitch)     if (old_style_drummap_mode)     {        MusECore::Undo operations; -      std::vector< std::pair<MusECore::Part*, MusECore::Event*> > delete_events; +      std::vector< std::pair<MusECore::Part*, MusECore::Event> > delete_events;        std::vector< std::pair<MusECore::Part*, MusECore::Event> > add_events; -      typedef std::vector< std::pair<MusECore::Part*, MusECore::Event*> >::iterator idel_ev; +      typedef std::vector< std::pair<MusECore::Part*, MusECore::Event> >::iterator idel_ev;        typedef std::vector< std::pair<MusECore::Part*, MusECore::Event> >::iterator iadd_ev;        MusECore::MidiTrackList* tracks = MusEGlobal::song->midis(); @@ -1042,9 +1041,9 @@ void DrumCanvas::mapChanged(int spitch, int dpitch)              MusECore::MidiPort* mp = &MusEGlobal::midiPorts[curTrack->outPort()];              MusECore::PartList* parts= curTrack->parts();              for (MusECore::iPart part = parts->begin(); part != parts->end(); ++part) { -                  MusECore::EventList* events = part->second->events(); +                  const MusECore::EventList& events = part->second->events();                    MusECore::Part* thePart = part->second; -                  for (MusECore::iEvent i = events->begin(); i != events->end(); ++i) { +                  for (MusECore::ciEvent i = events.begin(); i != events.end(); ++i) {                          MusECore::Event event = i->second;                          if(event.type() != MusECore::Controller && event.type() != MusECore::Note)                            continue; @@ -1058,9 +1057,9 @@ void DrumCanvas::mapChanged(int spitch, int dpitch)                          }                          if (pitch == spitch) { -                              MusECore::Event* spitch_event = &(i->second); -                              delete_events.push_back(std::pair<MusECore::Part*, MusECore::Event*>(thePart, spitch_event)); -                              MusECore::Event newEvent = spitch_event->clone(); +                              const MusECore::Event& spitch_event = i->second; +                              delete_events.push_back(std::pair<MusECore::Part*, MusECore::Event>(thePart, spitch_event)); +                              MusECore::Event newEvent = spitch_event.clone();                                if(drc)                                  newEvent.setA((newEvent.dataA() & ~0xff) | dpitch);                                else @@ -1068,9 +1067,9 @@ void DrumCanvas::mapChanged(int spitch, int dpitch)                                add_events.push_back(std::pair<MusECore::Part*, MusECore::Event>(thePart, newEvent));                                }                          else if (pitch == dpitch) { -                              MusECore::Event* dpitch_event = &(i->second); -                              delete_events.push_back(std::pair<MusECore::Part*, MusECore::Event*>(thePart, dpitch_event)); -                              MusECore::Event newEvent = dpitch_event->clone(); +                              const MusECore::Event& dpitch_event = i->second; +                              delete_events.push_back(std::pair<MusECore::Part*, MusECore::Event>(thePart, dpitch_event)); +                              MusECore::Event newEvent = dpitch_event.clone();                                if(drc)                                  newEvent.setA((newEvent.dataA() & ~0xff) | spitch);                                else @@ -1083,8 +1082,8 @@ void DrumCanvas::mapChanged(int spitch, int dpitch)        for (idel_ev i = delete_events.begin(); i != delete_events.end(); i++) {              MusECore::Part*  thePart = (*i).first; -            MusECore::Event* theEvent = (*i).second; -            operations.push_back(MusECore::UndoOp(MusECore::UndoOp::DeleteEvent, *theEvent, thePart, true, false)); +            const MusECore::Event& theEvent = (*i).second; +            operations.push_back(MusECore::UndoOp(MusECore::UndoOp::DeleteEvent, theEvent, thePart, true, false));              }        MusECore::DrumMap dm = MusEGlobal::drumMap[spitch]; @@ -1212,9 +1211,8 @@ void DrumCanvas::resizeEvent(QResizeEvent* ev)  void DrumCanvas::modifySelected(NoteInfo::ValType type, int val, bool delta_mode)        { -      QList< QPair<MusECore::EventList*,MusECore::Event> > already_done; -      MusEGlobal::audio->msgIdle(true); -      MusEGlobal::song->startUndo(); +      QList< QPair<int,MusECore::Event> > already_done; +      MusECore::Undo operations;        for (iCItem i = items.begin(); i != items.end(); ++i) {              if (!(i->second->isSelected()))                    continue; @@ -1225,7 +1223,7 @@ void DrumCanvas::modifySelected(NoteInfo::ValType type, int val, bool delta_mode              MusECore::MidiPart* part = (MusECore::MidiPart*)(e->part()); -            if (already_done.contains(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event))) +            if (already_done.contains(QPair<int,MusECore::Event>(part->clonemaster_sn(), event)))                continue;              MusECore::Event newEvent = event.clone(); @@ -1303,14 +1301,12 @@ void DrumCanvas::modifySelected(NoteInfo::ValType type, int val, bool delta_mode                          }                          break;                    } -            MusEGlobal::song->changeEvent(event, newEvent, part); -            // Indicate do not do port controller values and clone parts.  -            MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false)); -            already_done.append(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event)); +            operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false)); + +            already_done.append(QPair<int,MusECore::Event>(part->clonemaster_sn(), event));              } -      MusEGlobal::song->endUndo(SC_EVENT_MODIFIED); -      MusEGlobal::audio->msgIdle(false); +      MusEGlobal::song->applyOperationGroup(operations);        }  //--------------------------------------------------------- @@ -1481,18 +1477,17 @@ void DrumCanvas::setStep(int v)  //---------------------------------------------------------  //   getEventAtCursorPos  //--------------------------------------------------------- -MusECore::Event *DrumCanvas::getEventAtCursorPos() +const MusECore::Event* DrumCanvas::getEventAtCursorPos()  {      if (_tool != CursorTool)        return 0;      if (instrument_map[cursorPos.y()].tracks.contains(curPart->track()))      { -      MusECore::EventList* el = curPart->events(); -      MusECore::iEvent lower  = el->lower_bound(cursorPos.x()-curPart->tick()); -      MusECore::iEvent upper  = el->upper_bound(cursorPos.x()-curPart->tick()); +      MusECore::ciEvent lower  = curPart->events().lower_bound(cursorPos.x()-curPart->tick()); +      MusECore::ciEvent upper  = curPart->events().upper_bound(cursorPos.x()-curPart->tick());        int curPitch = instrument_map[cursorPos.y()].pitch; -      for (MusECore::iEvent i = lower; i != upper; ++i) { -        MusECore::Event &ev = i->second; +      for (MusECore::ciEvent i = lower; i != upper; ++i) { +        const MusECore::Event& ev = i->second;          if (ev.isNote()  &&  ev.pitch() == curPitch)            return &ev;        } @@ -1503,7 +1498,7 @@ MusECore::Event *DrumCanvas::getEventAtCursorPos()  //---------------------------------------------------------  //   selectCursorEvent  //--------------------------------------------------------- -void DrumCanvas::selectCursorEvent(MusECore::Event *ev) +void DrumCanvas::selectCursorEvent(const MusECore::Event* ev)  {    for (iCItem i = items.begin(); i != items.end(); ++i)    { diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h index 1a1ee546..300f2291 100644 --- a/muse2/muse/midiedit/dcanvas.h +++ b/muse2/muse/midiedit/dcanvas.h @@ -130,7 +130,7 @@ class DrumCanvas : public EventCanvas {        void dragEnterEvent(QDragEnterEvent* event);        void dragMoveEvent(QDragMoveEvent*);        void dragLeaveEvent(QDragLeaveEvent*); -      virtual CItem* addItem(MusECore::Part*, MusECore::Event&); +      virtual CItem* addItem(MusECore::Part*, const MusECore::Event&);        virtual void resizeEvent(QResizeEvent*);        virtual void curPartChanged();        int getNextStep(unsigned int pos, int basicStep, int stepSize=1); @@ -167,8 +167,8 @@ class DrumCanvas : public EventCanvas {        virtual void modifySelected(NoteInfo::ValType type, int val, bool delta_mode = true);        virtual void keyPress(QKeyEvent* event);        virtual void keyRelease(QKeyEvent* event); -      MusECore::Event *getEventAtCursorPos(); -      void selectCursorEvent(MusECore::Event *ev); +      const MusECore::Event* getEventAtCursorPos(); +      void selectCursorEvent(const MusECore::Event* ev);        int pitch_and_track_to_instrument(int pitch, MusECore::Track* track); diff --git a/muse2/muse/midiedit/dlist.cpp b/muse2/muse/midiedit/dlist.cpp index 09b33735..ecfc02ba 100644 --- a/muse2/muse/midiedit/dlist.cpp +++ b/muse2/muse/midiedit/dlist.cpp @@ -208,8 +208,7 @@ void DList::draw(QPainter& p, const QRect& rect)                                            continue;                                          found = true; -                                        MusECore::EventList* el = cur_part->events(); -                                        for(MusECore::iEvent ie = el->begin(); ie != el->end(); ++ie) +                                        for(MusECore::ciEvent ie = cur_part->events().begin(); ie != cur_part->events().end(); ++ie)                                          {                                            MusECore::Event e = ie->second;                                            if(e.type() != MusECore::Controller) @@ -303,14 +302,14 @@ void DList::draw(QPainter& p, const QRect& rect)                                                continue;                                              found = true; -                                            MusECore::EventList* el = cur_part->events(); +                                            const MusECore::EventList& el = cur_part->events();                                              //MusECore::PartList* part_list = dcanvas->drumEdit()->parts();                                              //for(MusECore::ciPart ip = part_list->cbegin(); ip != part_list->cend(); ++ip)                                              {                                                //MusECore::Part* part = ip->second;                                                ///if(part->track() !=  -                                              //MusECore::EventList* el = part->events(); -                                              for(MusECore::iEvent ie = el->begin(); ie != el->end(); ++ie) +                                              //const MusECore::EventList& el = part->events(); +                                              for(MusECore::ciEvent ie = el.begin(); ie != el.end(); ++ie)                                                {                                                  MusECore::Event e = ie->second;                                                  if(e.type() != MusECore::Controller) diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp index a93ad01e..175287cb 100644 --- a/muse2/muse/midiedit/drumedit.cpp +++ b/muse2/muse/midiedit/drumedit.cpp @@ -1850,8 +1850,8 @@ void DrumEdit::hideUnusedInstruments()      for (MusECore::ciPart p = parts()->begin(); p != parts()->end(); ++p)        if (p->second->track() == track)        { -        const EventList* el = p->second->cevents(); -        for (ciEvent ev=el->begin(); ev!=el->end(); ev++) +        const EventList& el = p->second->events(); +        for (ciEvent ev=el.begin(); ev!=el.end(); ev++)            hide[ev->second.pitch()]=false;        } @@ -1883,8 +1883,8 @@ void DrumEdit::hideEmptyInstruments()      for (MusECore::ciPart p = parts()->begin(); p != parts()->end(); ++p)        if (p->second->track() == track)        { -        const EventList* el = p->second->cevents(); -        for (ciEvent ev=el->begin(); ev!=el->end(); ev++) +        const EventList& el = p->second->events(); +        for (ciEvent ev=el.begin(); ev!=el.end(); ev++)            hide[ev->second.pitch()]=false;        } diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp index 4ae702f1..d70cc50c 100644 --- a/muse2/muse/midiedit/ecanvas.cpp +++ b/muse2/muse/midiedit/ecanvas.cpp @@ -192,8 +192,7 @@ void EventCanvas::songChanged(MusECore::SongChangedFlags_t flags)                    if (etick > end_tick)                          end_tick = etick; -                  MusECore::EventList* el = part->events(); -                  for (MusECore::iEvent i = el->begin(); i != el->end(); ++i) { +                  for (MusECore::ciEvent i = part->events().begin(); i != part->events().end(); ++i) {                          MusECore::Event e = i->second;                          // Do not add events which are past the end of the part.                          if(e.tick() > len)       diff --git a/muse2/muse/midiedit/ecanvas.h b/muse2/muse/midiedit/ecanvas.h index 95e856c8..e7d7ad6e 100644 --- a/muse2/muse/midiedit/ecanvas.h +++ b/muse2/muse/midiedit/ecanvas.h @@ -80,7 +80,7 @@ class EventCanvas : public Canvas {        bool _setCurPartIfOnlyOneEventIsSelected;        void updateSelection(); -      virtual CItem* addItem(MusECore::Part*, MusECore::Event&) = 0; +      virtual CItem* addItem(MusECore::Part*, const MusECore::Event&) = 0;        virtual QPoint raster(const QPoint&) const;        virtual MusECore::Undo moveCanvasItems(CItemList&, int, int, DragType, bool rasterize = true) = 0;        virtual bool moveItem(MusECore::Undo&, CItem*, const QPoint&, DragType, bool rasterize = true) = 0; diff --git a/muse2/muse/midiedit/piano.cpp b/muse2/muse/midiedit/piano.cpp index 40d93910..17553baa 100644 --- a/muse2/muse/midiedit/piano.cpp +++ b/muse2/muse/midiedit/piano.cpp @@ -570,8 +570,7 @@ void Piano::draw(QPainter& p, const QRect& r)          int num = cl->num();          int pitch = num & 0x7f;          bool used = false; -        MusECore::EventList* el = cur_part->events(); -        for (MusECore::ciEvent ie = el->begin(); ie != el->end(); ++ie) +        for (MusECore::ciEvent ie = cur_part->events().begin(); ie != cur_part->events().end(); ++ie)          {            MusECore::Event e = ie->second;            if(e.type() != MusECore::Controller) diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index 92ed3758..5be4c090 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -59,7 +59,7 @@ namespace MusEGui {  //   NEvent  //--------------------------------------------------------- -NEvent::NEvent(MusECore::Event& e, MusECore::Part* p, int y) : MusEGui::CItem(e, p) +NEvent::NEvent(const MusECore::Event& e, MusECore::Part* p, int y) : MusEGui::CItem(e, p)        {        y = y - KH/4;        unsigned tick = e.tick() + p->tick(); @@ -72,7 +72,7 @@ NEvent::NEvent(MusECore::Event& e, MusECore::Part* p, int y) : MusEGui::CItem(e,  //   addItem  //--------------------------------------------------------- -CItem* PianoCanvas::addItem(MusECore::Part* part, MusECore::Event& event) +CItem* PianoCanvas::addItem(MusECore::Part* part, const MusECore::Event& event)        {        if (signed(event.tick())<0) {              printf("ERROR: trying to add event before current part!\n"); @@ -635,11 +635,10 @@ void PianoCanvas::pianoCmd(int cmd)                    if (part == 0)                          break; -                  MusECore::EventList* el = part->events();                    MusECore::Undo operations;                    std::list <MusECore::Event> elist; -                  for (MusECore::iEvent e = el->lower_bound(pos[0] - part->tick()); e != el->end(); ++e) +                  for (MusECore::ciEvent e = part->events().lower_bound(pos[0] - part->tick()); e != part->events().end(); ++e)                          elist.push_back((MusECore::Event)e->second);                    for (std::list<MusECore::Event>::iterator i = elist.begin(); i != elist.end(); ++i) {                          MusECore::Event event = *i; @@ -663,10 +662,8 @@ void PianoCanvas::pianoCmd(int cmd)                          break;                    MusECore::Undo operations; -                  MusECore::EventList* el = part->events(); -                    std::list<MusECore::Event> elist; -                  for (MusECore::iEvent e = el->lower_bound(pos[0]); e != el->end(); ++e) +                  for (MusECore::ciEvent e = part->events().lower_bound(pos[0]); e != part->events().end(); ++e)                          elist.push_back((MusECore::Event)e->second);                    for (std::list<MusECore::Event>::iterator i = elist.begin(); i != elist.end(); ++i) {                          MusECore::Event event = *i; @@ -989,7 +986,7 @@ void PianoCanvas::curPartChanged()  void PianoCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int val, bool delta_mode)        { -      QList< QPair<MusECore::EventList*,MusECore::Event> > already_done; +      QList< QPair<int,MusECore::Event> > already_done;        MusEGlobal::audio->msgIdle(true);        MusEGlobal::song->startUndo();        for (MusEGui::iCItem i = items.begin(); i != items.end(); ++i) { @@ -1002,7 +999,7 @@ void PianoCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int val, bool              MusECore::MidiPart* part = (MusECore::MidiPart*)(e->part()); -            if (already_done.contains(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event))) +            if (already_done.contains(QPair<int,MusECore::Event>(part->clonemaster_sn(), event)))                continue;              MusECore::Event newEvent = event.clone(); @@ -1072,7 +1069,7 @@ void PianoCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int val, bool              // Indicate do not do port controller values and clone parts.               MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false)); -            already_done.append(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event)); +            already_done.append(QPair<int,MusECore::Event>(part->clonemaster_sn(), event));              }        MusEGlobal::song->endUndo(SC_EVENT_MODIFIED);        MusEGlobal::audio->msgIdle(false); diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h index 888427ea..4748093b 100644 --- a/muse2/muse/midiedit/prcanvas.h +++ b/muse2/muse/midiedit/prcanvas.h @@ -46,7 +46,7 @@ namespace MusEGui {  class NEvent : public CItem {     public: -      NEvent(MusECore::Event& e, MusECore::Part* p, int y); +      NEvent(const MusECore::Event& e, MusECore::Part* p, int y);        };  class ScrollScale; @@ -80,7 +80,7 @@ class PianoCanvas : public EventCanvas {        virtual void dragEnterEvent(QDragEnterEvent* event);        virtual void dragMoveEvent(QDragMoveEvent*);        virtual void dragLeaveEvent(QDragLeaveEvent*); -      virtual CItem* addItem(MusECore::Part*, MusECore::Event&); +      virtual CItem* addItem(MusECore::Part*, const MusECore::Event&);        int y2pitch(int) const;        int pitch2y(int) const; diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index 543e86aa..954cd08a 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -73,6 +73,8 @@ using namespace std;  using MusEGlobal::debugMsg;  using MusEGlobal::heavyDebugMsg; +using MusECore::UndoOp; +using MusECore::Undo;  namespace MusEGui { @@ -519,7 +521,7 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)  	selection_changed();  	connect(MusEGlobal::song, SIGNAL(songChanged(MusECore::SongChangedFlags_t)), SLOT(song_changed(MusECore::SongChangedFlags_t)));	 -	connect(MusEGlobal::song, SIGNAL(newPartsCreated(const std::map< MusECore::Part*, std::set<MusECore::Part*> >&)), score_canvas, SLOT(add_new_parts(const std::map< MusECore::Part*, std::set<MusECore::Part*> >&)));	 +	connect(MusEGlobal::song, SIGNAL(newPartsCreated(const std::map< const MusECore::Part*, std::set<const MusECore::Part*> >&)), score_canvas, SLOT(add_new_parts(const std::map< const MusECore::Part*, std::set<const MusECore::Part*> >&)));	  	score_canvas->fully_recalculate();  	score_canvas->goto_tick(initPos,true); @@ -653,7 +655,7 @@ void ScoreEdit::song_changed(MusECore::SongChangedFlags_t flags)  	if (flags & (SC_SELECTION | SC_EVENT_MODIFIED | SC_EVENT_REMOVED))  	{ -		map<MusECore::Event*, MusECore::Part*> selection=get_events(score_canvas->get_all_parts(),1); +		map<const MusECore::Event*, const MusECore::Part*> selection=get_events(score_canvas->get_all_parts(),1);  		if (selection.empty())  		{  			apply_velo_to_label->setText(tr("Apply to new notes:")); @@ -664,7 +666,7 @@ void ScoreEdit::song_changed(MusECore::SongChangedFlags_t flags)  			int velo=-1;  			int velo_off=-1; -			for (map<MusECore::Event*, MusECore::Part*>::iterator it=selection.begin(); it!=selection.end(); it++) +			for (map<const MusECore::Event*, const MusECore::Part*>::iterator it=selection.begin(); it!=selection.end(); it++)  				if (it->first->type()==MusECore::Note)  				{  					if (velo==-1) velo=it->first->velo(); @@ -897,7 +899,7 @@ void staff_t::write_status(int level, MusECore::Xml& xml) const  	xml.tag(level++, "staff");  	xml.intTag(level, "type", type);  	xml.intTag(level, "clef", clef); -	for (set<MusECore::Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +	for (set<const MusECore::Part*>::iterator part=parts.begin(); part!=parts.end(); part++)  	{  		MusECore::Track* track = (*part)->track();  		int trkIdx   = MusEGlobal::song->tracks()->index(track); @@ -962,7 +964,7 @@ void ScoreEdit::writeStatus(int level, MusECore::Xml& xml) const  	xml.intTag(level, "preambleContainsKeysig", preamble_keysig_action->isChecked());  	xml.intTag(level, "preambleContainsTimesig", preamble_timesig_action->isChecked()); -	MusECore::Part* selected_part=score_canvas->get_selected_part(); +	const MusECore::Part* selected_part=score_canvas->get_selected_part();  	if (selected_part==NULL)  	{  		xml.put(level, "<selectedPart>none</selectedPart>"); @@ -1520,9 +1522,9 @@ void ScoreCanvas::move_staff_below(list<staff_t>::iterator dest, list<staff_t>::  	move_staff_above(dest, src);  } -set<MusECore::Part*> ScoreCanvas::get_all_parts() +set<const MusECore::Part*> ScoreCanvas::get_all_parts()  { -	set<MusECore::Part*> result; +	set<const MusECore::Part*> result;  	for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++)  		result.insert(it->parts.begin(), it->parts.end()); @@ -1784,14 +1786,13 @@ void staff_t::create_appropriate_eventlist()  	// phase one: fill the list -----------------------------------------  	//insert note on events -	for (set<MusECore::Part*>::const_iterator part_it=parts.begin(); part_it!=parts.end(); part_it++) +	for (set<const MusECore::Part*>::const_iterator part_it=parts.begin(); part_it!=parts.end(); part_it++)  	{ -		MusECore::Part* part=*part_it; -		MusECore::EventList* el=part->events(); +		const MusECore::Part* part=*part_it; -		for (MusECore::iEvent it=el->begin(); it!=el->end(); it++) +		for (MusECore::ciEvent it=part->events().begin(); it!=part->events().end(); it++)  		{ -			MusECore::Event& event=it->second; +			const MusECore::Event& event=it->second;  			if ( ( event.isNote() && !event.isNoteOff() &&  			       // (event.endTick() <= part->lenTick()) ) && @@ -3804,7 +3805,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)  				if ((mouse_erases_notes) || (event->button()==Qt::MidButton)) //erase?  				{ -					MusEGlobal::audio->msgDeleteEvent(dragged_event, dragged_event_part, true, false, false); +					MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeleteEvent,dragged_event, dragged_event_part,  false, false));  				}  				else if (event->button()==Qt::LeftButton) //edit?  				{ @@ -3818,8 +3819,8 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)  				{  					if (mouse_inserts_notes)  					{ -						MusECore::Part* curr_part = NULL; -						set<MusECore::Part*> possible_dests=staff_it->parts_at_tick(tick); +						const MusECore::Part* curr_part = NULL; +						set<const MusECore::Part*> possible_dests=staff_it->parts_at_tick(tick);  						if (!possible_dests.empty())  						{ @@ -3866,7 +3867,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)  								newevent.setLenTick(curr_part->lenTick() - newevent.tick());  							} -							MusEGlobal::audio->msgAddEvent(newevent, curr_part, true, false, false); +							MusEGlobal::song->applyOperation(UndoOp(UndoOp::AddEvent, newevent, curr_part,false, false));  							set_dragged_event_part(curr_part);  							dragged_event=newevent; @@ -3913,7 +3914,7 @@ void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event)  			{  				if (debugMsg) cout << "new length <= 0, erasing item" << endl;  				if (undo_started) MusEGlobal::song->undo(); -				MusEGlobal::audio->msgDeleteEvent(dragged_event, dragged_event_part, true, false, false); +				MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeleteEvent,dragged_event, dragged_event_part, false, false));  			}  			else  			{ @@ -3928,9 +3929,7 @@ void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event)  				if (!ctrl)  					deselect_all(); -			clicked_event_ptr->setSelected(!clicked_event_ptr->selected()); - -			MusEGlobal::song->update(SC_SELECTION); +			MusEGlobal::song->applyOperation(UndoOp(UndoOp::SelectEvent, *clicked_event_ptr, !clicked_event_ptr->selected(), clicked_event_ptr->selected()));  		}  		setMouseTracking(false); @@ -3971,7 +3970,7 @@ void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event)  		if (!ctrl)  			deselect_all(); -		set<MusECore::Event*> already_processed; +		set<const MusECore::Event*> already_processed;  		for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++)  			it->apply_lasso(lasso.translated(x_pos-x_left, y_pos - it->y_draw), already_processed); @@ -4029,9 +4028,7 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event)  					if (!ctrl)  						deselect_all(); -					clicked_event_ptr->setSelected(true); -					 -					MusEGlobal::song->update(SC_SELECTION); +					MusEGlobal::song->applyOperation(UndoOp(UndoOp::SelectEvent, *clicked_event_ptr, true, clicked_event_ptr->selected()));  				}  				old_pitch=-1; @@ -4505,20 +4502,23 @@ void ScoreCanvas::set_velo_off(int velo)  void ScoreCanvas::deselect_all()  { -	set<MusECore::Part*> all_parts=get_all_parts(); +	set<const MusECore::Part*> all_parts=get_all_parts(); +	 +	Undo operations; +	operations.combobreaker=true; -	for (set<MusECore::Part*>::iterator part=all_parts.begin(); part!=all_parts.end(); part++) -		for (MusECore::iEvent event=(*part)->events()->begin(); event!=(*part)->events()->end(); event++) -			event->second.setSelected(false); +	for (set<const MusECore::Part*>::iterator part=all_parts.begin(); part!=all_parts.end(); part++) +		for (MusECore::ciEvent event=(*part)->events().begin(); event!=(*part)->events().end(); event++) +			operations.push_back(UndoOp(UndoOp::SelectEvent, event->second, false, event->second.selected())); -	MusEGlobal::song->update(SC_SELECTION); +	MusEGlobal::song->applyOperationGroup(operations);  }  bool staff_t::cleanup_parts()  {  	bool did_something=false; -	for (set<MusECore::Part*>::iterator it=parts.begin(); it!=parts.end();) +	for (set<const MusECore::Part*>::iterator it=parts.begin(); it!=parts.end();)  	{  		bool valid=false; @@ -4549,18 +4549,18 @@ bool staff_t::cleanup_parts()  	return did_something;  } -set<MusECore::Part*> staff_t::parts_at_tick(unsigned tick) +set<const MusECore::Part*> staff_t::parts_at_tick(unsigned tick)  { -	set<MusECore::Part*> result; +	set<const MusECore::Part*> result; -	for (set<MusECore::Part*>::iterator it=parts.begin(); it!=parts.end(); it++) +	for (set<const MusECore::Part*>::iterator it=parts.begin(); it!=parts.end(); it++)  		if ((tick >= (*it)->tick()) && (tick<=(*it)->endTick()))  			result.insert(*it);  	return result;  } -void staff_t::apply_lasso(QRect rect, set<MusECore::Event*>& already_processed) +void staff_t::apply_lasso(QRect rect, set<const MusECore::Event*>& already_processed)  {  	for (ScoreItemList::iterator it=itemlist.begin(); it!=itemlist.end(); it++)  		for (set<FloItem>::iterator it2=it->second.begin(); it2!=it->second.end(); it2++) @@ -4569,7 +4569,7 @@ void staff_t::apply_lasso(QRect rect, set<MusECore::Event*>& already_processed)  				if (rect.contains(it2->x, it2->y))  					if (already_processed.find(it2->source_event)==already_processed.end())  					{ -						it2->source_event->setSelected(!it2->source_event->selected()); +						MusEGlobal::song->applyOperation(UndoOp(UndoOp::SelectEvent,*it2->source_event,!it2->source_event->selected(),it2->source_event->selected()));  						already_processed.insert(it2->source_event);  					}  			} @@ -4617,7 +4617,7 @@ void staff_t::update_part_indices()  {  	part_indices.clear(); -	for (set<MusECore::Part*>::iterator it=parts.begin(); it!=parts.end(); it++) +	for (set<const MusECore::Part*>::iterator it=parts.begin(); it!=parts.end(); it++)  		part_indices.insert((*it)->sn());  } @@ -4654,15 +4654,15 @@ void ScoreEdit::keyPressEvent(QKeyEvent* event)  } -void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECore::Part*> >& param) +void ScoreCanvas::add_new_parts(const std::map< const MusECore::Part*, std::set<const MusECore::Part*> >& param)  {  	for (list<staff_t>::iterator staff=staves.begin(); staff!=staves.end(); staff++)  	{ -		for (std::map< MusECore::Part*, set<MusECore::Part*> >::const_iterator it = param.begin(); it!=param.end(); it++) +		for (std::map< const MusECore::Part*, set<const MusECore::Part*> >::const_iterator it = param.begin(); it!=param.end(); it++)  			if (staff->parts.find(it->first)!=staff->parts.end())  				staff->parts.insert(it->second.begin(), it->second.end()); -		//staff->cleanup_parts(); // don't cleanup here, because at this point, the parts may only exist +		//staff->cleanup_parts(); // don't cleanup here, because at this point, the parts might exist only  		                          // in the operation group. cleanup could remove them immediately  		staff->update_part_indices();  	} diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h index 3b413660..31bc0cff 100644 --- a/muse2/muse/midiedit/scoreedit.h +++ b/muse2/muse/midiedit/scoreedit.h @@ -257,8 +257,8 @@ class FloEvent  		enum typeEnum { NOTE_ON = 30, NOTE_OFF = 10, BAR = 20, KEY_CHANGE=23, TIME_SIG=26 }; //the order matters!  		typeEnum type;  		unsigned tick; -		MusECore::Part* source_part; -		MusECore::Event* source_event; +		const MusECore::Part* source_part; +		const MusECore::Event* source_event;  		int pitch;  		mutable int vel; @@ -270,7 +270,7 @@ class FloEvent  		MusECore::key_enum key; -		FloEvent(unsigned ti, int p,int v,int l,typeEnum t, MusECore::Part* part=NULL, MusECore::Event* event=NULL) +		FloEvent(unsigned ti, int p,int v,int l,typeEnum t, const MusECore::Part* part=NULL, const MusECore::Event* event=NULL)  		{  			pitch=p;  			vel=v; @@ -312,8 +312,8 @@ class FloItem  		enum typeEnum { NOTE=21, REST=22, NOTE_END=01, REST_END=02, BAR =10, KEY_CHANGE=13, TIME_SIG=16}; //the order matters!  		typeEnum type;  		unsigned begin_tick; -		MusECore::Event* source_event; -		MusECore::Part* source_part; +		const MusECore::Event* source_event; +		const MusECore::Part* source_part;  		note_pos_t pos;  		int len; @@ -343,7 +343,7 @@ class FloItem -		FloItem(typeEnum t, note_pos_t p, int l=0,int d=0, bool ti=false, unsigned beg=0, MusECore::Part* part=NULL, MusECore::Event* event=NULL) +		FloItem(typeEnum t, note_pos_t p, int l=0,int d=0, bool ti=false, unsigned beg=0, const MusECore::Part* part=NULL, const MusECore::Event* event=NULL)  		{  			pos=p;  			dots=d; @@ -546,7 +546,7 @@ enum staff_mode_t  struct staff_t  { -	set<MusECore::Part*> parts; +	set<const MusECore::Part*> parts;  	set<int> part_indices;  	ScoreEventList eventlist;  	ScoreItemList itemlist; @@ -568,7 +568,7 @@ struct staff_t  	void process_itemlist();  	void calc_item_pos(); -	void apply_lasso(QRect rect, set<MusECore::Event*>& already_processed); +	void apply_lasso(QRect rect, set<const MusECore::Event*>& already_processed);  	void recalculate()  	{ @@ -585,7 +585,7 @@ struct staff_t  		parent=parent_;  	} -	staff_t (ScoreCanvas* parent_, staff_type_t type_, clef_t clef_, set<MusECore::Part*> parts_) +	staff_t (ScoreCanvas* parent_, staff_type_t type_, clef_t clef_, set<const MusECore::Part*> parts_)  	{  		type=type_;  		clef=clef_; @@ -596,7 +596,7 @@ struct staff_t  	bool cleanup_parts(); -	set<MusECore::Part*> parts_at_tick(unsigned tick); +	set<const MusECore::Part*> parts_at_tick(unsigned tick);  	void read_status(MusECore::Xml& xml);  	void write_status(int level, MusECore::Xml& xml) const; @@ -718,7 +718,7 @@ class ScoreCanvas : public MusEGui::View  		float y_scroll_speed;  		float y_scroll_pos; -		MusECore::Part* selected_part; +		const MusECore::Part* selected_part;  		int selected_part_index;  		int last_len; @@ -742,11 +742,11 @@ class ScoreCanvas : public MusEGui::View  		bool inserting;  		bool dragging;  		bool drag_cursor_changed; -		MusECore::Part* dragged_event_part; +		const MusECore::Part* dragged_event_part;  		int dragged_event_part_index;  		MusECore::Event dragged_event;  		MusECore::Event original_dragged_event; -		MusECore::Event* clicked_event_ptr; +		const MusECore::Event* clicked_event_ptr;  		int old_pitch;  		unsigned old_dest_tick; @@ -790,7 +790,7 @@ class ScoreCanvas : public MusEGui::View  		void deselect_all();  		void midi_note(int pitch, int velo); -		void add_new_parts(const std::map< MusECore::Part*, std::set<MusECore::Part*> >&); +		void add_new_parts(const std::map< const MusECore::Part*, std::set<const MusECore::Part*> >&);  	public slots:  		void x_scroll_event(int); @@ -855,12 +855,12 @@ class ScoreCanvas : public MusEGui::View  		int get_last_len() {return last_len;}  		void set_last_len(int l) {last_len=l;} -		MusECore::Part* get_selected_part() {return selected_part;} -		void set_selected_part(MusECore::Part* p) {selected_part=p; if (selected_part) selected_part_index=selected_part->sn();} -		MusECore::Part* get_dragged_event_part() {return dragged_event_part;} -		void set_dragged_event_part(MusECore::Part* p) {dragged_event_part=p; if (dragged_event_part) dragged_event_part_index=dragged_event_part->sn();} +		const MusECore::Part* get_selected_part() const {return selected_part;} +		void set_selected_part(const MusECore::Part* p) {selected_part=p; if (selected_part) selected_part_index=selected_part->sn();} +		const MusECore::Part* get_dragged_event_part() const {return dragged_event_part;} +		void set_dragged_event_part(const MusECore::Part* p) {dragged_event_part=p; if (dragged_event_part) dragged_event_part_index=dragged_event_part->sn();} -		set<MusECore::Part*> get_all_parts(); +		set<const MusECore::Part*> get_all_parts();  		void write_staves(int level, MusECore::Xml& xml) const; diff --git a/muse2/muse/midieditor.cpp b/muse2/muse/midieditor.cpp index 13e6edc5..a4052d90 100644 --- a/muse2/muse/midieditor.cpp +++ b/muse2/muse/midieditor.cpp @@ -62,7 +62,7 @@ MidiEditor::MidiEditor(ToplevelType t, int r, MusECore::PartList* pl,        mainGrid->setSpacing(0);          setCentralWidget(mainw); -      connect(MusEGlobal::song, SIGNAL(newPartsCreated(const std::map< MusECore::Part*, std::set<MusECore::Part*> >&)), SLOT(addNewParts(const std::map< MusECore::Part*, std::set<MusECore::Part*> >&)));	 +      connect(MusEGlobal::song, SIGNAL(newPartsCreated(const std::map< const MusECore::Part*, std::set<const MusECore::Part*> >&)), SLOT(addNewParts(const std::map< const MusECore::Part*, std::set<const MusECore::Part*> >&)));        }  //--------------------------------------------------------- @@ -245,15 +245,15 @@ void MidiEditor::setCurCanvasPart(MusECore::Part* part)      canvas->setCurrentPart(part);   } -void MidiEditor::addNewParts(const std::map< MusECore::Part*, std::set<MusECore::Part*> >& param) +void MidiEditor::addNewParts(const std::map< const MusECore::Part*, std::set<const MusECore::Part*> >& param)  {    using std::map;    using std::set; -  for (map< MusECore::Part*, set<MusECore::Part*> >::const_iterator it = param.begin(); it!=param.end(); it++) +  for (map< const MusECore::Part*, set<const MusECore::Part*> >::const_iterator it = param.begin(); it!=param.end(); it++)      if (_pl->index(it->first) != -1) -      for (set<MusECore::Part*>::const_iterator it2=it->second.begin(); it2!=it->second.end(); it2++) -        addPart(*it2); +      for (set<const MusECore::Part*>::const_iterator it2=it->second.begin(); it2!=it->second.end(); it2++) +        addPart(const_cast<MusECore::Part*>(*it2)); // FIXME make this const-correct!  }  } // namespace MusEGui diff --git a/muse2/muse/midieditor.h b/muse2/muse/midieditor.h index 900f06b1..39feeedf 100644 --- a/muse2/muse/midieditor.h +++ b/muse2/muse/midieditor.h @@ -76,7 +76,7 @@ class MidiEditor : public TopWin  {        void genPartlist();     private slots: -      void addNewParts(const std::map< MusECore::Part*, std::set<MusECore::Part*> >&); +      void addNewParts(const std::map< const MusECore::Part*, std::set<const MusECore::Part*> >&);     public slots:        void songChanged(MusECore::SongChangedFlags_t type); diff --git a/muse2/muse/midievent.cpp b/muse2/muse/midievent.cpp index 9fd47eaf..fb6517cd 100644 --- a/muse2/muse/midievent.cpp +++ b/muse2/muse/midievent.cpp @@ -41,11 +41,26 @@ MidiEventBase::MidiEventBase(EventType t)        c = 0;        } +bool MidiEventBase::isSimilarTo(const EventBase& other_) const +{ +	const MidiEventBase* other = dynamic_cast<const MidiEventBase*>(&other_); +	if (other==NULL) // dynamic cast hsa failed: "other_" is not of type MidiEventBase. +		return false; +	 +	if ((a==other->a && b==other->b && c==other->c && edata.dataLen==other->edata.dataLen && this->PosLen::operator==(*other)) == false) +		return false; +	 +	if (edata.dataLen > 0) +		return (memcmp(edata.data, other->edata.data, edata.dataLen) == 0); +	else +		return true; // no data equals no data. +} +  //---------------------------------------------------------  //   MidiEventBase::mid  //--------------------------------------------------------- -EventBase* MidiEventBase::mid(unsigned b, unsigned e) +EventBase* MidiEventBase::mid(unsigned b, unsigned e) const        {        if (tick() < b || tick() >= e)              return 0; diff --git a/muse2/muse/midievent.h b/muse2/muse/midievent.h index a63fede2..dba2d727 100644 --- a/muse2/muse/midievent.h +++ b/muse2/muse/midievent.h @@ -36,11 +36,13 @@ class MidiEventBase : public EventBase {        int a, b, c;                  // pitch, velo-on, velo-off        EvData edata; -      virtual EventBase* clone() { return new MidiEventBase(*this); } +      virtual EventBase* clone() const { return new MidiEventBase(*this); }     public:        MidiEventBase(EventType t);        virtual ~MidiEventBase() {} +       +      virtual bool isSimilarTo(const EventBase& other) const;        virtual bool isNote() const                   { return type() == Note; }        virtual bool isNoteOff() const; @@ -71,7 +73,7 @@ class MidiEventBase : public EventBase {        virtual void dump(int n = 0) const;        virtual void read(Xml&);        virtual void write(int, Xml&, const Pos& offset, bool forcePath = false) const; -      virtual EventBase* mid(unsigned, unsigned); +      virtual EventBase* mid(unsigned, unsigned) const;        };  } // namespace MusECore diff --git a/muse2/muse/midiseq.cpp b/muse2/muse/midiseq.cpp index 8d0427d8..f6463d59 100644 --- a/muse2/muse/midiseq.cpp +++ b/muse2/muse/midiseq.cpp @@ -81,11 +81,6 @@ void MidiSeq::processMsg(const ThreadMsg* m)        {        MusECore::AudioMsg* msg = (MusECore::AudioMsg*)m;        switch(msg->id) { -            // This does not appear to be used anymore. Was sent in Audio::process1,  DELETETHIS 5 ?? -            //  now Audio::processMidi is called directly. p4.0.15 Tim. -            //case MusECore::MS_PROCESS: -            //      audio->processMidi(); -            //      break;              case MusECore::SEQM_SEEK:                    processSeek(); @@ -104,52 +99,6 @@ void MidiSeq::processMsg(const ThreadMsg* m)                    break; -            // Moved into Song::processMsg p4.0.34  ... -            case MusECore::SEQM_ADD_TRACK: -                  MusEGlobal::song->insertTrack2(msg->track, msg->ival); -                  updatePollFd(); -                  break; -            case MusECore::SEQM_REMOVE_TRACK: -                  MusEGlobal::song->cmdRemoveTrack(msg->track); -                  updatePollFd(); -                  break; -            //case MusECore::SEQM_CHANGE_TRACK: DELETETHIS 4 -            //      MusEGlobal::song->changeTrack((Track*)(msg->p1), (Track*)(msg->p2)); -            //      updatePollFd(); -            //      break; -            case MusECore::SEQM_ADD_PART: -                  MusEGlobal::song->cmdAddPart((Part*)msg->p1); -                  break; -            case MusECore::SEQM_REMOVE_PART: -                  MusEGlobal::song->cmdRemovePart((Part*)msg->p1); -                  break; -            case MusECore::SEQM_CHANGE_PART: -                  MusEGlobal::song->cmdChangePart((Part*)msg->p1, (Part*)msg->p2, msg->a, msg->b); -                  break; -                   -                   -            case MusECore::SEQM_SET_TRACK_OUT_CHAN: -                  { -                  MidiTrack* track = (MidiTrack*)(msg->p1); -                  track->setOutChanAndUpdate(msg->a); -                  } -                  break; -            case MusECore::SEQM_SET_TRACK_OUT_PORT: -                  { -                  MidiTrack* track = (MidiTrack*)(msg->p1); -                  track->setOutPortAndUpdate(msg->a); -                  } -                  break; -            case MusECore::SEQM_REMAP_PORT_DRUM_CTL_EVS: -                    MusEGlobal::song->remapPortDrumCtrlEvents(msg->ival, msg->a, msg->b, msg->c); -                  break; -            case MusECore::SEQM_CHANGE_ALL_PORT_DRUM_CTL_EVS:       -                    MusEGlobal::song->changeAllPortDrumCtrlEvents((bool)msg->a, (bool)msg->b); -                  break; -            case MusECore::SEQM_SET_MIDI_DEVICE: -                  ((MidiPort*)(msg->p1))->setMidiDevice((MidiDevice*)(msg->p2)); -                  updatePollFd(); -                  break;              case MusECore::SEQM_IDLE:                    idle = msg->a;                    break; @@ -169,35 +118,12 @@ void MidiSeq::processStop()    // TODO Try to move this into Audio::stopRolling().     playStateExt = false; // not playing -  // -  //    clear Alsa midi device notes and stop stuck notes -  // +  // clear Alsa midi device notes and stop stuck notes    for(iMidiDevice id = MusEGlobal::midiDevices.begin(); id != MusEGlobal::midiDevices.end(); ++id)  -  { -    //MidiDevice* md = *id; DELETETHIS 3 -    // Only ALSA devices are handled by this thread. -    //if((*id)->deviceType() == MidiDevice::ALSA_MIDI)              (*id)->handleStop();   -    /* DELETETHIS 14 -    if (md->midiPort() == -1) -          continue; -    MPEventList* pel = md->playEvents(); -    MPEventList* sel = md->stuckNotes(); -    pel->clear(); -    for(iMPEvent i = sel->begin(); i != sel->end(); ++i)  -    { -      MidiPlayEvent ev = *i; -      ev.setTime(0); -      pel->add(ev); -    } -    sel->clear(); -    //md->setNextPlayEvent(pel->begin());  // Removed p4.0.15 -    */ -  }  }  #endif -#if 1   //DELETETHIS #if and #endif  //---------------------------------------------------------  //   processSeek  //--------------------------------------------------------- @@ -209,62 +135,8 @@ void MidiSeq::processSeek()    //---------------------------------------------------    for (iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i)  -  { -    //MidiDevice* md = *i; DELETETHIS 3 -    // Only ALSA devices are handled by this thread. -    //if((*i)->deviceType() == MidiDevice::ALSA_MIDI)              (*i)->handleSeek();   -    /* DELETETHIS 47 -    int port = md->midiPort(); -    if (port == -1) -          continue; -    MidiPort* mp = &MusEGlobal::midiPorts[port]; -    MidiCtrlValListList* cll = mp->controller(); - -    MPEventList* el = md->playEvents(); - -    if (MusEGlobal::audio->isPlaying())  -    { -      // stop all notes -      el->clear(); -      MPEventList* sel = dev->stuckNotes(); -      for (iMPEvent i = sel->begin(); i != sel->end(); ++i)  -      { -            MidiPlayEvent ev = *i; -            ev.setTime(0); -            el->add(ev); -      } -      sel->clear(); -    } -    //else -      // Removed p4.0.15 Device now leaves beginning pointing at next event, -      //  immediately after playing some notes.   -      // NOTE: This removal needs testing. I'm not sure about this. -      //el->erase(el->begin(), dev->nextPlayEvent());   -     -    for (iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)  -    { -      MidiCtrlValList* vl = ivl->second; -      //int val = vl->value(pos); -      //if (val != CTRL_VAL_UNKNOWN) { -      //      int channel = ivl->first >> 24; -      //      el->add(MidiPlayEvent(0, port, channel, ME_CONTROLLER, vl->num(), val)); -      //      } -      iMidiCtrlVal imcv = vl->iValue(pos); -      if(imcv != vl->end())  -      { -        Part* p = imcv->second.part; -        unsigned t = (unsigned)imcv->first; -        // Do not add values that are outside of the part. -        if(p && t >= p->tick() && t < (p->tick() + p->lenTick()) ) -          el->add(MidiPlayEvent(0, port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val)); -      } -    } -    //dev->setNextPlayEvent(el->begin());    // Removed p4.0.15 -    */ -  }  } -#endif  //---------------------------------------------------------  //   MidiSeq @@ -353,22 +225,6 @@ signed int MidiSeq::selectTimer()  void MidiSeq::threadStart(void*)        { -      // Removed by Tim. p3.3.17 DELETETHIS 13 -      /* -      struct sched_param rt_param; -      memset(&rt_param, 0, sizeof(rt_param)); -      int prio_min = sched_get_priority_min(SCHED_FIFO); -      int prio_max = sched_get_priority_max(SCHED_FIFO); - -      if (prio < prio_min) prio = prio_min; -      else if (prio > prio_max) prio = prio_max; - -      rt_param.sched_priority = prio; -      int rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &rt_param); -      if (rv != 0) -            perror("set realtime scheduler"); -      */ -        int policy;        if ((policy = sched_getscheduler (0)) < 0) {              printf("Cannot get current client scheduler: %s\n", strerror(errno)); @@ -398,19 +254,6 @@ static void midiRead(void*, void* d)        dev->processInput();        } -// DELETETHIS 12 -//--------------------------------------------------------- -//   synthIRead -//--------------------------------------------------------- - -#if 0 -static void synthIRead(void*, void* d) -      { -      SynthI* syn = (SynthI*) d; -      syn->processInput(); -      } -#endif -  //---------------------------------------------------------  //   midiWrite  //--------------------------------------------------------- @@ -590,42 +433,6 @@ void MidiSeq::setSyncRecFilterPreset(MidiSyncInfo::SyncRecFilterPresetType type)  } -//--------------------------------------------------------- -//   processMidiClock -//--------------------------------------------------------- - -void MidiSeq::processMidiClock() -      { -      // DELETETHIS 30, maybe remove entire function? -//      if (genMCSync) { -//            MusEGlobal::midiPorts[txSyncPort].sendClock(); -//      } - -/*      if (state == START_PLAY) { -            // start play on sync -            state      = PLAY; -            _midiTick  = playTickPos; -            midiClock  = playTickPos; - -            int bar, beat, tick; -            sigmap.tickValues(_midiTick, &bar, &beat, &tick); -            midiClick      = sigmap.bar2tick(bar, beat+1, 0); - -            double cpos    = MusEGlobal::tempomap.tick2time(playTickPos); -            samplePosStart = samplePos - lrint(cpos * MusEGlobal::sampleRate); -            rtcTickStart   = rtcTick - lrint(cpos * realRtcTicks); - -            endSlice       = playTickPos; -            recTick        = playTickPos; -            lastTickPos    = playTickPos; - -            tempoSN = MusEGlobal::tempomap.tempoSN(); - -            startRecordPos.setPosTick(playTickPos); -            } -*/ -//      midiClock += MusEGlobal::config.division/24; -      }  //---------------------------------------------------------  //   midiTick @@ -698,126 +505,18 @@ void MidiSeq::processTimerTick()                        mp->sendClock();                      } -                    // DELETETHIS 35 ?? -                    /* -                    for(iMidiDevice imd = MusEGlobal::midiDevices.begin(); imd != MusEGlobal::midiDevices.end(); ++imd)  -                    { -                      MidiDevice* dev = *imd; -                       -                      if(!dev->syncInfo().MCOut()) -                        continue; -                         -                      // Shall we check open flags? -                      //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1)) -                      //if(!(dev->openFlags() & 1)) -                      //  continue; -         -                      int port = dev->midiPort(); -                      // Without this -1 check, interesting sync things can be done by the user without ever -                      //  assigning any devices to ports !  -                      //if(port < 0 || port > MIDI_PORTS) -                      if(port < -1 || port > MIDI_PORTS) -                        continue; -                         -                      if(port == -1) -                      // Send straight to the device... Copied from MidiPort. -                      { -                        MidiPlayEvent event(0, 0, 0, ME_CLOCK, 0, 0); -                        dev->putEvent(event); -                      }   -                      else -                        // Go through the port... -                        MusEGlobal::midiPorts[port].sendClock(); -                    } -                    */ -                                          if(MusEGlobal::debugMsg && used && perr > 1)                        printf("Dropped %d midi out clock(s). curTick:%d midiClock:%d div:%d\n", perr, curTick, midiClock, div); -                  //} DELETETHIS and maybe the below ??? -                     -                  // Increment as if we had caught the timer exactly on the mark, even if the timer -                  //  has passed beyond the mark, or even beyond 2 * div. -                  // If we missed some chances to send clock, resume the count where it would have been,  -                  //  had we not missed chances. -                  // We can't do anything about missed chances except send right away, and make up -                  //  for gained time by losing time in the next count... -                  // In other words, use equalization periods to counter gained/lost time, so that -                  //  ultimately, over time, the receiver remains in phase, despite any short dropouts / phase glitches. -                  // (midiClock only increments by div units). -                  // -                  // Tested: With midi thread set to high priority, very few clock dropouts ocurred (P4 1.6Ghz). -                  // But target device tick drifts out of phase with muse tick slowly over time, say 20 bars or so. -                  // May need more tweaking, possibly use round with/instead of lrint (above), and/or -                  //  do not use equalization periods - set midiClock to fractions of div. -                  // Tested: With RTC resolution at 1024, stability was actually better than with 8192! -                  // It stayed in sync more than 64 bars... -                  // -                  // +                    // Using equalization periods...                    midiClock += (perr * div); -                  //midiClock += perr; DELETETHIS -                  // -                  // No equalization periods... TODO: or DELETETHIS? -                  //midiClock += (perr * div);                 }              }        // play all events upto curFrame -      for (iMidiDevice id = MusEGlobal::midiDevices.begin(); id != MusEGlobal::midiDevices.end(); ++id) { -            //MidiDevice* md = *id; DELETETHIS 10 -            // Is it a Jack midi device? They are iterated in Audio::processMidi. p3.3.36  -            //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md); -            //if(mjd) -            //if(md->deviceType() == MidiDevice::JACK_MIDI) -            //  continue; -            //if(md->isSynti())      // syntis are handled by audio thread -            //      continue; -            // Only ALSA midi devices are handled by this thread. +      for (iMidiDevice id = MusEGlobal::midiDevices.begin(); id != MusEGlobal::midiDevices.end(); ++id)              if((*id)->deviceType() == MidiDevice::ALSA_MIDI)                (*id)->processMidi(); -             -            // Moved into MidiAlsaDevice.      p4.0.34 DELETETHIS 40 -            /* -            int port = md->midiPort(); -            MidiPort* mp = port != -1 ? &MusEGlobal::midiPorts[port] : 0; -            MPEventList* el = md->playEvents(); -            if (el->empty()) -                  continue; -             -            ///iMPEvent i = md->nextPlayEvent(); -            iMPEvent i = el->begin();            // p4.0.15 Tim. -             -            for (; i != el->end(); ++i) { -                  // p3.3.25 -                  // If syncing to external midi sync, we cannot use the tempo map. -                  // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. -                  //if (i->time() > curFrame) { -                  if (i->time() > (extsync ? tickpos : curFrame)) { -                        //printf("  curT %d  frame %d\n", i->time(), curFrame); -                        break; // skip this event -                        } - -                  if (mp) { -                        if (mp->sendEvent(*i)) -                              break; -                        } -                  else { -                        if (md->putEvent(*i)) -                              break; -                        } -                  } -            ///md->setNextPlayEvent(i); -            // p4.0.15 We are done with these events. Let us erase them here instead of Audio::processMidi. -            // That way we can simply set the next play event to the beginning. -            // This also allows other events to be inserted without the problems caused by the next play event  -            //  being at the 'end' iterator and not being *easily* set to some new place beginning of the newer insertions.  -            // The way that MPEventList sorts made it difficult to predict where the iterator of the first newly inserted items was. -            // The erasure in Audio::processMidi was missing some events because of that. -            el->erase(el->begin(), i); -            //md->setNextPlayEvent(el->begin());  // Removed p4.0.15 -            */ -             -            }        }  //--------------------------------------------------------- diff --git a/muse2/muse/midiseq.h b/muse2/muse/midiseq.h index 08adcdce..4a7fd829 100644 --- a/muse2/muse/midiseq.h +++ b/muse2/muse/midiseq.h @@ -78,7 +78,6 @@ class MidiSeq : public Thread {        void processTimerTick();        void processSeek();        void processStop(); -      void processMidiClock();        virtual void processMsg(const ThreadMsg*);        void updatePollFd(); diff --git a/muse2/muse/miditransform.cpp b/muse2/muse/miditransform.cpp index f9289dcc..723e067b 100644 --- a/muse2/muse/miditransform.cpp +++ b/muse2/muse/miditransform.cpp @@ -41,6 +41,9 @@  #include "gconfig.h"  #include "midictrl.h" +using MusECore::Undo; +using MusECore::UndoOp; +  namespace MusECore {  // @@ -484,8 +487,7 @@ void MidiTransformerDialog::accept()  //    subfunction of processEvent()  //--------------------------------------------------------- -void MidiTransformerDialog::transformEvent(MusECore::Event& event, MusECore::MidiPart* part, -  MusECore::MidiPart* newPart) +void MidiTransformerDialog::transformEvent(MusECore::Event& event, MusECore::MidiPart* part, MusECore::MidiPart* newPart, MusECore::Undo& operations)        {        MusECore::MidiTransformation* cmt = data->cmt;        MusECore::Event newEvent = event.clone(); @@ -676,33 +678,16 @@ void MidiTransformerDialog::transformEvent(MusECore::Event& event, MusECore::Mid              pos = 0;        newEvent.setTick(pos); -      MusECore::Event dummy;        switch(data->cmt->funcOp) {              case MusECore::Transform: -                  // Indicate do clone parts.  -                  removePortCtrlEvents(event, part, true); -                  MusEGlobal::song->changeEvent(event, newEvent, part); -                  // Indicate do clone parts.  -                  addPortCtrlEvents(newEvent, part, true); -                  // Indicate do port controller values and clone parts.  -                  MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, true, true)); -                  MusEGlobal::song->addUpdateFlags(SC_EVENT_MODIFIED); +                  operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, true, true));                    break;              case MusECore::Insert:                    // Indicate do port controller values and clone parts.  -                  MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::AddEvent, dummy, newEvent, part, true, true)); -                  MusEGlobal::song->addEvent(newEvent, part); -                  // Indicate do clone parts.  -                  addPortCtrlEvents(newEvent, part, true); -                  MusEGlobal::song->addUpdateFlags(SC_EVENT_INSERTED); +                  operations.push_back(UndoOp(UndoOp::AddEvent, newEvent, part, true, true));                    break;              case MusECore::Extract: -                  // Indicate do port controller values and clone parts.  -                  MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::DeleteEvent, dummy, event, part, true, true)); -                  // Indicate do clone parts.  -                  removePortCtrlEvents(event, part, true); -                  MusEGlobal::song->deleteEvent(event, part); -                  MusEGlobal::song->addUpdateFlags(SC_EVENT_REMOVED); +                  operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, true, true));              case MusECore::Copy:                    newPart->addEvent(newEvent);                    break; @@ -715,7 +700,7 @@ void MidiTransformerDialog::transformEvent(MusECore::Event& event, MusECore::Mid  //   processEvent  //--------------------------------------------------------- -void MidiTransformerDialog::processEvent(MusECore::Event& event, MusECore::MidiPart* part, MusECore::MidiPart* newPart) +void MidiTransformerDialog::processEvent(MusECore::Event& event, MusECore::MidiPart* part, MusECore::MidiPart* newPart, MusECore::Undo& operations)        {        switch(data->cmt->funcOp) {              case MusECore::Select: @@ -725,35 +710,22 @@ void MidiTransformerDialog::processEvent(MusECore::Event& event, MusECore::MidiP                    int tick = event.tick();                    int rt = AL::sigmap.raster(tick, data->cmt->quantVal) - tick;                    if (tick != rt) { -                        // Indicate do clone parts.  -                        removePortCtrlEvents(event, part, true);                          MusECore::Event newEvent = event.clone();                          newEvent.setTick(rt); -                        MusEGlobal::song->changeEvent(event, newEvent, part); -                        // Indicate do clone parts.  -                        addPortCtrlEvents(newEvent, part, true); -                        // Indicate do port controller values and clone parts.  -                        MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, true, true)); -                        MusEGlobal::song->addUpdateFlags(SC_EVENT_MODIFIED); +						operations.push_back(UndoOp(UndoOp::ModifyEvent,newEvent,event,part,true,true));                          }                    }                    break;              case MusECore::Delete:                    { -                  MusECore::Event ev; -                  // Indicate do port controller values and clone parts.  -                  MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::DeleteEvent, ev, event, part, true, true)); -                  // Indicate do clone parts.  -                  removePortCtrlEvents(event, part, true); -                  MusEGlobal::song->deleteEvent(event, part); -                  MusEGlobal::song->addUpdateFlags(SC_EVENT_REMOVED); +                  operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, true, true));                    }                    break;              case MusECore::Transform:              case MusECore::Insert:              case MusECore::Copy:              case MusECore::Extract: -                  transformEvent(event, part, newPart); +                  transformEvent(event, part, newPart, operations);                    break;              }        } @@ -764,7 +736,7 @@ void MidiTransformerDialog::processEvent(MusECore::Event& event, MusECore::MidiP  //    return true if event is selected  //--------------------------------------------------------- -bool MidiTransformerDialog::isSelected(MusECore::Event& event, MusECore::MidiPart*) +bool MidiTransformerDialog::isSelected(const MusECore::Event& event)        {        MusECore::MidiTransformation* cmt = data->cmt; @@ -927,13 +899,13 @@ bool MidiTransformerDialog::isSelected(MusECore::Event& event, MusECore::MidiPar  void MidiTransformerDialog::apply()        {        MusECore::SongChangedFlags_t flags = 0; -      MusEGlobal::song->startUndo(); -      MusEGlobal::audio->msgIdle(true); +	   +	  Undo operations;        bool copyExtract = (data->cmt->funcOp == MusECore::Copy)                           || (data->cmt->funcOp == MusECore::Extract); -      std::vector< MusECore::EventList* > doneList; -      typedef std::vector< MusECore::EventList* >::iterator iDoneList; +      QSet< int > doneList; +      typedef std::set< int >::iterator iDoneList;        iDoneList idl;        MusECore::MidiTrackList* tracks = MusEGlobal::song->midis(); @@ -947,21 +919,18 @@ void MidiTransformerDialog::apply()                    // check wether we must generate a new track                    for (MusECore::iPart p = pl->begin(); p != pl->end(); ++p) {                          MusECore::MidiPart* part = (MusECore::MidiPart *) p->second; -                        MusECore::EventList* el = part->events(); +                        const MusECore::EventList& el = part->events();                          // Check if the event list has already been done. Skip repeated clones. -                        for(idl = doneList.begin(); idl != doneList.end(); ++idl) -                          if(*idl == el) -                            break; -                        if(idl != doneList.end()) -                          break; -                        doneList.push_back(el); +                        if (doneList.contains(part->clonemaster_sn())) +                             continue; +                        doneList.insert(part->clonemaster_sn()); -                        for (MusECore::iEvent i = el->begin(); i != el->end(); ++i) { -                              MusECore::Event event = i->second; +                        for (MusECore::ciEvent i = el.begin(); i != el.end(); ++i) { +                              const MusECore::Event& event = i->second;                                unsigned tick = event.tick();                                if (data->cmt->insideLoop && (tick < MusEGlobal::song->lpos() || tick >= MusEGlobal::song->rpos()))                                      continue; -                              if (isSelected(event, part)) { +                              if (isSelected(event)) {                                      newTrack = new MusECore::MidiTrack();                                      tl.push_back(newTrack);                                      break; @@ -975,82 +944,56 @@ void MidiTransformerDialog::apply()              for (MusECore::iPart p = pl->begin(); p != pl->end(); ++p) {                    MusECore::MidiPart* part = (MusECore::MidiPart *) p->second;                    MusECore::MidiPart* newPart = 0; -                  MusECore::EventList* el = part->events(); +                  const MusECore::EventList& el = part->events();                    // Check if the event list has already been done. Skip repeated clones. -                  for(idl = doneList.begin(); idl != doneList.end(); ++idl) -                    if(*idl == el) -                      break; -                  if(idl != doneList.end()) -                    break; -                  doneList.push_back(el); +                  if (doneList.contains(part->clonemaster_sn())) +                      continue; +                  doneList.insert(part->clonemaster_sn());                    if (copyExtract) {                          // check wether we must generate a new part -                        for (MusECore::iEvent i = el->begin(); i != el->end(); ++i) { -                              MusECore::Event event = i->second; +                        for (MusECore::ciEvent i = el.begin(); i != el.end(); ++i) { +                              const MusECore::Event& event = i->second;                                unsigned tick = event.tick();                                if (data->cmt->insideLoop && (tick < MusEGlobal::song->lpos() || tick >= MusEGlobal::song->rpos()))                                      continue; -                              if (isSelected(event, part)) { +                              if (isSelected(event)) {                                      newPart = new MusECore::MidiPart(newTrack);                                      newPart->setName(part->name());                                      newPart->setColorIndex(part->colorIndex());                                      newPart->setTick(part->tick());                                      newPart->setLenTick(part->lenTick()); -                                    MusEGlobal::song->addPart(newPart); +                                    operations.push_back(UndoOp(UndoOp::AddPart,newPart));                                      flags |= SC_PART_INSERTED;                                      break;                                      }                                }                          }                    MusECore::EventList pel; -                  for (MusECore::iEvent i = el->begin(); i != el->end(); ++i) { -                        MusECore::Event event = i->second; +                  for (MusECore::ciEvent i = el.begin(); i != el.end(); ++i) { +                        const MusECore::Event& event = i->second;                          unsigned tick = event.tick();                          if (data->cmt->insideLoop && (tick < MusEGlobal::song->lpos() || tick >= MusEGlobal::song->rpos()))                                continue; -                        int flag = isSelected(event, part); +                        int flag = isSelected(event);                          if (data->cmt->funcOp == MusECore::Select) -                              event.setSelected(flag); +                              operations.push_back(UndoOp(UndoOp::SelectEvent, event,flag, event.selected()));                          else if (flag) -                              pel.add(event); +                              pel.add(const_cast<MusECore::Event&>(event)); // ough, FIXME, what an ugly hack.                          }                    for (MusECore::iEvent i = pel.begin(); i != pel.end(); ++i) {                          MusECore::Event event = i->second; -                        processEvent(event, part, newPart); +                        processEvent(event, part, newPart, operations);                          }                    }              }        if (!tl.empty()) {              flags |= SC_TRACK_INSERTED; -            for (MusECore::iTrack t = tl.begin(); t != tl.end(); ++t) { -                  MusEGlobal::song->insertTrack0(*t, -1); -                  } -            } +            for (MusECore::iTrack t = tl.begin(); t != tl.end(); ++t) +                  operations.push_back(UndoOp(UndoOp::AddTrack, -1, *t)); +      } -      switch(data->cmt->funcOp) { -            case MusECore::Select: -                  flags |= SC_SELECTION; -                  break; -            case MusECore::Quantize: -                  flags |= SC_EVENT_MODIFIED; -                  break; -            case MusECore::Delete: -                  flags |= SC_EVENT_REMOVED; -                  break; -            case MusECore::Transform: -                  flags |= SC_EVENT_MODIFIED; -                  break; -            case MusECore::Insert: -                  flags |= SC_EVENT_INSERTED; -                  break; -            case MusECore::Copy: -                  flags |= SC_EVENT_INSERTED; -            case MusECore::Extract: -                  break; -            } -      MusEGlobal::audio->msgIdle(false); -      MusEGlobal::song->endUndo(flags); +      MusEGlobal::song->applyOperationGroup(operations);        }  //--------------------------------------------------------- @@ -1721,9 +1664,9 @@ void MidiTransformerDialog::insideLoopChanged(bool val)  /*! -    \fn MidiTransformerDialog::typesMatch(MusECore::MidiEvent e, unsigned t) +    \fn MidiTransformerDialog::typesMatch(const MusECore::MidiEvent e, unsigned t)   */ -bool MidiTransformerDialog::typesMatch(MusECore::Event& e, unsigned selType) +bool MidiTransformerDialog::typesMatch(const MusECore::Event& e, unsigned selType)        {        bool matched = false;        switch (selType) diff --git a/muse2/muse/miditransform.h b/muse2/muse/miditransform.h index e8022277..5ff78357 100644 --- a/muse2/muse/miditransform.h +++ b/muse2/muse/miditransform.h @@ -32,6 +32,7 @@ class QDialog;  namespace MusECore { +class Undo;  class Event;  class MidiPart;  class MidiTransformation; @@ -84,10 +85,10 @@ class MidiTransformerDialog : public QDialog, public Ui::MidiTransformDialogBase        virtual void accept();        void setValOp(QWidget* a, QWidget* b, MusECore::ValOp op); -      void processEvent(MusECore::Event&, MusECore::MidiPart*, MusECore::MidiPart*); -      bool isSelected(MusECore::Event&, MusECore::MidiPart*); -      void transformEvent(MusECore::Event&, MusECore::MidiPart*, MusECore::MidiPart*); -      bool typesMatch(MusECore::Event& e, unsigned selType); +      void processEvent(MusECore::Event&, MusECore::MidiPart*, MusECore::MidiPart*, MusECore::Undo& operations); +      bool isSelected(const MusECore::Event&); +      void transformEvent(MusECore::Event&, MusECore::MidiPart*, MusECore::MidiPart*, MusECore::Undo& operations); +      bool typesMatch(const MusECore::Event& e, unsigned selType);        void updatePresetList(); diff --git a/muse2/muse/mixer/strip.cpp b/muse2/muse/mixer/strip.cpp index 06ee9443..cf4be792 100644 --- a/muse2/muse/mixer/strip.cpp +++ b/muse2/muse/mixer/strip.cpp @@ -42,6 +42,9 @@  #include "meter.h"  #include "utils.h"  #include "icons.h" +#include "undo.h" + +using MusECore::UndoOp;  namespace MusEGui { @@ -340,8 +343,7 @@ void Strip::mousePressEvent(QMouseEvent* ev)        QFrame::mousePressEvent(ev);        return;      } -    MusEGlobal::song->removeTrack0(track); -    MusEGlobal::audio->msgUpdateSoloStates(); +    MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeleteTrack, MusEGlobal::song->tracks()->index(track), track));      ev->accept();      return;    } diff --git a/muse2/muse/part.cpp b/muse2/muse/part.cpp index 5f3aa8ee..1d246c50 100644 --- a/muse2/muse/part.cpp +++ b/muse2/muse/part.cpp @@ -22,6 +22,7 @@  //  //========================================================= +#include <assert.h>  #include <stdio.h>  #include <cmath> @@ -39,316 +40,97 @@ namespace MusECore {  int Part::snGen=0; -//--------------------------------------------------------- -//   unchainClone -//--------------------------------------------------------- -void unchainClone(Part* p) +void Part::unchainClone()  { -  chainCheckErr(p); +  chainCheckErr(this); // FIXME proper assert! -  // Unchain the part. -  p->prevClone()->setNextClone(p->nextClone()); -  p->nextClone()->setPrevClone(p->prevClone()); +  if (_backupClone) printf("THIS SHOULD NEVER HAPPEN: Part::unchainClone() called, but _backupClone was non-NULL\n"); -  // Isolate the part. -  p->setPrevClone(p); -  p->setNextClone(p); -} - -//--------------------------------------------------------- -//   chainClone -//   The quick way - if part to chain to is known... -//--------------------------------------------------------- - -void chainClone(Part* p1, Part* p2) -{ -  chainCheckErr(p1); +  _backupClone=_prevClone; -  // Make sure the part to be chained is unchained first. -  p2->prevClone()->setNextClone(p2->nextClone()); -  p2->nextClone()->setPrevClone(p2->prevClone()); +  // Unchain the part. +  _prevClone->_nextClone = _nextClone; +  _nextClone->_prevClone = _prevClone; -  // Link the part to be chained. -  p2->setPrevClone(p1); -  p2->setNextClone(p1->nextClone()); +  // Isolate the part. +  _prevClone = this; +  _nextClone = this; -  // Re-link the existing part. -  p1->nextClone()->setPrevClone(p2); -  p1->setNextClone(p2); +  _clonemaster_sn = this->_sn;  } -//--------------------------------------------------------- -//   chainCloneInternal -//   No error check, so it can be called by replaceClone() -//--------------------------------------------------------- - -void chainCloneInternal(Part* p) +void Part::chainClone(Part* p)  { -  Track* t = p->track(); -  Part* p1 = 0; +  // FIXME assertion +  assert(p); -  // Look for a part with the same event list, that we can chain to. -  // It's faster if track type is known... -   -  if(!t || (t && t->isMidiTrack())) +  if (! (_prevClone==this && _nextClone==this)) // the part is still part of a clone chain!    { -    MidiTrack* mt = 0; -    MidiTrackList* mtl = MusEGlobal::song->midis(); -    for(ciMidiTrack imt = mtl->begin(); imt != mtl->end(); ++imt) -    { -      mt = *imt; -      const PartList* pl = mt->cparts(); -      for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) -      { -        if(ip->second != p && ip->second->cevents() == p->cevents()) -        { -          p1 = ip->second; -          break; -        } -      } -      // If a suitable part was found on a different track, we're done. We will chain to it. -      // Otherwise keep looking for parts on another track. If no others found, then we -      //  chain to any suitable part which was found on the same given track t. -      if(p1 && mt != t) -        break; -    } -  }   -  if((!p1 && !t) || (t && t->type() == Track::WAVE)) -  { -    MusECore::WaveTrack* wt = 0; -    MusECore::WaveTrackList* wtl = MusEGlobal::song->waves(); -    for(MusECore::ciWaveTrack iwt = wtl->begin(); iwt != wtl->end(); ++iwt) -    { -      wt = *iwt; -      const PartList* pl = wt->cparts(); -      for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) -      { -        if(ip->second != p && ip->second->cevents() == p->cevents()) -        { -          p1 = ip->second; -          break; -        } -      } -      if(p1 && wt != t) -        break; -    } +    printf("ERROR: THIS SHOULD NEVER HAPPEN: Part::chainClone() called, but part is already chained! I'll unchain for now, but better fix that!\n"); +    this->unchainClone();    } + +  // Make our links to the chain +  this->_prevClone = p; +  this->_nextClone = p->_nextClone; -  // No part found with same event list? Done. -  if(!p1) -    return; -     -  // Make sure the part to be chained is unchained first. -  p->prevClone()->setNextClone(p->nextClone()); -  p->nextClone()->setPrevClone(p->prevClone()); +  // Make the chain's links to us +  this->_nextClone->_prevClone = this; +  p->_nextClone = this; -  // Link the part to be chained. -  p->setPrevClone(p1); -  p->setNextClone(p1->nextClone()); +  // we only chain clones. we must trust in the GUI thread that the eventlist is consistent. -  // Re-link the existing part. -  p1->nextClone()->setPrevClone(p); -  p1->setNextClone(p); +  this->_clonemaster_sn = p->_sn;  } -//--------------------------------------------------------- -//   chainClone -//   The slow way - if part to chain to is not known... -//--------------------------------------------------------- - -void chainClone(Part* p) +void Part::rechainClone()  { -  chainCheckErr(p); -  chainCloneInternal(p); +    if(_backupClone) +    { +        this->chainClone(_backupClone); +        _backupClone = NULL; +    }  } -//--------------------------------------------------------- -//   replaceClone -//--------------------------------------------------------- +bool Part::isCloneOf(const Part* other) const +{ +	return this->_clonemaster_sn == other->_clonemaster_sn; +} -// this replaces p1 by p2. p1 is isolated, and p2 takes its place instead. -void replaceClone(Part* p1, Part* p2) +int Part::nClones() const  { -  chainCheckErr(p1); -   -  // Make sure the replacement part is unchained first. -  p2->prevClone()->setNextClone(p2->nextClone()); -  p2->nextClone()->setPrevClone(p2->prevClone()); -   -  // If the two parts share the same event list, then this MUST  -  //  be a straight forward replacement operation. Continue on. -  // If not, and either part has more than one ref count, then do this... -  if(p1->cevents() != p2->cevents()) -  { -    bool ret = false; -    // If the part to be replaced is a single uncloned part,  [DELETETHIS 4 this seems outdated=wrong to me] -    //  and the replacement part is not, then this operation -    //  MUST be an undo of a de-cloning of a cloned part.   -    //if(p1->cevents()->refCount() <= 1 && p2->cevents()->refCount() > 1) -    if(p2->cevents()->refCount() > 1) -    {   -      // Chain the replacement part. We don't know the chain it came from, -      //  so we use the slow method. -      chainCloneInternal(p2); -      //return; DELETETHIS -      ret = true; -    } -     -    // If the replacement part is a single uncloned part,    DELETETHIS same as above -    //  and the part to be replaced is not, then this operation -    //  MUST be a de-cloning of a cloned part.   -    //if(p1->cevents()->refCount() > 1 && p2->cevents()->refCount() <= 1) -    if(p1->cevents()->refCount() > 1) -    {   -      // Unchain the part to be replaced. -      p1->prevClone()->setNextClone(p1->nextClone()); -      p1->nextClone()->setPrevClone(p1->prevClone()); -      // Isolate the part. -      p1->setPrevClone(p1); -      p1->setNextClone(p1); -      ret = true; -    } -     -    // Was the operation handled? -    if(ret) -      return; -    // Note that two parts here with different event lists, each with more than one -    //  reference count, would be an error. It's not done anywhere in muse. But just  -    //  to be sure, four lines above were changed to allow that condition. -    // If each of the two different event lists, has only one ref count, we -    //  handle it like a regular replacement, below... -  } -   -  // If the part to be replaced is a clone not a single lone part, re-link its neighbours to the replacement part... -  if(p1->prevClone() != p1) -  { -    p1->prevClone()->setNextClone(p2); -    p2->setPrevClone(p1->prevClone()); -  } -  else   -    p2->setPrevClone(p2); -   -  if(p1->nextClone() != p1) -  { -    p1->nextClone()->setPrevClone(p2); -    p2->setNextClone(p1->nextClone()); -  } -  else -    p2->setNextClone(p2); -   -  // Isolate the replaced part. -  p1->setNextClone(p1); -  p1->setPrevClone(p1); +	int n=1; +	 +	for(const Part* it = this->_nextClone; it!=this; it=it->_nextClone) +		n++; +	 +	return n;  } + +// FIXME FINDMICHJETZT TODO: weg damit! +  //---------------------------------------------------------  //   unchainTrackParts  //--------------------------------------------------------- -void unchainTrackParts(Track* t, bool decRefCount) +void unchainTrackParts(Track* t)  {    PartList* pl = t->parts();    for(iPart ip = pl->begin(); ip != pl->end(); ++ip) -  { -    Part* p = ip->second; -    chainCheckErr(p); -     -    // Do we want to decrease the reference count? -    if(decRefCount) -      p->events()->incARef(-1); -       -    // Unchain the part. -    p->prevClone()->setNextClone(p->nextClone()); -    p->nextClone()->setPrevClone(p->prevClone()); -     -    // Isolate the part. -    p->setPrevClone(p); -    p->setNextClone(p); -  } +    ip->second->unchainClone();  }  //---------------------------------------------------------  //   chainTrackParts  //--------------------------------------------------------- -void chainTrackParts(Track* t, bool incRefCount) +void chainTrackParts(Track* t)  {    PartList* pl = t->parts(); -  for(iPart ip = pl->begin(); ip != pl->end(); ++ip) -  { -    Part* p = ip->second; -    chainCheckErr(p); -     -    // Do we want to increase the reference count? -    if(incRefCount) -      p->events()->incARef(1); -       -    Part* p1 = 0; -     -    // Look for a part with the same event list, that we can chain to. -    // It's faster if track type is known... -     -    if(!t || (t && t->isMidiTrack())) -    { -      MidiTrack* mt = 0; -      MidiTrackList* mtl = MusEGlobal::song->midis(); -      for(ciMidiTrack imt = mtl->begin(); imt != mtl->end(); ++imt) -      { -        mt = *imt; -        const PartList* pl = mt->cparts(); -        for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) -        { -          if(ip->second != p && ip->second->cevents() == p->cevents()) -          { -            p1 = ip->second; -            break; -          } -        } -        // If a suitable part was found on a different track, we're done. We will chain to it. -        // Otherwise keep looking for parts on another track. If no others found, then we -        //  chain to any suitable part which was found on the same given track t. -        if(p1 && mt != t) -          break; -      } -    }   -    if((!p1 && !t) || (t && t->type() == Track::WAVE)) -    { -      MusECore::WaveTrack* wt = 0; -      MusECore::WaveTrackList* wtl = MusEGlobal::song->waves(); -      for(MusECore::ciWaveTrack iwt = wtl->begin(); iwt != wtl->end(); ++iwt) -      { -        wt = *iwt; -        const PartList* pl = wt->cparts(); -        for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) -        { -          if(ip->second != p && ip->second->cevents() == p->cevents()) -          { -            p1 = ip->second; -            break; -          } -        } -        if(p1 && wt != t) -          break; -      } -    } -     -    // No part found with same event list? Done. -    if(!p1) -      continue; -       -    // Make sure the part to be chained is unchained first. -    p->prevClone()->setNextClone(p->nextClone()); -    p->nextClone()->setPrevClone(p->prevClone()); -     -    // Link the part to be chained. -    p->setPrevClone(p1); -    p->setNextClone(p1->nextClone()); -     -    // Re-link the existing part. -    p1->nextClone()->setPrevClone(p); -    p1->setNextClone(p); -  } +  for(riPart ip = pl->rbegin(); ip != pl->rend(); ++ip) // walk through in opposite direction than we unchained them. +    ip->second->rechainClone();  }  //--------------------------------------------------------- @@ -372,8 +154,6 @@ void addPortCtrlEvents(Event& event, Part* part, bool doClones)  {    // Traverse and process the clone chain ring until we arrive at the same part again.    // The loop is a safety net. -  // Update: Due to the varying calls, and order of, incARefcount, (msg)ChangePart, replaceClone, and remove/addPortCtrlEvents, -  //  we can not rely on the reference count as a safety net in these routines. We will just have to trust the clone chain.    Part* p = part;     while(1)    { @@ -434,8 +214,6 @@ void addPortCtrlEvents(Part* part, bool doClones)  {    // Traverse and process the clone chain ring until we arrive at the same part again.    // The loop is a safety net. -  // Update: Due to the varying calls, and order of, incARefcount, (msg)ChangePart, replaceClone, and remove/addPortCtrlEvents, -  //  we can not rely on the reference count as a safety net in these routines. We will just have to trust the clone chain.    Part* p = part;     while(1)    { @@ -445,9 +223,8 @@ void addPortCtrlEvents(Part* part, bool doClones)        MidiTrack* mt = (MidiTrack*)t;        MidiPort* mp = &MusEGlobal::midiPorts[mt->outPort()];        int ch = mt->outChannel(); -      const EventList* el = p->cevents();        unsigned len = p->lenTick(); -      for(ciEvent ie = el->begin(); ie != el->end(); ++ie) +      for(ciEvent ie = p->events().begin(); ie != p->events().end(); ++ie)        {          const Event& ev = ie->second;          // Added by T356. Do not add events which are past the end of the part. @@ -499,8 +276,6 @@ void removePortCtrlEvents(Event& event, Part* part, bool doClones)  {    // Traverse and process the clone chain ring until we arrive at the same part again.    // The loop is a safety net. -  // Update: Due to the varying calls, and order of, incARefcount, (msg)ChangePart, replaceClone, and remove/addPortCtrlEvents, -  //  we can not rely on the reference count as a safety net in these routines. We will just have to trust the clone chain.    Part* p = part;     while(1)    { @@ -555,8 +330,6 @@ void removePortCtrlEvents(Part* part, bool doClones)  {    // Traverse and process the clone chain ring until we arrive at the same part again.    // The loop is a safety net. -  // Update: Due to the varying calls, and order of, incARefcount, (msg)ChangePart, replaceClone, and remove/addPortCtrlEvents, -  //  we can not rely on the reference count as a safety net in these routines. We will just have to trust the clone chain.    Part* p = part;     while(1)    { @@ -566,16 +339,9 @@ void removePortCtrlEvents(Part* part, bool doClones)        MidiTrack* mt = (MidiTrack*)t;        MidiPort* mp = &MusEGlobal::midiPorts[mt->outPort()];        int ch = mt->outChannel(); -      const EventList* el = p->cevents(); -      //unsigned len = p->lenTick(); -      for(ciEvent ie = el->begin(); ie != el->end(); ++ie) +      for(ciEvent ie = p->events().begin(); ie != p->events().end(); ++ie)        {          const Event& ev = ie->second; -        // Added by T356. Do not remove events which are past the end of the part. DELETETHIS 5 -        // No, actually, do remove ALL of them belonging to the part. -        // Just in case there are stray values left after the part end. -        //if(ev.tick() >= len) -        //  break;          if(ev.type() == Controller)          { @@ -620,17 +386,18 @@ void removePortCtrlEvents(Part* part, bool doClones)  iEvent Part::addEvent(Event& p)        { -      return _events->add(p); +      assert(!hasClones()); +      return _events.add(p);        }  //---------------------------------------------------------  //   index  //--------------------------------------------------------- -int PartList::index(Part* part) +int PartList::index(const Part* part) const        {        int index = 0; -      for (iPart i = begin(); i != end(); ++i, ++index) +      for (ciPart i = begin(); i != end(); ++i, ++index)              if (i->second == part) {                    return index;                    } @@ -652,65 +419,81 @@ Part* PartList::find(int idx)        return 0;        } -//--------------------------------------------------------- -//   Part -//--------------------------------------------------------- - -Part::Part(const Part& p) : PosLen(p) -{ -  _sn=p._sn; -  _name=p._name; -  _selected=p._selected; -  _mute=p._mute; -  _colorIndex=p._colorIndex; -  _hiddenEvents=p._hiddenEvents; -  _track=p._track; -  _events=p._events; -  _prevClone=p._prevClone; -  _nextClone=p._nextClone; -   -  _events->incRef(1); -} -  Part::Part(Track* t)        {        _hiddenEvents = NoEventsHidden;        _prevClone = this;        _nextClone = this; -      setSn(newSn()); +      _backupClone = NULL; +      _sn = newSn(); +      _clonemaster_sn = _sn;        _track      = t;        _selected   = false;        _mute       = false;        _colorIndex = 0; -      _events     = new EventList; -      _events->incRef(1); -      _events->incARef(1);        } -Part::Part(Track* t, EventList* ev) -      { -      _hiddenEvents = NoEventsHidden; -      _prevClone = this; -      _nextClone = this; -      setSn(newSn()); -      _track      = t; -      _selected   = false; -      _mute       = false; -      _colorIndex = 0; -      _events     = ev; -      _events->incRef(1); -      _events->incARef(1); -      } +WavePart* WavePart::duplicateEmpty() const +{ +	WavePart* part = new WavePart((WaveTrack*)this->_track); +	part->setName(name()); +	part->setColorIndex(colorIndex()); + +	*(PosLen*)part = *(PosLen*)this; +	part->setMute(mute()); +	 +	return part; +} -//--------------------------------------------------------- -//   MidiPart -//   copy constructor -//--------------------------------------------------------- +WavePart* WavePart::duplicate() const +{ +	return (WavePart*)Part::duplicate(); +} -MidiPart::MidiPart(const MidiPart& p) : Part(p) +WavePart* WavePart::createNewClone() const  { -  _prevClone = this; -  _nextClone = this; +	return (WavePart*)Part::createNewClone(); +} + +MidiPart* MidiPart::duplicateEmpty() const +{ +	MidiPart* part = new MidiPart((MidiTrack*)this->_track); +	part->setName(name()); +	part->setColorIndex(colorIndex()); + +	*(PosLen*)part = *(PosLen*)this; +	part->setMute(mute()); +	 +	return part; +} + +MidiPart* MidiPart::duplicate() const +{ +	return (MidiPart*)Part::duplicate(); +} + +MidiPart* MidiPart::createNewClone() const +{ +	return (MidiPart*)Part::createNewClone(); +} + + +Part* Part::createNewClone() const +{ +	Part* clone = duplicate(); +	clone->_backupClone=const_cast<Part*>(this); +	return clone; +} + +Part* Part::duplicate() const +{ +	Part* dup = duplicateEmpty(); + +	// copy the eventlist; duplicate each Event(Ptr!). +	for (MusECore::ciEvent i = _events.begin(); i != _events.end(); ++i) +		dup->_events.add(i->second.clone()); + +	return dup;  } @@ -724,42 +507,21 @@ WavePart::WavePart(WaveTrack* t)        setType(FRAMES);        } -WavePart::WavePart(WaveTrack* t, EventList* ev) -   : Part(t, ev) -      { -      setType(FRAMES); -      } - -//--------------------------------------------------------- -//   WavePart -//   copy constructor -//--------------------------------------------------------- - -WavePart::WavePart(const WavePart& p) : Part(p) -{ -  _prevClone = this; -  _nextClone = this; -} -  //---------------------------------------------------------  //   Part  //---------------------------------------------------------  Part::~Part() -      { +{        if (_prevClone!=this || _nextClone!=this)        {          if (MusEGlobal::debugMsg) {              fprintf(stderr, "Part isn't unchained in ~Part()! Unchaining now...\n");          } -        unchainClone(this); -      } -         -      _events->incRef(-1); -      if (_events->refCount() <= 0) -            delete _events; -      } +        unchainClone(); +      }   +}  //--------------------------------------------------------- @@ -852,55 +614,24 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len, bool doClo        switch(track->type()) {              case Track::WAVE:                    { -                  MusECore::WavePart* nPart = new MusECore::WavePart(*(MusECore::WavePart*)oPart); -                  EventList* el = nPart->events(); -                  unsigned new_partlength = MusEGlobal::tempomap.deltaTick2frame(oPart->tick(), oPart->tick() + len); - -                  // If new nr of frames is less than previous what can happen is: -                  // -   0 or more events are beginning after the new final position. Those are removed from the part -                  // -   The last event begins before new final position and ends after it. If so, it will be resized to end at new part length -                  if (new_partlength < oPart->lenFrame()) { -                        Undo operations; - -                        for (iEvent i = el->begin(); i != el->end(); i++) { -                              Event e = i->second; -                              unsigned event_startframe = e.frame(); -                              unsigned event_endframe = event_startframe + e.lenFrame(); -                              if (event_endframe < new_partlength) -                                    continue; -                              } -                        nPart->setLenFrame(new_partlength); -                        // Do not do port controller values and clone parts.  -                        operations.push_back(UndoOp(UndoOp::ModifyPart, oPart, nPart, false, false)); - -                        MusEGlobal::song->applyOperationGroup(operations); -                        } -                  // If the part is expanded there can be no additional events beginning after the previous final position -                  // since those are removed if the part has been shrunk at some time (see above) -                  // The only thing we need to check is the final event: If it has data after the previous final position, -                  // we'll expand that event -                  else { -                        Undo operations; -                        if(!el->empty()) -                        { -                          iEvent i = el->end(); -                          i--; -                          Event last = i->second; -                          MusECore::SndFileR file = last.sndFile(); -                          if (file.isNull()) -                                return; -                          Event newEvent = last.clone(); -                          // Do not do port controller values and clone parts.  -                          operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, last, nPart, false, false)); -                        }   -                         -                        nPart->setLenFrame(new_partlength); -                        // Do not do port controller values and clone parts.  -                        operations.push_back(UndoOp(UndoOp::ModifyPart, oPart, nPart, false, false)); -                        MusEGlobal::song->applyOperationGroup(operations); -                        } -                  } +                  Undo operations; +									 +									unsigned orig_len=oPart->lenFrame(); +									WavePart* part_it=(WavePart*)oPart; +									do +									{ +										if (part_it->lenFrame()==orig_len) +										{ +											// Do port controller values but not clone parts.  +											operations.push_back(UndoOp(UndoOp::ModifyPartLengthFrames, part_it, part_it->lenFrame(), len, true, false)); +										} +										 +										part_it=(WavePart*)part_it->nextClone(); +									} while (doClones && (part_it != (WavePart*)oPart)); +                   +                  MusEGlobal::song->applyOperationGroup(operations);                    break; +                  }              case Track::MIDI:              case Track::DRUM:              case Track::NEW_DRUM: @@ -913,10 +644,8 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len, bool doClo  									{  										if (part_it->lenTick()==orig_len)  										{ -											MidiPart* newPart = new MidiPart(*part_it); -											newPart->setLenTick(len);  											// Do port controller values but not clone parts.  -											operations.push_back(UndoOp(UndoOp::ModifyPart, part_it, newPart, true, false)); +											operations.push_back(UndoOp(UndoOp::ModifyPartLength, part_it, part_it->lenTick(), len, true, false));  										}  										part_it=(MidiPart*)part_it->nextClone(); @@ -936,23 +665,23 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len, bool doClo  //    create two new parts p1 and p2  //--------------------------------------------------------- -void Track::splitPart(Part* part, int tickpos, Part*& p1, Part*& p2) +void Part::splitPart(int tickpos, Part*& p1, Part*& p2) const        {        int l1 = 0;       // len of first new part (ticks or samples)        int l2 = 0;       // len of second new part        int samplepos = MusEGlobal::tempomap.tick2frame(tickpos); -      switch (type()) { -            case WAVE: -                  l1 = samplepos - part->frame(); -                  l2 = part->lenFrame() - l1; +      switch (track()->type()) { +          case Track::WAVE: +                  l1 = samplepos - frame(); +                  l2 = lenFrame() - l1;                    break; -            case MIDI: -            case DRUM: -            case NEW_DRUM: -                  l1 = tickpos - part->tick(); -                  l2 = part->lenTick() - l1; +          case Track::MIDI: +          case Track::DRUM: +          case Track::NEW_DRUM: +                  l1 = tickpos - tick(); +                  l2 = lenTick() - l1;                    break;              default:                    return; @@ -961,20 +690,18 @@ void Track::splitPart(Part* part, int tickpos, Part*& p1, Part*& p2)        if (l1 <= 0 || l2 <= 0)              return; -      p1 = newPart(part);     // new left part -      p2 = newPart(part);     // new right part +      p1 = this->duplicateEmpty();   // new left part +      p2 = this->duplicateEmpty();   // new right part -      // Added by Tim. p3.3.6 -       -      switch (type()) { -            case WAVE: +      switch (track()->type()) { +          case Track::WAVE:                    p1->setLenFrame(l1);                    p2->setFrame(samplepos);                    p2->setLenFrame(l2);                    break; -            case MIDI: -            case DRUM: -            case NEW_DRUM: +          case Track::MIDI: +          case Track::DRUM: +          case Track::NEW_DRUM:                    p1->setLenTick(l1);                    p2->setTick(tickpos);                    p2->setLenTick(l2); @@ -983,158 +710,41 @@ void Track::splitPart(Part* part, int tickpos, Part*& p1, Part*& p2)                    break;              } -      p2->setSn(p2->newSn()); - -      EventList* se  = part->events(); -      EventList* de1 = p1->events(); -      EventList* de2 = p2->events(); - -      if (type() == WAVE) { -            int ps   = part->frame(); +      if (track()->type() == Track::WAVE) { +            int ps   = this->frame();              int d1p1 = p1->frame();              int d2p1 = p1->endFrame();              int d1p2 = p2->frame();              int d2p2 = p2->endFrame(); -            for (iEvent ie = se->begin(); ie != se->end(); ++ie) { -                  Event event = ie->second; +            for (ciEvent ie = _events.begin(); ie != _events.end(); ++ie) { +                  const Event& event = ie->second;                    int s1 = event.frame() + ps;                    int s2 = event.endFrame() + ps;                    if ((s2 > d1p1) && (s1 < d2p1)) {                          Event si = event.mid(d1p1 - ps, d2p1 - ps); -                        de1->add(si); +                        p1->_events.add(si);                          }                    if ((s2 > d1p2) && (s1 < d2p2)) {                          Event si = event.mid(d1p2 - ps, d2p2 - ps); -                        de2->add(si); +                        p2->_events.add(si);                          }                    }              }        else { -            for (iEvent ie = se->begin(); ie != se->end(); ++ie) { +            for (ciEvent ie = _events.begin(); ie != _events.end(); ++ie) {                    Event event = ie->second.clone();                    int t = event.tick();                    if (t >= l1) {                          event.move(-l1); -                        de2->add(event); +                        p2->_events.add(event);                          }                    else -                        de1->add(event); +                        p1->_events.add(event);                    }              }        } -//--------------------------------------------------------- -//   cmdSplitPart -//--------------------------------------------------------- - -void Song::cmdSplitPart(Track* track, Part* part, int tick) -      { -      int l1 = tick - part->tick(); -      int l2 = part->lenTick() - l1; -      if (l1 <= 0 || l2 <= 0) -            return; -      Part* p1; -      Part* p2; -      track->splitPart(part, tick, p1, p2); -       -      //MusEGlobal::song->informAboutNewParts(part, p1); // is unneccessary because of ChangePart below -      MusEGlobal::song->informAboutNewParts(part, p2); - -      startUndo(); -      // Indicate no undo, and do port controller values but not clone parts.  -      MusEGlobal::audio->msgChangePart(part, p1, false, true, false); -      MusEGlobal::audio->msgAddPart(p2, false); -      endUndo(SC_TRACK_MODIFIED | SC_PART_MODIFIED | SC_PART_INSERTED); -      } - -//--------------------------------------------------------- -//   changePart -//--------------------------------------------------------- - -void Song::changePart(Part* oPart, Part* nPart) -      { -      nPart->setSn(oPart->sn()); - -      Track* oTrack = oPart->track(); -      Track* nTrack = nPart->track(); - -      oTrack->parts()->remove(oPart); -      nTrack->parts()->add(nPart); -       -       -      // Added by T356.  -      // adjust song len: -      unsigned epos = nPart->tick() + nPart->lenTick(); -      if (epos > len()) -            _len = epos; -       -      } - -//--------------------------------------------------------- -//   cmdGluePart -//--------------------------------------------------------- - -void Song::cmdGluePart(Track* track, Part* oPart) -      { -      // p3.3.54 -      if(track->type() != Track::WAVE && !track->isMidiTrack()) -        return; -       -      PartList* pl   = track->parts(); -      Part* nextPart = 0; - -      for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { -            if (ip->second == oPart) { -                  ++ip; -                  if (ip == pl->end()) -                        return; -                  nextPart = ip->second; -                  break; -                  } -            } - -      Part* nPart = track->newPart(oPart); -      nPart->setLenTick(nextPart->tick() + nextPart->lenTick() - oPart->tick()); - -      // populate nPart with Events from oPart and nextPart - -      EventList* sl1 = oPart->events(); -      EventList* dl  = nPart->events(); - -      for (iEvent ie = sl1->begin(); ie != sl1->end(); ++ie) -            dl->add(ie->second); - -      EventList* sl2 = nextPart->events(); -       -      if(track->type() == Track::WAVE) -      { -        int frameOffset = nextPart->frame() - oPart->frame(); -        for (iEvent ie = sl2->begin(); ie != sl2->end(); ++ie)  -        { -              Event event = ie->second.clone(); -              event.setFrame(event.frame() + frameOffset); -              dl->add(event); -        } -      } -      else -      if(track->isMidiTrack()) -      { -        int tickOffset  = nextPart->tick() - oPart->tick(); -        for (iEvent ie = sl2->begin(); ie != sl2->end(); ++ie)  -        { -              Event event = ie->second.clone(); -              event.setTick(event.tick() + tickOffset); -              dl->add(event); -        } -      } -             -      startUndo(); -      MusEGlobal::audio->msgRemovePart(nextPart, false); -      // Indicate no undo, and do port controller values but not clone parts.  -      MusEGlobal::audio->msgChangePart(oPart, nPart, false, true, false); -      endUndo(SC_PART_MODIFIED | SC_PART_REMOVED); -      }  //---------------------------------------------------------  //   dump @@ -1169,21 +779,6 @@ void MidiPart::dump(int n) const        }  //--------------------------------------------------------- -//   clone -//--------------------------------------------------------- - -MidiPart* MidiPart::clone() const -      { -      return new MidiPart(*this); -      } - - -WavePart* WavePart::clone() const -      { -      return new WavePart(*this); -      } - -//---------------------------------------------------------  //   hasHiddenEvents  //   Returns combination of HiddenEventsType enum.  //--------------------------------------------------------- @@ -1193,7 +788,7 @@ int MidiPart::hasHiddenEvents()    unsigned len = lenTick();    // TODO: For now, we don't support events before the left border, only events past the right border. -  for(iEvent ev=events()->begin(); ev!=events()->end(); ev++) +  for(ciEvent ev=_events.begin(); ev!=_events.end(); ev++)    {      if(ev->second.endTick() > len)      { @@ -1215,7 +810,7 @@ int WavePart::hasHiddenEvents()    unsigned len = lenFrame();    // TODO: For now, we don't support events before the left border, only events past the right border. -  for(iEvent ev=events()->begin(); ev!=events()->end(); ev++) +  for(ciEvent ev=_events.begin(); ev!=_events.end(); ev++)    {      if(ev->second.endFrame() > len)      { diff --git a/muse2/muse/part.h b/muse2/muse/part.h index 357ec1db..02056a2d 100644 --- a/muse2/muse/part.h +++ b/muse2/muse/part.h @@ -60,16 +60,13 @@ typedef CloneList::iterator iClone;  class Part : public PosLen {     public:        enum HiddenEventsType { NoEventsHidden = 0, LeftEventsHidden, RightEventsHidden }; -    -   // @@@@@@@@@@@ IMPORTANT @@@@@@@@@@@@ -   // @@ when adding member variables @@ -   // @@ here, don't forget to update @@ -   // @@ the copy-constructor!        @@ -   // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +       +      static Part* readFromXml(Xml&, Track*, bool doClone = false, bool toTrack = true);     private:        static int snGen;        int _sn; +      int _clonemaster_sn; // the serial number of some clone in the chain. every member of the chain has the same value here.        QString _name;        bool _selected; @@ -78,22 +75,24 @@ class Part : public PosLen {     protected:        Track* _track; -      EventList* _events; +      EventList _events;        Part* _prevClone;        Part* _nextClone; +      Part* _backupClone; // when a part gets removed, it's still there; and for undo-ing the remove, it must know about where it was clone-chained to.        int _hiddenEvents;   // Combination of HiddenEventsType. -                    +     public:        Part(Track*); -      Part(Track*, EventList*); -      Part(const Part& p);        virtual ~Part(); -      int sn()                         { return _sn; } -      void setSn(int n)                { _sn = n; } +      virtual Part* duplicate() const; +      virtual Part* duplicateEmpty() const = 0; +      virtual Part* createNewClone() const; // this does NOT chain clones yet. Chain is updated only when the part is really added! +      virtual void splitPart(int tickpos, Part*& p1, Part*& p2) const; +       +      int clonemaster_sn() const       { return _clonemaster_sn; } +      int sn() const                   { return _sn; }        int newSn()                      { return snGen++; } -      virtual Part* clone() const = 0; -        const QString& name() const      { return _name; }        void setName(const QString& s)   { _name = s; }        bool selected() const            { return _selected; } @@ -102,23 +101,26 @@ class Part : public PosLen {        void setMute(bool b)             { _mute = b; }        Track* track() const             { return _track; }        void setTrack(Track*t)           { _track = t; } -      EventList* events() const        { return _events; } -      const EventList* cevents() const { return _events; } +      const EventList& events() const  { return _events; } +      EventList& nonconst_events()     { return _events; }        int colorIndex() const           { return _colorIndex; }        void setColorIndex(int idx)      { _colorIndex = idx; } -      Part* prevClone()                { return _prevClone; } -      Part* nextClone()                { return _nextClone; } -      void setPrevClone(Part* p)       { _prevClone = p; } -      void setNextClone(Part* p)       { _nextClone = p; } +      bool isCloneOf(const Part*) const; +      bool hasClones() const           { return _prevClone!=this || _nextClone!=this; } +      int nClones() const; +      Part* prevClone() const          { return _prevClone; } // FINDMICHJETZT make it const Part*! +      Part* nextClone() const          { return _nextClone; } +      Part* backupClone() const        { return _backupClone; } +       +      void unchainClone(); +      void chainClone(Part* p); // *this is made a sibling of p! p is not touched (except for its clone-chain), whereas this->events will get altered +      void rechainClone(); // re-chains the part to the same clone chain it was unchained before        // Returns combination of HiddenEventsType enum. -      virtual int hasHiddenEvents() = 0; -      // If repeated calls to hasHiddenEvents() are desired, then to avoid re-iteration of the event list,  -      //  call this after hasHiddenEvents(). -      int cachedHasHiddenEvents() const { return _hiddenEvents; } +      virtual int hasHiddenEvents() const { return _hiddenEvents; } -      iEvent addEvent(Event& p); +      iEvent addEvent(Event& p); // DEPRECATED. requires the part to be NOT a clone. FIXME remove!        virtual void write(int, Xml&, bool isCopy = false, bool forceWavePaths = false) const; @@ -134,10 +136,12 @@ class MidiPart : public Part {     public:        MidiPart(MidiTrack* t) : Part((Track*)t) {} -      MidiPart(MidiTrack* t, EventList* ev) : Part((Track*)t, ev) {} -      MidiPart(const MidiPart& p);        virtual ~MidiPart() {} -      virtual MidiPart* clone() const; +      virtual MidiPart* duplicate() const; +      virtual MidiPart* duplicateEmpty() const; +      virtual MidiPart* createNewClone() const; + +              MidiTrack* track() const   { return (MidiTrack*)Part::track(); }        // Returns combination of HiddenEventsType enum.        int hasHiddenEvents(); @@ -154,13 +158,14 @@ class WavePart : public Part {        // p3.3.31        AudioConvertMap _converters; -       +     public:        WavePart(WaveTrack* t); -      WavePart(WaveTrack* t, EventList* ev); -      WavePart(const WavePart& p);        virtual ~WavePart() {} -      virtual WavePart* clone() const; +      virtual WavePart* duplicate() const; +      virtual WavePart* duplicateEmpty() const; +      virtual WavePart* createNewClone() const; +        WaveTrack* track() const   { return (WaveTrack*)Part::track(); }        // Returns combination of HiddenEventsType enum.        int hasHiddenEvents(); @@ -182,7 +187,7 @@ class PartList : public std::multimap<int, Part*, std::less<unsigned> > {        iPart findPart(unsigned tick);        iPart add(Part*);        void remove(Part* part); -      int index(Part*); +      int index(const Part*) const;        Part* find(int idx);        void clearDelete() {              for (iPart i = begin(); i != end(); ++i) @@ -191,18 +196,13 @@ class PartList : public std::multimap<int, Part*, std::less<unsigned> > {              }        }; -extern void chainClone(Part* p); -extern void chainClone(Part* p1, Part* p2); -extern void unchainClone(Part* p); -extern void replaceClone(Part* p1, Part* p2);  extern void chainCheckErr(Part* p); -extern void unchainTrackParts(Track* t, bool decRefCount); -extern void chainTrackParts(Track* t, bool incRefCount); +extern void unchainTrackParts(Track* t); +extern void chainTrackParts(Track* t);  extern void addPortCtrlEvents(Part* part, bool doClones);  extern void addPortCtrlEvents(Event& event, Part* part, bool doClones);  extern void removePortCtrlEvents(Part* part, bool doClones);  extern void removePortCtrlEvents(Event& event, Part* part, bool doClones); -extern Part* readXmlPart(Xml&, Track*, bool doClone = false, bool toTrack = true);  } // namespace MusECore diff --git a/muse2/muse/remote/pyapi.cpp b/muse2/muse/remote/pyapi.cpp index 7e03fa0e..8f5abe06 100644 --- a/muse2/muse/remote/pyapi.cpp +++ b/muse2/muse/remote/pyapi.cpp @@ -199,9 +199,9 @@ PyObject* getParts(PyObject*, PyObject* args)                    Py_DECREF(pstrtick2);                    // Pack midi events into list before wrapping it all up -                  EventList* events = mpart->events(); +                  const EventList& events = mpart->events();                    PyObject* pyevents = Py_BuildValue("[]"); -                  for (ciEvent e = events->begin(); e != events->end(); e++) { +                  for (ciEvent e = events.begin(); e != events.end(); e++) {                          PyObject* pyevent = PyDict_New(); // The event structure - a dictionary with keys 'type','tick','data'                          const Event& event = e->second; @@ -331,7 +331,7 @@ bool addPyPartEventsToMusePart(MidiPart* npart, PyObject* part)                    event.setC(data[2]);                    event.setTick(etick);                    event.setLenTick(elen); -                  npart->events()->add(event); +                  npart->nonconst_events().add(event);                    }              else                    printf("Unhandled event type from python: %s\n", type.c_str()); @@ -404,12 +404,12 @@ PyObject* modifyPart(PyObject*, PyObject* part)        npart->setLenTick(opart->lenTick());        npart->setSn(opart->sn()); -      for (iEvent e = opart->events()->begin(); e != opart->events()->end(); e++) { +      for (ciEvent e = opart->events().begin(); e != opart->events().end(); e++) {              Event& event = e->second;              if (event.type() == Note || event.type() == Controller)                     continue; -            npart->events()->add(event); +            npart->nonconst_events()->add(event);              }        addPyPartEventsToMusePart(npart, part); @@ -1131,9 +1131,7 @@ bool Song::event(QEvent* _e)                    break;                    }              case QPybridgeEvent::SONG_ADD_TRACK: { -                  MusECore::Undo operations; -                  MusEGlobal::song->addTrack(operations, (Track::TrackType)e->getP1());  // Add at end of list. -                  MusEGlobal::song->applyOperationGroup(operations); +                  MusEGlobal::song->addTrack((Track::TrackType)e->getP1());  // Add at end of list.                    break;                    }              case QPybridgeEvent::SONG_CHANGE_TRACKNAME: { diff --git a/muse2/muse/seqmsg.cpp b/muse2/muse/seqmsg.cpp index fcffc332..669aff9d 100644 --- a/muse2/muse/seqmsg.cpp +++ b/muse2/muse/seqmsg.cpp @@ -319,38 +319,6 @@ void Audio::msgSetRecord(AudioTrack* node, bool val)        sendMsg(&msg);        } -/* DELETETHIS 34 -//--------------------------------------------------------- -//   msgSetVolume -//--------------------------------------------------------- - -void Audio::msgSetVolume(AudioTrack* src, double val) -      { -      AudioMsg msg; -      msg.id    = AUDIO_VOL; -      msg.snode    = src; -      msg.dval  = val; -      sendMsg(&msg); -      //muse->arranger->controllerChanged(src); -      MusEGlobal::song->controllerChange(src); -      } - -//--------------------------------------------------------- -//   msgSetPan -//--------------------------------------------------------- - -void Audio::msgSetPan(AudioTrack* node, double val) -      { -      AudioMsg msg; -      msg.id    = AUDIO_PAN; -      msg.snode = node; -      msg.dval  = val; -      sendMsg(&msg); -      //muse->arranger->controllerChanged(node); -      MusEGlobal::song->controllerChange(node); -      } -*/ -  //---------------------------------------------------------  //   msgSetPrefader  //--------------------------------------------------------- @@ -492,26 +460,6 @@ void Audio::msgSetChannels(AudioTrack* node, int n)        sendMsg(&msg);        } -/* DELETETHIS 20 -//--------------------------------------------------------- -//   msgSetPluginCtrlVal -//--------------------------------------------------------- - -void Audio::msgSetPluginCtrlVal(AudioTrack* track, int param, double val) -{ -      AudioMsg msg; -       -      msg.id     = AUDIO_SET_PLUGIN_CTRL_VAL; -      msg.ival   = param; -      msg.dval   = val; -      //msg.plugin = plugin; -      msg.snode  = track; -      sendMsg(&msg); -      //muse->arranger->controllerChanged(track); -      MusEGlobal::song->controllerChange(track); -} -*/ -  //---------------------------------------------------------  //   msgSwapControllerIDX  //--------------------------------------------------------- @@ -646,18 +594,6 @@ void Audio::msgSetSolo(Track* track, bool val)        sendMsg(&msg);  } -//--------------------------------------------------------- -//   msgSetSegSize -//--------------------------------------------------------- - -void Audio::msgSetSegSize(int bs, int sr) -      { -      AudioMsg msg; -      msg.id = AUDIO_SET_SEG_SIZE; -      msg.ival = bs; -      msg.iival = sr; -      sendMsg(&msg); -      }  //---------------------------------------------------------  //   msgSeek @@ -670,26 +606,37 @@ void Audio::msgSeek(const Pos& pos)        }  //--------------------------------------------------------- -//   msgUndo +//   msgExecuteOperationGroup  //--------------------------------------------------------- -void Audio::msgUndo() -      { -      AudioMsg msg; -      msg.id = SEQM_UNDO; -      sendMsg(&msg); -      } +void Audio::msgExecuteOperationGroup(Undo& operations) +{ +	MusEGlobal::song->executeOperationGroup1(operations); +	 +	AudioMsg msg; +	msg.id = SEQM_EXECUTE_OPERATION_GROUP; +	msg.operations=&operations; +	sendMsg(&msg); + +	MusEGlobal::song->executeOperationGroup3(operations); +}  //--------------------------------------------------------- -//   msgRedo +//   msgRevertOperationGroup  //--------------------------------------------------------- -void Audio::msgRedo() -      { -      AudioMsg msg; -      msg.id = SEQM_REDO; -      sendMsg(&msg); -      } +void Audio::msgRevertOperationGroup(Undo& operations) +{ +	MusEGlobal::song->revertOperationGroup1(operations); +	 +	 +	AudioMsg msg; +	msg.id = SEQM_REVERT_OPERATION_GROUP; +	msg.operations=&operations; +	sendMsg(&msg); + +	MusEGlobal::song->revertOperationGroup3(operations); +}  //---------------------------------------------------------  //   msgPlay @@ -714,56 +661,7 @@ void Audio::msgPlay(bool val)              }        } -/* DELETETHIS 31 -//--------------------------------------------------------- -//   msgShowInstrumentGui -//--------------------------------------------------------- - -void Audio::msgShowInstrumentGui(MidiInstrument* instr, bool val) -      { -      instr->showGui(val); -      // No need for this - it called msgUpdatePollFd which has nothing -      //  to do with showing a gui. -      //AudioMsg msg; -      //msg.id = MIDI_SHOW_INSTR_GUI; -      //msg.p1 = instr; -      //msg.a  = val; -      //sendMessage(&msg, false); -      } - -//--------------------------------------------------------- -//   msgShowInstrumentNativeGui -//--------------------------------------------------------- - -void Audio::msgShowInstrumentNativeGui(MidiInstrument* instr, bool val) -      { -      instr->showNativeGui(val); -      //AudioMsg msg; -      //msg.id = MIDI_SHOW_INSTR_NATIVE_GUI; -      //msg.p1 = instr; -      //msg.a  = val; -      //sendMessage(&msg, false); -      } -*/ - -//--------------------------------------------------------- -//   msgAddTrack -//--------------------------------------------------------- -void Song::msgInsertTrack(Track* track, int idx, bool doUndoFlag) -      { -      AudioMsg msg; -      msg.id = SEQM_ADD_TRACK; -      msg.track = track; -      msg.ival  = idx; -      if (doUndoFlag) { -            MusEGlobal::song->startUndo(); -            addUndo(UndoOp(UndoOp::AddTrack, idx, track)); -            } -      MusEGlobal::audio->sendMsg(&msg); -      if (doUndoFlag) -            endUndo(SC_TRACK_INSERTED); -      }  //---------------------------------------------------------  //   msgRemoveTrack @@ -771,10 +669,7 @@ void Song::msgInsertTrack(Track* track, int idx, bool doUndoFlag)  void Audio::msgRemoveTrack(Track* track, bool doUndoFlag)        { -      AudioMsg msg; -      msg.id = SEQM_REMOVE_TRACK; -      msg.track = track; -      sendMessage(&msg, doUndoFlag); +      MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeleteTrack, MusEGlobal::song->tracks()->index(track), track), doUndoFlag);        }  //--------------------------------------------------------- @@ -794,9 +689,7 @@ void Audio::msgRemoveTracks()            Track* tr = *t;            if (tr->selected())             { -            MusEGlobal::song->removeTrack1(tr); -            msgRemoveTrack(tr, false); -            MusEGlobal::song->removeTrack3(tr); +            MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeleteTrack, MusEGlobal::song->tracks()->index(tr), tr), false);              loop = true;              break;            } @@ -834,23 +727,6 @@ void Audio::msgRemoveTracks()  } -/*    DELETETHIS 18 -//--------------------------------------------------------- -//   msgChangeTrack -//    oldTrack - copy of the original track befor modification -//    newTrack - modified original track -//--------------------------------------------------------- - -void Audio::msgChangeTrack(Track* oldTrack, Track* newTrack, bool doUndoFlag)    -      { -      AudioMsg msg; -      msg.id = SEQM_CHANGE_TRACK; -      msg.p1 = oldTrack; -      msg.p2 = newTrack; -      sendMessage(&msg, doUndoFlag); -      } -*/ -       //---------------------------------------------------------  //   msgMoveTrack  //    move track idx1 to slot idx2 @@ -863,11 +739,7 @@ void Audio::msgMoveTrack(int idx1, int idx2, bool doUndoFlag)        int n = MusEGlobal::song->tracks()->size();        if (idx1 >= n || idx2 >= n)   // sanity check              return; -      AudioMsg msg; -      msg.id = SEQM_MOVE_TRACK; -      msg.a = idx1; -      msg.b = idx2; -      sendMessage(&msg, doUndoFlag); +      MusEGlobal::song->applyOperation(UndoOp(UndoOp::SwapTrack, idx1, idx2), doUndoFlag);        }  //--------------------------------------------------------- @@ -876,10 +748,7 @@ void Audio::msgMoveTrack(int idx1, int idx2, bool doUndoFlag)  void Audio::msgAddPart(Part* part, bool doUndoFlag)        { -      AudioMsg msg; -      msg.id = SEQM_ADD_PART; -      msg.p1 = part; -      sendMessage(&msg, doUndoFlag); +      MusEGlobal::song->applyOperation(UndoOp(UndoOp::AddPart, part), doUndoFlag);        }  //--------------------------------------------------------- @@ -888,54 +757,9 @@ void Audio::msgAddPart(Part* part, bool doUndoFlag)  void Audio::msgRemovePart(Part* part, bool doUndoFlag)        { -      AudioMsg msg; -      msg.id = SEQM_REMOVE_PART; -      msg.p1 = part; -      sendMessage(&msg, doUndoFlag); -      } - -//--------------------------------------------------------- -//   msgRemoveParts -//    remove selected parts; return true if any part was -//    removed -//--------------------------------------------------------- - -bool Song::msgRemoveParts() -      { -      Undo operations; -      bool partSelected = false; - -            TrackList* tl = MusEGlobal::song->tracks(); - -            for (iTrack it = tl->begin(); it != tl->end(); ++it) { -                  PartList* pl = (*it)->parts(); -                  for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { -                        if (ip->second->selected()) { -                              operations.push_back(UndoOp(UndoOp::DeletePart,ip->second)); -                              partSelected = true; -                              } -                        } -                  } -       -      MusEGlobal::song->applyOperationGroup(operations); -       -      return partSelected; +      MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeletePart, part), doUndoFlag);        } -//--------------------------------------------------------- -//   msgChangePart -//--------------------------------------------------------- - -void Audio::msgChangePart(Part* oldPart, Part* newPart, bool doUndoFlag, bool doCtrls, bool doClones) -      { -      AudioMsg msg; -      msg.id = SEQM_CHANGE_PART; -      msg.p1 = oldPart; -      msg.p2 = newPart; -      msg.a = doCtrls; -      msg.b = doClones; -      sendMessage(&msg, doUndoFlag); -      }  //---------------------------------------------------------  //   msgAddEvent @@ -943,13 +767,7 @@ void Audio::msgChangePart(Part* oldPart, Part* newPart, bool doUndoFlag, bool do  void Audio::msgAddEvent(Event& event, Part* part, bool doUndoFlag, bool doCtrls, bool doClones)        { -      AudioMsg msg; -      msg.id = SEQM_ADD_EVENT; -      msg.ev1 = event; -      msg.p2 = part; -      msg.a = doCtrls; -      msg.b = doClones; -      sendMessage(&msg, doUndoFlag); +      MusEGlobal::song->applyOperation(UndoOp(UndoOp::AddEvent, event,part, doCtrls, doClones), doUndoFlag);        }  //--------------------------------------------------------- @@ -958,13 +776,7 @@ void Audio::msgAddEvent(Event& event, Part* part, bool doUndoFlag, bool doCtrls,  void Audio::msgDeleteEvent(Event& event, Part* part, bool doUndoFlag, bool doCtrls, bool doClones)        { -      AudioMsg msg; -      msg.id = SEQM_REMOVE_EVENT; -      msg.ev1 = event; -      msg.p2 = part; -      msg.a = doCtrls; -      msg.b = doClones; -      sendMessage(&msg, doUndoFlag); +      MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeleteEvent, event,part, doCtrls, doClones), doUndoFlag);        }  //--------------------------------------------------------- @@ -973,14 +785,7 @@ void Audio::msgDeleteEvent(Event& event, Part* part, bool doUndoFlag, bool doCtr  void Audio::msgChangeEvent(Event& oe, Event& ne, Part* part, bool doUndoFlag, bool doCtrls, bool doClones)        { -      AudioMsg msg; -      msg.id = SEQM_CHANGE_EVENT; -      msg.ev1 = oe; -      msg.ev2 = ne; -      msg.p3 = part; -      msg.a = doCtrls; -      msg.b = doClones; -      sendMessage(&msg, doUndoFlag); +      MusEGlobal::song->applyOperation(UndoOp(UndoOp::ModifyEvent, ne,oe, part, doCtrls, doClones), doUndoFlag);        }  //--------------------------------------------------------- @@ -989,11 +794,7 @@ void Audio::msgChangeEvent(Event& oe, Event& ne, Part* part, bool doUndoFlag, bo  void Audio::msgAddTempo(int tick, int tempo, bool doUndoFlag)        { -      AudioMsg msg; -      msg.id = SEQM_ADD_TEMPO; -      msg.a = tick; -      msg.b = tempo; -      sendMessage(&msg, doUndoFlag); +      MusEGlobal::song->applyOperation(UndoOp(UndoOp::AddTempo, tick, tempo), doUndoFlag);        }  //--------------------------------------------------------- @@ -1027,11 +828,7 @@ void Audio::msgSetGlobalTempo(int val)  void Audio::msgDeleteTempo(int tick, int tempo, bool doUndoFlag)        { -      AudioMsg msg; -      msg.id = SEQM_REMOVE_TEMPO; -      msg.a = tick; -      msg.b = tempo; -      sendMessage(&msg, doUndoFlag); +      MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeleteTempo, tick, tempo), doUndoFlag);        }  //--------------------------------------------------------- @@ -1090,16 +887,6 @@ void Audio::msgRemoveKey(int tick, int key, bool doUndoFlag)        sendMessage(&msg, doUndoFlag);        } -//--------------------------------------------------------- -//   msgScanAlsaMidiPorts -//--------------------------------------------------------- - -void Audio::msgScanAlsaMidiPorts() -      { -      AudioMsg msg; -      msg.id = SEQM_SCAN_ALSA_MIDI_PORTS; -      sendMessage(&msg, false); -      }  //---------------------------------------------------------  //   msgResetMidiDevices @@ -1285,32 +1072,6 @@ void Audio::msgSetHwCtrlStates(MidiPort* port, int ch, int ctrl, int val, int la        }  //--------------------------------------------------------- -//   msgSetTrackOutChannel -//--------------------------------------------------------- - -void Audio::msgSetTrackOutChannel(MidiTrack* track, int ch) -{ -      AudioMsg msg; -      msg.id = SEQM_SET_TRACK_OUT_CHAN; -      msg.p1 = track; -      msg.a = ch; -      sendMessage(&msg, false); -} - -//--------------------------------------------------------- -//   msgSetTrackOutPort -//--------------------------------------------------------- - -void Audio::msgSetTrackOutPort(MidiTrack* track, int port) -{ -      AudioMsg msg; -      msg.id = SEQM_SET_TRACK_OUT_PORT; -      msg.p1 = track; -      msg.a = port; -      sendMessage(&msg, false); -} - -//---------------------------------------------------------  //   msgSetTrackAutomationType  //--------------------------------------------------------- @@ -1324,34 +1085,6 @@ void Audio::msgSetTrackAutomationType(Track* track, int type)  }  //--------------------------------------------------------- -//   msgRemapPortDrumCtlEvents -//--------------------------------------------------------- - -void Audio::msgRemapPortDrumCtlEvents(int mapidx, int newnote, int newchan, int newport) -{ -      AudioMsg msg; -      msg.id = SEQM_REMAP_PORT_DRUM_CTL_EVS; -      msg.ival = mapidx; -      msg.a = newnote; -      msg.b = newchan; -      msg.c = newport; -      sendMessage(&msg, false); -} - -//--------------------------------------------------------- -//   msgChangeAllPortDrumCtlEvents -//--------------------------------------------------------- - -void Audio::msgChangeAllPortDrumCtrlEvents(bool add, bool drumonly) -{ -      AudioMsg msg; -      msg.id = SEQM_CHANGE_ALL_PORT_DRUM_CTL_EVS; -      msg.a = (int)add; -      msg.b = (int)drumonly; -      sendMessage(&msg, false); -} - -//---------------------------------------------------------  //   msgSetSendMetronome  //--------------------------------------------------------- diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp index d13f8398..926ba0ac 100644 --- a/muse2/muse/song.cpp +++ b/muse2/muse/song.cpp @@ -216,9 +216,7 @@ Track* Song::addNewTrack(QAction* action, Track* insertAt)        if((Track::TrackType)n >= Track::AUDIO_SOFTSYNTH)          return 0; -      Undo operations; -      Track* t = addTrack(operations, (Track::TrackType)n, insertAt); -      applyOperationGroup(operations); +      Track* t = addTrack((Track::TrackType)n, insertAt);        if (t->isVisible()) {          deselectTracks();          t->setSelected(true); @@ -236,7 +234,7 @@ Track* Song::addNewTrack(QAction* action, Track* insertAt)  //    If insertAt is valid, inserts before insertAt. Else at the end after all tracks.  //--------------------------------------------------------- -Track* Song::addTrack(Undo& /*operations*/, Track::TrackType type, Track* insertAt) +Track* Song::addTrack(Track::TrackType type, Track* insertAt)        {        Track* track = 0;        int lastAuxIdx = _auxs.size(); @@ -293,12 +291,9 @@ Track* Song::addTrack(Undo& /*operations*/, Track::TrackType type, Track* insert        int idx = insertAt ? _tracks.index(insertAt) : -1; -      insertTrack1(track, idx);         // this and the below are replaced -      msgInsertTrack(track, idx, true); // by the UndoOp-operation -      insertTrack3(track, idx); // does nothing -      // No, can't do this. insertTrack2 needs to be called now, not later, otherwise it sees +      // Apply it *now*. insertTrack2 needs to be called now, not later, otherwise it sees        //  that the track may have routes, and reciprocates them, causing duplicate routes. -      ///operations.push_back(UndoOp(UndoOp::AddTrack, idx, track));   +      applyOperation(UndoOp(UndoOp::AddTrack, idx, track));        // Add default track <-> midiport routes.         if(track->isMidiTrack())  @@ -439,7 +434,8 @@ void Song::duplicateTracks()    QString track_name;    int idx;    int trackno = tl.size(); -  MusEGlobal::song->startUndo(); +   +  Undo operations;    for(TrackList::reverse_iterator it = tl.rbegin(); it != tl.rend(); ++it)     {      Track* track = *it; @@ -449,114 +445,23 @@ void Song::duplicateTracks()        for(int cp = 0; cp < copies; ++cp)        { -        // There are two ways to copy a track now. Using the copy constructor or using new + assign().  -        // Tested: Both ways seem OK. Prefer copy constructors for simplicity. But new + assign() may be  -        //  required for fine-grained control over initializing various track types. -        // -         -        //  Set to 0 to use the copy constructor. Set to 1 to use new + assign(). -        // DELETETHIS is this still necessary to keep around? -        //            also consider removing and adding a hint to a revision number instead -  #if 0       -         -        Track* new_track = 0; -        int lastAuxIdx = _auxs.size(); -        switch(track->type())  -        { -          case Track::AUDIO_SOFTSYNTH:  // TODO: Handle synths.   p4.0.47 -                // ((AudioTrack*)new_track)->addAuxSend(lastAuxIdx); DELETETHIS? -                break; -             -          case Track::MIDI: -                new_track = new MidiTrack(); -                new_track->setType(Track::MIDI); -                break; -          case Track::DRUM: -                new_track = new MidiTrack(); -                new_track->setType(Track::DRUM); -                //((MidiTrack*)new_track)->setOutChannel(9); DELETETHIS? -                break; -          case Track::WAVE: -                new_track = new MusECore::WaveTrack(); -                //((AudioTrack*)new_track)->addAuxSend(lastAuxIdx); DELETETHIS? -                break; -          case Track::AUDIO_OUTPUT: -                new_track = new AudioOutput(); -                break; -          case Track::AUDIO_GROUP: -                new_track = new AudioGroup(); -                //((AudioTrack*)new_track)->addAuxSend(lastAuxIdx); DELETETHIS? -                break; -          case Track::AUDIO_AUX: -                new_track = new AudioAux(); -                break; -          case Track::AUDIO_INPUT: -                new_track = new AudioInput(); -                //((AudioTrack*)new_track)->addAuxSend(lastAuxIdx); DELETETHIS? -                break; -          default: -                printf("Song::duplicateTracks: Illegal type %d\n", track->type()); -                break; -        } -             -        if(new_track)    -        { -          new_track->assign(*track, flags); -  #else       -        {            Track* new_track = track->clone(flags);   -  #endif            //new_track->setDefaultName(track_name);  // Handled in class now.            idx = trackno + cp; -          insertTrack1(new_track, idx);          -          addUndo(MusECore::UndoOp(MusECore::UndoOp::AddTrack, idx, new_track)); -          msgInsertTrack(new_track, idx, false); // No undo. -          insertTrack3(new_track, idx);  -        } +          operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddTrack, idx, new_track));        }        }      --trackno;    } -  MusECore::SongChangedFlags_t update_flags = SC_TRACK_INSERTED; -  if(flags & (Track::ASSIGN_ROUTES | Track::ASSIGN_DEFAULT_ROUTES)) -    update_flags |= SC_ROUTE; -  MusEGlobal::song->endUndo(update_flags); +  MusEGlobal::song->applyOperationGroup(operations);    MusEGlobal::audio->msgUpdateSoloStates();  }           -//--------------------------------------------------------- -//   cmdRemoveTrack -//--------------------------------------------------------- -void Song::cmdRemoveTrack(Track* track) -      { -      int idx = _tracks.index(track); -      addUndo(UndoOp(UndoOp::DeleteTrack, idx, track)); -      removeTrack2(track); -      updateFlags |= SC_TRACK_REMOVED; -      } -//--------------------------------------------------------- -//   removeMarkedTracks -//--------------------------------------------------------- - -void Song::removeMarkedTracks() -      { -      bool loop; -      do { -            loop = false; -            for (iTrack t = _tracks.begin(); t != _tracks.end(); ++t) { -                  if ((*t)->selected()) { -                        removeTrack2(*t); -                        loop = true; -                        break; -                        } -                  } -            } while (loop); -      }  //---------------------------------------------------------  //   deselectTracks @@ -577,15 +482,15 @@ bool Song::addEvent(Event& event, Part* part)        {        // Return false if the event is already found.         // (But allow a port controller value, above, in case it is not already stored.) -      if(part->events()->find(event) != part->events()->end()) +      if(part->events().find(event) != part->events().end())        {          // This can be normal for some (redundant) operations.          if(MusEGlobal::debugMsg) -          printf("Song::addEvent event already found in part:%s size:%zd\n", part->name().toLatin1().constData(), part->events()->size()); +          printf("Song::addEvent event already found in part:%s size:%zd\n", part->name().toLatin1().constData(), part->events().size());          return false;        } -      part->events()->add(event); +      part->nonconst_events().add(event);        return true;        } @@ -595,18 +500,18 @@ bool Song::addEvent(Event& event, Part* part)  void Song::changeEvent(Event& oldEvent, Event& newEvent, Part* part)  { -      iEvent i = part->events()->find(oldEvent); +      iEvent i = part->nonconst_events().find(oldEvent); -      if (i == part->events()->end()) { +      if (i == part->nonconst_events().end()) {              // This can be normal for some (redundant) operations.              if(MusEGlobal::debugMsg) -              printf("Song::changeEvent event not found in part:%s size:%zd\n", part->name().toLatin1().constData(), part->events()->size()); +              printf("Song::changeEvent event not found in part:%s size:%zd\n", part->name().toLatin1().constData(), part->nonconst_events().size());              // no "return;" because: Allow it to add the new event.  (And remove the old one from the midi port controller!) (tim)              }        else -        part->events()->erase(i); +        part->nonconst_events().erase(i); -      part->events()->add(newEvent); +      part->nonconst_events().add(newEvent);  }  //--------------------------------------------------------- @@ -615,14 +520,14 @@ void Song::changeEvent(Event& oldEvent, Event& newEvent, Part* part)  void Song::deleteEvent(Event& event, Part* part)        { -      iEvent ev = part->events()->find(event); -      if (ev == part->events()->end()) { +      iEvent ev = part->nonconst_events().find(event); +      if (ev == part->nonconst_events().end()) {              // This can be normal for some (redundant) operations.              if(MusEGlobal::debugMsg) -              printf("Song::deleteEvent event not found in part:%s size:%zd\n", part->name().toLatin1().constData(), part->events()->size()); +              printf("Song::deleteEvent event not found in part:%s size:%zd\n", part->name().toLatin1().constData(), part->nonconst_events().size());              return;              } -      part->events()->erase(ev); +      part->nonconst_events().erase(ev);        }  //--------------------------------------------------------- @@ -646,8 +551,8 @@ void Song::remapPortDrumCtrlEvents(int mapidx, int newnote, int newchan, int new      for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)       {        MidiPart* part = (MidiPart*)(ip->second); -      const EventList* el = part->cevents(); -      for(ciEvent ie = el->begin(); ie != el->end(); ++ie) +      const EventList& el = part->events(); +      for(ciEvent ie = el.begin(); ie != el.end(); ++ie)        {          const Event& ev = ie->second;          if(ev.type() != Controller) @@ -717,17 +622,10 @@ void Song::changeAllPortDrumCtrlEvents(bool add, bool drumonly)      for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)       {        MidiPart* part = (MidiPart*)(ip->second); -      const EventList* el = part->cevents(); -      // unsigned len = part->lenTick(); // Commented out by flo, see below -      for(ciEvent ie = el->begin(); ie != el->end(); ++ie) +      for(ciEvent ie = part->events().begin(); ie != part->events().end(); ++ie)        {          const Event& ev = ie->second; -        // Added by T356. Do not handle events which are past the end of the part. -        // Commented out by flo: yes, DO handle them! these are "hidden events" -        //                       which may be revealed later again! -        // if(ev.tick() >= len) -        //   break; -                     +          if(ev.type() != Controller)            continue; @@ -765,45 +663,35 @@ void Song::changeAllPortDrumCtrlEvents(bool add, bool drumonly)    }  } -void Song::addACEvent(AudioTrack* t, int acid, int frame, double val) -{ -  MusEGlobal::audio->msgAddACEvent(t, acid, frame, val); -} - -void Song::changeACEvent(AudioTrack* t, int acid, int frame, int newFrame, double val) -{ -  MusEGlobal::audio->msgChangeACEvent(t, acid, frame, newFrame, val); -} -  //---------------------------------------------------------  //   cmdAddRecordedEvents  //    add recorded Events into part  //--------------------------------------------------------- -void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned startTick) +void Song::cmdAddRecordedEvents(MidiTrack* mt, const EventList& events, unsigned startTick)        { -      if (events->empty()) { +      if (events.empty()) {              if (MusEGlobal::debugMsg)                    printf("no events recorded\n");              return;              } -      iEvent s; -      iEvent e; +      ciEvent s; +      ciEvent e;        unsigned endTick;        if((MusEGlobal::audio->loopCount() > 0 && startTick > lPos().tick()) || (punchin() && startTick < lPos().tick()))        {              startTick = lpos(); -            s = events->lower_bound(startTick); +            s = events.lower_bound(startTick);        }        else         { -            s = events->begin(); +            s = events.begin();        }        // search for last noteOff:        endTick = 0; -      for (iEvent i = events->begin(); i != events->end(); ++i) { +      for (ciEvent i = events.begin(); i != events.end(); ++i) {              Event ev   = i->second;              unsigned l = ev.endTick();              if (l > endTick) @@ -813,10 +701,10 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start        if((MusEGlobal::audio->loopCount() > 0) || (punchout() && endTick > rPos().tick()) )        {              endTick = rpos(); -            e = events->lower_bound(endTick); +            e = events.lower_bound(endTick);        }        else -            e = events->end(); +            e = events.end();        if (startTick > endTick) {              if (MusEGlobal::debugMsg) @@ -832,7 +720,7 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start        //---------------------------------------------------        PartList* pl = mt->parts(); -      MidiPart* part = 0; +      const MidiPart* part = 0;        iPart ip;        for (ip = pl->begin(); ip != pl->end(); ++ip) {              part = (MidiPart*)(ip->second); @@ -845,39 +733,42 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start              if (MusEGlobal::debugMsg)                    printf("create new part for recorded events\n");              // create new part -            part      = new MidiPart(mt); +            MidiPart* newpart; +            newpart      = new MidiPart(mt);              // Round the start down using the Arranger part snap raster value.               startTick = AL::sigmap.raster1(startTick, arrangerRaster());              // Round the end up using the Arranger part snap raster value.               endTick   = AL::sigmap.raster2(endTick, arrangerRaster()); -            part->setTick(startTick); -            part->setLenTick(endTick - startTick); -            part->setName(mt->name()); +            newpart->setTick(startTick); +            newpart->setLenTick(endTick - startTick); +            newpart->setName(mt->name());              // copy events -            for (iEvent i = s; i != e; ++i) { -                  Event old = i->second; +            for (ciEvent i = s; i != e; ++i) { +                  const Event& old = i->second;                    Event event = old.clone();                    event.setTick(old.tick() - startTick);                    // addEvent also adds port controller values. So does msgAddPart, below. Let msgAddPart handle them.                    //addEvent(event, part); -                  if(part->events()->find(event) == part->events()->end()) -                    part->events()->add(event); +                  if(newpart->events().find(event) == newpart->events().end()) +                    newpart->nonconst_events().add(event);                    } -            MusEGlobal::audio->msgAddPart(part); +            MusEGlobal::audio->msgAddPart(newpart);              updateFlags |= SC_PART_INSERTED;              return;              }        updateFlags |= SC_EVENT_INSERTED; +      Undo operations; +        unsigned partTick = part->tick();        if (endTick > part->endTick()) {              // Determine new part length...              endTick = 0; -            for (iEvent i = s; i != e; ++i) { -                  Event event = i->second; +            for (ciEvent i = s; i != e; ++i) { +                  const Event& event = i->second;                    unsigned tick = event.tick() - partTick + event.lenTick();                    if (endTick < tick)                          endTick = tick; @@ -886,88 +777,31 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start              // Round the end up (again) using the Arranger part snap raster value.               endTick   = AL::sigmap.raster2(endTick, arrangerRaster()); -             -            removePortCtrlEvents(part, false); // Remove all of the part's port controller values. Don't do clone parts. - -            // Clone the part. This doesn't increment aref count, and doesn't chain clones. -            // It also gives the new part a new serial number, but it is  -            //  overwritten with the old one by Song::changePart(), below.  -            Part* newPart = part->clone(); -             -            newPart->setLenTick(endTick);  // Set the new part's length. -            changePart(part, newPart);     // Change the part. -             -            part->events()->incARef(-1);   // Manually adjust reference counts. HACK! -            newPart->events()->incARef(1); -             -            replaceClone(part, newPart);   // Replace the part in the clone chain with the new part. -             -            // Now add all of the new part's port controller values. Indicate do not do clone parts. -            addPortCtrlEvents(newPart, false); -                          // Create an undo op. Indicate do port controller values but not clone parts.  -            addUndo(UndoOp(UndoOp::ModifyPart, part, newPart, true, false)); +            operations.push_back(UndoOp(UndoOp::ModifyPartLength, part, part->lenTick(), endTick, true, false)); // FIXME XTICKS! FINDMICHJETZT!              updateFlags |= SC_PART_MODIFIED; +      } -            if (_recMode == REC_REPLACE) -            { -                  iEvent si = newPart->events()->lower_bound(startTick - newPart->tick()); -                  iEvent ei = newPart->events()->lower_bound(newPart->endTick() - newPart->tick()); -                  for (iEvent i = si; i != ei; ++i)  -                  { -                    Event event = i->second; -                    // Indicate do port controller values and clone parts.  -                    addUndo(UndoOp(UndoOp::DeleteEvent, event, newPart, true, true)); -                    // Remove the event from the new part's port controller values, and do all clone parts. -                    removePortCtrlEvents(event, newPart, true); -                  } -                  newPart->events()->erase(si, ei); -            } -             -            for (iEvent i = s; i != e; ++i) { -                  Event event = i->second; -                  event.setTick(event.tick() - partTick); -                  Event e; -                  // Create an undo op. Indicate do port controller values and clone parts.  -                  addUndo(UndoOp(UndoOp::AddEvent, e, event, newPart, true, true)); -                   -                  if(newPart->events()->find(event) == newPart->events()->end()) -                    newPart->events()->add(event); -                   -                  // Add the event to the new part's port controller values, and do all clone parts. -                  addPortCtrlEvents(event, newPart, true); -                  } -            } -      else { -            if (_recMode == REC_REPLACE) { -                  iEvent si = part->events()->lower_bound(startTick - part->tick()); -                  iEvent ei = part->events()->lower_bound(endTick   - part->tick()); - -                  for (iEvent i = si; i != ei; ++i) { -                        Event event = i->second; -                        // Indicate that controller values and clone parts were handled. -                        addUndo(UndoOp(UndoOp::DeleteEvent, event, part, true, true)); -                        // Remove the event from the part's port controller values, and do all clone parts. -                        removePortCtrlEvents(event, part, true); -                        } -                  part->events()->erase(si, ei); -                  } -            for (iEvent i = s; i != e; ++i) { -                  Event event = i->second; -                  int tick = event.tick() - partTick; -                  event.setTick(tick); -                   + +      if (_recMode == REC_REPLACE) { +            ciEvent si = part->events().lower_bound(startTick - part->tick()); +            ciEvent ei = part->events().lower_bound(endTick   - part->tick()); + +            for (ciEvent i = si; i != ei; ++i) { +                  const Event& event = i->second;                    // Indicate that controller values and clone parts were handled. -                  addUndo(UndoOp(UndoOp::AddEvent, event, part, true, true)); -                   -                  if(part->events()->find(event) == part->events()->end()) -                    part->events()->add(event); -                   -                  // Add the event to the part's port controller values, and do all clone parts. -                  addPortCtrlEvents(event, part, true); -                  } +                  operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, true, true));              }        } +      for (ciEvent i = s; i != e; ++i) { +            Event event = i->second.clone(); +            event.setTick(event.tick() - partTick); +            // Indicate that controller values and clone parts were handled. +            operations.push_back(UndoOp(UndoOp::AddEvent, event, part, true, true)); +      } +       +      applyOperationGroup(operations,false); // don't do undo, startUndo must have been called from outside. +}  //---------------------------------------------------------  //   findTrack @@ -1400,23 +1234,6 @@ void Song::updatePos()        }  //--------------------------------------------------------- -//   setChannelMute -//    mute all midi tracks associated with channel -//--------------------------------------------------------- - -void Song::setChannelMute(int channel, bool val) -      { -      for (iTrack i = _tracks.begin(); i != _tracks.end(); ++i) { -            MidiTrack* track = dynamic_cast<MidiTrack*>(*i); -            if (track == 0) -                  continue; -            if (track->outChannel() == channel) -                  track->setMute(val); -            } -      emit songChanged(SC_MUTE); -      } - -//---------------------------------------------------------  //   len  //--------------------------------------------------------- @@ -1788,10 +1605,17 @@ void Song::endMsgCmd()  void Song::undo()        {        updateFlags = 0; -      if (doUndo1()) +       +      Undo& opGroup = undoList->back(); +       +      if (opGroup.empty())              return; -      MusEGlobal::audio->msgUndo(); -      doUndo3(); +       +      MusEGlobal::audio->msgRevertOperationGroup(opGroup); +       +      redoList->push_back(opGroup); +      undoList->pop_back(); +              MusEGlobal::redoAction->setEnabled(true);        MusEGlobal::undoAction->setEnabled(!undoList->empty());        setUndoRedoText(); @@ -1800,6 +1624,7 @@ void Song::undo()          MusEGlobal::audio->msgUpdateSoloStates();        emit songChanged(updateFlags); +      emit sigDirty();        }  //--------------------------------------------------------- @@ -1809,10 +1634,17 @@ void Song::undo()  void Song::redo()        {        updateFlags = 0; -      if (doRedo1()) + +      Undo& opGroup = redoList->back(); +       +      if (opGroup.empty())              return; -      MusEGlobal::audio->msgRedo(); -      doRedo3(); +       +      MusEGlobal::audio->msgExecuteOperationGroup(opGroup); +       +      undoList->push_back(opGroup); +      redoList->pop_back(); +              MusEGlobal::undoAction->setEnabled(true);        MusEGlobal::redoAction->setEnabled(!redoList->empty());        setUndoRedoText(); @@ -1821,6 +1653,7 @@ void Song::redo()          MusEGlobal::audio->msgUpdateSoloStates();        emit songChanged(updateFlags); +      emit sigDirty();        }  //--------------------------------------------------------- @@ -1834,78 +1667,14 @@ void Song::processMsg(AudioMsg* msg)              case SEQM_UPDATE_SOLO_STATES:                    updateSoloStates();                    break; -            case SEQM_UNDO: -                  doUndo2(); -                  break; -            case SEQM_REDO: -                  doRedo2(); -                  break; -            case SEQM_MOVE_TRACK: -                  if (msg->a > msg->b) { -                        for (int i = msg->a; i > msg->b; --i) { -                              swapTracks(i, i-1); -                              } -                        } -                  else { -                        for (int i = msg->a; i < msg->b; ++i) { -                              swapTracks(i, i+1); -                              } -                        } -                  updateFlags = SC_TRACK_MODIFIED; -                  break; -            case SEQM_ADD_EVENT: -                  updateFlags = SC_EVENT_INSERTED; -                  if (addEvent(msg->ev1, (MidiPart*)msg->p2)) { -                        Event ev; -                        addUndo(UndoOp(UndoOp::AddEvent, ev, msg->ev1, (Part*)msg->p2, msg->a, msg->b)); -                        } -                  else -                        updateFlags = 0; -                  if(msg->a) -                    addPortCtrlEvents(msg->ev1, (Part*)msg->p2, msg->b); +            case SEQM_EXECUTE_OPERATION_GROUP: +                  executeOperationGroup2(*msg->operations);                    break; -            case SEQM_REMOVE_EVENT: -                  { -                  Event event = msg->ev1; -                  MidiPart* part = (MidiPart*)msg->p2; -                  if(msg->a) -                    removePortCtrlEvents(event, part, msg->b); -                  Event e; -                  addUndo(UndoOp(UndoOp::DeleteEvent, e, event, (Part*)part, msg->a, msg->b)); -                  deleteEvent(event, part); -                  updateFlags = SC_EVENT_REMOVED; -                  } -                  break; -            case SEQM_CHANGE_EVENT: -                  if(msg->a) -                    removePortCtrlEvents(msg->ev1, (MidiPart*)msg->p3, msg->b); -                  changeEvent(msg->ev1, msg->ev2, (MidiPart*)msg->p3); -                  if(msg->a) -                    addPortCtrlEvents(msg->ev2, (Part*)msg->p3, msg->b); -                  addUndo(UndoOp(UndoOp::ModifyEvent, msg->ev2, msg->ev1, (Part*)msg->p3, msg->a, msg->b)); -                  updateFlags = SC_EVENT_MODIFIED; -                  break; -             -            // Moved here from MidiSeq::processMsg   p4.0.34 -            case SEQM_ADD_TRACK: -                  insertTrack2(msg->track, msg->ival); -                  break; -            case SEQM_REMOVE_TRACK: -                  cmdRemoveTrack(msg->track); -                  break; -            //case SEQM_CHANGE_TRACK:     DELETETHIS 3 -            //      changeTrack((Track*)(msg->p1), (Track*)(msg->p2)); -            //      break; -            case SEQM_ADD_PART: -                  cmdAddPart((Part*)msg->p1); -                  break; -            case SEQM_REMOVE_PART: -                  cmdRemovePart((Part*)msg->p1); -                  break; -            case SEQM_CHANGE_PART: -                  cmdChangePart((Part*)msg->p1, (Part*)msg->p2, msg->a, msg->b); +            case SEQM_REVERT_OPERATION_GROUP: +                  revertOperationGroup2(*msg->operations);                    break; +              case SEQM_ADD_TEMPO:                    addUndo(UndoOp(UndoOp::AddTempo, msg->a, msg->b));                    MusEGlobal::tempomap.addTempo(msg->a, msg->b); @@ -1959,56 +1728,6 @@ void Song::processMsg(AudioMsg* msg)        }  //--------------------------------------------------------- -//   cmdAddPart -//--------------------------------------------------------- - -void Song::cmdAddPart(Part* part) -      { -      addPart(part); -      addUndo(UndoOp(UndoOp::AddPart, part)); -      updateFlags = SC_PART_INSERTED; -      } - -//--------------------------------------------------------- -//   cmdRemovePart -//--------------------------------------------------------- - -void Song::cmdRemovePart(Part* part) -      { -      removePart(part); -      addUndo(UndoOp(UndoOp::DeletePart, part)); -      part->events()->incARef(-1); -      unchainClone(part); -      updateFlags = SC_PART_REMOVED; -      } - -//--------------------------------------------------------- -//   cmdChangePart -//--------------------------------------------------------- - -void Song::cmdChangePart(Part* oldPart, Part* newPart, bool doCtrls, bool doClones) -      { -      if(doCtrls) -        removePortCtrlEvents(oldPart, doClones); -       -      changePart(oldPart, newPart); -       -      addUndo(UndoOp(UndoOp::ModifyPart, oldPart, newPart, doCtrls, doClones)); -       -      // Changed by T356. Do not decrement ref count if the new part is a clone of the old part, since the event list -      //  will still be active. -      if(oldPart->cevents() != newPart->cevents()) -        oldPart->events()->incARef(-1); -       -      replaceClone(oldPart, newPart); - -      if(doCtrls) -        addPortCtrlEvents(newPart, doClones); -       -      updateFlags = SC_PART_MODIFIED; -      } - -//---------------------------------------------------------  //   panic  //--------------------------------------------------------- @@ -2383,7 +2102,7 @@ void Song::recordEvent(MidiTrack* mt, Event& event)        unsigned tick  = event.tick();        PartList* pl   = mt->parts(); -      MidiPart* part = 0; +      const MidiPart* part = 0;        iPart ip;        for (ip = pl->begin(); ip != pl->end(); ++ip) {              part = (MidiPart*)(ip->second); @@ -2395,14 +2114,14 @@ void Song::recordEvent(MidiTrack* mt, Event& event)        updateFlags |= SC_EVENT_INSERTED;        if (ip == pl->end()) {              // create new part -            part          = new MidiPart(mt); +            MidiPart* part = new MidiPart(mt);              int startTick = roundDownBar(tick);              int endTick   = roundUpBar(tick + 1);              part->setTick(startTick);              part->setLenTick(endTick - startTick);              part->setName(mt->name());              event.move(-startTick); -            part->events()->add(event); +            part->nonconst_events().add(event);              MusEGlobal::audio->msgAddPart(part);              return;              } @@ -2413,23 +2132,21 @@ void Song::recordEvent(MidiTrack* mt, Event& event)        Event ev;        if(event.type() == Controller)        { -        EventRange range = part->events()->equal_range(tick); -        for(iEvent i = range.first; i != range.second; ++i)  +        EventRange range = part->events().equal_range(tick); +        for(ciEvent i = range.first; i != range.second; ++i)           {            ev = i->second;            if(ev.type() == Controller && ev.dataA() == event.dataA())            {              if(ev.dataB() == event.dataB()) // Don't bother if already set.                return; -            // Indicate do undo, and do port controller values and clone parts.  -            MusEGlobal::audio->msgChangeEvent(ev, event, part, true, true, true); +            MusEGlobal::song->applyOperation(UndoOp(UndoOp::ModifyEvent,event,ev,part,true,true));              return;            }          }        }   -      // Indicate do undo, and do port controller values and clone parts.  -      MusEGlobal::audio->msgAddEvent(event, part, true, true, true); +      MusEGlobal::song->applyOperation(UndoOp(UndoOp::AddEvent, event, part, true,true));        }  //--------------------------------------------------------- @@ -2705,8 +2422,8 @@ int Song::execMidiAutomationCtlPopup(MidiTrack* track, MidiPart* part, const QPo      unsigned partEnd   = partStart + part->lenTick();      if(tick >= partStart && tick < partEnd)      { -      EventRange range = part->events()->equal_range(tick - partStart); -      for(iEvent i = range.first; i != range.second; ++i)  +      EventRange range = part->events().equal_range(tick - partStart); +      for(ciEvent i = range.first; i != range.second; ++i)         {          ev = i->second;          if(ev.type() == Controller) @@ -2785,7 +2502,7 @@ int Song::execMidiAutomationCtlPopup(MidiTrack* track, MidiPart* part, const QPo                part->setLenTick(endTick - startTick);                part->setName(mt->name());                e.setTick(tick - startTick); -              part->events()->add(e); +              part->nonconst_events().add(e);                // Allow undo.                MusEGlobal::audio->msgAddPart(part);              } @@ -3040,7 +2757,7 @@ void Song::connectJackRoutes(AudioTrack* track, bool disconnect)  void Song::insertTrack0(Track* track, int idx)        {        insertTrack1(track, idx); -      insertTrack2(track, idx);  // MusEGlobal::audio->msgInsertTrack(track, idx, false); DELETETHIS or is this somehow explanatory? +      insertTrack2(track, idx);  // the same as MusEGlobal::audio->msgInsertTrack(track, idx, false);        insertTrack3(track, idx);        } @@ -3221,18 +2938,6 @@ void Song::insertTrack3(Track* /*track*/, int /*idx*/)//prevent compiler warning  }  //--------------------------------------------------------- -//   removeTrack0 -//--------------------------------------------------------- - -void Song::removeTrack0(Track* track) -      { -      removeTrack1(track); -      MusEGlobal::audio->msgRemoveTrack(track); -      removeTrack3(track); -      update(SC_TRACK_REMOVED); -      } - -//---------------------------------------------------------  //   removeTrack1  //    non realtime part of removeTrack  //--------------------------------------------------------- @@ -3285,12 +2990,12 @@ void Song::removeTrack2(Track* track)              case Track::DRUM:              case Track::NEW_DRUM:                    removePortCtrlEvents(((MidiTrack*)track)); -                  unchainTrackParts(track, true); +                  unchainTrackParts(track);                    _midis.erase(track);                    break;              case Track::WAVE: -                  unchainTrackParts(track, true); +                  unchainTrackParts(track);                    _waves.erase(track);                    break; @@ -3439,7 +3144,7 @@ void Song::executeScript(const char* scriptfile, PartList* parts, int quant, boo              fprintf(fp, "BEATLEN %d\n", AL::sigmap.ticksBeat(0));              fprintf(fp, "QUANTLEN %d\n", quant); -            for (iEvent e = part->events()->begin(); e != part->events()->end(); e++) { +            for (ciEvent e = part->events().begin(); e != part->events().end(); e++) {                  Event ev = e->second;                  if (ev.isNote()) @@ -3583,14 +3288,14 @@ QString Song::getScriptPath(int id, bool isdelivered)        return path;  } -void Song::informAboutNewParts(const std::map< Part*, std::set<Part*> >& param) +void Song::informAboutNewParts(const std::map< const Part*, std::set<const Part*> >& param)  {    emit newPartsCreated(param);  } -void Song::informAboutNewParts(Part* orig, Part* p1, Part* p2, Part* p3, Part* p4, Part* p5, Part* p6, Part* p7, Part* p8, Part* p9) +void Song::informAboutNewParts(const Part* orig, const Part* p1, const Part* p2, const Part* p3, const Part* p4, const Part* p5, const Part* p6, const Part* p7, const Part* p8, const Part* p9)  { -  std::map< Part*, std::set<Part*> > temp; +  std::map<const Part*, std::set<const Part*> > temp;    temp[orig].insert(p1);    temp[orig].insert(p2); @@ -3601,7 +3306,7 @@ void Song::informAboutNewParts(Part* orig, Part* p1, Part* p2, Part* p3, Part* p    temp[orig].insert(p7);    temp[orig].insert(p8);    temp[orig].insert(p9); -  temp[orig].erase(static_cast<Part*>(NULL)); +  temp[orig].erase(static_cast<const Part*>(NULL));    temp[orig].erase(orig);    informAboutNewParts(temp); diff --git a/muse2/muse/song.h b/muse2/muse/song.h index 6621de35..a25f1d55 100644 --- a/muse2/muse/song.h +++ b/muse2/muse/song.h @@ -171,9 +171,27 @@ class Song : public QObject {        Song(const char* name = 0);        ~Song(); -      bool applyOperationGroup(Undo& group, bool doUndo=true); -      void informAboutNewParts(const std::map< Part*, std::set<Part*> >&); -      void informAboutNewParts(Part* orig, Part* p1, Part* p2=NULL, Part* p3=NULL, Part* p4=NULL, Part* p5=NULL, Part* p6=NULL, Part* p7=NULL, Part* p8=NULL, Part* p9=NULL); +      /** It is not allowed nor checked(!) to AddPart a clone, and +       *  to AddEvent/DeleteEvent/ModifyEvent/SelectEvent events which +       *  would need to be replicated to the newly added clone part! +       */ +      bool applyOperationGroup(Undo& group, bool doUndo=true); // group may be changed! prepareOperationGroup is called on group! +      bool applyOperation(const UndoOp& op, bool doUndo=true); +       +      /** this sends emits a signal to each MidiEditor or whoever is interested. +       *  For each part which is 1) opened in this MidiEditor and 2) which is +       *  a key in this map, the Editors shall no more edit this part, but instead +       *  all parts in the_map[old_part] (which is a std::set<Part*>) +       */ +      void informAboutNewParts(const std::map< const Part*, std::set<const Part*> >&); +      /** this sends emits a signal to each MidiEditor or whoever is interested. +       *  For each part which is 1) opened in this MidiEditor and 2) which is +       *  a key in this map, the Editors shall no more edit this part, but instead +       *  all parts in the_map[old_part] (which is a std::set<Part*>) +       *  this is a special case of the general function, which only replaces one part +       *  by up to nine different. +       */ +      void informAboutNewParts(const Part* orig, const Part* p1, const Part* p2=NULL, const Part* p3=NULL, const Part* p4=NULL, const Part* p5=NULL, const Part* p6=NULL, const Part* p7=NULL, const Part* p8=NULL, const Part* p9=NULL);        void putEvent(int pv);        void endMsgCmd(); @@ -263,36 +281,29 @@ class Song : public QObject {        //-----------------------------------------        void cmdAddRecordedWave(WaveTrack* track, Pos, Pos);   -      void cmdAddRecordedEvents(MidiTrack*, EventList*, unsigned); -      bool addEvent(Event&, Part*); -      void changeEvent(Event&, Event&, Part*); -      void deleteEvent(Event&, Part*); -      void cmdChangeWave(QString original, QString tmpfile, unsigned sx, unsigned ex); -      void remapPortDrumCtrlEvents(int mapidx, int newnote, int newchan, int newport); -      void changeAllPortDrumCtrlEvents(bool add, bool drumonly = false); +      void cmdAddRecordedEvents(MidiTrack*, const EventList&, unsigned); +      bool addEvent(Event&, Part*);                 // only called from audio thread. FIXME TODO: move functionality into undo.cpp +      void changeEvent(Event&, Event&, Part*);      // only called from audio thread. FIXME TODO: move functionality into undo.cpp +      void deleteEvent(Event&, Part*);              // only called from audio thread. FIXME TODO: move functionality into undo.cpp +      void cmdChangeWave(QString original, QString tmpfile, unsigned sx, unsigned ex); // FIXME TODO broken, fix that. +      void remapPortDrumCtrlEvents(int mapidx, int newnote, int newchan, int newport); // called from GUI thread +      void changeAllPortDrumCtrlEvents(bool add, bool drumonly = false); // called from GUI thread -      void addACEvent(AudioTrack* t, int acid, int frame, double val); -      void changeACEvent(AudioTrack* t, int acid, int frame, int newFrame, double val);        void addExternalTempo(const TempoRecEvent& e) { _tempoFifo.put(e); }        //-----------------------------------------        //   part manipulations        //----------------------------------------- -      void cmdResizePart(Track* t, Part* p, unsigned int size, bool doClones=false); -      void cmdSplitPart(Track* t, Part* p, int tick); -      void cmdGluePart(Track* t, Part* p); +      void cmdResizePart(Track* t, Part* p, unsigned int size, bool doClones=false); // called from GUI thread, calls applyOperationGroup. FIXME TODO: better move that into functions.cpp or whatever.        void addPart(Part* part);        void removePart(Part* part); -      void changePart(Part*, Part*); -      PartList* getSelectedMidiParts() const; + +       +      PartList* getSelectedMidiParts() const; // FIXME TODO move functionality into function.cpp        PartList* getSelectedWaveParts() const; -      bool msgRemoveParts(); -      void cmdChangePart(Part* oldPart, Part* newPart, bool doCtrls, bool doClones); -      void cmdRemovePart(Part* part); -      void cmdAddPart(Part* part);        int arrangerRaster() { return _arrangerRaster; }        // Used by Song::cmdAddRecordedWave to snap new wave parts        void setArrangerRaster(int r) { _arrangerRaster = r; }  // Used by Arranger snap combo box @@ -309,17 +320,12 @@ class Song : public QObject {        AuxList* auxs()           { return &_auxs;    }        SynthIList* syntis()      { return &_synthIs; } -      void cmdRemoveTrack(Track* track); -      void removeTrack0(Track* track);        void removeTrack1(Track* track);        void removeTrack2(Track* track);        void removeTrack3(Track* track); -      void removeMarkedTracks(); -      //void changeTrack(Track* oldTrack, Track* newTrack); DELETETHIS        MidiTrack* findTrack(const Part* part) const;        Track* findTrack(const QString& name) const;        void swapTracks(int i1, int i2); -      void setChannelMute(int channel, bool flag);        void setRecordFlag(Track*, bool);        void insertTrack0(Track*, int idx);        void insertTrack1(Track*, int idx); @@ -328,7 +334,6 @@ class Song : public QObject {        void deselectTracks();        void readRoute(Xml& xml);        void recordEvent(MidiTrack*, Event&); -      void msgInsertTrack(Track* track, int idx, bool u = true);        // Enable all track and plugin controllers, and synth controllers if applicable, which are NOT in AUTO_WRITE mode.        void reenableTouchedControllers();          void clearRecAutomation(bool clearList); @@ -340,20 +345,20 @@ class Song : public QObject {        void updateSoloStates();        //----------------------------------------- -      //   undo, redo +      //   undo, redo, operation groups        //-----------------------------------------        void startUndo();        void endUndo(MusECore::SongChangedFlags_t); -      void undoOp(UndoOp::UndoType type, const char* changedFile, const char* changeData, int startframe, int endframe); +	  void undoOp(UndoOp::UndoType type, const char* changedFile, const char* changeData, int startframe, int endframe); // FIXME FINDMICHJETZT what's that?! remove it! -      bool doUndo1(); -      void doUndo2(); -      void doUndo3(); -      bool doRedo1(); -      void doRedo2(); -      void doRedo3(); +      void executeOperationGroup1(Undo& operations); +      void executeOperationGroup2(Undo& operations); +      void executeOperationGroup3(Undo& operations); +      void revertOperationGroup1(Undo& operations); +      void revertOperationGroup2(Undo& operations); +      void revertOperationGroup3(Undo& operations);        void addUndo(UndoOp i);        void setUndoRedoText(); @@ -412,7 +417,7 @@ class Song : public QObject {        void setQuantize(bool val);        void panic();        void seqSignal(int fd); -      Track* addTrack(Undo& operations, Track::TrackType type, Track* insertAt = 0); +      Track* addTrack(Track::TrackType type, Track* insertAt = 0);        Track* addNewTrack(QAction* action, Track* insertAt = 0);        void duplicateTracks();        QString getScriptPath(int id, bool delivered); @@ -432,7 +437,7 @@ class Song : public QObject {        void midiPortsChanged();        void midiNote(int pitch, int velo);          void controllerChanged(MusECore::Track*, int);  -      void newPartsCreated(const std::map< MusECore::Part*, std::set<MusECore::Part*> >&); +      void newPartsCreated(const std::map< const MusECore::Part*, std::set<const MusECore::Part*> >&);        void sigDirty();        }; diff --git a/muse2/muse/songfile.cpp b/muse2/muse/songfile.cpp index b07d1243..78338bac 100644 --- a/muse2/muse/songfile.cpp +++ b/muse2/muse/songfile.cpp @@ -56,49 +56,6 @@ MusECore::CloneList cloneList;  namespace MusECore { -/* DELETETHIS 42 -//--------------------------------------------------------- -//   updateCloneList -//--------------------------------------------------------- - -void updateCloneList(Part* oPart, Part* nPart) -{ -  for(iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)  -  { -    if(i->cp == oPart)  -    { -      i->cp = nPart; -      break; -    } -  } -} - -void updateCloneList(PartList* oParts, PartList* nParts) -{ -  for(iPart ip = oParts->begin(); ip != oParts->end(); ++ip)  -  { -    for(iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)  -    { -      if(i->cp == oPart)  -      { -        i->cp = nPart; -        break; -      } -    }   -  } -} - -//--------------------------------------------------------- -//   clearClipboardAndCloneList -//--------------------------------------------------------- - -void clearClipboardAndCloneList() -{ -  //QApplication::clipboard()->clear(QClipboard::Clipboard); -  MusEGlobal::cloneList.clear(); -} -*/ -  //---------------------------------------------------------  //   NKey::write  //--------------------------------------------------------- @@ -167,10 +124,10 @@ void Scale::read(Xml& xml)        }  //--------------------------------------------------------- -//   readXmlPart +//   Part::readFromXml  //--------------------------------------------------------- -Part* readXmlPart(Xml& xml, Track* track, bool doClone, bool toTrack) +Part* Part::readFromXml(Xml& xml, Track* track, bool doClone, bool toTrack)        {        int id = -1;        Part* npart = 0; @@ -197,7 +154,7 @@ Part* readXmlPart(Xml& xml, Track* track, bool doClone, bool toTrack)                              {                                if(i->id == id) // Is a matching part found in the clone list?                                { -                                // This makes a clone, chains the part, and increases ref counts. +                                // Create a clone. It must still be added later in a operationgroup                                  npart = track->newPart((Part*)i->cp, true);                                  break;                                } @@ -242,7 +199,7 @@ Part* readXmlPart(Xml& xml, Track* track, bool doClone, bool toTrack)                                  if(!doClone && !isclone)                                    break; -                                // This makes a clone, chains the part, and increases ref counts. +                                // Create a clone. It must still be added later in a operationgroup                                  npart = track->newPart((Part*)i->cp, true);                                  break;                                } @@ -340,14 +297,6 @@ Part* readXmlPart(Xml& xml, Track* track, bool doClone, bool toTrack)                                  e.move( -npart->tick() );                                  int tick = e.tick();   -                                // DELETETHIS 7 -                                // Do not discard events belonging to clone parts, -                                //  at least not yet. A later clone might have a longer,  -                                //  fully accommodating part length! -                                //if ((tick < 0) || (tick >= (int) lenTick())) { -                                //if ((tick < 0) || ( id == -1 && !clone && (tick >= (int)lenTick()) ))  -                                // No way to tell at the moment whether there will be clones referencing this... -                                // No choice but to accept all events past 0.                                  if(tick < 0)                                   {                                    printf("readClone: warning: event at tick:%d not in part:%s, discarded\n", @@ -355,7 +304,7 @@ Part* readXmlPart(Xml& xml, Track* track, bool doClone, bool toTrack)                                  }                                  else                                   { -                                  npart->events()->add(e); +                                  npart->_events.add(e);                                  }                                      }                                else // ...Otherwise a clone was created, so we don't need the events. @@ -373,25 +322,6 @@ Part* readXmlPart(Xml& xml, Track* track, bool doClone, bool toTrack)                          else if (tag == "cloneId")                          {                            id = xml.s2().toInt(); -                          //if(id != -1) DELETETHIS 19 -                          //{ -                          //  for(iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)  -                          //  { -                              // Is a matching part found in the clone list? -                          //    if(i->id == id)  -                          //    { -                                // If it's a regular paste (not paste clone), and the original part is -                                //  not a clone, defer so that a new copy is created in TagStart above. -                                //if(!doClone && i->cp->cevents()->arefCount() <= 1) -                                //if(!doClone && !isclone) -                                //  break; -                                   -                                // This makes a clone, chains the part, and increases ref counts. -                          //      npart = track->newPart((Part*)i->cp, true); -                          //      break; -                          //    } -                          //  } -                          //}                            }                                else if (tag == "uuid")                          { @@ -399,55 +329,6 @@ Part* readXmlPart(Xml& xml, Track* track, bool doClone, bool toTrack)                            if(!uuid_is_null(uuid))                            {                              uuidvalid = true; -                            /* DELETETHIS 50 -                            for(iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)  -                            { -                              // Is a matching part found in the clone list? -                              if(uuid_compare(uuid, i->uuid) == 0)  -                              { -                                Track* cpt = i->cp->track(); -                                // If we want to paste to the given track... -                                if(toTrack) -                                { -                                  // If the given track type is not the same as the part's  -                                  //  original track type, we can't continue. Just return. -                                  if(!track || cpt->type() != track->type()) -                                  { -                                    xml.skip("part"); -                                    return 0; -                                  }   -                                } -                                else -                                // ...else we want to paste to the part's original track. -                                { -                                  // Make sure the track exists (has not been deleted). -                                  if((cpt->isMidiTrack() && MusEGlobal::song->midis()->find(cpt) != MusEGlobal::song->midis()->end()) ||  -                                     (cpt->type() == Track::WAVE && MusEGlobal::song->waves()->find(cpt) != MusEGlobal::song->waves()->end())) -                                    track = cpt;    -                                  else -                                  // Track was not found. Try pasting to the given track, as above... -                                  { -                                    if(!track || cpt->type() != track->type()) -                                    { -                                      // No luck. Just return. -                                      xml.skip("part"); -                                      return 0; -                                    }   -                                  } -                                } -                                 -                                // If it's a regular paste (not paste clone), and the original part is -                                //  not a clone, defer so that a new copy is created in TagStart above. -                                //if(!doClone && i->cp->cevents()->arefCount() <= 1) -                                if(!doClone && !isclone) -                                  break; -                                   -                                // This makes a clone, chains the part, and increases ref counts. -                                npart = track->newPart((Part*)i->cp, true); -                                break; -                              } -                            } -                            */                              }                          }                                else if(tag == "isclone")         @@ -471,7 +352,6 @@ Part* readXmlPart(Xml& xml, Track* track, bool doClone, bool toTrack)  void Part::write(int level, Xml& xml, bool isCopy, bool forceWavePaths) const        { -      const EventList* el = cevents();        int id              = -1;        uuid_t uuid;         uuid_clear(uuid); @@ -482,7 +362,7 @@ void Part::write(int level, Xml& xml, bool isCopy, bool forceWavePaths) const        {          for(iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)           { -          if(i->cp->cevents() == el)  +          if(i->cp->isCloneOf(this))             {              uuid_copy(uuid, i->uuid);              dumpEvents = false; @@ -498,11 +378,11 @@ void Part::write(int level, Xml& xml, bool isCopy, bool forceWavePaths) const        }          else        { -        if (el->arefCount() > 1)  +        if (this->hasClones())           {            for (iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)             { -            if (i->cp->cevents() == el)  +            if (i->cp->isCloneOf(this))               {                id = i->id;                dumpEvents = false; @@ -531,7 +411,7 @@ void Part::write(int level, Xml& xml, bool isCopy, bool forceWavePaths) const          else              xml.nput(level, "<part uuid=\"%s\"", sid); -        if(el->arefCount() > 1) +        if(hasClones())            xml.nput(" isclone=\"1\"");          xml.put(">");          level++;   @@ -552,292 +432,12 @@ void Part::write(int level, Xml& xml, bool isCopy, bool forceWavePaths) const        if (_mute)              xml.intTag(level, "mute", _mute);        if (dumpEvents) { -            for (ciEvent e = el->begin(); e != el->end(); ++e) +            for (ciEvent e = events().begin(); e != events().end(); ++e)                    e->second.write(level, xml, *this, forceWavePaths);              }        xml.etag(level, "part");        } -// DELETETHIS 280! whoa! -/* -//--------------------------------------------------------- -//   Part::read -//--------------------------------------------------------- - -void Part::read(Xml& xml, int, bool toTrack)    // int newPartOffset -      { -      int id = -1; -      bool containsEvents = false; -      uuid_t uuid;  -      uuid_clear(uuid); -      bool uuidvalid = false; -      bool clone = false; - -      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 == "name") -                              _name = xml.parse1(); -                        else if (tag == "poslen") { -                              PosLen::read(xml, "poslen"); -                              } -                        else if (tag == "pos") { -                              Pos pos; -                              pos.read(xml, "pos");  // obsolete -                              setTick(pos.tick()); -                              } -                        else if (tag == "len") { -                              Pos len; -                              len.read(xml, "len");  // obsolete -                              setLenTick(len.tick()); -                              } -                        else if (tag == "selected") -                              _selected = xml.parseInt(); -                        else if (tag == "color") -                              _colorIndex = xml.parseInt(); -                        else if (tag == "mute") -                              _mute = xml.parseInt(); -                        else if (tag == "event") { -                              containsEvents = true; -                              EventType type = Wave; -                              if (_track->isMidiTrack()) -                                    type = Note; -                              Event e(type); -                              e.read(xml); -                              // stored tickpos for event has absolute value. However internally -                              // tickpos is relative to start of part, we substract tick(). -                              // TODO: better handling for wave event -                              e.move(-tick()); -                              int tick = e.tick();   -                               -                              // Changed by T356. Do not discard events belonging to clone parts, -                              //  at least not yet. A later clone might have a longer,  -                              //  fully accommodating part length! -                              //if ((tick < 0) || (tick >= (int) lenTick())) { -                              if ((tick < 0) || ( id == -1 && !clone && (tick >= (int)lenTick()) ))  -                              { -                                    //printf("Part::read: warning: event not in part: %d - %d -%d, discarded\n", -                                    printf("Part::read: warning: event at tick:%d not in part:%s, discarded\n", -                                       tick, name().toLatin1().constData()); -                              } -                              else { -                                    _events->add(e); -*/                                     -                                     -                                     -                                    /* -                                    // TODO: This should NOT be done here since the event list -                                    //  might be deleted below. Since after reading a part it -                                    //  likely (always?) that (msg)AddPart() or (msg)ChangePart() -                                    //  will be called (must check if they're ever called BEFORE  -                                    //  Part::read), then those routines will take care of it, -                                    //  they are already coded to do so.  -                                    // Note the redundancy of doing it here AND (msg)Add/ChangePart ! -                                    // Try to eliminate this section altogether by verifying that -                                    //  (msg)Add/ChangePart (or one of the other routines which add port -                                    //  controller values) is always called after Part::read... -                                    if (e.type() == Controller) { -                                          MidiTrack* mt = (MidiTrack*)_track; -                                          int channel = mt->outChannel(); -                                          MidiPort* mp = &MusEGlobal::midiPorts[mt->outPort()]; -                                          // tick is relative to part, controller needs an absolute value hence -                                          // part offset is added. If newPartOffset was given we use that instead of -                                          // the recorded offset! -                                          if (!newPartOffset) -                                            newPartOffset=this->tick(); - -                                          int ctl = e.dataA(); -                                          if(mt->type() == Track::DRUM) -                                          { -                                            // Is it a drum controller event, according to the track port's instrument? -                                            MidiController* mc = mp->drumController(ctl); -                                            if(mc) -                                            { -                                              int note = ctl & 0x7f; -                                              ctl &= ~0xff; -                                              channel = drumMap[note].channel; -                                              mp = &MusEGlobal::midiPorts[drumMap[note].port]; -                                              ctl |= drumMap[note].anote; -                                            } -                                          }   -                                           -                                          // Removed by T356 -                                          // check if controller exists -                                          //if (mp->hwCtrlState(channel, e.dataA()) == CTRL_VAL_UNKNOWN) { -                                          //      mp->addManagedController(channel, e.dataA()); -                                          //      } -                                           -                                          // Changed by T356 -                                          // add controller value -                                          //mp->setCtrl(channel, tick+newPartOffset, e.dataA(), e.dataB()); -                                          mp->setControllerVal(channel, tick+newPartOffset, ctl, e.dataB(), this); -                                          } -                                      */ -/*                                     -                                    } -                              } -                        else -                              xml.unknown("Part::read"); -                        break; -                  case Xml::Attribut: -                        if (tag == "cloneId") -                              id = xml.s2().toInt(); -                        else if (tag == "uuid") -                              { -                                uuid_parse(xml.s2().toLatin1().constData(), uuid); -                                if(!uuid_is_null(uuid)) -                                  uuidvalid = true; -                              }   -                        else if (tag == "isclone") -                              clone = xml.s2().toInt(); -                        break; -                  case Xml::TagEnd: -                        if (tag == "part")  -                        { -*/                               -                              /* -                              if (id != -1)  -                              { -                                     -                                    // clone part -                                    if (containsEvents) { -                                          // add to MusEGlobal::cloneList: -                                          //ClonePart cp(_events, id); -                                          ClonePart cp(this, id); -                                          MusEGlobal::cloneList.push_back(cp); -                                          } -                                    else { -                                          // replace event list with clone event -                                          // list -                                          for (iClone i = MusEGlobal::cloneList.begin(); -                                             i != MusEGlobal::cloneList.end(); ++i) { -                                                if (i->id == id) { -                                                      delete _events; -                                                      //_events = (EventList*)(i->el); -                                                      _events = (EventList*)(i->cp->cevents()); -                                                      _events->incRef(1); -                                                      _events->incARef(1); -                                                      //i->cp->chainClone(this); -                                                      chainClone((Part*)i->cp, this); -                                                      break; -                                                      } -                                                } -                                          } -                                */           -                                           -/*                           -                          if(id != -1)  -                          { -                            // See if the part exists in the clone list.  -                            // The clone list is also the copy/paste clone list. -                            // Care must be taken to ensure the list is ALWAYS EMPTY  -                            //  before loading or dropping parts INTO muse, because the -                            //  current song parts are NOT the same as when the imported parts  -                            //  were created, (even if they were created from the current session, -                            //  we should NOT look them up). Always back up the list, clear it, -                            //  read part(s), then restore the list so that paste works after. -                            Part* cp = 0; -                            for(iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)  -                            {   -                              if(i->id == id)  -                              { -                                cp = (Part*)i->cp; -                                break; -                              } -                            } -                            // Was a matching part found in the clone list? -                            if(cp) -                            { -                              // Make this part a clone of that part. Use its event list... -                              delete _events; -                              _events = (EventList*)(cp->cevents()); -                              _events->incRef(1); -                              _events->incARef(1); -                              chainClone(cp, this); -                            } -                            else                                 -                            { -                              // No matching part to clone was found in the clone list.  -                              // Does the part contain some events? -                              //if(containsEvents)  -                              { -                                // Add the part to the clone list so that subsequent parts -                                //  can look it up and clone from it... -                                ClonePart ncp(this, id); -                                MusEGlobal::cloneList.push_back(ncp); -                              } -                              // Otherwise this part has no matching part in the clone list -                              //  and no events of its own. Nothing left to do, we now have  -                              //  a blank part with the original offset, colour etc. -                            } -                          } -                          else -                          // If a uuid was found, do the same as above. Using uuids   -                          //  allows foolproof rejection of copied parts not found  -                          //  in the clone list, particularly when copying parts from  -                          //  another instance of muse. -                          if(uuidvalid)  -                          { -                            Part* cp = 0; -                            for(iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)  -                            {   -                              if(uuid_compare(uuid, i->uuid) == 0)  -                              { -                                cp = (Part*)i->cp; -                                break; -                              } -                            } -                            // If a matching part was found, and we want to paste to the original track... -                            if(cp && !toTrack) -                            { -                              // Make sure the track exists (has not been deleted). -                              if((cp->track()->isMidiTrack() && MusEGlobal::song->midis()->find(cp->track()) != MusEGlobal::song->midis()->end()) ||  -                                 (cp->track()->type() == Track::WAVE && MusEGlobal::song->waves()->find(cp->track()) != MusEGlobal::song->waves()->end())) -                                setTrack(cp->track()); -                            }   -                            // Was a matching part found in the clone list, and was it  -                            //  originally a clone part? -                            if(cp && clone) -                            { -                              // Make this part a clone of that part. Use its event list... -                              delete _events; -                              _events = (EventList*)(cp->cevents()); -                              _events->incRef(1); -                              _events->incARef(1); -                              // Chain the clone. -                              // Use the slower function which makes sure it chains to a part -                              //  within a valid (non-deleted) track. -                              //chainClone(cp, this); -                              chainClone(this); -                            } -                            else                                 -                            { -                              // No matching part to clone was found in the clone list.  -                              // Does the part contain some events? -                              //if(containsEvents)  -                              { -                                // Add the part to the clone list so that subsequent parts -                                //  can look it up and clone from it... -                                ClonePart ncp(this); -                                // New ClonePart creates its own uuid, but we need to replace it. -                                uuid_copy(ncp.uuid, uuid); -                                MusEGlobal::cloneList.push_back(ncp); -                              } -                            } -                          } -                          return; -                        } -                  default: -                        break; -                  } -            } -      } -*/  //---------------------------------------------------------  //   writeFont diff --git a/muse2/muse/steprec.cpp b/muse2/muse/steprec.cpp index 723fe650..44da5a7e 100644 --- a/muse2/muse/steprec.cpp +++ b/muse2/muse/steprec.cpp @@ -55,7 +55,7 @@ void StepRec::timeout()  	}  } -void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ctrl, bool shift, int incoming_pitch) +void StepRec::record(const Part* part, int pitch, int len, int step, int velo, bool ctrl, bool shift, int incoming_pitch)  {  	unsigned tick = MusEGlobal::song->cpos();  	unsigned lasttick=0; @@ -76,12 +76,12 @@ void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ct  		chord_timer->stop();  		// extend len of last note? -		EventList* events = part->events(); +		const EventList& events = part->events();  		if (ctrl)  		{ -			for (iEvent i = events->begin(); i != events->end(); ++i) +			for (ciEvent i = events.begin(); i != events.end(); ++i)  			{ -				Event ev = i->second; +				const Event& ev = i->second;  				if (ev.isNote() && ev.pitch() == pitch && ((ev.tick() + ev.lenTick() + part->tick()) == tick))  				{  					Event e = ev.clone(); @@ -106,13 +106,13 @@ void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ct  			// if we would find a note after part->lenTick(), the above "if"  			// avoids this. this has to be avoided because then part->hasHiddenEvents() is true  			// which results in forbidding any action beyond its end -			EventRange range = events->equal_range(tick - part->tick()); -			for (iEvent i = range.first; i != range.second; ++i) +			EventRange range = events.equal_range(tick - part->tick()); +			for (ciEvent i = range.first; i != range.second; ++i)  			{ -				Event ev = i->second; +				const Event& ev = i->second;  				if (ev.isNote() && ev.pitch() == pitch)  				{ -					MusEGlobal::audio->msgDeleteEvent(ev, part, true, false, false); +					MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeleteEvent,ev, part, true,true));  					if (!shift)  					{ @@ -161,18 +161,18 @@ void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ct  			// extend len of last note(s)  			using std::set; -			set<Event*> extend_set; -			EventList* events = part->events(); -			for (iEvent i = events->begin(); i != events->end(); ++i) +			set<const Event*> extend_set; +			const EventList& events = part->events(); +			for (ciEvent i = events.begin(); i != events.end(); ++i)  			{ -				Event& ev = i->second; +				const Event& ev = i->second;  				if (ev.isNote() && note_held_down[ev.pitch()] && ((ev.tick() + ev.lenTick() + part->tick()) == tick))  					extend_set.insert(&ev);  			} -			for (set<Event*>::iterator it=extend_set.begin(); it!=extend_set.end(); it++) +			for (set<const Event*>::iterator it=extend_set.begin(); it!=extend_set.end(); it++)  			{ -				Event& ev=**it; +				const Event& ev=**it;  				Event e = ev.clone();  				e.setLenTick(ev.lenTick() + len);  				operations.push_back(UndoOp(UndoOp::ModifyEvent,e, ev, part, false, false)); diff --git a/muse2/muse/steprec.h b/muse2/muse/steprec.h index a82cab20..f99fffc4 100644 --- a/muse2/muse/steprec.h +++ b/muse2/muse/steprec.h @@ -37,7 +37,7 @@ class StepRec : public QObject  	public:  		StepRec(bool* note_held_down_array); -		void record(Part* part,  int recorded_pitch, int len, int step, int velo=80, bool ctrl=false, bool shift=false, int incoming_pitch=1337); +		void record(const Part* part,  int recorded_pitch, int len, int step, int velo=80, bool ctrl=false, bool shift=false, int incoming_pitch=1337);  	private slots:  	  void timeout(); diff --git a/muse2/muse/structure.cpp b/muse2/muse/structure.cpp index 65489cac..0c1d673d 100644 --- a/muse2/muse/structure.cpp +++ b/muse2/muse/structure.cpp @@ -5,6 +5,7 @@  //  //  (C) Copyright 1999-2004 Werner Schweer (ws@seh.de)  //  (C) Copyright 2011  Robert Jonsson (rj@spamatica.se) +//  (C) Copyright 2013  Florian Jung (flo93@sourceforge.net)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -161,19 +162,15 @@ void globalCut(bool onlySelectedTracks)                    else if ((t < lpos) && ((t+l) > lpos) && ((t+l) <= rpos)) {                        // remove part tail                        int len = lpos - t; -                      Part *nPart; -                      if (track->isMidiTrack()) -                        nPart = new MidiPart(*(MidiPart*)part); -                      else -                        nPart = new WavePart(*(WavePart*)part); - -                      nPart->setLenTick(len); -                      // cut Events in nPart -                      EventList* el = nPart->events(); -                      for (iEvent ie = el->lower_bound(len); ie != el->end(); ++ie) -                            operations.push_back(UndoOp(UndoOp::DeleteEvent,ie->second, nPart, false, false)); - -                      operations.push_back(UndoOp(UndoOp::ModifyPart,part, nPart, true, true)); +                       +                      if (part->nextClone()==part) // no clones +                      { +                            // cut Events +                            const EventList& el = part->events(); +                            for (ciEvent ie = el.lower_bound(len); ie != el.end(); ++ie) +                                    operations.push_back(UndoOp(UndoOp::DeleteEvent,ie->second, part, false, false)); +                      } +                      operations.push_back(UndoOp(UndoOp::ModifyPartLength, part, part->lenTick(), len, true, true));                    }                    else if ((t < lpos) && ((t+l) > lpos) && ((t+l) > rpos)) {                          //---------------------- @@ -182,16 +179,15 @@ void globalCut(bool onlySelectedTracks)                          Part* p1;                          Part* p2;                          Part* p3; -                        track->splitPart(part, lpos, p1, p2); +                        part->splitPart(lpos, p1, p2);                          delete p2; -                        track->splitPart(part, rpos, p2, p3); +                        part->splitPart(rpos, p2, p3);                          delete p2;                          p3->setTick(lpos); -                        p1->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ -                        p3->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ -                        // Indicate no undo, and do port controller values and clone parts. -                        operations.push_back(UndoOp(UndoOp::ModifyPart,part, p1, true, true)); +                        MusEGlobal::song->informAboutNewParts(part,p1,p3); +                        operations.push_back(UndoOp(UndoOp::DeletePart,part)); +                        operations.push_back(UndoOp(UndoOp::AddPart,p1));                          operations.push_back(UndoOp(UndoOp::AddPart,p3));                          }                    else if ((t >= lpos) && (t < rpos) && (t+l) > rpos) { @@ -199,23 +195,18 @@ void globalCut(bool onlySelectedTracks)                          Part* p1;                          Part* p2; -                        track->splitPart(part, rpos, p1, p2); +                        part->splitPart(rpos, p1, p2);                          delete p1;                          p2->setTick(lpos); -                        p2->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ -                        operations.push_back(UndoOp(UndoOp::ModifyPart,part, p2, true, true)); +                         +                        MusEGlobal::song->informAboutNewParts(part,p2); +                        operations.push_back(UndoOp(UndoOp::DeletePart,part)); +                        operations.push_back(UndoOp(UndoOp::AddPart,p2));                          }                    else if (t >= rpos) {                          // move part to the left -                        Part *nPart; -                        if (track->isMidiTrack()) -                          nPart = new MidiPart(*(MidiPart*)part); -                        else -                          nPart = new WavePart(*(WavePart*)part);                          int nt = part->tick(); -                        nPart->setTick(nt - (rpos -lpos)); -                        // Indicate no undo, and do port controller values but not clone parts. -                        operations.push_back(UndoOp(UndoOp::ModifyPart,part, nPart, true, false)); +                        operations.push_back(UndoOp(UndoOp::ModifyPartTick,part,part->tick(), nt - (rpos -lpos) ));                          }                    }              } @@ -263,22 +254,16 @@ Undo movePartsTotheRight(unsigned int startTicks, int moveTicks, bool only_selec                          // split part to insert new space                          Part* p1;                          Part* p2; -                        track->splitPart(part, startTicks, p1, p2); +                        part->splitPart(startTicks, p1, p2);                          p2->setTick(startTicks+moveTicks); -                        p2->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ -                        p1->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ -                        operations.push_back(UndoOp(UndoOp::ModifyPart, part, p1, true, true)); +                        MusEGlobal::song->informAboutNewParts(part,p1,p2); +                        operations.push_back(UndoOp(UndoOp::DeletePart, part)); +                        operations.push_back(UndoOp(UndoOp::AddPart, p1));                          operations.push_back(UndoOp(UndoOp::AddPart, p2));                          }                    else if (t >= startTicks) { -                        Part *nPart; -                        if (track->isMidiTrack()) -                          nPart = new MidiPart(*(MidiPart*)part); -                        else -                          nPart = new WavePart(*(WavePart*)part); -                        nPart->setTick(t + moveTicks); -                        operations.push_back(UndoOp(UndoOp::ModifyPart, part, nPart, true, false)); +                        operations.push_back(UndoOp(UndoOp::ModifyPartTick, part, part->tick(), t + moveTicks));                          }                    }              } @@ -318,24 +303,17 @@ Undo partSplitter(unsigned int pos, bool onlySelectedTracks)                if (pos > p1 && pos < (p1+l0)) {                      Part* p1;                      Part* p2; -                    track->splitPart(part, pos, p1, p2); +                    part->splitPart(pos, p1, p2); -                    p1->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it -                    p2->events()->incARef(-1); // so we must decrement it first :/ - -                    //MusEGlobal::song->informAboutNewParts(part, p1); // is unneccessary because of ModifyPart +                    MusEGlobal::song->informAboutNewParts(part, p1);                      MusEGlobal::song->informAboutNewParts(part, p2); -                    operations.push_back(UndoOp(UndoOp::ModifyPart,part, p1, true, false)); +                    operations.push_back(UndoOp(UndoOp::DeletePart,part)); +                    operations.push_back(UndoOp(UndoOp::AddPart,p1));                      operations.push_back(UndoOp(UndoOp::AddPart,p2)); -                    if (MusEGlobal::debugMsg) -                    { -                          printf("in partSplitter: part1 %d\n",p1->events()->refCount()); -                          printf("in partSplitter: part2 %d\n",p2->events()->refCount()); -                          }                      break; -                    }                }          } +    }      return operations;  } diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp index d8d09048..32568e31 100644 --- a/muse2/muse/synth.cpp +++ b/muse2/muse/synth.cpp @@ -696,11 +696,7 @@ SynthI* Song::createSynthI(const QString& sclass, const QString& label, Synth::T        int idx = insertAt ? _tracks.index(insertAt) : -1; -      insertTrack1(si, idx); -       -      msgInsertTrack(si, idx, true);       // add to instance list -       -      insertTrack3(si, idx); +      MusEGlobal::song->applyOperation(UndoOp(UndoOp::AddTrack, idx, si));        OutputList* ol = MusEGlobal::song->outputs();        // add default route to master (first audio output) diff --git a/muse2/muse/track.cpp b/muse2/muse/track.cpp index cc1e56ac..8d30fccb 100644 --- a/muse2/muse/track.cpp +++ b/muse2/muse/track.cpp @@ -66,9 +66,9 @@ void addPortCtrlEvents(MidiTrack* t)    for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)    {      Part* part = ip->second; -    const EventList* el = part->cevents(); +    const EventList& el = part->events();      unsigned len = part->lenTick(); -    for(ciEvent ie = el->begin(); ie != el->end(); ++ie) +    for(ciEvent ie = el.begin(); ie != el.end(); ++ie)      {        const Event& ev = ie->second;        // Added by T356. Do not add events which are past the end of the part. @@ -116,8 +116,8 @@ void removePortCtrlEvents(MidiTrack* t)    for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)    {      Part* part = ip->second; -    const EventList* el = part->cevents(); -    for(ciEvent ie = el->begin(); ie != el->end(); ++ie) +    const EventList& el = part->events(); +    for(ciEvent ie = el.begin(); ie != el.end(); ++ie)      {        const Event& ev = ie->second; @@ -468,8 +468,6 @@ MidiTrack::MidiTrack()     : Track(MIDI)        {        init(); -      _events = new EventList; -      _mpevents = new MPEventList;        clefType=trebleClef;        _drummap=new DrumMap[128]; @@ -481,9 +479,6 @@ MidiTrack::MidiTrack()  MidiTrack::MidiTrack(const MidiTrack& mt, int flags)    : Track(mt, flags)  { -      _events   = new EventList; -      _mpevents = new MPEventList; -        _drummap=new DrumMap[128];        _drummap_hidden=new bool[128]; @@ -592,27 +587,11 @@ void MidiTrack::internal_assign(const Track& t, int flags)          const PartList* pl = t.cparts();          for (ciPart ip = pl->begin(); ip != pl->end(); ++ip) {                Part* spart = ip->second; -              bool clone = spart->events()->arefCount() > 1; -              // This increments aref count if cloned, and chains clones. -              // It also gives the new part a new serial number. -              Part* dpart = newPart(spart, clone); -              if(!clone) { -                    // Copy Events -                    MusECore::EventList* se = spart->events(); -                    MusECore::EventList* de = dpart->events(); -                    for (MusECore::iEvent i = se->begin(); i != se->end(); ++i) { -                          MusECore::Event oldEvent = i->second; -                          MusECore::Event ev = oldEvent.clone(); -                          de->add(ev); -                          } -                    } - -              // TODO: Should we include the parts in the undo?       -              //      dpart->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it -              //                                    // so we must decrement it first :/ -              //      // These will not increment ref count, and will not chain clones... -              //      // DELETETHIS: is the above comment still correct (by flo93)? i doubt it! -              //      operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddPart,dpart)); +              Part* dpart; +              if (spart->hasClones()) +                  dpart = spart->createNewClone(); +              else +                  dpart = spart->duplicate();                parts()->add(dpart);                } @@ -628,8 +607,6 @@ void MidiTrack::assign(const Track& t, int flags)  MidiTrack::~MidiTrack()        { -      delete _events; -      delete _mpevents;        delete [] _drummap;        delete [] _drummap_hidden; @@ -803,90 +780,6 @@ void MidiTrack::setInPortAndChannelMask(unsigned int portmask, int chanmask)    }    } -/* DELETETHIS 84 -//--------------------------------------------------------- -//   addPortCtrlEvents -//--------------------------------------------------------- - -void MidiTrack::addPortCtrlEvents() -{ -  const PartList* pl = cparts(); -  for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) -  { -    Part* part = ip->second; -    const EventList* el = part->cevents(); -    for(ciEvent ie = el->begin(); ie != el->end(); ++ie) -    { -      const Event& ev = ie->second; -      if(ev.type() == Controller) -      { -        int tick  = ev.tick() + part->tick(); -        int cntrl = ev.dataA(); -        int val   = ev.dataB(); -        int ch = _outChannel; -         -        MidiPort* mp = &MusEGlobal::midiPorts[_outPort]; -        // Is it a drum controller event, according to the track port's instrument? -        if(type() == DRUM) -        { -          MidiController* mc = mp->drumController(cntrl); -          if(mc) -          { -            int note = cntrl & 0x7f; -            cntrl &= ~0xff; -            ch = MusEGlobal::drumMap[note].channel; -            mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[note].port]; -            cntrl |= MusEGlobal::drumMap[note].anote; -          } -        } -         -        mp->setControllerVal(ch, tick, cntrl, val, part); -      } -    } -  } -} - -//--------------------------------------------------------- -//   removePortCtrlEvents -//--------------------------------------------------------- - -void MidiTrack::removePortCtrlEvents() -{ -  const PartList* pl = cparts(); -  for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) -  { -    Part* part = ip->second; -    const EventList* el = part->cevents(); -    for(ciEvent ie = el->begin(); ie != el->end(); ++ie) -    { -      const Event& ev = ie->second; -      if(ev.type() == Controller) -      { -        int tick  = ev.tick() + part->tick(); -        int cntrl = ev.dataA(); -        int ch = _outChannel; -         -        MidiPort* mp = &MusEGlobal::midiPorts[_outPort]; -        // Is it a drum controller event, according to the track port's instrument? -        if(type() == DRUM) -        { -          MidiController* mc = mp->drumController(cntrl); -          if(mc) -          { -            int note = cntrl & 0x7f; -            cntrl &= ~0xff; -            ch = MusEGlobal::drumMap[note].channel; -            mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[note].port]; -            cntrl |= MusEGlobal::drumMap[note].anote; -          } -        } -         -        mp->deleteController(ch, tick, cntrl, part); -      } -    } -  } -} -*/  //---------------------------------------------------------  //   newPart @@ -894,7 +787,16 @@ void MidiTrack::removePortCtrlEvents()  Part* MidiTrack::newPart(Part*p, bool clone)        { -      MidiPart* part = clone ? new MidiPart(this, p->events()) : new MidiPart(this); +      MidiPart* part; +      if (clone) +      { +            part = (MidiPart*)p->createNewClone(); +            part->setTrack(this); +      } +      else +            part= new MidiPart(this); +       +              if (p) {              part->setName(p->name());              part->setColorIndex(p->colorIndex()); @@ -903,10 +805,6 @@ Part* MidiTrack::newPart(Part*p, bool clone)              part->setMute(p->mute());              } -      if(clone) -        //p->chainClone(part); -        chainClone(p, part); -              return part;        } @@ -1004,7 +902,7 @@ void MidiTrack::read(Xml& xml)              switch (token) {                    case Xml::Error:                    case Xml::End: -                        return; +                        goto out_of_MidiTrackRead_forloop;                    case Xml::TagStart:                          if (tag == "transposition")                                transposition = xml.parseInt(); @@ -1017,10 +915,7 @@ void MidiTrack::read(Xml& xml)                          else if (tag == "compression")                                compression = xml.parseInt();                          else if (tag == "part") { -                              //Part* p = newPart(); -                              //p->read(xml); -                              Part* p = 0; -                              p = readXmlPart(xml, this); +                              Part* p = Part::readFromXml(xml, this);                                if(p)                                  parts()->add(p);                                } @@ -1094,12 +989,15 @@ void MidiTrack::read(Xml& xml)                          if (tag == "miditrack" || tag == "drumtrack" || tag == "newdrumtrack")                           {                            setInPortAndChannelMask(portmask, chanmask); // Support old files. -                          return; +                          goto out_of_MidiTrackRead_forloop;                          }                    default:                          break;                    }              } +       +out_of_MidiTrackRead_forloop: +      chainTrackParts(this);        }  void MidiTrack::readOurDrumSettings(Xml& xml) @@ -1335,7 +1233,7 @@ int MidiTrack::getFirstControllerValue(int ctrl, int def)    {      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++) +    for (ciEvent eit=part->events().begin(); eit!=part->events().end(); eit++)      {        if (eit->first+part->tick() >= tick) break;        if (eit->first > part->lenTick()) break; // ignore events past the end of the part @@ -1359,7 +1257,7 @@ int MidiTrack::getControllerChangeAtTick(unsigned tick, int ctrl, int def)      Part* part=pit->second;      if (part->tick() > tick) break; // ignore this and the rest. we'd find nothing any more      if (part->endTick() < tick) continue; // ignore only this. -    for (iEvent eit=part->events()->begin(); eit!=part->events()->end(); eit++) +    for (ciEvent eit=part->events().begin(); eit!=part->events().end(); eit++)      {        if (eit->first+part->tick() > tick) break; // we won't find anything in this part from now on.        if (eit->first > part->lenTick()) break; // ignore events past the end of the part @@ -1385,7 +1283,7 @@ unsigned MidiTrack::getControllerValueLifetime(unsigned tick, int ctrl)      Part* part=pit->second;      if (part->tick() > result) break; // ignore this and the rest. we won't find anything new.      if (part->endTick() < tick) continue; // ignore only this part, we won't find anything there. -    for (iEvent eit=part->events()->begin(); eit!=part->events()->end(); eit++) +    for (ciEvent eit=part->events().begin(); eit!=part->events().end(); eit++)      {        if (eit->first+part->tick() >= result) break;        if (eit->first > part->lenTick()) break; // ignore events past the end of the part diff --git a/muse2/muse/track.h b/muse2/muse/track.h index 664364ba..f3551ce0 100644 --- a/muse2/muse/track.h +++ b/muse2/muse/track.h @@ -32,6 +32,7 @@  #include "wave.h" // for SndFileR  #include "part.h" +#include "mpevent.h"  #include "key.h"  #include "node.h"  #include "route.h" @@ -41,7 +42,6 @@  #include "controlfifo.h"  namespace MusECore { -class MPEventList;  class Pipeline;  class PluginI;  class SynthI; @@ -158,7 +158,6 @@ class Track {        virtual Part* newPart(Part*p=0, bool clone = false) = 0;        void dump() const; -      virtual void splitPart(Part*, int, Part*&, Part*&);        virtual void setMute(bool val);        virtual void setOff(bool val); @@ -212,8 +211,11 @@ class MidiTrack : public Track {        int _outChannel;        bool _recEcho;              // For midi (and audio). Whether to echo incoming record events to output device. -      EventList* _events;     // tmp Events during midi import -      MPEventList* _mpevents; // tmp Events druring recording +   public: +      EventList events;     // tmp Events during midi import +      MPEventList mpevents; // tmp Events druring recording + +   private:        static bool _isVisible;        clefTypes clefType; @@ -255,9 +257,6 @@ class MidiTrack : public Track {        virtual bool setRecordFlag1(bool f) { _recordFlag = f; return true;}        virtual void setRecordFlag2(bool) {} -      EventList* events() const          { return _events; } -      MPEventList* mpevents() const      { return _mpevents; } -        virtual void read(Xml&);        virtual void write(int, Xml&) const; diff --git a/muse2/muse/undo.cpp b/muse2/muse/undo.cpp index fc6fc1d8..103b47ac 100644 --- a/muse2/muse/undo.cpp +++ b/muse2/muse/undo.cpp @@ -21,6 +21,8 @@  //  //========================================================= +#include "assert.h" +  //#include "sig.h"  #include "al/sig.h"    #include "keyevent.h" @@ -50,8 +52,9 @@ const char* UndoOp::typeName()        {        static const char* name[] = {              "AddTrack", "DeleteTrack",  -            "AddPart",  "DeletePart",  "ModifyPart", -            "AddEvent", "DeleteEvent", "ModifyEvent", +            "AddPart",  "DeletePart",  "ModifyPartTick", "ModifyPartLength", "ModifyPartLengthFrames", "ModifyPartName", "SelectPart", +            "MovePartToTrack", +            "AddEvent", "DeleteEvent", "ModifyEvent", "SelectEvent",              "AddTempo", "DeleteTempo",              "AddSig", "DeleteSig",              "AddKey", "DeleteKey", @@ -77,7 +80,11 @@ void UndoOp::dump()                    break;              case AddPart:              case DeletePart: -            case ModifyPart: +            case ModifyPartTick: +            case ModifyPartLength: +            case ModifyPartLengthFrames: +            case ModifyPartName: +            case MovePartToTrack:                    break;              case AddEvent:              case DeleteEvent: @@ -132,15 +139,11 @@ void UndoList::clearDelete()            {              case UndoOp::DeleteTrack:                    if(i->track) -                    delete i->track; +                    delete const_cast<Track*>(i->track);                    break;              case UndoOp::DeletePart: -                  delete i->oPart; -                  break; - -            case UndoOp::ModifyPart: -                  delete i->oPart; +                  delete const_cast<Part*>(i->part);                    break;              case UndoOp::ModifyMarker: @@ -176,12 +179,9 @@ void UndoList::clearDelete()                    break;              case UndoOp::AddPart: -                  delete i->oPart; +                  delete i->part;                    break; -            case UndoOp::ModifyPart: -                  delete i->nPart; -                  break;              case UndoOp::ModifyMarker:                    if (i->realMarker)                      delete i->realMarker; @@ -213,9 +213,9 @@ void UndoList::clearDelete()  void Song::startUndo()        {        redoList->clearDelete(); // redo must be invalidated when a new undo is started -			MusEGlobal::redoAction->setEnabled(false); +      MusEGlobal::redoAction->setEnabled(false);        setUndoRedoText(); -			 +              undoList->push_back(Undo());        updateFlags = 0;        undoMode = true; @@ -227,6 +227,15 @@ void Song::startUndo()  void Song::endUndo(SongChangedFlags_t flags)        { +      riUndo prev_undo = undoList->rbegin(); +      prev_undo++; +      if (prev_undo!=undoList->rend()) +      { +            // try to merge the current Undo with the last one +            if (prev_undo->merge_combo(undoList->back())) +                  undoList->pop_back(); +      } +              updateFlags |= flags;        endMsgCmd();        undoMode = false; @@ -276,12 +285,49 @@ void Song::setUndoRedoText()  } -void cleanOperationGroup(Undo& group) +bool Undo::merge_combo(const Undo& other)  { -	using std::set; +	if (this->combobreaker || other.combobreaker) +		return false; +	 +	bool has_select_event=false; +	bool has_select_part=false; +	bool has_other=false; +	 +	for (ciUndoOp op=this->begin(); op!=this->end(); op++) +		switch(op->type) +		{ +			case UndoOp::DoNothing: break; +			case UndoOp::SelectEvent: has_select_event=true; break; +			case UndoOp::SelectPart: has_select_part=true; break; +			default: has_other=true; break; +		} +	 +	for (ciUndoOp op=other.begin(); op!=other.end(); op++) +		switch(op->type) +		{ +			case UndoOp::DoNothing: break; +			case UndoOp::SelectEvent: has_select_event=true; break; +			case UndoOp::SelectPart: has_select_part=true; break; +			default: has_other=true; break; +		} +	 +	bool mergeable = (has_select_event && !has_select_part && !has_other) || +	                 (has_select_part && !has_select_event && !has_other); +	 +	if (mergeable) +		this->insert(this->end(), other.begin(), other.end()); +	 +	return mergeable; +} + +void prepareOperationGroup(Undo& group) +{ +	QSet<const Track*> deleted_tracks; +	QSet<const Part*> deleted_parts; + +	int songlen = MusEGlobal::song->len(); -	set<Track*> processed_tracks; -	set<Part*> processed_parts;  	for (iUndoOp op=group.begin(); op!=group.end();)  	{ @@ -290,46 +336,108 @@ void cleanOperationGroup(Undo& group)  		if (op->type==UndoOp::DeleteTrack)  		{ -			if (processed_tracks.find(op->track)!=processed_tracks.end()) +			if (deleted_tracks.contains(op->track)) +			{  				group.erase(op); +			}  			else -				processed_tracks.insert(op->track); +			{ +				const PartList* pl = op->track->cparts(); +				for (ciPart part = pl->begin(); part != pl->end(); part++) +					if (!deleted_parts.contains(part->second)) +					{ +						// they will be inserted between op and op_ +						// because we set op=op_ below, the inserted +						// elements will be skipped. +						group.insert(op, UndoOp(UndoOp::DeletePart, part->second)); +						deleted_parts.insert(part->second); +					} +					 +				deleted_tracks.insert(op->track); +			}  		} -		else if ((op->type==UndoOp::ModifyPart) || (op->type==UndoOp::DeletePart)) +		else if (op->type==UndoOp::DeletePart)  		{ -			if (processed_parts.find(op->oPart)!=processed_parts.end()) +			if (deleted_parts.contains(op->part))  				group.erase(op);  			else -				processed_parts.insert(op->oPart); +				deleted_parts.insert(op->part); +		} +		else if (op->type==UndoOp::AddPart || op->type==UndoOp::ModifyPartLength || +		         op->type==UndoOp::ModifyPartTick) +		{ +			if (op->type==UndoOp::AddPart) +			{ +				if (songlen < op->part->endTick()) +					songlen = op->part->endTick(); +			} +			else if (op->type==UndoOp::ModifyPartTick) +			{ +				if (songlen < op->new_partlen_or_tick+op->part->lenTick()) +					songlen = op->new_partlen_or_tick+op->part->lenTick(); +			} +			else if (op->type==UndoOp::ModifyPartLength) +			{ +				if (songlen < op->part->tick()+op->new_partlen_or_tick) +					songlen=op->part->tick()+op->new_partlen_or_tick; +			}  		}  		op=op_;  	} +	 +	if (songlen >= MusEGlobal::song->len()) +		group.push_back(UndoOp(UndoOp::ModifySongLen, songlen, MusEGlobal::song->len())); +	 +	// replicate Event modifications to keep clones up to date. +	// do not replicate SelectEvent because... umm, it just doesn't feel right. +	for (iUndoOp op=group.begin(); op!=group.end(); op++) +	{ +		if (op->type==UndoOp::AddEvent || op->type==UndoOp::DeleteEvent || op->type==UndoOp::ModifyEvent) +		{ +			for (const Part* it = op->part->nextClone(); it!=op->part; it=it->nextClone()) +			{ +				UndoOp newop; +				if (op->type==UndoOp::AddEvent) // we need to clone the event +					newop = UndoOp(UndoOp::AddEvent, op->nEvent.clone(), it, op->doCtrls, op->doClones); +				else if (op->type==UndoOp::DeleteEvent) +					newop = UndoOp(UndoOp::DeleteEvent, it->events().findSimilar(op->nEvent)->second, it, op->doCtrls, op->doClones); +				else if (op->type==UndoOp::ModifyEvent) +					newop = UndoOp(UndoOp::ModifyEvent, op->nEvent.clone(), it->events().findSimilar(op->oEvent)->second, it, op->doCtrls, op->doClones); +				 +				group.insert(op, newop); +			} +		} +	}  } +bool Song::applyOperation(const UndoOp& op, bool doUndo) +{ +	Undo operations; +	operations.push_back(op); +	return applyOperationGroup(operations, doUndo); +}  bool Song::applyOperationGroup(Undo& group, bool doUndo)  {        if (!group.empty())        { -            cleanOperationGroup(group); -            //this is a HACK! but it works :)    (added by flo93) -            redoList->push_back(group); -            redo(); +            prepareOperationGroup(group); -            if (!doUndo) -            { -                  undoList->pop_back(); -                  MusEGlobal::undoAction->setEnabled(!undoList->empty()); -                  setUndoRedoText(); -            } -            else -            { -                  redoList->clearDelete(); // redo must be invalidated when a new undo is started -                  MusEGlobal::redoAction->setEnabled(false); -                  setUndoRedoText(); -            } +            if (doUndo) +                 startUndo(); + +            MusEGlobal::audio->msgExecuteOperationGroup(group); +            // append all elements from "group" to the end of undoList->back(). +            Undo& curUndo = undoList->back(); +            curUndo.insert(curUndo.end(), group.begin(), group.end()); +            if (group.combobreaker) +               curUndo.combobreaker=true; +             +            if (doUndo) +                 endUndo(0); +              return doUndo;        }        else @@ -339,22 +447,24 @@ bool Song::applyOperationGroup(Undo& group, bool doUndo)  //--------------------------------------------------------- -//   doUndo2 +//   revertOperationGroup2  //    real time part  //--------------------------------------------------------- -void Song::doUndo2() +void Song::revertOperationGroup2(Undo& operations)        { -      Undo& u = undoList->back(); -      for (riUndoOp i = u.rbegin(); i != u.rend(); ++i) { +      for (riUndoOp i = operations.rbegin(); i != operations.rend(); ++i) { +            Track* editable_track = const_cast<Track*>(i->track); +// uncomment if needed            Track* editable_property_track = const_cast<Track*>(i->_propertyTrack); +            Part* editable_part = const_cast<Part*>(i->part);              switch(i->type) {                    case UndoOp::AddTrack: -                        removeTrack2(i->track); +                        removeTrack2(editable_track);                          updateFlags |= SC_TRACK_REMOVED;                          break; -                  case UndoOp::DeleteTrack: -                        insertTrack2(i->track, i->trackno); -                        chainTrackParts(i->track, true); +                  case UndoOp::DeleteTrack: // FINDMICHJETZT FIXME TODO: DeletePart on all parts, only empty tracks may be deleted! this removes the necessarity of un... +                        insertTrack2(editable_track, i->trackno); +                        chainTrackParts(editable_track);                          updateFlags |= SC_TRACK_INSERTED;                          break; @@ -369,49 +479,55 @@ void Song::doUndo2()                          }                          break;                    case UndoOp::AddPart: -                        { -                        Part* part = i->oPart; -                        removePart(part); +                        removePart(editable_part);                          updateFlags |= SC_PART_REMOVED; -                        i->oPart->events()->incARef(-1); -                        unchainClone(i->oPart); -                        } +                        editable_part->unchainClone();                          break;                    case UndoOp::DeletePart: -                        addPart(i->oPart); +                        addPart(editable_part);                          updateFlags |= SC_PART_INSERTED; -                        i->oPart->events()->incARef(1); -                        chainClone(i->oPart); +                        editable_part->rechainClone();                          break; -                  case UndoOp::ModifyPart: -                        if(i->doCtrls) -                          removePortCtrlEvents(i->nPart, i->doClones); -                        changePart(i->nPart, i->oPart); -                        i->nPart->events()->incARef(-1); -                        i->oPart->events()->incARef(1); -                        replaceClone(i->nPart, i->oPart); -                        if(i->doCtrls) -                          addPortCtrlEvents(i->oPart, i->doClones); +                  case UndoOp::MovePartToTrack: +                        removePart(editable_part); // remove it from the track it currently lives on. (does not touch the clone chain) +                        editable_part->setTrack(const_cast<Track*>(i->oldTrack)); +                        addPart(editable_part); // add it to the track we just set. +                        updateFlags |= SC_PART_INSERTED | SC_PART_REMOVED; +                        break; +                  case UndoOp::ModifyPartName: +                        editable_part->setName(i->_oldName); +                        updateFlags |= SC_PART_MODIFIED; +                        break; +                  case UndoOp::ModifyPartTick: // TODO FIXME (?) do port ctrls/clones? +                        editable_part->setTick(i->old_partlen_or_tick); +                        updateFlags |= SC_PART_MODIFIED; +                        break; +                  case UndoOp::ModifyPartLength: // TODO FIXME (?) do port ctrls/clones? +                        editable_part->setLenTick(i->old_partlen_or_tick); +                        updateFlags |= SC_PART_MODIFIED; +                        break; +                  case UndoOp::ModifyPartLengthFrames: // TODO FIXME  FINDMICH frames deprecated!   do port ctrls/clones? +                        editable_part->setLenFrame(i->old_partlen_or_tick);                          updateFlags |= SC_PART_MODIFIED;                          break;                    case UndoOp::AddEvent:                          if(i->doCtrls) -                          removePortCtrlEvents(i->nEvent, i->part, i->doClones); -                        deleteEvent(i->nEvent, i->part); +                          removePortCtrlEvents(i->nEvent, editable_part, i->doClones); +                        deleteEvent(i->nEvent, editable_part);                          updateFlags |= SC_EVENT_REMOVED;                          break;                    case UndoOp::DeleteEvent: -                        addEvent(i->nEvent, i->part); +                        addEvent(i->nEvent, editable_part);                          if(i->doCtrls) -                          addPortCtrlEvents(i->nEvent, i->part, i->doClones); +                          addPortCtrlEvents(i->nEvent, editable_part, i->doClones);                          updateFlags |= SC_EVENT_INSERTED;                          break;                    case UndoOp::ModifyEvent:                          if(i->doCtrls) -                          removePortCtrlEvents(i->oEvent, i->part, i->doClones); -                        changeEvent(i->oEvent, i->nEvent, i->part); +                          removePortCtrlEvents(i->nEvent, editable_part, i->doClones); +                        changeEvent(i->nEvent, i->oEvent, editable_part);                          if(i->doCtrls) -                          addPortCtrlEvents(i->nEvent, i->part, i->doClones); +                          addPortCtrlEvents(i->oEvent, editable_part, i->doClones);                          updateFlags |= SC_EVENT_MODIFIED;                          break;                    case UndoOp::AddTempo: @@ -455,22 +571,24 @@ void Song::doUndo2()        }  //--------------------------------------------------------- -//   Song::doRedo2 +//   Song::executeOperationGroup2  //--------------------------------------------------------- -void Song::doRedo2() +void Song::executeOperationGroup2(Undo& operations)        { -      Undo& u = redoList->back(); -      for (iUndoOp i = u.begin(); i != u.end(); ++i) { +      for (iUndoOp i = operations.begin(); i != operations.end(); ++i) { +            Track* editable_track = const_cast<Track*>(i->track); +// uncomment if needed            Track* editable_property_track = const_cast<Track*>(i->_propertyTrack); +            Part* editable_part = const_cast<Part*>(i->part);              switch(i->type) {                    case UndoOp::AddTrack: -                        insertTrack2(i->track, i->trackno); -                        chainTrackParts(i->track, true); +                        insertTrack2(editable_track, i->trackno); +                        chainTrackParts(editable_track);                          updateFlags |= SC_TRACK_INSERTED;                          break;                    case UndoOp::DeleteTrack: -                        removeTrack2(i->track); +                        removeTrack2(editable_track);                          updateFlags |= SC_TRACK_REMOVED;                          break; @@ -484,46 +602,55 @@ void Song::doRedo2()                          }                          break;                    case UndoOp::AddPart: -                        addPart(i->oPart); +                        addPart(editable_part);                          updateFlags |= SC_PART_INSERTED; -                        i->oPart->events()->incARef(1); -                        chainClone(i->oPart); +                        editable_part->rechainClone();                          break;                    case UndoOp::DeletePart: -                        removePart(i->oPart); +                        removePart(editable_part);                          updateFlags |= SC_PART_REMOVED; -                        i->oPart->events()->incARef(-1); -                        unchainClone(i->oPart); +                        editable_part->unchainClone();                          break; -                  case UndoOp::ModifyPart: -                        if(i->doCtrls) -                          removePortCtrlEvents(i->oPart, i->doClones); -                        changePart(i->oPart, i->nPart); -                        i->nPart->events()->incARef(1); -                        i->oPart->events()->incARef(-1); -                        replaceClone(i->oPart, i->nPart); -                        if(i->doCtrls) -                          addPortCtrlEvents(i->nPart, i->doClones); +                  case UndoOp::MovePartToTrack: +                        removePart(editable_part); // remove it from the track it currently lives on. (does not touch the clone chain) +                        editable_part->setTrack(editable_track); +                        addPart(editable_part); // add it to the track we just set. +                        updateFlags |= SC_PART_INSERTED | SC_PART_REMOVED; +                        break; +                  case UndoOp::ModifyPartName: +                        editable_part->setName(i->_newName); +                        updateFlags |= SC_PART_MODIFIED; +                        break; +                  case UndoOp::ModifyPartTick: // TODO FIXME (?) do port ctrls/clones? +                        editable_part->setTick(i->new_partlen_or_tick); +                        updateFlags |= SC_PART_MODIFIED; +                        break; +                  case UndoOp::ModifyPartLength: // TODO FIXME (?) do port ctrls/clones? +                        editable_part->setLenTick(i->new_partlen_or_tick); +                        updateFlags |= SC_PART_MODIFIED; +                        break; +                  case UndoOp::ModifyPartLengthFrames: // TODO FIXME  FINDMICH frames deprecated!   do port ctrls/clones? +                        editable_part->setLenFrame(i->new_partlen_or_tick);                          updateFlags |= SC_PART_MODIFIED;                          break;                    case UndoOp::AddEvent: -                        addEvent(i->nEvent, i->part); +                        addEvent(i->nEvent, editable_part);                          if(i->doCtrls) -                          addPortCtrlEvents(i->nEvent, i->part, i->doClones); +                          addPortCtrlEvents(i->nEvent, editable_part, i->doClones);                          updateFlags |= SC_EVENT_INSERTED;                          break;                    case UndoOp::DeleteEvent:                          if(i->doCtrls) -                          removePortCtrlEvents(i->nEvent, i->part, i->doClones); -                        deleteEvent(i->nEvent, i->part); +                          removePortCtrlEvents(i->nEvent, editable_part, i->doClones); +                        deleteEvent(i->nEvent, editable_part);                          updateFlags |= SC_EVENT_REMOVED;                          break;                    case UndoOp::ModifyEvent:                          if(i->doCtrls) -                          removePortCtrlEvents(i->nEvent, i->part, i->doClones); -                        changeEvent(i->nEvent, i->oEvent, i->part); +                          removePortCtrlEvents(i->oEvent, editable_part, i->doClones); +                        changeEvent(i->oEvent, i->nEvent, editable_part);                          if(i->doCtrls) -                          addPortCtrlEvents(i->oEvent, i->part, i->doClones); +                          addPortCtrlEvents(i->nEvent, editable_part, i->doClones);                          updateFlags |= SC_EVENT_MODIFIED;                          break;                    case UndoOp::AddTempo: @@ -569,13 +696,13 @@ UndoOp::UndoOp()    type=UndoOp::DoNothing;  } -UndoOp::UndoOp(UndoType type_) -{ -	type = type_; -} -  UndoOp::UndoOp(UndoType type_, int a_, int b_, int c_)        { +      assert(type_==AddKey || type_==DeleteKey || +             type_==AddTempo || type_==DeleteTempo || +             type_==AddSig || type_==DeleteSig || +             type_==ModifySongLen || type_==SwapTrack); +              type = type_;        a  = a_;        b  = b_; @@ -583,21 +710,56 @@ UndoOp::UndoOp(UndoType type_, int a_, int b_, int c_)        } -UndoOp::UndoOp(UndoType type_, int n, Track* track_) +UndoOp::UndoOp(UndoType type_, int n, const Track* track_)        { +      assert(type_==AddTrack || type_==DeleteTrack); +      assert(track_); +              type    = type_;        trackno = n;        track  = track_;        } -UndoOp::UndoOp(UndoType type_, Part* part) +UndoOp::UndoOp(UndoType type_, const Part* part_, unsigned old_len_or_tick, unsigned new_len_or_tick, bool, bool)        { +      assert(type_==AddPart || type_==DeletePart || type_==ModifyPartLength || type_==ModifyPartLengthFrames || type_==ModifyPartTick ); +      assert(part_); +              type  = type_; -      oPart = part; +      part = part_; +      old_partlen_or_tick=old_len_or_tick; +      new_partlen_or_tick=new_len_or_tick;        } +       +UndoOp::UndoOp(UndoType type_, const Part* part_, bool selected_, bool sel_old_) +{ +    assert(type_==SelectPart); +    assert(part_); +     +    type=type_; +    part = part_; +    selected=selected_; +    selected_old=sel_old_; +} -UndoOp::UndoOp(UndoType type_, Event& oev, Event& nev, Part* part_, bool doCtrls_, bool doClones_) +UndoOp::UndoOp(UndoType type_, const Part* part_, const Track* nTrack, const Track* oTrack) +{ +    assert(type_==MovePartToTrack); +    assert(part_); +    assert(nTrack); +    assert(oTrack); +     +    type=type_; +    part = part_; +    track=nTrack; +    oldTrack=oTrack; +} + +UndoOp::UndoOp(UndoType type_, const Event& nev, const Event& oev, const Part* part_, bool doCtrls_, bool doClones_)        { +      assert(type_==ModifyEvent); +      assert(part_); +              type   = type_;        nEvent = nev;        oEvent = oev; @@ -606,35 +768,35 @@ UndoOp::UndoOp(UndoType type_, Event& oev, Event& nev, Part* part_, bool doCtrls        doClones = doClones_;        } -UndoOp::UndoOp(UndoType type_, Event& nev, Part* part_, bool doCtrls_, bool doClones_) +UndoOp::UndoOp(UndoType type_, const Event& nev, const Part* part_, bool doCtrls_, bool doClones_)        { +      assert(type_==DeleteEvent || type_==AddEvent); +      assert(part_); +              type   = type_;        nEvent = nev;        part   = part_;        doCtrls = doCtrls_;        doClones = doClones_;        } +       +UndoOp::UndoOp(UndoType type_, const Event& nev, bool selected_, bool sel_old_) +{ +    assert(type_==SelectEvent); +     +    type=type_; +    nEvent = nev; +    selected=selected_; +    selected_old=sel_old_; +} -UndoOp::UndoOp(UndoType type_, Part* oPart_, Part* nPart_, bool doCtrls_, bool doClones_) -      { -      type  = type_; -      oPart = oPart_; -      nPart = nPart_; -      doCtrls = doCtrls_; -      doClones = doClones_; -      } - -UndoOp::UndoOp(UndoType type_, int c, int ctrl_, int ov, int nv) -      { -      type    = type_; -      channel = c; -      ctrl    = ctrl_; -      oVal    = ov; -      nVal    = nv; -      }  UndoOp::UndoOp(UndoType type_, Marker* copyMarker_, Marker* realMarker_)        { +      assert(type_==ModifyMarker); +      assert(copyMarker_); +      assert(realMarker_); +              type    = type_;        realMarker  = realMarker_;        copyMarker  = copyMarker_; @@ -642,6 +804,8 @@ UndoOp::UndoOp(UndoType type_, Marker* copyMarker_, Marker* realMarker_)  UndoOp::UndoOp(UndoType type_, const char* changedFile, const char* changeData, int startframe_, int endframe_)        { +      assert(type_==ModifyClip); +              type = type_;        filename   = changedFile;        tmpwavfile = changeData; @@ -649,18 +813,41 @@ UndoOp::UndoOp(UndoType type_, const char* changedFile, const char* changeData,        endframe   = endframe_;        } -UndoOp::UndoOp(UndoOp::UndoType type_, Track* track_, const char* old_name, const char* new_name) +UndoOp::UndoOp(UndoOp::UndoType type_, const Part* part_, const char* old_name, const char* new_name) +{ +    assert(type_==ModifyPartName); +    assert(part_); +    assert(old_name); +    assert(new_name); +     +    type=type_; +    part=part_; +    _oldName = new char[strlen(old_name) + 1]; +    _newName = new char[strlen(new_name) + 1]; +    strcpy(_oldName, old_name); +    strcpy(_newName, new_name); +} + +UndoOp::UndoOp(UndoOp::UndoType type_, const Track* track_, const char* old_name, const char* new_name)  { +  assert(type_==ModifyTrackName); +  assert(track_); +  assert(old_name); +  assert(new_name);     +        type = type_; -  _renamedTrack = track_; +  track = track_;    _oldName = new char[strlen(old_name) + 1];    _newName = new char[strlen(new_name) + 1];    strcpy(_oldName, old_name);    strcpy(_newName, new_name);  } -UndoOp::UndoOp(UndoOp::UndoType type_, Track* track_, int old_chan, int new_chan) +UndoOp::UndoOp(UndoOp::UndoType type_, const Track* track_, int old_chan, int new_chan)  { +  assert(type_==ModifyTrackChannel); +  assert(track_); +      type = type_;    _propertyTrack = track_;    _oldPropValue = old_chan; @@ -688,37 +875,46 @@ void Song::addUndo(UndoOp i)        }  //--------------------------------------------------------- -//   doUndo1 +//   revertOperationGroup1  //    non realtime context  //    return true if nothing to do  //--------------------------------------------------------- -bool Song::doUndo1() +void Song::revertOperationGroup1(Undo& operations)        { -      if (undoList->empty()) -            return true; -      Undo& u = undoList->back(); -      for (riUndoOp i = u.rbegin(); i != u.rend(); ++i) { +      for (riUndoOp i = operations.rbegin(); i != operations.rend(); ++i) { +            Track* editable_track = const_cast<Track*>(i->track); +            Track* editable_property_track = const_cast<Track*>(i->_propertyTrack); +            Part* editable_part = const_cast<Part*>(i->part);              switch(i->type) { +                  case UndoOp::SelectPart: +                        editable_part->setSelected(i->selected_old); +                        updateFlags |= SC_SELECTION; +                        break; +                  case UndoOp::SelectEvent: +                        i->nEvent.setSelected(i->selected_old); +                        updateFlags |= SC_SELECTION; +                        break; +                                            case UndoOp::AddTrack: -                        removeTrack1(i->track); +                        removeTrack1(editable_track);                          break;                    case UndoOp::DeleteTrack: -                        insertTrack1(i->track, i->trackno); +                        insertTrack1(editable_track, i->trackno);                          // FIXME: Would like to put this part in Undo2, but indications                          //  elsewhere are that (dis)connecting jack routes must not be                          //  done in the realtime thread. The result is that we get a few                          //  "PANIC Process init: No buffer from audio device" messages                          //  before the routes are (dis)connected. So far seems to do no harm though... -                        switch(i->track->type()) +                        switch(editable_track->type())                          {                                case Track::AUDIO_OUTPUT:                                case Track::AUDIO_INPUT: -                                      connectJackRoutes((AudioTrack*)i->track, false); +                                      connectJackRoutes((AudioTrack*)editable_track, false);                                      break;                                //case Track::AUDIO_SOFTSYNTH: DELETETHIS 4 -                                      //SynthI* si = (SynthI*)i->track; +                                      //SynthI* si = (SynthI*)editable_track;                                        //si->synth()->init(                                //      break;                                default: @@ -727,16 +923,16 @@ bool Song::doUndo1()                          break;                    case UndoOp::ModifyTrackName: -                          i->_renamedTrack->setName(i->_oldName); +                          editable_track->setName(i->_oldName);                            updateFlags |= SC_TRACK_MODIFIED;                          break;                    case UndoOp::ModifyClip:                          MusECore::SndFile::applyUndoFile(i->filename, i->tmpwavfile, i->startframe, i->endframe);                          break;                    case UndoOp::ModifyTrackChannel: -                        if (i->_propertyTrack->isMidiTrack())  +                        if (editable_property_track->isMidiTrack())                           { -                          MusECore::MidiTrack* mt = dynamic_cast<MusECore::MidiTrack*>(i->_propertyTrack); +                          MusECore::MidiTrack* mt = dynamic_cast<MusECore::MidiTrack*>(editable_property_track);                            if (mt == 0 || mt->type() == MusECore::Track::DRUM)                              break;                            if (i->_oldPropValue != mt->outChannel())  @@ -756,9 +952,9 @@ bool Song::doUndo1()                          }                          else                          { -                            if(i->_propertyTrack->type() != MusECore::Track::AUDIO_SOFTSYNTH) +                            if(editable_property_track->type() != MusECore::Track::AUDIO_SOFTSYNTH)                              { -                              MusECore::AudioTrack* at = dynamic_cast<MusECore::AudioTrack*>(i->_propertyTrack); +                              MusECore::AudioTrack* at = dynamic_cast<MusECore::AudioTrack*>(editable_property_track);                                if (at == 0)                                  break;                                if (i->_oldPropValue != at->channels()) { @@ -773,24 +969,26 @@ bool Song::doUndo1()                          break;                    }              } -      return false; +      return;        }  //--------------------------------------------------------- -//   doUndo3 +//   revertOperationGroup3  //    non realtime context  //--------------------------------------------------------- -void Song::doUndo3() +void Song::revertOperationGroup3(Undo& operations)        { -      Undo& u = undoList->back(); -      for (riUndoOp i = u.rbegin(); i != u.rend(); ++i) { +      for (riUndoOp i = operations.rbegin(); i != operations.rend(); ++i) { +            Track* editable_track = const_cast<Track*>(i->track); +// uncomment if needed            Track* editable_property_track = const_cast<Track*>(i->_propertyTrack); +// uncomment if needed            Part* editable_part = const_cast<Part*>(i->part);              switch(i->type) {                    case UndoOp::AddTrack: -                        removeTrack3(i->track); +                        removeTrack3(editable_track);                          break;                    case UndoOp::DeleteTrack: -                        insertTrack3(i->track, i->trackno); +                        insertTrack3(editable_track, i->trackno);                          break;                    case UndoOp::ModifyMarker:                          { @@ -810,36 +1008,42 @@ void Song::doUndo3()                          break;                    }              } -      redoList->push_back(u); // put item on redo list -      undoList->pop_back(); -      emit sigDirty();        }  //--------------------------------------------------------- -//   doRedo1 +//   executeOperationGroup1  //    non realtime context  //    return true if nothing to do  //--------------------------------------------------------- -bool Song::doRedo1() +void Song::executeOperationGroup1(Undo& operations)        { -      if (redoList->empty()) -            return true; -      Undo& u = redoList->back(); -      for (iUndoOp i = u.begin(); i != u.end(); ++i) { +      for (iUndoOp i = operations.begin(); i != operations.end(); ++i) { +            Track* editable_track = const_cast<Track*>(i->track); +            Track* editable_property_track = const_cast<Track*>(i->_propertyTrack); +            Part* editable_part = const_cast<Part*>(i->part);              switch(i->type) { +                  case UndoOp::SelectPart: +                        editable_part->setSelected(i->selected); +                        updateFlags |= SC_SELECTION; +                        break; +                  case UndoOp::SelectEvent: +                        i->nEvent.setSelected(i->selected); +                        updateFlags |= SC_SELECTION; +                        break; +                                            case UndoOp::AddTrack: -                        insertTrack1(i->track, i->trackno); +                        insertTrack1(editable_track, i->trackno);                          // FIXME: See comments in Undo1. -                        switch(i->track->type()) +                        switch(editable_track->type())                          {                                case Track::AUDIO_OUTPUT:                                case Track::AUDIO_INPUT: -                                      connectJackRoutes((AudioTrack*)i->track, false); +                                      connectJackRoutes((AudioTrack*)editable_track, false);                                      break;                                //case Track::AUDIO_SOFTSYNTH: DELETETHIS 4 -                                      //SynthI* si = (SynthI*)i->track; +                                      //SynthI* si = (SynthI*)editable_track;                                        //si->synth()->init(                                //      break;                                default: @@ -848,19 +1052,19 @@ bool Song::doRedo1()                          break;                    case UndoOp::DeleteTrack: -                        removeTrack1(i->track); +                        removeTrack1(editable_track);                          break;                    case UndoOp::ModifyTrackName: -                          i->_renamedTrack->setName(i->_newName); +                          editable_track->setName(i->_newName);                            updateFlags |= SC_TRACK_MODIFIED;                          break;                    case UndoOp::ModifyClip:                          MusECore::SndFile::applyUndoFile(i->filename, i->tmpwavfile, i->startframe, i->endframe);                          break;                    case UndoOp::ModifyTrackChannel: -                        if (i->_propertyTrack->isMidiTrack())  +                        if (editable_property_track->isMidiTrack())                           { -                          MusECore::MidiTrack* mt = dynamic_cast<MusECore::MidiTrack*>(i->_propertyTrack); +                          MusECore::MidiTrack* mt = dynamic_cast<MusECore::MidiTrack*>(editable_property_track);                            if (mt == 0 || mt->type() == MusECore::Track::DRUM)                              break;                            if (i->_newPropValue != mt->outChannel())  @@ -880,9 +1084,9 @@ bool Song::doRedo1()                          }                          else                          { -                            if(i->_propertyTrack->type() != MusECore::Track::AUDIO_SOFTSYNTH) +                            if(editable_property_track->type() != MusECore::Track::AUDIO_SOFTSYNTH)                              { -                              MusECore::AudioTrack* at = dynamic_cast<MusECore::AudioTrack*>(i->_propertyTrack); +                              MusECore::AudioTrack* at = dynamic_cast<MusECore::AudioTrack*>(editable_property_track);                                if (at == 0)                                  break;                                if (i->_newPropValue != at->channels()) { @@ -897,24 +1101,25 @@ bool Song::doRedo1()                          break;                    }              } -      return false;        }  //--------------------------------------------------------- -//   doRedo3 +//   executeOperationGroup3  //    non realtime context  //--------------------------------------------------------- -void Song::doRedo3() +void Song::executeOperationGroup3(Undo& operations)        { -      Undo& u = redoList->back(); -      for (iUndoOp i = u.begin(); i != u.end(); ++i) { +      for (iUndoOp i = operations.begin(); i != operations.end(); ++i) { +            Track* editable_track = const_cast<Track*>(i->track); +// uncomment if needed            Track* editable_property_track = const_cast<Track*>(i->_propertyTrack); +// uncomment if needed            Part* editable_part = const_cast<Part*>(i->part);              switch(i->type) {                    case UndoOp::AddTrack: -                        insertTrack3(i->track, i->trackno); +                        insertTrack3(editable_track, i->trackno);                          break;                    case UndoOp::DeleteTrack: -                        removeTrack3(i->track); +                        removeTrack3(editable_track);                          break;                    case UndoOp::ModifyMarker:                          { @@ -933,9 +1138,6 @@ void Song::doRedo3()                          break;                    }              } -      undoList->push_back(u); // put item on undo list -      redoList->pop_back(); -      emit sigDirty();        } diff --git a/muse2/muse/undo.h b/muse2/muse/undo.h index 2f582d8e..f83ce491 100644 --- a/muse2/muse/undo.h +++ b/muse2/muse/undo.h @@ -46,8 +46,9 @@ extern std::list<QString> temporaryWavFiles; //!< Used for storing all tmp-files  struct UndoOp {        enum UndoType {              AddTrack, DeleteTrack, -            AddPart,  DeletePart,  ModifyPart, -            AddEvent, DeleteEvent, ModifyEvent, +            AddPart,  DeletePart,  ModifyPartTick, ModifyPartLength, ModifyPartLengthFrames, /* FINDMICH FIXME frames are to be deprecated */ ModifyPartName, SelectPart, +            MovePartToTrack, +            AddEvent, DeleteEvent, ModifyEvent, SelectEvent,              AddTempo, DeleteTempo,              AddSig,   DeleteSig,              AddKey,   DeleteKey, @@ -67,15 +68,9 @@ struct UndoOp {                    int c;                    };              struct { -                  Track* track; -                  int trackno; -                  }; -            struct { -                  Part* oPart; -                  Part* nPart; -                  }; -            struct { -                  Part* part; // this part is only relevant for EVENT operations, NOT for part ops! +                  const Part* part; +                  unsigned old_partlen_or_tick; // FIXME FINDMICHJETZT XTicks!! +                  unsigned new_partlen_or_tick;                    };              struct {                    int channel; @@ -90,50 +85,72 @@ struct UndoOp {                    const char* tmpwavfile; //!< The file with the changed data                    };              struct { -                  Marker* realMarker; +                  Marker* realMarker;                     Marker* copyMarker;                  };              struct { -                  Track* _renamedTrack; -                  char* _oldName; -                  char* _newName; -                }; -            struct { -                  Track* _propertyTrack; +                  const Track* _propertyTrack;                    int _oldPropValue;                    int _newPropValue;                  };              }; + +      char* _oldName; +      char* _newName;        Event oEvent;        Event nEvent; +      bool selected; +      bool selected_old;        bool doCtrls;        bool doClones; +      const Track* track; +      const Track* oldTrack; +      int trackno;        const char* typeName();        void dump();        UndoOp();        UndoOp(UndoType type, int a, int b, int c=0); -      UndoOp(UndoType type, int n, Track* track); -      UndoOp(UndoType type, Part* part); -      UndoOp(UndoType type, Event& oev, Event& nev, Part* part, bool doCtrls, bool doClones); -      UndoOp(UndoType type, Event& nev, Part* part, bool doCtrls, bool doClones); -      UndoOp(UndoType type, Part* oPart, Part* nPart, bool doCtrls, bool doClones); -      UndoOp(UndoType type, int c, int ctrl, int ov, int nv); +      UndoOp(UndoType type, int n, const Track* track); +      UndoOp(UndoType type, const Part* part, unsigned old_len_or_tick=-1, unsigned new_len_or_tick=-1, bool doCtrls=false, bool doClones=false); // FIXME these bools are UNUSED!!. XTICKS! +      UndoOp(UndoType type, const Part* part, const char* old_name, const char* new_name); +      UndoOp(UndoType type, const Part* part, bool selected, bool selected_old); +      UndoOp(UndoType type, const Part* part, const Track* nTrack, const Track* oTrack); +      UndoOp(UndoType type, const Event& nev, const Event& oev, const Part* part, bool doCtrls, bool doClones); +      UndoOp(UndoType type, const Event& nev, const Part* part, bool doCtrls, bool doClones); +      UndoOp(UndoType type, const Event& nev, bool selected, bool selected_old);        UndoOp(UndoType type, const char* changedFile, const char* changeData, int startframe, int endframe);        UndoOp(UndoType type, Marker* copyMarker, Marker* realMarker); -      UndoOp(UndoType type, Track* track, const char* old_name, const char* new_name); -      UndoOp(UndoType type, Track* track, int old_chan, int new_chan); -      UndoOp(UndoType type); +      UndoOp(UndoType type, const Track* track, const char* old_name, const char* new_name); +      UndoOp(UndoType type, const Track* track, int old_chan, int new_chan);  };  class Undo : public std::list<UndoOp> {     public: +      Undo() : std::list<UndoOp>() { combobreaker=false; } +      Undo(const Undo& other) : std::list<UndoOp>(other) { this->combobreaker=other.combobreaker; } +      Undo& operator=(const Undo& other) { std::list<UndoOp>::operator=(other); this->combobreaker=other.combobreaker; return *this;} +        bool empty() const; +       +       +      /** if set, forbid merging (below). +       *  Defaults to false */ +      bool combobreaker;  +       +      /** is possible, merges itself and other by appending +       *  all contents of other at this->end(). +       *  returns true if merged, false otherwise. +       *  in case of success, the caller has to ensure that +       *  other is deleted from the UndoList. */ +      bool merge_combo(const Undo& other);  };  typedef Undo::iterator iUndoOp;  typedef Undo::reverse_iterator riUndoOp; +typedef Undo::const_iterator ciUndoOp; +typedef Undo::const_reverse_iterator criUndoOp;  class UndoList : public std::list<Undo> {     protected: diff --git a/muse2/muse/wave.cpp b/muse2/muse/wave.cpp index 8c647685..9bf26753 100644 --- a/muse2/muse/wave.cpp +++ b/muse2/muse/wave.cpp @@ -826,11 +826,11 @@ bool SndFile::checkCopyOnWrite()      PartList* pl = (*it)->parts();      for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)      { -      EventList* el = ip->second->events(); +      const EventList& el = ip->second->events();        // We are looking for active independent non-clone parts -      if(el->arefCount() > 1) +      if(ip->second->hasClones())          continue; -      for(ciEvent ie = el->begin(); ie != el->end(); ++ie) +      for(ciEvent ie = el.begin(); ie != el.end(); ++ie)        {          if(ie->second.type() != Wave)            continue; @@ -1114,7 +1114,10 @@ void Song::cmdAddRecordedWave(MusECore::WaveTrack* track, MusECore::Pos s, MusEC        event.setLenFrame(e.frame() - s.frame());        part->addEvent(event); -      MusEGlobal::song->cmdAddPart(part); +      // TODO FIXME that's ugly (flo) +      addPart(part); +      addUndo(UndoOp(UndoOp::AddPart, part)); +      updateFlags = SC_PART_INSERTED;        if (MusEGlobal::song->len() < etick)              MusEGlobal::song->setLen(etick); diff --git a/muse2/muse/waveedit/wavecanvas.cpp b/muse2/muse/waveedit/wavecanvas.cpp index 95ecd250..db886bce 100644 --- a/muse2/muse/waveedit/wavecanvas.cpp +++ b/muse2/muse/waveedit/wavecanvas.cpp @@ -79,7 +79,7 @@ namespace MusEGui {  //   WEvent  //--------------------------------------------------------- -WEvent::WEvent(MusECore::Event& e, MusECore::Part* p, int height) : MusEGui::CItem(e, p) +WEvent::WEvent(const MusECore::Event& e, MusECore::Part* p, int height) : MusEGui::CItem(e, p)        {        unsigned frame = e.frame() + p->frame();        setPos(QPoint(frame, 0)); @@ -93,7 +93,7 @@ WEvent::WEvent(MusECore::Event& e, MusECore::Part* p, int height) : MusEGui::CIt  //   addItem  //--------------------------------------------------------- -CItem* WaveCanvas::addItem(MusECore::Part* part, MusECore::Event& event) +CItem* WaveCanvas::addItem(MusECore::Part* part, const MusECore::Event& event)        {        if (signed(event.frame())<0) {              printf("ERROR: trying to add event before current part!\n"); @@ -183,9 +183,8 @@ void WaveCanvas::songChanged(MusECore::SongChangedFlags_t flags)                    if (esample > endSample)                          endSample = esample; -                  MusECore::EventList* el = part->events(); -                  for (MusECore::iEvent i = el->begin(); i != el->end(); ++i) { -                        MusECore::Event e = i->second; +                  for (MusECore::ciEvent i = part->events().begin(); i != part->events().end(); ++i) { +                        const MusECore::Event& e = i->second;                          // Do not add events which are past the end of the part.                          if(e.frame() > len)                                  break; @@ -578,9 +577,9 @@ void WaveCanvas::draw(QPainter& p, const QRect& r)            if(ci->isSelected())               list4.push_back(ci);            // Draw clone parts, and parts with hidden events, in front of others all except selected. -          //else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1 || ci->part()->cachedHasHiddenEvents())) +          //else if(ci->event().empty() && (ci->part()->hasClones() || ci->part()->cachedHasHiddenEvents()))            // Draw clone parts in front of others all except selected. -          //else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1)) +          //else if(ci->event().empty() && ci->part()->hasClones())            //  list3.push_back(ci);            else                // Draw unselected parts. @@ -1327,9 +1326,9 @@ MusECore::Undo WaveCanvas::moveCanvasItems(MusEGui::CItemList& items, int /*dp*/      MusECore::Part* opart = ip2c->first;      if (opart->hasHiddenEvents())      { -                        forbidden=true; -                        break; -                } +        forbidden=true; +        break; +    }    }     @@ -1478,7 +1477,6 @@ void WaveCanvas::newItem(MusEGui::CItem* item, bool noSnap)          if (diff > 0)// part must be extended?          { -              //schedule_resize_all_same_len_clone_parts(part, event.endTick(), operations);                schedule_resize_all_same_len_clone_parts(part, event.endFrame(), operations);                printf("newItem: extending\n");          } @@ -1686,11 +1684,11 @@ void WaveCanvas::waveCmd(int cmd)                    if (part == 0)                          break; -                  MusECore::EventList* el = part->events(); +                  const MusECore::EventList& el = part->events();                    MusECore::Undo operations;                    std::list <MusECore::Event> elist; -                  for (MusECore::iEvent e = el->lower_bound(pos[0] - part->tick()); e != el->end(); ++e) +                  for (MusECore::ciEvent e = el.lower_bound(pos[0] - part->tick()); e != el.end(); ++e)                          elist.push_back((MusECore::Event)e->second);                    for (std::list<MusECore::Event>::iterator i = elist.begin(); i != elist.end(); ++i) {                          MusECore::Event event = *i; @@ -1714,10 +1712,10 @@ void WaveCanvas::waveCmd(int cmd)                          break;                    MusECore::Undo operations; -                  MusECore::EventList* el = part->events(); +                  const MusECore::EventList& el = part->events();                    std::list<MusECore::Event> elist; -                  for (MusECore::iEvent e = el->lower_bound(pos[0]); e != el->end(); ++e) +                  for (MusECore::ciEvent e = el.lower_bound(pos[0]); e != el.end(); ++e)                          elist.push_back((MusECore::Event)e->second);                    for (std::list<MusECore::Event>::iterator i = elist.begin(); i != elist.end(); ++i) {                          MusECore::Event event = *i; @@ -1927,17 +1925,17 @@ void WaveCanvas::cmd(int cmd)                        tempPart->setPos(MusEGlobal::song->lpos());                        tempPart->setLenTick(MusEGlobal::song->rpos() - MusEGlobal::song->lpos());                        // loop through the events and set them accordingly -                      for (MusECore::iEvent iWaveEvent = origPart->events()->begin(); iWaveEvent != origPart->events()->end(); iWaveEvent++) +                      for (MusECore::ciEvent iWaveEvent = origPart->events().begin(); iWaveEvent != origPart->events().end(); iWaveEvent++)                        {                            // TODO: handle multiple events correctly,                            // the math for subsequent events isn't correct -                          MusECore::Event &ev = iWaveEvent->second; +                          const MusECore::Event& ev = iWaveEvent->second;                            MusECore::Event *newEvent = new MusECore::Event(ev.clone());                            newEvent->setSpos(ev.spos() + frameDistance);                            newEvent->setLenTick(MusEGlobal::song->rpos() - MusEGlobal::song->lpos());                            tempPart->addEvent(*newEvent);                        } -                      std::set<MusECore::Part*> partList; +                      std::set<const MusECore::Part*> partList;                        partList.insert(tempPart);                        QMimeData *mimeData =  MusECore::parts_to_mime(partList); @@ -1993,10 +1991,9 @@ MusECore::WaveSelectionList WaveCanvas::getSelection(unsigned startpos, unsigned              MusECore::WavePart* wp = (MusECore::WavePart*)(ip->second);              unsigned part_offset = wp->frame(); -            MusECore::EventList* el = wp->events(); -            //printf("eventlist length=%d\n",el->size()); +            const MusECore::EventList& el = wp->events(); -            for (MusECore::iEvent e = el->begin(); e != el->end(); ++e) { +            for (MusECore::ciEvent e = el.begin(); e != el.end(); ++e) {                    MusECore::Event event  = e->second;                    if (event.empty())                          continue; @@ -2587,7 +2584,7 @@ void WaveCanvas::curPartChanged()  void WaveCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int val, bool delta_mode)        {        // TODO: New WaveCanvas: Convert this routine to frames and remove unneeded operations.  -      QList< QPair<MusECore::EventList*,MusECore::Event> > already_done; +      QList< QPair<int,MusECore::Event> > already_done;        MusEGlobal::audio->msgIdle(true);        MusEGlobal::song->startUndo();        for (MusEGui::iCItem i = items.begin(); i != items.end(); ++i) { @@ -2600,7 +2597,7 @@ void WaveCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int val, bool d              MusECore::WavePart* part = (MusECore::WavePart*)(e->part()); -            if (already_done.contains(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event))) +            if (already_done.contains(QPair<int,MusECore::Event>(part->clonemaster_sn(), event)))                continue;              MusECore::Event newEvent = event.clone(); @@ -2670,7 +2667,7 @@ void WaveCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int val, bool d              // Indicate do not do port controller values and clone parts.               MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false)); -            already_done.append(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event)); +            already_done.append(QPair<int,MusECore::Event>(part->clonemaster_sn(), event));              }        MusEGlobal::song->endUndo(SC_EVENT_MODIFIED);        MusEGlobal::audio->msgIdle(false); diff --git a/muse2/muse/waveedit/wavecanvas.h b/muse2/muse/waveedit/wavecanvas.h index 10f75291..63979915 100644 --- a/muse2/muse/waveedit/wavecanvas.h +++ b/muse2/muse/waveedit/wavecanvas.h @@ -64,7 +64,7 @@ namespace MusEGui {  class WEvent : public CItem {     public: -      WEvent(MusECore::Event& e, MusECore::Part* p, int height); +      WEvent(const MusECore::Event& e, MusECore::Part* p, int height);        };  //--------------------------------------------------------- @@ -124,7 +124,7 @@ class WaveCanvas : public EventCanvas {        virtual void dragEnterEvent(QDragEnterEvent* event);        virtual void dragMoveEvent(QDragMoveEvent*);        virtual void dragLeaveEvent(QDragLeaveEvent*); -      virtual CItem* addItem(MusECore::Part*, MusECore::Event&); +      virtual CItem* addItem(MusECore::Part*, const MusECore::Event&);        int y2pitch(int) const;        int pitch2y(int) const; diff --git a/muse2/muse/waveedit/waveview.cpp b/muse2/muse/waveedit/waveview.cpp index 3e3ea057..2cb63dc5 100644 --- a/muse2/muse/waveedit/waveview.cpp +++ b/muse2/muse/waveedit/waveview.cpp @@ -119,9 +119,8 @@ void WaveView::pdraw(QPainter& p, const QRect& rr)              int channels = wp->track()->channels();              int px = wp->frame(); -            MusECore::EventList* el = wp->events(); -            for (MusECore::iEvent e = el->begin(); e != el->end(); ++e) { -                  MusECore::Event event  = e->second; +            for (MusECore::ciEvent e = wp->events().begin(); e != wp->events().end(); ++e) { +                  const MusECore::Event event&  = e->second;                    if (event.empty())                          continue;                    MusECore::SndFileR f = event.sndFile(); diff --git a/muse2/muse/waveevent.cpp b/muse2/muse/waveevent.cpp index 38ae10c6..24be2d01 100644 --- a/muse2/muse/waveevent.cpp +++ b/muse2/muse/waveevent.cpp @@ -53,16 +53,25 @@ WaveEventBase::WaveEventBase(EventType t)  //   WaveEventBase::clone  //--------------------------------------------------------- -EventBase* WaveEventBase::clone()  +EventBase* WaveEventBase::clone() const  {     return new WaveEventBase(*this);   } +bool WaveEventBase::isSimilarTo(const EventBase& other_) const +{ +	const WaveEventBase* other = dynamic_cast<const WaveEventBase*>(&other_); +	if (other==NULL) // dynamic cast hsa failed: "other_" is not of type WaveEventBase. +		return false; +	 +	return f.dirPath()==other->f.dirPath() && _spos==other->_spos && this->PosLen::operator==(*other); +} +  //---------------------------------------------------------  //   WaveEvent::mid  //--------------------------------------------------------- -EventBase* WaveEventBase::mid(unsigned b, unsigned e) +EventBase* WaveEventBase::mid(unsigned b, unsigned e) const        {        WaveEventBase* ev = new WaveEventBase(*this);        unsigned fr = frame(); diff --git a/muse2/muse/waveevent.h b/muse2/muse/waveevent.h index e814fe3d..d11803c7 100644 --- a/muse2/muse/waveevent.h +++ b/muse2/muse/waveevent.h @@ -44,15 +44,17 @@ class WaveEventBase : public EventBase {        int _spos;            // start sample position in WaveFile        bool deleted; -      virtual EventBase* clone(); +      virtual EventBase* clone() const;     public:        WaveEventBase(EventType t);        virtual ~WaveEventBase() {} +       +      virtual bool isSimilarTo(const EventBase& other) const;        virtual void read(Xml&);        virtual void write(int, Xml&, const Pos& offset, bool forcePath = false) const; -      virtual EventBase* mid(unsigned, unsigned); +      virtual EventBase* mid(unsigned, unsigned) const;        virtual void dump(int n = 0) const; diff --git a/muse2/muse/wavetrack.cpp b/muse2/muse/wavetrack.cpp index 363f8966..f21992a6 100644 --- a/muse2/muse/wavetrack.cpp +++ b/muse2/muse/wavetrack.cpp @@ -60,27 +60,11 @@ void WaveTrack::internal_assign(const Track& t, int flags)          const PartList* pl = t.cparts();          for (ciPart ip = pl->begin(); ip != pl->end(); ++ip) {                Part* spart = ip->second; -              bool clone = spart->events()->arefCount() > 1; -              // This increments aref count if cloned, and chains clones. -              // It also gives the new part a new serial number. -              Part* dpart = newPart(spart, clone); -              if(!clone) { -                    // Copy Events -                    MusECore::EventList* se = spart->events(); -                    MusECore::EventList* de = dpart->events(); -                    for (MusECore::iEvent i = se->begin(); i != se->end(); ++i) { -                          MusECore::Event oldEvent = i->second; -                          MusECore::Event ev = oldEvent.clone(); -                          de->add(ev); -                          } -                    } - -              // TODO: Should we include the parts in the undo? -              //      dpart->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it -              //                                    // so we must decrement it first :/ -              //      // These will not increment ref count, and will not chain clones... -              //      // DELETETHIS: is the above comment still correct (by flo93)? i doubt it! -              //      operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddPart,dpart)); +              Part* dpart; +              if (spart->hasClones()) +                  dpart = spart->createNewClone(); +              else +                  dpart = spart->duplicate();                parts()->add(dpart);                } @@ -127,8 +111,7 @@ void WaveTrack::fetchData(unsigned pos, unsigned samples, float** bp, bool doSee                if (pos >= p_epos)                  continue; -              EventList* events = part->events(); -              for (iEvent ie = events->begin(); ie != events->end(); ++ie) { +              for (iEvent ie = part->nonconst_events().begin(); ie != part->nonconst_events().end(); ++ie) {                      Event& event = ie->second;                      unsigned e_spos  = event.frame() + p_spos;                      unsigned nn      = event.lenFrame(); @@ -201,11 +184,11 @@ void WaveTrack::read(Xml& xml)              switch (token) {                    case Xml::Error:                    case Xml::End: -                        return; +                        goto out_of_WaveTrackRead_forloop;                    case Xml::TagStart:                          if (tag == "part") {                                Part* p = 0; -                              p = readXmlPart(xml, this); +                              p = Part::readFromXml(xml, this);                                if(p)                                  parts()->add(p);                                } @@ -217,12 +200,14 @@ void WaveTrack::read(Xml& xml)                    case Xml::TagEnd:                          if (tag == "wavetrack") {                                mapRackPluginsToControllers(); -                              return; +                              goto out_of_WaveTrackRead_forloop;                                }                    default:                          break;                    }              } +out_of_WaveTrackRead_forloop: +      chainTrackParts(this);        }  //--------------------------------------------------------- @@ -231,7 +216,16 @@ void WaveTrack::read(Xml& xml)  Part* WaveTrack::newPart(Part*p, bool clone)        { -      WavePart* part = clone ? new WavePart(this, p->events()) : new WavePart(this); +      WavePart* part; +      if (clone) +      { +            part = (WavePart*)p->createNewClone(); +            part->setTrack(this); +      } +      else +            part = new WavePart(this); +       +              if (p) {              part->setName(p->name());              part->setColorIndex(p->colorIndex()); @@ -240,9 +234,6 @@ Part* WaveTrack::newPart(Part*p, bool clone)              part->setMute(p->mute());              } -      if(clone) -        chainClone(p, part); -              return part;        } diff --git a/muse2/muse/widgets/mtrackinfo.cpp b/muse2/muse/widgets/mtrackinfo.cpp index 09d45577..a73eb212 100644 --- a/muse2/muse/widgets/mtrackinfo.cpp +++ b/muse2/muse/widgets/mtrackinfo.cpp @@ -682,18 +682,11 @@ void MidiTrackInfo::iOutputChannelChanged(int channel)        MusECore::MidiTrack* track = (MusECore::MidiTrack*)selected;        if (channel != track->outChannel()) {              ++_blockHeartbeatCount; -            // Changed by T356. -            //track->setOutChannel(channel);              MusEGlobal::audio->msgIdle(true); -            //audio->msgSetTrackOutChannel(track, channel);              track->setOutChanAndUpdate(channel);              MusEGlobal::audio->msgIdle(false); -            // may result in adding/removing mixer strip: -            //MusEGlobal::song->update(-1); -            //MusEGlobal::song->update(SC_MIDI_TRACK_PROP);              MusEGlobal::audio->msgUpdateSoloStates();                   // p4.0.14 -            //MusEGlobal::song->update(SC_MIDI_TRACK_PROP | SC_ROUTE);  //              MusEGlobal::song->update(SC_MIDI_TRACK_PROP);               //              --_blockHeartbeatCount;              } @@ -714,16 +707,11 @@ void MidiTrackInfo::iOutputPortChanged(int index)        if (port_num == track->outPort())              return;        ++_blockHeartbeatCount; -      // Changed by T356. -      //track->setOutPort(port_num);        MusEGlobal::audio->msgIdle(true); -      //audio->msgSetTrackOutPort(track, port_num);        track->setOutPortAndUpdate(port_num);        MusEGlobal::audio->msgIdle(false); -      //MusEGlobal::song->update(SC_MIDI_TRACK_PROP);          MusEGlobal::audio->msgUpdateSoloStates();                   // p4.0.14 -      //MusEGlobal::song->update(SC_MIDI_TRACK_PROP | SC_ROUTE);  //        MusEGlobal::song->update(SC_MIDI_TRACK_PROP);               //        --_blockHeartbeatCount;        } diff --git a/muse2/muse/widgets/utils.cpp b/muse2/muse/widgets/utils.cpp index ab1d74fd..687c76e4 100644 --- a/muse2/muse/widgets/utils.cpp +++ b/muse2/muse/widgets/utils.cpp @@ -532,7 +532,7 @@ int get_paste_len()                          if (tag == "part")                                {                                Part* p = 0; -                              p = readXmlPart(xml, NULL, false, false); +                              p = Part::readFromXml(xml, NULL, false, false);                                if (p)                                      { @@ -542,7 +542,7 @@ int get_paste_len()                                      if (p->endTick() > end_tick)                                            end_tick=p->endTick(); -                                    unchainClone(p); +                                    p->unchainClone(); // just for safety; shouldn't be chained anyway.                                      delete p;                                      }                                }  | 
