From 18cef43657bc6841e4dab526fce83a6ad6a34374 Mon Sep 17 00:00:00 2001 From: Robert Jonsson Date: Wed, 26 Jan 2011 12:29:04 +0000 Subject: some automation changes --- muse2/ChangeLog | 3 + muse2/muse/arranger/pcanvas.cpp | 239 ++++++++++++++++++++++++--------------- muse2/muse/arranger/pcanvas.h | 11 +- muse2/muse/audiotrack.cpp | 2 +- muse2/muse/midiedit/dcanvas.cpp | 7 ++ muse2/muse/midiedit/dcanvas.h | 1 + muse2/muse/midiedit/prcanvas.cpp | 5 + muse2/muse/midiedit/prcanvas.h | 1 + muse2/muse/widgets/canvas.cpp | 8 +- muse2/muse/widgets/canvas.h | 2 + 10 files changed, 182 insertions(+), 97 deletions(-) diff --git a/muse2/ChangeLog b/muse2/ChangeLog index 4d6d7bee..eeb6024e 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,3 +1,6 @@ +26.01.2011: + - moved automation lines ontop of parts (rj) + - fixes to automation editing, still many bugs though (rj) 21.01.2011: - Added: graphical editing of automation, also now stores which parameters are visible (rj) Edit with new automation tool in arranger, to create new points hold down ctrl. diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp index 95ceebd5..9c970c52 100644 --- a/muse2/muse/arranger/pcanvas.cpp +++ b/muse2/muse/arranger/pcanvas.cpp @@ -142,7 +142,8 @@ PartCanvas::PartCanvas(int* r, QWidget* parent, int sx, int sy) drag = DRAG_OFF; curColorIndex = 0; automation.currentCtrl = 0; - moveController = 0; + automation.controllerState = doNothing; + automation.moveController = false; partsChanged(); } @@ -1025,9 +1026,9 @@ void PartCanvas::mousePress(QMouseEvent* event) break; } case AutomationTool: - if (automation.currentCtrl || (automation.currentCtrlList && event->modifiers() & Qt::ControlModifier)) - moveController=true; - break; + if (automation.controllerState != doNothing) + automation.moveController=true; + break; } } @@ -1037,7 +1038,9 @@ void PartCanvas::mousePress(QMouseEvent* event) void PartCanvas::mouseRelease(const QPoint&) { - moveController=false; + // clear all the automation parameters + automation.moveController=false; + automation.controllerState = doNothing; automation.currentCtrl=0; automation.currentTrack=0; automation.currentCtrlList=0; @@ -2868,9 +2871,39 @@ void PartCanvas::drawCanvas(QPainter& p, const QRect& rect) } //--------------------------------------------------------- -// drawAudioTrack +// drawLast //--------------------------------------------------------- +void PartCanvas::drawTopItem(QPainter& p, const QRect& rect) +{ + int x = rect.x(); + int y = rect.y(); + int w = rect.width(); + int h = rect.height(); + + QColor baseColor(config.partCanvasBg.light(104)); + p.setPen(baseColor); + + TrackList* tl = song->tracks(); + int yy = 0; + int th; + for (iTrack it = tl->begin(); it != tl->end(); ++it) { + if (yy > y + h) + break; + Track* track = *it; + th = track->height(); + if (!track->isMidiTrack()) { // draw automation + QRect r = rect & QRect(x, yy, w, track->height()); + drawAutomation(p, r, (AudioTrack*)track); + p.setPen(baseColor); + + } + yy += track->height(); + } +} +//--------------------------------------------------------- +// drawAudioTrack +//--------------------------------------------------------- void PartCanvas::drawAudioTrack(QPainter& p, const QRect& r, AudioTrack* /* t */) { // NOTE: For one-pixel border use first line and don't bother with setCosmetic. @@ -2927,7 +2960,8 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t) // prepare prevVal if (cl->id() == AC_VOLUME ) { // use db scale for volume - prevVal = (20.0*log10(cvFirst.val)+60) / 70.0; // represent volume between 0 and 1 + printf("volume cvval=%f\n", cvFirst.val); + prevVal = dbToVal(cvFirst.val); // represent volume between 0 and 1 if (prevVal < 0) prevVal = 0.0; } else { @@ -2945,7 +2979,7 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t) CtrlVal cv = ic->second; double nextVal = cv.val; // was curVal if (cl->id() == AC_VOLUME ) { // use db scale for volume - nextVal = (20.0*log10(cv.val)+60) / 70.0; // represent volume between 0 and 1 + nextVal = dbToVal(cv.val); // represent volume between 0 and 1 if (nextVal < 0) nextVal = 0.0; } else { @@ -2985,9 +3019,21 @@ quitDrawing: p.restore(); } + +//--------------------------------------------------------- +// checkAutomation +// compares the current mouse pointer with the automation +// lines on the track under it. +// if there is a controller to be moved it is marked +// in the automation object +// if addNewCtrl is set and a valid line is found the +// automation object will also be set but no +// controller added. +//--------------------------------------------------------- + void PartCanvas::checkAutomation(Track * t, const QPoint &pointer, bool addNewCtrl) { - int circumference = 4; + int circumference = 5; if (t->isMidiTrack()) return; //printf("checkAutomation p.x()=%d p.y()=%d\n", mapx(pointer.x()), mapx(pointer.y())); @@ -3009,6 +3055,7 @@ void PartCanvas::checkAutomation(Track * t, const QPoint &pointer, bool addNewCt int oldY=-1; int ypixel; int xpixel; + // First check that there ARE automation, ic == cl->end means no automation if (ic != cl->end()) { for (; ic !=cl->end(); ic++) @@ -3016,7 +3063,7 @@ void PartCanvas::checkAutomation(Track * t, const QPoint &pointer, bool addNewCt CtrlVal &cv = ic->second; double y; if (cl->id() == AC_VOLUME ) { // use db scale for volume - y = (20.0*log10(cv.val)+60) / 70.0; // represent volume between 0 and 1 + y = dbToVal(cv.val); // represent volume between 0 and 1 if (y < 0) y = 0; } else { @@ -3062,10 +3109,13 @@ void PartCanvas::checkAutomation(Track * t, const QPoint &pointer, bool addNewCt if (foundIt) { QWidget::setCursor(Qt::CrossCursor); - if (addNewCtrl) - automation.currentCtrl = 0; // the logic relies on this to be zero if a new controller is to be added - else + if (addNewCtrl) { + automation.currentCtrl = 0; + automation.controllerState = addNewController; + }else { automation.currentCtrl=&cv; + automation.controllerState = movingController; + } automation.currentCtrlList = cl; automation.currentTrack = t; return; @@ -3074,30 +3124,28 @@ void PartCanvas::checkAutomation(Track * t, const QPoint &pointer, bool addNewCt } // if if (addNewCtrl) { - // check if we are reasonably close to a line, we only need to check Y as this is the line is straight after the last controller - //printf("LAST ypixel=%d oldY=%d currY=%d\n", ypixel, oldY, currY); + // check if we are reasonably close to a line, we only need to check Y + // as the line is straight after the last controller bool foundIt=false; if ( ypixel == oldY && abs(currY-ypixel) < circumference) { - //printf("found it!\n"); foundIt=true; } if (foundIt) { QWidget::setCursor(Qt::CrossCursor); + automation.controllerState = addNewController; automation.currentCtrlList = cl; automation.currentTrack = t; automation.currentCtrl = 0; return; } - - } - } + // if there are no hits we default to clearing all the data + automation.controllerState = doNothing; automation.currentCtrl = 0; automation.currentCtrlList = 0; automation.currentTrack = 0; - // setCursor(); } @@ -3110,88 +3158,95 @@ void PartCanvas::processAutomationMovements(QMouseEvent *event) { if (_tool == AutomationTool) { - bool addNewPoints=false; - if (event->modifiers() & Qt::ControlModifier) { - addNewPoints=true; - } - if (moveController) { - //printf("update automation for controller=%d\n", automation.currentCtrl); - // update currentController to this position - - int prevFrame = 0; - int nextFrame = -1; - if (addNewPoints && automation.currentCtrl == 0) // we don't have a controller, create one! - { - //printf("adding a new ctrler!\n"); - int frame = tempomap.tick2frame(event->pos().x()); - automation.currentCtrlList->add( frame, 1.0 /*dummy value */); + if (!automation.moveController) { // currently nothing going lets's check for some action. + Track * t = y2Track(event->pos().y()); + if (t) { + bool addNewPoints=false; + if (event->modifiers() & Qt::ControlModifier) + addNewPoints=true; + checkAutomation(t, event->pos(), addNewPoints); + } + return; + } - iCtrl ic=automation.currentCtrlList->begin(); - for (; ic !=automation.currentCtrlList->end(); ic++) { - CtrlVal &cv = ic->second; - if (cv.frame == frame) { - automation.currentCtrl = &cv; - break; - } - } + // automation.moveController is set, lets rock. - } + int prevFrame = 0; + int nextFrame = -1; - // get previous and next frame position to give x bounds for this event. - iCtrl ic=automation.currentCtrlList->begin(); - for (; ic !=automation.currentCtrlList->end(); ic++) - { - CtrlVal &cv = ic->second; - if (&cv == automation.currentCtrl) - break; - prevFrame = cv.frame; - } - if ( ++ic != automation.currentCtrlList->end()) { - CtrlVal &cv = ic->second; - nextFrame = cv.frame; - } - int currFrame = tempomap.tick2frame(event->pos().x()); - if (currFrame < prevFrame) currFrame=prevFrame+1; - if (nextFrame!=-1 && currFrame > nextFrame) currFrame=nextFrame-1; - automation.currentCtrl->frame = currFrame; + if (automation.controllerState == addNewController) + { + //printf("adding a new ctrler!\n"); + int frame = tempomap.tick2frame(event->pos().x()); + automation.currentCtrlList->add( frame, 1.0 /*dummy value */); + + iCtrl ic=automation.currentCtrlList->begin(); + for (; ic !=automation.currentCtrlList->end(); ic++) { + CtrlVal &cv = ic->second; + if (cv.frame == frame) { + automation.currentCtrl = &cv; + automation.controllerState = movingController; + break; + } + } + } - int mouseY = automation.currentTrack->height() - (mapy(event->pos().y()) - automation.currentTrack->y())-2; - double yfraction = ((double)mouseY)/automation.currentTrack->height(); + // get previous and next frame position to give x bounds for this event. + iCtrl ic=automation.currentCtrlList->begin(); + for (; ic !=automation.currentCtrlList->end(); ic++) + { + CtrlVal &cv = ic->second; + if (&cv == automation.currentCtrl) + break; + prevFrame = cv.frame; + } + if ( ++ic != automation.currentCtrlList->end()) { + CtrlVal &cv = ic->second; + nextFrame = cv.frame; + } + int currFrame = tempomap.tick2frame(event->pos().x()); + if (currFrame < prevFrame) currFrame=prevFrame+1; + if (nextFrame!=-1 && currFrame > nextFrame) currFrame=nextFrame-1; + automation.currentCtrl->frame = currFrame; - if (automation.currentCtrlList->id() == AC_VOLUME ) { // use db scale for volume - //y = (20.0*log10(cv.val)+60) / 70.0; // represent volume between 0 and 1 + int mouseY = automation.currentTrack->height() - (mapy(event->pos().y()) - automation.currentTrack->y())-2; + double yfraction = ((double)mouseY)/automation.currentTrack->height(); - double cvval = exp10((yfraction*70.0-60)/20.0); - //printf("calc yfraction = %f v=%f ",yfraction,cvval); - double min, max; - automation.currentCtrlList->range(&min,&max); - if (cvval< min) cvval=min; - if (cvval>max) cvval=max; - automation.currentCtrl->val=cvval; + if (automation.currentCtrlList->id() == AC_VOLUME ) { // use db scale for volume - } - else { - // we need to set curVal between 0 and 1 - double min, max; - automation.currentCtrlList->range(&min,&max); - double cvval = yfraction * (max-min) + min; - - if (cvval< min) cvval=min; - if (cvval>max) cvval=max; - automation.currentCtrl->val = cvval; - //printf("calc cvval=%f yfraction=%f ", cvval, yfraction); - } - //printf("mouseY=%d\n", mouseY); - controllerChanged(automation.currentTrack); + double cvval = valToDb(yfraction); + //printf("calc yfraction = %f v=%f ",yfraction,cvval); + double min, max; + automation.currentCtrlList->range(&min,&max); + if (cvval< min) cvval=min; + if (cvval>max) cvval=max; + automation.currentCtrl->val=cvval; - } else { + } + else { + // we need to set curVal between 0 and 1 + double min, max; + automation.currentCtrlList->range(&min,&max); + double cvval = yfraction * (max-min) + min; + + if (cvval< min) cvval=min; + if (cvval>max) cvval=max; + automation.currentCtrl->val = cvval; + //printf("calc cvval=%f yfraction=%f ", cvval, yfraction); + } + //printf("mouseY=%d\n", mouseY); + controllerChanged(automation.currentTrack); - Track * t = y2Track(event->pos().y()); - if (t) { - checkAutomation(t, event->pos(), addNewPoints); - } - } } } + +double PartCanvas::dbToVal(double inDb) +{ + return (20.0*log10(inDb)+60) / 70.0; +} +double PartCanvas::valToDb(double inV) +{ + return exp10((inV*70.0-60)/20.0); +} diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h index 6afe1dca..6a324770 100644 --- a/muse2/muse/arranger/pcanvas.h +++ b/muse2/muse/arranger/pcanvas.h @@ -37,10 +37,13 @@ class NPart : public CItem { Track* track() const { return part()->track(); } }; +enum ControllerVals { doNothing, movingController, addNewController }; struct AutomationObject { CtrlVal *currentCtrl; CtrlList *currentCtrlList; Track *currentTrack; + bool moveController; + ControllerVals controllerState; }; class QLineEdit; @@ -64,9 +67,8 @@ class PartCanvas : public Canvas { bool editMode; AutomationObject automation; - bool moveController; - std::vector automationViews; + //std::vector automationViews; Q_OBJECT virtual void keyPress(QKeyEvent*); virtual void mousePress(QMouseEvent*); @@ -113,8 +115,13 @@ class PartCanvas : public Canvas { Track* y2Track(int) const; void drawAudioTrack(QPainter& p, const QRect& r, AudioTrack* track); void drawAutomation(QPainter& p, const QRect& r, AudioTrack* track); + void drawTopItem(QPainter& p, const QRect& rect); + void checkAutomation(Track * t, const QPoint& pointer, bool addNewCtrl); void processAutomationMovements(QMouseEvent *event); + double dbToVal(double inDb); + double valToDb(double inV); + protected: diff --git a/muse2/muse/audiotrack.cpp b/muse2/muse/audiotrack.cpp index 4be1a1a9..af066437 100644 --- a/muse2/muse/audiotrack.cpp +++ b/muse2/muse/audiotrack.cpp @@ -79,7 +79,7 @@ AudioTrack::AudioTrack(TrackType t) _automationType = AUTO_OFF; //setChannels(1); setChannels(2); - addController(new CtrlList(AC_VOLUME,"Volume",0.0,1.0)); + addController(new CtrlList(AC_VOLUME,"Volume",0.0,3.16 /* roughly 10 db */)); addController(new CtrlList(AC_PAN, "Pan", -1.0, 1.0)); addController(new CtrlList(AC_MUTE,"Mute",0.0,1.0, true /*dont show in arranger */)); diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index 34622296..fa89b8ad 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -587,6 +587,13 @@ void DrumCanvas::drawCanvas(QPainter& p, const QRect& rect) drawTickRaster(p, x, y, w, h, editor->raster()); } +//--------------------------------------------------------- +// drawTopItem +//--------------------------------------------------------- +void DrumCanvas::drawTopItem(QPainter &, const QRect &) +{ + +} //--------------------------------------------------------- // y2pitch //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h index 0b81df68..a5510b3c 100644 --- a/muse2/muse/midiedit/dcanvas.h +++ b/muse2/muse/midiedit/dcanvas.h @@ -44,6 +44,7 @@ class DrumCanvas : public EventCanvas { Q_OBJECT virtual void drawCanvas(QPainter&, const QRect&); virtual void drawItem(QPainter&, const CItem*, const QRect&); + void drawTopItem(QPainter& p, const QRect& rect); virtual void drawMoving(QPainter&, const CItem*, const QRect&); virtual void moveCanvasItems(CItemList&, int, int, DragType, int*); // Changed by T356. diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index 84e19e86..4b280a16 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -209,6 +209,11 @@ void PianoCanvas::drawItem(QPainter& p, const CItem* item, p.drawRect(r); } +//--------------------------------------------------------- +// drawTopItem +//--------------------------------------------------------- +void PianoCanvas::drawTopItem(QPainter& , const QRect&) +{} //--------------------------------------------------------- // drawMoving diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h index 81acf426..bda22fc3 100644 --- a/muse2/muse/midiedit/prcanvas.h +++ b/muse2/muse/midiedit/prcanvas.h @@ -44,6 +44,7 @@ class PianoCanvas : public EventCanvas { Q_OBJECT virtual void viewMouseDoubleClickEvent(QMouseEvent*); virtual void drawItem(QPainter&, const CItem*, const QRect&); + void drawTopItem(QPainter &p, const QRect &rect); virtual void drawMoving(QPainter&, const CItem*, const QRect&); virtual void moveCanvasItems(CItemList&, int, int, DragType, int*); // Changed by T356. diff --git a/muse2/muse/widgets/canvas.cpp b/muse2/muse/widgets/canvas.cpp index 5b6dc453..ff9d0c3b 100644 --- a/muse2/muse/widgets/canvas.cpp +++ b/muse2/muse/widgets/canvas.cpp @@ -189,9 +189,12 @@ void Canvas::draw(QPainter& p, const QRect& rect) to = moving.lower_bound(x2); for (iCItem i = moving.begin(); i != to; ++i) { - drawItem(p, i->second, rect); - } + drawItem(p, i->second, rect); } + + drawTopItem(p,rect); + + } else { p.save(); setPainter(p); @@ -266,6 +269,7 @@ void Canvas::draw(QPainter& p, const QRect& rect) { drawItem(p, i->second, rect); } + drawTopItem(p, QRect(x,y,w,h)); p.save(); setPainter(p); } diff --git a/muse2/muse/widgets/canvas.h b/muse2/muse/widgets/canvas.h index 2f9a3907..97392f1e 100644 --- a/muse2/muse/widgets/canvas.h +++ b/muse2/muse/widgets/canvas.h @@ -91,6 +91,8 @@ class Canvas : public View { virtual void mouseMove(QMouseEvent* event) = 0; virtual void mouseRelease(const QPoint&) {} virtual void drawCanvas(QPainter&, const QRect&) = 0; + virtual void drawTopItem(QPainter& p, const QRect& rect) = 0; + virtual void drawItem(QPainter&, const CItem*, const QRect&) = 0; virtual void drawMoving(QPainter&, const CItem*, const QRect&) = 0; virtual void updateSelection() = 0; -- cgit v1.2.3