diff options
Diffstat (limited to 'attic/muse2-oom/muse2/muse/midiedit/prcanvas.cpp')
-rw-r--r-- | attic/muse2-oom/muse2/muse/midiedit/prcanvas.cpp | 1864 |
1 files changed, 1864 insertions, 0 deletions
diff --git a/attic/muse2-oom/muse2/muse/midiedit/prcanvas.cpp b/attic/muse2-oom/muse2/muse/midiedit/prcanvas.cpp new file mode 100644 index 00000000..28d0d049 --- /dev/null +++ b/attic/muse2-oom/muse2/muse/midiedit/prcanvas.cpp @@ -0,0 +1,1864 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: prcanvas.cpp,v 1.20.2.19 2009/11/16 11:29:33 lunar_shuttle Exp $ +// (C) Copyright 1999-2004 Werner Schweer (ws@seh.de) +//========================================================= + +#include <QApplication> +#include <QClipboard> +#include <QPainter> +#include <QDrag> +#include <QDragLeaveEvent> +#include <QDragEnterEvent> +#include <QDragMoveEvent> +#include <QDropEvent> +#include <QMouseEvent> + +#include <values.h> +#include <stdio.h> +#include <math.h> +#include <errno.h> +//#include <sys/stat.h> +//#include <sys/types.h> +//#include <sys/mman.h> +//#include <fcntl.h> +//#include <dirent.h> + +#include "xml.h" +#include "prcanvas.h" +#include "midiport.h" +#include "event.h" +#include "mpevent.h" +#include "globals.h" +#include "cmd.h" +#include "gatetime.h" +#include "velocity.h" +#include "song.h" +#include "audio.h" + +//--------------------------------------------------------- +// NEvent +//--------------------------------------------------------- + +NEvent::NEvent(Event& e, Part* p, int y) : CItem(e, p) + { + y = y - KH/4; + unsigned tick = e.tick() + p->tick(); + setPos(QPoint(tick, y)); + setBBox(QRect(tick, y, e.lenTick(), KH/2)); + } + +//--------------------------------------------------------- +// addItem +//--------------------------------------------------------- + +void PianoCanvas::addItem(Part* part, Event& event) + { + if (signed(event.tick())<0) { + printf("ERROR: trying to add event before current part!\n"); + return; + } + + NEvent* ev = new NEvent(event, part, pitch2y(event.pitch())); + items.add(ev); + + int diff = event.endTick()-part->lenTick(); + if (diff > 0) {// too short part? extend it + //printf("addItem - this code should not be run!\n"); + //Part* newPart = part->clone(); + //newPart->setLenTick(newPart->lenTick()+diff); + //audio->msgChangePart(part, newPart,false); + //part = newPart; + part->setLenTick(part->lenTick()+diff); + } + } + +//--------------------------------------------------------- +// PianoCanvas +//--------------------------------------------------------- + +PianoCanvas::PianoCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy) + : EventCanvas(pr, parent, sx, sy) + { + colorMode = 0; + cmdRange = 0; // all Events + playedPitch = -1; + + songChanged(SC_TRACK_INSERTED); + connect(song, SIGNAL(midiNote(int, int)), SLOT(midiNote(int,int))); + } + +//--------------------------------------------------------- +// pitch2y +//--------------------------------------------------------- + +int PianoCanvas::pitch2y(int pitch) const + { + int tt[] = { + 5, 12, 19, 26, 33, 44, 51, 58, 64, 71, 78, 85 + }; + int y = (75 * KH) - (tt[pitch%12] + (7 * KH) * (pitch/12)); + if (y < 0) + y = 0; + return y; + } + +//--------------------------------------------------------- +// y2pitch +//--------------------------------------------------------- + +int PianoCanvas::y2pitch(int y) const + { + const int total = (10 * 7 + 5) * KH; // 75 Ganztonschritte + y = total - y; + int oct = (y / (7 * KH)) * 12; + char kt[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 1, 1, 1, 1, 1, 1, 1, // 13 + 2, 2, 2, 2, 2, 2, // 19 + 3, 3, 3, 3, 3, 3, 3, // 26 + 4, 4, 4, 4, 4, 4, 4, 4, 4, // 34 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 43 + 6, 6, 6, 6, 6, 6, 6, // 52 + 7, 7, 7, 7, 7, 7, // 58 + 8, 8, 8, 8, 8, 8, 8, // 65 + 9, 9, 9, 9, 9, 9, // 71 + 10, 10, 10, 10, 10, 10, 10, // 78 + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 // 87 + }; + return kt[y % 91] + oct; + } + +//--------------------------------------------------------- +// drawEvent +// draws a note +//--------------------------------------------------------- + +void PianoCanvas::drawItem(QPainter& p, const CItem* item, + const QRect& rect) +{ + QRect r = item->bbox(); + if(!virt()) + r.moveCenter(map(item->pos())); + r = r.intersected(rect); + if(!r.isValid()) + return; + p.setPen(Qt::black); + struct Triple + { + int r, g, b; + }; + + static Triple myColors /*Qt::color1*/[12] = + { // ddskrjp + { 0xff, 0x3d, 0x39 }, + { 0x39, 0xff, 0x39 }, + { 0x39, 0x3d, 0xff }, + { 0xff, 0xff, 0x39 }, + { 0xff, 0x3d, 0xff }, + { 0x39, 0xff, 0xff }, + { 0xff, 0x7e, 0x7a }, + { 0x7a, 0x7e, 0xff }, + { 0x7a, 0xff, 0x7a }, + { 0xff, 0x7e, 0xbf }, + { 0x7a, 0xbf, 0xff }, + { 0xff, 0xbf, 0x7a } + }; + + QPen mainPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + p.setPen(mainPen); + + QColor colMoving; + colMoving.setRgb(220, 220, 120, 127); + + QPen movingPen(Qt::darkGray, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + + QColor colSelected; + colSelected.setRgb(243, 206, 105, 127); + + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + if (nevent->part() != curPart) + { + if(item->isMoving()) + { + p.setPen(movingPen); + p.setBrush(colMoving); + } + else if(item->isSelected()) + { + p.setPen(mainPen); + p.setBrush(colSelected); + } + else + { + p.setPen(movingPen); + p.setBrush(QColor(192,192,192,127)); + } + } + else { + if (item->isMoving()) + { + p.setPen(movingPen); + p.setBrush(colMoving); + //p.setBrush(Qt::gray); + } + else if (item->isSelected()) + { + p.setPen(mainPen); + p.setBrush(colSelected); + } + else + { + QColor color; + //color.setRgb(80, 102, 143); + color.setRgb(13,124,151,127); + switch(colorMode) + { + case 0: + break; + case 1: // pitch + { + Triple* c = &myColors/*Qt::color1*/[event.pitch() % 12]; + color.setRgb(c->r, c->g, c->b, 127); + } + break; + case 2: // velocity + { + int velo = event.velo(); + /* + if (velo < 64) + color.setRgb(velo*4, 0, 0xff); + else + color.setRgb(0xff, 0, (127-velo) * 4); + */ + /* + if(velo <= 11) + color.setRgb(75,145,47); + else if(velo <= 22) + color.setRgb(56,145,79); + else if(velo <= 33) + color.setRgb(64,139,84); + else if(velo <= 44) + color.setRgb(60,137,99); + else if(velo <= 55) + color.setRgb(55,134,113); + else if(velo <= 66) + color.setRgb(51,132,127); + else if(velo <= 77) + color.setRgb(48,130,141); + else if(velo <= 88) + color.setRgb(57,121,144); + else if(velo <= 99) + color.setRgb(72,108,143); + else if(velo <= 110) + color.setRgb(86,96,142); + else if(velo <= 121) + color.setRgb(101,84,141); + else + color.setRgb(116,72,140); + */ + + if(velo <= 11) + color.setRgb(147,186,195,127); + else if(velo <= 22) + color.setRgb(119,169,181,127); + else if(velo <= 33) + color.setRgb(85,157,175,127); + else if(velo <= 44) + color.setRgb(58,152,176,127); + else if(velo <= 55) + color.setRgb(33,137,163,127); + else if(velo <= 66) + color.setRgb(30,136,162,127); + else if(velo <= 77) + color.setRgb(13,124,151,127); + else if(velo <= 88) + color.setRgb(0,110,138,127); + else if(velo <= 99) + color.setRgb(0,99,124,127); + else if(velo <= 110) + color.setRgb(0,77,96,127); + else if(velo <= 121) + color.setRgb(0,69,86,127); + else + color.setRgb(0,58,72,127); + + } + break; + } + p.setBrush(color); + } + } + p.drawRect(r); +} + + +//--------------------------------------------------------- +// drawMoving +// draws moving items +//--------------------------------------------------------- + +void PianoCanvas::drawMoving(QPainter& p, const CItem* item, const QRect& rect) + { + //if(((NEvent*)item)->part() != curPart) + // return; + //if(!item->isMoving()) + // return; + QRect mr = QRect(item->mp().x(), item->mp().y() - item->height()/2, item->width(), item->height()); + mr = mr.intersected(rect); + if(!mr.isValid()) + return; + p.setPen(Qt::black); + p.setBrush(Qt::NoBrush); + p.drawRect(mr); + } + +//--------------------------------------------------------- +// viewMouseDoubleClickEvent +//--------------------------------------------------------- + +void PianoCanvas::viewMouseDoubleClickEvent(QMouseEvent* event) + { + if ((_tool != PointerTool) && (event->button() != Qt::LeftButton)) { + mousePress(event); + return; + } + } + +//--------------------------------------------------------- +// moveCanvasItems +//--------------------------------------------------------- + +void PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtype, int* pflags) +{ + if(editor->parts()->empty()) + return; + + PartsToChangeMap parts2change; + + int modified = 0; + for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) + { + Part* part = ip->second; + if(!part) + continue; + + int npartoffset = 0; + for(iCItem ici = items.begin(); ici != items.end(); ++ici) + { + CItem* ci = ici->second; + if(ci->part() != part) + continue; + + int x = ci->pos().x() + dx; + int y = pitch2y(y2pitch(ci->pos().y()) + dp); + QPoint newpos = raster(QPoint(x, y)); + + // Test moving the item... + NEvent* nevent = (NEvent*) ci; + Event event = nevent->event(); + x = newpos.x(); + if(x < 0) + x = 0; + int ntick = editor->rasterVal(x) - part->tick(); + if(ntick < 0) + ntick = 0; + int diff = ntick + event.lenTick() - part->lenTick(); + + // If moving the item would require a new part size... + if(diff > npartoffset) + npartoffset = diff; + } + + if(npartoffset > 0) + { + // Create new part... + // if there are several events that are moved outside the part, it will be recreated for each + // so the part _in_ the event will not be valid, ask the authority. +// Part* newPart = part->clone(); + //Part* newPart = Canvas::part()->clone(); + +// newPart->setLenTick(newPart->lenTick() + npartoffset); + //audio->msgChangePart(part, newPart,false); + +// modified = SC_PART_MODIFIED; + + // BUG FIX: #1650953 + // Added by T356. + // Fixes posted "select and drag past end of part - crashing" bug +// for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) +// { +// if(ip->second == part) +// { +// editor->parts()->erase(ip); +// break; +// } +// } + +// editor->parts()->add(newPart); +// audio->msgChangePart(part, newPart,false); + + //if(parts2change.find(part) == parts2change.end()) + // parts2change.insert(std::pair<Part*, Part*> (part, newPart)); + iPartToChange ip2c = parts2change.find(part); + if(ip2c == parts2change.end()) + { + PartToChange p2c = {0, npartoffset}; + parts2change.insert(std::pair<Part*, PartToChange> (part, p2c)); + } + else + ip2c->second.xdiff = npartoffset; + + //part = newPart; // reassign + //item->setPart(part); + //item->setEvent(newEvent); + //curPart = part; + //curPartId = curPart->sn(); + + } + } + + for(iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c) + { + Part* opart = ip2c->first; + int diff = ip2c->second.xdiff; + + Part* newPart = opart->clone(); + + newPart->setLenTick(newPart->lenTick() + diff); + + modified = SC_PART_MODIFIED; + + // BUG FIX: #1650953 + // Added by T356. + // Fixes posted "select and drag past end of part - crashing" bug + for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) + { + if(ip->second == opart) + { + editor->parts()->erase(ip); + break; + } + } + + editor->parts()->add(newPart); + // Indicate no undo, and do port controller values but not clone parts. + audio->msgChangePart(opart, newPart, false, true, false); + + ip2c->second.npart = newPart; + + } + + iPartToChange icp = parts2change.find(curPart); + if(icp != parts2change.end()) + { + curPart = icp->second.npart; + curPartId = curPart->sn(); + } + + std::vector< CItem* > doneList; + typedef std::vector< CItem* >::iterator iDoneList; + + for(iCItem ici = items.begin(); ici != items.end(); ++ici) + { + CItem* ci = ici->second; + + // If this item's part is in the parts2change list, change the item's part to the new part. + Part* pt = ci->part(); + iPartToChange ip2c = parts2change.find(pt); + if(ip2c != parts2change.end()) + ci->setPart(ip2c->second.npart); + + int x = ci->pos().x(); + int y = ci->pos().y(); + int nx = x + dx; + int ny = pitch2y(y2pitch(y) + dp); + QPoint newpos = raster(QPoint(nx, ny)); + selectItem(ci, true); + + iDoneList idl; + for(idl = doneList.begin(); idl != doneList.end(); ++idl) + // This compares EventBase pointers to see if they're the same... + if((*idl)->event() == ci->event()) + break; + + // Do not process if the event has already been processed (meaning it's an event in a clone part)... + //if(moveItem(ci, newpos, dtype)) + if(idl != doneList.end()) + // Just move the canvas item. + ci->move(newpos); + else + { + // Currently moveItem always returns true. + if(moveItem(ci, newpos, dtype)) + { + // Add the canvas item to the list of done items. + doneList.push_back(ci); + // Move the canvas item. + ci->move(newpos); + } + } + + if(moving.size() == 1) + itemReleased(curItem, newpos); + if(dtype == MOVE_COPY || dtype == MOVE_CLONE) + selectItem(ci, false); + } + + if(pflags) + *pflags = modified; +} + +//--------------------------------------------------------- +// moveItem +// called after moving an object +//--------------------------------------------------------- + +// Changed by T356. +//bool PianoCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype, int* pflags) +bool PianoCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) + { + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + int npitch = y2pitch(pos.y()); + Event newEvent = event.clone(); + int x = pos.x(); + if (x < 0) + x = 0; + if (event.pitch() != npitch && _playEvents) { + int port = track()->outPort(); + int channel = track()->outChannel(); + // release note: + MidiPlayEvent ev1(0, port, channel, 0x90, event.pitch() + track()->transposition, 0); + audio->msgPlayMidiEvent(&ev1); + MidiPlayEvent ev2(0, port, channel, 0x90, npitch + track()->transposition, event.velo()); + audio->msgPlayMidiEvent(&ev2); + } + + // Changed by T356. + Part* part = nevent->part(); // + //Part * part = Canvas::part(); // part can be dynamically recreated, ask the authority + + newEvent.setPitch(npitch); + int ntick = editor->rasterVal(x) - part->tick(); + if (ntick < 0) + ntick = 0; + newEvent.setTick(ntick); + newEvent.setLenTick(event.lenTick()); + + // Removed by T356. + /* + int modified=0; + //song->startUndo(); + int diff = newEvent.endTick()-part->lenTick(); + if (diff > 0){// too short part? extend it + // if there are several events that are moved outside the part, it will be recreated for each + // so the part _in_ the event will not be valid, ask the authority. + //Part* newPart = part->clone(); + Part* newPart = Canvas::part()->clone(); + + newPart->setLenTick(newPart->lenTick()+diff); + audio->msgChangePart(Canvas::part(), newPart,false); + + modified = SC_PART_MODIFIED; + part = newPart; // reassign + + // BUG FIX: #1650953 + // Added by T356. + // Fixes posted "select and drag past end of part - crashing" bug + for(iPart i = editor->parts()->begin(); i != editor->parts()->end(); ++i) + { + if(i->second == Canvas::part()) + { + editor->parts()->erase(i); + break; + } + } + editor->parts()->add(part); + item->setPart(part); + item->setEvent(newEvent); + curPart = part; + curPartId = curPart->sn(); + + } + */ + + // Added by T356. + // msgAddEvent and msgChangeEvent (below) will set these, but set them here first? + //item->setPart(part); + item->setEvent(newEvent); + + // Added by T356. + if(((int)newEvent.endTick() - (int)part->lenTick()) > 0) + printf("PianoCanvas::moveItem Error! New event end:%d exceeds length:%d of part:%s\n", newEvent.endTick(), part->lenTick(), part->name().toLatin1().constData()); + + if (dtype == MOVE_COPY || dtype == MOVE_CLONE) + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(newEvent, part, false); + audio->msgAddEvent(newEvent, part, false, false, false); + else + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, part, false); + audio->msgChangeEvent(event, newEvent, part, false, false, false); + //song->endUndo(modified); + + // Removed by T356. + //if(pflags) + // *pflags = modified; + + return true; + } + +//--------------------------------------------------------- +// newItem(p, state) +//--------------------------------------------------------- + +CItem* PianoCanvas::newItem(const QPoint& p, int) + { + //printf("newItem point\n"); + int pitch = y2pitch(p.y()); + int tick = editor->rasterVal1(p.x()); + int len = p.x() - tick; + tick -= curPart->tick(); + if (tick < 0) + tick=0; + Event e = Event(Note); + e.setTick(tick); + e.setPitch(pitch); + e.setVelo(curVelo); + e.setLenTick(len); + return new NEvent(e, curPart, pitch2y(pitch)); + } + +void PianoCanvas::newItem(CItem* item, bool noSnap) + { + //printf("newItem citem\n"); + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + int x = item->x(); + if (x<0) + x=0; + int w = item->width(); + + if (!noSnap) { + x = editor->rasterVal1(x); //round down + w = editor->rasterVal(x + w) - x; + if (w == 0) + w = editor->raster(); + } + Part* part = nevent->part(); + event.setTick(x - part->tick()); + event.setLenTick(w); + event.setPitch(y2pitch(item->y())); + + song->startUndo(); + int modified=SC_EVENT_MODIFIED; + int diff = event.endTick()-part->lenTick(); + if (diff > 0) {// too short part? extend it + //printf("extend Part!\n"); + Part* newPart = part->clone(); + newPart->setLenTick(newPart->lenTick()+diff); + // Indicate no undo, and do port controller values but not clone parts. + //audio->msgChangePart(part, newPart,false); + audio->msgChangePart(part, newPart, false, true, false); + modified=modified|SC_PART_MODIFIED; + part = newPart; // reassign + } + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(event, part,false); + audio->msgAddEvent(event, part, false, false, false); + song->endUndo(modified); + } + +//--------------------------------------------------------- +// resizeItem +//--------------------------------------------------------- + +void PianoCanvas::resizeItem(CItem* item, bool noSnap) // experimental changes to try dynamically extending parts + { + //printf("resizeItem!\n"); + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + Event newEvent = event.clone(); + int len; + + Part* part = nevent->part(); + + if (noSnap) + len = nevent->width(); + else { + //Part* part = nevent->part(); + unsigned tick = event.tick() + part->tick(); + len = editor->rasterVal(tick + nevent->width()) - tick; + if (len <= 0) + len = editor->raster(); + } + song->startUndo(); + int modified=SC_EVENT_MODIFIED; + //printf("event.tick()=%d len=%d part->lenTick()=%d\n",event.endTick(),len,part->lenTick()); + int diff = event.tick()+len-part->lenTick(); + if (diff > 0) {// too short part? extend it + //printf("extend Part!\n"); + Part* newPart = part->clone(); + newPart->setLenTick(newPart->lenTick()+diff); + // Indicate no undo, and do port controller values but not clone parts. + //audio->msgChangePart(part, newPart,false); + audio->msgChangePart(part, newPart, false, true, false); + modified=modified|SC_PART_MODIFIED; + part = newPart; // reassign + } + + newEvent.setLenTick(len); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, nevent->part(),false); + audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false); + song->endUndo(modified); + } + +//--------------------------------------------------------- +// deleteItem +//--------------------------------------------------------- + +bool PianoCanvas::deleteItem(CItem* item) + { + NEvent* nevent = (NEvent*) item; + if (nevent->part() == curPart) { + Event ev = nevent->event(); + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, curPart); + audio->msgDeleteEvent(ev, curPart, true, false, false); + return true; + } + return false; + } + +//--------------------------------------------------------- +// pianoCmd +//--------------------------------------------------------- + +void PianoCanvas::pianoCmd(int cmd) + { + switch(cmd) { + case CMD_LEFT: + { + int spos = pos[0]; + if(spos > 0) + { + spos -= 1; // Nudge by -1, then snap down with raster1. + spos = AL::sigmap.raster1(spos, editor->rasterStep(pos[0])); + } + if(spos < 0) + spos = 0; + Pos p(spos,true); + song->setPos(0, p, true, true, true); + } + break; + case CMD_RIGHT: + { + int spos = AL::sigmap.raster2(pos[0] + 1, editor->rasterStep(pos[0])); // Nudge by +1, then snap up with raster2. + Pos p(spos,true); + song->setPos(0, p, true, true, true); + } + break; + case CMD_LEFT_NOSNAP: + { + int spos = pos[0] - editor->rasterStep(pos[0]); + if (spos < 0) + spos = 0; + Pos p(spos,true); + song->setPos(0, p, true, true, true); //CDW + } + break; + case CMD_RIGHT_NOSNAP: + { + Pos p(pos[0] + editor->rasterStep(pos[0]), true); + //if (p > part->tick()) + // p = part->tick(); + song->setPos(0, p, true, true, true); //CDW + } + break; + case CMD_INSERT: + { + if (pos[0] < start() || pos[0] >= end()) + break; + MidiPart* part = (MidiPart*)curPart; + + if (part == 0) + break; + song->startUndo(); + EventList* el = part->events(); + + std::list <Event> elist; + for (iEvent e = el->lower_bound(pos[0] - part->tick()); e != el->end(); ++e) + elist.push_back((Event)e->second); + for (std::list<Event>::iterator i = elist.begin(); i != elist.end(); ++i) { + Event event = *i; + Event newEvent = event.clone(); + newEvent.setTick(event.tick() + editor->raster());// - part->tick()); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, part, false); + audio->msgChangeEvent(event, newEvent, part, false, false, false); + } + song->endUndo(SC_EVENT_MODIFIED); + Pos p(editor->rasterVal(pos[0] + editor->rasterStep(pos[0])), true); + song->setPos(0, p, true, false, true); + } + return; + case CMD_DELETE: + if (pos[0] < start() || pos[0] >= end()) + break; + { + MidiPart* part = (MidiPart*)curPart; + if (part == 0) + break; + song->startUndo(); + EventList* el = part->events(); + + std::list<Event> elist; + for (iEvent e = el->lower_bound(pos[0]); e != el->end(); ++e) + elist.push_back((Event)e->second); + for (std::list<Event>::iterator i = elist.begin(); i != elist.end(); ++i) { + Event event = *i; + Event newEvent = event.clone(); + newEvent.setTick(event.tick() - editor->raster() - part->tick()); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, part, false); + audio->msgChangeEvent(event, newEvent, part, false, false, false); + } + song->endUndo(SC_EVENT_MODIFIED); + Pos p(editor->rasterVal(pos[0] - editor->rasterStep(pos[0])), true); + song->setPos(0, p, true, false, true); + } + break; + } + } + +//--------------------------------------------------------- +// pianoPressed +//--------------------------------------------------------- + +void PianoCanvas::pianoPressed(int pitch, int velocity, bool shift) + { + int port = track()->outPort(); + int channel = track()->outChannel(); + pitch += track()->transposition; + + // play note: + //MidiPlayEvent e(0, port, channel, 0x90, pitch, 127); + MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); + audio->msgPlayMidiEvent(&e); + + if (_steprec && pos[0] >= start_tick && pos[0] < end_tick) { + if (curPart == 0) + return; + int len = editor->raster(); + unsigned tick = pos[0] - curPart->tick(); //CDW + if (shift) + tick -= editor->rasterStep(tick); + Event e(Note); + e.setTick(tick); + e.setPitch(pitch); + e.setVelo(127); + e.setLenTick(len); + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(e, curPart); + audio->msgAddEvent(e, curPart, true, false, false); + tick += editor->rasterStep(tick) + curPart->tick(); + if (tick != song->cpos()) { + Pos p(tick, true); + song->setPos(0, p, true, false, true); + } + } + } + +//--------------------------------------------------------- +// pianoReleased +//--------------------------------------------------------- + +void PianoCanvas::pianoReleased(int pitch, bool) + { + int port = track()->outPort(); + int channel = track()->outChannel(); + pitch += track()->transposition; + + // release key: + MidiPlayEvent e(0, port, channel, 0x90, pitch, 0); + audio->msgPlayMidiEvent(&e); + } + +//--------------------------------------------------------- +// drawTickRaster +//--------------------------------------------------------- + +void drawTickRaster(QPainter& p, int x, int y, int w, int h, int raster) +{ + + QColor colBeat; + colBeat.setRgb(210, 216, 219); + QColor colBar1; + colBar1.setRgb(82,85,87); + QColor colBar2; + colBar2.setRgb(150,160,167); + + + int bar1, bar2, beat; + unsigned tick; + AL::sigmap.tickValues(x, &bar1, &beat, &tick); + AL::sigmap.tickValues(x+w, &bar2, &beat, &tick); + ++bar2; + int y2 = y + h; + for (int bar = bar1; bar < bar2; ++bar) { + unsigned x = AL::sigmap.bar2tick(bar, 0, 0); + p.setPen(colBar1); + p.drawLine(x, y, x, y2); + int z, n; + AL::sigmap.timesig(x, z, n); + ///int q = p.xForm(QPoint(raster, 0)).x() - p.xForm(QPoint(0, 0)).x(); + int q = p.combinedTransform().map(QPoint(raster, 0)).x() - p.combinedTransform().map(QPoint(0, 0)).x(); + int qq = raster; + if (q < 8) // grid too dense + qq *= 2; + //switch (quant) { + // case 32: + // case 48: + // case 64: + // case 96: + // case 192: // 8tel + // case 128: // 8tel Triolen + // case 288: + p.setPen(colBeat); + if (raster>=4) + { + int xx = x + qq; + int xxx = AL::sigmap.bar2tick(bar, z, 0); + while (xx <= xxx) { + p.drawLine(xx, y, xx, y2); + xx += qq; + } + xx = xxx; + } + // break; + // default: + // break; + // } + p.setPen(colBar2); + for (int beat = 1; beat < z; beat++) + { + int xx = AL::sigmap.bar2tick(bar, beat, 0); + p.drawLine(xx, y, xx, y2); + } + + } +} + +//--------------------------------------------------------- +// draw +//--------------------------------------------------------- + +void PianoCanvas::drawCanvas(QPainter& p, const QRect& rect) + { + int x = rect.x(); + int y = rect.y(); + int w = rect.width(); + int h = rect.height(); + + //--------------------------------------------------- + // horizontal lines + //--------------------------------------------------- + + int yy = ((y-1) / KH) * KH + KH; + int key = 75 - (yy / KH); + for (; yy < y + h; yy += KH) + { + switch (key % 7) + { + case 0: + case 3: + p.setPen(QColor(213,220,213)); + p.drawLine(x, yy, x + w, yy); + break; + default: + //p.setPen(lightGray); + //p.fillRect(x, yy-3, w, 6, QBrush(QColor(230,230,230))); + p.fillRect(x, yy-3, w, 6, QBrush(QColor(209,213,209))); + //p.drawLine(x, yy, x + w, yy); + break; + } + --key; + } + + //--------------------------------------------------- + // vertical lines + //--------------------------------------------------- + + drawTickRaster(p, x, y, w, h, editor->raster()); +} + +//--------------------------------------------------------- +// cmd +// pulldown menu commands +//--------------------------------------------------------- + +void PianoCanvas::cmd(int cmd, int quantStrength, + int quantLimit, bool quantLen, int range) + { + cmdRange = range; + printf("PianoCanvas cmd called with command: %d\n\n", cmd); + switch (cmd) { + case CMD_CUT: + copy(); + song->startUndo(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!(i->second->isSelected())) + continue; + NEvent* e = (NEvent*)(i->second); + Event ev = e->event(); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, e->part(), false); + audio->msgDeleteEvent(ev, e->part(), false, false, false); + } + song->endUndo(SC_EVENT_REMOVED); + break; + case CMD_COPY: + copy(); + break; + case CMD_PASTE: + paste(); + break; + case CMD_DEL: + if (selectionSize()) { + song->startUndo(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!i->second->isSelected()) + continue; + Event ev = i->second->event(); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, i->second->part(), false); + audio->msgDeleteEvent(ev, i->second->part(), false, false, false); + } + song->endUndo(SC_EVENT_REMOVED); + } + return; + case CMD_OVER_QUANTIZE: // over quantize + quantize(100, 1, quantLen); + break; + case CMD_ON_QUANTIZE: // note on quantize + quantize(50, 1, false); + break; + case CMD_ONOFF_QUANTIZE: // note on/off quantize + quantize(50, 1, true); + break; + case CMD_ITERATIVE_QUANTIZE: // Iterative Quantize + quantize(quantStrength, quantLimit, quantLen); + break; + case CMD_SELECT_ALL: // select all + for (iCItem k = items.begin(); k != items.end(); ++k) { + if (!k->second->isSelected()) + selectItem(k->second, true); + } + break; + case CMD_SELECT_NONE: // select none + deselectAll(); + break; + case CMD_SELECT_INVERT: // invert selection + for (iCItem k = items.begin(); k != items.end(); ++k) { + selectItem(k->second, !k->second->isSelected()); + } + break; + case CMD_SELECT_ILOOP: // select inside loop + for (iCItem k = items.begin(); k != items.end(); ++k) { + NEvent* nevent = (NEvent*)(k->second); + Part* part = nevent->part(); + Event event = nevent->event(); + unsigned tick = event.tick() + part->tick(); + if (tick < song->lpos() || tick >= song->rpos()) + selectItem(k->second, false); + else + selectItem(k->second, true); + } + break; + case CMD_SELECT_OLOOP: // select outside loop + for (iCItem k = items.begin(); k != items.end(); ++k) { + NEvent* nevent = (NEvent*)(k->second); + Part* part = nevent->part(); + Event event = nevent->event(); + unsigned tick = event.tick() + part->tick(); + if (tick < song->lpos() || tick >= song->rpos()) + selectItem(k->second, true); + else + selectItem(k->second, false); + } + break; + case CMD_SELECT_PREV_PART: // select previous part + { + Part* pt = editor->curCanvasPart(); + Part* newpt = pt; + PartList* pl = editor->parts(); + for(iPart ip = pl->begin(); ip != pl->end(); ++ip) + if(ip->second == pt) + { + if(ip == pl->begin()) + ip = pl->end(); + --ip; + newpt = ip->second; + break; + } + if(newpt != pt) + editor->setCurCanvasPart(newpt); + } + break; + case CMD_SELECT_NEXT_PART: // select next part + { + Part* pt = editor->curCanvasPart(); + Part* newpt = pt; + PartList* pl = editor->parts(); + for(iPart ip = pl->begin(); ip != pl->end(); ++ip) + if(ip->second == pt) + { + ++ip; + if(ip == pl->end()) + ip = pl->begin(); + newpt = ip->second; + break; + } + if(newpt != pt) + editor->setCurCanvasPart(newpt); + } + break; + case CMD_MODIFY_GATE_TIME: + { + GateTime w(this); + w.setRange(range); + if (!w.exec()) + break; + int range = w.range(); // all, selected, looped, sel+loop + int rate = w.rateVal(); + int offset = w.offsetVal(); + + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + NEvent* nevent =(NEvent*)(k->second); + Event event = nevent->event(); + if (event.type() != Note) + continue; + unsigned tick = event.tick(); + bool selected = k->second->isSelected(); + bool inLoop = (tick >= song->lpos()) && (tick < song->rpos()); + + if ((range == 0) + || (range == 1 && selected) + || (range == 2 && inLoop) + || (range == 3 && selected && inLoop)) { + unsigned int len = event.lenTick(); //prevent compiler warning: comparison singed/unsigned + + len = rate ? (len * 100) / rate : 1; + len += offset; + if (len < 1) + len = 1; + + if (event.lenTick() != len) { + Event newEvent = event.clone(); + newEvent.setLenTick(len); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, nevent->part(), false); + audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false); + } + } + } + song->endUndo(SC_EVENT_MODIFIED); + } + break; + + case CMD_MODIFY_VELOCITY: + { + Velocity w; + w.setRange(range); + if (!w.exec()) + break; + int range = w.range(); // all, selected, looped, sel+loop + int rate = w.rateVal(); + int offset = w.offsetVal(); + + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + NEvent* nevent = (NEvent*)(k->second); + Event event = nevent->event(); + if (event.type() != Note) + continue; + unsigned tick = event.tick(); + bool selected = k->second->isSelected(); + bool inLoop = (tick >= song->lpos()) && (tick < song->rpos()); + + if ((range == 0) + || (range == 1 && selected) + || (range == 2 && inLoop) + || (range == 3 && selected && inLoop)) { + int velo = event.velo(); + + //velo = rate ? (velo * 100) / rate : 64; + velo = (velo * rate) / 100; + velo += offset; + + if (velo <= 0) + velo = 1; + if (velo > 127) + velo = 127; + if (event.velo() != velo) { + Event newEvent = event.clone(); + newEvent.setVelo(velo); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, nevent->part(), false); + audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false); + } + } + } + song->endUndo(SC_EVENT_MODIFIED); + } + break; + + case CMD_FIXED_LEN: //Set notes to the length specified in the drummap + if (!selectionSize()) + break; + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + if (k->second->isSelected()) { + NEvent* nevent = (NEvent*)(k->second); + Event event = nevent->event(); + Event newEvent = event.clone(); + newEvent.setLenTick(editor->raster()); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, nevent->part() , false); + audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false); + } + } + song->endUndo(SC_EVENT_MODIFIED); + break; + + case CMD_DELETE_OVERLAPS: + if (!selectionSize()) + break; + + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); k++) { + if (k->second->isSelected() == false) + continue; + + NEvent* e1 = (NEvent*) (k->second); // first note + NEvent* e2 = NULL; // ptr to next selected note (which will be checked for overlap) + Event ce1 = e1->event(); + Event ce2; + + if (ce1.type() != Note) + continue; + + // Find next selected item on the same pitch + iCItem l = k; l++; + for (; l != items.end(); l++) { + if (l->second->isSelected() == false) + continue; + + e2 = (NEvent*) l->second; + ce2 = e2->event(); + + // Same pitch? + if (ce1.dataA() == ce2.dataA()) + break; + + // If the note has the same len and place we treat it as a duplicate note and not a following note + // The best thing to do would probably be to delete the duplicate note, we just want to avoid + // matching against the same note + if ( ce1.tick() + e1->part()->tick() == ce2.tick() + e2->part()->tick() + && ce1.lenTick() + e1->part()->tick() == ce2.lenTick() + e2->part()->tick()) + { + e2 = NULL; // this wasn't what we were looking for + continue; + } + + } + + if (e2 == NULL) // None found + break; + + Part* part1 = e1->part(); + Part* part2 = e2->part(); + if (ce2.type() != Note) + continue; + + + unsigned event1pos = ce1.tick() + part1->tick(); + unsigned event1end = event1pos + ce1.lenTick(); + unsigned event2pos = ce2.tick() + part2->tick(); + + //printf("event1pos %u event1end %u event2pos %u\n", event1pos, event1end, event2pos); + if (event1end > event2pos) { + Event newEvent = ce1.clone(); + unsigned newlen = ce1.lenTick() - (event1end - event2pos); + //printf("newlen: %u\n", newlen); + newEvent.setLenTick(newlen); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(ce1, newEvent, e1->part(), false); + audio->msgChangeEvent(ce1, newEvent, e1->part(), false, false, false); + } + } + song->endUndo(SC_EVENT_MODIFIED); + break; + + + case CMD_CRESCENDO: + case CMD_TRANSPOSE: + case CMD_THIN_OUT: + case CMD_ERASE_EVENT: + case CMD_NOTE_SHIFT: + case CMD_MOVE_CLOCK: + case CMD_COPY_MEASURE: + case CMD_ERASE_MEASURE: + case CMD_DELETE_MEASURE: + case CMD_CREATE_MEASURE: + break; + default: +// printf("unknown ecanvas cmd %d\n", cmd); + break; + } + updateSelection(); + redraw(); + } + +//--------------------------------------------------------- +// quantize +//--------------------------------------------------------- + +void PianoCanvas::quantize(int strength, int limit, bool quantLen) + { + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + NEvent* nevent = (NEvent*)(k->second); + Event event = nevent->event(); + Part* part = nevent->part(); + if (event.type() != Note) + continue; + + if ((cmdRange & CMD_RANGE_SELECTED) && !k->second->isSelected()) + continue; + + unsigned tick = event.tick() + part->tick(); + + if ((cmdRange & CMD_RANGE_LOOP) + && ((tick < song->lpos() || tick >= song->rpos()))) + continue; + + unsigned int len = event.lenTick(); //prevent compiler warning: comparison singed/unsigned + int tick2 = tick + len; + + // quant start position + int diff = AL::sigmap.raster(tick, editor->quant()) - tick; + if (abs(diff) > limit) + tick += ((diff * strength) / 100); + + // quant len + diff = AL::sigmap.raster(tick2, editor->quant()) - tick2; + if (quantLen && (abs(diff) > limit)) + len += ((diff * strength) / 100); + + // something changed? + if (((event.tick() + part->tick()) != tick) || (event.lenTick() != len)) { + Event newEvent = event.clone(); + newEvent.setTick(tick - part->tick()); + newEvent.setLenTick(len); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, part, false); + audio->msgChangeEvent(event, newEvent, part, false, false, false); + } + } + song->endUndo(SC_EVENT_MODIFIED); + } + +//--------------------------------------------------------- +// midiNote +//--------------------------------------------------------- + +void PianoCanvas::midiNote(int pitch, int velo) + { + if (_midiin && _steprec && curPart + && !audio->isPlaying() && velo && pos[0] >= start_tick + && pos[0] < end_tick + && !(globalKeyState & Qt::AltModifier)) { + unsigned int len = editor->quant();//prevent compiler warning: comparison singed/unsigned + unsigned tick = pos[0]; //CDW + unsigned starttick = tick; + if (globalKeyState & Qt::ShiftModifier) + tick -= editor->rasterStep(tick); + + // + // extend len of last note? + // + EventList* events = curPart->events(); + if (globalKeyState & Qt::ControlModifier) { + for (iEvent i = events->begin(); i != events->end(); ++i) { + Event ev = i->second; + if (!ev.isNote()) + continue; + if (ev.pitch() == pitch && ((ev.tick() + ev.lenTick()) == /*(int)*/starttick)) { + Event e = ev.clone(); + e.setLenTick(ev.lenTick() + editor->rasterStep(starttick)); + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(ev, e, curPart); + audio->msgChangeEvent(ev, e, curPart, true, false, false); + tick += editor->rasterStep(tick); + if (tick != song->cpos()) { + Pos p(tick, true); + song->setPos(0, p, true, false, true); + } + return; + } + } + } + + // + // if we already entered the note, delete it + // + EventRange range = events->equal_range(tick); + for (iEvent i = range.first; i != range.second; ++i) { + Event ev = i->second; + if (ev.isNote() && ev.pitch() == pitch) { + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, curPart); + audio->msgDeleteEvent(ev, curPart, true, false, false); + if (globalKeyState & Qt::ShiftModifier) + tick += editor->rasterStep(tick); + return; + } + } + Event e(Note); + e.setTick(tick - curPart->tick()); + e.setPitch(pitch); + e.setVelo(velo); + e.setLenTick(len); + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(e, curPart); + audio->msgAddEvent(e, curPart, true, false, false); + tick += editor->rasterStep(tick); + if (tick != song->cpos()) { + Pos p(tick, true); + song->setPos(0, p, true, false, true); + } + } + } + +/* +//--------------------------------------------------------- +// getTextDrag +//--------------------------------------------------------- + +Q3TextDrag* PianoCanvas::getTextDrag(QWidget* parent) + { + //--------------------------------------------------- + // generate event list from selected events + //--------------------------------------------------- + + EventList el; + unsigned startTick = MAXINT; + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!i->second->isSelected()) + continue; + NEvent* ne = (NEvent*)(i->second); + Event e = ne->event(); + if (startTick == MAXINT) + startTick = e.tick(); + el.add(e); + } + + //--------------------------------------------------- + // write events as XML into tmp file + //--------------------------------------------------- + + FILE* tmp = tmpfile(); + if (tmp == 0) { + fprintf(stderr, "PianoCanvas::copy() fopen failed: %s\n", + strerror(errno)); + return 0; + } + Xml xml(tmp); + + int level = 0; + xml.tag(level++, "eventlist"); + for (ciEvent e = el.begin(); e != el.end(); ++e) + e->second.write(level, xml, -startTick); + xml.etag(--level, "eventlist"); + + //--------------------------------------------------- + // read tmp file into QTextDrag Object + //--------------------------------------------------- + + fflush(tmp); + struct stat f_stat; + if (fstat(fileno(tmp), &f_stat) == -1) { + fprintf(stderr, "PianoCanvas::copy() fstat failes:<%s>\n", + strerror(errno)); + fclose(tmp); + return 0; + } + int n = f_stat.st_size; + char* fbuf = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE, + MAP_PRIVATE, fileno(tmp), 0); + fbuf[n] = 0; + Q3TextDrag* drag = new Q3TextDrag(QString(fbuf), parent); + drag->setSubtype("eventlist"); + munmap(fbuf, n); + fclose(tmp); + return drag; + } +*/ + +//--------------------------------------------------------- +// copy +// cut copy paste +//--------------------------------------------------------- + +void PianoCanvas::copy() + { + //QDrag* drag = getTextDrag(); + QMimeData* drag = getTextDrag(); + + if (drag) + QApplication::clipboard()->setMimeData(drag, QClipboard::Clipboard); + } + +/* +//--------------------------------------------------------- +// pasteAt +//--------------------------------------------------------- + +void PianoCanvas::pasteAt(const QString& pt, int pos) + { + QByteArray ba = pt.toLatin1(); + const char* p = ba.constData(); + Xml xml(p); + for (;;) { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) { + case Xml::Error: + case Xml::End: + return; + case Xml::TagStart: + if (tag == "eventlist") { + song->startUndo(); + EventList* el = new EventList(); + el->read(xml, "eventlist", true); + int modified = SC_EVENT_INSERTED; + for (iEvent i = el->begin(); i != el->end(); ++i) { + Event e = i->second; + int tick = e.tick() + pos - curPart->tick(); + if (tick<0) { + printf("ERROR: trying to add event before current part!\n"); + song->endUndo(SC_EVENT_INSERTED); + delete el; + return; + } + + e.setTick(tick); + int diff = e.endTick()-curPart->lenTick(); + if (diff > 0) {// too short part? extend it + Part* newPart = curPart->clone(); + newPart->setLenTick(newPart->lenTick()+diff); + // Indicate no undo, and do port controller values but not clone parts. + audio->msgChangePart(curPart, newPart, false, true, false); + modified=modified|SC_PART_MODIFIED; + curPart = newPart; // reassign + } + // Indicate no undo, and do not do port controller values and clone parts. + audio->msgAddEvent(e, curPart, false, false, false); + } + song->endUndo(modified); + delete el; + return; + } + else + xml.unknown("pasteAt"); + break; + case Xml::Attribut: + case Xml::TagEnd: + default: + break; + } + } + } +*/ + +//--------------------------------------------------------- +// paste +// paste events +//--------------------------------------------------------- + +void PianoCanvas::paste() + { +/* + //Q3CString subtype("eventlist"); ddskrjo + QString subtype("eventlist"); + QMimeSource* ms = QApplication::clipboard()->data(QClipboard::Clipboard); + QString pt; + if (!Q3TextDrag::decode(ms, pt, subtype)) { + printf("cannot paste: bad data type\n"); + return; + } + pasteAt(pt, song->cpos()); +*/ + QString stype("x-muse-eventlist"); + + //QString s = QApplication::clipboard()->text(stype, QClipboard::Selection); + QString s = QApplication::clipboard()->text(stype, QClipboard::Clipboard); // TODO CHECK Tim. + + pasteAt(s, song->cpos()); + } + +//--------------------------------------------------------- +// startDrag +//--------------------------------------------------------- + +void PianoCanvas::startDrag(CItem* /* item*/, bool copymode) + { + QMimeData* md = getTextDrag(); + //QDrag* drag = getTextDrag(); + + if (md) { +// QApplication::clipboard()->setData(drag, QClipboard::Clipboard); // This line NOT enabled in muse-1 + //QApplication::clipboard()->setMimeData(md); // TODO CHECK Tim. + //QApplication::clipboard()->setMimeData(drag->mimeData()); // + + // "Note that setMimeData() assigns ownership of the QMimeData object to the QDrag object. + // The QDrag must be constructed on the heap with a parent QWidget to ensure that Qt can + // clean up after the drag and drop operation has been completed. " + QDrag* drag = new QDrag(this); + drag->setMimeData(md); + + if (copymode) + drag->exec(Qt::CopyAction); + else + drag->exec(Qt::MoveAction); + } + } + +//--------------------------------------------------------- +// dragEnterEvent +//--------------------------------------------------------- + +void PianoCanvas::dragEnterEvent(QDragEnterEvent* event) + { + ///event->accept(Q3TextDrag::canDecode(event)); + event->acceptProposedAction(); // TODO CHECK Tim. + } + +//--------------------------------------------------------- +// dragMoveEvent +//--------------------------------------------------------- + +void PianoCanvas::dragMoveEvent(QDragMoveEvent*) + { + //printf("drag move %x\n", this); + //event->acceptProposedAction(); + } + +//--------------------------------------------------------- +// dragLeaveEvent +//--------------------------------------------------------- + +void PianoCanvas::dragLeaveEvent(QDragLeaveEvent*) + { + //printf("drag leave\n"); + //event->acceptProposedAction(); + } + +/* +//--------------------------------------------------------- +// dropEvent +//--------------------------------------------------------- + +void PianoCanvas::viewDropEvent(QDropEvent* event) + { + QString text; + if (event->source() == this) { + printf("local DROP\n"); // REMOVE Tim + //event->acceptProposedAction(); + //event->ignore(); // TODO CHECK Tim. + return; + } + ///if (Q3TextDrag::decode(event, text)) { + //if (event->mimeData()->hasText()) { + if (event->mimeData()->hasFormat("text/x-muse-eventlist")) { + + //text = event->mimeData()->text(); + text = QString(event->mimeData()->data("text/x-muse-eventlist")); + + int x = editor->rasterVal(event->pos().x()); + if (x < 0) + x = 0; + pasteAt(text, x); + //event->accept(); // TODO + } + else { + printf("cannot decode drop\n"); + //event->acceptProposedAction(); + //event->ignore(); // TODO CHECK Tim. + } + } +*/ + +//--------------------------------------------------------- +// itemPressed +//--------------------------------------------------------- + +void PianoCanvas::itemPressed(const CItem* item) + { + if (!_playEvents) + return; + + int port = track()->outPort(); + int channel = track()->outChannel(); + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + playedPitch = event.pitch() + track()->transposition; + int velo = event.velo(); + + // play note: + MidiPlayEvent e(0, port, channel, 0x90, playedPitch, velo); + audio->msgPlayMidiEvent(&e); + } + +//--------------------------------------------------------- +// itemReleased +//--------------------------------------------------------- + +void PianoCanvas::itemReleased(const CItem*, const QPoint&) + { + if (!_playEvents) + return; + int port = track()->outPort(); + int channel = track()->outChannel(); + + // release note: + MidiPlayEvent ev(0, port, channel, 0x90, playedPitch, 0); + audio->msgPlayMidiEvent(&ev); + playedPitch = -1; + } + +//--------------------------------------------------------- +// itemMoved +//--------------------------------------------------------- + +void PianoCanvas::itemMoved(const CItem* item, const QPoint& pos) + { + int npitch = y2pitch(pos.y()); + if ((playedPitch != -1) && (playedPitch != npitch)) { + int port = track()->outPort(); + int channel = track()->outChannel(); + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + + // release note: + MidiPlayEvent ev1(0, port, channel, 0x90, playedPitch, 0); + audio->msgPlayMidiEvent(&ev1); + // play note: + MidiPlayEvent e2(0, port, channel, 0x90, npitch + track()->transposition, event.velo()); + audio->msgPlayMidiEvent(&e2); + playedPitch = npitch + track()->transposition; + } + } + +//--------------------------------------------------------- +// curPartChanged +//--------------------------------------------------------- + +void PianoCanvas::curPartChanged() + { + editor->setWindowTitle(getCaption()); + } + +//--------------------------------------------------------- +// modifySelected +//--------------------------------------------------------- + +void PianoCanvas::modifySelected(NoteInfo::ValType type, int delta) + { + audio->msgIdle(true); + song->startUndo(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!(i->second->isSelected())) + continue; + NEvent* e = (NEvent*)(i->second); + Event event = e->event(); + if (event.type() != Note) + continue; + + MidiPart* part = (MidiPart*)(e->part()); + Event newEvent = event.clone(); + + switch (type) { + case NoteInfo::VAL_TIME: + { + int newTime = event.tick() + delta; + if (newTime < 0) + newTime = 0; + newEvent.setTick(newTime); + } + break; + case NoteInfo::VAL_LEN: + { + int len = event.lenTick() + delta; + if (len < 1) + len = 1; + newEvent.setLenTick(len); + } + break; + case NoteInfo::VAL_VELON: + { + int velo = event.velo() + delta; + if (velo > 127) + velo = 127; + else if (velo < 0) + velo = 0; + newEvent.setVelo(velo); + } + break; + case NoteInfo::VAL_VELOFF: + { + int velo = event.veloOff() + delta; + if (velo > 127) + velo = 127; + else if (velo < 0) + velo = 0; + newEvent.setVeloOff(velo); + } + break; + case NoteInfo::VAL_PITCH: + { + int pitch = event.pitch() + delta; + if (pitch > 127) + pitch = 127; + else if (pitch < 0) + pitch = 0; + newEvent.setPitch(pitch); + } + break; + } + song->changeEvent(event, newEvent, part); + // Indicate do not do port controller values and clone parts. + //song->undoOp(UndoOp::ModifyEvent, newEvent, event, part); + song->undoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false); + } + song->endUndo(SC_EVENT_MODIFIED); + audio->msgIdle(false); + } + +//--------------------------------------------------------- +// resizeEvent +//--------------------------------------------------------- + +void PianoCanvas::resizeEvent(QResizeEvent* ev) + { + if (ev->size().width() != ev->oldSize().width()) + emit newWidth(ev->size().width()); + EventCanvas::resizeEvent(ev); + } + |