summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2013-09-18 23:54:35 +0200
committerFlorian Jung <flo@windfisch.org>2013-09-18 23:54:35 +0200
commitb3fc353a09496ee0aea7099d72e6963f4c2fc774 (patch)
tree83ab91e988c59076d81ebddc09e8ff274dee8af5
parent48a93993cfce160fb7d4cf0b67b4b77e22db19e5 (diff)
parent85a51421d44f3893a1010f77e0418caf6be70235 (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.)
-rw-r--r--muse2/muse/arranger/arrangerview.cpp4
-rw-r--r--muse2/muse/arranger/pcanvas.cpp751
-rw-r--r--muse2/muse/arranger/pcanvas.h3
-rw-r--r--muse2/muse/arranger/tlist.cpp212
-rw-r--r--muse2/muse/audio.cpp62
-rw-r--r--muse2/muse/audio.h67
-rw-r--r--muse2/muse/ctrl/ctrlcanvas.cpp5
-rw-r--r--muse2/muse/event.cpp8
-rw-r--r--muse2/muse/event.h22
-rw-r--r--muse2/muse/eventbase.h6
-rw-r--r--muse2/muse/eventlist.cpp38
-rw-r--r--muse2/muse/exportmidi.cpp18
-rw-r--r--muse2/muse/functions.cpp469
-rw-r--r--muse2/muse/functions.h77
-rw-r--r--muse2/muse/helper.cpp8
-rw-r--r--muse2/muse/helper.h2
-rw-r--r--muse2/muse/importmidi.cpp53
-rw-r--r--muse2/muse/liste/listedit.cpp4
-rw-r--r--muse2/muse/midi.cpp23
-rw-r--r--muse2/muse/midi.h2
-rw-r--r--muse2/muse/midiedit/dcanvas.cpp63
-rw-r--r--muse2/muse/midiedit/dcanvas.h6
-rw-r--r--muse2/muse/midiedit/dlist.cpp9
-rw-r--r--muse2/muse/midiedit/drumedit.cpp8
-rw-r--r--muse2/muse/midiedit/ecanvas.cpp3
-rw-r--r--muse2/muse/midiedit/ecanvas.h2
-rw-r--r--muse2/muse/midiedit/piano.cpp3
-rw-r--r--muse2/muse/midiedit/prcanvas.cpp17
-rw-r--r--muse2/muse/midiedit/prcanvas.h4
-rw-r--r--muse2/muse/midiedit/scoreedit.cpp78
-rw-r--r--muse2/muse/midiedit/scoreedit.h38
-rw-r--r--muse2/muse/midieditor.cpp10
-rw-r--r--muse2/muse/midieditor.h2
-rw-r--r--muse2/muse/midievent.cpp17
-rw-r--r--muse2/muse/midievent.h6
-rw-r--r--muse2/muse/midiseq.cpp307
-rw-r--r--muse2/muse/midiseq.h1
-rw-r--r--muse2/muse/miditransform.cpp143
-rw-r--r--muse2/muse/miditransform.h9
-rw-r--r--muse2/muse/mixer/strip.cpp6
-rw-r--r--muse2/muse/part.cpp743
-rw-r--r--muse2/muse/part.h80
-rw-r--r--muse2/muse/remote/pyapi.cpp14
-rw-r--r--muse2/muse/seqmsg.cpp337
-rw-r--r--muse2/muse/song.cpp519
-rw-r--r--muse2/muse/song.h79
-rw-r--r--muse2/muse/songfile.cpp420
-rw-r--r--muse2/muse/steprec.cpp28
-rw-r--r--muse2/muse/steprec.h2
-rw-r--r--muse2/muse/structure.cpp84
-rw-r--r--muse2/muse/synth.cpp6
-rw-r--r--muse2/muse/track.cpp158
-rw-r--r--muse2/muse/track.h13
-rw-r--r--muse2/muse/undo.cpp570
-rw-r--r--muse2/muse/undo.h71
-rw-r--r--muse2/muse/wave.cpp11
-rw-r--r--muse2/muse/waveedit/wavecanvas.cpp45
-rw-r--r--muse2/muse/waveedit/wavecanvas.h4
-rw-r--r--muse2/muse/waveedit/waveview.cpp5
-rw-r--r--muse2/muse/waveevent.cpp13
-rw-r--r--muse2/muse/waveevent.h6
-rw-r--r--muse2/muse/wavetrack.cpp51
-rw-r--r--muse2/muse/widgets/mtrackinfo.cpp12
-rw-r--r--muse2/muse/widgets/utils.cpp4
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;
}
}