diff options
author | Florian Jung <flo@windfisch.org> | 2012-07-01 16:42:16 +0000 |
---|---|---|
committer | Florian Jung <flo@windfisch.org> | 2012-07-01 16:42:16 +0000 |
commit | 9c4664d162c537ba4dd4fd8220971c0fb727103a (patch) | |
tree | 37a28b7cd4e4d8984ad4934a4884cd7b4da0505c /muse2/muse/arranger | |
parent | e87fedf1be804f7ec774071d844b1f163be30b96 (diff) |
final merge
Diffstat (limited to 'muse2/muse/arranger')
-rw-r--r-- | muse2/muse/arranger/arranger.cpp | 8 | ||||
-rw-r--r-- | muse2/muse/arranger/arranger.h | 2 | ||||
-rw-r--r-- | muse2/muse/arranger/pcanvas.cpp | 88 | ||||
-rw-r--r-- | muse2/muse/arranger/pcanvas.h | 2 | ||||
-rw-r--r-- | muse2/muse/arranger/tlist.cpp | 186 |
5 files changed, 234 insertions, 52 deletions
diff --git a/muse2/muse/arranger/arranger.cpp b/muse2/muse/arranger/arranger.cpp index 29e69582..8d786311 100644 --- a/muse2/muse/arranger/arranger.cpp +++ b/muse2/muse/arranger/arranger.cpp @@ -531,7 +531,7 @@ Arranger::Arranger(ArrangerView* parent, const char* name) connect(canvas, SIGNAL(dropMidiFile(const QString&)), SIGNAL(dropMidiFile(const QString&))); connect(canvas, SIGNAL(toolChanged(int)), SIGNAL(toolChanged(int))); - connect(MusEGlobal::song, SIGNAL(controllerChanged(MusECore::Track*)), SLOT(controllerChanged(MusECore::Track*))); + connect(MusEGlobal::song, SIGNAL(controllerChanged(MusECore::Track*, int)), SLOT(controllerChanged(MusECore::Track*, int))); configChanged(); // set configuration values if(canvas->part()) @@ -677,7 +677,7 @@ void Arranger::songChanged(int type) // Keep this light, partsChanged is a heavy move! TEST p4.0.36 Try these, may need more. if(type & (SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED | SC_PART_INSERTED | SC_PART_REMOVED | SC_PART_MODIFIED | - SC_SIG | SC_TEMPO)) // Maybe sig. Requires tempo. + SC_SIG | SC_TEMPO | SC_MASTER)) // Maybe sig. Requires tempo. canvas->partsChanged(); if (type & SC_SIG) @@ -1110,9 +1110,9 @@ void Arranger::clear() // emit redirectWheelEvent(ev); // } -void Arranger::controllerChanged(MusECore::Track *t) +void Arranger::controllerChanged(MusECore::Track *t, int ctrlId) { - canvas->controllerChanged(t); + canvas->controllerChanged(t, ctrlId); } //--------------------------------------------------------- diff --git a/muse2/muse/arranger/arranger.h b/muse2/muse/arranger/arranger.h index e51ec068..60390a8f 100644 --- a/muse2/muse/arranger/arranger.h +++ b/muse2/muse/arranger/arranger.h @@ -186,7 +186,7 @@ class Arranger : public QWidget { void setTool(int); void updateTrackInfo(int flags); void configChanged(); - void controllerChanged(MusECore::Track *t); + void controllerChanged(MusECore::Track *t, int ctrlId); void focusCanvas(); public: diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp index cc23b59b..c5c3ca6d 100644 --- a/muse2/muse/arranger/pcanvas.cpp +++ b/muse2/muse/arranger/pcanvas.cpp @@ -904,12 +904,25 @@ bool PartCanvas::mousePress(QMouseEvent* event) } } case AutomationTool: - if (event->button() & Qt::RightButton) { - QMenu *automationMenu = new QMenu(this); - QAction* act; - act = automationMenu->addAction(tr("Remove selected")); - act = automationMenu->exec(event->globalPos()); - if (act && automation.currentTrack) { + if (event->button() & Qt::RightButton || + event->button() & Qt::MidButton) { + + bool do_delete; + + if (event->button() & Qt::MidButton) // mid-click + do_delete=true; + else // right-click + { + QMenu *automationMenu = new QMenu(this); + QAction* act; + act = automationMenu->addAction(tr("Remove selected")); + act = automationMenu->exec(event->globalPos()); + if (act) + do_delete=true; + else + do_delete=false; + } + if (do_delete && automation.currentTrack) { foreach(int frame, automation.currentCtrlFrameList) MusEGlobal::audio->msgEraseACEvent((MusECore::AudioTrack*)automation.currentTrack, automation.currentCtrlList->id(), frame); @@ -2683,6 +2696,7 @@ void PartCanvas::cmd(int cmd) case 0: paste_mode=PASTEMODE_MIX; break; case 1: paste_mode=PASTEMODE_MOVEALL; break; case 2: paste_mode=PASTEMODE_MOVESOME; break; + default: paste_mode=PASTEMODE_MIX; // shall never be executed } paste(paste_dialog->clone, paste_mode, paste_dialog->all_in_one_track, @@ -3411,7 +3425,7 @@ void PartCanvas::drawTopItem(QPainter& p, const QRect& rect) yy += th; } - unsigned int startPos = MusEGlobal::audio->getStartRecordPos().tick(); + unsigned int startPos = MusEGlobal::extSyncFlag.value() ? MusEGlobal::audio->getStartExternalRecTick() : MusEGlobal::audio->getStartRecordPos().tick(); if (MusEGlobal::song->punchin()) startPos=MusEGlobal::song->lpos(); int startx = mapx(startPos); @@ -3663,19 +3677,36 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& rr, MusECore::AudioTra bool checkIfOnLine(double mouseX, double mouseY, double firstX, double lastX, double firstY, double lastY, int circumference) { - double proportion = (mouseX-firstX)/(lastX-firstX); - - // 10 X(15) 20 - // proportion = 0.5 - // 10 - // / - // Y(5) - // / - // 1 - double calcY = (lastY-firstY)*proportion+firstY; - if(ABS(calcY-mouseY) < circumference || (lastX == firstX && ABS(mouseX-lastX) < circumference)) - return true; - return false; + if (lastX==firstX) + return (ABS(mouseX-lastX) < circumference); + else if (mouseX < firstX || mouseX > lastX+circumference) // (*) + return false; + else + { + double proportion = (mouseX-firstX)/(lastX-firstX); // a value between 0 and 1, where firstX->0 and lastX->1 + double calcY = (lastY-firstY)*proportion+firstY; // where the drawn line's y-coord is at mouseX + double slope = (lastY-firstY)/(lastX-firstX); + + return (ABS(calcY-mouseY) < (circumference * sqrt(1+slope*slope))); + // this is equivalent to circumference / cos( atan(slope) ). to + // verify, draw a sloped line (the graph), a 90°-line to it with + // length "circumference". from the (unconnected) endpoint of that + // line, draw a vertical line down to the sloped line. + // use slope=tan(alpha) <==> alpha=atan(slope) and + // cos(alpha) = adjacent side / hypothenuse (hypothenuse is what we + // want, and adjacent = circumference). + // to optimize: this looks similar to abs(slope)+1 + + //return (ABS(calcY-mouseY) < circumference); + } + + /* without the +circumference in the above if statement (*), moving + * the mouse towards a control point from the right would result in + * the line segment from the targeted point to the next to be con- + * sidered, but not the segment from the previous to the targeted. + * however, only points for which the line segment they _end_ is + * under the cursor are considered, so we need to enlengthen this + * a bit (flo93)*/ } //--------------------------------------------------------- @@ -3684,12 +3715,7 @@ bool checkIfOnLine(double mouseX, double mouseY, double firstX, double lastX, do bool checkIfNearPoint(int mouseX, int mouseY, int eventX, int eventY, int circumference) { - int x1 = ABS(mouseX - eventX) ; - int y1 = ABS(mouseY - eventY); - if (x1 < circumference && y1 < circumference) { - return true; - } - return false; + return (ABS(mouseX - eventX) < circumference && ABS(mouseY - eventY) < circumference); } //--------------------------------------------------------- @@ -3703,7 +3729,7 @@ bool checkIfNearPoint(int mouseX, int mouseY, int eventX, int eventY, int circum // controller added. //--------------------------------------------------------- -void PartCanvas::checkAutomation(MusECore::Track * t, const QPoint &pointer, bool NOTaddNewCtrl) +void PartCanvas::checkAutomation(MusECore::Track * t, const QPoint &pointer, bool /*NOTaddNewCtrl*/) { if (t->isMidiTrack()) return; @@ -3751,7 +3777,7 @@ void PartCanvas::checkAutomation(MusECore::Track * t, const QPoint &pointer, boo } else // we have automation, loop through it { - for (; ic !=cl->end(); ic++) + for (; ic!=cl->end(); ic++) { double y = ic->second.val; if (cl->valueType() == MusECore::VAL_LOG ) { // use db scale for volume @@ -3774,7 +3800,7 @@ void PartCanvas::checkAutomation(MusECore::Track * t, const QPoint &pointer, boo eventOldX = eventX; eventOldY = eventY; - + if (onLine) { if (!onPoint) { QWidget::setCursor(Qt::CrossCursor); @@ -3799,7 +3825,7 @@ void PartCanvas::checkAutomation(MusECore::Track * t, const QPoint &pointer, boo // check if we are reasonably close to a line, we only need to check Y // as the line is straight after the last controller //printf("post oldX:%d oldY:%d xpixel:%d ypixel:%d currX:%d currY:%d\n", oldX, oldY, xpixel, ypixel, currX, currY); - if(mouseX >= eventX && eventY == eventOldY && ABS(mouseY-eventY) < circumference) { + if(mouseX >= eventX && ABS(mouseY-eventY) < circumference) { QWidget::setCursor(Qt::CrossCursor); automation.controllerState = addNewController; automation.currentCtrlList = cl; @@ -3817,7 +3843,7 @@ void PartCanvas::checkAutomation(MusECore::Track * t, const QPoint &pointer, boo setCursor(); } -void PartCanvas::controllerChanged(MusECore::Track* t) +void PartCanvas::controllerChanged(MusECore::Track* t, int) { redraw((QRect(0, mapy(t->y()), width(), rmapy(t->height())))); // TODO Check this - correct? } diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h index ab227eb2..1b766c5d 100644 --- a/muse2/muse/arranger/pcanvas.h +++ b/muse2/muse/arranger/pcanvas.h @@ -184,7 +184,7 @@ class PartCanvas : public Canvas { public slots: void redirKeypress(QKeyEvent* e) { keyPress(e); } - void controllerChanged(MusECore::Track *t); + void controllerChanged(MusECore::Track *t, int CtrlId); }; } // namespace MusEGui diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp index 3d831ba9..05e23321 100644 --- a/muse2/muse/arranger/tlist.cpp +++ b/muse2/muse/arranger/tlist.cpp @@ -22,6 +22,8 @@ #include <cmath> +#include <QAction> +#include <QActionGroup> #include <QKeyEvent> #include <QLineEdit> #include <QMessageBox> @@ -35,6 +37,7 @@ #include <QIcon> #include <QSpinBox> #include <QToolTip> +#include <QList> #include "popupmenu.h" #include "globals.h" @@ -64,6 +67,8 @@ #include "menutitleitem.h" #include "arranger.h" #include "undo.h" +#include "midi_audio_control.h" +#include "ctrl.h" #ifdef DSSI_SUPPORT #include "dssihost.h" @@ -1409,18 +1414,21 @@ MusECore::TrackList TList::getRecEnabledTracks() void TList::changeAutomation(QAction* act) { - if ( (editAutomation->type() == MusECore::Track::MIDI) || (editAutomation->type() == MusECore::Track::DRUM) || (editAutomation->type() == MusECore::Track::NEW_DRUM) ) { - printf("this is wrong, we can't edit automation for midi tracks from arranger yet!\n"); + if(!editAutomation || editAutomation->isMidiTrack()) + return; + if(act->data().toInt() == -1) return; - } int colindex = act->data().toInt() & 0xff; - int id = (act->data().toInt() & 0x00ffffff) / 256; + int id = (act->data().toInt() & 0x00ffffff) >> 8; + // Is it the midi control action or clear action item? + if (colindex == 254 || colindex == 255) + return; + if (colindex < 100) return; // this was meant for changeAutomationColor // one of these days I'll rewrite this so it's understandable // this is just to get it up and running... - MusECore::CtrlListList* cll = ((MusECore::AudioTrack*)editAutomation)->controller(); for(MusECore::CtrlListList::iterator icll =cll->begin();icll!=cll->end();++icll) { MusECore::CtrlList *cl = icll->second; @@ -1435,13 +1443,81 @@ void TList::changeAutomation(QAction* act) //--------------------------------------------------------- void TList::changeAutomationColor(QAction* act) { - if ( (editAutomation->type() == MusECore::Track::MIDI) || (editAutomation->type() == MusECore::Track::DRUM) || (editAutomation->type() == MusECore::Track::NEW_DRUM) ) { - printf("this is wrong, we can't edit automation for midi tracks from arranger yet!\n"); + if(!editAutomation || editAutomation->isMidiTrack()) + return; + if(act->data().toInt() == -1) return; - } int colindex = act->data().toInt() & 0xff; - int id = (act->data().toInt() & 0x00ffffff) / 256; + int id = (act->data().toInt() & 0x00ffffff) >> 8; + // Is it the clear midi control action item? + if(colindex == 254) + { + MusECore::AudioTrack* track = static_cast<MusECore::AudioTrack*>(editAutomation); + MusECore::MidiAudioCtrlMap* macp = track->controller()->midiControls(); + MusECore::AudioMidiCtrlStructMap amcs; + macp->find_audio_ctrl_structs(id, &amcs); + if(!amcs.empty()) + MusEGlobal::audio->msgIdle(true); // Gain access to structures, and sync with audio + for(MusECore::iAudioMidiCtrlStructMap iamcs = amcs.begin(); iamcs != amcs.end(); ++iamcs) + macp->erase(*iamcs); + if(!amcs.empty()) + MusEGlobal::audio->msgIdle(false); + + // Hm, need to remove the 'clear' item, and the status lines below it. Try this: + QActionGroup* midi_actgrp = act->actionGroup(); + if(midi_actgrp) + { + QList<QAction*> act_list = midi_actgrp->actions(); + int sz = act_list.size(); + for(int i = 0; i < sz; ++i) + { + QAction* list_act = act_list.at(i); + ///midi_actgrp->removeAction(list_act); + // list_act has no parent now. + ///delete list_act; + list_act->setVisible(false); // HACK Cannot delete any actions! Causes crash with our PopupMenu due to recent fixes. + } + } + return; + } + + // Is it the midi control action item? + if(colindex == 255) + { + MusECore::AudioTrack* track = static_cast<MusECore::AudioTrack*>(editAutomation); + MusECore::MidiAudioCtrlMap* macm = track->controller()->midiControls(); + MusECore::AudioMidiCtrlStructMap amcs; + macm->find_audio_ctrl_structs(id, &amcs); + + int port = -1, chan = 0, ctrl = 0; + for(MusECore::iAudioMidiCtrlStructMap iamcs = amcs.begin(); iamcs != amcs.end(); ++iamcs) + { + macm->hash_values((*iamcs)->first, &port, &chan, &ctrl); + break; // Only a single item for now, thanks! + } + + MidiAudioControl* pup = new MidiAudioControl(port, chan, ctrl); + + if(pup->exec() == QDialog::Accepted) + { + MusEGlobal::audio->msgIdle(true); // Gain access to structures, and sync with audio + // Erase all for now. + for(MusECore::iAudioMidiCtrlStructMap iamcs = amcs.begin(); iamcs != amcs.end(); ++iamcs) + macm->erase(*iamcs); + + port = pup->port(); chan = pup->chan(); ctrl = pup->ctrl(); + if(port >= 0 && chan >=0 && ctrl >= 0) + // Add will replace if found. + macm->add_ctrl_struct(port, chan, ctrl, MusECore::MidiAudioCtrlStruct(id)); + + MusEGlobal::audio->msgIdle(false); + } + + delete pup; + return; + } + if (colindex > 100) return; // this was meant for changeAutomation // one of these days I'll rewrite this so it's understandable @@ -1461,7 +1537,10 @@ void TList::changeAutomationColor(QAction* act) //--------------------------------------------------------- PopupMenu* TList::colorMenu(QColor c, int id, QWidget* parent) { - PopupMenu * m = new PopupMenu(parent); //, true); //TODO + PopupMenu * m = new PopupMenu(parent, true); + + QActionGroup* col_actgrp = new QActionGroup(m); + col_actgrp->setExclusive(true); for (int i = 0; i< 6; i++) { QPixmap pix(10,10); QPainter p(&pix); @@ -1469,14 +1548,52 @@ PopupMenu* TList::colorMenu(QColor c, int id, QWidget* parent) p.setPen(Qt::black); p.drawRect(0,0,10,10); QIcon icon(pix); - QAction *act = m->addAction(icon,""); + QAction *act = col_actgrp->addAction(icon,""); act->setCheckable(true); if (c == collist[i]) act->setChecked(true); - int data = id * 256; // shift 8 bits - data += i; // color in the bottom 8 bits - act->setData(data); + act->setData((id<<8) + i); // Shift 8 bits. Color in the bottom 8 bits. } + m->addActions(col_actgrp->actions()); + + //m->addSeparator(); + m->addAction(new MenuTitleItem(tr("Midi control"), m)); + + if(editAutomation && !editAutomation->isMidiTrack()) + { + QAction *act = m->addAction(tr("Assign")); + act->setCheckable(false); + act->setData((id<<8) + 255); // Shift 8 bits. Make midi menu the last item at 255. + + MusECore::AudioTrack* track = static_cast<MusECore::AudioTrack*>(editAutomation); + MusECore::MidiAudioCtrlMap* macm = track->controller()->midiControls(); + MusECore::AudioMidiCtrlStructMap amcs; + macm->find_audio_ctrl_structs(id, &amcs); + + // Group only the clear and status items so they can both be easily removed when clear is clicked. + if(!amcs.empty()) + { + QActionGroup* midi_actgrp = new QActionGroup(m); + QAction *cact = midi_actgrp->addAction(tr("Clear")); + cact->setData((id<<8) + 254); // Shift 8 bits. Make clear the second-last item at 254 + for(MusECore::iAudioMidiCtrlStructMap iamcs = amcs.begin(); iamcs != amcs.end(); ++iamcs) + { + int port, chan, mctrl; + macm->hash_values((*iamcs)->first, &port, &chan, &mctrl); + //QString s = QString("Port:%1 Chan:%2 Ctl:%3-%4").arg(port + 1) + QString s = QString("Port:%1 Chan:%2 Ctl:%3").arg(port + 1) + .arg(chan + 1) + //.arg((mctrl >> 8) & 0xff) + //.arg(mctrl & 0xff); + .arg(MusECore::midiCtrlName(mctrl, true)); + QAction *mact = midi_actgrp->addAction(s); + mact->setEnabled(false); + mact->setData(-1); // Not used + } + m->addActions(midi_actgrp->actions()); + } + } + connect(m, SIGNAL(triggered(QAction*)), SLOT(changeAutomationColor(QAction*))); return m; @@ -1611,14 +1728,53 @@ void TList::mousePressEvent(QMouseEvent* ev) p->setTitle(tr("Viewable automation")); MusECore::CtrlListList* cll = ((MusECore::AudioTrack*)t)->controller(); QAction* act = 0; + int last_rackpos = -1; + bool internal_found = false; + bool synth_found = false; for(MusECore::CtrlListList::iterator icll =cll->begin();icll!=cll->end();++icll) { MusECore::CtrlList *cl = icll->second; if (cl->dontShow()) continue; + + int ctrl = cl->id(); + + if(ctrl < AC_PLUGIN_CTL_BASE) + { + if(!internal_found) + p->addAction(new MusEGui::MenuTitleItem(tr("Internal"), p)); + internal_found = true; + } + else + { + if(ctrl < (int)MusECore::genACnum(MAX_PLUGINS, 0)) // The beginning of the special dssi synth controller block. + { + int rackpos = (ctrl - AC_PLUGIN_CTL_BASE) >> AC_PLUGIN_CTL_BASE_POW; + if(rackpos < PipelineDepth) + { + if(rackpos != last_rackpos) + { + QString s = ((MusECore::AudioTrack*)t)->efxPipe()->name(rackpos); + p->addAction(new MusEGui::MenuTitleItem(s, p)); + } + last_rackpos = rackpos; + } + } + else + { + if(t->type() == MusECore::Track::AUDIO_SOFTSYNTH) + { + if(!synth_found) + p->addAction(new MusEGui::MenuTitleItem(tr("Synth"), p)); + synth_found = true; + } + } + } + act = p->addAction(cl->name()); act->setCheckable(true); act->setChecked(cl->isVisible()); - int data = cl->id() * 256; // shift 8 bits + + int data = ctrl<<8; // shift 8 bits data += 150; // illegal color > 100 act->setData(data); PopupMenu *m = colorMenu(cl->color(), cl->id(), p); |