summaryrefslogtreecommitdiff
path: root/muse2/muse/arranger
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2012-07-01 16:42:16 +0000
committerFlorian Jung <flo@windfisch.org>2012-07-01 16:42:16 +0000
commit9c4664d162c537ba4dd4fd8220971c0fb727103a (patch)
tree37a28b7cd4e4d8984ad4934a4884cd7b4da0505c /muse2/muse/arranger
parente87fedf1be804f7ec774071d844b1f163be30b96 (diff)
final merge
Diffstat (limited to 'muse2/muse/arranger')
-rw-r--r--muse2/muse/arranger/arranger.cpp8
-rw-r--r--muse2/muse/arranger/arranger.h2
-rw-r--r--muse2/muse/arranger/pcanvas.cpp88
-rw-r--r--muse2/muse/arranger/pcanvas.h2
-rw-r--r--muse2/muse/arranger/tlist.cpp186
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);