1
//=========================================================
4
// $Id: ctrlcanvas.cpp,v 1.3 2002/02/07 10:02:48 muse Exp $
5
// (C) Copyright 1999 Werner Schweer (ws@seh.de)
6
//=========================================================
12
#include <qtoolbutton.h>
13
#include <qpopupmenu.h>
18
#include "midieditor.h"
22
#include "midithread.h"
24
extern void drawTickRaster(QPainter& p, int x, int y,
25
int w, int h, int quant);
27
//---------------------------------------------------------
29
//---------------------------------------------------------
31
CEvent::CEvent(MidiEvent* e, MidiPart* pt, int v)
36
ex = e ? e->posTick() : 0;
39
//---------------------------------------------------------
41
//---------------------------------------------------------
43
bool CEvent::contains(int x1, int x2) const
45
int tick = _event ? _event->posTick() : 0;
46
return ((tick >= x1 && tick < x2)
47
|| (ex >= x1 && ex < x2)
48
|| (tick < x1 && ex >= x2));
51
//---------------------------------------------------------
53
//---------------------------------------------------------
55
CtrlCanvas::CtrlCanvas(MidiEditor* e, QWidget* parent, int xmag,
56
const char* name = 0) : View(parent, xmag, 1, name)
65
connect(song, SIGNAL(posChanged(int, int, bool)), this, SLOT(setPos(int, int, bool)));
67
setMouseTracking(true);
68
if (editor->parts()->empty()) {
73
curPart = (MidiPart*)(editor->parts()->begin()->second);
74
curTrack = (MidiTrack*)(curPart->track());
76
connect(song, SIGNAL(songChanged(int)), SLOT(songChanged(int)));
77
songChanged(SC_TRACK_INSERTED);
80
//---------------------------------------------------------
82
// set one of three markers
83
// idx - 0-cpos 1-lpos 2-rpos
84
// flag - emit followEvent()
85
//---------------------------------------------------------
87
void CtrlCanvas::setPos(int idx, int val, bool adjustScrollbar)
90
// printf("ctrlCanvas: setPos %d %d\n", idx, val);
94
int opos = mapx(pos[idx]);
97
if (adjustScrollbar && idx == 0) {
98
switch (song->follow()) {
102
if (npos >= width()) {
103
int ppos = val - rmapxDev(width()/4);
106
emit followEvent(ppos);
107
opos = mapx(pos[idx]);
111
int ppos = val - rmapxDev(width()*3/4);
114
emit followEvent(ppos);
115
opos = mapx(pos[idx]);
119
case Song::CONTINUOUS:
120
if (npos > (width()*5)/8) {
121
int ppos = pos[idx] - rmapxDev(width()*5/8);
124
emit followEvent(ppos);
125
opos = mapx(pos[idx]);
128
else if (npos < (width()*3)/8) {
129
int ppos = pos[idx] - rmapxDev(width()*3/8);
132
emit followEvent(ppos);
133
opos = mapx(pos[idx]);
151
//printf(" redraw %d %d %d %d\n", x, 0, w, height());
152
redraw(QRect(x, 0, w, height()));
158
int opos = mapx(pos[idx]);
164
if (adjustScrollbar && idx == 0) {
165
switch (song->follow()) {
169
if (val >= width()) {
170
emit followEvent(val);
174
case Song::CONTINUOUS:
175
if (val > width()/2) {
176
int ppos = pos[idx] - rmapxDev(width()/2);
179
emit followEvent(ppos);
195
paint(QRect(x, 0, w, height()));
199
//---------------------------------------------------------
201
//---------------------------------------------------------
203
void CtrlCanvas::setController(const MidiController& c)
209
//---------------------------------------------------------
211
//---------------------------------------------------------
213
void CtrlCanvas::leaveEvent(QEvent*)
215
emit xposChanged(-1);
216
emit yposChanged(-1);
219
QPoint CtrlCanvas::raster(const QPoint& p) const
224
//---------------------------------------------------------
226
//---------------------------------------------------------
228
void CtrlCanvas::deselectAll()
230
// for (iCEvent i = selection.begin(); i != selection.end(); ++i)
231
// (*i)->setState(CEvent::Normal);
232
// selection.clear();
236
//---------------------------------------------------------
238
//---------------------------------------------------------
240
void CtrlCanvas::selectItem(CEvent*)
242
// e->setState(CEvent::Selected);
243
// selection.push_back(e);
247
//---------------------------------------------------------
249
//---------------------------------------------------------
251
void CtrlCanvas::deselectItem(CEvent*)
253
/* e->setState(CEvent::Normal);
254
for (iCEvent i = selection.begin(); i != selection.end(); ++i) {
264
//---------------------------------------------------------
266
// alle markierten Parts werden hier
267
// in die interne Eventliste aufgenommen
268
//---------------------------------------------------------
270
void CtrlCanvas::songChanged(int)
272
if (editor->parts()->empty())
276
MidiPort* port = &midiPorts[curTrack->outPort()];
278
//---------------------------------------------------
279
// get initial controller value
280
//---------------------------------------------------
283
ChannelState* ics = port->iState(curTrack->outChannel());
284
switch(ctrl.type()) {
285
case MidiController::Controller7:
286
val = ics->controller[ctrl.hnum()];
288
case MidiController::Controller14:
290
int hval = ics->controller[ctrl.hnum()];
291
int lval = ics->controller[ctrl.lnum()];
292
if (hval == -1 && lval == -1)
299
val = (hval << 7) + lval;
303
case MidiController::RPN:
304
case MidiController::NRPN:
307
case MidiController::Pitch:
310
case MidiController::XgSysex:
311
case MidiController::Sysex:
314
case MidiController::Velo:
321
for (iPart p = editor->parts()->begin(); p != editor->parts()->end(); ++p) {
322
MidiPart* part = (MidiPart*)(p->second);
323
EventList* el = part->events();
324
for (iEvent i = el->begin(); i != el->end(); ++i) {
325
MidiEvent* e = (MidiEvent*)i->second;
326
switch(ctrl.type()) {
327
case MidiController::Velo:
328
if (e->type() != MidiEvent::Note)
330
items.add(new CEvent(e, part, e->velo()));
332
case MidiController::Controller7:
333
if (e->type() != MidiEvent::Ctrl7)
335
if (e->cntrl() != ctrl.hnum())
338
lastce = new CEvent(0, part, val);
342
lastce->setEX(e->posTick());
343
lastce = new CEvent(e, part, e->cntrlVal());
347
case MidiController::Controller14:
348
if (e->type() != MidiEvent::Ctrl14)
350
if ((e->dataA() != ctrl.hnum()) || (e->dataC() != ctrl.lnum()))
353
lastce = new CEvent(0, part, val);
357
lastce->setEX(e->posTick());
358
lastce = new CEvent(e, part, e->dataB());
362
case MidiController::Pitch:
363
if (e->type() != MidiEvent::Pitch)
366
lastce = new CEvent(0, part, val);
370
lastce->setEX(e->posTick());
371
lastce = new CEvent(e, part, e->dataA());
383
//---------------------------------------------------------
384
// viewMousePressEvent
385
//---------------------------------------------------------
387
void CtrlCanvas::viewMousePressEvent(QMouseEvent* event)
389
start = event->pos();
390
Tool activeTool = tool;
391
bool shift = event->state() & ShiftButton;
393
int xpos = start.x();
394
int ypos = start.y();
396
switch (activeTool) {
398
drag = DRAG_LASSO_START;
403
if (ctrl.type() != MidiController::Velo) {
406
newVal(xpos, xpos, ypos);
412
changeVal(xpos, xpos, ypos);
417
if (ctrl.type() != MidiController::Velo) {
420
deleteVal(xpos, xpos, ypos);
429
newValRamp(line1x, line1y, line2x, line2y);
431
changeValRamp(line1x, line1y, line2x, line2y);
432
drawLineMode = false;
435
line2x = line1x = xpos;
436
line2y = line1y = ypos;
447
//---------------------------------------------------------
449
//---------------------------------------------------------
451
void CtrlCanvas::newValRamp(int x1, int y1, int x2, int y2)
453
int xx1 = editor->rasterVal1(x1);
454
int xx2 = editor->rasterVal2(x2);
455
int min = ctrl.minVal();
456
int max = ctrl.maxVal();
459
int raster = editor->raster();
460
if (raster == 1) // set reasonable raster
465
// delete existing events
467
for (ciCEvent i = items.begin(); i != items.end(); ++i) {
469
MidiEvent* event = ev->event();
472
int x = event->posTick();
477
midiThread->msgDeleteEvent(event, ev->part(), false);
481
for (int x = xx1; x < xx2; x += raster) {
482
int y = (x2==x1) ? y1 : (((y2-y1)*(x-x1))/(x2-x1))+y1;
483
int nval = (((h - y) * (max-min)) / h) + min;
487
MidiEvent* event = 0;
488
switch(ctrl.type()) {
489
case MidiController::Controller7:
490
event = new MidiEvent(
491
curTrack->outPort(), curTrack->outChannel(),
492
x, MidiEvent::Ctrl7, ctrl.hnum(), nval, 0, 0);
494
case MidiController::Controller14:
495
event = new MidiEvent(
496
curTrack->outPort(), curTrack->outChannel(),
497
x, MidiEvent::Ctrl14, ctrl.hnum(), nval, ctrl.lnum(), 0);
499
case MidiController::RPN:
500
event = new MidiEvent(
501
curTrack->outPort(), curTrack->outChannel(),
502
x, MidiEvent::RPN, ctrl.hnum()*128+ctrl.lnum(), nval, 0, 0);
504
case MidiController::NRPN:
505
event = new MidiEvent(
506
curTrack->outPort(), curTrack->outChannel(),
507
x, MidiEvent::RPN, ctrl.hnum()*128+ctrl.lnum(), nval, 0, 0);
509
case MidiController::XgSysex:
510
case MidiController::Sysex:
512
case MidiController::Pitch:
513
event = new MidiEvent(
514
curTrack->outPort(), curTrack->outChannel(),
515
x, MidiEvent::Pitch, nval, 0, 0, 0);
517
case MidiController::Velo:
521
midiThread->msgAddEvent(event, curPart, false);
526
song->endUndo(SC_EVENT_MODIFIED | SC_EVENT_INSERTED | SC_EVENT_REMOVED);
529
//---------------------------------------------------------
531
//---------------------------------------------------------
533
void CtrlCanvas::changeValRamp(int x1, int y1, int x2, int y2)
536
int min = ctrl.minVal();
537
int max = ctrl.maxVal();
538
bool changed = false;
541
for (ciCEvent i = items.begin(); i != items.end(); ++i) {
542
if ((*i)->contains(x1, x2)) {
544
MidiEvent* event = ev->event();
548
MidiPart* part = ev->part();
550
int x = event->posTick();
551
int y = (x2==x1) ? y1 : (((y2-y1)*(x-x1))/(x2-x1))+y1;
552
int nval = (((h - y) * (max-min)) / h) + min;
557
if (ctrl.type() == MidiController::Velo) {
558
if ((event->velo() != nval)) {
559
MidiEvent* newEvent = new MidiEvent(*event);
560
newEvent->setVelo(nval);
561
midiThread->msgChangeEvent(event, newEvent, part, false);
562
ev->setEvent(newEvent);
566
else if (ctrl.type() == MidiController::Controller7) {
568
if ((event->cntrlVal() != nval)) {
569
MidiEvent* newEvent = new MidiEvent(*event);
570
newEvent->setB(nval);
571
midiThread->msgChangeEvent(event, newEvent, part, false);
572
ev->setEvent(newEvent);
577
MidiPort* port = &midiPorts[curTrack->outPort()];
578
int channel = curTrack->outChannel();
579
int oval = port->iState(channel)->controller[ctrl.hnum()];
581
port->iState(channel)->controller[ctrl.hnum()] = nval;
590
song->endUndo(SC_EVENT_MODIFIED);
593
//---------------------------------------------------------
594
// viewMouseMoveEvent
595
//---------------------------------------------------------
597
void CtrlCanvas::viewMouseMoveEvent(QMouseEvent* event)
599
QPoint pos = event->pos();
600
QPoint dist = pos - start;
601
bool moving = dist.y() >= 3 || dist.y() <= 3 || dist.x() >= 3 || dist.x() <= 3;
603
case DRAG_LASSO_START:
607
// weiter mit DRAG_LASSO:
609
lasso.setRect(start.x(), start.y(), dist.x(), dist.y());
613
changeVal(start.x(), pos.x(), pos.y());
618
newVal(start.x(), pos.x(), pos.y());
623
deleteVal(start.x(), pos.x(), pos.y());
630
if (tool == DrawTool && drawLineMode) {
635
emit xposChanged(pos.x());
636
int min = ctrl.minVal();
637
int max = ctrl.maxVal();
638
int val = max - (pos.y() * (max-min) / height());
643
emit yposChanged(val);
646
//---------------------------------------------------------
647
// viewMouseReleaseEvent
648
//---------------------------------------------------------
650
void CtrlCanvas::viewMouseReleaseEvent(QMouseEvent* event)
652
bool shift = event->state() & ShiftButton;
658
song->endUndo(SC_EVENT_MODIFIED | SC_EVENT_INSERTED);
661
case DRAG_LASSO_START:
662
lasso.setRect(-1, -1, -1, -1);
667
lasso = lasso.normalize();
668
for (iCEvent i = items.begin(); i != items.end(); ++i) {
670
if ((*i)->intersects(lasso)) {
671
if (shift && (*i)->isSelected())
688
//---------------------------------------------------------
690
//---------------------------------------------------------
692
void CtrlCanvas::changeVal(int x1, int x2, int y)
695
int min = ctrl.minVal();
696
int max = ctrl.maxVal();
698
bool changed = false;
699
int nval = (((h - y) * (max-min)) / h) + min;
702
for (ciCEvent i = items.begin(); i != items.end(); ++i) {
703
if ((*i)->contains(x1, x2)) {
705
MidiEvent* event = ev->event();
706
MidiPart* part = ev->part();
708
if (ctrl.type() == MidiController::Velo) {
709
if ((event->velo() != nval)) {
710
MidiEvent* newEvent = new MidiEvent(*event);
711
newEvent->setVelo(nval);
712
midiThread->msgChangeEvent(event, newEvent, part, false);
713
ev->setEvent(newEvent);
717
else if (ctrl.type() == MidiController::Controller7) {
719
if ((event->cntrlVal() != nval)) {
720
MidiEvent* newEvent = new MidiEvent(*event);
721
newEvent->setB(nval);
722
midiThread->msgChangeEvent(event, newEvent, part, false);
723
ev->setEvent(newEvent);
728
MidiPort* port = &midiPorts[curTrack->outPort()];
729
int channel = curTrack->outChannel();
730
int oval = port->iState(channel)->controller[ctrl.hnum()];
732
port->iState(channel)->controller[ctrl.hnum()] = nval;
743
//---------------------------------------------------------
745
//---------------------------------------------------------
747
void CtrlCanvas::newVal(int x1, int x2, int y)
749
int xx1 = editor->rasterVal1(x1);
750
int xx2 = editor->rasterVal2(x2);
751
int min = ctrl.minVal();
752
int max = ctrl.maxVal();
755
int nval = (((h - y) * (max-min)) / h) + min;
760
bool song_changed = false;
761
for (ciCEvent i = items.begin(); i != items.end(); ++i) {
763
MidiEvent* event = ev->event();
766
int x = event->posTick();
775
switch(ctrl.type()) {
776
case MidiController::Controller7:
777
if ((event->cntrlVal() != nval)) {
778
MidiEvent* newEvent = new MidiEvent(*event);
779
newEvent->setB(nval);
780
midiThread->msgChangeEvent(event, newEvent, ev->part(), false);
781
ev->setEvent(newEvent);
785
case MidiController::Pitch:
787
//TODO: check for change
788
MidiEvent* newEvent = new MidiEvent(
789
curTrack->outPort(), curTrack->outChannel(),
790
xx1, MidiEvent::Pitch, nval, 0, 0, 0);
791
midiThread->msgChangeEvent(event, newEvent, ev->part(), false);
792
ev->setEvent(newEvent);
803
MidiEvent* event = ev->event();
805
midiThread->msgDeleteEvent(event, ev->part(), false);
812
MidiEvent* event = 0;
814
switch(ctrl.type()) {
815
case MidiController::Controller7:
816
event = new MidiEvent(
817
curTrack->outPort(), curTrack->outChannel(),
818
xx1, MidiEvent::Ctrl7, ctrl.hnum(), nval, 0, 0);
820
case MidiController::Controller14:
821
event = new MidiEvent(
822
curTrack->outPort(), curTrack->outChannel(),
823
xx1, MidiEvent::Ctrl14, ctrl.hnum(), nval, ctrl.lnum(), 0);
825
case MidiController::RPN:
826
event = new MidiEvent(
827
curTrack->outPort(), curTrack->outChannel(),
828
xx1, MidiEvent::RPN, ctrl.hnum()*128+ctrl.lnum(), nval, 0, 0);
830
case MidiController::NRPN:
831
event = new MidiEvent(
832
curTrack->outPort(), curTrack->outChannel(),
833
xx1, MidiEvent::RPN, ctrl.hnum()*128+ctrl.lnum(), nval, 0, 0);
835
case MidiController::XgSysex:
836
case MidiController::Sysex:
838
case MidiController::Pitch:
839
event = new MidiEvent(
840
curTrack->outPort(), curTrack->outChannel(),
841
xx1, MidiEvent::Pitch, nval, 0, 0, 0);
843
case MidiController::Velo:
847
midiThread->msgAddEvent(event, curPart, false);
858
//---------------------------------------------------------
860
//---------------------------------------------------------
862
void CtrlCanvas::deleteVal(int x1, int x2, int)
864
int xx1 = editor->rasterVal1(x1);
865
int xx2 = editor->rasterVal2(x2);
867
bool song_changed = false;
868
for (ciCEvent i = items.begin(); i != items.end(); ++i) {
870
MidiEvent* event = ev->event();
873
int x = event->posTick();
879
midiThread->msgDeleteEvent(event, ev->part(), false);
889
//---------------------------------------------------------
891
//---------------------------------------------------------
893
void CtrlCanvas::setTool(int t)
900
setCursor(QCursor(*pencilIcon, 4, 15));
903
drawLineMode = false;
906
setCursor(QCursor(arrowCursor));
911
//---------------------------------------------------------
913
//---------------------------------------------------------
915
void CtrlCanvas::pdraw(QPainter& p, const QRect& rect)
917
int x = rect.x() - 1; // compensate for 3 pixel line width
919
int w = rect.width() + 2;
920
int h = rect.height();
924
//---------------------------------------------------
926
//---------------------------------------------------
928
if (ctrl.type() == MidiController::Velo) {
930
for (iCEvent i = items.begin(); i != items.end(); ++i) {
932
int tick = mapx(e->event()->posTick());
937
int y1 = wh - (e->val() * wh / 128);
939
p.setPen(QPen(blue, 3));
940
p.drawLine(tick, wh, tick, y1);
944
int min = ctrl.minVal();
945
int max = ctrl.maxVal();
948
for (iCEvent i = items.begin(); i != items.end(); ++i) {
950
int tick = mapx(e->event() ? e->event()->posTick() : 0);
955
lval = wh - ((e->val() - min) * wh / (max - min));
961
p.fillRect(x1, 0, tick - x1, wh, gray);
963
p.fillRect(x1, lval, tick - x1, wh - lval, blue);
968
lval = wh - ((e->val() - min) * wh / (max - min));
971
p.fillRect(x1, 0, (x+w) - x1, wh, gray);
973
p.fillRect(x1, lval, (x+w) - x1, wh - lval, blue);
977
View::pdraw(p, rect);
980
//---------------------------------------------------
982
//---------------------------------------------------
984
int xp = mapx(pos[0]);
985
if (xp >= x && xp < x+w) {
987
p.drawLine(xp, y, xp, y+h);
990
if (xp >= x && xp < x+w) {
992
p.drawLine(xp, y, xp, y+h);
995
if (xp >= x && xp < x+w) {
997
p.drawLine(xp, y, xp, y+h);
1000
//---------------------------------------------------
1002
//---------------------------------------------------
1004
if (drag == DRAG_LASSO) {
1007
p.setBrush(NoBrush);
1010
// View::pdraw(p, rect);
1013
//---------------------------------------------------------
1015
//---------------------------------------------------------
1017
void CtrlCanvas::drawOverlay(QPainter& p)
1019
QString s(ctrl.name());
1020
//printf("draw overlay %s\n", ctrl.name().latin1());
1023
QFontMetrics fm(font3);
1024
int y = fm.lineSpacing() + 2;
1025
p.drawText(2, y, s);
1028
//---------------------------------------------------------
1030
// returns geometry of overlay rectangle
1031
//---------------------------------------------------------
1033
QRect CtrlCanvas::overlayRect() const
1035
QFontMetrics fm(font3);
1036
QRect r(fm.boundingRect(ctrl.name()));
1037
r.moveBy(2, 2); // top/left margin
1041
//---------------------------------------------------------
1043
//---------------------------------------------------------
1045
void CtrlCanvas::draw(QPainter& p, const QRect& rect)
1047
drawTickRaster(p, rect.x(), rect.y(),
1048
rect.width(), rect.height(), editor->quant());
1050
//---------------------------------------------------
1052
//---------------------------------------------------
1054
if (drawLineMode && (tool == DrawTool)) {
1056
p.drawLine(line1x, line1y, line2x, line2y);