From c6f2151b1589c91292563a1b319cdbd193834d67 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 7 Jun 2011 18:45:32 +0000 Subject: modified behaviour for clones: - resizing a clone in the arranger also resizes all clones with the same length - same for auto-expanding in the pianoroll - auto-expanding in the pianoroll does NOT expand for parts which already contain hidden notes; then inserting notes is forbidden; buggy, see below still TODO and BUGS: - forbidding notes doesn't work properly. the pianoroll still displays them until the next full song update. - that stuff must be done in the drum canvas as well - step-rec and the score editor need support for auto-expanding --- muse2/muse/arranger/pcanvas.cpp | 4 +-- muse2/muse/arranger/pcanvas.h | 2 +- muse2/muse/functions.cpp | 39 ++++++++++++++++++++++++++ muse2/muse/functions.h | 2 ++ muse2/muse/midiedit/dcanvas.cpp | 2 +- muse2/muse/midiedit/dcanvas.h | 2 +- muse2/muse/midiedit/prcanvas.cpp | 58 +++++++++++++++++++-------------------- muse2/muse/midiedit/prcanvas.h | 2 +- muse2/muse/midiedit/scoreedit.cpp | 9 ++++-- muse2/muse/part.cpp | 53 +++++++++++++++++++---------------- muse2/muse/part.h | 2 ++ muse2/muse/song.h | 2 +- muse2/muse/widgets/canvas.cpp | 2 +- muse2/muse/widgets/canvas.h | 2 +- 14 files changed, 117 insertions(+), 64 deletions(-) diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp index f7a2abde..9fefaf70 100644 --- a/muse2/muse/arranger/pcanvas.cpp +++ b/muse2/muse/arranger/pcanvas.cpp @@ -448,7 +448,7 @@ void PartCanvas::updateSelection() // resizeItem //--------------------------------------------------------- -void PartCanvas::resizeItem(CItem* i, bool noSnap) +void PartCanvas::resizeItem(CItem* i, bool noSnap, bool ctrl) { Track* t = ((NPart*)(i))->track(); Part* p = ((NPart*)(i))->part(); @@ -462,7 +462,7 @@ void PartCanvas::resizeItem(CItem* i, bool noSnap) if (newwidth == 0) newwidth = AL::sigmap.rasterStep(p->tick(), *_raster); - song->cmdResizePart(t, p, newwidth); + song->cmdResizePart(t, p, newwidth, !ctrl); } //--------------------------------------------------------- diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h index acfe565e..ccfb1fcc 100644 --- a/muse2/muse/arranger/pcanvas.h +++ b/muse2/muse/arranger/pcanvas.h @@ -83,7 +83,7 @@ class PartCanvas : public Canvas { virtual int pitch2y(int p) const; virtual CItem* newItem(const QPoint&, int); - virtual void resizeItem(CItem*,bool); + virtual void resizeItem(CItem*,bool, bool ctrl); virtual void newItem(CItem*,bool); virtual bool deleteItem(CItem*); virtual void moveCanvasItems(CItemList&, int, int, DragType); diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index b47874fd..9ab209c6 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -866,6 +866,45 @@ void shrink_parts(int raster) song->applyOperationGroup(operations); } +void internal_schedule_expand_part(Part* part, int raster, Undo& operations) +{ + EventList* events=part->events(); + unsigned len=part->lenTick(); + + for (iEvent ev=events->begin(); ev!=events->end(); ev++) + if (ev->second.endTick() > len) + len=ev->second.endTick(); + + if (raster) len=ceil((float)len/raster)*raster; + + if (len > part->lenTick()) + { + MidiPart* new_part = new MidiPart(*(MidiPart*)part); + new_part->setLenTick(len); + operations.push_back(UndoOp(UndoOp::ModifyPart, part, new_part, true, false)); + } +} + +void schedule_resize_all_same_len_clone_parts(Part* part, unsigned new_len, Undo& operations) +{ + unsigned old_len=part->lenTick(); + if (old_len!=new_len) + { + Part* part_it=part; + do + { + if (part_it->lenTick()==old_len) + { + 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)); + } + + part_it=part_it->nextClone(); + } while (part_it!=part); + } +} + void expand_parts(int raster) { Undo operations; diff --git a/muse2/muse/functions.h b/muse2/muse/functions.h index 633457a9..90fc64e9 100644 --- a/muse2/muse/functions.h +++ b/muse2/muse/functions.h @@ -24,6 +24,7 @@ class QString; class QMimeData; +class Undo; extern GateTime* gatetime_dialog; extern Velocity* velocity_dialog; @@ -87,6 +88,7 @@ void select_not_in_loop(const std::set& 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 clean_parts(); //functions for reading and writing default values diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index 92e514af..b19831a0 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -308,7 +308,7 @@ CItem* DrumCanvas::newItem(int tick, int instrument, int velocity) // resizeItem //--------------------------------------------------------- -void DrumCanvas::resizeItem(CItem* item, bool) +void DrumCanvas::resizeItem(CItem* item, bool, bool) { DEvent* nevent = (DEvent*) item; Event ev = nevent->event(); diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h index 868113a6..a2d0f7de 100644 --- a/muse2/muse/midiedit/dcanvas.h +++ b/muse2/muse/midiedit/dcanvas.h @@ -57,7 +57,7 @@ class DrumCanvas : public EventCanvas { virtual Undo moveCanvasItems(CItemList&, int, int, DragType); virtual UndoOp moveItem(CItem*, const QPoint&, DragType); virtual CItem* newItem(const QPoint&, int); - virtual void resizeItem(CItem*, bool); + virtual void resizeItem(CItem*, bool, bool); virtual void newItem(CItem*, bool); virtual void newItem(CItem*, bool, bool replace ); virtual bool deleteItem(CItem*); diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index 091582ef..db42be6c 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -479,28 +479,28 @@ void PianoCanvas::newItem(CItem* item, bool noSnap) event.setLenTick(w); event.setPitch(y2pitch(item->y())); - song->startUndo(); - int modified=SC_EVENT_MODIFIED; + Undo operations; int diff = event.endTick()-part->lenTick(); - if (diff > 0) {// too short part? extend it - //printf("extend Part!\n"); - Part* newPart = part->clone(); - newPart->setLenTick(newPart->lenTick()+diff); - // Indicate no undo, and do port controller values but not clone parts. - audio->msgChangePart(part, newPart, false, true, false); - modified=modified|SC_PART_MODIFIED; - part = newPart; // reassign + + if (! ((diff > 0) && part->hasHiddenNotes()) ) //operation is allowed + { + operations.push_back(UndoOp(UndoOp::AddEvent,event, part, false, false)); + + if (diff > 0)// part must be extended? + { + schedule_resize_all_same_len_clone_parts(part, event.endTick(), operations); + printf("newItem: extending\n"); } - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgAddEvent(event, part, false, false, false); - song->endUndo(modified); + } + //FINDMICH TODO: forbid action! this is currently wrong! + song->applyOperationGroup(operations); } //--------------------------------------------------------- // resizeItem //--------------------------------------------------------- -void PianoCanvas::resizeItem(CItem* item, bool noSnap) // experimental changes to try dynamically extending parts +void PianoCanvas::resizeItem(CItem* item, bool noSnap, bool) // experimental changes to try dynamically extending parts { //printf("resizeItem!\n"); NEvent* nevent = (NEvent*) item; @@ -519,23 +519,23 @@ void PianoCanvas::resizeItem(CItem* item, bool noSnap) // experimental c if (len <= 0) len = editor->raster(); } - song->startUndo(); - int modified=SC_EVENT_MODIFIED; + + Undo operations; int diff = event.tick()+len-part->lenTick(); - if (diff > 0) {// too short part? extend it - //printf("extend Part!\n"); - Part* newPart = part->clone(); - newPart->setLenTick(newPart->lenTick()+diff); - // Indicate no undo, and do port controller values but not clone parts. - audio->msgChangePart(part, newPart, false, true, false); - modified=modified|SC_PART_MODIFIED; - part = newPart; // reassign - } + + if (! ((diff > 0) && part->hasHiddenNotes()) ) //operation is allowed + { + newEvent.setLenTick(len); + operations.push_back(UndoOp(UndoOp::ModifyEvent,newEvent, event, nevent->part(), false, false)); + + if (diff > 0)// part must be extended? + { + schedule_resize_all_same_len_clone_parts(part, event.tick()+len, operations); + printf("resizeItem: extending\n");} + } + //FINDMICH TODO: forbid action! this is currently wrong! + song->applyOperationGroup(operations); - newEvent.setLenTick(len); - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false); - song->endUndo(modified); } //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h index c6e47c9e..d96dd4df 100644 --- a/muse2/muse/midiedit/prcanvas.h +++ b/muse2/muse/midiedit/prcanvas.h @@ -57,7 +57,7 @@ class PianoCanvas : public EventCanvas { virtual Undo moveCanvasItems(CItemList&, int, int, DragType); virtual UndoOp moveItem(CItem*, const QPoint&, DragType); virtual CItem* newItem(const QPoint&, int); - virtual void resizeItem(CItem*, bool noSnap); + virtual void resizeItem(CItem*, bool noSnap, bool); virtual void newItem(CItem*, bool noSnap); virtual bool deleteItem(CItem*); virtual void startDrag(CItem* item, bool copymode); diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index 1a885d99..f7d9237b 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -4457,11 +4457,14 @@ void staff_t::update_part_indices() * between, for example, when a cis is tied to a des * * CURRENT TODO - * o clones should have same size - * o insert empty measure should also work inside parts, that is, - * move notes _within_ parts + * o do autoexpand correctly in prcanvas.cpp, then port that to + * dcanvas.cpp, steprec.cpp and scoreedit.cpp * * IMPORTANT TODO + * o shrink a part from its beginning as well! watch out for clones! + * o insert empty measure should also work inside parts, that is, + * move notes _within_ parts + * * o canvas editor: create clone via "alt+drag" moves window instead * o investigate with valgrind * o controller view in score editor diff --git a/muse2/muse/part.cpp b/muse2/muse/part.cpp index 398720af..9bb3431c 100644 --- a/muse2/muse/part.cpp +++ b/muse2/muse/part.cpp @@ -819,7 +819,7 @@ void Song::removePart(Part* part) // cmdResizePart //--------------------------------------------------------- -void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len) +void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len, bool doClones) { switch(track->type()) { case Track::WAVE: @@ -899,28 +899,21 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len) case Track::DRUM: { Undo operations; - - MidiPart* nPart = new MidiPart(*(MidiPart*)oPart); - nPart->setLenTick(len); - // Do port controller values but not clone parts. - operations.push_back(UndoOp(UndoOp::ModifyPart, oPart, nPart, true, false)); - - // cut Events in nPart - // Changed by T356. Don't delete events if this is a clone part. - // The other clones might be longer than this one and need these events. - if(nPart->cevents()->arefCount() <= 1) - { - if(oPart->lenTick() > len) { - EventList* el = nPart->events(); - iEvent ie = el->lower_bound(len); - for (; ie != el->end();) { - iEvent i = ie; - ++ie; - // Do port controller values and clone parts. - operations.push_back(UndoOp(UndoOp::DeleteEvent, i->second, nPart, true, true)); - } - } - } + + unsigned orig_len=oPart->lenTick(); + MidiPart* part_it=(MidiPart*)oPart; + do + { + 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)); + } + + part_it=(MidiPart*)part_it->nextClone(); + } while (doClones && (part_it != (MidiPart*)oPart)); song->applyOperationGroup(operations); break; @@ -1176,3 +1169,17 @@ WavePart* WavePart::clone() const return new WavePart(*this); } + + +bool Part::hasHiddenNotes() +{ + unsigned lastNote=0; + + for (iEvent ev=events()->begin(); ev!=events()->end(); ev++) + if (ev->second.endTick() > lastNote) + lastNote=ev->second.endTick(); + + printf ("in hasHiddenNotes: lastNote=%i, lenTick=%i\n",lastNote, lenTick()); + + return lastNote > lenTick(); +} diff --git a/muse2/muse/part.h b/muse2/muse/part.h index 9b037edd..ff7091a6 100644 --- a/muse2/muse/part.h +++ b/muse2/muse/part.h @@ -82,6 +82,8 @@ class Part : public PosLen { void setPrevClone(Part* p) { _prevClone = p; } void setNextClone(Part* p) { _nextClone = p; } + bool hasHiddenNotes(); + iEvent addEvent(Event& p); virtual void write(int, Xml&, bool isCopy = false, bool forceWavePaths = false) const; diff --git a/muse2/muse/song.h b/muse2/muse/song.h index fd88b278..45751418 100644 --- a/muse2/muse/song.h +++ b/muse2/muse/song.h @@ -253,7 +253,7 @@ class Song : public QObject { // part manipulations //----------------------------------------- - void cmdResizePart(Track* t, Part* p, unsigned int size); + 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); diff --git a/muse2/muse/widgets/canvas.cpp b/muse2/muse/widgets/canvas.cpp index 650b10b7..9025590a 100644 --- a/muse2/muse/widgets/canvas.cpp +++ b/muse2/muse/widgets/canvas.cpp @@ -1131,7 +1131,7 @@ void Canvas::viewMouseReleaseEvent(QMouseEvent* event) case DRAG_OFF: break; case DRAG_RESIZE: - resizeItem(curItem, false); + resizeItem(curItem, false, ctrl); break; case DRAG_NEW: newItem(curItem, false); diff --git a/muse2/muse/widgets/canvas.h b/muse2/muse/widgets/canvas.h index 2eae3d03..dbe13fcb 100644 --- a/muse2/muse/widgets/canvas.h +++ b/muse2/muse/widgets/canvas.h @@ -102,7 +102,7 @@ class Canvas : public View { virtual int pitch2y(int) const = 0; //CDW virtual CItem* newItem(const QPoint&, int state) = 0; - virtual void resizeItem(CItem*, bool noSnap=false) = 0; + virtual void resizeItem(CItem*, bool noSnap=false, bool ctrl=false) = 0; virtual void newItem(CItem*, bool noSnap=false) = 0; virtual bool deleteItem(CItem*) = 0; int getCurrentDrag(); -- cgit v1.2.3 From 2f4a98c62adf7241944ea7949d4b6a50d4b4af36 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Fri, 10 Jun 2011 13:48:16 +0000 Subject: fixed problem with forbidden notes (see previous commit) shift now also selects all items on the same pitch when ctrl is pressed --- muse2/muse/midiedit/prcanvas.cpp | 9 ++++++--- muse2/muse/midiedit/scoreedit.cpp | 1 - muse2/muse/widgets/canvas.cpp | 23 ++++++++++++----------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index db42be6c..11a142e1 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -492,8 +492,10 @@ void PianoCanvas::newItem(CItem* item, bool noSnap) printf("newItem: extending\n"); } } - //FINDMICH TODO: forbid action! this is currently wrong! + //else forbid action by not applying it song->applyOperationGroup(operations); + songChanged(SC_EVENT_INSERTED); //this forces an update of the itemlist, which is neccessary + //to remove "forbidden" events from the list again } //--------------------------------------------------------- @@ -533,9 +535,10 @@ void PianoCanvas::resizeItem(CItem* item, bool noSnap, bool) // experime schedule_resize_all_same_len_clone_parts(part, event.tick()+len, operations); printf("resizeItem: extending\n");} } - //FINDMICH TODO: forbid action! this is currently wrong! + //else forbid action by not performing it song->applyOperationGroup(operations); - + songChanged(SC_EVENT_MODIFIED); //this forces an update of the itemlist, which is neccessary + //to remove "forbidden" events from the list again } //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index f7d9237b..c14c14fd 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -4452,7 +4452,6 @@ void staff_t::update_part_indices() /* BUGS and potential bugs - * o when the keymap is not used, this will probably lead to a bug * o tied notes don't work properly when there's a key-change in * between, for example, when a cis is tied to a des * diff --git a/muse2/muse/widgets/canvas.cpp b/muse2/muse/widgets/canvas.cpp index 9025590a..a74e8a8f 100644 --- a/muse2/muse/widgets/canvas.cpp +++ b/muse2/muse/widgets/canvas.cpp @@ -525,7 +525,6 @@ void Canvas::viewMousePressEvent(QMouseEvent* event) //printf("viewMousePressEvent ignoring buttons:%x mods:%x button:%x\n", (int)event->buttons(), (int)keyState, event->button()); return; } - bool shift = keyState & Qt::ShiftModifier; bool alt = keyState & Qt::AltModifier; bool ctrl = keyState & Qt::ControlModifier; start = event->pos(); @@ -624,15 +623,6 @@ void Canvas::viewMousePressEvent(QMouseEvent* event) else if (alt) { drag = DRAG_CLONE_START; } - else if (shift) { //Select all on the same pitch (e.g. same y-value) - deselectAll(); - for (iCItem i = items.begin(); i != items.end(); ++i) { - if (i->second->y() == curItem->y() ) - selectItem(i->second, true); - } - updateSelection(); - redraw(); - } else drag = DRAG_MOVE_START; } @@ -1088,6 +1078,7 @@ void Canvas::viewMouseReleaseEvent(QMouseEvent* event) QPoint pos = event->pos(); bool ctrl = ((QInputEvent*)event)->modifiers() & Qt::ControlModifier; + bool shift = ((QInputEvent*)event)->modifiers() & Qt::ShiftModifier; bool redrawFlag = false; switch (drag) { @@ -1096,7 +1087,17 @@ void Canvas::viewMouseReleaseEvent(QMouseEvent* event) case DRAG_CLONE_START: if (!ctrl) deselectAll(); - selectItem(curItem, !(ctrl && curItem->isSelected())); + + if (!shift) { //Select or deselect only the clicked item + selectItem(curItem, !(ctrl && curItem->isSelected())); + } + else { //Select or deselect all on the same pitch (e.g. same y-value) + bool selectionFlag = !(ctrl && curItem->isSelected()); + for (iCItem i = items.begin(); i != items.end(); ++i) + if (i->second->y() == curItem->y() ) + selectItem(i->second, selectionFlag); + } + updateSelection(); redrawFlag = true; itemReleased(curItem, curItem->pos()); -- cgit v1.2.3 From 416fa4c9121621bec775f2590554e6219c045f96 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 28 Jun 2011 12:42:32 +0000 Subject: yay! commit #1000 =) forgot a single, tiny change in the changelog (and yeah, i wanted to do this commit myself ;) ) btw, the merge was successful =) *happy* --- muse2/ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muse2/ChangeLog b/muse2/ChangeLog index f21cd4ba..260d7225 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,3 +1,6 @@ +27.06.2011: + - Massively speeded up muse by using operation groups (flo93) + - Changed behaviour of middle click in all canvases to "delete" (flo93) 21.06.2011: - Fixed wave editor position and marker drawing corruption. (Tim) - Updated Yamaha m06 IDF file to version 4 by Geoff King. (Tim) -- cgit v1.2.3 From 9633b537bea22bc753ca8e3e0481fd38419524ae Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 28 Jun 2011 15:43:50 +0000 Subject: autoexpand now works properly also for moving notes --- muse2/muse/midiedit/dcanvas.cpp | 159 +++++++++++++++++--------------------- muse2/muse/midiedit/ecanvas.cpp | 7 +- muse2/muse/midiedit/prcanvas.cpp | 136 ++++++++++++++------------------ muse2/muse/midiedit/scoreedit.cpp | 3 +- muse2/muse/part.cpp | 2 - 5 files changed, 139 insertions(+), 168 deletions(-) diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index b19831a0..4b5c3ea9 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -104,9 +104,9 @@ Undo DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp { if(editor->parts()->empty()) return Undo(); //return empty list - + PartsToChangeMap parts2change; - Undo operations; + Undo operations; for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) { @@ -153,85 +153,66 @@ Undo DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp ip2c->second.xdiff = npartoffset; } } - + + bool forbidden=false; for(iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c) { Part* opart = ip2c->first; int diff = ip2c->second.xdiff; - Part* newPart = opart->clone(); - - newPart->setLenTick(newPart->lenTick() + diff); - - // BUG FIX: #1650953 - // Added by T356. - // Fixes posted "select and drag past end of part - crashing" bug - for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) + if (opart->hasHiddenNotes()) { - if(ip->second == opart) - { - editor->parts()->erase(ip); - break; - } - } - - editor->parts()->add(newPart); - // Do port controller values but not clone parts. - operations.push_back(UndoOp(UndoOp::ModifyPart, opart, newPart, true, false)); - - ip2c->second.npart = newPart; + forbidden=true; + break; + } + schedule_resize_all_same_len_clone_parts(opart, opart->lenTick() + diff, operations); + } + + + if (!forbidden) + { + std::vector< CItem* > doneList; + typedef std::vector< CItem* >::iterator iDoneList; + + for(iCItem ici = items.begin(); ici != items.end(); ++ici) + { + CItem* ci = ici->second; + + int x = ci->pos().x(); + int y = ci->pos().y(); + int nx = x + dx; + int ny = pitch2y(y2pitch(y) + dp); + QPoint newpos = raster(QPoint(nx, ny)); + selectItem(ci, true); + + iDoneList idl; + for(idl = doneList.begin(); idl != doneList.end(); ++idl) + // This compares EventBase pointers to see if they're the same... + if((*idl)->event() == ci->event()) + break; + + // Do not process if the event has already been processed (meaning it's an event in a clone part)... + if (idl == doneList.end()) + { + operations.push_back(moveItem(ci, newpos, dtype)); + doneList.push_back(ci); + } + ci->move(newpos); + + if(moving.size() == 1) + itemReleased(curItem, newpos); + + if(dtype == MOVE_COPY || dtype == MOVE_CLONE) + selectItem(ci, false); + } + + return operations; } - - iPartToChange icp = parts2change.find(curPart); - if(icp != parts2change.end()) - { - curPart = icp->second.npart; - curPartId = curPart->sn(); - } - - std::vector< CItem* > doneList; - typedef std::vector< CItem* >::iterator iDoneList; - - for(iCItem ici = items.begin(); ici != items.end(); ++ici) + else { - CItem* ci = ici->second; - - // If this item's part is in the parts2change list, change the item's part to the new part. - Part* pt = ci->part(); - iPartToChange ip2c = parts2change.find(pt); - if(ip2c != parts2change.end()) - ci->setPart(ip2c->second.npart); - - int x = ci->pos().x(); - int y = ci->pos().y(); - int nx = x + dx; - int ny = pitch2y(y2pitch(y) + dp); - QPoint newpos = raster(QPoint(nx, ny)); - selectItem(ci, true); - - iDoneList idl; - for(idl = doneList.begin(); idl != doneList.end(); ++idl) - // This compares EventBase pointers to see if they're the same... - if((*idl)->event() == ci->event()) - break; - - // Do not process if the event has already been processed (meaning it's an event in a clone part)... - if (idl == doneList.end()) - { - operations.push_back(moveItem(ci, newpos, dtype)); - doneList.push_back(ci); - } - ci->move(newpos); - - if(moving.size() == 1) { - itemReleased(curItem, newpos); - } - if(dtype == MOVE_COPY || dtype == MOVE_CLONE) - selectItem(ci, false); - } - - return operations; + return Undo(); //return empty list + } } //--------------------------------------------------------- @@ -261,9 +242,10 @@ UndoOp DrumCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) //item->setPart(part); item->setEvent(newEvent); - // Added by T356. - if(((int)newEvent.endTick() - (int)part->lenTick()) > 0) - printf("DrumCanvas::moveItem Error! New event end:%d exceeds length:%d of part:%s\n", newEvent.endTick(), part->lenTick(), part->name().toLatin1().constData()); + // Added by T356, removed by flo93: with operation groups, it happens that the + // part is too short right now, even if it's queued for being extended + //if(((int)newEvent.endTick() - (int)part->lenTick()) > 0) + // printf("DrumCanvas::moveItem Error! New event end:%d exceeds length:%d of part:%s\n", newEvent.endTick(), part->lenTick(), part->name().toLatin1().constData()); if (dtype == MOVE_COPY || dtype == MOVE_CLONE) return UndoOp(UndoOp::AddEvent, newEvent, part, false, false); @@ -361,20 +343,23 @@ void DrumCanvas::newItem(CItem* item, bool noSnap, bool replace) // Added by T356. Part* part = nevent->part(); - song->startUndo(); - int modified=SC_EVENT_MODIFIED; + Undo operations; int diff = event.endTick()-part->lenTick(); - if (diff > 0) {// too short part? extend it - Part* newPart = part->clone(); - newPart->setLenTick(newPart->lenTick()+diff); - // Indicate no undo, and do port controller values but not clone parts. - audio->msgChangePart(part, newPart, false, true, false); - modified=modified|SC_PART_MODIFIED; - part = newPart; // reassign + + if (! ((diff > 0) && part->hasHiddenNotes()) ) //operation is allowed + { + operations.push_back(UndoOp(UndoOp::AddEvent,event, part, false, false)); + + if (diff > 0)// part must be extended? + { + schedule_resize_all_same_len_clone_parts(part, event.endTick(), operations); + printf("newItem: extending\n"); } - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgAddEvent(event, part, false, false, false); - song->endUndo(modified); + } + //else forbid action by not applying it + song->applyOperationGroup(operations); + songChanged(SC_EVENT_INSERTED); //this forces an update of the itemlist, which is neccessary + //to remove "forbidden" events from the list again } //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp index ef47e0d6..a829650c 100644 --- a/muse2/muse/midiedit/ecanvas.cpp +++ b/muse2/muse/midiedit/ecanvas.cpp @@ -416,7 +416,12 @@ void EventCanvas::endMoveItems(const QPoint& pos, DragType dragtype, int dir) Undo operations = moveCanvasItems(moving, dp, dx, dragtype); - song->applyOperationGroup(operations); + if (operations.empty()) + songChanged(SC_EVENT_MODIFIED); //this is a hack to force the canvas to repopulate + //itself. otherwise, if a moving operation was forbidden, + //the canvas would still show the movement + else + song->applyOperationGroup(operations); moving.clear(); updateSelection(); diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index 11a142e1..a659ad26 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -261,8 +261,8 @@ Undo PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty if(editor->parts()->empty()) return Undo(); //return empty list - Undo operations; PartsToChangeMap parts2change; + Undo operations; for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) { @@ -310,84 +310,65 @@ Undo PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty } } + bool forbidden=false; for(iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c) { Part* opart = ip2c->first; int diff = ip2c->second.xdiff; - Part* newPart = opart->clone(); - - newPart->setLenTick(newPart->lenTick() + diff); - - // BUG FIX: #1650953 - // Added by T356. - // Fixes posted "select and drag past end of part - crashing" bug - for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) + if (opart->hasHiddenNotes()) { - if(ip->second == opart) - { - editor->parts()->erase(ip); - break; - } - } - - editor->parts()->add(newPart); - // Do port controller values but not clone parts. - operations.push_back(UndoOp(UndoOp::ModifyPart, opart, newPart, true, false)); - - ip2c->second.npart = newPart; + forbidden=true; + break; + } + schedule_resize_all_same_len_clone_parts(opart, opart->lenTick() + diff, operations); + } + + + if (!forbidden) + { + std::vector< CItem* > doneList; + typedef std::vector< CItem* >::iterator iDoneList; + + for(iCItem ici = items.begin(); ici != items.end(); ++ici) + { + CItem* ci = ici->second; + + int x = ci->pos().x(); + int y = ci->pos().y(); + int nx = x + dx; + int ny = pitch2y(y2pitch(y) + dp); + QPoint newpos = raster(QPoint(nx, ny)); + selectItem(ci, true); + + iDoneList idl; + for(idl = doneList.begin(); idl != doneList.end(); ++idl) + // This compares EventBase pointers to see if they're the same... + if((*idl)->event() == ci->event()) + break; + + // Do not process if the event has already been processed (meaning it's an event in a clone part)... + if (idl == doneList.end()) + { + operations.push_back(moveItem(ci, newpos, dtype)); + doneList.push_back(ci); + } + ci->move(newpos); + + if(moving.size() == 1) + itemReleased(curItem, newpos); + + if(dtype == MOVE_COPY || dtype == MOVE_CLONE) + selectItem(ci, false); + } + + return operations; } - - iPartToChange icp = parts2change.find(curPart); - if(icp != parts2change.end()) - { - curPart = icp->second.npart; - curPartId = curPart->sn(); - } - - std::vector< CItem* > doneList; - typedef std::vector< CItem* >::iterator iDoneList; - - - for(iCItem ici = items.begin(); ici != items.end(); ++ici) + else { - CItem* ci = ici->second; - - // If this item's part is in the parts2change list, change the item's part to the new part. - Part* pt = ci->part(); - iPartToChange ip2c = parts2change.find(pt); - if(ip2c != parts2change.end()) - ci->setPart(ip2c->second.npart); - - int x = ci->pos().x(); - int y = ci->pos().y(); - int nx = x + dx; - int ny = pitch2y(y2pitch(y) + dp); - QPoint newpos = raster(QPoint(nx, ny)); - selectItem(ci, true); - - iDoneList idl; - for(idl = doneList.begin(); idl != doneList.end(); ++idl) - // This compares EventBase pointers to see if they're the same... - if((*idl)->event() == ci->event()) - break; - - // Do not process if the event has already been processed (meaning it's an event in a clone part)... - if (idl == doneList.end()) - { - operations.push_back(moveItem(ci, newpos, dtype)); - doneList.push_back(ci); - } - ci->move(newpos); - - if(moving.size() == 1) - itemReleased(curItem, newpos); - if(dtype == MOVE_COPY || dtype == MOVE_CLONE) - selectItem(ci, false); - } - - return operations; + return Undo(); //return empty list + } } //--------------------------------------------------------- @@ -427,9 +408,10 @@ UndoOp PianoCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) item->setEvent(newEvent); - // Added by T356. - if(((int)newEvent.endTick() - (int)part->lenTick()) > 0) - printf("PianoCanvas::moveItem Error! New event end:%d exceeds length:%d of part:%s\n", newEvent.endTick(), part->lenTick(), part->name().toLatin1().constData()); + // Added by T356, removed by flo93: with operation groups, it happens that the + // part is too short right now, even if it's queued for being extended + //if(((int)newEvent.endTick() - (int)part->lenTick()) > 0) + // printf("PianoCanvas::moveItem Error! New event end:%d exceeds length:%d of part:%s\n", newEvent.endTick(), part->lenTick(), part->name().toLatin1().constData()); if (dtype == MOVE_COPY || dtype == MOVE_CLONE) return UndoOp(UndoOp::AddEvent, newEvent, part, false, false); @@ -491,11 +473,13 @@ void PianoCanvas::newItem(CItem* item, bool noSnap) schedule_resize_all_same_len_clone_parts(part, event.endTick(), operations); printf("newItem: extending\n"); } + + song->applyOperationGroup(operations); } //else forbid action by not applying it - song->applyOperationGroup(operations); - songChanged(SC_EVENT_INSERTED); //this forces an update of the itemlist, which is neccessary - //to remove "forbidden" events from the list again + else + songChanged(SC_EVENT_INSERTED); //this forces an update of the itemlist, which is neccessary + //to remove "forbidden" events from the list again } //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index c14c14fd..c2380539 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -4456,8 +4456,7 @@ void staff_t::update_part_indices() * between, for example, when a cis is tied to a des * * CURRENT TODO - * o do autoexpand correctly in prcanvas.cpp, then port that to - * dcanvas.cpp, steprec.cpp and scoreedit.cpp + * o do autoexpand in steprec.cpp and scoreedit.cpp * * IMPORTANT TODO * o shrink a part from its beginning as well! watch out for clones! diff --git a/muse2/muse/part.cpp b/muse2/muse/part.cpp index 9bb3431c..67cf441e 100644 --- a/muse2/muse/part.cpp +++ b/muse2/muse/part.cpp @@ -1179,7 +1179,5 @@ bool Part::hasHiddenNotes() if (ev->second.endTick() > lastNote) lastNote=ev->second.endTick(); - printf ("in hasHiddenNotes: lastNote=%i, lenTick=%i\n",lastNote, lenTick()); - return lastNote > lenTick(); } -- cgit v1.2.3 From 363cebc27a30edcca80fe24f1b535dc0b39efd15 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 29 Jun 2011 18:43:33 +0000 Subject: added autoexpand to steprec.cpp reformatted StepRec::record to Allman style ("my" style) fixed a bug in steprec.cpp: parts with tick() being !=0 were treated wrong --- muse2/muse/midiedit/dcanvas.cpp | 4 +- muse2/muse/midiedit/prcanvas.cpp | 7 +- muse2/muse/midiedit/scoreedit.cpp | 4 +- muse2/muse/steprec.cpp | 248 +++++++++++++++++++++----------------- 4 files changed, 144 insertions(+), 119 deletions(-) diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index 4b5c3ea9..b9ff5a20 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -731,7 +731,7 @@ void DrumCanvas::keyPressed(int index, int velocity) MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); audio->msgPlayMidiEvent(&e); - if (_steprec && pos[0] >= start_tick && pos[0] < end_tick && curPart) + if (_steprec && pos[0] >= start_tick /* && pos[0] < end_tick [removed by flo93: this is handled in steprec->record] */ && curPart) steprec->record(curPart,index,drumMap[index].len,editor->raster(),velocity,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier); } @@ -1120,7 +1120,7 @@ void DrumCanvas::midiNote(int pitch, int velo) if (_midiin && _steprec && curPart && !audio->isPlaying() && velo && pos[0] >= start_tick - && pos[0] < end_tick + /* && pos[0] < end_tick [removed by flo93: this is handled in steprec->record] */ && !(globalKeyState & Qt::AltModifier)) { steprec->record(curPart,drumInmap[pitch],drumMap[(int)drumInmap[pitch]].len,editor->raster(),velo,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier); } diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index a659ad26..73e70e84 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -66,7 +66,7 @@ void PianoCanvas::addItem(Part* part, Event& event) NEvent* ev = new NEvent(event, part, pitch2y(event.pitch())); items.add(ev); - int diff = event.endTick()-part->lenTick(); + int diff = event.tick()-part->lenTick(); if (diff > 0) {// too short part? extend it //printf("addItem - this code should not be run!\n"); //Part* newPart = part->clone(); @@ -655,9 +655,8 @@ void PianoCanvas::pianoPressed(int pitch, int velocity, bool shift) MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); audio->msgPlayMidiEvent(&e); - if (_steprec && pos[0] >= start_tick && pos[0] < end_tick && curPart) { + if (_steprec && pos[0] >= start_tick /* && pos[0] < end_tick [removed by flo93: this is handled in steprec->record] */ && curPart) steprec->record(curPart,pitch,editor->raster(),editor->raster(),velocity,globalKeyState&Qt::ControlModifier,shift); - } } //--------------------------------------------------------- @@ -881,7 +880,7 @@ void PianoCanvas::midiNote(int pitch, int velo) if (_midiin && _steprec && curPart && !audio->isPlaying() && velo && pos[0] >= start_tick - && pos[0] < end_tick + /* && pos[0] < end_tick [removed by flo93: this is handled in steprec->record] */ && !(globalKeyState & Qt::AltModifier)) { steprec->record(curPart,pitch,editor->raster(),editor->raster(),velo,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier); } diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index c2380539..d7131db9 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -4456,7 +4456,8 @@ void staff_t::update_part_indices() * between, for example, when a cis is tied to a des * * CURRENT TODO - * o do autoexpand in steprec.cpp and scoreedit.cpp + * o do autoexpand in scoreedit.cpp + * o draw the edge of parts hiding notes "jagged" (hasHiddenNotes() is interesting for this) * * IMPORTANT TODO * o shrink a part from its beginning as well! watch out for clones! @@ -4477,6 +4478,7 @@ void staff_t::update_part_indices() * o transpose etc. must also transpose key-pressure events * o transpose: support in-key-transpose * o thin out: remove unneeded ctrl messages + * o make muse usable without the middle mouse button * * less important stuff * o quantize-templates (everything is forced into a specified diff --git a/muse2/muse/steprec.cpp b/muse2/muse/steprec.cpp index 29cb9540..c1fc23b1 100644 --- a/muse2/muse/steprec.cpp +++ b/muse2/muse/steprec.cpp @@ -9,6 +9,7 @@ #include "part.h" #include "event.h" #include "globals.h" +#include "functions.h" #include "song.h" #include "audio.h" @@ -39,121 +40,144 @@ void StepRec::timeout() void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ctrl, bool shift) { - unsigned tick = song->cpos(); - - if (pitch!=rcSteprecNote) { - chord_timer->stop(); - - - // - // extend len of last note? - // - EventList* events = part->events(); - if (ctrl) { - for (iEvent i = events->begin(); i != events->end(); ++i) { - Event ev = i->second; - if (!ev.isNote()) - continue; - if (ev.pitch() == pitch && ((ev.tick() + ev.lenTick()) == tick)) { - Event e = ev.clone(); - e.setLenTick(ev.lenTick() + len); - // Indicate do undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(ev, e, part, true, false, false); - - if (!shift) { - chord_timer_set_to_tick = tick + step; - chord_timer->start(); - } - return; - } - } - } + unsigned tick = song->cpos(); + unsigned lasttick=0; + Undo operations; + + if (pitch!=rcSteprecNote) + { + chord_timer->stop(); + + // extend len of last note? + EventList* events = part->events(); + if (ctrl) + { + for (iEvent i = events->begin(); i != events->end(); ++i) + { + Event ev = i->second; + if (ev.isNote() && ev.pitch() == pitch && ((ev.tick() + ev.lenTick() + part->tick()) == tick)) + { + Event e = ev.clone(); + e.setLenTick(ev.lenTick() + len); + operations.push_back(UndoOp(UndoOp::ModifyEvent, e,ev, part, false, false)); + + if (!shift) + { + chord_timer_set_to_tick = tick + step; + chord_timer->start(); + } + + lasttick=tick+len - part->tick(); + goto steprec_record_foot; + } + } + } - // - // if we already entered the note, delete it - // - EventRange range = events->equal_range(tick); - for (iEvent i = range.first; i != range.second; ++i) { - Event ev = i->second; - if (ev.isNote() && ev.pitch() == pitch) { - // Indicate do undo, and do not do port controller values and clone parts. - //audio->msgDeleteEvent(ev, part); - audio->msgDeleteEvent(ev, part, true, false, false); + if (tick<=part->endTick()) + { + // if we already entered the note, delete it + // if we would find a note after part->lenTick(), the above "if" + // avoids this. this has to be avoided because then part->hasHiddenNotes() 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) + { + Event ev = i->second; + if (ev.isNote() && ev.pitch() == pitch) + { + audio->msgDeleteEvent(ev, part, true, false, false); - if (!shift) { - chord_timer_set_to_tick = tick + step; - chord_timer->start(); - } - - return; - } - } - - Event e(Note); - e.setTick(tick - part->tick()); - e.setPitch(pitch); - e.setVelo(velo); - e.setLenTick(len); - // Indicate do undo, and do not do port controller values and clone parts. - //audio->msgAddEvent(e, part); - audio->msgAddEvent(e, part, true, false, false); - - if (! (globalKeyState & Qt::ShiftModifier)) { - chord_timer_set_to_tick = tick + step; - chord_timer->start(); - } - } - else { // equals if (pitch==rcSteprecNote) - bool held_notes=false; - if (note_held_down!=NULL) - { - for (int i=0;i<128;i++) - if (note_held_down[i]) { held_notes=true; break; } - } - else - held_notes=false; - - - if (held_notes) - { - chord_timer->stop(); - - // extend len of last note(s) - using std::set; - - set extend_set; - EventList* events = part->events(); - for (iEvent i = events->begin(); i != events->end(); ++i) { - Event& ev = i->second; - if (!ev.isNote()) - continue; + if (!shift) + { + chord_timer_set_to_tick = tick + step; + chord_timer->start(); + } + + return; + } + } + } + + + Event e(Note); + e.setTick(tick - part->tick()); + e.setPitch(pitch); + e.setVelo(velo); + e.setLenTick(len); + operations.push_back(UndoOp(UndoOp::AddEvent, e, part, false, false)); + lasttick=e.endTick(); + + if (! (globalKeyState & Qt::ShiftModifier)) + { + chord_timer_set_to_tick = tick + step; + chord_timer->start(); + } + + goto steprec_record_foot; // this is actually unneccessary, but for clarity + } + else // equals if (pitch==rcSteprecNote) + { + bool held_notes=false; + if (note_held_down!=NULL) + { + for (int i=0;i<128;i++) + if (note_held_down[i]) { held_notes=true; break; } + } + else + held_notes=false; + - if (note_held_down[ev.pitch()] && ((ev.tick() + ev.lenTick()) == tick)) - extend_set.insert(&ev); - } - for (set::iterator it=extend_set.begin(); it!=extend_set.end(); it++) - { - Event& ev=**it; - Event e = ev.clone(); - e.setLenTick(ev.lenTick() + len); - // Indicate do undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(ev, e, part, true, false, false); - } + if (held_notes) + { + chord_timer->stop(); + + // extend len of last note(s) + using std::set; + + set extend_set; + EventList* events = part->events(); + for (iEvent i = events->begin(); i != events->end(); ++i) + { + 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::iterator it=extend_set.begin(); it!=extend_set.end(); it++) + { + Event& ev=**it; + Event e = ev.clone(); + e.setLenTick(ev.lenTick() + len); + operations.push_back(UndoOp(UndoOp::ModifyEvent,e, ev, part, false, false)); + } - if (!shift) { - chord_timer_set_to_tick = tick + step; - chord_timer->start(); - } - return; - - } - else // equals if (!held_notes) - { - chord_timer->stop(); + if (!shift) + { + chord_timer_set_to_tick = tick + step; + chord_timer->start(); + } + + lasttick=tick+len - part->tick(); + goto steprec_record_foot; // this is actually unneccessary, but for clarity + } + else // equals if (!held_notes) + { + chord_timer->stop(); - //simply proceed, inserting a rest - Pos p(song->cpos() + step, true); - song->setPos(0, p, true, false, true); - } - } + // simply proceed, inserting a rest + Pos p(song->cpos() + step, true); + song->setPos(0, p, true, false, true); + + return; + } + } + + steprec_record_foot: + if (!((lasttick > part->lenTick()) && part->hasHiddenNotes())) // allowed? + { + if (lasttick > part->lenTick()) // we have to expand the part? + schedule_resize_all_same_len_clone_parts(part, lasttick, operations); + + song->applyOperationGroup(operations); + } } -- cgit v1.2.3 From 99934de53a85e71c8a33c1f39f16eb46d2df3cb7 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sat, 2 Jul 2011 15:38:16 +0000 Subject: fixed two bugs: - don't first resize parts and then deal with the old part pointer - the scoreedit now behaves as the canvases when dealing with hidden notes (begin tick must be inside the part, not end tick) --- muse2/muse/midiedit/dcanvas.cpp | 12 +++++++++--- muse2/muse/midiedit/prcanvas.cpp | 15 +++++++++++---- muse2/muse/midiedit/scoreedit.cpp | 7 ++++--- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index b9ff5a20..d0a5ee31 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -165,8 +165,6 @@ Undo DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp forbidden=true; break; } - - schedule_resize_all_same_len_clone_parts(opart, opart->lenTick() + diff, operations); } @@ -206,6 +204,14 @@ Undo DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp if(dtype == MOVE_COPY || dtype == MOVE_CLONE) selectItem(ci, false); } + + for(iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c) + { + Part* opart = ip2c->first; + int diff = ip2c->second.xdiff; + + schedule_resize_all_same_len_clone_parts(opart, opart->lenTick() + diff, operations); + } return operations; } @@ -354,7 +360,7 @@ void DrumCanvas::newItem(CItem* item, bool noSnap, bool replace) { schedule_resize_all_same_len_clone_parts(part, event.endTick(), operations); printf("newItem: extending\n"); - } + } } //else forbid action by not applying it song->applyOperationGroup(operations); diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index 73e70e84..5fb59099 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -321,8 +321,6 @@ Undo PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty forbidden=true; break; } - - schedule_resize_all_same_len_clone_parts(opart, opart->lenTick() + diff, operations); } @@ -362,6 +360,14 @@ Undo PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty if(dtype == MOVE_COPY || dtype == MOVE_CLONE) selectItem(ci, false); } + + for(iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c) + { + Part* opart = ip2c->first; + int diff = ip2c->second.xdiff; + + schedule_resize_all_same_len_clone_parts(opart, opart->lenTick() + diff, operations); + } return operations; } @@ -472,7 +478,7 @@ void PianoCanvas::newItem(CItem* item, bool noSnap) { schedule_resize_all_same_len_clone_parts(part, event.endTick(), operations); printf("newItem: extending\n"); - } + } song->applyOperationGroup(operations); } @@ -517,7 +523,8 @@ void PianoCanvas::resizeItem(CItem* item, bool noSnap, bool) // experime if (diff > 0)// part must be extended? { schedule_resize_all_same_len_clone_parts(part, event.tick()+len, operations); - printf("resizeItem: extending\n");} + printf("resizeItem: extending\n"); + } } //else forbid action by not performing it song->applyOperationGroup(operations); diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index d7131db9..0cb5428f 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -1682,7 +1682,8 @@ void staff_t::create_appropriate_eventlist() Event& event=it->second; if ( ( event.isNote() && !event.isNoteOff() && - (event.endTick() <= part->lenTick()) ) && + // (event.endTick() <= part->lenTick()) ) && + (event.tick() <= part->lenTick()) ) && // changed to accord to prcanvas.cpp and others (flo93) ( ((type==GRAND_TOP) && (event.pitch() >= SPLIT_NOTE)) || ((type==GRAND_BOTTOM) && (event.pitch() < SPLIT_NOTE)) || (type==NORMAL) ) ) @@ -3684,7 +3685,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) " setting it to " << newevent.lenTick() << endl; } - if (newevent.endTick() > curr_part->lenTick()) + if (newevent.endTick() > curr_part->lenTick()) //FINDMICH EXTEND { if (debugMsg) cout << "clipping inserted note from len="< dragged_event_part->lenTick()) + if (tmp.endTick() > dragged_event_part->lenTick()) //FINDMICH EXTEND { tmp.setLenTick(dragged_event_part->lenTick() - tmp.tick()); if (debugMsg) cout << "resized note would exceed its part; limiting length to " << tmp.lenTick() << endl; -- cgit v1.2.3 From 3970fed7542ca0377c7f418f86f93c513c9b0b63 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sun, 3 Jul 2011 15:53:46 +0000 Subject: auto-expanding for the score edit's resize tool and for the global "move notes" function --- muse2/muse/functions.cpp | 25 +++++++++++------ muse2/muse/midiedit/scoreedit.cpp | 56 ++++++++++++++++++++++----------------- muse2/muse/midiedit/scoreedit.h | 4 +++ 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index 9ab209c6..e34adb11 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -286,7 +286,7 @@ bool modify_off_velocity(const set& parts, int range, int rate, int offse return false; } -bool modify_notelen(const set& parts, int range, int rate, int offset) +bool modify_notelen(const set& parts, int range, int rate, int offset) //FINDMICH EXTEND { map events = get_events(parts, range); Undo operations; @@ -320,7 +320,7 @@ bool modify_notelen(const set& parts, int range, int rate, int offset) return false; } -bool set_notelen(const set& parts, int range, int len) +bool set_notelen(const set& parts, int range, int len) //FINDMICH EXTEND { return modify_notelen(parts, range, 0, len); } @@ -481,10 +481,11 @@ bool crescendo(const set& parts, int range, int start_val, int end_val, b return false; } -bool move_notes(const set& parts, int range, signed int ticks) //TODO: clipping +bool move_notes(const set& parts, int range, signed int ticks) { map events = get_events(parts, range); Undo operations; + map partlen; if ( (!events.empty()) && (ticks!=0) ) { @@ -500,12 +501,17 @@ bool move_notes(const set& parts, int range, signed int ticks) //TODO: cl else newEvent.setTick(event.tick()+ticks); - if (newEvent.endTick() > part->lenTick()) //if exceeding the part's end, clip + if (newEvent.endTick() > part->lenTick()) //if exceeding the part's end: { - if (part->lenTick() > newEvent.tick()) - newEvent.setLenTick(part->lenTick() - newEvent.tick()); + if (part->hasHiddenNotes()) // auto-expanding is forbidden, clip + { + if (part->lenTick() > newEvent.tick()) + newEvent.setLenTick(part->lenTick() - newEvent.tick()); + else + del=true; //if the new length would be <= 0, erase the note + } else - del=true; //if the new length would be <= 0, erase the note + partlen[part]=newEvent.endTick(); // schedule auto-expanding } if (del==false) @@ -514,6 +520,9 @@ bool move_notes(const set& parts, int range, signed int ticks) //TODO: cl operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, false, false)); } + for (map::iterator it=partlen.begin(); it!=partlen.end(); it++) + schedule_resize_all_same_len_clone_parts(it->first, it->second, operations); + return song->applyOperationGroup(operations); } else @@ -712,7 +721,7 @@ QMimeData* selected_events_to_mime(const set& parts, int range) return md; } -void paste_at(Part* dest_part, const QString& pt, int pos) +void paste_at(Part* dest_part, const QString& pt, int pos) //FINDMICH EXTEND { Undo operations; diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index 0cb5428f..f50af815 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -1189,6 +1189,7 @@ ScoreCanvas::ScoreCanvas(ScoreEdit* pr, QWidget* parent_widget) : View(parent_wi undo_started=false; selected_part=NULL; + dragged_event_part=NULL; last_len=384; new_len=-1; @@ -3624,7 +3625,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) clicked_event_ptr=set_it->source_event; dragged_event=*set_it->source_event; original_dragged_event=dragged_event.clone(); - dragged_event_part=set_it->source_part; + set_dragged_event_part(set_it->source_part); if ((mouse_erases_notes) || (event->button()==Qt::MidButton)) //erase? { @@ -3665,7 +3666,6 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) signed int relative_tick=(signed) tick - curr_part->tick(); if (relative_tick<0) cerr << "ERROR: THIS SHOULD NEVER HAPPEN: relative_tick is negative!" << endl; - song->startUndo(); if (!ctrl) deselect_all(); @@ -3685,13 +3685,13 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) " setting it to " << newevent.lenTick() << endl; } - if (newevent.endTick() > curr_part->lenTick()) //FINDMICH EXTEND + if (newevent.endTick() > curr_part->lenTick()) { if (debugMsg) cout << "clipping inserted note from len="<msgDeleteEvent(dragged_event, dragged_event_part, false, false, false); + if (undo_started) song->undo(); + audio->msgDeleteEvent(dragged_event, dragged_event_part, true, false, false); } else { last_len=flo_quantize(dragged_event.lenTick(), quant_ticks()); } - - if (undo_started) - song->endUndo(SC_EVENT_MODIFIED | SC_EVENT_REMOVED); } @@ -3864,6 +3861,7 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event) old_pitch=-1; old_dest_tick=MAXINT; + old_len=-1; } } @@ -3906,7 +3904,7 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event) if (dest_tick != old_dest_tick) { - if (undo_started) song->undo(); + if (undo_started) song->undo(); //FINDMICH EXTEND undo_started=move_notes(part_to_set(dragged_event_part),1, (signed)dest_tick-original_dragged_event.tick()); old_dest_tick=dest_tick; } @@ -3916,14 +3914,8 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event) case LENGTH: tick+=quant_ticks(); - if (dragged_event.tick()+dragged_event.lenTick() + dragged_event_part->tick() != unsigned(tick)) + if (dragged_event.tick()+old_len + dragged_event_part->tick() != unsigned(tick)) { - if (!undo_started) - { - song->startUndo(); - undo_started=true; - } - Event tmp=dragged_event.clone(); signed relative_tick=tick-signed(dragged_event_part->tick()); signed new_len=relative_tick-dragged_event.tick(); @@ -3936,16 +3928,29 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event) if (debugMsg) cout << "not setting len to a negative value. using 0 instead" << endl; } - if (tmp.endTick() > dragged_event_part->lenTick()) //FINDMICH EXTEND + unsigned newpartlen=dragged_event_part->lenTick(); + if (tmp.endTick() > dragged_event_part->lenTick()) { - tmp.setLenTick(dragged_event_part->lenTick() - tmp.tick()); - if (debugMsg) cout << "resized note would exceed its part; limiting length to " << tmp.lenTick() << endl; + if (dragged_event_part->hasHiddenNotes()) // do not allow autoexpand + { + tmp.setLenTick(dragged_event_part->lenTick() - tmp.tick()); + if (debugMsg) cout << "resized note would exceed its part; limiting length to " << tmp.lenTick() << endl; + } + else + { + newpartlen=tmp.endTick(); + if (debugMsg) cout << "resized note would exceeds its part; expanding the part..." << endl; + } } - audio->msgChangeEvent(dragged_event, tmp, dragged_event_part, false, false, false); - dragged_event=tmp; + if (undo_started) song->undo(); + Undo operations; + operations.push_back(UndoOp(UndoOp::ModifyEvent, tmp, dragged_event, dragged_event_part, false, false)); + if (newpartlen != dragged_event_part->lenTick()) + schedule_resize_all_same_len_clone_parts(dragged_event_part, newpartlen, operations); + undo_started=song->applyOperationGroup(operations); - fully_recalculate(); + old_len=new_len; } break; @@ -4414,6 +4419,9 @@ void ScoreCanvas::update_parts() if (selected_part!=NULL) //if it's null, let it be null selected_part=partFromSerialNumber(selected_part_index); + if (dragged_event_part!=NULL) //same thing here + dragged_event_part=partFromSerialNumber(dragged_event_part_index); + for (list::iterator it=staves.begin(); it!=staves.end(); it++) it->update_parts(); } @@ -4457,7 +4465,7 @@ void staff_t::update_part_indices() * between, for example, when a cis is tied to a des * * CURRENT TODO - * o do autoexpand in scoreedit.cpp + * o do autoexpand in scoreedit.cpp and functions.cpp * o draw the edge of parts hiding notes "jagged" (hasHiddenNotes() is interesting for this) * * IMPORTANT TODO diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h index e7302a46..6a5dd63a 100644 --- a/muse2/muse/midiedit/scoreedit.h +++ b/muse2/muse/midiedit/scoreedit.h @@ -701,12 +701,14 @@ class ScoreCanvas : public View bool dragging; bool drag_cursor_changed; Part* dragged_event_part; + int dragged_event_part_index; Event dragged_event; Event original_dragged_event; Event* clicked_event_ptr; int old_pitch; unsigned old_dest_tick; + int old_len; bool have_lasso; QPoint lasso_start; @@ -811,6 +813,8 @@ class ScoreCanvas : public View Part* get_selected_part() {return selected_part;} void set_selected_part(Part* p) {selected_part=p; if (selected_part) selected_part_index=selected_part->sn();} + Part* get_dragged_event_part() {return dragged_event_part;} + void set_dragged_event_part(Part* p) {dragged_event_part=p; if (dragged_event_part) dragged_event_part_index=dragged_event_part->sn();} set get_all_parts(); -- cgit v1.2.3 From e1fbd43836e433c2f19bb5240e19338135b3b2be Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sun, 3 Jul 2011 16:19:36 +0000 Subject: added autoexpand to functions.cpp --- muse2/muse/functions.cpp | 43 ++++++++++++++++++++++++++++----------- muse2/muse/midiedit/scoreedit.cpp | 7 ++++++- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index e34adb11..66257401 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -286,10 +286,11 @@ bool modify_off_velocity(const set& parts, int range, int rate, int offse return false; } -bool modify_notelen(const set& parts, int range, int rate, int offset) //FINDMICH EXTEND +bool modify_notelen(const set& parts, int range, int rate, int offset) { map events = get_events(parts, range); Undo operations; + map partlen; if ( (!events.empty()) && ((rate!=100) || (offset!=0)) ) { @@ -305,6 +306,9 @@ bool modify_notelen(const set& parts, int range, int rate, int offset) // if (len <= 0) len = 1; + + if ((event.tick()+len > part->lenTick()) && (!part->hasHiddenNotes())) + partlen[part]=event.tick()+len; // schedule auto-expanding if (event.lenTick() != len) { @@ -314,13 +318,16 @@ bool modify_notelen(const set& parts, int range, int rate, int offset) // } } + for (map::iterator it=partlen.begin(); it!=partlen.end(); it++) + schedule_resize_all_same_len_clone_parts(it->first, it->second, operations); + return song->applyOperationGroup(operations); } else return false; } -bool set_notelen(const set& parts, int range, int len) //FINDMICH EXTEND +bool set_notelen(const set& parts, int range, int len) { return modify_notelen(parts, range, 0, len); } @@ -721,9 +728,10 @@ QMimeData* selected_events_to_mime(const set& parts, int range) return md; } -void paste_at(Part* dest_part, const QString& pt, int pos) //FINDMICH EXTEND +void paste_at(Part* dest_part, const QString& pt, int pos) { Undo operations; + unsigned newpartlen=dest_part->lenTick(); Xml xml(pt.toLatin1().constData()); for (;;) @@ -753,18 +761,29 @@ void paste_at(Part* dest_part, const QString& pt, int pos) //FINDMICH EXTEND e.setTick(tick); e.setSelected(true); - int diff = e.endTick()-dest_part->lenTick(); - if (diff > 0) // too short part? extend it + + if (e.endTick() > dest_part->lenTick()) // event exceeds part? { - Part* newPart = dest_part->clone(); - newPart->setLenTick(newPart->lenTick()+diff); - // Indicate no undo, and do port controller values but not clone parts. - operations.push_back(UndoOp(UndoOp::ModifyPart,dest_part, newPart, true, false)); - dest_part = newPart; // reassign TODO FINDME does this work, or has dest_part to be a nonconst reference? + if (dest_part->hasHiddenNotes()) // auto-expanding is forbidden? + { + if (e.tick() < dest_part->lenTick()) + e.setLenTick(dest_part->lenTick() - e.tick()); // clip + else + e.setLenTick(0); // don't insert that note at all + } + else + { + if (e.endTick() > newpartlen) + newpartlen=e.endTick(); + } } - // Indicate no undo, and do not do port controller values and clone parts. - operations.push_back(UndoOp(UndoOp::AddEvent,e, dest_part, false, false)); + + if (e.lenTick() != 0) operations.push_back(UndoOp(UndoOp::AddEvent,e, dest_part, false, false)); } + + if (newpartlen != dest_part->lenTick()) + schedule_resize_all_same_len_clone_parts(dest_part, newpartlen, operations); + song->applyOperationGroup(operations); goto end_of_paste_at; } diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index f50af815..201c7119 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -4463,10 +4463,15 @@ void staff_t::update_part_indices() /* BUGS and potential bugs * o tied notes don't work properly when there's a key-change in * between, for example, when a cis is tied to a des + * o schedule_all_same_len_parts: if there are two clones A and B, + * and both A and B get scheduled to be expanded (because we + * have one event from A and one event from B), this causes a bug, + * because after A (and B) got resized, the B-resize is invalid! * * CURRENT TODO - * o do autoexpand in scoreedit.cpp and functions.cpp * o draw the edge of parts hiding notes "jagged" (hasHiddenNotes() is interesting for this) + * o in Song::applyOperationGroup(): check for double entries (for example, + * resizing the same part twice) * * IMPORTANT TODO * o shrink a part from its beginning as well! watch out for clones! -- cgit v1.2.3 From a0162f23ad2bbb050dcfdf38c80c34f417446159 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sun, 3 Jul 2011 16:48:36 +0000 Subject: added cleanOperationGroup() function which at least avoids crashes when processing the same part or track twice in one operation group this however does probably NOT cause intended behaviour. this simply executes the first action with the given pointer and discards the others. --- muse2/muse/undo.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/muse2/muse/undo.cpp b/muse2/muse/undo.cpp index 0c05ef08..d13b38d7 100644 --- a/muse2/muse/undo.cpp +++ b/muse2/muse/undo.cpp @@ -15,6 +15,7 @@ #include "globals.h" #include +#include // iundo points to last Undo() in Undo-list @@ -207,10 +208,43 @@ void Song::endUndo(int flags) } +void cleanOperationGroup(Undo& group) +{ + using std::set; + + set processed_tracks; + set processed_parts; + + for (iUndoOp op=group.begin(); op!=group.end();) + { + iUndoOp op_=op; + op_++; + + if ((op->type==UndoOp::ModifyTrack) || (op->type==UndoOp::DeleteTrack)) + { + if (processed_tracks.find(op->oTrack)!=processed_tracks.end()) + group.erase(op); + else + processed_tracks.insert(op->oTrack); + } + else if ((op->type==UndoOp::ModifyPart) || (op->type==UndoOp::DeletePart)) + { + if (processed_parts.find(op->oPart)!=processed_parts.end()) + group.erase(op); + else + processed_parts.insert(op->oPart); + } + + op=op_; + } +} + + 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(); -- cgit v1.2.3