diff options
| author | Robert Jonsson <spamatica@gmail.com> | 2009-12-27 11:30:35 +0000 |
|---|---|---|
| committer | Robert Jonsson <spamatica@gmail.com> | 2009-12-27 11:30:35 +0000 |
| commit | b703eab295330e6f81564fbb39a10a1a2fdd2f54 (patch) | |
| tree | e46b5c9a6bc22fd661c15d1d2123f5bf631cef80 /muse_qt4_evolution/muse/midiedit | |
| parent | 5d5fa0fdf913907edbc3d2d29a7548f0cb658c94 (diff) | |
moved old qt4 branch
Diffstat (limited to 'muse_qt4_evolution/muse/midiedit')
34 files changed, 7970 insertions, 0 deletions
diff --git a/muse_qt4_evolution/muse/midiedit/CMakeLists.txt b/muse_qt4_evolution/muse/midiedit/CMakeLists.txt new file mode 100644 index 00000000..a71aed71 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/CMakeLists.txt @@ -0,0 +1,71 @@ +#============================================================================= +# MusE +# Linux Music Editor +# $Id:$ +# +# Copyright (C) 2002-2006 by Werner Schweer and others +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +#============================================================================= + +QT4_WRAP_CPP ( midiedit_mocs + midicmd.h + gatetime.h + velocity.h + quantconfig.h + dcanvas.h + drumedit.h + ecanvas.h + midieditor.h + pianoroll.h + prcanvas.h + miditracker.h + trackpattern.h + ) + +QT4_WRAP_UI ( midiedit_ui_headers + midicmd.ui + gatetime.ui + velocity.ui + quantconfig.ui + ) + +add_library ( midiedit STATIC + midicmd.h + gatetime.h + ${midiedit_ui_headers} + ${midiedit_mocs} + midicmd.cpp + gatetime.cpp + velocity.cpp + quantconfig.cpp + citem.h + cmd.h + drummap.h + midicmd.h + citem.cpp + dcanvas.cpp + drumedit.cpp + drummap.cpp + ecanvas.cpp + midieditor.cpp + pianoroll.cpp + prcanvas.cpp + miditracker.cpp + trackpattern.cpp + ) + +set_target_properties( midiedit + PROPERTIES COMPILE_FLAGS "-include ${PROJECT_BINARY_DIR}/all.h" + ) + diff --git a/muse_qt4_evolution/muse/midiedit/citem.cpp b/muse_qt4_evolution/muse/midiedit/citem.cpp new file mode 100644 index 00000000..b7ae8287 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/citem.cpp @@ -0,0 +1,82 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "part.h" +#include "citem.h" + +//--------------------------------------------------------- +// CItem +//--------------------------------------------------------- + +CItem::CItem() + { + isMoving = false; + } + +CItem::CItem(const Event& e, Part* p) + { + event = e; + part = p; + isMoving = false; + pos = e.pos() + *p; + } + +//--------------------------------------------------------- +// isSelected +//--------------------------------------------------------- + +bool CItem::isSelected() const + { + return event.empty() ? part->selected() : event.selected(); + } + +//--------------------------------------------------------- +// setSelected +//--------------------------------------------------------- + +void CItem::setSelected(bool f) + { + event.empty() ? part->setSelected(f) : event.setSelected(f); + } + +//--------------------------------------------------------- +// CItemList +//--------------------------------------------------------- + +CItem* CItemList::find(const QPoint& pos) const + { + for (rciCItem i = rbegin(); i != rend(); ++i) { + if (i->second->contains(pos)) + return i->second; + } + return 0; + } + +//--------------------------------------------------------- +// CItemList +//--------------------------------------------------------- + +void CItemList::add(CItem* item) + { + std::multimap<int, CItem*, std::less<int> >::insert( + std::pair<const unsigned int, CItem*> (item->pos.tick(), item) + ); + } + diff --git a/muse_qt4_evolution/muse/midiedit/citem.h b/muse_qt4_evolution/muse/midiedit/citem.h new file mode 100644 index 00000000..5b3452ac --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/citem.h @@ -0,0 +1,70 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __CITEM_H__ +#define __CITEM_H__ + +#include "al/pos.h" +#include "event.h" + +class Part; + +//--------------------------------------------------------- +// CItem +// Canvas Item +//--------------------------------------------------------- + +struct CItem { + Event event; + Part* part; + + bool isMoving; + AL::Pos moving; + int my; + + QRect bbox; + AL::Pos pos; + + CItem(); + CItem(const Event& e, Part* p); + + bool isSelected() const; + void setSelected(bool f); + bool contains(const QPoint& p) const { return bbox.contains(p); } + bool intersects(const QRect& r) const { return r.intersects(bbox); } + }; + +typedef std::multimap<int, CItem*, std::less<int> >::iterator iCItem; +typedef std::multimap<int, CItem*, std::less<int> >::const_iterator ciCItem; +typedef std::multimap<int, CItem*, std::less<int> >::const_reverse_iterator rciCItem; + +//--------------------------------------------------------- +// CItemList +// Canvas Item List +//--------------------------------------------------------- + +class CItemList: public std::multimap<int, CItem*, std::less<int> > { + public: + void add(CItem*); + CItem* find(const QPoint& pos) const; + }; + +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/cmd.h b/muse_qt4_evolution/muse/midiedit/cmd.h new file mode 100644 index 00000000..7f51abdd --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/cmd.h @@ -0,0 +1,32 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __CMD_H__ +#define __CMD_H__ + +enum { + MCMD_LEFT, + MCMD_RIGHT, + MCMD_INSERT, + MCMD_DELETE, + }; + +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/dcanvas.cpp b/muse_qt4_evolution/muse/midiedit/dcanvas.cpp new file mode 100644 index 00000000..20d8170d --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/dcanvas.cpp @@ -0,0 +1,723 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "dcanvas.h" +#include "song.h" +#include "midieditor.h" +#include "drummap.h" +#include "audio.h" +#include "velocity.h" +#include "gconfig.h" +#include "part.h" + +#define CARET 12 +#define CARET2 6 + +//--------------------------------------------------------- +// drumMap +//--------------------------------------------------------- + +DrumMap* DrumCanvas::drumMap() const + { + DrumMap* drumMap = track()->drumMap(); + if (drumMap == 0) + drumMap = &noDrumMap; + return drumMap; + } + +//--------------------------------------------------------- +// y2pitch +//--------------------------------------------------------- + +int DrumCanvas::y2pitch(int y) const + { + return drumMap()->anote(EventCanvas::y2pitch(y)); + } + +//--------------------------------------------------------- +// pitch2y +//--------------------------------------------------------- + +int DrumCanvas::pitch2y(int pitch) const + { + return EventCanvas::pitch2y(drumMap()->outmap(pitch)); + } + +//--------------------------------------------------------- +// DrumCanvas +//--------------------------------------------------------- + +DrumCanvas::DrumCanvas(MidiEditor* pr) + : EventCanvas(pr, TIME_CANVAS_DRUMEDIT) + { + singlePitch = -1; + verticalScrollBar()->setSingleStep(drumHeight/2); + canvasTools = PointerTool | PencilTool | RubberTool; + songChanged(SC_TRACK_INSERTED); + connect(track(), SIGNAL(drumMapChanged()), widget(), SLOT(update())); + } + +//--------------------------------------------------------- +// addItem +//--------------------------------------------------------- + +void DrumCanvas::addItem(Part* part, const Event& event) + { + CItem* item = new CItem(event, part); + unsigned tick = event.tick() + part->tick(); + item->pos = Pos(tick); + items.add(item); + } + +//--------------------------------------------------------- +// paint +//--------------------------------------------------------- + +void DrumCanvas::paint(QPainter& p, QRect r) + { + p.setPen(QPen(Qt::black, 0.0)); + + QPainterPath pa; + pa.moveTo(-CARET2, 0); + pa.lineTo(0, - CARET2); + pa.lineTo(CARET2, 0); + pa.lineTo(0, CARET2); + pa.closeSubpath(); + + Pos p1(pix2pos(r.x() - CARET2)); + Pos p2(pix2pos(r.x() + r.width() + CARET2)); + iCItem from(items.lower_bound(p1.tick())); + iCItem to(items.upper_bound(p2.tick())); + + for (iCItem i = from; i != to; ++i) { + CItem* e = i->second; + int x = pos2pix(AL::Pos(i->first)); + int y = pitch2y(e->event.pitch()) + drumHeight/2; + QPoint pt(x, y); + Event me(e->event); + + DrumMapEntry* dm = drumMap()->entry(me.pitch()); //Get the drum item + QColor color; + int velo = me.velo(); + if (velo < dm->lv1) + color.setRgb(240, 240, 255); + else if (velo < dm->lv2) + color.setRgb(200, 200, 255); + else if (velo < dm->lv3) + color.setRgb(170, 170, 255); + else + color.setRgb(0, 0, 255); + + if (e->part != curPart) + p.setBrush(Qt::lightGray); + else if (e->isMoving) { + p.setBrush(Qt::gray); + p.translate(pt); + p.drawPath(pa); + p.translate(-pt); + p.setBrush(Qt::black); + + int x = pos2pix(e->moving); + int y = e->my + drumHeight/2; + pt = QPoint(x, y); + } + else if (e->isSelected()) + p.setBrush(Qt::black); + else + p.setBrush(color); + p.translate(pt); + p.drawPath(pa); + p.translate(-pt); + } + + //--------------------------------------------------- + // draw lasso + //--------------------------------------------------- + + if (drag == DRAG_LASSO) { + p.setPen(Qt::blue); + p.setBrush(Qt::NoBrush); + p.drawRect(lasso); + } + } + +//--------------------------------------------------------- +// moveItem +//--------------------------------------------------------- + +void DrumCanvas::moveItem(CItem* nevent, DragType dtype) + { + Part* part = nevent->part; + Event event = nevent->event; + int npitch = y2pitch(nevent->my); + + Event newEvent = event.clone(); + newEvent.setPitch(npitch); + newEvent.setPos(nevent->moving - *(nevent->part)); + if (dtype == MOVE_COPY) + audio->msgAddEvent(newEvent, part, false); + else + audio->msgChangeEvent(event, newEvent, part, false); + } + +//--------------------------------------------------------- +// newItem +//--------------------------------------------------------- + +CItem* DrumCanvas::newItem(const QPoint& p, int state) + { + AL::Pos pos(pix2pos(p.x())); + pos.snap(raster()); + if (pos < partPos1 || pos >= partPos2) { + return 0; + } + + int pitch = y2pitch(p.y()); + int instr = drumMap()->outmap(pitch); + DrumMapEntry* dm = drumMap()->entry(instr); + int velo = dm->lv4; + if (state == Qt::ShiftModifier) + velo = dm->lv3; + else if (state == Qt::ControlModifier) + velo = dm->lv2; + else if (state == (Qt::ControlModifier | Qt::ShiftModifier)) + velo = dm->lv1; + + Event e(Note); + e.setPos(pos - *curPart); + e.setPitch(drumMap()->anote(instr)); + e.setVelo(velo); + e.setLenTick(dm->len); + return new CItem(e, curPart); + } + +//--------------------------------------------------------- +// resizeItem +//--------------------------------------------------------- + +void DrumCanvas::resizeItem(CItem* nevent, bool) + { + Event ev = nevent->event; + audio->msgDeleteEvent(ev, nevent->part); + } + +//--------------------------------------------------------- +// newItem +//--------------------------------------------------------- + +void DrumCanvas::newItem(CItem* nevent, bool noSnap) + { + Event event = nevent->event; + Pos pos(nevent->pos); + if (!noSnap) + pos.snap(editor->raster()); + event.setPos(pos - *(nevent->part)); + int npitch = event.pitch(); + event.setPitch(npitch); + + // + // check for existing event + // if found change command semantic from insert to delete + // + EventList* el = nevent->part->events(); + iEvent lower = el->lower_bound(event.tick()); + iEvent upper = el->upper_bound(event.tick()); + + for (iEvent i = lower; i != upper; ++i) { + Event ev = i->second; + if (ev.pitch() == npitch) { + audio->msgDeleteEvent(ev, nevent->part); + return; + } + } + + audio->msgAddEvent(event, nevent->part); + } + +//--------------------------------------------------------- +// deleteItem +//--------------------------------------------------------- + +bool DrumCanvas::deleteItem(CItem* item) + { + Event ev = item->event; + audio->msgDeleteEvent(ev, item->part); + return false; + } + +//--------------------------------------------------------- +// cmd +//--------------------------------------------------------- + +void DrumCanvas::cmd(QAction* a) + { + QString cmd(a->data().toString()); + + if (cmd == "paste") + paste(); + else if (cmd == "sel_all") { + for (iCItem k = items.begin(); k != items.end(); ++k) { + if (!k->second->isSelected()) + selectItem(k->second, true); + } + } + else if (cmd == "sel_none") + deselectAll(); + else if (cmd == "sel_inv") { + for (iCItem k = items.begin(); k != items.end(); ++k) + selectItem(k->second, !k->second->isSelected()); + } + else if (cmd == "sel_ins_loc") { + for (iCItem k = items.begin(); k != items.end(); ++k) { + CItem* 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); + } + } + else if (cmd == "sel_out_loc") { + for (iCItem k = items.begin(); k != items.end(); ++k) { + CItem* 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); + } + } + else if (cmd == "delete") { + if (selectionSize()) { + song->startUndo(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!i->second->isSelected()) + continue; + Event ev = i->second->event; + audio->msgDeleteEvent(ev, i->second->part, false); + } + song->endUndo(SC_EVENT_REMOVED); + } + return; + } + else if (cmd == "midi_fixed_len") { + if (selectionSize()) { + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + if (k->second->isSelected()) { + CItem* devent = k->second; + Event event = devent->event; + Event newEvent = event.clone(); + newEvent.setLenTick(drumMap()->entry(event.pitch())->len); + audio->msgChangeEvent(event, newEvent, devent->part, false); + } + } + song->endUndo(SC_EVENT_MODIFIED); + } + } + else if (cmd == "goto_left") { + int frames = pos[0].tick() - editor->rasterStep(pos[0].tick()); + if (frames < 0) + frames = 0; + Pos p(frames, AL::TICKS); + song->setPos(0, p, true, true, true); + } + else if (cmd == "goto_right") { + Pos p(pos[0].tick() + editor->rasterStep(pos[0].tick()), AL::TICKS); + song->setPos(0, p, true, true, true); + } + else if (cmd == "mid_mod_velo") { + Velocity w(this); + w.setRange(editor->applyTo()); + if (w.exec()) { + editor->setApplyTo(w.range()); + int rate = w.rateVal(); + int offset = w.offsetVal(); + + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + CItem* devent = k->second; + Event event = devent->event; + if (event.type() != Note) + continue; + unsigned tick = event.tick(); + bool selected = devent->isSelected(); + bool inLoop = (tick >= song->lpos()) && (tick < song->rpos()); + + int range = editor->applyTo(); + if ((range == RANGE_ALL) + || (range == RANGE_SELECTED && selected) + || (range == RANGE_LOOPED && inLoop) + || (range == (RANGE_LOOPED | RANGE_SELECTED) && 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); + audio->msgChangeEvent(event, newEvent, devent->part, false); + } + } + } + song->endUndo(SC_EVENT_MODIFIED); + } + } + widget()->update(); + } + +//--------------------------------------------------------- +// paste +// paste events +//--------------------------------------------------------- + +void DrumCanvas::paste() + { + QString stype("x-muse-eventlist"); + QString s = QApplication::clipboard()->text(stype, QClipboard::Selection); + pasteAt(s, song->cpos()); + } + +//--------------------------------------------------------- +// startDrag +//--------------------------------------------------------- + +void DrumCanvas::startDrag(CItem* /* item*/, bool /*copymode*/) + { +printf("DrumCanvas: startDrag\n"); +#if 0 //TD + QMimeData* drag = getTextDrag(); + if (drag) { + QApplication::clipboard()->setMimeData(drag, QClipboard::Selection); + if (copymode) + drag->dragCopy(); + else + drag->dragMove(); + } +#endif + } + +//--------------------------------------------------------- +// dragEnterEvent +//--------------------------------------------------------- + +void DrumCanvas::dragEnterEvent(QDragEnterEvent* /*event*/) + { +printf("DrumCanvas: dragEnterEvent\n"); +//TD event->accept(Q3TextDrag::canDecode(event)); + } + +//--------------------------------------------------------- +// dragMoveEvent +//--------------------------------------------------------- + +void DrumCanvas::dragMoveEvent(QDragMoveEvent*) + { + printf("drag move %p\n", this); + } + +//--------------------------------------------------------- +// dragLeaveEvent +//--------------------------------------------------------- + +void DrumCanvas::dragLeaveEvent(QDragLeaveEvent*) + { + printf("drag leave\n"); + } + +//--------------------------------------------------------- +// dropEvent +//--------------------------------------------------------- + +void DrumCanvas::viewDropEvent(QDropEvent* /*event*/) + { +printf("DrumCanvas: viewDropEvent\n"); +#if 0 //TD + QString text; + if (event->source() == this) { + printf("local DROP\n"); + return; + } + if (Q3TextDrag::decode(event, text)) { +// printf("drop <%s>\n", text.ascii()); + int x = editor->rasterVal(event->pos().x()); + if (x < 0) + x = 0; + pasteAt(text, x); + } +#endif + } + +//--------------------------------------------------------- +// keyPressed +//--------------------------------------------------------- + +void DrumCanvas::keyPressed(int index, bool) + { + int pitch = drumMap()->entry(index)->anote; + + // play note: + MidiEvent e(0, 0, 0x90, pitch, 127); + track()->playMidiEvent(&e); + } + +//--------------------------------------------------------- +// keyReleased +//--------------------------------------------------------- + +void DrumCanvas::keyReleased(int index, bool) + { + int pitch = drumMap()->entry(index)->anote; + + // release note: + MidiEvent e(0, 0, 0x90, pitch, 0); + track()->playMidiEvent(&e); + } + +//--------------------------------------------------------- +// resizeEvent +//--------------------------------------------------------- + +void DrumCanvas::resizeEvent(QResizeEvent* ev) + { + if (ev->size().width() != ev->oldSize().width()) + emit newWidth(ev->size().width()); + EventCanvas::resizeEvent(ev); + } + + +//--------------------------------------------------------- +// modifySelected +//--------------------------------------------------------- + +void DrumCanvas::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; + CItem* e = i->second; + Event event = e->event; + if (event.type() != Note) + continue; + + Part* part = 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); + } + */ + printf("DrumCanvas::modifySelected - NoteInfo::VAL_LEN not implemented\n"); + break; + case NoteInfo::VAL_VELON: + /* + { + int velo = event->velo() + delta; + if (velo > 127) + velo = 127; + else if (velo < 0) + velo = 0; + newEvent.setVelo(velo); + } + */ + printf("DrumCanvas::modifySelected - NoteInfo::VAL_VELON not implemented\n"); + break; + case NoteInfo::VAL_VELOFF: + /* + { + int velo = event.veloOff() + delta; + if (velo > 127) + velo = 127; + else if (velo < 0) + velo = 0; + newEvent.setVeloOff(velo); + } + */ + printf("DrumCanvas::modifySelected - NoteInfo::VAL_VELOFF not implemented\n"); + break; + case NoteInfo::VAL_PITCH: + { + int pitch = event.pitch() - delta; // Reversing order since the drumlist is displayed in increasing order + if (pitch > 127) + pitch = 127; + else if (pitch < 0) + pitch = 0; + newEvent.setPitch(pitch); + } + break; + } + song->changeEvent(event, newEvent, part); + song->undoOp(UndoOp::ModifyEvent, newEvent, event, part); + } + song->endUndo(SC_EVENT_MODIFIED); + audio->msgIdle(false); + } + +//--------------------------------------------------------- +// paintDrumList +//--------------------------------------------------------- + +void DrumCanvas::paintDrumList(QPainter& p, QRect r) + { + p.fillRect(r, QColor(0xe0, 0xe0, 0xe0)); + paintVLine(p, 0, rPanelB.y(), rPanelA.x() + rPanelA.width()); +// p.setFont(config.fonts[1]); + + int yoff = wpos.y() - rPanelA.y(); + int i = (r.y() + yoff) / drumHeight; + if (i < 0) + i = 0; + if (i > 127) + return; + int y = i * drumHeight - yoff; + DrumMap* dm = drumMap(); + + for (; i < 128; ++i, y += drumHeight) { + if (y > r.y() + r.height()) + break; + QRect r(3, y, drumWidth-4, drumHeight); + if (dm->anote(i) == curPitch || dm->anote(i) == singlePitch) + p.fillRect(0, y, drumWidth-4, drumHeight, Qt::white); + DrumMapEntry* de = dm->entry(i); + if (de->mute) { + p.setPen(Qt::red); + p.drawText(r, Qt::AlignVCenter | Qt::AlignLeft, "m"); + p.setPen(Qt::darkGray); + p.drawText(r.adjusted(16, 0, 0, 0), Qt::AlignVCenter | Qt::AlignLeft, de->name); + } + else { + p.setPen(Qt::black); + p.drawText(r, Qt::AlignVCenter | Qt::AlignLeft, "m"); + p.drawText(r.adjusted(16, 0, 0, 0), Qt::AlignVCenter | Qt::AlignLeft, de->name); + } + if (i != 0) + p.drawLine(0, y, drumWidth-3, y); + } + p.setPen(QPen(Qt::darkGray, 1)); + p.drawLine(17, r.y(), 17, r.y() + r.height()); + } + +//--------------------------------------------------------- +// searchItem +//--------------------------------------------------------- + +CItem* DrumCanvas::searchItem(const QPoint& p) const + { + Pos p1(pix2pos(p.x() - CARET2)); + Pos p2(pix2pos(p.x() + CARET2)); + + ciCItem from(items.lower_bound(p1.tick())); + ciCItem to(items.upper_bound(p2.tick())); + + int pitch = y2pitch(p.y()); + for (ciCItem i = from; i != to; ++i) { + if (pitch == i->second->event.pitch()) + return i->second; + } + return 0; + } + +//--------------------------------------------------------- +// selectLasso +//--------------------------------------------------------- + +void DrumCanvas::selectLasso(bool toggle) + { + Pos p1(pix2pos(lasso.x())); + Pos p2(pix2pos(lasso.x() + lasso.width())); + + iCItem from(items.lower_bound(p1.tick())); + iCItem to(items.upper_bound(p2.tick())); + int y = lasso.y(); + int pitch1 = y2pitch(y); + int pitch2 = y2pitch(y + lasso.height()); + + int n = 0; + for (iCItem i = from; i != to; ++i) { + CItem* item = i->second; + int pitch = item->event.pitch(); + if (pitch >= pitch1 && pitch <= pitch2) { + selectItem(item, !(toggle && item->isSelected())); + ++n; + } + } + if (n) { + updateSelection(); + widget()->update(); + } + } + +//--------------------------------------------------------- +// mousePress +//--------------------------------------------------------- + +void DrumCanvas::mousePress(QMouseEvent* ev) + { + QPoint r(ev->pos()); + int pitch = y2pitch(r.y() - rPanelA.y() - wpos.y()); + if (r.x() < 20) { + // + // "mute" button click + // + DrumMap* dm = drumMap(); + int idx = dm->outmap(pitch); + DrumMapEntry* de = dm->entry(idx); + de->mute = !de->mute; + widget()->update(rPanelA); + return; + } + else if (r.x() < rCanvasA.x()) { + if (pitch != singlePitch) { + singlePitch = pitch; + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) + (*i)->setSinglePitch(singlePitch); + widget()->update(); + } + } + EventCanvas::mousePress(ev); + } + + diff --git a/muse_qt4_evolution/muse/midiedit/dcanvas.h b/muse_qt4_evolution/muse/midiedit/dcanvas.h new file mode 100644 index 00000000..9d4ab754 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/dcanvas.h @@ -0,0 +1,77 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __DCANVAS_H__ +#define __DCANVAS_H__ + +#include "ecanvas.h" + +class MidiEditor; +class DrumMap; + +//--------------------------------------------------------- +// DrumCanvas +//--------------------------------------------------------- + +class DrumCanvas : public EventCanvas { + Q_OBJECT + + int singlePitch; + virtual void mousePress(QMouseEvent*); + virtual void paint(QPainter&, QRect); + virtual void addItem(Part* part, const Event& event); + virtual void moveItem(CItem*, DragType); + virtual CItem* newItem(const QPoint&, int); + virtual void resizeItem(CItem*, bool); + virtual void newItem(CItem*, bool); + virtual bool deleteItem(CItem*); + virtual CItem* searchItem(const QPoint& p) const; + + void copy(); + void paste(); + void startDrag(CItem*, bool copymode); + void dragEnterEvent(QDragEnterEvent* event); + void dragMoveEvent(QDragMoveEvent*); + void dragLeaveEvent(QDragLeaveEvent*); + void viewDropEvent(QDropEvent* event); + virtual void resizeEvent(QResizeEvent*); + virtual void paintDrumList(QPainter&, QRect); + virtual void selectLasso(bool toggle); + + DrumMap* drumMap() const; + + protected: + virtual int y2pitch(int y) const; + virtual int pitch2y(int pitch) const; + + signals: + void newWidth(int); + + public slots: + void keyPressed(int, bool); + void keyReleased(int, bool); + + public: + DrumCanvas(MidiEditor*); + void cmd(QAction*); + virtual void modifySelected(NoteInfo::ValType type, int delta); + }; +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/drumedit.cpp b/muse_qt4_evolution/muse/midiedit/drumedit.cpp new file mode 100644 index 00000000..a21a56a0 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/drumedit.cpp @@ -0,0 +1,450 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "drumedit.h" +#include "icons.h" +#include "drummap.h" +#include "audio.h" +#include "shortcuts.h" +#include "part.h" +#include "muse.h" +#include "song.h" + +static const int drumeditTools = PointerTool | PencilTool | RubberTool | DrawTool; + +int DrumEdit::initWidth = DrumEdit::INIT_WIDTH; +int DrumEdit::initHeight = DrumEdit::INIT_HEIGHT; +int DrumEdit::initRaster = DrumEdit::INIT_RASTER; +int DrumEdit::initQuant = DrumEdit::INIT_QUANT; +bool DrumEdit::initFollow = DrumEdit::INIT_FOLLOW; +bool DrumEdit::initSpeaker = DrumEdit::INIT_SPEAKER; +bool DrumEdit::initMidiin = DrumEdit::INIT_MIDIIN; +double DrumEdit::initXmag = 0.08; // DrumEdit::INIT_XMAG; +int DrumEdit::initApplyTo = DrumEdit::INIT_APPLY_TO; + +//--------------------------------------------------------- +// DrumEdit +//--------------------------------------------------------- + +DrumEdit::DrumEdit(PartList* pl, bool init) + : MidiEditor(pl) + { + _applyTo = initApplyTo; + + deltaMode = false; + drumMap = &noDrumMap; + + //---------Pulldown Menu---------------------------- + QMenuBar* mb = menuBar(); + + menuEdit->addSeparator(); + menuEdit->addAction(getAction("delete", this)); + + // Functions + menuFunctions = mb->addMenu(tr("&Functions")); + menuFunctions->addAction(getAction("midi_fixed_len", this)); + menuFunctions->addAction(getAction("midi_mod_velo", this)); + + menuSelect = menuEdit->addMenu(tr("&Select")); + menuSelect->setIcon(QIcon(*selectIcon)); + + menuSelect->addAction(getAction("sel_all", this)); + menuSelect->addAction(getAction("sel_none", this)); + menuSelect->addAction(getAction("sel_inv", this)); + menuSelect->addSeparator(); + menuSelect->addAction(getAction("sel_ins_loc", this)); + menuSelect->addAction(getAction("sel_out_loc", this)); + + connect(menuSelect, SIGNAL(triggered(QAction*)), SLOT(cmd(QAction*))); + connect(menuFunctions, SIGNAL(triggered(QAction*)), SLOT(cmd(QAction*))); + + //--------------------------------------------------- + // Toolbars + //--------------------------------------------------- + + tools = addToolBar(tr("Drum Tools")); + tools->addAction(undoAction); + tools->addAction(redoAction); + tools->addSeparator(); + + tools->addAction(stepRecAction); + stepRecAction->setChecked(INIT_SREC); + + tools->addAction(midiInAction); + midiInAction->setChecked(INIT_MIDIIN); + + tools->addAction(speaker); + speaker->setChecked(INIT_SPEAKER); + + tools->addAction(followSongAction); + followSongAction->setChecked(INIT_FOLLOW); + + tools2 = new EditToolBar(this, drumeditTools); + addToolBar(tools2); + + QToolBar* transport = addToolBar(tr("Transport")); + muse->setupTransportToolbar(transport); + + addToolBarBreak(); + toolbar = new Toolbar1(initRaster, initQuant, false); + addToolBar(toolbar); + addToolBarBreak(); + info = new NoteInfo(this); + addToolBar(info); + + tcanvas = new DrumCanvas(this); + setCentralWidget(tcanvas); + tcanvas->setCornerWidget(new QSizeGrip(tcanvas)); + tcanvas->setFollow(INIT_FOLLOW); + + connect(song, SIGNAL(posChanged(int,const AL::Pos&,bool)), canvas(), SLOT(setLocatorPos(int,const AL::Pos&,bool))); + connect(canvas(), SIGNAL(posChanged(int,const AL::Pos&)), SLOT(setPos(int,const AL::Pos&))); + + connect(canvas(), SIGNAL(toolChanged(int)), tools2, SLOT(set(int))); + connect(tools2, SIGNAL(toolChanged(int)), canvas(), SLOT(setTool(int))); + + connect(canvas(), SIGNAL(selectionChanged(int, Event&, Part*)), + SLOT(setSelection(int, Event&, Part*))); + + setWindowTitle(canvas()->getCaption()); + + Pos p1(0, AL::TICKS), p2(0, AL::TICKS); + canvas()->range(p1, p2); + p2 += AL::sigmap.ticksMeasure(p2.tick()); // show one more measure + canvas()->setTimeRange(p1, p2); + + // connect toolbar + connect(canvas(), SIGNAL(cursorPos(const AL::Pos&,bool)), toolbar, SLOT(setTime(const AL::Pos&,bool))); + connect(toolbar, SIGNAL(quantChanged(int)), SLOT(setQuant(int))); + connect(toolbar, SIGNAL(rasterChanged(int)), SLOT(setRaster(int))); + connect(toolbar, SIGNAL(soloChanged(bool)), SLOT(soloChanged(bool))); + connect(toolbar, SIGNAL(toChanged(int)), SLOT(setApplyTo(int))); + + connect(info, SIGNAL(valueChanged(NoteInfo::ValType, int)), SLOT(noteinfoChanged(NoteInfo::ValType, int))); + + clipboardChanged(); // enable/disable "Paste" + selectionChanged(); // enable/disable "Copy" & "Paste" + + canvas()->selectFirst(); + + // + // install misc shortcuts + // + QShortcut* sc; + sc = new QShortcut(Qt::Key_Escape, this); + sc->setContext(Qt::WindowShortcut); + connect(sc, SIGNAL(activated()), SLOT(close())); + + QSignalMapper* cmdMap = new QSignalMapper(this); + static const char* actions[] = { + "curpos_increase", "curpos_decrease", + "pointer", "pencil", "eraser", + "midi_quant_1", "midi_quant_2", "midi_quant_3", "midi_quant_4", + "midi_quant_5", "midi_quant_6", "midi_quant_7", + "midi_quant_triol", "midi_quant_punct", "midi_quant_punct2" + }; + for (unsigned i = 0; i < sizeof(actions)/sizeof(*actions); ++i) { + QAction* a = getAction(actions[i], this); + addAction(a); + cmdMap->setMapping(a, a); + connect(a, SIGNAL(triggered()), cmdMap, SLOT(map())); + } + connect(cmdMap, SIGNAL(mapped(QObject*)), SLOT(drumCmd(QObject*))); + + + connect(song, SIGNAL(songChanged(int)), canvas(), SLOT(songChanged(int))); + connect(followSongAction, SIGNAL(toggled(bool)), canvas(), SLOT(setFollow(bool))); + canvas()->selectFirst(); + + Part* part = canvas()->part(); + + setRaster(part->raster() != -1 ? part->raster() : initRaster); + setQuant(part->quant() != -1 ? part->quant() : initQuant); + setXmag(part->xmag() != -1.0 ? part->xmag() : initXmag); + + if (init) + initFromPart(); + else + resize(initWidth, initHeight); + } + +//--------------------------------------------------------- +// ~DrumEdit +//--------------------------------------------------------- + +DrumEdit::~DrumEdit() + { + } + +//--------------------------------------------------------- +// closeEvent +//--------------------------------------------------------- + +void DrumEdit::closeEvent(QCloseEvent* e) + { + MidiEditor::closeEvent(e); + } + +//--------------------------------------------------------- +// setSelection +// update Info Line +//--------------------------------------------------------- + +void DrumEdit::setSelection(int tick, Event& e, Part* p) + { + int selections = canvas()->selectionSize(); + selEvent = e; + selPart = p; + + if (selections > 1) { + info->setEnabled(true); + info->setDeltaMode(true); + if (!deltaMode) { + deltaMode = true; + info->setValues(0, 0, 0, 0, 0); + tickOffset = 0; + lenOffset = 0; + pitchOffset = 0; + veloOnOffset = 0; + veloOffOffset = 0; + } + } + else if (selections == 1) { + deltaMode = false; + info->setEnabled(true); + info->setDeltaMode(false); + info->setValues(tick, + selEvent.lenTick(), + selEvent.pitch(), + selEvent.velo(), + selEvent.veloOff()); + } + else { + deltaMode = false; + info->setEnabled(false); + } + selectionChanged(); + } + +//--------------------------------------------------------- +// soloChanged +//--------------------------------------------------------- + +void DrumEdit::soloChanged(bool flag) + { + song->setSolo(canvas()->track(), flag); + } + +//--------------------------------------------------------- +// edit currently selected Event +//--------------------------------------------------------- + +void DrumEdit::noteinfoChanged(NoteInfo::ValType type, int val) + { + int selections = canvas()->selectionSize(); + + if (selections == 0) { + printf("noteinfoChanged while nothing selected\n"); + } + else if (selections == 1) { + Event event = selEvent.clone(); + switch(type) { + case NoteInfo::VAL_TIME: + event.setTick(val - selPart->tick()); + break; + case NoteInfo::VAL_LEN: + event.setLenTick(val); + break; + case NoteInfo::VAL_VELON: + event.setVelo(val); + break; + case NoteInfo::VAL_VELOFF: + event.setVeloOff(val); + break; + case NoteInfo::VAL_PITCH: + event.setPitch(val); + break; + } + audio->msgChangeEvent(selEvent, event, selPart); + } + else { + // multiple events are selected; treat noteinfo values + // as offsets to event values + + int delta = 0; + switch (type) { + case NoteInfo::VAL_TIME: + delta = val - tickOffset; + tickOffset = val; + break; + case NoteInfo::VAL_LEN: + delta = val - lenOffset; + lenOffset = val; + break; + case NoteInfo::VAL_VELON: + delta = val - veloOnOffset; + veloOnOffset = val; + break; + case NoteInfo::VAL_VELOFF: + delta = val - veloOffOffset; + veloOffOffset = val; + break; + case NoteInfo::VAL_PITCH: + delta = val - pitchOffset; + pitchOffset = val; + break; + } + if (delta) + canvas()->modifySelected(type, delta); + } + } + +//--------------------------------------------------------- +// cmd +// pulldown menu commands +//--------------------------------------------------------- + +void DrumEdit::cmd(QAction* a) + { + canvas()->cmd(a); + } + +//--------------------------------------------------------- +// drumCmd +//--------------------------------------------------------- + +void DrumEdit::drumCmd(QObject* object) + { + QAction* a = (QAction*)object; + QString cmd(a->data().toString()); + + static const int rasterTable[] = { + //-9----8- 7 6 5 4 3(1/4) 2 1 + 4, 8, 16, 32, 64, 128, 256, 512, 1024, // triple + 6, 12, 24, 48, 96, 192, 384, 768, 1536, + 9, 18, 36, 72, 144, 288, 576, 1152, 2304 // dot + }; + + DrumCanvas* dc = canvas(); + int index = 0; + int n = sizeof(rasterTable); + for (; index < n; ++index) + if (rasterTable[index] == raster()) + break; + int off = (index / 9) * 9; + index = index % 9; + int val; + + if (cmd == "curpos_increase") { + dc->cmd(a); + return; + } + else if (cmd == "curpos_decrease") { + dc->cmd(a); + return; + } + else if (cmd == "pointer") { + tools2->set(PointerTool); + return; + } + else if (cmd == "pencil") { + tools2->set(PencilTool); + return; + } + else if (cmd == "eraser") { + tools2->set(RubberTool); + return; + } + else if (cmd == "midi_quant_1") + val = rasterTable[8 + off]; + else if (cmd == "midi_quant_2") + val = rasterTable[7 + off]; + else if (cmd == "midi_quant_3") + val = rasterTable[6 + off]; + else if (cmd == "midi_quant_4") + val = rasterTable[5 + off]; + else if (cmd == "midi_quant_5") + val = rasterTable[4 + off]; + else if (cmd == "midi_quant_6") + val = rasterTable[3 + off]; + else if (cmd == "midi_quant_7") + val = rasterTable[2 + off]; + else if (cmd == "midi_quant_triol") + val = rasterTable[index + ((off == 0) ? 9 : 0)]; + else if (cmd == "midi_quant_punct") + val = rasterTable[index + ((off == 18) ? 9 : 18)]; + + else if (cmd == "midi_quant_punct2") { + if ((off == 18) && (index > 2)) { + val = rasterTable[index + 9 - 1]; + } + else if ((off == 9) && (index < 8)) { + val = rasterTable[index + 18 + 1]; + } + else + return; + } + else { + printf("DrumEdit::drumCmd: unknown cmd <%s>\n", cmd.toLatin1().data()); + return; + } + setQuant(val); + setRaster(val); + toolbar->setQuant(quant()); + toolbar->setRaster(raster()); + } + +//--------------------------------------------------------- +// writeConfiguration +//--------------------------------------------------------- + +void DrumEdit::writeConfiguration(Xml& xml) + { + xml.stag("DrumEdit"); + if (DrumEdit::initWidth != DrumEdit::INIT_WIDTH) + xml.tag("width", DrumEdit::initWidth); + if (DrumEdit::initHeight != DrumEdit::INIT_HEIGHT) + xml.tag("height", DrumEdit::initHeight); + if (DrumEdit::initRaster != DrumEdit::INIT_RASTER) + xml.tag("raster", DrumEdit::initRaster); + xml.etag("DrumEdit"); + } + +//--------------------------------------------------------- +// readConfiguration +//--------------------------------------------------------- + +void DrumEdit::readConfiguration(QDomNode node) + { + for (node = node.firstChild(); !node.isNull(); node = node.nextSibling()) { + QDomElement e = node.toElement(); + QString tag(e.tagName()); + int i = e.text().toInt(); + if (tag == "width") + DrumEdit::initWidth = i; + else if (tag == "height") + DrumEdit::initHeight = i; + else if (tag == "raster") + DrumEdit::initRaster = i; + else + printf("MusE:DrumEdit: unknown tag %s\n", tag.toLatin1().data()); + } + } + diff --git a/muse_qt4_evolution/muse/midiedit/drumedit.h b/muse_qt4_evolution/muse/midiedit/drumedit.h new file mode 100644 index 00000000..20cf99f6 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/drumedit.h @@ -0,0 +1,93 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __DRUM_EDIT_H__ +#define __DRUM_EDIT_H__ + +#include "midieditor.h" +#include "dcanvas.h" + +namespace AL { + class Xml; + }; +using AL::Xml; + + +class PartList; +class Part; +class DrumMap; + +//--------------------------------------------------------- +// DrumEdit +//--------------------------------------------------------- + +class DrumEdit : public MidiEditor { + Q_OBJECT + + Event selEvent; + DrumMap* drumMap; + int selTick; + QMenu *menuFunctions, *menuSelect; + + int tickOffset; + int lenOffset; + int pitchOffset; + int veloOnOffset; + int veloOffOffset; + bool deltaMode; + + virtual void closeEvent(QCloseEvent*); + QWidget* genToolbar(QWidget* parent); + DrumCanvas* canvas() { return (DrumCanvas*)tcanvas; } + + private slots: + void noteinfoChanged(NoteInfo::ValType type, int val); + virtual void cmd(QAction*); + void drumCmd(QObject* object); + + public slots: + void setSelection(int, Event&, Part*); + void soloChanged(bool); // called by Solo button + + public: + DrumEdit(PartList*, bool); + ~DrumEdit(); + + static int initRaster, initQuant, initWidth, initHeight; + static bool initFollow, initSpeaker, initMidiin; + static int initApplyTo; + static double initXmag; + + static void readConfiguration(QDomNode); + static void writeConfiguration(Xml&); + + static const int INIT_WIDTH = 650; + static const int INIT_HEIGHT = 450; + static const int INIT_RASTER = 384 / 4; + static const int INIT_QUANT = 384 / 4; + static const bool INIT_FOLLOW = false; + static const bool INIT_SPEAKER = true; + static const bool INIT_SREC = false; + static const bool INIT_MIDIIN = false; + static const double INIT_XMAG = 0.08; + static const int INIT_APPLY_TO = 0; + }; + +#endif diff --git a/muse_qt4_evolution/muse/midiedit/drummap.cpp b/muse_qt4_evolution/muse/midiedit/drummap.cpp new file mode 100644 index 00000000..978c7dab --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/drummap.cpp @@ -0,0 +1,219 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "drummap.h" +#include "al/xml.h" + +static const int DEFAULT_QUANT = 16; +static const int DEFAULT_LEN = 32; +static const int DEFAULT_CHANNEL = -1; +static const int DEFAULT_LV1 = 70; +static const int DEFAULT_LV2 = 90; +static const int DEFAULT_LV3 = 110; +static const int DEFAULT_LV4 = 127; + +//--------------------------------------------------------- +// GM default drum map +//--------------------------------------------------------- + +DrumMap gmDrumMap("generic"); +DrumMap noDrumMap("no-map"); + +//--------------------------------------------------------- +// DrumMap +//--------------------------------------------------------- + +DrumMap::DrumMap(const QString& s) + { + _name = s; + for (int i = 0; i < DRUM_MAPSIZE; ++i) { + map[i].name = "?"; + map[i].enote = i; + map[i].anote = i; + map[i].quant = DEFAULT_QUANT; + map[i].len = DEFAULT_LEN; + map[i].channel = DEFAULT_CHANNEL; + map[i].lv1 = DEFAULT_LV1; + map[i].lv2 = DEFAULT_LV2; + map[i].lv3 = DEFAULT_LV3; + map[i].lv4 = DEFAULT_LV4; + map[i].mute = false; + } + init(); + } + +//--------------------------------------------------------- +// initGm +//--------------------------------------------------------- + +void DrumMap::initGm() + { + static const char* gmNames[] = { + "Acoustic Bass Drum", "Bass Drum 1", "Side Stick", "Acoustic Snare", + "Hand Clap", "Electric Snare", "Low Floor Tom", "Closed Hi-Hat", + "High Floor Tom", "Pedal Hi-Hat", "Low Tom", "Open Hi-Hat", "Low-Mid Tom", + "Hi-Mid Tom", "Crash Cymbal 1", "High Tom", "Ride Cymbal 1", + "Chinese Cymbal", "Ride Bell", "Tambourine", "Splash Cymbal", + "Cowbell", "Crash Cymbal 2", "Vibraslap", "Ride Cymbal 2", + "Hi Bongo", "Low Bongo", "Mute Hi Conga", "Open Hi Conga", + "Low Conga", "High Timbale", "Low Timbale", "High Agogo", + "Low Agogo", "Cabasa", "Maracas", "Short Whistle", + "Long Whistle", "Short Guiro", "Long Guiro", "Claves", + "Hi Wood Block", "Low Wood Block", "Mute Cuica", + "Open Cuica", "Mute Triangle", "Open Triangle", 0 + }; + init(); + int idx = 0; + const char** p = &gmNames[0]; + int val = 35; + for (; *p; ++p, ++val, ++idx) { + map[idx].name = *p; + map[idx].enote = val; + map[idx].anote = val; + _inmap[int(map[idx].enote)] = idx; + _outmap[int(map[idx].anote)] = idx; + } + } + +//--------------------------------------------------------- +// init +// populate Inmap and Outmap +//--------------------------------------------------------- + +void DrumMap::init() + { + memset(_inmap, 0, sizeof(_inmap)); + memset(_outmap, 0, sizeof(_outmap)); + for (int i = 0; i < DRUM_MAPSIZE; ++i) { + _inmap[int(map[i].enote)] = i; + _outmap[int(map[i].anote)] = i; + } + } + +//--------------------------------------------------------- +// writeDrumMap +//--------------------------------------------------------- + +void DrumMap::write(Xml& xml) + { + xml.stag("drummap"); + for (int i = 0; i < DRUM_MAPSIZE; ++i) { + DrumMapEntry* dm = &map[i]; + dm->write(xml); + } + xml.etag("drummap"); + } + +//--------------------------------------------------------- +// write +//--------------------------------------------------------- + +void DrumMapEntry::write(Xml& xml) + { + xml.stag("entry"); + xml.tag("name", name); + if (quant != DEFAULT_QUANT) + xml.tag("quant", quant); + if (len != DEFAULT_LEN) + xml.tag("len", len); + if (channel != DEFAULT_CHANNEL) + xml.tag("channel", channel); + if (lv1 != DEFAULT_LV1) + xml.tag("lv1", lv1); + if (lv2 != DEFAULT_LV2) + xml.tag("lv2", lv2); + if (lv3 != DEFAULT_LV3) + xml.tag("lv3", lv3); + if (lv4 != DEFAULT_LV4) + xml.tag("lv4", lv4); + xml.tag("enote", enote); + if (anote != enote) + xml.tag("anote", anote); + xml.etag("entry"); + } + +//--------------------------------------------------------- +// read +//--------------------------------------------------------- + +void DrumMapEntry::read(QDomNode n) + { + anote = -1; + for (QDomNode node = n.firstChild(); !node.isNull(); node = node.nextSibling()) { + QDomElement e = node.toElement(); + QString tag(e.tagName()); + QString s(e.text()); + if (tag == "name") + name = s; + else if (tag == "quant") + quant = s.toInt(); + else if (tag == "len") + len = s.toInt(); + else if (tag == "channel") + channel = s.toInt(); + else if (tag == "lv1") + lv1 = s.toInt(); + else if (tag == "lv2") + lv2 = s.toInt(); + else if (tag == "lv3") + lv3 = s.toInt(); + else if (tag == "lv4") + lv4 = s.toInt(); + else if (tag == "enote") + enote = s.toInt(); + else if (tag == "anote") + anote = s.toInt(); + else if (tag == "mute") + mute = s.toInt(); + else { + printf("read Drummap Entry: unknown tag %s\n", tag.toLatin1().data()); + break; + } + } + if (anote == -1) + anote = enote; + } + +//--------------------------------------------------------- +// readDrummap +//--------------------------------------------------------- + +void DrumMap::read(QDomNode node) + { + init(); + int idx = 0; + for (; !node.isNull(); node = node.nextSibling()) { + QDomElement e = node.toElement(); + QString tag(e.tagName()); + + if (tag == "entry") { + QDomNode entryNode = node.firstChild(); + map[idx].read(entryNode); + _inmap[int(map[idx].enote)] = idx; + _outmap[int(map[idx].anote)] = idx; + ++idx; + } + else { + printf("read Drummap: unknown tag %s\n", tag.toLatin1().data()); + break; + } + } + } + diff --git a/muse_qt4_evolution/muse/midiedit/drummap.h b/muse_qt4_evolution/muse/midiedit/drummap.h new file mode 100644 index 00000000..0ec1d536 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/drummap.h @@ -0,0 +1,81 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __DRUMMAP_H__ +#define __DRUMMAP_H__ + +namespace AL { + class Xml; + }; +using AL::Xml; + +const int DRUM_MAPSIZE = 128; + +//--------------------------------------------------------- +// DrumMapEntry +//--------------------------------------------------------- + +struct DrumMapEntry { + QString name; + int quant; + int len; // len of event in ticks + int channel; // midi channel + char lv1, lv2, lv3, lv4; // velocities + char enote, anote; // input note - output note + bool mute; + + void read(QDomNode node); + void write(Xml& xml); + }; + +//--------------------------------------------------------- +// DrumMap +//--------------------------------------------------------- + +class DrumMap { + QString _name; + DrumMapEntry map[DRUM_MAPSIZE]; + char _outmap[DRUM_MAPSIZE]; + char _inmap[DRUM_MAPSIZE]; + + public: + DrumMap(const QString& name); + void init(); + void write(Xml& xml); + void read(QDomNode); + void initGm(); + DrumMapEntry* entry(int idx) { return &map[idx]; } + QString name() const { return _name; } + QString name(int i) const { return map[i].name; } + int quant(int i) const { return map[i].quant; } + int len(int i) const { return map[i].len; } + int channel(int i) const { return map[i].channel; } + int enote(int i) const { return map[i].enote; } + int anote(int i) const { return map[i].anote; } + bool mute(int i) const { return map[i].mute; } + int inmap(int i) const { return _inmap[i]; } + int outmap(int i) const { return _outmap[i]; } + }; + +extern DrumMap gmDrumMap; +extern DrumMap noDrumMap; + +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/ecanvas.cpp b/muse_qt4_evolution/muse/midiedit/ecanvas.cpp new file mode 100644 index 00000000..8c2eefbf --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/ecanvas.cpp @@ -0,0 +1,1549 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "midieditor.h" +#include "ecanvas.h" +#include "song.h" +#include "shortcuts.h" +#include "widgets/simplebutton.h" +#include "widgets/tools.h" +#include "widgets/utils.h" +#include "part.h" +#include "audio.h" +#include "midi.h" + +//--------------------------------------------------------- +// EventCanvas +//--------------------------------------------------------- + +EventCanvas::EventCanvas(MidiEditor* pr, TimeCanvasType type) + : TimeCanvas(type) + { + setMarkerList(song->marker()); + canvasTools = 0; + curItem = 0; + curSplitter = -1; + dragSplitter = false; + + keyDown = -1; + + itemPopupMenu = 0; + canvasPopupMenu = 0; + drag = DRAG_OFF; + + editor = pr; + curVelo = 70; + + setAcceptDrops(true); + setFocusPolicy(Qt::StrongFocus); + setMouseTracking(true); + + curPart = editor->parts()->begin()->second; + connect(song, SIGNAL(midiEvent(const MidiEvent&)), SLOT(midiNote(const MidiEvent&))); + } + +//--------------------------------------------------------- +// range +//--------------------------------------------------------- + +void EventCanvas::range(AL::Pos& s, AL::Pos& e) const + { + s.setTick(startTick); + e.setTick(endTick); + } + +//--------------------------------------------------------- +// getCaption +//--------------------------------------------------------- + +QString EventCanvas::getCaption() const + { + int bar1, bar2, xx; + unsigned x; + AL::sigmap.tickValues(curPart->tick(), &bar1, &xx, &x); + AL::sigmap.tickValues(curPart->tick() + curPart->lenTick(), &bar2, &xx, &x); + + return QString("MusE: Part <") + curPart->name() + + QString("> %1-%2").arg(bar1+1).arg(bar2+1); + } + +//--------------------------------------------------------- +// startUndo +//--------------------------------------------------------- + +void EventCanvas::startUndo(DragType) + { + song->startUndo(); + } + +//--------------------------------------------------------- +// endUndo +//--------------------------------------------------------- + +void EventCanvas::endUndo(DragType dtype) + { + song->endUndo((dtype == MOVE_COPY) ? SC_EVENT_INSERTED : SC_EVENT_MODIFIED); + } + +//--------------------------------------------------------- +// updateSelection +//--------------------------------------------------------- + +void EventCanvas::updateSelection() + { + song->update(SC_SELECTION); + } + +//--------------------------------------------------------- +// songChanged(type) +// called from MidiEditor +//--------------------------------------------------------- + +void EventCanvas::songChanged(int flags) + { + if ((flags & ~SC_SELECTION) && !editor->parts()->empty()) { + items.clear(); + startTick = INT_MAX; + endTick = 0; + for (iPart p = editor->parts()->begin(); p != editor->parts()->end(); ++p) { + Part* part = p->second; + unsigned stick = part->tick(); + unsigned etick = stick + part->lenTick(); + if (stick < startTick) + startTick = stick; + if (etick > endTick) + endTick = etick; + + EventList* el = part->events(); + for (iEvent i = el->begin(); i != el->end(); ++i) { + Event e = i->second; + if (e.isNote()) + addItem(part, e); + } + } + } + + Event event; + Part* part = 0; + int x = 0; + CItem* nevent = 0; + + int n = 0; // count selections + for (iCItem k = items.begin(); k != items.end(); ++k) { + Event ev = k->second->event; + bool selected = ev.selected(); + if (selected) { + k->second->setSelected(true); + ++n; + if (!nevent) { + nevent = k->second; + Event mi = nevent->event; + curVelo = mi.velo(); + } + } + } + startTick = song->roundDownBar(startTick); + endTick = song->roundUpBar(endTick); + + if (n == 1) { + x = nevent->bbox.x(); + event = nevent->event; + part = nevent->part; + } + emit selectionChanged(x, event, part); + if (curPart) + setPart(*curPart, curPart->end()); + widget()->update(); + } + +//--------------------------------------------------------- +// selectFirst +//--------------------------------------------------------- + +void EventCanvas::selectFirst() + { + //Select leftmost note if none selected and there are any + if (!items.empty() && selectionSize() == 0) { + iCItem i = items.begin(); + if (!i->second->isSelected()) { + selectItem(i->second, true); + songChanged(SC_SELECTION); + } + } + } + +//--------------------------------------------------------- +// track +//--------------------------------------------------------- + +MidiTrack* EventCanvas::track() const + { + return (MidiTrack*)(curPart->track()); + } + +//--------------------------------------------------------- +// keyPress +//--------------------------------------------------------- + +void EventCanvas::keyPress(QKeyEvent* event) + { +#if 0 // TODOB + int key = event->key(); + if (event->modifiers() & Qt::ShiftModifier) + key += Qt::SHIFT; + if (event->modifiers() & Qt::AltModifier) + key += Qt::ALT; + if (event->modifiers() & Qt::ControlModifier) + key += Qt::CTRL; + + // + // Shortcut for DrumEditor & PianoRoll + // Sets locators to selected events + // + if (key == shortcuts[SHRT_LOCATORS_TO_SELECTION].key) { + int tick_max = 0; + int tick_min = INT_MAX; + bool found = false; + + for (iCItem i= items.begin(); i != items.end(); i++) { + if (!i->second->isSelected()) + continue; + + int tick = i->second->bbox.x(); + int len = i->second->event.lenTick(); + found = true; + if (tick + len > tick_max) + tick_max = tick + len; + if (tick < tick_min) + tick_min = tick; + } + if (found) { + Pos p1(tick_min, AL::TICKS); + Pos p2(tick_max, AL::TICKS); + song->setPos(1, p1); + song->setPos(2, p2); + } + } + // Select items by key (PianoRoll & DrumEditor) + else if (key == shortcuts[SHRT_SEL_RIGHT].key || key == shortcuts[SHRT_SEL_RIGHT_ADD].key) { + iCItem i, iRightmost; + CItem* rightmost = NULL; + //Get the rightmost selected note (if any) + for (i = items.begin(); i != items.end(); ++i) { + if (i->second->isSelected()) { + iRightmost = i; + rightmost = i->second; + } + } + if (rightmost) { + iCItem temp = iRightmost; + temp++; + //If so, deselect current note and select the one to the right + if (temp != items.end()) { + if (key != shortcuts[SHRT_SEL_RIGHT_ADD].key) + deselectAll(); + + iRightmost++; + iRightmost->second->setSelected(true); + updateSelection(); + } + } + } + //Select items by key: (PianoRoll & DrumEditor) + else if (key == shortcuts[SHRT_SEL_LEFT].key || key == shortcuts[SHRT_SEL_LEFT_ADD].key) { + iCItem i, iLeftmost; + CItem* leftmost = NULL; + for (i = items.end(), i--; i != items.begin(); i--) { + if (i->second->isSelected()) { + iLeftmost = i; + leftmost = i->second; + } + } + if (leftmost) { + if (iLeftmost != items.begin()) { + //Add item + if (key != shortcuts[SHRT_SEL_LEFT_ADD].key) + deselectAll(); + + iLeftmost--; + iLeftmost->second->setSelected(true); + updateSelection(); + } + } + } + else if (key == shortcuts[SHRT_INC_PITCH].key) { + modifySelected(NoteInfo::VAL_PITCH, 1); + } + else if (key == shortcuts[SHRT_DEC_PITCH].key) { + modifySelected(NoteInfo::VAL_PITCH, -1); + } + else if (key == shortcuts[SHRT_INC_POS].key) { + // TODO: Check boundaries + modifySelected(NoteInfo::VAL_TIME, editor->raster()); + } + else if (key == shortcuts[SHRT_DEC_POS].key) { + // TODO: Check boundaries + modifySelected(NoteInfo::VAL_TIME, 0 - editor->raster()); + } + else + event->ignore(); +#endif + } + +//--------------------------------------------------------- +// mousePressCanvasA +//--------------------------------------------------------- + +void EventCanvas::mousePressCanvasA(QMouseEvent* me) + { + QPoint p(me->pos() - rCanvasA.topLeft()); + + // special events if right button is clicked while operations + // like moving or drawing lasso is performed. + + if (button == Qt::RightButton) { + switch (drag) { + case DRAG_LASSO: + drag = DRAG_OFF; + widget()->update(); + return; + case DRAG_MOVE: + drag = DRAG_OFF; + endMoveItems(MOVE_MOVE); + return; + default: + break; + } + } + // ignore event if (another) button is already active: + if (me->buttons() & (Qt::LeftButton | Qt::RightButton | Qt::MidButton) + & ~button) + return; + + bool shift = keyState & Qt::ShiftModifier; + bool ctrl = keyState & Qt::ControlModifier; + start = p; + startPitch = y2pitch(start.y()); + deltaPitch = 0; + + //--------------------------------------------------- + // set curItem to item mouse is pointing + // (if any) + //--------------------------------------------------- + + curItem = searchItem(start); + if (curItem && editor->playEvents()) { + int pitch = curItem->event.pitch() + track()->transposition(); + MidiEvent e(0, 0, ME_NOTEON, pitch, curItem->event.velo()); + track()->playMidiEvent(&e); + } + + if (curItem && (button == Qt::MidButton)) { + if (!curItem->isSelected()) { + selectItem(curItem, true); + updateSelection(); + widget()->update(); + } + startDrag(curItem, shift); + } + else if (button == Qt::RightButton) { + if (curItem) { + if (shift) { + drag = DRAG_RESIZE; + setCursor(); + Pos p1(curItem->bbox.x(), timeType()); + Pos p2(pix2pos(start.x())); + curItem->bbox.setWidth(p2.time(timeType())-p1.time(timeType())); + + start.setX(curItem->bbox.x()); + deselectAll(); + selectItem(curItem, true); + updateSelection(); + widget()->update(); + } + else { + itemPopupMenu = genItemPopup(curItem); + if (itemPopupMenu) { + QAction* a = itemPopupMenu->exec(QCursor::pos()); + if (a) { + int n = a->data().toInt(); + itemPopup(curItem, n, start); + } + delete itemPopupMenu; + } + } + } + else { + canvasPopupMenu = genCanvasPopup(); + if (canvasPopupMenu) { + QAction* a = canvasPopupMenu->exec(QCursor::pos(), 0); + if (a) { + int n = a->data().toInt(); + canvasPopup(n); + } + delete canvasPopupMenu; + } + } + } + else if (button == Qt::LeftButton) { + switch (_tool) { + case PointerTool: + if (curItem) { + itemPressed(curItem); + if (curItem->part != curPart) + setCurPart(curItem->part); + if (shift && !ctrl) + drag = DRAG_COPY_START; + else if (!shift && ctrl) { + //Select all on the same pitch + deselectAll(); + int pitch = curItem->event.pitch(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (i->second->event.pitch() == pitch) + selectItem(i->second, true); + } + updateSelection(); + widget()->update(); + drag = DRAG_MOVE_START; + } + else + drag = DRAG_MOVE_START; + } + else + drag = DRAG_LASSO_START; + setCursor(); + break; + + case RubberTool: + deleteItem(p); + drag = DRAG_DELETE; + setCursor(); + break; + + case PencilTool: + if (curItem) { + drag = DRAG_RESIZE; + setCursor(); + + Pos p1(curItem->bbox.x(), timeType()); + Pos p2(pix2pos(start.x())); + int w = p2.time(timeType()) - p1.time(timeType()); + curItem->bbox.setWidth(w); + start.setX(curItem->bbox.x()); + start.setY(curItem->bbox.y()); + } + else { + drag = DRAG_NEW; + setCursor(); + curItem = newItem(start, keyState); + if (curItem) { + items.add(curItem); + if (editor->playEvents()) { + int pitch = curItem->event.pitch() + track()->transposition(); + MidiEvent e(0, 0, ME_NOTEON, pitch, curItem->event.velo()); + track()->playMidiEvent(&e); + } + } + else { + drag = DRAG_OFF; + setCursor(); + } + } + deselectAll(); + if (curItem) + selectItem(curItem, true); + updateSelection(); + widget()->update(); + break; + + default: + break; + } + } + } + +//--------------------------------------------------------- +// mouseMoveCanvasA +// pos is relative to CanvasA +//--------------------------------------------------------- + +void EventCanvas::mouseMoveCanvasA(QPoint pos) + { + QPoint dist = pos - start; + bool isMoving = dist.manhattanLength() >= QApplication::startDragDistance(); + + switch (drag) { + case DRAG_LASSO_START: + if (!isMoving) + break; + drag = DRAG_LASSO; + setCursor(); + // proceed with DRAG_LASSO: + + case DRAG_LASSO: + lasso = QRect(start, QSize(dist.x(), dist.y())); + widget()->update(); + break; + + case DRAG_MOVE_START: + case DRAG_COPY_START: + if (!isMoving) + break; + { + bool shift = keyState & Qt::ShiftModifier; + bool ctrl = keyState & Qt::ControlModifier; + if (shift && ctrl) { + if (qAbs(dist.x()) > qAbs(dist.y())) { + if (drag == DRAG_MOVE_START) + drag = DRAGX_MOVE; + else + drag = DRAGX_COPY; + } + else { + if (drag == DRAG_MOVE_START) + drag = DRAGY_MOVE; + else + drag = DRAGY_COPY; + } + } + else { + if (drag == DRAG_MOVE_START) + drag = DRAG_MOVE; + else + drag = DRAG_COPY; + } + setCursor(); + if (!curItem->isSelected()) { + if (drag == DRAG_MOVE) + deselectAll(); + selectItem(curItem, true); + updateSelection(); + widget()->update(); + } + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (i->second->isSelected()) { + i->second->isMoving = true; + moving.add(i->second); + } + } + moveItems(pos, 0); + } + break; + + case DRAG_MOVE: + case DRAG_COPY: + moveItems(pos, 0); + break; + + case DRAGX_MOVE: + case DRAGX_COPY: + moveItems(pos, 1); + break; + + case DRAGY_MOVE: + case DRAGY_COPY: + moveItems(pos, 2); + break; + + case DRAG_NEW: + case DRAG_RESIZE: + if (dist.x()) { + Pos p1(curItem->bbox.x(), timeType()); + Pos p2(pix2pos(pos.x())); + int w = p2.time(timeType()) - p1.time(timeType()); + if (w < 1) + w = 1; + curItem->bbox.setWidth(w); + widget()->update(); + } + break; + case DRAG_DELETE: + deleteItem(pos); + break; + + case DRAG_OFF: + break; + } + } + +//--------------------------------------------------------- +// mouseReleaseCanvasA +//--------------------------------------------------------- + +void EventCanvas::mouseReleaseCanvasA(QMouseEvent* me) + { + if (curItem && editor->playEvents()) { + int pitch = curItem->event.pitch() + track()->transposition(); + MidiEvent e(0, 0, ME_NOTEON, pitch, 0); + track()->playMidiEvent(&e); + } + // ignore event if (another) button is already active: + + if (me->buttons() & (Qt::LeftButton | Qt::RightButton | Qt::MidButton) + & ~button) + return; + + bool shift = keyState & Qt::ShiftModifier; + bool ctrl = keyState & Qt::ControlModifier; + bool redrawFlag = false; + + switch (drag) { + case DRAG_MOVE_START: + case DRAG_COPY_START: + if (!(shift || ctrl)) + deselectAll(); + if (!ctrl) + selectItem(curItem, !(shift && curItem->isSelected())); + updateSelection(); + redrawFlag = true; + itemReleased(); + break; + case DRAG_COPY: + case DRAGX_COPY: + case DRAGY_COPY: + endMoveItems(MOVE_COPY); + break; + case DRAG_MOVE: + case DRAGX_MOVE: + case DRAGY_MOVE: + endMoveItems(MOVE_MOVE); + break; + case DRAG_OFF: + break; + case DRAG_RESIZE: + resizeItem(curItem, false); + break; + case DRAG_NEW: + newItem(curItem, false); + redrawFlag = true; + break; + case DRAG_LASSO_START: + lasso.setRect(-1, -1, -1, -1); + if (!shift) + deselectAll(); + updateSelection(); + redrawFlag = true; + break; + + case DRAG_LASSO: + if (!shift) + deselectAll(); + lasso = lasso.normalized(); + selectLasso(shift); + updateSelection(); + redrawFlag = true; + break; + + case DRAG_DELETE: + break; + } + drag = DRAG_OFF; + if (redrawFlag) + widget()->update(); + setCursor(); + } + + +//--------------------------------------------------------- +// endMoveItems +//--------------------------------------------------------- + +void EventCanvas::endMoveItems(DragType dragtype) + { + startUndo(dragtype); + + for (iCItem i = moving.begin(); i != moving.end(); ++i) { + selectItem(i->second, true); + moveItem(i->second, dragtype); +//TD if (moving.size() == 1) { +// itemReleased(); +// } + if (dragtype == MOVE_COPY) + selectItem(i->second, false); + } + endUndo(dragtype); + moving.clear(); + updateSelection(); + widget()->update(); + } + +//--------------------------------------------------------- +// selectItem +//--------------------------------------------------------- + +void EventCanvas::selectItem(CItem* e, bool flag) + { + e->setSelected(flag); + } + +//--------------------------------------------------------- +// deselectAll +//--------------------------------------------------------- + +void EventCanvas::deselectAll() + { + for (iCItem i = items.begin(); i != items.end(); ++i) + i->second->setSelected(false); + } + +//--------------------------------------------------------- +// genCanvasPopup +//--------------------------------------------------------- + +QMenu* EventCanvas::genCanvasPopup() + { + if (canvasTools == 0) + return 0; + QMenu* canvasPopup = new QMenu(this); + + for (int i = 0; i < TOOLS; ++i) { + int data = 1 << i; + if ((canvasTools & data) == 0) + continue; + QAction* a = getAction(toolList[i], this); + a->setData(data); + a->setCheckable(true); + a->setChecked(data == int(_tool)); + canvasPopup->addAction(a); + } + return canvasPopup; + } + +//--------------------------------------------------------- +// canvasPopup +//--------------------------------------------------------- + +void EventCanvas::canvasPopup(int n) + { + setTool(n); + } + +//--------------------------------------------------------- +// setCursor +//--------------------------------------------------------- + +void EventCanvas::setCursor() + { + if (curSplitter != -1) { + widget()->setCursor(Qt::SplitVCursor); + return; + } + switch (drag) { + case DRAGX_MOVE: + case DRAGX_COPY: + widget()->setCursor(QCursor(Qt::SizeHorCursor)); + break; + + case DRAGY_MOVE: + case DRAGY_COPY: + widget()->setCursor(QCursor(Qt::SizeVerCursor)); + break; + + case DRAG_MOVE: + case DRAG_COPY: + widget()->setCursor(QCursor(Qt::SizeAllCursor)); + break; + + case DRAG_RESIZE: + widget()->setCursor(QCursor(Qt::SizeHorCursor)); + break; + + case DRAG_DELETE: + case DRAG_COPY_START: + case DRAG_MOVE_START: + case DRAG_NEW: + case DRAG_LASSO_START: + case DRAG_LASSO: + case DRAG_OFF: + TimeCanvas::setCursor(); + break; + } + } + +//--------------------------------------------------------- +// deleteItem +// p is relative to CanvasA +//--------------------------------------------------------- + +void EventCanvas::deleteItem(const QPoint& p) + { + Pos pos(pix2pos(p.x())); + int pitch(y2pitch(p.y())); + +// printf("%d %d - %d %d\n", p.x(), p.y(), pos.tick(), pitch); + + pos -= *curPart; + for (iCItem i = items.begin(); i != items.end(); ++i) { + Event& event = i->second->event; + if (event.pitch() == pitch + && (pos >= event.pos()) + && (pos < event.end())) { + deleteItem(i->second); + break; + } + } + } + +//--------------------------------------------------------- +// moveItems +// dir = 0 move in all directions +// 1 move only horizontal +// 2 move only vertical +//--------------------------------------------------------- + +void EventCanvas::moveItems(const QPoint& pos, int dir) + { + int dpitch = y2pitch(pos.y()) - startPitch; + + Pos sp(pix2pos(start.x())); + Pos cp(pix2pos(pos.x())); + + bool left = sp > cp; + Pos dx(left ? sp - cp : cp - sp); + + if (dir == 2) + dx.setTick(0); + + for (iCItem i = moving.begin(); i != moving.end(); ++i) { + CItem* item = i->second; + Pos p; + if (left) { + // + // restrict movement to pos >= 0 + // + if (dx > item->pos) + p.setTick(0); + else + p = item->pos - dx; + } + else + p = item->pos + dx; + p.snap(raster()); + + if (p < *curPart) + p = *curPart; + + if (item->moving != p || dpitch != deltaPitch) { + item->moving = p; + if (dir != 1) + item->my = pitch2y(item->event.pitch() + dpitch) + + (int)(wpos.y() / _ymag); + itemMoved(item); + } + } + deltaPitch = dpitch; + widget()->update(); + } + +//--------------------------------------------------------- +// selectionSize +//--------------------------------------------------------- + +int EventCanvas::selectionSize() const + { + int n = 0; + for (ciCItem i = items.begin(); i != items.end(); ++i) { + if (i->second->isSelected()) + ++n; + } + return n; + } + +//--------------------------------------------------------- +// layout +// called after resize +//--------------------------------------------------------- + +void EventCanvas::layout() + { + int n = ctrlEditList.size(); + if (n == 0) + return; + if (ctrlHeight == 0) { + int wh = widget()->height(); + resizeController(wh < 120 ? wh / 2 : 100); + } + + // check, if layout is ok already; this happens after + // song load + int h = 0; + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) { + CtrlEdit* c = *i; + h += c->height(); + } + if (h == ctrlHeight) { + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) + layoutPanelB(*i); + return; + } + + int y = 0; + int sch = ctrlHeight / n; + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) { + CtrlEdit* c = *i; + c->y = y; + c->setHeight(sch); + layoutPanelB(c); + y += sch; + } + } + +//--------------------------------------------------------- +// layout1 +// called after read song +//--------------------------------------------------------- + +void EventCanvas::layout1() + { + int n = ctrlEditList.size(); + if (n == 0) + return; + int y = 0; + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) { + CtrlEdit* c = *i; + c->y = y; + y += c->height(); + } + resizeController(y); + } + +//--------------------------------------------------------- +// layoutPanelB +//--------------------------------------------------------- + +void EventCanvas::layoutPanelB(CtrlEdit* c) + { + int y = c->y; + int h = c->height(); + int bx = rPanelB.x() + rPanelB.width() - 23; + int by = rPanelB.y() + y + h - 19; + c->minus->setGeometry(bx, by, 18, 18); + bx = rPanelB.x() + 1; + by = rPanelB.y() + y + 5; + c->sel->setGeometry(bx, by, rPanelB.width()-5, 18); + } + +//--------------------------------------------------------- +// addController +//--------------------------------------------------------- + +void EventCanvas::addController() + { + int n = ctrlEditList.size(); + CtrlEdit* ce = new CtrlEdit(widget(), this, track()); + ce->setHeight(50); + ctrlEditList.push_back(ce); + + ce->minus->defaultAction()->setData(n); + connect(ce->minus, SIGNAL(triggered(QAction*)), SLOT(removeController(QAction*))); + ce->minus->show(); + ce->sel->show(); + + layout(); + widget()->update(); + updatePartControllerList(); + } + +void EventCanvas::addController(int id, int h) + { + ctrlHeight += h; + int n = ctrlEditList.size(); + + CtrlEdit* ce = new CtrlEdit(widget(), this, track()); + ce->setHeight(h); + ce->setCtrl(id); + ctrlEditList.push_back(ce); + + ce->minus->defaultAction()->setData(n); + connect(ce->minus, SIGNAL(triggered(QAction*)), SLOT(removeController(QAction*))); + } + +//--------------------------------------------------------- +// paintControllerCanvas +// r(0, 0) is PanelB topLeft() +//--------------------------------------------------------- + +void EventCanvas::paintControllerCanvas(QPainter& p, QRect r) + { + int x1 = r.x(); + int x2 = x1 + r.width(); + + int xx2 = rCanvasB.width(); + if (xx2 >= x2) + x2 = xx2 - 2; + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) { + CtrlEdit* c = *i; + int y = c->y; + paintHLine(p, x1, x2, y); + p.setPen(lineColor[0]); + p.drawLine(xx2-1, 1, xx2-1, splitWidth-2); + + QRect rc(0, y + splitWidth, rCanvasB.width(), c->cheight()); + QPoint pt(rc.topLeft()); + rc &= r; + if (!rc.isEmpty()) { + p.translate(pt); + c->paint(p, rc.translated(-pt)); + p.translate(-pt); + } + } + } + +//--------------------------------------------------------- +// paintControllerPanel +// panelB +//--------------------------------------------------------- + +void EventCanvas::paintControllerPanel(QPainter& p, QRect r) + { + p.fillRect(r, QColor(0xe0, 0xe0, 0xe0)); + int x1 = r.x(); + int x2 = x1 + r.width(); + + paintVLine(p, r.y() + splitWidth, r.y() + r.height(), + rPanelB.x() + rPanelB.width()); + + if (x1 == 0) + x1 = 1; + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) { + CtrlEdit* c = *i; + paintHLine(p, x1, x2, c->y); + p.setPen(lineColor[0]); + p.drawLine(0, 1, 0, splitWidth-2); + } + } + +//--------------------------------------------------------- +// removeController +//--------------------------------------------------------- + +void EventCanvas::removeController(QAction* a) + { + int id = a->data().toInt(); + + int k = 0; + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i, ++k) { + if (k == id) { + CtrlEdit* c = *i; + delete c; + ctrlEditList.erase(i); + break; + } + } + k = 0; + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i, ++k) { + CtrlEdit* c = *i; + c->minus->defaultAction()->setData(k); + } + + if (ctrlEditList.empty()) + resizeController(0); + else + layout(); + widget()->update(); + updatePartControllerList(); + } + +//--------------------------------------------------------- +// enterB +//--------------------------------------------------------- + +void EventCanvas::enterB() + { + if ((button == 0) && curSplitter != -1) { + curSplitter = -1; + setCursor(); + } + } + +//--------------------------------------------------------- +// leaveB +//--------------------------------------------------------- + +void EventCanvas::leaveB() + { + if ((button == 0) && (curSplitter != -1)) { + curSplitter = -1; + setCursor(); + } + } + +//--------------------------------------------------------- +// noteOn +//--------------------------------------------------------- + +void EventCanvas::noteOn(int pitch, int velocity, bool shift) + { + DrumMap* dm = track()->drumMap(); + if (!dm) + pitch += track()->transposition(); + + // play note: + if (editor->playEvents()) { + MidiEvent e(0, 0, ME_NOTEON, pitch, velocity); + track()->playMidiEvent(&e); + } + + if (curPart && editor->stepRec() + && pos[0].tick() >= startTick + && pos[0].tick() < endTick) { + int len = editor->quant(); + unsigned tick = pos[0].tick() - curPart->tick(); //CDW + if (shift) + tick -= editor->rasterStep(tick); + Event e(Note); + e.setTick(tick); + e.setPitch(pitch); + e.setVelo(127); + e.setLenTick(len); + audio->msgAddEvent(e, curPart); + tick += editor->rasterStep(tick) + curPart->tick(); + if (tick != song->cpos()) { + Pos p(tick, AL::TICKS); + song->setPos(0, p, true, false, true); + } + } + } + +//--------------------------------------------------------- +// noteOff +//--------------------------------------------------------- + +void EventCanvas::noteOff(int pitch) + { + if (!editor->playEvents()) + return; + DrumMap* dm = track()->drumMap(); + if (!dm) + pitch += track()->transposition(); + + // release key: + MidiEvent e(0, 0, ME_NOTEON, pitch, 0); + track()->playMidiEvent(&e); + } + +//--------------------------------------------------------- +// mouseDoubleClick +//--------------------------------------------------------- + +void EventCanvas::mouseDoubleClick(QMouseEvent* me) + { + mousePress(me); + } + +//--------------------------------------------------------- +// mousePress +//--------------------------------------------------------- + +void EventCanvas::mousePress(QMouseEvent* me) + { + QPoint pos(me->pos()); + if (rPanelA.contains(pos)) { + bool shift = keyState & Qt::ShiftModifier; + if (keyDown != -1) { + noteOff(keyDown); + keyDown = -1; + } + keyDown = y2pitch(pos.y() - rCanvasA.y()); + int velocity = me->x()*127/40; + if (keyDown != -1) + noteOn(keyDown, velocity, shift); + return; + } + if (rCanvasA.contains(pos)) { + mousePressCanvasA(me); + return; + } + if (curSplitter != -1) { + dragSplitter = true; + splitterY = pos.y(); + return; + } + if (rCanvasB.contains(pos)) { + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) { + CtrlEdit* c = *i; + QRect r(rCanvasB.x(), rCanvasB.y() + c->y + splitWidth, + rCanvasB.width(), c->cheight()); + if (r.contains(pos)) { + c->mousePress(pos - r.topLeft(), me); + break; + } + } + } + } + +//--------------------------------------------------------- +// mouseMove +//--------------------------------------------------------- + +void EventCanvas::mouseMove(QPoint pos) + { + if (rPanelA.contains(pos) || rCanvasA.contains(pos)) { + int y = pos.y() - rCanvasA.y(); + int pitch = y2pitch(y); + if (curPitch != pitch) { + curPitch = pitch; + widget()->update(rPanelA); // update keyboard + emit pitchChanged(curPitch); + if (button != Qt::NoButton) { + if (keyDown != -1 && curPitch != -1) { + bool shift = keyState & Qt::ShiftModifier; + if (curPitch != keyDown) { + noteOff(keyDown); + keyDown = curPitch; + int velocity = std::min(pos.x()*127/40, 127); + noteOn(keyDown, velocity, shift); + } + } + } + } + } + if (dragSplitter) { + int deltaY = pos.y() - splitterY; + + iCtrlEdit i = ctrlEditList.begin(); + int y = 0; + if (curSplitter > 0) { + int k = 0; + CtrlEdit* c = 0; + for (; i != ctrlEditList.end(); ++i, ++k) { + c = *i; + y += c->height(); + if ((k+1) == curSplitter) + break; + } + if (i == ctrlEditList.end()) { + printf("unexpected edit list end, curSplitter %d\n", curSplitter); + return; + } + if (c->height() + deltaY < splitWidth) + deltaY = splitWidth - c->height(); + ++i; + int rest = 0; + for (iCtrlEdit ii = i; ii != ctrlEditList.end(); ++ii) + rest += (*ii)->cheight(); + if (rest < deltaY) + deltaY = rest; + c->setHeight(c->height() + deltaY); + layoutPanelB(c); + y += deltaY; + } + // + // layout rest, add deltaY vertical + // + int rest = 0; + for (iCtrlEdit ii = i; ii != ctrlEditList.end(); ++ii) { + CtrlEdit* c = *ii; + rest += c->cheight(); + } + if (rest < deltaY) + deltaY = rest; + rest = deltaY; + for (; i != ctrlEditList.end(); ++i) { + CtrlEdit* c = *i; + int d = c->cheight(); + if (d > deltaY) + d = deltaY; + c->setHeight(c->height() - d); + c->y = y; + layoutPanelB(c); + y += c->height(); + deltaY -= d; + if (deltaY == 0) + break; + } + if (i != ctrlEditList.end()) + ++i; + for (; i != ctrlEditList.end(); ++i) { + CtrlEdit* c = *i; + c->y = y; + y += c->height(); + } + if (curSplitter == 0) + resizeController(ctrlHeight - rest); + else + widget()->update(rPanelB | rCanvasB); + splitterY = pos.y(); + updatePartControllerList(); + return; + } + if (rCanvasA.contains(pos)) { + mouseMoveCanvasA(pos - rCanvasA.topLeft()); + return; + } + if (button == 0) { + if (rPanelB.contains(pos) || rCanvasB.contains(pos)) { + int y = pos.y() - rPanelB.y(); + int k = 0; + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i, ++k) { + CtrlEdit* c = *i; + if (y >= c->y && y < (c->y + splitWidth)) { + curSplitter = k; + setCursor(); + return; + } + int ypos = y - c->y - splitWidth; + if (ypos >= 0) + emit yChanged(c->pixel2val(ypos)); + } + } + if (curSplitter != -1) { + curSplitter = -1; + setCursor(); + } + return; + } + if (rCanvasB.contains(pos)) { + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) { + CtrlEdit* c = *i; + QRect r(rCanvasB.x(), rCanvasB.y() + c->y + splitWidth, + rCanvasB.width(), c->cheight()); + if (r.contains(pos)) { + c->mouseMove(pos - r.topLeft()); + break; + } + } + } + } + +//--------------------------------------------------------- +// mouseRelease +//--------------------------------------------------------- + +void EventCanvas::mouseRelease(QMouseEvent* me) + { + if (keyDown != -1) { + noteOff(keyDown); + keyDown = -1; + } + if (dragSplitter) { + dragSplitter = false; + return; + } + QPoint pos(me->pos()); + if (rCanvasA.contains(pos)) { + mouseReleaseCanvasA(me); + return; + } + if (rCanvasB.contains(pos)) { + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) { + CtrlEdit* c = *i; + QRect r(rCanvasB.x(), rCanvasB.y() + c->y + splitWidth, + rCanvasB.width(), c->cheight()); + if (r.contains(pos)) { + c->mouseRelease(); + break; + } + } + } + } + +//--------------------------------------------------------- +// setCurPart +//--------------------------------------------------------- + +void EventCanvas::setCurPart(Part* part) + { + curPart = part; + + if (curPart->raster() != -1) + editor->setRaster(curPart->raster()); + if (curPart->quant() != -1) + editor->setQuant(curPart->quant()); + if (curPart->xmag() != 0.0) + editor->setXmag(curPart->xmag()); + curPart->setRaster(editor->raster()); + curPart->setQuant(editor->quant()); + curPart->setXmag(editor->xmag()); + setPart(*curPart, curPart->end()); + editor->setWindowTitle(getCaption()); + } + +//--------------------------------------------------------- +// getTextDrag +//--------------------------------------------------------- + +QMimeData* EventCanvas::getTextDrag() + { + //--------------------------------------------------- + // generate event list from selected events + //--------------------------------------------------- + + EventList el; + unsigned startTick = INT_MAX; + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!i->second->isSelected()) + continue; + CItem* ne = i->second; + Event e = ne->event; + if (startTick == INT_MAX) + startTick = e.tick(); + el.add(e); + } + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + Xml xml(&buffer); + xml.header(); + + xml.stag("eventlist"); + for (ciEvent e = el.begin(); e != el.end(); ++e) + e->second.write(xml, -startTick); + xml.etag("eventlist"); + + QByteArray data = buffer.buffer(); + QMimeData* drag = new QMimeData; + drag->setData("text/x-muse-eventlist", data); + buffer.close(); + return drag; + } + +//--------------------------------------------------------- +// pasteAt +//--------------------------------------------------------- + +void EventCanvas::pasteAt(const QString& pt, unsigned pos) + { + QDomDocument doc; + + if (!doc.setContent(pt, false)) { + printf("MusE:pasteAt(): syntax error\n"); + printf(">>%s<<\n", pt.toLatin1().data()); + return; + } + for (QDomNode node = doc.documentElement(); !node.isNull(); node = node.nextSibling()) { + QDomElement e = node.toElement(); + if (e.isNull()) + continue; + if (e.tagName() == "eventlist") { + EventList el; + el.read(node.firstChild(), true); + song->startUndo(); + for (iEvent i = el.begin(); i != el.end(); ++i) { + Event e = i->second; + e.setTick(e.tick() + pos - curPart->tick()); + audio->msgAddEvent(e, curPart, false); + } + song->endUndo(SC_EVENT_INSERTED); + } + else + printf("MusE:pasteAt(): tag %s not supported\n", e.tagName().toLatin1().data()); + } + } + +//--------------------------------------------------------- +// midiNote +//--------------------------------------------------------- + +void EventCanvas::midiNote(const MidiEvent& me) + { + if (me.type() != ME_NOTEON) + return; + int pitch = me.dataA(); + int velo = me.dataB(); + + if (editor->midiIn() && editor->stepRec() && curPart + && !audio->isPlaying() && velo && pos[0].tick() >= startTick + && pos[0].tick() < endTick + && !(keyState & Qt::AltModifier)) { + int len = editor->quant(); + unsigned tick = pos[0].tick(); //CDW + unsigned starttick = tick; + if (keyState & Qt::ShiftModifier) + tick -= editor->rasterStep(tick); + + // + // extend len of last note? + // + EventList* events = curPart->events(); + if (keyState & 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()) == starttick)) { + Event e = ev.clone(); + e.setLenTick(ev.lenTick() + editor->rasterStep(starttick)); + audio->msgChangeEvent(ev, e, curPart); + tick += editor->rasterStep(tick); + if (tick != song->cpos()) { + Pos p(tick, AL::TICKS); + 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) { + audio->msgDeleteEvent(ev, curPart); + if (keyState & Qt::ShiftModifier) + tick += editor->rasterStep(tick); + return; + } + } + Event e(Note); + e.setTick(tick - curPart->tick()); + e.setPitch(pitch); + e.setVelo(velo); + e.setLenTick(len); + audio->msgAddEvent(e, curPart); + tick += editor->rasterStep(tick); + if (tick != song->cpos()) { + Pos p(tick, AL::TICKS); + song->setPos(0, p, true, false, true); + } + } + } + +//--------------------------------------------------------- +// magChanged +//--------------------------------------------------------- + +void EventCanvas::magChanged() + { + if (part()) { + part()->setXmag(_xmag); + } + } + +//--------------------------------------------------------- +// updatePartControllerList +//--------------------------------------------------------- + +void EventCanvas::updatePartControllerList() + { + if (curPart == 0) + return; + CtrlCanvasList* cl = curPart->getCtrlCanvasList(); + cl->clear(); + for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) { + CtrlCanvas cc; + cc.ctrlId = (*i)->ctrlId; + cc.height = (*i)->height(); + cl->push_back(cc); + } + } + diff --git a/muse_qt4_evolution/muse/midiedit/ecanvas.h b/muse_qt4_evolution/muse/midiedit/ecanvas.h new file mode 100644 index 00000000..f128e5fa --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/ecanvas.h @@ -0,0 +1,173 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __ECANVAS_H__ +#define __ECANVAS_H__ + +#include "al/pos.h" +#include "awl/tcanvas.h" +#include "widgets/noteinfo.h" +#include "citem.h" +#include "ctrl/ctrledit.h" +#include "widgets/tb1.h" + +class MidiTrack; +class MidiEditor; +class MidiEvent; +class Part; +class Event; +class CtrlEdit; + +//--------------------------------------------------------- +// EventCanvas +//--------------------------------------------------------- + +class EventCanvas : public TimeCanvas { + Q_OBJECT + + int startPitch; // on start dragging events + int deltaPitch; + int keyDown; // pressed key on piano keypad (or drum instrument list) + int playedPitch; + + void noteOn(int pitch, int velocity, bool shift); + void noteOff(int pitch); + virtual void layout(); + virtual void magChanged(); + + protected: + enum DragMode { + DRAG_OFF, DRAG_NEW, + DRAG_MOVE_START, DRAG_MOVE, + DRAG_COPY_START, DRAG_COPY, + DRAGX_MOVE, DRAGY_MOVE, + DRAGX_COPY, DRAGY_COPY, + DRAG_DELETE, + DRAG_RESIZE, DRAG_LASSO_START, DRAG_LASSO, + }; + + enum DragType { + MOVE_MOVE, MOVE_COPY + }; + + CtrlEditList ctrlEditList; + MidiEditor* editor; + CItemList items; + CItemList moving; + CItem* curItem; + Part* curPart; + int canvasTools; + int curSplitter; // -1 mouse not in splitter + bool dragSplitter; + int splitterY; + + DragMode drag; + QRect lasso; + QPoint start; + QMenu* itemPopupMenu; + QMenu* canvasPopupMenu; + + unsigned startTick, endTick; + int curVelo; + + virtual void mousePress(QMouseEvent*); + virtual void mouseDoubleClick(QMouseEvent*); + virtual void mouseMove(QPoint); + virtual void enterB(); + virtual void leaveB(); + virtual void mouseRelease(QMouseEvent*); + void layoutPanelB(CtrlEdit* c); + + void updateSelection(); + virtual CItem* searchItem(const QPoint& p) const = 0; + virtual void addItem(Part*, const Event&) = 0; + virtual void moveItem(CItem*, DragType) = 0; + virtual CItem* newItem(const QPoint&, int state) = 0; + virtual void newItem(CItem*, bool noSnap=false) = 0; + virtual bool deleteItem(CItem*) = 0; + virtual void resizeItem(CItem*, bool noSnap=false) = 0; + + virtual void startDrag(CItem*, bool) {} + virtual QMenu* genItemPopup(CItem*) { return 0; } + virtual void itemPopup(CItem*, int, const QPoint&) {} + virtual void itemReleased() {} + virtual void itemPressed(const CItem*) {} + virtual void itemMoved(const CItem*) {} + + virtual void addController(); + + void endMoveItems(DragType); + virtual void selectItem(CItem* e, bool); + virtual void deselectAll(); + QMenu* genCanvasPopup(); + void canvasPopup(int); + virtual void startUndo(DragType); + virtual void endUndo(DragType); + virtual void selectLasso(bool) {} + void setCursor(); + virtual void deleteItem(const QPoint&); + void moveItems(const QPoint& pos, int dir); + void mousePressCanvasA(QPoint pos); + void mousePressCanvasA(QMouseEvent*); + void mouseMoveCanvasA(QPoint pos); + void mouseReleaseCanvasA(QMouseEvent*); + + virtual void paintControllerCanvas(QPainter&, QRect); + virtual void paintControllerPanel(QPainter&, QRect); + + void pasteAt(const QString& pt, unsigned pos); + void updatePartControllerList(); + + private slots: + void removeController(QAction*); + void midiNote(const MidiEvent&); + + public slots: + void setQuant(int) { update(); } + void songChanged(int); + + signals: + void selectionChanged(int, Event&, Part*); + void enterCanvas(); + void yChanged(int); // emitted from mouseMove in controller canvas + + public: + EventCanvas(MidiEditor*, TimeCanvasType); + MidiTrack* track() const; + Part* part() const { return curPart; } + QString getCaption() const; + void range(AL::Pos& s, AL::Pos& e) const; + void selectFirst(); + virtual void modifySelected(NoteInfo::ValType, int) {} + virtual void keyPress(QKeyEvent*); + int selectionSize() const; + void setCurPart(Part*); + QMimeData* getTextDrag(); + CItemList* getItems() { return &items; } + CtrlEditList* getCtrlEditors() { return &ctrlEditList; } + const CtrlEditList* getCtrlEditors() const { return &ctrlEditList; } + void addController(int id, int h); + void layout1(); + }; + +extern void paintVLine(QPainter& p, int y1, int y2, int x); + +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/gatetime.cpp b/muse_qt4_evolution/muse/midiedit/gatetime.cpp new file mode 100644 index 00000000..862d4aaf --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/gatetime.cpp @@ -0,0 +1,105 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "gatetime.h" +#include "song.h" +#include "tb1.h" + +//--------------------------------------------------------- +// GateTime +//--------------------------------------------------------- + +GateTime::GateTime(QWidget*) + : MidiCmdDialog() + { + setWindowTitle(tr("MusE: Modify Gate Time")); + QWidget* gateTime = new QWidget; + gt.setupUi(gateTime); + layout->addWidget(gateTime); + layout->addStretch(10); + _rateVal = 0; + _offsetVal = 0; + gt.rate->setValue(_rateVal); + gt.offset->setValue(_offsetVal); + } + +//--------------------------------------------------------- +// accept +//--------------------------------------------------------- + +void GateTime::accept() + { + _rateVal = gt.rate->value(); + _offsetVal = gt.offset->value(); + MidiCmdDialog::accept(); + } + +//--------------------------------------------------------- +// MidifyGateTime +//--------------------------------------------------------- + +ModifyGateTimeCmd::ModifyGateTimeCmd(MidiEditor* e) + : MidiCmd(e) + { + dialog = 0; + } + +//--------------------------------------------------------- +// guiDialog +//--------------------------------------------------------- + +MidiCmdDialog* ModifyGateTimeCmd::guiDialog() + { + if (dialog == 0) + dialog = new GateTime(0); + return dialog; + } + +//--------------------------------------------------------- +// process +//--------------------------------------------------------- + +void ModifyGateTimeCmd::process(CItemList* items) + { + int rate = dialog->rateVal(); + int offset = dialog->offsetVal(); + + for (iCItem k = items->begin(); k != items->end(); ++k) { + CItem* item = k->second; + Event event = item->event; + if (event.type() != Note) + continue; + + if (itemInRange(item)) { + unsigned len = event.lenTick(); + len = rate ? (len * 100) / rate : 1; + len += offset; + if (len <= 1) + len = 1; + + if (event.lenTick() != len) { + Event newEvent = event.clone(); + newEvent.setLenTick(len); + changeEvent(event, newEvent, item->part); + } + } + } + } + diff --git a/muse_qt4_evolution/muse/midiedit/gatetime.h b/muse_qt4_evolution/muse/midiedit/gatetime.h new file mode 100644 index 00000000..699b7c61 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/gatetime.h @@ -0,0 +1,62 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __GATETIME_H__ +#define __GATETIME_H__ + +#include "ui_gatetime.h" +#include "midicmd.h" + +//--------------------------------------------------------- +// GateTime +//--------------------------------------------------------- + +class GateTime : public MidiCmdDialog { + Q_OBJECT + + Ui::GateTimeBase gt; + int _rateVal; + int _offsetVal; + + protected slots: + void accept(); + + public: + GateTime(QWidget* parent = 0); + int rateVal() const { return _rateVal; } + int offsetVal() const { return _offsetVal; } + }; + +//--------------------------------------------------------- +// ModifyGateTimeCmd +//--------------------------------------------------------- + +class ModifyGateTimeCmd : public MidiCmd + { + GateTime* dialog; + virtual MidiCmdDialog* guiDialog(); + virtual void process(CItemList* items); + + public: + ModifyGateTimeCmd(MidiEditor* e); + }; + +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/gatetime.ui b/muse_qt4_evolution/muse/midiedit/gatetime.ui new file mode 100644 index 00000000..e1b92e7e --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/gatetime.ui @@ -0,0 +1,85 @@ +<ui version="4.0" > + <author></author> + <comment></comment> + <exportmacro></exportmacro> + <class>GateTimeBase</class> + <widget class="QWidget" name="GateTimeBase" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>262</width> + <height>149</height> + </rect> + </property> + <property name="windowTitle" > + <string>MusE: Modify Gate Time</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QGroupBox" name="GroupBox3" > + <property name="title" > + <string>Values</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>6</number> + </property> + <property name="spacing" > + <number>3</number> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="TextLabel3" > + <property name="text" > + <string>Rate:</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="TextLabel4" > + <property name="text" > + <string>Offset:</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QSpinBox" name="rate" > + <property name="suffix" > + <string>%</string> + </property> + <property name="maximum" > + <number>200</number> + </property> + <property name="value" > + <number>100</number> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QSpinBox" name="offset" > + <property name="maximum" > + <number>999</number> + </property> + <property name="minimum" > + <number>-999</number> + </property> + <property name="singleStep" > + <number>1</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> + <resources/> + <connections/> +</ui> diff --git a/muse_qt4_evolution/muse/midiedit/midicmd.cpp b/muse_qt4_evolution/muse/midiedit/midicmd.cpp new file mode 100644 index 00000000..bb6b1972 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/midicmd.cpp @@ -0,0 +1,135 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "midicmd.h" +#include "song.h" +#include "gatetime.h" +#include "velocity.h" +#include "audio.h" +#include "midieditor.h" +#include "widgets/tb1.h" + +//========================================================== +// class MidiCmd is an attempt to formalize the +// interface between midi command code and MusE. +// Maybe this can be extended to an specialized +// plugin interface +//========================================================== + +//--------------------------------------------------------- +// MidiCmdDialog +//--------------------------------------------------------- + +MidiCmdDialog::MidiCmdDialog() + : QDialog() + { + QWidget* rangeWidget = new QWidget; + mc.setupUi(rangeWidget); + layout = new QVBoxLayout; + setLayout(layout); + layout->addWidget(rangeWidget); + rangeGroup = new QButtonGroup(this); + rangeGroup->setExclusive(true); + rangeGroup->addButton(mc.allEventsButton, RANGE_ALL); + rangeGroup->addButton(mc.selectedEventsButton, RANGE_SELECTED); + rangeGroup->addButton(mc.loopedEventsButton, RANGE_LOOPED); + rangeGroup->addButton(mc.selectedLoopedButton, RANGE_SELECTED | RANGE_LOOPED); + mc.allEventsButton->setChecked(true); + } + +//--------------------------------------------------------- +// setRange +//--------------------------------------------------------- + +void MidiCmdDialog::setRange(int id) + { + if (rangeGroup->button(id)) + rangeGroup->button(id)->setChecked(true); + else + printf("setRange: not button %d!\n", id); + } + +//--------------------------------------------------------- +// accept +//--------------------------------------------------------- + +void MidiCmdDialog::accept() + { + _range = rangeGroup->checkedId(); + QDialog::accept(); + } + +//--------------------------------------------------------- +// MidiCmd +//--------------------------------------------------------- + +MidiCmd::MidiCmd(MidiEditor* e) + { + editor = e; + } + +//--------------------------------------------------------- +// processEvents +//--------------------------------------------------------- + +void MidiCmd::processEvents(CItemList* items) + { + MidiCmdDialog* dialog = guiDialog(); + range = editor->applyTo(); + dialog->setRange(range); + bool rv = dialog->exec(); + if (!rv) + return; + range = dialog->range(); // all, selected, looped, sel+loop + editor->setApplyTo(range); + + modified = 0; + song->startUndo(); + process(items); + song->endUndo(modified); + } + +//--------------------------------------------------------- +// eventInRange +//--------------------------------------------------------- + +bool MidiCmd::itemInRange(CItem* item) + { + unsigned tick = item->event.tick(); + bool selected = item->isSelected(); + bool inLoop = (tick >= song->lpos()) && (tick < song->rpos()); + return ( + (range == 0) + || (range == 1 && selected) + || (range == 2 && inLoop) + || (range == 3 && selected && inLoop) + ); + } + +//--------------------------------------------------------- +// changeEvent +//--------------------------------------------------------- + +void MidiCmd::changeEvent(Event oldEvent, Event newEvent, Part* part) + { + audio->msgChangeEvent(oldEvent, newEvent, part, false); + modified = SC_EVENT_MODIFIED; + } + diff --git a/muse_qt4_evolution/muse/midiedit/midicmd.h b/muse_qt4_evolution/muse/midiedit/midicmd.h new file mode 100644 index 00000000..f78f9cb9 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/midicmd.h @@ -0,0 +1,81 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __MIDICMD_H__ +#define __MIDICMD_H__ + +#include "citem.h" +#include "ui_midicmd.h" + +class MidiEditor; +class MidiCmdDialog; + +//--------------------------------------------------------- +// MidiCmdDialog +// GUI base class for midiCmd +//--------------------------------------------------------- + +class MidiCmdDialog : public QDialog + { + Q_OBJECT + + QButtonGroup* rangeGroup; + int _range; + Ui::MidiCmd mc; + + protected: + void accept(); + QVBoxLayout* layout; + + public: + MidiCmdDialog(); + int range() const { return _range; } + void setRange(int); + }; + +//--------------------------------------------------------- +// MidiCmd +// abstract base class for midi commands +//--------------------------------------------------------- + +class MidiCmd { + int modified; + + protected: + MidiEditor* editor; + int range; + + // convenience classes for derived classes + bool itemInRange(CItem* item); + void changeEvent(Event oldEvent, Event newEvent, Part* part); + + // virtual functions provided by derived classes + virtual void process(CItemList*) = 0; + virtual MidiCmdDialog* guiDialog() { return 0; } + + public: + MidiCmd(MidiEditor*); + virtual ~MidiCmd() {} + void processEvents(CItemList*); + }; + + +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/midicmd.ui b/muse_qt4_evolution/muse/midiedit/midicmd.ui new file mode 100644 index 00000000..e64e6ba4 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/midicmd.ui @@ -0,0 +1,76 @@ +<ui version="4.0" > + <author></author> + <comment></comment> + <exportmacro></exportmacro> + <class>MidiCmd</class> + <widget class="QWidget" name="MidiCmd" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>387</width> + <height>392</height> + </rect> + </property> + <property name="windowTitle" > + <string>MusE: Modify Gate Time</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QGroupBox" name="rangeGroup" > + <property name="title" > + <string>Apply To</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>6</number> + </property> + <property name="spacing" > + <number>3</number> + </property> + <item> + <widget class="QRadioButton" name="allEventsButton" > + <property name="text" > + <string>All Events</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="selectedEventsButton" > + <property name="text" > + <string>Selected Events</string> + </property> + <property name="checked" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="loopedEventsButton" > + <property name="text" > + <string>Looped Events</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="selectedLoopedButton" > + <property name="text" > + <string>Selected AND Looped</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> + <resources/> + <connections/> +</ui> diff --git a/muse_qt4_evolution/muse/midiedit/midieditor.cpp b/muse_qt4_evolution/muse/midiedit/midieditor.cpp new file mode 100644 index 00000000..d004ef29 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/midieditor.cpp @@ -0,0 +1,444 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "midieditor.h" +#include "part.h" +#include "song.h" +#include "widgets/tools.h" +#include "ecanvas.h" +#include "icons.h" +#include "audio.h" +#include "shortcuts.h" + +//--------------------------------------------------------- +// MidiEditor +//--------------------------------------------------------- + +MidiEditor::MidiEditor(PartList* pl) + : Editor() + { + _pl = pl; + selPart = 0; + tools2 = 0; + info = 0; + tools = 0; + toolbar = 0; + + QMenuBar* mb = menuBar(); + + //---------Menu------------------------------- + menuEdit = new QMenu(tr("&Edit")); + mb->addMenu(menuEdit); + + menuEdit->addAction(undoAction); + menuEdit->addAction(redoAction); + + menuEdit->addSeparator(); + cutAction = getAction("cut", this); + menuEdit->addAction(cutAction); + copyAction = getAction("copy", this); + menuEdit->addAction(copyAction); + pasteAction = getAction("paste", this); + menuEdit->addAction(pasteAction); + + speaker = new QAction(this); + speaker->setCheckable(true); + speaker->setIcon(QIcon(*speakerIcon)); + speaker->setText(tr("Play Events")); + speaker->setToolTip(tr("Play Events")); + + stepRecAction = new QAction(this); + stepRecAction->setIcon(QIcon(*steprecIcon)); + stepRecAction->setText(tr("Step Record")); + stepRecAction->setToolTip(tr("Step Record")); + stepRecAction->setCheckable(true); + + midiInAction = new QAction(this); + midiInAction->setIcon(QIcon(*midiinIcon)); + midiInAction->setText(tr("Midi Input")); + midiInAction->setToolTip(tr("Midi Input")); + midiInAction->setCheckable(true); + + followSongAction = new QAction(this); + followSongAction->setText("F"); + followSongAction->setToolTip(tr("Follow Song")); + followSongAction->setCheckable(true); + + connect(song, SIGNAL(songChanged(int)), SLOT(songChanged(int))); + + QClipboard* cb = QApplication::clipboard(); + connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged())); + connect(cb, SIGNAL(selectionChanged()), SLOT(clipboardChanged())); + connect(menuEdit, SIGNAL(triggered(QAction*)), SLOT(midiCmd(QAction*))); + } + +//--------------------------------------------------------- +// cmd +//--------------------------------------------------------- + +void MidiEditor::midiCmd(QAction* a) + { + QString s(a->data().toString()); + if (s == "cut") { + copy(); + song->startUndo(); + CItemList* items = canvas()->getItems(); + for (iCItem i = items->begin(); i != items->end(); ++i) { + if (!i->second->isSelected()) + continue; + CItem* e = i->second; + Event event = e->event; + audio->msgDeleteEvent(event, e->part, false); + } + song->endUndo(SC_EVENT_REMOVED); + } + else if (s == "copy") + copy(); + else + cmd(a); + } + +//--------------------------------------------------------- +// copy +// cut copy paste +//--------------------------------------------------------- + +void MidiEditor::copy() + { + QMimeData* drag = canvas()->getTextDrag(); + if (drag) + QApplication::clipboard()->setMimeData(drag, QClipboard::Selection); + } + + +//--------------------------------------------------------- +// setPos +// snap locator positioning +//--------------------------------------------------------- + +void MidiEditor::setPos(int idx, const AL::Pos& pos) + { + song->setPos(idx, pos.snaped(_raster)); + } + +//--------------------------------------------------------- +// genPartlist +//--------------------------------------------------------- + +void MidiEditor::genPartlist() + { + MidiTrackList* tl = song->midis(); + PartList* npl = new PartList; + for (iPart ip = _pl->begin(); ip != _pl->end(); ++ip) { + Part* part = ip->second; + for (iMidiTrack it = tl->begin(); it != tl->end(); ++it) { + PartList* pl2 = (*it)->parts(); + iPart ip2 = pl2->begin(); + for (; ip2 != pl2->end(); ++ip2) + if (ip2->second == part) { + npl->add(part); + break; + } + if (ip2 != pl2->end()) + break; + } + } + delete _pl; + _pl = npl; + for (iPart ip = _pl->begin(); ip != _pl->end(); ++ip) { + if (ip->second == selPart) + return; + } + if (_pl->empty()) + return; + selPart = _pl->begin()->second; + if (canvas()) + canvas()->setCurPart(selPart); + } + +//--------------------------------------------------------- +// MidiEditor +//--------------------------------------------------------- + +MidiEditor::~MidiEditor() + { + if (_pl) + delete _pl; + } + +//--------------------------------------------------------- +// writePartList +//--------------------------------------------------------- + +void MidiEditor::writePartList(Xml& xml) const + { + for (ciPart p = _pl->begin(); p != _pl->end(); ++p) { + Part* part = p->second; + Track* track = part->track(); + int trkIdx = song->tracks()->indexOf(track); + int partIdx = track->parts()->index(part); + xml.stag("part"); + xml.put(QString("%1:%2").arg(trkIdx).arg(partIdx)); + xml.etag("part"); + } + } + +//--------------------------------------------------------- +// songChanged +//--------------------------------------------------------- + +void MidiEditor::songChanged(int type) + { + if (type & (SC_PART_REMOVED | SC_PART_MODIFIED + | SC_PART_INSERTED | SC_TRACK_REMOVED)) { + genPartlist(); + // close window if editor has no parts anymore + if (parts()->empty()) { + close(); + return; + } + } + canvas()->songChanged(type); + } + +//--------------------------------------------------------- +// setQuant +//--------------------------------------------------------- + +void MidiEditor::setQuant(int val) + { + _quant = val; + if (toolbar) + toolbar->setQuant(val); + if (canvas() && canvas()->part()) + canvas()->part()->setQuant(val); + } + +//--------------------------------------------------------- +// setRaster +//--------------------------------------------------------- + +void MidiEditor::setRaster(int val) + { + _raster = val; + if (toolbar) + toolbar->setRaster(val); + if (canvas()) { + canvas()->setRaster(val); + if (canvas()->part()) + canvas()->part()->setRaster(val); + } + } + +//--------------------------------------------------------- +// setApplyTo +//--------------------------------------------------------- + +void MidiEditor::setApplyTo(int val) + { + _applyTo = val; + if (toolbar) + toolbar->setApplyTo(_applyTo); + } + +//--------------------------------------------------------- +// rasterStep +//--------------------------------------------------------- + +int MidiEditor::rasterStep(unsigned tick) const + { + return AL::sigmap.rasterStep(tick, raster()); + } + +//--------------------------------------------------------- +// rasterVal +//--------------------------------------------------------- + +unsigned MidiEditor::rasterVal(unsigned v) const + { + return AL::sigmap.raster(v, raster()); + } + +//--------------------------------------------------------- +// rasterVal1 +//--------------------------------------------------------- + +unsigned MidiEditor::rasterVal1(unsigned v) const + { + return AL::sigmap.raster1(v, raster()); + } + +//--------------------------------------------------------- +// rasterVal2 +//--------------------------------------------------------- + +unsigned MidiEditor::rasterVal2(unsigned v) const + { + return AL::sigmap.raster2(v, raster()); + } + +//--------------------------------------------------------- +// quantVal +//--------------------------------------------------------- + +int MidiEditor::quantVal(int v) const + { + int q = quant(); + int val = ((v+q/2)/q)*q; + if (val == 0) + val = q; + return val; + } + +//--------------------------------------------------------- +// xmag +//--------------------------------------------------------- + +double MidiEditor::xmag() const + { + return tcanvas->xmag(); + } + +//--------------------------------------------------------- +// setXmag +//--------------------------------------------------------- + +void MidiEditor::setXmag(double val) + { + if (canvas()) + canvas()->setMag(val, tcanvas->ymag()); + } + +//--------------------------------------------------------- +// tool +//--------------------------------------------------------- + +int MidiEditor::tool() const + { + return tcanvas->tool(); + } + +//--------------------------------------------------------- +// setTool +//--------------------------------------------------------- + +void MidiEditor::setTool(int n) + { + tcanvas->setTool(n); + tools2->set(n); + } + +//--------------------------------------------------------- +// canvasPos +//--------------------------------------------------------- + +QPoint MidiEditor::canvasPos() const + { + return tcanvas->getWPos(); + } + +//--------------------------------------------------------- +// setCanvasPos +//--------------------------------------------------------- + +void MidiEditor::setCanvasPos(const QPoint& p) + { + if (tcanvas) + tcanvas->setWPos(p); + } + +//--------------------------------------------------------- +// clipboardChanged +//--------------------------------------------------------- + +void MidiEditor::clipboardChanged() + { + QString stype("x-muse-eventlist"); + QString s = QApplication::clipboard()->text(stype, QClipboard::Selection); + pasteAction->setEnabled(!s.isEmpty()); + } + +//--------------------------------------------------------- +// selectionChanged +//--------------------------------------------------------- + +void MidiEditor::selectionChanged() + { + bool flag = canvas()->selectionSize() > 0; + cutAction->setEnabled(flag); + copyAction->setEnabled(flag); + } + +//--------------------------------------------------------- +// read +//--------------------------------------------------------- + +void MidiEditor::read(QDomNode node) + { + for (node = node.firstChild(); !node.isNull(); node = node.nextSibling()) { + QDomElement e = node.toElement(); + QString tag(e.tagName()); + if (tag == "CtrlEdit") { + int id = e.attribute("id","0").toInt(); + int h = e.attribute("h","50").toInt(); + canvas()->addController(id, h); + } + else + AL::readProperties(this, node); + } + canvas()->layout1(); + } + +//--------------------------------------------------------- +// write +//--------------------------------------------------------- + +void MidiEditor::write(Xml& xml) const + { + writePartList(xml); + xml.stag(metaObject()->className()); + xml.writeProperties(this); + const CtrlEditList* el = canvas()->getCtrlEditors(); + for (ciCtrlEdit i = el->begin(); i != el->end(); ++i) { + xml.tagE(QString("CtrlEdit h=\"%1\" id=\"%2\"") + .arg((*i)->height()).arg((*i)->ctrl()->id())); + } + xml.etag(metaObject()->className()); + } + +//--------------------------------------------------------- +// initFromPart +//--------------------------------------------------------- + +void MidiEditor::initFromPart() + { + Part* part = canvas()->part(); + CtrlCanvasList* cl = part->getCtrlCanvasList(); + if (!cl->empty()) { +#if 0 + for (iCtrlCanvas i = cl->begin(); i != cl->end(); ++i) { +printf("MidiEditor::initFromPart(): add controller %d %d\n", i->ctrlId, i->height); + canvas()->addController(i->ctrlId, i->height); + } +#endif + canvas()->layout1(); + } + } + diff --git a/muse_qt4_evolution/muse/midiedit/midieditor.h b/muse_qt4_evolution/muse/midiedit/midieditor.h new file mode 100644 index 00000000..3791e017 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/midieditor.h @@ -0,0 +1,147 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __MIDIEDITOR_H__ +#define __MIDIEDITOR_H__ + +#include "editor.h" + +namespace AL { + class Xml; + class Pos; + }; +using AL::Xml; + +class EditToolBar; +class NoteInfo; +class Toolbar1; +class Part; +class PartList; +class EventCanvas; +class ScrollScale; +class MTScale; +class WaveView; + +//--------------------------------------------------------- +// MidiEditor +//--------------------------------------------------------- + +class MidiEditor : public Editor { + Q_OBJECT + + Q_PROPERTY(int raster READ raster WRITE setRaster) + Q_PROPERTY(int quant READ quant WRITE setQuant) + Q_PROPERTY(bool stepRec READ stepRec WRITE setStepRec) + Q_PROPERTY(bool midiIn READ midiIn WRITE setMidiIn) + Q_PROPERTY(bool playEvents READ playEvents WRITE setPlayEvents) + Q_PROPERTY(bool followSong READ followSong WRITE setFollowSong) + Q_PROPERTY(double xmag READ xmag WRITE setXmag) + Q_PROPERTY(int applyTo READ applyTo WRITE setApplyTo) + Q_PROPERTY(QPoint canvasPos READ canvasPos WRITE setCanvasPos) + Q_PROPERTY(int tool READ tool WRITE setTool) + + bool _playEvents; + + EventCanvas* canvas() { return (EventCanvas*)tcanvas; } + const EventCanvas* canvas() const { return (EventCanvas*)tcanvas; } + void copy(); + + protected: + int _raster; + int _quant; + int _applyTo; + + PartList* _pl; + Part* selPart; + + QMenu *menuEdit; + QAction* speaker; + QAction* stepRecAction; + QAction* midiInAction; + QAction* followSongAction; + QAction* cutAction; + QAction* copyAction; + QAction* pasteAction; + + EditToolBar* tools2; + NoteInfo* info; + QToolBar* tools; + Toolbar1* toolbar; + + void writePartList(Xml&) const; + void genPartlist(); + void writeStatus(Xml&) const; + void initFromPart(); + + private slots: + void midiCmd(QAction*); + + protected slots: + void clipboardChanged(); // enable/disable "Paste" + void selectionChanged(); // enable/disable "Copy" & "Paste" + virtual void songChanged(int); //add virtual to allow editors that do not use + //ecancav to use there own songChanged slot + //and avoid crashing, like MidiTrackerEditor + void setPos(int, const AL::Pos&); + virtual void cmd(QAction*) = 0; + + public slots: + void setQuant(int val); + void setApplyTo(int val); + void setRaster(int val); + + public: + MidiEditor(PartList*); + virtual ~MidiEditor(); + + void read(QDomNode); + void write(Xml&) const; + void readStatus(QDomNode); + + PartList* parts() { return _pl; } + int rasterStep(unsigned tick) const; + unsigned rasterVal(unsigned v) const; + unsigned rasterVal1(unsigned v) const; + unsigned rasterVal2(unsigned v) const; + int quantVal(int v) const; + int raster() const { return _raster; } + int quant() const { return _quant; } + int applyTo() const { return _applyTo; } + bool playEvents() const { return speaker->isChecked(); } + void setPlayEvents(bool val) { speaker->setChecked(val); } + bool stepRec() const { return stepRecAction->isChecked(); } + void setStepRec(bool val) { stepRecAction->setChecked(val); } + bool midiIn() const { return midiInAction->isChecked(); } + void setMidiIn(bool val) { midiInAction->setChecked(val); } + bool followSong() const { return followSongAction->isChecked(); } + void setFollowSong(bool val) { followSongAction->setChecked(val); } + double xmag() const; + void setXmag(double val); + QPoint canvasPos() const; + void setCanvasPos(const QPoint&); + void setTool(int); + int tool() const; + enum { + CMD_CUT, CMD_COPY, CMD_PASTE + }; + }; + +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/miditracker.cpp b/muse_qt4_evolution/muse/midiedit/miditracker.cpp new file mode 100644 index 00000000..e345f454 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/miditracker.cpp @@ -0,0 +1,234 @@ +//================================================================= +// miditracker +// midi editor a la soundtracker +// miditracker.cpp +// (C) Copyright 2006 Nil Geisweiller (a_lin@user.sourceforge.net) +//================================================================= + +#include "ecanvas.h" +#include "miditracker.h" +#include "trackpattern.h" +#include "song.h" +#include "muse.h" +#include "part.h" + +#define MAX(x,y) (x>y?x:y) + +class TrackPattern; +//class EventCanvas; + +//--------------------------------------------------------- +// MidiTrackerEditor +//--------------------------------------------------------- + +MidiTrackerEditor::MidiTrackerEditor(PartList* pl, bool /*init*/) + : MidiEditor(pl) { + //-------- + //menuView + //-------- + menuView = menuBar()->addMenu(tr("&View")); + + //------- + //ToolBar + //------- + tools = addToolBar(tr("MidiTracker Tools")); + tools->addAction(undoAction); + tools->addAction(redoAction); + tools->addSeparator(); + + tools->addAction(stepRecAction); + stepRecAction->setChecked(INIT_SREC); + + tools->addAction(midiInAction); + midiInAction->setChecked(INIT_MIDIIN); + + tools->addAction(speaker); + speaker->setChecked(INIT_SPEAKER); + + tools->addAction(followSongAction); + followSongAction->setChecked(INIT_FOLLOW); + setFollow(INIT_FOLLOW); + + //panic button + QToolBar* panicToolbar = addToolBar(tr("Panic")); + panicToolbar->addAction(panicAction); + + //Transport Bar + QToolBar* transport = addToolBar(tr("Transport")); + muse->setupTransportToolbar(transport); + + //frame containing the different matrices of time and notes and FX + //QFrame* matricesFrame = new QFrame + + //second bar + addToolBarBreak(); + //row per bar + QToolBar* rowfeatures = addToolBar(tr("row features")); + + QLabel* quantLabel = new QLabel(tr("Quantize")); + quantLabel->setIndent(5); + rowfeatures->addWidget(quantLabel); + _quantCombo = new QuantCombo(rowfeatures); + rowfeatures->addWidget(_quantCombo); + + //QLabel* rpmLabel = new QLabel(tr("Row per bar"), rowfeatures); + //rpmLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + //rpmLabel->setIndent(3); + //rowfeatures->addWidget(rpmLabel); + //_rpmSpinBox = new QSpinBox(rowfeatures); + //_rpmSpinBox->setRange(1, 256); + //_rpmSpinBox->setFixedHeight(24); + //rowfeatures->addWidget(_rpmSpinBox); + + //init row per bar + setQuant(96); //corresponds to 16 quant + updateQuant(); + + //number of visible rows + //rowfeatures->addSeparator(); + /*QLabel* nvrLabel = new QLabel(tr("Number of visible rows"), rowfeatures); + nvrLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + nvrLabel->setIndent(3); + rowfeatures->addWidget(nvrLabel); + _nvrSpinBox = new QSpinBox(rowfeatures); + _nvrSpinBox->setRange(1, 256); + _nvrSpinBox->setFixedHeight(24); + rowfeatures->addWidget(_nvrSpinBox);*/ + //init number of visible row + /*setNumVisibleRows(20); + updateNumVisibleRows();*/ + + //evaluate fisrtTick and lastTick + unsigned firstTick = _pl->begin()->second->tick(); + unsigned lastTick = 0; + for(ciPart p = _pl->begin(); p != _pl->end(); ++p) { + Part* part = p->second; + lastTick = MAX(lastTick, part->endTick()); + } + + //------------- + //timing matrix + //------------- + _timingPattern = + new TimingPattern(this, "Timing", firstTick, lastTick, _quant); + int nbrRow = _timingPattern->getAbsoluteNbrRow(); + + //--------------- + //tracks matrices + //--------------- + for(ciPart p = _pl->begin(); p != _pl->end(); ++p) { + Part* part = p->second; + Track* track = part->track(); + if(track->isMidiTrack()) { + bool trackNotFound = true; + for(unsigned int i = 0; i < _trackPatterns.size(); i++) + if(_trackPatterns[i]->getTrack()==track) trackNotFound = false; + if(trackNotFound) { + TrackPattern* tp; + tp = new TrackPattern(this, track->name(), firstTick, lastTick, + _quant, pl, (MidiTrack*) track, nbrRow); + _trackPatterns.push_back(tp); + } + } + } + + //signals from TimingPattern and TrackPattern + connect(_timingPattern, SIGNAL(moveCurrentRow(unsigned)), + this, SLOT(updateMoveCurrentRow(unsigned))); + for(unsigned i = 0; i < _trackPatterns.size(); i++) { + connect(_trackPatterns[i], SIGNAL(moveCurrentRow(unsigned)), + this, SLOT(updateMoveCurrentRow(unsigned))); + } + + /* + addToolBarBreak(); + toolbar = new Toolbar1(initRaster, initQuant); + addToolBar(toolbar); + + addToolBarBreak(); + info = new NoteInfo(this); + addToolBar(info); + + setCentralWidget(tcanvas); + tcanvas->setCornerWidget(new QSizeGrip(tcanvas)); + + connect(song, SIGNAL(posChanged(int,const AL::Pos&,bool)), canvas(), + SLOT(setLocatorPos(int,const AL::Pos&,bool))); + connect(canvas(), SIGNAL(posChanged(int,const AL::Pos&)), + SLOT(setPos(int,const AL::Pos&))); + + connect(canvas(), SIGNAL(toolChanged(int)), tools2, SLOT(set(int))); + connect(tools2, SIGNAL(toolChanged(int)), canvas(), SLOT(setTool(int))); + + connect(info, SIGNAL(valueChanged(NoteInfo::ValType, int)), + SLOT(noteinfoChanged(NoteInfo::ValType, int))); + + connect(canvas(), SIGNAL(selectionChanged(int, Event&, Part*)), this, + SLOT(setSelection(int, Event&, Part*))); + + info->setEnabled(false); + + setWindowTitle(canvas()->getCaption()); + int s1, e; + canvas()->range(&s1, &e); + e += AL::sigmap.ticksMeasure(e); // show one more measure + canvas()->setTimeRange(s1, e);*/ + +} + +//--------------------------------------------------------- +// setQuant +//--------------------------------------------------------- +void MidiTrackerEditor::setQuant(int q) { + _quant = q; +} + +//--------------------------------------------------------- +// getQuant +//--------------------------------------------------------- +int MidiTrackerEditor::getQuant() { + return _quant; +} + +//--------------------------------------------------------- +// updateQuant +//--------------------------------------------------------- +void MidiTrackerEditor::updateQuant() { + _quantCombo->blockSignals(true); + _quantCombo->setQuant(_quant); + _quantCombo->blockSignals(false); +} + +//--------------------------------------------------------- +// setFollow +//--------------------------------------------------------- +void MidiTrackerEditor::setFollow(bool f) { + _follow = f; +} + +//--------------------------------------------------------- +// songChanged +//--------------------------------------------------------- +void MidiTrackerEditor::songChanged(int i) { + emit signalSongChanged(i); +} + +//--------------------------------------------------------- +// cmd +// pulldown menu commands +//--------------------------------------------------------- + +void MidiTrackerEditor::cmd(QAction* /*a*/) { + //int cmd = a->data().toInt(); + //canvas()->cmd(cmd, _quantStrength, _quantLimit, _quantLen); +} + +//void MidiTrackerEditor::resizeEvent(QResizeEvent *event) { +// for(int i = 0; i < _trackPatterns.size(); i++) +// _trackPatterns[i]->fillTrackPat(); +// _timingPattern->fillTimmingPat(); +//} + +void MidiTrackerEditor::updateMoveCurrentRow(unsigned index) { + emit signalMoveCurrentRow(index); +} diff --git a/muse_qt4_evolution/muse/midiedit/miditracker.h b/muse_qt4_evolution/muse/midiedit/miditracker.h new file mode 100644 index 00000000..5e6d706a --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/miditracker.h @@ -0,0 +1,76 @@ +//================================================================= +// miditracker +// midi editor a la soundtracker +// miditracker.h +// (C) Copyright 2006 Nil Geisweiller (a_lin@user.sourceforge.net) +//================================================================= + +#ifndef __MTEDITOR_H__ +#define __MTEDITOR_H__ + +#include "midieditor.h" +#include "trackpattern.h" +#include "quantcombo.h" +#include <vector> + + +class QuantCombo; + +namespace AL { + class Xml; + }; +using AL::Xml; + +//--------------------------------------------------------- +// MidiTrackerEditor +//--------------------------------------------------------- + +class MidiTrackerEditor : public MidiEditor { + Q_OBJECT + + private: + int _quant; + QuantCombo* _quantCombo; + //int _numVisibleRows; + //QSpinBox* _nvrSpinBox; + + QMenu* menuView; + bool _follow; + void setFollow(bool); + + std::vector<TrackPattern*> _trackPatterns; + TimingPattern* _timingPattern; + + private slots: + void updateMoveCurrentRow(unsigned); + virtual void cmd(QAction*); + + protected slots: + virtual void songChanged(int); + + public: + MidiTrackerEditor(PartList*, bool); + ~MidiTrackerEditor() {} + + void setQuant(int rpm); + int getQuant(); + void updateQuant(); //update the gui + + void setNumVisibleRows(int nvr); + int getNumVisibleRows(); + void updateNumVisibleRows(); //update the gui + + static const bool INIT_FOLLOW = false; + static const bool INIT_SPEAKER = true; + static const bool INIT_SREC = false; + static const bool INIT_MIDIIN = false; + + protected: + //void resizeEvent(QResizeEvent *event); + + signals: + void signalMoveCurrentRow(unsigned); + void signalSongChanged(int); +}; + +#endif diff --git a/muse_qt4_evolution/muse/midiedit/pianoroll.cpp b/muse_qt4_evolution/muse/midiedit/pianoroll.cpp new file mode 100644 index 00000000..c9be06e9 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/pianoroll.cpp @@ -0,0 +1,526 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "pianoroll.h" +#include "song.h" +#include "icons.h" +#include "cmd.h" +#include "muse.h" +#include "widgets/tools.h" +#include "quantconfig.h" +#include "shortcuts.h" +#include "audio.h" +#include "part.h" + +static int pianorollTools = PointerTool | PencilTool | RubberTool | DrawTool; +int PianoRoll::initWidth = PianoRoll::INIT_WIDTH; +int PianoRoll::initHeight = PianoRoll::INIT_HEIGHT; +int PianoRoll::initRaster = PianoRoll::INIT_RASTER; +int PianoRoll::initQuant = PianoRoll::INIT_QUANT; +int PianoRoll::initColorMode = PianoRoll::INIT_COLOR_MODE; +bool PianoRoll::initFollow = PianoRoll::INIT_FOLLOW; +bool PianoRoll::initSpeaker = PianoRoll::INIT_SPEAKER; +bool PianoRoll::initMidiin = PianoRoll::INIT_MIDIIN; +double PianoRoll::initXmag = 0.08; // PianoRoll::INIT_XMAG; (compiler problem?) +int PianoRoll::initApplyTo = PianoRoll::INIT_APPLY_TO; +int PianoRoll::initQuantStrength = PianoRoll::INIT_QUANT_STRENGTH; +int PianoRoll::initQuantLimit = PianoRoll::INIT_QUANT_LIMIT; +bool PianoRoll::initQuantLen = PianoRoll::INIT_QUANT_LEN; + +//--------------------------------------------------------- +// PianoRoll +//--------------------------------------------------------- + +PianoRoll::PianoRoll(PartList* pl, bool init) + : MidiEditor(pl) + { + _applyTo = initApplyTo; + _colorMode = initColorMode; + _quantStrength = initQuantStrength; + _quantLimit = initQuantLimit; + _quantLen = initQuantLen; + + deltaMode = false; + quantConfig = 0; + + tcanvas = new PianoCanvas(this); + QMenuBar* mb = menuBar(); + + menu_ids[CMD_EVENT_COLOR] = getAction("change_event_color", this); + menu_ids[CMD_CONFIG_QUANT] = getAction("config_quant", this); + + //---------Menu---------------------------------- + menuEdit->addSeparator(); + + QAction* a = getAction("delete", this); + menuEdit->addAction(a); + + menuEdit->addSeparator(); + + menuSelect = menuEdit->addMenu(QIcon(*selectIcon),tr("&Select")); + + menuSelect->addAction(getAction("sel_all", this)); + menuSelect->addAction(getAction("sel_none", this)); + menuSelect->addAction(getAction("sel_inv", this)); + menuSelect->addAction(getAction("sel_ins_loc", this)); + menuSelect->addAction(getAction("sel_out_loc", this)); + + menuConfig = mb->addMenu(tr("&Config")); + eventColor = menuConfig->addMenu(tr("event color")); + menu_ids[CMD_EVENT_COLOR] = eventColor->menuAction(); + + colorModeAction[0] = eventColor->addAction(tr("blue")); + colorModeAction[0]->setData(0); + colorModeAction[0]->setCheckable(true); + colorModeAction[1] = eventColor->addAction(tr("pitch colors")); + colorModeAction[1]->setData(1); + colorModeAction[1]->setCheckable(true); + colorModeAction[2] = eventColor->addAction(tr("velocity colors")); + colorModeAction[2]->setData(2); + colorModeAction[2]->setCheckable(true); + connect(eventColor, SIGNAL(triggered(QAction*)), SLOT(setEventColorMode(QAction*))); + + menuFunctions = mb->addMenu(tr("&Functions")); + + menuFunctions->addAction(getAction("midi_over_quant", this)); + menuFunctions->addAction(getAction("midi_quant_noteon", this)); + menuFunctions->addAction(getAction("midi_quant_noteoff", this)); + menuFunctions->addAction(getAction("midi_quant_iterative", this)); + + menuFunctions->addSeparator(); + + menu_ids[CMD_CONFIG_QUANT] = menuFunctions->addAction(tr("Config Quant...")); + connect(menu_ids[CMD_CONFIG_QUANT], SIGNAL(triggered()), this, SLOT(configQuant())); + + menuFunctions->addSeparator(); + + menuFunctions->addAction(getAction("midi_mod_gate_time", this)); + menuFunctions->addAction(getAction("midi_mod_velo", this)); + +#if 0 // TODO + menuFunctions->addAction(getAction("midi_crescendo", this)); + menuFunctions->addAction(getAction("midi_transpose", this)); + menuFunctions->addAction(getAction("midi_thin_out", this)); + menuFunctions->addAction(getAction("midi_erase_event", this)); + menuFunctions->addAction(getAction("midi_note_shift", this)); + menuFunctions->addAction(getAction("midi_move_clock", this)); + menuFunctions->addAction(getAction("midi_copy_measure", this)); + menuFunctions->addAction(getAction("midi_erase_measure", this)); + menuFunctions->addAction(getAction("midi_delete_measure", this)); + menuFunctions->addAction(getAction("midi_create_measure", this)); +#endif + + connect(menuSelect, SIGNAL(triggered(QAction*)), SLOT(cmd(QAction*))); + connect(menuFunctions, SIGNAL(triggered(QAction*)), SLOT(cmd(QAction*))); + + //---------ToolBar---------------------------------- + tools = addToolBar(tr("Pianoroll Tools")); + tools->addAction(undoAction); + tools->addAction(redoAction); + tools->addSeparator(); + + tools->addAction(stepRecAction); + stepRecAction->setChecked(INIT_SREC); + + tools->addAction(midiInAction); + midiInAction->setChecked(INIT_MIDIIN); + + tools->addAction(speaker); + speaker->setChecked(INIT_SPEAKER); + + tools->addAction(followSongAction); + followSongAction->setChecked(INIT_FOLLOW); + tcanvas->setFollow(INIT_FOLLOW); + + tools2 = new EditToolBar(this, pianorollTools); + addToolBar(tools2); + + QToolBar* panicToolbar = addToolBar(tr("Panic")); + panicToolbar->addAction(panicAction); + + //------------------------------------------------------------- + // Transport Bar + + QToolBar* transport = addToolBar(tr("Transport")); + muse->setupTransportToolbar(transport); + + addToolBarBreak(); + toolbar = new Toolbar1(initRaster, initQuant); + addToolBar(toolbar); + + addToolBarBreak(); + info = new NoteInfo(this); + addToolBar(info); + + setCentralWidget(tcanvas); + tcanvas->setCornerWidget(new QSizeGrip(tcanvas)); + + connect(song, SIGNAL(posChanged(int,const AL::Pos&,bool)), canvas(), SLOT(setLocatorPos(int,const AL::Pos&,bool))); + connect(canvas(), SIGNAL(posChanged(int,const AL::Pos&)), SLOT(setPos(int,const AL::Pos&))); + + connect(canvas(), SIGNAL(toolChanged(int)), tools2, SLOT(set(int))); + connect(tools2, SIGNAL(toolChanged(int)), canvas(), SLOT(setTool(int))); + + connect(info, SIGNAL(valueChanged(NoteInfo::ValType, int)), SLOT(noteinfoChanged(NoteInfo::ValType, int))); + + connect(canvas(), SIGNAL(selectionChanged(int, Event&, Part*)), this, + SLOT(setSelection(int, Event&, Part*))); + + info->setEnabled(false); + + setWindowTitle(canvas()->getCaption()); + Pos p1(0, AL::TICKS), p2(0, AL::TICKS); + canvas()->range(p1, p2); + p2 += AL::sigmap.ticksMeasure(p2.tick()); // show one more measure + canvas()->setTimeRange(p1, p2); + + // connect to toolbar + connect(canvas(), SIGNAL(pitchChanged(int)), toolbar, SLOT(setPitch(int))); + connect(canvas(), SIGNAL(yChanged(int)), toolbar, SLOT(setInt(int))); + connect(canvas(), SIGNAL(cursorPos(const AL::Pos&,bool)), toolbar, SLOT(setTime(const AL::Pos&,bool))); + connect(toolbar, SIGNAL(quantChanged(int)), SLOT(setQuant(int))); + connect(toolbar, SIGNAL(rasterChanged(int)),SLOT(setRaster(int))); + connect(toolbar, SIGNAL(toChanged(int)), SLOT(setApplyTo(int))); + connect(toolbar, SIGNAL(soloChanged(bool)), SLOT(soloChanged(bool))); + + setEventColorMode(_colorMode); + + clipboardChanged(); // enable/disable "Paste" + selectionChanged(); // enable/disable "Copy" & "Paste" + + // + // install misc shortcuts + // + QShortcut* sc = new QShortcut(Qt::Key_Escape, this); + sc->setContext(Qt::WindowShortcut); + connect(sc, SIGNAL(activated()), SLOT(close())); + + QSignalMapper* cmdMap = new QSignalMapper(this); + static const char* actions[] = { + "curpos_increase", "curpos_decrease", + "midi_insert_at_loc", + "midi_quant_1", "midi_quant_2", "midi_quant_3", "midi_quant_4", + "midi_quant_5", "midi_quant_6", "midi_quant_7", + "midi_quant_punct", "midi_quant_punct2", "midi_quant_triol", + }; + for (unsigned i = 0; i < sizeof(actions)/sizeof(*actions); ++i) { + a = getAction(actions[i], this); + addAction(a); + cmdMap->setMapping(a, a); + connect(a, SIGNAL(triggered()), cmdMap, SLOT(map())); + } + connect(cmdMap, SIGNAL(mapped(QObject*)), SLOT(pianoCmd(QObject*))); + + connect(song, SIGNAL(songChanged(int)), canvas(), SLOT(songChanged(int))); + connect(followSongAction, SIGNAL(toggled(bool)), canvas(), SLOT(setFollow(bool))); + canvas()->selectFirst(); + + Part* part = canvas()->part(); + setRaster(part->raster() != -1 ? part->raster() : initRaster); + setQuant(part->quant() != -1 ? part->quant() : initQuant); + setXmag(part->xmag() != -1.0 ? part->xmag() : initXmag); + + if (init) + initFromPart(); + else { + resize(initWidth, initHeight); + } + } + +//--------------------------------------------------------- +// cmd +// pulldown menu commands +//--------------------------------------------------------- + +void PianoRoll::cmd(QAction* a) + { + canvas()->cmd(a, _quantStrength, _quantLimit, _quantLen); + } + +//--------------------------------------------------------- +// setSelection +// update Info Line +//--------------------------------------------------------- + +void PianoRoll::setSelection(int tick, Event& e, Part* p) + { + int selections = canvas()->selectionSize(); + + selEvent = e; + selPart = p; + + if (selections > 1) { + info->setEnabled(true); + info->setDeltaMode(true); + if (!deltaMode) { + deltaMode = true; + info->setValues(0, 0, 0, 0, 0); + tickOffset = 0; + lenOffset = 0; + pitchOffset = 0; + veloOnOffset = 0; + veloOffOffset = 0; + } + } + else if (selections == 1) { + deltaMode = false; + info->setEnabled(true); + info->setDeltaMode(false); + info->setValues(tick, + selEvent.lenTick(), + selEvent.pitch(), + selEvent.velo(), + selEvent.veloOff()); + } + else { + deltaMode = false; + info->setEnabled(false); + } + selectionChanged(); + } + +//--------------------------------------------------------- +// edit currently selected Event +//--------------------------------------------------------- + +void PianoRoll::noteinfoChanged(NoteInfo::ValType type, int val) + { + int selections = canvas()->selectionSize(); + + if (selections == 0) { + printf("noteinfoChanged while nothing selected\n"); + } + else if (selections == 1) { + Event event = selEvent.clone(); + switch(type) { + case NoteInfo::VAL_TIME: + event.setTick(val - selPart->tick()); + break; + case NoteInfo::VAL_LEN: + event.setLenTick(val); + break; + case NoteInfo::VAL_VELON: + event.setVelo(val); + break; + case NoteInfo::VAL_VELOFF: + event.setVeloOff(val); + break; + case NoteInfo::VAL_PITCH: + event.setPitch(val); + break; + } + audio->msgChangeEvent(selEvent, event, selPart); + } + else { + // multiple events are selected; treat noteinfo values + // as offsets to event values + + int delta = 0; + switch (type) { + case NoteInfo::VAL_TIME: + delta = val - tickOffset; + tickOffset = val; + break; + case NoteInfo::VAL_LEN: + delta = val - lenOffset; + lenOffset = val; + break; + case NoteInfo::VAL_VELON: + delta = val - veloOnOffset; + veloOnOffset = val; + break; + case NoteInfo::VAL_VELOFF: + delta = val - veloOffOffset; + veloOffOffset = val; + break; + case NoteInfo::VAL_PITCH: + delta = val - pitchOffset; + pitchOffset = val; + break; + } + if (delta) + canvas()->modifySelected(type, delta); + } + } + +//--------------------------------------------------------- +// soloChanged +// signal from solo button +//--------------------------------------------------------- + +void PianoRoll::soloChanged(bool flag) + { + song->setSolo(canvas()->track(), flag); + } + +//--------------------------------------------------------- +// pianoCmd +//--------------------------------------------------------- + +void PianoRoll::pianoCmd(QObject* object) + { + QAction* a = (QAction*)object; + QString cmd(a->data().toString()); + + static int rasterTable[] = { + //-9----8- 7 6 5 4 3(1/4) 2 1 + 4, 8, 16, 32, 64, 128, 256, 512, 1024, // triple + 6, 12, 24, 48, 96, 192, 384, 768, 1536, + 9, 18, 36, 72, 144, 288, 576, 1152, 2304 // dot + }; + + int index; + int n = sizeof(rasterTable)/sizeof(*rasterTable); + for (index = 0; index < n; ++index) + if (rasterTable[index] == raster()) + break; + if (index == n) { + index = 0; + // raster 1 is not in table + } + int off = (index / 9) * 9; + index = index % 9; + + int val = 0; + + PianoCanvas* pc = canvas(); + + if (cmd == "curpos_increase") + canvas()->pianoCmd(MCMD_LEFT); + else if (cmd == "curpos_decrease") + canvas()->pianoCmd(MCMD_RIGHT); + else if (cmd == "midi_insert_at_loc") { + pc->pianoCmd(MCMD_INSERT); + return; + } + else if (cmd == "midi_quant_1") + val = rasterTable[8 + off]; + else if (cmd == "midi_quant_2") + val = rasterTable[7 + off]; + else if (cmd == "midi_quant_3") + val = rasterTable[6 + off]; + else if (cmd == "midi_quant_4") + val = rasterTable[5 + off]; + else if (cmd == "midi_quant_5") + val = rasterTable[4 + off]; + else if (cmd == "midi_quant_6") + val = rasterTable[3 + off]; + else if (cmd == "midi_quant_7") + val = rasterTable[2 + off]; + else if (cmd == "midi_quant_triol") + val = rasterTable[index + ((off == 0) ? 9 : 0)]; + else if (cmd == "change_event_color") { + _colorMode = (_colorMode + 1) % 3; + setEventColorMode(_colorMode); + return; + } + else if (cmd == "midi_quant_punct") + val = rasterTable[index + ((off == 18) ? 9 : 18)]; + else if (cmd == "midi_quant_punct2") { + if ((off == 18) && (index > 2)) { + val = rasterTable[index + 9 - 1]; + } + else if ((off == 9) && (index < 8)) { + val = rasterTable[index + 18 + 1]; + } + else + return; + } + else + printf("unknown cmd <%s>\n", cmd.toLatin1().data()); + setQuant(val); + setRaster(val); + toolbar->setQuant(quant()); + toolbar->setRaster(raster()); + } + +//--------------------------------------------------------- +// configQuant +//--------------------------------------------------------- + +void PianoRoll::configQuant() + { + QuantConfig quantConfig(_quantStrength, _quantLimit, _quantLen, this); + if (!quantConfig.exec()) + return; + _quantStrength = quantConfig.quantStrength(); + _quantLimit = quantConfig.quantLimit(); + _quantLen = quantConfig.doQuantLen(); + } + +//--------------------------------------------------------- +// setEventColorMode +//--------------------------------------------------------- + +void PianoRoll::setEventColorMode(QAction* a) + { + setEventColorMode(a->data().toInt()); + } + +void PianoRoll::setEventColorMode(int mode) + { + _colorMode = mode; + for (int i = 0; i < 3; ++i) + colorModeAction[i]->setChecked(mode == i); + canvas()->setColorMode(mode); + } + +//--------------------------------------------------------- +// readConfiguration +// read static init values +//--------------------------------------------------------- + +void PianoRoll::readConfiguration(QDomNode node) + { + for (node = node.firstChild(); !node.isNull(); node = node.nextSibling()) { + QDomElement e = node.toElement(); + QString tag(e.tagName()); + int i = e.text().toInt(); + if (tag == "width") + PianoRoll::initWidth = i; + else if (tag == "height") + PianoRoll::initHeight = i; + else if (tag == "raster") + PianoRoll::initRaster = i; + else if (tag == "quant") + PianoRoll::initQuant = i; + else + printf("MusE:PianoRoll: unknown tag %s\n", tag.toLatin1().data()); + } + } + +//--------------------------------------------------------- +// writeConfiguration +// write static init values +//--------------------------------------------------------- + +void PianoRoll::writeConfiguration(Xml& xml) + { + xml.stag("PianoRoll"); + if (PianoRoll::initWidth != PianoRoll::INIT_WIDTH) + xml.tag("width", PianoRoll::initWidth); + if (PianoRoll::initHeight != PianoRoll::INIT_HEIGHT) + xml.tag("height", PianoRoll::initHeight); + if (PianoRoll::initRaster != PianoRoll::INIT_RASTER) + xml.tag("raster", PianoRoll::initRaster); + if (PianoRoll::initQuant != PianoRoll::INIT_QUANT) + xml.tag("quant", PianoRoll::initQuant); + xml.etag("PianoRoll"); + } diff --git a/muse_qt4_evolution/muse/midiedit/pianoroll.h b/muse_qt4_evolution/muse/midiedit/pianoroll.h new file mode 100644 index 00000000..e510408c --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/pianoroll.h @@ -0,0 +1,126 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __PIANOROLL_H__ +#define __PIANOROLL_H__ + +#include "midieditor.h" +#include "prcanvas.h" + +namespace AL { + class Xml; + }; +using AL::Xml; + +class PianoCanvas; +class PartList; +class QuantConfig; +class Part; +class TimeCanvas; + +//--------------------------------------------------------- +// PianoRoll +//--------------------------------------------------------- + +class PianoRoll : public MidiEditor { + Q_OBJECT + + Q_PROPERTY(int colorMode READ colorMode WRITE setColorMode) + Q_PROPERTY(int quantStrength READ quantStrength WRITE setQuantStrength) + Q_PROPERTY(int quantLimit READ quantLimit WRITE setQuantLimit) + Q_PROPERTY(bool quantLen READ quantLen WRITE setQuantLen) + + int _quantStrength, _quantLimit; + bool _quantLen; + int _colorMode; + + Event selEvent; + + enum { CMD_EVENT_COLOR, CMD_CONFIG_QUANT, CMD_LAST }; + + QAction* menu_ids[CMD_LAST]; + QMenu *menuFunctions, *menuSelect, *menuConfig; + + int tickOffset; + int lenOffset; + int pitchOffset; + int veloOnOffset; + int veloOffOffset; + bool deltaMode; + + QAction* colorModeAction[3]; + QMenu* eventColor; + QuantConfig* quantConfig; + + QWidget* genToolbar(QWidget* parent); + void setEventColorMode(int); + PianoCanvas* canvas() { return (PianoCanvas*)tcanvas; } + const PianoCanvas* canvas() const { return (PianoCanvas*)tcanvas; } + + private slots: + void setSelection(int, Event&, Part*); + void noteinfoChanged(NoteInfo::ValType, int); + void soloChanged(bool flag); + void configQuant(); + + virtual void cmd(QAction*); + void setEventColorMode(QAction*); + void pianoCmd(QObject*); + + public: + PianoRoll(PartList*, bool); + ~PianoRoll() {} + + int colorMode() const { return _colorMode; } + void setColorMode(int val) { _colorMode = val; } + int quantStrength() const { return _quantStrength; } + int quantLimit() const { return _quantLimit; } + bool quantLen() const { return _quantLen; } + void setQuantStrength(int val) { _quantStrength = val; } + void setQuantLimit(int val) { _quantLimit = val; } + void setQuantLen(bool val) { _quantLen = val; } + + static void readConfiguration(QDomNode); + static void writeConfiguration(Xml&); + static int initRaster, initQuant, initWidth, initHeight; + static bool initFollow, initSpeaker, initMidiin; + static int initColorMode, initApplyTo; + static double initXmag; + static int initQuantStrength, initQuantLimit; + static bool initQuantLen; + + static const int INIT_WIDTH = 650; + static const int INIT_HEIGHT = 450; + static const int INIT_RASTER = 384 / 2; + static const int INIT_QUANT = 384 / 2; + static const bool INIT_FOLLOW = false; + static const bool INIT_SPEAKER = true; + static const bool INIT_MIDIIN = false; + static const bool INIT_SREC = false; + static const bool INIT_COLOR_MODE = 0; + static const double INIT_XMAG = 0.08; + static const int INIT_APPLY_TO = 0; + static const int INIT_QUANT_STRENGTH = 100; + static const int INIT_QUANT_LIMIT = 0; + static const int INIT_QUANT_LEN = false; + }; + +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/prcanvas.cpp b/muse_qt4_evolution/muse/midiedit/prcanvas.cpp new file mode 100644 index 00000000..f6890b02 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/prcanvas.cpp @@ -0,0 +1,773 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "midieditor.h" +#include "prcanvas.h" +#include "cmd.h" +#include "gatetime.h" +#include "velocity.h" +#include "song.h" +#include "audio.h" +#include "part.h" + +#include "velocity.h" +#include "gatetime.h" + +//--------------------------------------------------------- +// PianoCanvas +//--------------------------------------------------------- + +PianoCanvas::PianoCanvas(MidiEditor* pr) + : EventCanvas(pr, TIME_CANVAS_PIANOROLL) + { + verticalScrollBar()->setSingleStep(keyHeight/2); + playedPitch = -1; + colorMode = 0; + canvasTools = PointerTool | PencilTool | RubberTool | DrawTool; + + // register midi commands + cmdModifyGateTime = new ModifyGateTimeCmd(pr); + cmdModifyVelocity = new ModifyVelocityCmd(pr); + + songChanged(SC_TRACK_INSERTED); + } + +//--------------------------------------------------------- +// addItem +//--------------------------------------------------------- + +void PianoCanvas::addItem(Part* part, const Event& event) + { + CItem* item = new CItem(event, part); + int y = pitch2y(event.pitch()) + keyHeight/4 + (int)(wpos.y()/_ymag); + item->pos = event.pos() + *part; + unsigned time = item->pos.time(timeType()); + item->bbox = QRect(time, y, event.lenTick(), keyHeight/2); + items.add(item); + } + +//--------------------------------------------------------- +// timeTypeChanged +//--------------------------------------------------------- + +void PianoCanvas::timeTypeChanged() + { + // + // recalculate bounding boxes + // + for (iCItem i = items.begin(); i != items.end(); ++i) { + CItem* item = i->second; + unsigned t1 = item->event.pos().time(timeType()); + unsigned t2 = item->event.end().time(timeType()); + item->bbox.setX(t1 + (item->part)->time(timeType())); + item->bbox.setWidth(t2 - t1); + } + } + +//--------------------------------------------------------- +// paint +//--------------------------------------------------------- + +void PianoCanvas::paint(QPainter& p, QRect cr) + { + static QColor color1[12] = { + QColor(0xff, 0x3d, 0x39), + QColor(0x39, 0xff, 0x39), + QColor(0x39, 0x3d, 0xff), + QColor(0xff, 0xff, 0x39), + QColor(0xff, 0x3d, 0xff), + QColor(0x39, 0xff, 0xff), + QColor(0xff, 0x7e, 0x7a), + QColor(0x7a, 0x7e, 0xff), + QColor(0x7a, 0xff, 0x7a), + QColor(0xff, 0x7e, 0xbf), + QColor(0x7a, 0xbf, 0xff), + QColor(0xff, 0xbf, 0x7a) + }; + + QPoint off(MAP_OFFSET - wpos.x(), -wpos.y()); + p.translate(off); + cr.translate(-off); + + int time1 = lrint(cr.x() / _xmag); + int w = lrint(cr.width() / _xmag); + cr.setRect( + time1, + lrint(cr.y() / _ymag), + w, + lrint(cr.height() / _ymag) + ); + p.scale(_xmag, _ymag); + + int time2 = time1 + w; + + //--------------------------------------------------- + // draw Canvas Items + //--------------------------------------------------- + + p.setPen(QPen(Qt::black, 0.0)); + + for (iCItem i = items.begin(); i != items.end(); ++i) { + CItem* item = i->second; + QRect r(item->bbox); + if (r.x() >= time2) + break; + if (!cr.intersects(r)) + continue; + Event event(item->event); + + QColor color; + if (item->part != curPart) + p.setBrush(Qt::lightGray); + else { + if (item->isMoving) { + p.setBrush(Qt::gray); + p.drawRect(r); + p.setBrush(Qt::NoBrush); + int x = item->moving.tick(); + int y = item->my + item->bbox.height()/2; + int w = item->bbox.width(); + int h = item->bbox.height(); + p.drawRect(x, y, w, h); + } + else if (item->isSelected()) { + p.setBrush(Qt::black); + } + else { + if (colorMode == 1) + color = color1[event.pitch() % 12]; + else if (colorMode == 2) { + int velo = event.velo(); + if (velo < 64) + color.setRgb(velo*4, 0, 0xff); + else + color.setRgb(0xff, 0, (127-velo) * 4); + } + else + color.setRgb(0, 0, 255); + p.setBrush(color); + } + } + p.drawRect(r); + } + + //--------------------------------------------------- + // draw lasso + //--------------------------------------------------- + + p.resetMatrix(); + p.translate(rCanvasA.topLeft()); + + if (drag == DRAG_LASSO) { + p.setPen(Qt::blue); + p.setBrush(Qt::NoBrush); + p.drawRect(lasso); + QColor fillColor(Qt::blue); + fillColor.setAlpha(40); + QBrush fillBrush(fillColor); + p.fillRect(lasso,fillBrush); + } + } + +//--------------------------------------------------------- +// viewMouseDoubleClickEvent +//--------------------------------------------------------- + +void PianoCanvas::viewMouseDoubleClickEvent(QMouseEvent* event) + { + if ((_tool != PointerTool) && (event->button() != Qt::LeftButton)) { +// mousePress(event); + return; + } + } + +//--------------------------------------------------------- +// moveItem +// called after moving an object +//--------------------------------------------------------- + +void PianoCanvas::moveItem(CItem* item, DragType dtype) + { + Part* part = item->part; + Event event = item->event; + int npitch = y2pitch((int)((item->my - (int)(wpos.y()/_ymag) + + item->bbox.height())*_ymag)); + if ((curItem==item) //remove this if want to have all selection playing + && event.pitch() != npitch && editor->playEvents()) { + // release note: + MidiEvent ev1(0, 0, 0x90, playedPitch, 0); + track()->playMidiEvent(&ev1); + //remove below because the note is never cut off + //MidiEvent ev2(0, 0, 0x90, npitch + track()->transposition(), event.velo()); + //track()->playMidiEvent(&ev2); + } + + Event newEvent = event.clone(); + newEvent.setPitch(npitch); + newEvent.setPos(item->moving - *part); + + if (dtype == MOVE_COPY) + audio->msgAddEvent(newEvent, part, false); + else + audio->msgChangeEvent(event, newEvent, part, false); + } + +//--------------------------------------------------------- +// newItem(p, state) +//--------------------------------------------------------- + +CItem* PianoCanvas::newItem(const QPoint& p, int) + { + Pos opos(pix2pos(p.x())); + Pos pos(opos); + pos.downSnap(raster()); + + if (pos < partPos1 || pos >= partPos2) + return 0; + + int pitch = y2pitch(p.y()); + + Event e(Note); + e.setPitch(pitch); + e.setVelo(curVelo); + e.setPos(pos - *curPart); + + CItem* i = new CItem(e, curPart); + int l = timeType() == AL::TICKS ? e.lenTick() : e.lenFrame(); + int x = pos.time(timeType()); + int y = pitch2y(pitch) + keyHeight/4 + (int)(wpos.y() / _ymag); + i->bbox = QRect(x, y, l, keyHeight/2); + + return i; + } + +void PianoCanvas::newItem(CItem* item, bool noSnap) + { + Event event = item->event; + Pos p1(item->bbox.x(), timeType()); + Pos p2(item->bbox.x() + item->bbox.width(), timeType()); + int tickLen; + + if (noSnap) + tickLen = p2.tick() - p1.tick(); + else { + p1.downSnap(raster()); + tickLen = editor->quantVal(p2.tick() - p1.tick()); + } + + Part* part = item->part; + event.setPos(p1 - *part); + event.setLenTick(tickLen); + audio->msgAddEvent(event, part); + } + +//--------------------------------------------------------- +// resizeItem +//--------------------------------------------------------- + +void PianoCanvas::resizeItem(CItem* item, bool noSnap) + { + Event event = item->event; + Event newEvent = event.clone(); + int len; + if (noSnap) + len = item->bbox.width(); + else + len = editor->quantVal(item->bbox.width()); + newEvent.setLenTick(len); + audio->msgChangeEvent(event, newEvent, item->part); + } + +//--------------------------------------------------------- +// deleteItem +//--------------------------------------------------------- + +bool PianoCanvas::deleteItem(CItem* item) + { + if (item->part == curPart) { + Event ev = item->event; + audio->msgDeleteEvent(ev, curPart); + return true; + } + return false; + } + +//--------------------------------------------------------- +// pianoCmd +//--------------------------------------------------------- + +void PianoCanvas::pianoCmd(int cmd) + { + switch(cmd) { + case MCMD_LEFT: + { + int frames = pos[0].tick() - editor->rasterStep(pos[0].tick()); + if (frames < 0) + frames = 0; + Pos p(frames, AL::TICKS); + song->setPos(0, p, true, true, true); //CDW + } + break; + case MCMD_RIGHT: + { + Pos p(pos[0].tick() + editor->rasterStep(pos[0].tick()), AL::TICKS); + //if (p > part->tick()) + // p = part->tick(); + song->setPos(0, p, true, true, true); //CDW + } + break; + case MCMD_INSERT: + { + if (pos[0].tick() < startTick || pos[0].tick() >= endTick) + break; + Part* part = curPart; + + if (part == 0) + break; + song->startUndo(); + EventList* el = part->events(); + + std::list <Event> elist; + for (iEvent e = el->lower_bound(pos[0].tick() - 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()); + audio->msgChangeEvent(event, newEvent, part, false); + } + song->endUndo(SC_EVENT_MODIFIED); + Pos p(editor->rasterVal(pos[0].tick() + editor->rasterStep(pos[0].tick())), AL::TICKS); + song->setPos(0, p, true, false, true); + } + return; + case MCMD_DELETE: + if (pos[0].tick() < startTick || pos[0].tick() >= endTick) + break; + { + Part* part = curPart; + if (part == 0) + break; + song->startUndo(); + EventList* el = part->events(); + + std::list<Event> elist; + for (iEvent e = el->lower_bound(pos[0].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()); + audio->msgChangeEvent(event, newEvent, part, false); + } + song->endUndo(SC_EVENT_MODIFIED); + Pos p(editor->rasterVal(pos[0].tick() - editor->rasterStep(pos[0].tick())), AL::TICKS); + song->setPos(0, p, true, false, true); + } + break; + } + } + +//--------------------------------------------------------- +// cmd +// pulldown menu commands +//--------------------------------------------------------- + +void PianoCanvas::cmd(QAction* a, int quantStrength, int quantLimit, bool quantLen) + { + QString cmd(a->data().toString()); + + if (cmd == "paste") + paste(); + else if (cmd == "delete") { + if (selectionSize()) { + song->startUndo(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!i->second->isSelected()) + continue; + Event ev = i->second->event; + audio->msgDeleteEvent(ev, i->second->part, false); + } + song->endUndo(SC_EVENT_REMOVED); + } + return; + } + if (cmd == "midi_over_quant") + quantize(100, 1, quantLen); + else if (cmd == "midi_quant_noteon") + quantize(50, 1, false); + else if (cmd == "midi_quant_noteoff") + quantize(50, 1, true); + else if (cmd == "midi_quant_iterative") + quantize(quantStrength, quantLimit, quantLen); + else if (cmd == "sel_all") { + for (iCItem k = items.begin(); k != items.end(); ++k) { + if (!k->second->isSelected()) + selectItem(k->second, true); + } + } + else if (cmd == "sel_none") + deselectAll(); + else if (cmd == "sel_inv") { + for (iCItem k = items.begin(); k != items.end(); ++k) + selectItem(k->second, !k->second->isSelected()); + } + else if (cmd == "sel_ins_loc") { + for (iCItem k = items.begin(); k != items.end(); ++k) { + CItem* item = k->second; + Event event = item->event; + unsigned tick = event.tick(); + if (tick < song->lpos() || tick >= song->rpos()) + selectItem(k->second, false); + else + selectItem(k->second, true); + } + } + else if (cmd == "sel_out_loc") { + for (iCItem k = items.begin(); k != items.end(); ++k) { + CItem* item = k->second; + Event event = item->event; + unsigned tick = event.tick(); + if (tick < song->lpos() || tick >= song->rpos()) + selectItem(k->second, true); + else + selectItem(k->second, false); + } + } + else if (cmd == "midi_mod_gate_time") + cmdModifyGateTime->processEvents(&items); + else if (cmd == "midi_mod_velo") + cmdModifyVelocity->processEvents(&items); + updateSelection(); + widget()->update(); + } + +//--------------------------------------------------------- +// quantize +//--------------------------------------------------------- + +void PianoCanvas::quantize(int strength, int limit, bool quantLen) + { + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + CItem* item = k->second; + Event event = item->event; + Part* part = item->part; + if (event.type() != Note) + continue; + + if ((editor->applyTo() & CMD_RANGE_SELECTED) && !k->second->isSelected()) + continue; + + unsigned tick = event.tick() + part->tick(); + + if ((editor->applyTo() & CMD_RANGE_LOOP) + && ((tick < song->lpos() || tick >= song->rpos()))) + continue; + + unsigned len = event.lenTick(); + int tick2 = tick + len; + + // quant start position + int diff = editor->rasterVal(tick) - tick; + if (abs(diff) > limit) + tick += ((diff * strength) / 100); + + // quant len + diff = editor->rasterVal(tick2) - 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); + audio->msgChangeEvent(event, newEvent, part, false); + } + } + song->endUndo(SC_EVENT_MODIFIED); + } + +//--------------------------------------------------------- +// paste +// paste events +//--------------------------------------------------------- + +void PianoCanvas::paste() + { + QString stype("x-muse-eventlist"); + QString s = QApplication::clipboard()->text(stype, QClipboard::Selection); + pasteAt(s, song->cpos()); + } + +//--------------------------------------------------------- +// startDrag +//--------------------------------------------------------- + +void PianoCanvas::startDrag(CItem* /*item*/, bool /*copymode*/) + { +printf("PianoCanvas: startDrag\n"); + QMimeData* drag = getTextDrag(); + if (drag) { + QApplication::clipboard()->setMimeData(drag); +#if 0 + if (copymode) + drag->dragCopy(); + else + drag->dragMove(); +#endif + } + } + +//--------------------------------------------------------- +// dragEnterEvent +//--------------------------------------------------------- + +void PianoCanvas::dragEnterEvent(QDragEnterEvent*) + { +printf("PianoCanvas: dragEnterEvent\n"); +//TD event->accept(Q3TextDrag::canDecode(event)); + } + +//--------------------------------------------------------- +// dragMoveEvent +//--------------------------------------------------------- + +void PianoCanvas::dragMoveEvent(QDragMoveEvent*) + { + printf("drag move %p\n", this); + } + +//--------------------------------------------------------- +// dragLeaveEvent +//--------------------------------------------------------- + +void PianoCanvas::dragLeaveEvent(QDragLeaveEvent*) + { + printf("drag leave\n"); + } + +//--------------------------------------------------------- +// dropEvent +//--------------------------------------------------------- + +void PianoCanvas::viewDropEvent(QDropEvent*) + { +printf("PianoCanvas: viewDropEvent\n"); +#if 0 //TD + QString text; + if (event->source() == this) { + printf("local DROP\n"); + return; + } + if (Q3TextDrag::decode(event, text)) { + int x = editor->rasterVal(event->pos().x()); + if (x < 0) + x = 0; + pasteAt(text, x); + } + else { + printf("cannot decode drop\n"); + } +#endif + } + + +//--------------------------------------------------------- +// itemPressed +//--------------------------------------------------------- + +void PianoCanvas::itemPressed(const CItem* item) + { + if (!editor->playEvents()) + return; + Event event = item->event; + playedPitch = event.pitch() + track()->transposition(); + //int velo = event.velo(); + + // play note: + //I comment the following code because a note + //is already played in EventCanvas::mousePressCanvasA(QMouseEvent* me) + /*MidiEvent e(0, 0, 0x90, playedPitch, velo); + track()->playMidiEvent(&e);*/ + } + +//--------------------------------------------------------- +// itemReleased +//--------------------------------------------------------- + +void PianoCanvas::itemReleased() + { + if (!editor->playEvents()) + return; + + // release note: + MidiEvent ev(0, 0, 0x90, playedPitch, 0); + track()->playMidiEvent(&ev); + playedPitch = -1; + } + +//--------------------------------------------------------- +// itemMoved +//--------------------------------------------------------- + +void PianoCanvas::itemMoved(const CItem* item) + { + int npitch = y2pitch((int)((item->my - (int)(wpos.y()/_ymag) + + item->bbox.height())*_ymag)); + npitch += track()->transposition(); + if ((curItem==item) //remove this if want to have all selection playing + && (playedPitch != -1) && (playedPitch != npitch) + && editor->playEvents()) { + Event event = item->event; + // release note: + MidiEvent ev1(0, 0, 0x90, playedPitch, 0); + track()->playMidiEvent(&ev1); + // play note: + MidiEvent e2(0, 0, 0x90, npitch, event.velo()); + track()->playMidiEvent(&e2); + playedPitch = npitch; + } + } + +//--------------------------------------------------------- +// 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; + CItem* e = i->second; + Event event = e->event; + if (event.type() != Note) + continue; + + Part* part = 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); + song->undoOp(UndoOp::ModifyEvent, newEvent, event, part); + } + song->endUndo(SC_EVENT_MODIFIED); + audio->msgIdle(false); + } + +//--------------------------------------------------------- +// setColorMode +//--------------------------------------------------------- + +void PianoCanvas::setColorMode(int mode) + { + colorMode = mode; + widget()->update(); + } + +//--------------------------------------------------------- +// searchItem +//--------------------------------------------------------- + +CItem* PianoCanvas::searchItem(const QPoint& pt) const + { + QPoint p( + lrint((pt.x() - MAP_OFFSET + wpos.x()) / _xmag), + lrint((pt.y() + wpos.y()) / _ymag) + ); + return items.find(p); + } + +//--------------------------------------------------------- +// selectLasso +//--------------------------------------------------------- + +void PianoCanvas::selectLasso(bool toggle) + { + QRect r( + lrint((lasso.x() + wpos.x()) / _xmag), + lrint((lasso.y() + wpos.y()) / _ymag), + lrint(lasso.width() / _xmag), + lrint(lasso.height() / _ymag) + ); + + int n = 0; + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (i->second->intersects(r)) { + selectItem(i->second, !(toggle && i->second->isSelected())); + ++n; + } + } + if (n) { + updateSelection(); + widget()->update(); + } + } + diff --git a/muse_qt4_evolution/muse/midiedit/prcanvas.h b/muse_qt4_evolution/muse/midiedit/prcanvas.h new file mode 100644 index 00000000..7f92e95e --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/prcanvas.h @@ -0,0 +1,75 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __PRCANVAS_H__ +#define __PRCANVAS_H__ + +#include "ecanvas.h" + +class CItem; +class MidiCmd; + +//--------------------------------------------------------- +// PianoCanvas +//--------------------------------------------------------- + +class PianoCanvas : public EventCanvas { + Q_OBJECT + + int colorMode; + int playedPitch; + + MidiCmd* cmdModifyGateTime; + MidiCmd* cmdModifyVelocity; + + virtual void paint(QPainter&, QRect); + virtual CItem* searchItem(const QPoint& p) const; + virtual void addItem(Part* part, const Event& event); + virtual void viewMouseDoubleClickEvent(QMouseEvent*); + virtual void moveItem(CItem*, DragType); + virtual CItem* newItem(const QPoint&, int); + virtual void resizeItem(CItem*, bool noSnap); + virtual void newItem(CItem*, bool noSnap); + virtual bool deleteItem(CItem*); + virtual void startDrag(CItem* item, bool copymode); + virtual void dragEnterEvent(QDragEnterEvent* event); + virtual void dragMoveEvent(QDragMoveEvent*); + virtual void dragLeaveEvent(QDragLeaveEvent*); + virtual void viewDropEvent(QDropEvent* event); + virtual void selectLasso(bool toggle); + virtual void timeTypeChanged(); + + void quantize(int, int, bool); + void paste(); + virtual void itemPressed(const CItem*); + virtual void itemReleased(); + virtual void itemMoved(const CItem*); + + public slots: + void pianoCmd(int); + + public: + PianoCanvas(MidiEditor*); + void cmd(QAction*, int, int, bool); + void setColorMode(int mode); + virtual void modifySelected(NoteInfo::ValType type, int delta); + }; +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/quantconfig.cpp b/muse_qt4_evolution/muse/midiedit/quantconfig.cpp new file mode 100644 index 00000000..229b8875 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/quantconfig.cpp @@ -0,0 +1,68 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "quantconfig.h" + +const char* wtStrengthTxt = QT_TR_NOOP("sets amount of quantization:\n" + "0 - no quantization\n" + "100 - full quantization"); +const char* wtQLimitTxt = QT_TR_NOOP("don't quantize notes above this tick limit"); +const char* wtQLenTxt = QT_TR_NOOP("quantize also note len as default"); + +//--------------------------------------------------------- +// QuantConfig +//--------------------------------------------------------- + +QuantConfig::QuantConfig(int s, int l, bool lenFlag, QWidget* parent) + : QDialog(parent) + { + setupUi(this); + strength->setValue(s); + dontQuantize->setValue(l); + quantLen->setChecked(lenFlag); + } + +//--------------------------------------------------------- +// quantStrength +//--------------------------------------------------------- + +int QuantConfig::quantStrength() const + { + return strength->value(); + } + +//--------------------------------------------------------- +// quantLimit +//--------------------------------------------------------- + +int QuantConfig::quantLimit() const + { + return dontQuantize->value(); + } + +//--------------------------------------------------------- +// doQuantLen +//--------------------------------------------------------- + +bool QuantConfig::doQuantLen() const + { + return quantLen->isChecked(); + } + diff --git a/muse_qt4_evolution/muse/midiedit/quantconfig.h b/muse_qt4_evolution/muse/midiedit/quantconfig.h new file mode 100644 index 00000000..08e75cb2 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/quantconfig.h @@ -0,0 +1,42 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __QCONFIG_H__ +#define __QCONFIG_H__ + +#include "ui_quantconfig.h" + +//--------------------------------------------------------- +// QuantConfig +//--------------------------------------------------------- + +class QuantConfig : public QDialog, public Ui::QuantConfigBase { + Q_OBJECT + + public: + QuantConfig(int, int, bool, QWidget* parent = 0); + int quantStrength() const; + int quantLimit() const; + bool doQuantLen() const; + }; + + +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/quantconfig.ui b/muse_qt4_evolution/muse/midiedit/quantconfig.ui new file mode 100644 index 00000000..1da9f790 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/quantconfig.ui @@ -0,0 +1,151 @@ +<ui version="4.0" > + <author></author> + <comment></comment> + <exportmacro></exportmacro> + <class>QuantConfigBase</class> + <widget class="QDialog" name="QuantConfigBase" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>333</width> + <height>193</height> + </rect> + </property> + <property name="windowTitle" > + <string>MusE: Configure Quantize</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="1" column="1" > + <widget class="QSpinBox" name="dontQuantize" > + <property name="maximum" > + <number>500</number> + </property> + </widget> + </item> + <item row="4" column="0" colspan="2" > + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>131</width> + <height>31</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="okButton" > + <property name="text" > + <string>OK</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cancelButton" > + <property name="text" > + <string>Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Strength:</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QSpinBox" name="strength" > + <property name="suffix" > + <string>%</string> + </property> + <property name="maximum" > + <number>100</number> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Don't Quantize:</string> + </property> + </widget> + </item> + <item row="2" column="0" colspan="2" > + <widget class="QCheckBox" name="quantLen" > + <property name="text" > + <string>Quant Len</string> + </property> + </widget> + </item> + <item row="3" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <pixmapfunction></pixmapfunction> + <resources/> + <connections> + <connection> + <sender>okButton</sender> + <signal>clicked()</signal> + <receiver>QuantConfigBase</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>278</x> + <y>253</y> + </hint> + <hint type="destinationlabel" > + <x>96</x> + <y>254</y> + </hint> + </hints> + </connection> + <connection> + <sender>cancelButton</sender> + <signal>clicked()</signal> + <receiver>QuantConfigBase</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>369</x> + <y>253</y> + </hint> + <hint type="destinationlabel" > + <x>179</x> + <y>282</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/muse_qt4_evolution/muse/midiedit/trackpattern.cpp b/muse_qt4_evolution/muse/midiedit/trackpattern.cpp new file mode 100644 index 00000000..d50fffd0 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/trackpattern.cpp @@ -0,0 +1,627 @@ +#include "trackpattern.h" +#include "event.h" +#include "al/sig.h" + +class EventList; + +#define MAX(x,y) (x>y?x:y) + +#define EMPTYCHAR "-" +#define NONREADCHAR "*" +#define SPACECHAR "-" +#define PLUSCHAR "+" +#define STOPCHAR "=" +#define SEPCHAR " " +//#define FONT "Console" +#define FONT "Monospace" +//#define FONT "MiscFixed" +#define FONT_HEIGHT 14 +#define OFFSET_HEIGHT 3 +#define OFFSET_Y 3 + +//---------------------------------------------------------- +// EventPat +// has to be derived, can be note or control +//---------------------------------------------------------- +EventPat::EventPat(bool e, bool r) {_isEmpty = e; _isReadable = r;} +EventPat::EventPat() {EventPat(true, true);} +EventPat::~EventPat() {} + +void EventPat::setEmpty(bool e) {_isEmpty = e;} +bool EventPat::getEmpty() {return _isEmpty;} +void EventPat::setReadable(bool r) {_isReadable = r;} +bool EventPat::getReadable() {return _isReadable;} + +//---------------------------------------------------------- +// VoiceEventPat +//---------------------------------------------------------- +VoiceEventPat::VoiceEventPat(int n, int v):EventPat(false, true) { + _noteNum = n; + _velocity = v; +} + +VoiceEventPat::VoiceEventPat(bool e, bool r):EventPat(e, r) {} + +VoiceEventPat::VoiceEventPat():EventPat(true, true) {} + +VoiceEventPat::~VoiceEventPat() {} + + +void VoiceEventPat::setNoteNum(int n) { _noteNum = n; } + +int VoiceEventPat::getNoteNum() { return _noteNum; } + +void VoiceEventPat::setVelocity(int n) { _velocity = n; } + +int VoiceEventPat::getVelocity() { return _velocity; } + +QString VoiceEventPat::str() { + if(_isEmpty) { + return QString(EMPTYCHAR EMPTYCHAR EMPTYCHAR EMPTYCHAR) + + QString(SEPCHAR) + QString(EMPTYCHAR EMPTYCHAR EMPTYCHAR); + } + else if(_isReadable) { + if(_velocity==0) { + return QString(STOPCHAR STOPCHAR STOPCHAR STOPCHAR) + + QString(SEPCHAR) + QString(EMPTYCHAR EMPTYCHAR EMPTYCHAR); + } + else { + int octave = _noteNum/12 - 2; + int note = _noteNum%12; + QString sNote; + switch(note) { + case 0: sNote = QString("C") + QString(SPACECHAR); + break; + case 1: sNote = QString("C#"); + break; + case 2: sNote = QString("D") + QString(SPACECHAR); + break; + case 3: sNote = QString("D#"); + break; + case 4: sNote = QString("E") + QString(SPACECHAR); + break; + case 5: sNote = QString("F") + QString(SPACECHAR); + break; + case 6: sNote = QString("F#"); + break; + case 7: sNote = QString("G") + QString(SPACECHAR); + break; + case 8: sNote = QString("G#"); + break; + case 9: sNote = QString("A") + QString(SPACECHAR); + break; + case 10: sNote = QString("A#"); + break; + case 11: sNote = QString("F") + QString(SPACECHAR); + break; + default: + printf("VoiceEventPat::str() Error : case note not treated\n"); + break; + } + QString sOctave; + sOctave.setNum(octave); + if(octave>=0) { + sOctave = QString(PLUSCHAR) + sOctave; + } + QString sVel; + sVel.setNum(_velocity); + if(_velocity<10) { + sVel = QString("00") + sVel; + } + else if(_velocity<100) { + sVel = QString("0") + sVel; + } + return sNote + sOctave + QString(SEPCHAR) + sVel; + } + } + else { + return QString(NONREADCHAR NONREADCHAR NONREADCHAR NONREADCHAR) + + QString(SEPCHAR) + QString(NONREADCHAR NONREADCHAR NONREADCHAR); + } +} + +//---------------------------------------------------------- +// CtrlEventPat +//---------------------------------------------------------- +CtrlEventPat::CtrlEventPat(int c, int v):EventPat(false, true) { + _ctrlNum = c; + _value = v; +} + +CtrlEventPat::CtrlEventPat():EventPat(true, true) {} + +CtrlEventPat::~CtrlEventPat() {} + + +void CtrlEventPat::setCtrlNum(int n) { _ctrlNum = n; } + +int CtrlEventPat::getCtrlNum() { return _ctrlNum; } + +void CtrlEventPat::setValue(int n) { _value = n; } + +int CtrlEventPat::getValue() { return _value; } + +QString CtrlEventPat::str() { + //TODO + if(_isReadable) { + QString sCtrl; + sCtrl.setNum(_ctrlNum); + QString s = " "; + QString sVal; + sVal.setNum(_value); + return sCtrl + s + sVal; + } + else { + QString s = "***"; + return s; + } +} + +//---------------------------------------------------------- +// BasePat +//---------------------------------------------------------- +BasePat::BasePat() { +} +BasePat::BasePat(QString name, unsigned firstTick, + unsigned lastTick, int quant) { + _name = name; + _firstTick = firstTick; + _lastTick = lastTick; + _quant = quant; +} + +BasePat::~BasePat() {} + +QString BasePat::getName() { + return _name; +} + +bool BasePat::isRow(unsigned tick) { + Pos p = AL::sigmap.raster(_firstTick + tick, _quant); + return p.tick() == _firstTick + tick; +} + +unsigned BasePat::tick2row(unsigned tick) { + return (_firstTick + tick) / _quant - (_firstTick / _quant); +} + +//---------------------------------------------------------- +// VoicePat +//---------------------------------------------------------- +VoicePat::VoicePat(QString name, unsigned firstTick, unsigned lastTick, + int quant):BasePat(name, firstTick, lastTick, quant) { + _events = new EventList(); +} + +VoicePat::~VoicePat() { + delete(_events); +} + + +std::vector<VoiceEventPat*> VoicePat::getEventsCol() { + return _eventsCol; +} + +bool VoicePat::add(const Event* ev, unsigned tick) { + Event* e = new Event(*ev); + if(isFreeSpace(e, tick)) { + //add into the list of events + _events->add(*e, tick); + //add the begin tick into the column + unsigned beginRow = tick2row(tick); + if(beginRow >= _eventsCol.size()) { + for(unsigned i = _eventsCol.size(); i <= beginRow; i++) { + //empty voice event + _eventsCol.push_back(new VoiceEventPat()); + } + } + VoiceEventPat* vbep; + if(isRow(tick)) vbep = new VoiceEventPat(e->pitch(), e->velo()); + else vbep = new VoiceEventPat(false, false); //non-readable + if(_eventsCol[beginRow]) delete(_eventsCol[beginRow]); + _eventsCol[beginRow] = vbep; + + //add the end tick into the column + unsigned endTick = e->lenTick() + tick; + unsigned endRow = tick2row(endTick); + if(endRow >= _eventsCol.size()) { + for(unsigned i = _eventsCol.size(); i <= endRow; i++) { + //empty voice event + _eventsCol.push_back(new VoiceEventPat()); + } + } + VoiceEventPat* veep; + if(isRow(endTick)) veep = new VoiceEventPat(e->pitch(), 0); + else veep = new VoiceEventPat(false, false); //non-readable + if(_eventsCol[endRow] + && + (_eventsCol[endRow]->getEmpty() || tick2row(endTick)==tick2row(tick))) { + delete(_eventsCol[endRow]); + _eventsCol[endRow] = veep; + } + return true; + } + else { + return false; + } +} + +bool VoicePat::isFreeSpace(const Event* e, unsigned tick) { + bool isFree = true; + for(ciEvent ce = _events->begin(); ce != _events->end(); ce++) { + const Event* cevent = &ce->second; + unsigned beginTick = ce->first; + unsigned endTick = ce->first + cevent->lenTick(); + isFree = (endTick <= tick) || (beginTick >= tick + e->lenTick()); + if(!isFree) break; + } + return isFree; +} + +//---------------------------------------------------------- +// CtrlPat +//---------------------------------------------------------- +CtrlPat::CtrlPat(QString /*name*/) { +} + +CtrlPat::~CtrlPat() {} + +//---------------------------------------------------------- +// BaseTrackPat +//---------------------------------------------------------- +BaseTrackPat::BaseTrackPat(QMainWindow* parent, unsigned anr) { + _parent = parent; + _tree = new QTreeWidget(this); + + _absoluteNbrRow = anr; + + _update = false; + + connect(_tree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), + SLOT(currentItemChanged(QTreeWidgetItem*))); + connect(_tree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), + SLOT(currentItemChanged(QTreeWidgetItem*))); + connect(_parent, SIGNAL(signalMoveCurrentRow(unsigned)), this, + SLOT(moveRowFromSignal(unsigned))); + //connect signalSongChanged to update the pattern + connect(parent, SIGNAL(signalSongChanged(int)), this, SLOT(updatePattern(int))); +} + +BaseTrackPat::~BaseTrackPat() { +} + +void BaseTrackPat::setRowMag() { + _rowMag = (unsigned) height()/_fontHeight - OFFSET_Y; + _lastRow = _firstRow + _rowMag - 1; +} +void BaseTrackPat::setFirstRow(unsigned f) { + _firstRow = f; + _lastRow = f + _rowMag - 1; +} +void BaseTrackPat::setRelativeCurrentRow(unsigned r) { + _relativeCurrentRow = r; + _absoluteCurrentRow = r + _firstRow; +} +void BaseTrackPat::setAbsoluteCurrentRow(unsigned a) { + _absoluteCurrentRow = a; + _relativeCurrentRow = a - _firstRow; +} + +unsigned BaseTrackPat::getRowMag() { + return _rowMag; +} +unsigned BaseTrackPat::getFirstRow() { + return _firstRow; +} +unsigned BaseTrackPat::getLastRow() { + return _lastRow; +} +unsigned BaseTrackPat::getRelativeCurrentRow() { + return _relativeCurrentRow; +} +unsigned BaseTrackPat::getAbsoluteCurrentRow() { + return _absoluteCurrentRow; +} + +unsigned BaseTrackPat::getAbsoluteNbrRow() { + return _absoluteNbrRow; +} + +void BaseTrackPat::moveRelativeCurrentRow(unsigned newIndex) { + if(newIndex==0 && getFirstRow()>0) { + setFirstRow(getFirstRow() - 1); + setRelativeCurrentRow(newIndex + 1); + _update = true; + } + else if(newIndex==getRowMag()-1 && getLastRow()<_absoluteNbrRow-1) { + setFirstRow(getFirstRow() + 1); + setRelativeCurrentRow(newIndex - 1); + _update = true; + } + else setRelativeCurrentRow(newIndex); +} + +//void BaseTrackPat::itemSelectionChanged() { +void BaseTrackPat::currentItemChanged(QTreeWidgetItem* nitem) { + int index; + if(nitem) { + index = _tree->indexOfTopLevelItem(nitem); + + emit moveCurrentRow(index); + } +} + +void BaseTrackPat::moveRowFromSignal(unsigned index) { + moveRelativeCurrentRow(index); + if(_update==true) { + fillPattern(); + _update = false; + } + selectCurrentRow(); +} + +void BaseTrackPat::resizeEvent(QResizeEvent* /*event*/) { + setRowMag(); + fillPattern(); + selectCurrentRow(); +} + +void BaseTrackPat::selectCurrentRow() { + unsigned rcr = getRelativeCurrentRow(); + if(rcr < getRowMag()) { + QTreeWidgetItem* item = _tree->topLevelItem(getRelativeCurrentRow()); + if(item) { + _tree->blockSignals(true); + item->setSelected(true); + _tree->setCurrentItem(item); + _tree->blockSignals(false); + } + } +} + +void BaseTrackPat::updatePattern(int /*type*/) { + clearMatrix(); + buildMatrix(); + fillPattern(); + selectCurrentRow(); +} + +//---------------------------------------------------------- +// TrackPattern +//---------------------------------------------------------- +TrackPattern::TrackPattern(QMainWindow* parent, QString name, + unsigned firstTick, unsigned lastTick, + int quant, PartList* pl, MidiTrack* t, unsigned anr) + : BaseTrackPat(parent, anr), BasePat(name, firstTick, lastTick, quant) { + + //set attributs + _track = t; + + //build the list of parts belonging to track t + _partList = new PartList; + for(ciPart p = pl->begin(); p != pl->end(); p++) { + Part* part = p->second; + if(t==part->track()) + _partList->add(part); + } + + //build the matrix of events + buildMatrix(); + + //configure and add the dockWidget + setWindowTitle(_track->name()); + setFeatures(QDockWidget::DockWidgetClosable |QDockWidget::DockWidgetMovable); + parent->addDockWidget(Qt::LeftDockWidgetArea, this, Qt::Horizontal); + + //build the treeWidget + _tree->setColumnCount(_voiceColumns.size() + _ctrlColumns.size()); + QStringList headerLabels; + for(unsigned i = 0; i < _voiceColumns.size(); i++) { + headerLabels += QStringList(_voiceColumns[i]->getName()); + } + for(unsigned i = 0; i < _ctrlColumns.size(); i++) { + //TODO CTRL + //headerLabels += QStringList(_ctrlColumns[i]->getName()); + } + _tree->setHeaderLabels(headerLabels); + //set some display properties + _tree->setRootIsDecorated(false); + _tree->setUniformRowHeights(true); + _tree->setAlternatingRowColors(true); + QFont font =_tree->font(); + font.setFamily(FONT); + _tree->setFont(font); + font.setPixelSize(FONT_HEIGHT); + _fontHeight = font.pixelSize() + OFFSET_HEIGHT; + setWidget(_tree); + + //set the range of rows to display + setFirstRow(10); //TODO : choose accordingly to current position of muse song + setAbsoluteCurrentRow(10); //TODO : the same + setRowMag(); + + //fill the treeWidget + fillPattern(); + selectCurrentRow(); + + //Resize the columns + for(unsigned i = 0; i < _voiceColumns.size(); i++) + _tree->resizeColumnToContents(i); +} + +TrackPattern::~TrackPattern() { +} + +void TrackPattern::add(const Event* e, unsigned tick) { + if(e->isNote()) { + bool success = false; + for(unsigned i = 0; i < _voiceColumns.size(); i++) { + success = _voiceColumns[i]->add(e, tick); + if(success) break; + } + if(!success) { + QString voiceName; + voiceName.setNum(_voiceColumns.size()); + voiceName = QString("Voice " + voiceName); + VoicePat* vp = new VoicePat(voiceName, _firstTick, 0, _quant); + _voiceColumns.push_back(vp); + bool success = vp->add(e, tick); + if(!success) printf("Error TrackPattern::add\n"); + } + } + else { + //TODO Ctrl + } +} + +void TrackPattern::setQuant(int /*quant*/) { + //TODO +} + +void TrackPattern::clearMatrix() { + _voiceColumns.clear(); + _ctrlColumns.clear(); +} + +void TrackPattern::buildMatrix() { + for(ciPart p = _partList->begin(); p != _partList->end(); p++) { + Part* part = p->second; + EventList* events = part->events(); + for(ciEvent e = events->begin(); e != events->end(); e++) { + const Event* event = &e->second; + unsigned rescaledTick = part->tick() + event->tick() - _firstTick; + add(event, rescaledTick); + } + } +} + +void TrackPattern::fillPattern() { + _tree->blockSignals(true); + + _tree->clear(); + for(unsigned i = 0; i < _voiceColumns.size(); i++) { + for(unsigned j = getFirstRow(); j <= getLastRow(); j++) { + QTreeWidgetItem* item = _tree->topLevelItem(j - getFirstRow()); + if(!item) item = new QTreeWidgetItem(_tree); + VoiceEventPat* vep = (_voiceColumns[i]->getEventsCol())[j]; + if(vep) item->setText(i, vep->str()); + } + } + for(unsigned i = 0; i < _ctrlColumns.size(); i++) { + //TODO CTRL + } + + _tree->blockSignals(false); +} + +//--------------------------------------------------------------- +// TimingEvent +//--------------------------------------------------------------- +TimingEvent::TimingEvent(unsigned row) { + _row = row; +} +TimingEvent::~TimingEvent() { +} + +void TimingEvent::setBarBeatTick(unsigned tick) { + AL::sigmap.tickValues(tick, &_bar, &_beat, &_tick); +} + +QString TimingEvent::barBeatTickStr() { + QString barS; + barS.setNum(_bar + 1); + if(_bar<10) barS = QString("000") + barS; + else if(_bar<100) barS = QString("00") + barS; + else if(_bar<1000) barS = QString("0") + barS; + QString beatS; + beatS.setNum(_beat + 1); + if(_beat<10) beatS = QString("0") + beatS; + QString tickS; + tickS.setNum(_tick); + if(_tick<10) tickS = QString("00") + tickS; + else if(_tick<100) tickS = QString("0") + tickS; + return barS + QString(":") + beatS + QString(":") + tickS; +} + +QString TimingEvent::rowStr() { + QString r; + r.setNum(_row); + if(_row<10) r = QString("00") + r; + else if(_row<100) r = QString("0") + r; + return r; +} + +//--------------------------------------------------------------- +// TimingPattern +//--------------------------------------------------------------- +TimingPattern::TimingPattern(QMainWindow* parent, QString name, + unsigned firstTick, unsigned lastTick, int quant) + : BasePat(name, firstTick, lastTick, quant), BaseTrackPat(parent) { + //build the timing matrix + buildMatrix(); + + //configure and add the dockWidget + setWindowTitle(name); + setFeatures(QDockWidget::DockWidgetClosable |QDockWidget::DockWidgetMovable); + parent->addDockWidget(Qt::LeftDockWidgetArea, this, Qt::Horizontal); + + //build the treeWidget + QStringList headerLabels; + _tree->setHeaderLabels(QStringList("bar:bt:tick") + QStringList("row")); + _tree->setHeaderLabels(headerLabels); + //set some display properties + _tree->setRootIsDecorated(false); + _tree->setUniformRowHeights(true); + _tree->setAlternatingRowColors(true); + QFont font =_tree->font(); + font.setFamily(FONT); + _tree->setFont(font); + font.setPixelSize(FONT_HEIGHT); + _fontHeight = font.pixelSize() + OFFSET_HEIGHT; + setWidget(_tree); + + //set the range of rows to display + setFirstRow(10); //TODO : choose accordingly to current position of muse song + setAbsoluteCurrentRow(10); //TODO : the same + setRowMag(); + + //fill the treeWidget + fillPattern(); + selectCurrentRow(); + + //resize the columns + for(int i = 0; i < _tree->columnCount(); i++) + _tree->resizeColumnToContents(i); +} + +TimingPattern::~TimingPattern() { +} + +void TimingPattern::clearMatrix() { + _timingEvents.clear(); +} + +void TimingPattern::buildMatrix() { + for(unsigned tick = _firstTick; tick <= _lastTick; tick++) { + if(isRow(tick)) { + TimingEvent* te = new TimingEvent(tick2row(tick) - tick2row(_firstTick)); + te->setBarBeatTick(tick); + _timingEvents.push_back(te); + } + } + _absoluteNbrRow = _timingEvents.size(); +} + +void TimingPattern::fillPattern() { + _tree->blockSignals(true); + + _tree->clear(); + for(unsigned i = getFirstRow(); i <= getLastRow(); i++) { + QTreeWidgetItem* item = new QTreeWidgetItem(_tree); + TimingEvent* te = _timingEvents[i]; + item->setText(0, te->barBeatTickStr()); + item->setText(1, te->rowStr()); + } + + _tree->blockSignals(false); +} diff --git a/muse_qt4_evolution/muse/midiedit/trackpattern.h b/muse_qt4_evolution/muse/midiedit/trackpattern.h new file mode 100644 index 00000000..d9d91aee --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/trackpattern.h @@ -0,0 +1,261 @@ +//================================================================= +// trackpattern.h +// TrackPattern class for miditracker, QDock, QTree, Part, matrix +// miditracker.h +// (C) Copyright 2006 Nil Geisweiller (a_lin@user.sourceforge.net) +//================================================================= + +#ifndef __TRACKERPATTERN_H__ +#define __TRACKERPATTERN_H__ + +#include <vector> +#include "miditrack.h" +#include "part.h" + +class PartList; + +//---------------------------------------------------------- +// EventPat +// has to be derived, can be note or control +//---------------------------------------------------------- +class EventPat { + private: + protected: + bool _isReadable; //true iff the time of the event is the exact row time + bool _isEmpty; + public: + EventPat(bool isEmpty, bool isReadable); + EventPat(); //_isEmpty=true and_isReadable=true at the initialization + ~EventPat(); + + void setEmpty(bool); + bool getEmpty(); + void setReadable(bool); + bool getReadable(); +}; + +//---------------------------------------------------------- +// VoiceEventPat +//---------------------------------------------------------- +class VoiceEventPat : public EventPat { + private: + int _noteNum; //absolute note number including octave + int _velocity; //if velocity is 0 note is off + public: + VoiceEventPat(int noteNum, int velocity); // _isReadable is initialized true + VoiceEventPat(bool isEmpty, bool isReadable); + VoiceEventPat(); //_isEmpty = true, _isReadable = true + ~VoiceEventPat(); + + void setNoteNum(int n); + int getNoteNum(); + void setVelocity(int n); + int getVelocity(); + QString str(); //return the string to display on the entry of the pattern +}; + +//---------------------------------------------------------- +// CtrlEventPat +//---------------------------------------------------------- +class CtrlEventPat : public EventPat { + private: + int _ctrlNum; + int _value; //if velocity is 0 note is off + public: + CtrlEventPat(int ctrlNum, int value); // _isReadable is initialized true + CtrlEventPat(); // _isReadable is initialized false + ~CtrlEventPat(); + + void setCtrlNum(int n); + int getCtrlNum(); + void setValue(int n); + int getValue(); + QString str(); //return the string to display on the entry of the pattern +}; + +//---------------------------------------------------------- +// BasePat +//---------------------------------------------------------- +class BasePat { + protected: + QString _name; + unsigned _firstTick; + unsigned _lastTick; + int _quant; + public: + BasePat(); + BasePat(QString name, unsigned firstTick, unsigned lastTick, int quant); + ~BasePat(); + + QString getName(); + + bool isRow(unsigned tick); //return true iff tick coincides with one row + unsigned tick2row(unsigned tick); +}; + +//---------------------------------------------------------- +// VoicePat +//---------------------------------------------------------- +class VoicePat : public BasePat { + private: + std::vector<VoiceEventPat*> _eventsCol; //column of VoiceEventPat to display + EventList* _events; //actual list of events, only one at a time + public: + VoicePat(QString name, unsigned firstTick, unsigned lastTick, int quant); + ~VoicePat(); + + std::vector<VoiceEventPat*> getEventsCol(); + + bool add(const Event* e, unsigned tick); //add the Event e into the EventList + //and update properly _events + //return true if success, that is + //there is an empty space of the + //event + bool isFreeSpace(const Event* e, unsigned tick); //return true iff there + //is space to add the + //event e without + //overlapping other events +}; + +//---------------------------------------------------------- +// CtrlPat +//---------------------------------------------------------- +class CtrlPat { + private: + std::vector<CtrlEventPat> _events; //column of CtrlEventPat + public: + CtrlPat(QString name); + ~CtrlPat(); +}; + +//------------------------------------------------------ +// BaseTrackPat +//------------------------------------------------------ +class BaseTrackPat : public QDockWidget { + Q_OBJECT + + protected: + QTreeWidget* _tree; + QMainWindow* _parent; + + unsigned _rowMag; //contains the number of rows + unsigned _firstRow; //absolute index of the first row + unsigned _lastRow; //absolute index of the last row, included + unsigned _relativeCurrentRow; //index of the current according to the tree + unsigned _absoluteCurrentRow; //index of the current row according to the + //event matrix + unsigned _absoluteNbrRow; //contains the number of rows of the matrix + + int _fontHeight; + + bool _update; //if true then the tree must updated + + public: + BaseTrackPat(QMainWindow* parent, unsigned anr = 0); + ~BaseTrackPat(); + + void setRowMag(); //set _rowMag with the number of rows to display according + //to the size of the window, adjust _lastRow accordingly, + //assum that first row is set appropriately + void setFirstRow(unsigned f); //set _firstRow with f, that is the absolute index + //of the first row, adjust _lastRow appropriately + void setRelativeCurrentRow(unsigned r); //set _relativeCurrentRow with r + //and _absoluteCurrentRow accordingly + void setAbsoluteCurrentRow(unsigned a); //set _absoluteCurrentRow with a + //and _relativeCurrentRow accordingly + + unsigned getRowMag(); + unsigned getFirstRow(); + unsigned getLastRow(); + unsigned getRelativeCurrentRow(); + unsigned getAbsoluteCurrentRow(); + + unsigned getAbsoluteNbrRow(); + + void moveRelativeCurrentRow(unsigned newIndex); //update _firstRow, _lastrow + //relativeCurrentRow, + //absoluteCurrentRow, considering + //that the new relative index is + //newIndex + + void resizeEvent(QResizeEvent* /*event*/); + + virtual void clearMatrix() {} + virtual void buildMatrix() {} + virtual void fillPattern() {} //fill the treeWidget with the right window of times + //according to _firstRow and _lastRow + + + void selectCurrentRow(); //block the signals and select the current row + + signals: + void moveCurrentRow(unsigned i); //send the signal that the current row is moved + //at the relative index i + private slots: + void currentItemChanged(QTreeWidgetItem* nitem); + void moveRowFromSignal(unsigned index); + void updatePattern(int songChangeType); +}; + +//------------------------------------------------------ +// TrackPattern +//------------------------------------------------------ +class TrackPattern : public BaseTrackPat, public BasePat { + private: + PartList* _partList; //partList concerned by a track + MidiTrack* _track; + std::vector<VoicePat*> _voiceColumns; //matrix of voice events + std::vector<CtrlPat*> _ctrlColumns; //matrix of ctrl events + public: + TrackPattern(QMainWindow* parent, QString name, + unsigned firstTick, unsigned lastTick, + int quant, PartList* pl, MidiTrack* t, unsigned anr = 0); + ~TrackPattern(); + + void add(const Event* e, unsigned tick); //add the Event e and + //build consequently + //the matrix, + //creating new voices when necessary + MidiTrack* getTrack() {return _track;} + void setQuant(int quant); + + virtual void clearMatrix(); + virtual void buildMatrix(); + virtual void fillPattern(); +}; + +//------------------------------------------------------ +// TimingEvent +//------------------------------------------------------ +class TimingEvent { + private: + int _bar; + int _beat; + unsigned _tick; + unsigned _row; + + public: + TimingEvent(unsigned row); + ~TimingEvent(); + + void setBarBeatTick(unsigned tick); + + QString barBeatTickStr(); + QString rowStr(); +}; + +class TimingPattern : public BasePat, public BaseTrackPat { + private: + //QTreeWidget* _tree; + std::vector<TimingEvent*> _timingEvents; + public: + TimingPattern(QMainWindow* parent, QString name, unsigned firstTick, + unsigned lastTick, int quant); + ~TimingPattern(); + + virtual void clearMatrix(); + virtual void buildMatrix(); + virtual void fillPattern(); +}; + +#endif diff --git a/muse_qt4_evolution/muse/midiedit/velocity.cpp b/muse_qt4_evolution/muse/midiedit/velocity.cpp new file mode 100644 index 00000000..f0abd845 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/velocity.cpp @@ -0,0 +1,108 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "velocity.h" +#include "song.h" +#include "tb1.h" +#include "audio.h" + +//--------------------------------------------------------- +// Velocity +//--------------------------------------------------------- + +Velocity::Velocity(QWidget*) + : MidiCmdDialog() + { + setWindowTitle(tr("MusE: Modify Velocity")); + QWidget* velocityWidget = new QWidget; + velo.setupUi(velocityWidget); + layout->addWidget(velocityWidget); + layout->addStretch(10); + _rateVal = 0; + _offsetVal = 0; + velo.rate->setValue(_rateVal); + velo.offset->setValue(_offsetVal); + } + +//--------------------------------------------------------- +// accept +//--------------------------------------------------------- + +void Velocity::accept() + { + _rateVal = velo.rate->value(); + _offsetVal = velo.offset->value(); + MidiCmdDialog::accept(); + } + +//--------------------------------------------------------- +// ModifyVelocityCmd +//--------------------------------------------------------- + +ModifyVelocityCmd::ModifyVelocityCmd(MidiEditor* e) + : MidiCmd(e) + { + dialog = 0; + } + +//--------------------------------------------------------- +// guiDialog +//--------------------------------------------------------- + +MidiCmdDialog* ModifyVelocityCmd::guiDialog() + { + if (dialog == 0) + dialog = new Velocity(0); + return dialog; + } + +//--------------------------------------------------------- +// process +//--------------------------------------------------------- + +void ModifyVelocityCmd::process(CItemList* items) + { + int rate = dialog->rateVal(); + int offset = dialog->offsetVal(); + + for (iCItem k = items->begin(); k != items->end(); ++k) { + CItem* item = k->second; + Event event = item->event; + if (event.type() != Note) + continue; + if (itemInRange(item)) { + int velo = event.velo(); + 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); + audio->msgChangeEvent(event, newEvent, item->part, false); + } + } + } + } + + diff --git a/muse_qt4_evolution/muse/midiedit/velocity.h b/muse_qt4_evolution/muse/midiedit/velocity.h new file mode 100644 index 00000000..2ac4e700 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/velocity.h @@ -0,0 +1,62 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __VELOCITY_H__ +#define __VELOCITY_H__ + +#include "ui_velocity.h" +#include "midicmd.h" + +//--------------------------------------------------------- +// Velocity +//--------------------------------------------------------- + +class Velocity : public MidiCmdDialog { + Q_OBJECT + + Ui::VelocityBase velo; + int _rateVal; + int _offsetVal; + + protected slots: + void accept(); + + public: + Velocity(QWidget* parent = 0); + int rateVal() const { return _rateVal; } + int offsetVal() const { return _offsetVal; } + }; + +//--------------------------------------------------------- +// ModifyVelocityCmd +//--------------------------------------------------------- + +class ModifyVelocityCmd : public MidiCmd + { + Velocity* dialog; + virtual MidiCmdDialog* guiDialog(); + virtual void process(CItemList* items); + + public: + ModifyVelocityCmd(MidiEditor* e); + }; + +#endif + diff --git a/muse_qt4_evolution/muse/midiedit/velocity.ui b/muse_qt4_evolution/muse/midiedit/velocity.ui new file mode 100644 index 00000000..342611c0 --- /dev/null +++ b/muse_qt4_evolution/muse/midiedit/velocity.ui @@ -0,0 +1,86 @@ +<ui version="4.0" > + <author></author> + <comment></comment> + <exportmacro></exportmacro> + <class>VelocityBase</class> + <widget class="QWidget" name="VelocityBase" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>275</width> + <height>335</height> + </rect> + </property> + <property name="windowTitle" > + <string>MusE: Modify Velocity</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QGroupBox" name="GroupBox3" > + <property name="title" > + <string>Values</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>6</number> + </property> + <property name="spacing" > + <number>3</number> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="TextLabel3" > + <property name="text" > + <string>Rate:</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="TextLabel4" > + <property name="text" > + <string>Offset:</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QSpinBox" name="rate" > + <property name="suffix" > + <string>%</string> + </property> + <property name="maximum" > + <number>200</number> + </property> + <property name="value" > + <number>100</number> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QSpinBox" name="offset" > + <property name="maximum" > + <number>127</number> + </property> + <property name="minimum" > + <number>1</number> + </property> + <property name="singleStep" > + <number>1</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> + <resources/> + <connections/> +</ui> |
