1
//=========================================================
4
// $Id: ctrlcanvas.cpp,v 1.2 2003/11/19 21:28:40 lunar_shuttle Exp $
5
// (C) Copyright 1999 Werner Schweer (ws@seh.de)
6
//=========================================================
12
#include <qtoolbutton.h>
13
#include <qpopupmenu.h>
19
#include "midieditor.h"
23
#include "midithread.h"
25
extern void drawTickRaster(QPainter& p, int x, int y,
26
int w, int h, int quant);
28
//---------------------------------------------------------
30
//---------------------------------------------------------
32
CEvent::CEvent(MidiEvent* e, MidiPart* pt, int v)
37
ex = e ? e->posTick() : 0;
40
//---------------------------------------------------------
42
//---------------------------------------------------------
44
bool CEvent::contains(int x1, int x2) const
46
int tick1 = _event ? _event->posTick() + _part->posTick() : 0;
47
int tick2 = ex + _part->posTick();
48
return ((tick1 >= x1 && tick1 < x2)
49
|| (tick2 >= x1 && tick2 < x2)
50
|| (tick1 < x1 && tick2 >= x2));
53
//---------------------------------------------------------
55
//---------------------------------------------------------
57
CtrlCanvas::CtrlCanvas(MidiEditor* e, QWidget* parent, int xmag,
58
const char* name) : View(parent, xmag, 1, name)
67
keyFilter = -1; //Start with no key filter
68
connect(song, SIGNAL(posChanged(int, int, bool)), this, SLOT(setPos(int, int, bool)));
70
setMouseTracking(true);
71
if (editor->parts()->empty()) {
76
curPart = (MidiPart*)(editor->parts()->begin()->second);
77
curTrack = (MidiTrack*)(curPart->track());
79
connect(song, SIGNAL(songChanged(int)), SLOT(songChanged(int)));
80
songChanged(SC_TRACK_INSERTED);
83
//---------------------------------------------------------
85
// set one of three markers
86
// idx - 0-cpos 1-lpos 2-rpos
87
// flag - emit followEvent()
88
//---------------------------------------------------------
90
void CtrlCanvas::setPos(int idx, int val, bool adjustScrollbar)
93
// printf("ctrlCanvas: setPos %d %d\n", idx, val);
97
int opos = mapx(pos[idx]);
100
if (adjustScrollbar && idx == 0) {
101
switch (song->follow()) {
105
if (npos >= width()) {
106
int ppos = val - rmapxDev(width()/4);
109
emit followEvent(ppos);
110
opos = mapx(pos[idx]);
114
int ppos = val - rmapxDev(width()*3/4);
117
emit followEvent(ppos);
118
opos = mapx(pos[idx]);
122
case Song::CONTINUOUS:
123
if (npos > (width()*5)/8) {
124
int ppos = pos[idx] - rmapxDev(width()*5/8);
127
emit followEvent(ppos);
128
opos = mapx(pos[idx]);
131
else if (npos < (width()*3)/8) {
132
int ppos = pos[idx] - rmapxDev(width()*3/8);
135
emit followEvent(ppos);
136
opos = mapx(pos[idx]);
154
//printf(" redraw %d %d %d %d\n", x, 0, w, height());
155
redraw(QRect(x, 0, w, height()));
161
int opos = mapx(pos[idx]);
167
if (adjustScrollbar && idx == 0) {
168
switch (song->follow()) {
172
if (val >= width()) {
173
emit followEvent(val);
177
case Song::CONTINUOUS:
178
if (val > width()/2) {
179
int ppos = pos[idx] - rmapxDev(width()/2);
182
emit followEvent(ppos);
198
paint(QRect(x, 0, w, height()));
202
//---------------------------------------------------------
204
//---------------------------------------------------------
206
void CtrlCanvas::setController(const MidiController& c)
212
//---------------------------------------------------------
214
//---------------------------------------------------------
215
void CtrlCanvas::setKeyfilter(char in_keyfilter)
217
keyFilter = in_keyfilter;
218
songChanged(-1); //Correct?
221
//---------------------------------------------------------
223
//---------------------------------------------------------
225
void CtrlCanvas::leaveEvent(QEvent*)
227
emit xposChanged(-1);
228
emit yposChanged(-1);
231
QPoint CtrlCanvas::raster(const QPoint& p) const
236
//---------------------------------------------------------
238
//---------------------------------------------------------
240
void CtrlCanvas::deselectAll()
242
// for (iCEvent i = selection.begin(); i != selection.end(); ++i)
243
// (*i)->setState(CEvent::Normal);
244
// selection.clear();
248
//---------------------------------------------------------
250
//---------------------------------------------------------
252
void CtrlCanvas::selectItem(CEvent*)
254
// e->setState(CEvent::Selected);
255
// selection.push_back(e);
259
//---------------------------------------------------------
261
//---------------------------------------------------------
263
void CtrlCanvas::deselectItem(CEvent*)
265
/* e->setState(CEvent::Normal);
266
for (iCEvent i = selection.begin(); i != selection.end(); ++i) {
276
//---------------------------------------------------------
278
// alle markierten Parts werden hier
279
// in die interne Eventliste aufgenommen
280
//---------------------------------------------------------
282
void CtrlCanvas::songChanged(int)
284
if (editor->parts()->empty())
288
MidiPort* port = &midiPorts[curTrack->outPort()];
290
//---------------------------------------------------
291
// get initial controller value
292
//---------------------------------------------------
295
ChannelState* ics = port->iState(curTrack->outChannel());
296
switch(ctrl.type()) {
297
case MidiController::Controller7:
298
val = ics->controller[ctrl.hnum()];
300
case MidiController::Controller14:
302
int hval = ics->controller[ctrl.hnum()];
303
int lval = ics->controller[ctrl.lnum()];
304
if (hval == -1 && lval == -1)
311
val = (hval << 7) + lval;
315
case MidiController::RPN:
316
case MidiController::NRPN:
319
case MidiController::Pitch:
322
case MidiController::XgSysex:
323
case MidiController::Sysex:
326
case MidiController::Velo:
333
for (iPart p = editor->parts()->begin(); p != editor->parts()->end(); ++p) {
334
MidiPart* part = (MidiPart*)(p->second);
335
EventList* el = part->events();
336
for (iEvent i = el->begin(); i != el->end(); ++i) {
337
MidiEvent* e = (MidiEvent*)i->second;
338
switch(ctrl.type()) {
339
case MidiController::Velo:
340
if (e->type() != MidiEvent::Note)
342
//If it's velocity and keyFilter is activated, only add items with the same key
343
if (keyFilter == -1) { //If no keyFilter, just add it:
344
items.add(new CEvent(e, part, e->velo()));
346
else if (e->dataA() == keyFilter) //If keyFilter matches, add it
347
items.add(new CEvent(e, part, e->velo()));
350
case MidiController::Controller7:
351
if (e->type() != MidiEvent::Ctrl7)
353
if (e->cntrl() != ctrl.hnum())
356
lastce = new CEvent(0, part, val);
360
lastce->setEX(e->posTick());
361
lastce = new CEvent(e, part, e->cntrlVal());
365
case MidiController::Controller14:
366
if (e->type() != MidiEvent::Ctrl14)
368
if ((e->dataA() != ctrl.hnum()) || (e->dataC() != ctrl.lnum()))
371
lastce = new CEvent(0, part, val);
375
lastce->setEX(e->posTick());
376
lastce = new CEvent(e, part, e->dataB());
380
case MidiController::Pitch:
381
if (e->type() != MidiEvent::Pitch)
384
lastce = new CEvent(0, part, val);
388
lastce->setEX(e->posTick());
389
lastce = new CEvent(e, part, e->dataA());
401
//---------------------------------------------------------
402
// viewMousePressEvent
403
//---------------------------------------------------------
405
void CtrlCanvas::viewMousePressEvent(QMouseEvent* event)
407
start = event->pos();
408
Tool activeTool = tool;
409
bool shift = event->state() & ShiftButton;
411
int xpos = start.x();
412
int ypos = start.y();
414
switch (activeTool) {
416
drag = DRAG_LASSO_START;
421
if (ctrl.type() != MidiController::Velo) {
424
newVal(xpos, xpos, ypos);
430
changeVal(xpos, xpos, ypos);
435
if (ctrl.type() != MidiController::Velo) {
438
deleteVal(xpos, xpos, ypos);
447
newValRamp(line1x, line1y, line2x, line2y);
449
changeValRamp(line1x, line1y, line2x, line2y);
450
drawLineMode = false;
453
line2x = line1x = xpos;
454
line2y = line1y = ypos;
465
//---------------------------------------------------------
467
//---------------------------------------------------------
469
void CtrlCanvas::newValRamp(int x1, int y1, int x2, int y2)
471
int xx1 = editor->rasterVal1(x1);
472
int xx2 = editor->rasterVal2(x2);
473
int min = ctrl.minVal();
474
int max = ctrl.maxVal();
477
int raster = editor->raster();
478
if (raster == 1) // set reasonable raster
483
// delete existing events
485
for (ciCEvent i = items.begin(); i != items.end(); ++i) {
487
MidiEvent* event = ev->event();
490
int x = event->posTick();
495
midiThread->msgDeleteEvent(event, ev->part(), false);
499
for (int x = xx1; x < xx2; x += raster) {
500
int y = (x2==x1) ? y1 : (((y2-y1)*(x-x1))/(x2-x1))+y1;
501
int nval = (((h - y) * (max-min)) / h) + min;
505
int tick = x - curPart->posTick();
506
MidiEvent* event = 0;
507
switch(ctrl.type()) {
508
case MidiController::Controller7:
509
event = new MidiEvent(
510
tick, MidiEvent::Ctrl7, ctrl.hnum(), nval, 0, 0);
512
case MidiController::Controller14:
513
event = new MidiEvent(
514
tick, MidiEvent::Ctrl14, ctrl.hnum(), nval, ctrl.lnum(), 0);
516
case MidiController::RPN:
517
event = new MidiEvent(
518
tick, MidiEvent::RPN, ctrl.hnum()*128+ctrl.lnum(), nval, 0, 0);
520
case MidiController::NRPN:
521
event = new MidiEvent(
522
tick, MidiEvent::RPN, ctrl.hnum()*128+ctrl.lnum(), nval, 0, 0);
524
case MidiController::XgSysex:
525
case MidiController::Sysex:
527
case MidiController::Pitch:
528
event = new MidiEvent(
529
tick, MidiEvent::Pitch, nval, 0, 0, 0);
531
case MidiController::Velo:
535
midiThread->msgAddEvent(event, curPart, false);
540
song->endUndo(SC_EVENT_MODIFIED | SC_EVENT_INSERTED | SC_EVENT_REMOVED);
543
//---------------------------------------------------------
545
//---------------------------------------------------------
547
void CtrlCanvas::changeValRamp(int x1, int y1, int x2, int y2)
550
int min = ctrl.minVal();
551
int max = ctrl.maxVal();
552
bool changed = false;
555
for (ciCEvent i = items.begin(); i != items.end(); ++i) {
556
if ((*i)->contains(x1, x2)) {
558
MidiEvent* event = ev->event();
562
MidiPart* part = ev->part();
564
int x = event->posTick() + ev->part()->posTick();
565
int y = (x2==x1) ? y1 : (((y2-y1)*(x-x1))/(x2-x1))+y1;
566
int nval = (((h - y) * (max-min)) / h) + min;
571
if (ctrl.type() == MidiController::Velo) {
572
if ((event->velo() != nval)) {
573
MidiEvent* newEvent = new MidiEvent(*event);
574
newEvent->setVelo(nval);
575
midiThread->msgChangeEvent(event, newEvent, part, false);
576
ev->setEvent(newEvent);
580
else if (ctrl.type() == MidiController::Controller7) {
582
if ((event->cntrlVal() != nval)) {
583
MidiEvent* newEvent = new MidiEvent(*event);
584
newEvent->setB(nval);
585
midiThread->msgChangeEvent(event, newEvent, part, false);
586
ev->setEvent(newEvent);
591
MidiPort* port = &midiPorts[curTrack->outPort()];
592
int channel = curTrack->outChannel();
593
int oval = port->iState(channel)->controller[ctrl.hnum()];
595
port->iState(channel)->controller[ctrl.hnum()] = nval;
604
song->endUndo(SC_EVENT_MODIFIED);
607
//---------------------------------------------------------
608
// viewMouseMoveEvent
609
//---------------------------------------------------------
611
void CtrlCanvas::viewMouseMoveEvent(QMouseEvent* event)
613
QPoint pos = event->pos();
614
QPoint dist = pos - start;
615
bool moving = dist.y() >= 3 || dist.y() <= 3 || dist.x() >= 3 || dist.x() <= 3;
617
case DRAG_LASSO_START:
621
// weiter mit DRAG_LASSO:
623
lasso.setRect(start.x(), start.y(), dist.x(), dist.y());
627
changeVal(start.x(), pos.x(), pos.y());
632
newVal(start.x(), pos.x(), pos.y());
637
deleteVal(start.x(), pos.x(), pos.y());
644
if (tool == DrawTool && drawLineMode) {
649
emit xposChanged(pos.x());
650
int min = ctrl.minVal();
651
int max = ctrl.maxVal();
652
int val = max - (pos.y() * (max-min) / height());
657
emit yposChanged(val);
660
//---------------------------------------------------------
661
// viewMouseReleaseEvent
662
//---------------------------------------------------------
664
void CtrlCanvas::viewMouseReleaseEvent(QMouseEvent* event)
666
bool shift = event->state() & ShiftButton;
672
song->endUndo(SC_EVENT_MODIFIED | SC_EVENT_INSERTED);
675
case DRAG_LASSO_START:
676
lasso.setRect(-1, -1, -1, -1);
681
lasso = lasso.normalize();
682
for (iCEvent i = items.begin(); i != items.end(); ++i) {
684
if ((*i)->intersects(lasso)) {
685
if (shift && (*i)->isSelected())
702
//---------------------------------------------------------
704
//---------------------------------------------------------
706
void CtrlCanvas::changeVal(int x1, int x2, int y)
709
int min = ctrl.minVal();
710
int max = ctrl.maxVal();
712
bool changed = false;
713
int nval = (((h - y) * (max-min)) / h) + min;
717
for (ciCEvent i = items.begin(); i != items.end(); ++i) {
718
if (!(*i)->contains(x1, x2))
722
MidiEvent* event = ev->event();
723
MidiPart* part = ev->part();
725
if (ctrl.type() == MidiController::Velo) {
726
if ((event->velo() != nval)) {
727
MidiEvent* newEvent = new MidiEvent(*event);
728
newEvent->setVelo(nval);
729
midiThread->msgChangeEvent(event, newEvent, part, false);
730
ev->setEvent(newEvent);
734
else if (ctrl.type() == MidiController::Controller7) {
736
if ((event->cntrlVal() != nval)) {
737
MidiEvent* newEvent = new MidiEvent(*event);
738
newEvent->setB(nval);
739
midiThread->msgChangeEvent(event, newEvent, part, false);
740
ev->setEvent(newEvent);
745
MidiPort* port = &midiPorts[curTrack->outPort()];
746
int channel = curTrack->outChannel();
747
int oval = port->iState(channel)->controller[ctrl.hnum()];
749
port->iState(channel)->controller[ctrl.hnum()] = nval;
754
else if (ctrl.type() == MidiController::Pitch) {
756
if ((event->pitch() != nval)) {
757
MidiEvent* newEvent = new MidiEvent(
758
event->posTick(), MidiEvent::Pitch, nval, 0, 0, 0);
759
midiThread->msgChangeEvent(event, newEvent, part, false);
760
ev->setEvent(newEvent);
765
MidiPort* port = &midiPorts[curTrack->outPort()];
766
int channel = curTrack->outChannel();
767
int oval = port->iState(channel)->pitch;
769
port->iState(channel)->pitch = nval;
779
//---------------------------------------------------------
781
//---------------------------------------------------------
783
void CtrlCanvas::newVal(int x1, int x2, int y)
785
int xx1 = editor->rasterVal1(x1);
786
int xx2 = editor->rasterVal2(x2);
787
int min = ctrl.minVal();
788
int max = ctrl.maxVal();
791
int nval = (((h - y) * (max-min)) / h) + min;
796
bool song_changed = false;
797
for (ciCEvent i = items.begin(); i != items.end(); ++i) {
799
int partTick = ev->part()->posTick();
800
MidiEvent* event = ev->event();
803
int ax = event->posTick() + partTick;
812
switch(ctrl.type()) {
813
case MidiController::Controller7:
814
if ((event->cntrlVal() != nval)) {
815
MidiEvent* newEvent = new MidiEvent(*event);
816
newEvent->setB(nval);
817
midiThread->msgChangeEvent(event, newEvent, ev->part(), false);
818
ev->setEvent(newEvent);
822
case MidiController::Pitch:
824
if (event->pitch() != nval) {
825
MidiEvent* newEvent = new MidiEvent(
826
xx1-partTick, MidiEvent::Pitch, nval, 0, 0, 0);
827
midiThread->msgChangeEvent(event, newEvent, ev->part(), false);
828
ev->setEvent(newEvent);
840
midiThread->msgDeleteEvent(event, ev->part(), false);
846
MidiEvent* event = 0;
847
int tick = xx1 - curPart->posTick();
849
switch(ctrl.type()) {
850
case MidiController::Controller7:
851
event = new MidiEvent(
852
tick, MidiEvent::Ctrl7, ctrl.hnum(), nval, 0, 0);
854
case MidiController::Controller14:
855
event = new MidiEvent(
856
tick, MidiEvent::Ctrl14, ctrl.hnum(), nval, ctrl.lnum(), 0);
858
case MidiController::RPN:
859
event = new MidiEvent(
860
tick, MidiEvent::RPN, ctrl.hnum()*128+ctrl.lnum(), nval, 0, 0);
862
case MidiController::NRPN:
863
event = new MidiEvent(
864
tick, MidiEvent::RPN, ctrl.hnum()*128+ctrl.lnum(), nval, 0, 0);
866
case MidiController::XgSysex:
867
case MidiController::Sysex:
869
case MidiController::Pitch:
870
event = new MidiEvent(
871
tick, MidiEvent::Pitch, nval, 0, 0, 0);
873
case MidiController::Velo:
877
midiThread->msgAddEvent(event, curPart, false);
888
//---------------------------------------------------------
890
//---------------------------------------------------------
892
void CtrlCanvas::deleteVal(int x1, int x2, int)
894
int xx1 = editor->rasterVal1(x1);
895
int xx2 = editor->rasterVal2(x2);
897
int partTick = curPart->posTick();
901
bool song_changed = false;
902
for (ciCEvent i = items.begin(); i != items.end(); ++i) {
904
MidiEvent* event = ev->event();
907
int x = event->posTick();
913
midiThread->msgDeleteEvent(event, ev->part(), false);
923
//---------------------------------------------------------
925
//---------------------------------------------------------
927
void CtrlCanvas::setTool(int t)
934
setCursor(QCursor(*pencilIcon, 4, 15));
937
drawLineMode = false;
940
setCursor(QCursor(arrowCursor));
945
//---------------------------------------------------------
947
//---------------------------------------------------------
949
void CtrlCanvas::pdraw(QPainter& p, const QRect& rect)
951
int x = rect.x() - 1; // compensate for 3 pixel line width
953
int w = rect.width() + 2;
954
int h = rect.height();
958
//---------------------------------------------------
960
//---------------------------------------------------
962
if (ctrl.type() == MidiController::Velo) {
964
for (iCEvent i = items.begin(); i != items.end(); ++i) {
966
int tick = mapx(e->event()->posTick() + e->part()->posTick());
971
int y1 = wh - (e->val() * wh / 128);
973
p.setPen(QPen(blue, 3));
974
p.drawLine(tick, wh, tick, y1);
978
int min = ctrl.minVal();
979
int max = ctrl.maxVal();
982
for (iCEvent i = items.begin(); i != items.end(); ++i) {
984
int tick = mapx(e->event() ? e->event()->posTick() + e->part()->posTick() : 0);
989
lval = wh - ((e->val() - min) * wh / (max - min));
995
p.fillRect(x1, 0, tick - x1, wh, gray);
997
p.fillRect(x1, lval, tick - x1, wh - lval, blue);
1002
lval = wh - ((e->val() - min) * wh / (max - min));
1005
p.fillRect(x1, 0, (x+w) - x1, wh, gray);
1007
p.fillRect(x1, lval, (x+w) - x1, wh - lval, blue);
1011
View::pdraw(p, rect);
1014
//---------------------------------------------------
1016
//---------------------------------------------------
1018
int xp = mapx(pos[0]);
1019
if (xp >= x && xp < x+w) {
1021
p.drawLine(xp, y, xp, y+h);
1024
if (xp >= x && xp < x+w) {
1026
p.drawLine(xp, y, xp, y+h);
1029
if (xp >= x && xp < x+w) {
1031
p.drawLine(xp, y, xp, y+h);
1034
//---------------------------------------------------
1036
//---------------------------------------------------
1038
if (drag == DRAG_LASSO) {
1041
p.setBrush(NoBrush);
1044
// View::pdraw(p, rect);
1047
//---------------------------------------------------------
1049
//---------------------------------------------------------
1051
void CtrlCanvas::drawOverlay(QPainter& p)
1053
QString s(ctrl.name());
1054
//printf("draw overlay %s\n", ctrl.name().latin1());
1057
QFontMetrics fm(font3);
1058
int y = fm.lineSpacing() + 2;
1059
p.drawText(2, y, s);
1062
//---------------------------------------------------------
1064
// returns geometry of overlay rectangle
1065
//---------------------------------------------------------
1067
QRect CtrlCanvas::overlayRect() const
1069
QFontMetrics fm(font3);
1070
QRect r(fm.boundingRect(ctrl.name()));
1071
r.moveBy(2, 2); // top/left margin
1075
//---------------------------------------------------------
1077
//---------------------------------------------------------
1079
void CtrlCanvas::draw(QPainter& p, const QRect& rect)
1081
drawTickRaster(p, rect.x(), rect.y(),
1082
rect.width(), rect.height(), editor->quant());
1084
//---------------------------------------------------
1086
//---------------------------------------------------
1088
if (drawLineMode && (tool == DrawTool)) {
1090
p.drawLine(line1x, line1y, line2x, line2y);