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 | |
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.)
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; } } |