diff options
Diffstat (limited to 'muse2/muse/midiedit')
-rw-r--r-- | muse2/muse/midiedit/dcanvas.cpp | 79 | ||||
-rw-r--r-- | muse2/muse/midiedit/dcanvas.h | 13 | ||||
-rw-r--r-- | muse2/muse/midiedit/dlist.cpp | 158 | ||||
-rw-r--r-- | muse2/muse/midiedit/dlist.h | 27 | ||||
-rw-r--r-- | muse2/muse/midiedit/drumedit.cpp | 19 | ||||
-rw-r--r-- | muse2/muse/midiedit/drumedit.h | 4 | ||||
-rw-r--r-- | muse2/muse/midiedit/ecanvas.cpp | 134 | ||||
-rw-r--r-- | muse2/muse/midiedit/ecanvas.h | 3 | ||||
-rw-r--r-- | muse2/muse/midiedit/piano.h | 4 | ||||
-rw-r--r-- | muse2/muse/midiedit/pianoroll.cpp | 21 | ||||
-rw-r--r-- | muse2/muse/midiedit/pianoroll.h | 4 | ||||
-rw-r--r-- | muse2/muse/midiedit/prcanvas.cpp | 167 | ||||
-rw-r--r-- | muse2/muse/midiedit/prcanvas.h | 16 | ||||
-rw-r--r-- | muse2/muse/midiedit/scoreedit.cpp | 563 | ||||
-rw-r--r-- | muse2/muse/midiedit/scoreedit.h | 71 |
15 files changed, 734 insertions, 549 deletions
diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index 61e98aea..92e514af 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -34,6 +34,7 @@ #include "audio.h" #include "shortcuts.h" #include "icons.h" +#include "functions.h" #define CARET 10 #define CARET2 5 @@ -88,7 +89,11 @@ DrumCanvas::DrumCanvas(MidiEditor* pr, QWidget* parent, int sx, setVirt(false); cursorPos= QPoint(0,0); _stepSize=1; + + steprec=new StepRec(NULL); + songChanged(SC_TRACK_INSERTED); + connect(song, SIGNAL(midiNote(int, int)), SLOT(midiNote(int,int))); } //--------------------------------------------------------- @@ -538,26 +543,7 @@ int DrumCanvas::pitch2y(int pitch) const void DrumCanvas::cmd(int cmd) { - switch(cmd) { - case CMD_CUT: - copy(); - song->startUndo(); - for (iCItem i = items.begin(); i != items.end(); ++i) { - if (!i->second->isSelected()) - continue; - DEvent* e = (DEvent*)(i->second); - Event event = e->event(); - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgDeleteEvent(event, e->part(), false, false, false); - } - song->endUndo(SC_EVENT_REMOVED); - break; - case CMD_COPY: - copy(); - break; - case CMD_PASTE: - paste(); - break; + switch (cmd) { case CMD_SELECT_ALL: // select all for (iCItem k = items.begin(); k != items.end(); ++k) { if (!k->second->isSelected()) @@ -698,41 +684,12 @@ void DrumCanvas::cmd(int cmd) //--------------------------------------------------------- -// copy -// cut copy paste -//--------------------------------------------------------- - -void DrumCanvas::copy() - { - QMimeData* md = getTextDrag(); - - if (md) - QApplication::clipboard()->setMimeData(md, QClipboard::Clipboard); - } - - -//--------------------------------------------------------- -// paste -// paste events -//--------------------------------------------------------- - -void DrumCanvas::paste() - { - QString stype("x-muse-eventlist"); - - //QString s = QApplication::clipboard()->text(stype, QClipboard::Selection); - QString s = QApplication::clipboard()->text(stype, QClipboard::Clipboard); // TODO CHECK Tim. - - pasteAt(s, song->cpos()); - } - -//--------------------------------------------------------- // startDrag //--------------------------------------------------------- void DrumCanvas::startDrag(CItem* /* item*/, bool copymode) { - QMimeData* md = getTextDrag(); + QMimeData* md = selected_events_to_mime(partlist_to_set(editor->parts()), 1); if (md) { // "Note that setMimeData() assigns ownership of the QMimeData object to the QDrag object. @@ -788,6 +745,10 @@ void DrumCanvas::keyPressed(int index, int velocity) // play note: MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); audio->msgPlayMidiEvent(&e); + + if (_steprec && pos[0] >= start_tick && pos[0] < end_tick && curPart) + steprec->record(curPart,index,drumMap[index].len,editor->raster(),velocity,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier); + } //--------------------------------------------------------- @@ -818,7 +779,7 @@ void DrumCanvas::mapChanged(int spitch, int dpitch) typedef std::vector< std::pair<Part*, Event*> >::iterator idel_ev; typedef std::vector< std::pair<Part*, Event> >::iterator iadd_ev; - + MidiTrackList* tracks = song->midis(); for (ciMidiTrack t = tracks->begin(); t != tracks->end(); t++) { MidiTrack* curTrack = *t; @@ -1163,3 +1124,19 @@ void DrumCanvas::moveAwayUnused() used.erase(it++); } } + + +//--------------------------------------------------------- +// midiNote +//--------------------------------------------------------- +void DrumCanvas::midiNote(int pitch, int velo) + { + if (debugMsg) printf("DrumCanvas::midiNote: pitch=%i, velo=%i\n", pitch, velo); + + if (_midiin && _steprec && curPart + && !audio->isPlaying() && velo && pos[0] >= start_tick + && pos[0] < end_tick + && !(globalKeyState & Qt::AltModifier)) { + steprec->record(curPart,drumInmap[pitch],drumMap[(int)drumInmap[pitch]].len,editor->raster(),velo,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier); + } + } diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h index cc3b8fff..868113a6 100644 --- a/muse2/muse/midiedit/dcanvas.h +++ b/muse2/muse/midiedit/dcanvas.h @@ -10,6 +10,7 @@ #include "ecanvas.h" #include "song.h" +#include "steprec.h" #define TH 18 @@ -40,12 +41,15 @@ class PianoRoll; //--------------------------------------------------------- class DrumCanvas : public EventCanvas { - + Q_OBJECT + + StepRec* steprec; + // Cursor tool position QPoint cursorPos; int _stepSize; - Q_OBJECT + virtual void drawCanvas(QPainter&, const QRect&); virtual void drawItem(QPainter&, const CItem*, const QRect&); void drawTopItem(QPainter& p, const QRect& rect); @@ -61,8 +65,6 @@ class DrumCanvas : public EventCanvas { int y2pitch(int y) const; int pitch2y(int pitch) const; - void copy(); - void paste(); void startDrag(CItem*, bool copymode); void dragEnterEvent(QDragEnterEvent* event); void dragMoveEvent(QDragMoveEvent*); @@ -75,6 +77,9 @@ class DrumCanvas : public EventCanvas { signals: void newWidth(int); + private slots: + void midiNote(int pitch, int velo); + public slots: void mapChanged(int, int); void keyPressed(int, int); diff --git a/muse2/muse/midiedit/dlist.cpp b/muse2/muse/midiedit/dlist.cpp index 0b8bf3aa..66922e83 100644 --- a/muse2/muse/midiedit/dlist.cpp +++ b/muse2/muse/midiedit/dlist.cpp @@ -23,7 +23,6 @@ #include "song.h" #include "scrollscale.h" - //--------------------------------------------------------- // draw //--------------------------------------------------------- @@ -244,7 +243,7 @@ void DList::viewMousePressEvent(QMouseEvent* ev) dm->mute = !dm->mute; break; case COL_PORT: - if (button == Qt::RightButton) { + if ((button == Qt::RightButton) || (button == Qt::LeftButton)) { bool changeAll = ev->modifiers() & Qt::ControlModifier; devicesPopupMenu(dm, mapx(x), mapy(pitch * TH), changeAll); } @@ -296,7 +295,6 @@ void DList::viewMousePressEvent(QMouseEvent* ev) if(val != dm->anote) { audio->msgIdle(true); - //audio->msgRemapPortDrumCtlEvents(pitch, val, -1, -1); song->remapPortDrumCtrlEvents(pitch, val, -1, -1); audio->msgIdle(false); dm->anote = val; @@ -372,24 +370,7 @@ void DList::viewMousePressEvent(QMouseEvent* ev) case COL_NAME: emit keyPressed(pitch, 100); //Mapping done on other side, send index break; -#if 0 - case COL_CHANNEL: - { - int channel = t->channel(); - if (button == Qt::RightButton) { - if (channel < 15) - ++channel; - } - else if (button == Qt::MidButton) { - if (channel > 0) - --channel; - } - if (channel != t->channel()) { - t->setChannel(channel); - emit channelChanged(); - } - } -#endif + default: break; } @@ -409,10 +390,13 @@ void DList::viewMouseDoubleClickEvent(QMouseEvent* ev) int section = header->logicalIndexAt(x); if ((section == COL_NAME || section == COL_VOL || section == COL_LEN || section == COL_LV1 || - section == COL_LV2 || section == COL_LV3 || section == COL_LV4) && (ev->button() == Qt::LeftButton)) + section == COL_LV2 || section == COL_LV3 || section == COL_LV4 || section == COL_CHANNEL || + section == COL_QNT) && (ev->button() == Qt::LeftButton)) { lineEdit(pitch, section); } + else if ((section == COL_ANOTE || section == COL_ENOTE) && (ev->button() == Qt::LeftButton)) + pitchEdit(pitch, section); else viewMousePressEvent(ev); } @@ -467,6 +451,14 @@ void DList::lineEdit(int line, int section) case COL_LV4: editor->setText(QString::number(dm->lv4)); break; + + case COL_QNT: + editor->setText(QString::number(dm->quant)); + break; + + case COL_CHANNEL: + editor->setText(QString::number(dm->channel+1)); + break; } editor->end(false); @@ -479,6 +471,40 @@ void DList::lineEdit(int line, int section) } +//--------------------------------------------------------- +// pitchEdit +//--------------------------------------------------------- +void DList::pitchEdit(int line, int section) + { + DrumMap* dm = &drumMap[line]; + editEntry = dm; + if (pitch_editor == 0) { + pitch_editor = new DPitchEdit(this); + connect(pitch_editor, SIGNAL(editingFinished()), + SLOT(pitchEdited())); + pitch_editor->setFrame(true); + } + int colx = mapx(header->sectionPosition(section)); + int colw = rmapx(header->sectionSize(section)); + int coly = mapy(line * TH); + int colh = rmapy(TH); + selectedColumn = section; //Store selected column to have an idea of which one was selected when return is pressed + switch (section) { + case COL_ENOTE: + pitch_editor->setValue(dm->enote); + break; + + case COL_ANOTE: + pitch_editor->setValue(dm->anote); + break; + } + + pitch_editor->setGeometry(colx, coly, colw, colh); + pitch_editor->show(); + pitch_editor->setFocus(); + + } + //--------------------------------------------------------- // x2col @@ -534,22 +560,35 @@ void DList::returnPressed() { ///val = atoi(editor->text().ascii()); val = atoi(editor->text().toAscii().constData()); - if (selectedColumn != COL_LEN) + + switch (selectedColumn) { - if(selectedColumn == COL_VOL) - { + case COL_VOL: if (val > 200) //Check bounds for volume val = 200; if (val < 0) val = 0; - } - else - { + break; + + case COL_LV1: + case COL_LV2: + case COL_LV3: + case COL_LV4: if (val > 127) //Check bounds for lv1-lv4 values val = 127; if (val < 0) val = 0; - } + break; + + case COL_CHANNEL: + val--; + if (val >= 16) + val = 15; + if (val < 0) + val = 0; + break; + + default: break; } } @@ -583,6 +622,14 @@ void DList::returnPressed() editEntry->lv4 = val; break; + case COL_QNT: + editEntry->quant = val; + break; + + case COL_CHANNEL: + editEntry->channel = val; + break; + default: printf("Return pressed in unknown column\n"); break; @@ -595,6 +642,52 @@ void DList::returnPressed() } //--------------------------------------------------------- +// pitchValueChanged +//--------------------------------------------------------- + +void DList::pitchEdited() +{ + int val=pitch_editor->value(); + int pitch=(editEntry-drumMap); + + switch(selectedColumn) { + case COL_ANOTE: + if(val != editEntry->anote) + { + audio->msgIdle(true); + song->remapPortDrumCtrlEvents(pitch, val, -1, -1); + audio->msgIdle(false); + editEntry->anote = val; + song->update(SC_DRUMMAP); + } + break; + + case COL_ENOTE: + //Check if there is any other drumMap with the same inmap value (there should be one (and only one):-) + //If so, switch the inmap between the instruments + for (int i=0; i<DRUM_MAPSIZE; i++) { + if (drumMap[i].enote == val && &drumMap[i] != editEntry) { + drumInmap[int(editEntry->enote)] = i; + drumMap[i].enote = editEntry->enote; + break; + } + } + //TODO: Set all the notes on the track with pitch=dm->enote to pitch=val + editEntry->enote = val; + drumInmap[val] = pitch; + break; + default: + printf("Value changed in unknown column\n"); + break; + } + selectedColumn = -1; + pitch_editor->hide(); + editEntry = 0; + setFocus(); + redraw(); + } + +//--------------------------------------------------------- // moved //--------------------------------------------------------- @@ -641,6 +734,7 @@ DList::DList(QHeaderView* h, QWidget* parent, int ymag) setFocusPolicy(Qt::StrongFocus); drag = NORMAL; editor = 0; + pitch_editor = 0; editEntry = 0; // always select a drum instrument currentlySelected = &drumMap[0]; @@ -696,9 +790,9 @@ void DList::viewMouseReleaseEvent(QMouseEvent* ev) emit mapChanged(sPitch, dPitch); //Track pitch change done in canvas } drag = NORMAL; -//?? redraw(); - if (editEntry) - editor->setFocus(); +//?? redraw(); //commented out NOT by flo93; was already commented out +// if (editEntry) //removed by flo93; seems to work without it +// editor->setFocus(); //and causes segfaults after adding the pitchedits int x = ev->x(); int y = ev->y(); bool shift = ev->modifiers() & Qt::ShiftModifier; diff --git a/muse2/muse/midiedit/dlist.h b/muse2/muse/midiedit/dlist.h index f57b7501..00f21c55 100644 --- a/muse2/muse/midiedit/dlist.h +++ b/muse2/muse/midiedit/dlist.h @@ -11,6 +11,7 @@ #include <QKeyEvent> #include <QLineEdit> +#include "awl/pitchedit.h" #include "view.h" #define TH 18 // normal Track-hight @@ -46,13 +47,35 @@ class DLineEdit: public QLineEdit }; //--------------------------------------------------------- +// DPitchEdit +//--------------------------------------------------------- +class DPitchEdit: public Awl::PitchEdit +{ + public: + DPitchEdit(QWidget* parent) : PitchEdit(parent) {} + virtual ~DPitchEdit() {}; + + virtual void keyPressEvent(QKeyEvent* keyItem) { + if ((keyItem->key() == Qt::Key_Escape) || (keyItem->key() == Qt::Key_Return)) { + parentWidget()->setFocus(); + hide(); + } + else + PitchEdit::keyPressEvent(keyItem); + } +}; + +//--------------------------------------------------------- // DList //--------------------------------------------------------- class DList : public View { + Q_OBJECT + QHeaderView* header; ScrollScale* scroll; QLineEdit* editor; + DPitchEdit* pitch_editor; DrumMap* editEntry; DrumMap* currentlySelected; int selectedColumn; @@ -71,12 +94,13 @@ class DList : public View { int x2col(int x) const; void devicesPopupMenu(DrumMap* t, int x, int y, bool changeAll); - Q_OBJECT + //void setCurDrumInstrument(int n); private slots: void sizeChange(int, int, int); void returnPressed(); + void pitchEdited(); void moved(int, int, int); signals: @@ -91,6 +115,7 @@ class DList : public View { void songChanged(int); public: void lineEdit(int line, int section); + void pitchEdit(int line, int section); void setCurDrumInstrument(int n); DList(QHeaderView*, QWidget* parent, int ymag); ~DList(); diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp index 9e64d7a7..1e678432 100644 --- a/muse2/muse/midiedit/drumedit.cpp +++ b/muse2/muse/midiedit/drumedit.cpp @@ -302,7 +302,7 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini midiin->setIcon(*midiinIcon); midiin->setCheckable(true); tools->addWidget(midiin); - + tools2 = new EditToolBar(this, drumeditTools); addToolBar(tools2); @@ -903,12 +903,27 @@ void DrumEdit::reset() void DrumEdit::cmd(int cmd) { switch(cmd) { + case DrumCanvas::CMD_CUT: + copy_notes(partlist_to_set(parts()), 1); + erase_notes(partlist_to_set(parts()), 1); + break; + case DrumCanvas::CMD_COPY: copy_notes(partlist_to_set(parts()), 1); break; + case DrumCanvas::CMD_PASTE: + ((DrumCanvas*)canvas)->cmd(DrumCanvas::CMD_SELECT_NONE); + paste_notes(canvas->part()); + break; case DrumCanvas::CMD_LOAD: load(); break; case DrumCanvas::CMD_SAVE: save(); break; case DrumCanvas::CMD_RESET: reset(); break; case DrumCanvas::CMD_MODIFY_VELOCITY: modify_velocity(partlist_to_set(parts())); break; case DrumCanvas::CMD_CRESCENDO: crescendo(partlist_to_set(parts())); break; - case DrumCanvas::CMD_QUANTIZE: quantize_notes(partlist_to_set(parts())); break; + case DrumCanvas::CMD_QUANTIZE: + if (quantize_dialog->exec()) + quantize_notes(partlist_to_set(parts()), quantize_dialog->range, + (config.division*4)/(1<<quantize_dialog->raster_power2), + /* quant_len= */false, quantize_dialog->strength, + quantize_dialog->swing, quantize_dialog->threshold); + break; case DrumCanvas::CMD_ERASE_EVENT: erase_notes(partlist_to_set(parts())); break; case DrumCanvas::CMD_DEL: erase_notes(partlist_to_set(parts()),1); break; //delete selected events case DrumCanvas::CMD_DELETE_OVERLAPS: delete_overlaps(partlist_to_set(parts())); break; diff --git a/muse2/muse/midiedit/drumedit.h b/muse2/muse/midiedit/drumedit.h index 30fe8487..64390cd9 100644 --- a/muse2/muse/midiedit/drumedit.h +++ b/muse2/muse/midiedit/drumedit.h @@ -49,6 +49,8 @@ class SNode; //--------------------------------------------------------- class DrumEdit : public MidiEditor { + Q_OBJECT + Event selEvent; MidiPart* selPart; int selTick; @@ -79,7 +81,7 @@ class DrumEdit : public MidiEditor { QAction *sallAction, *snoneAction, *invAction, *inAction , *outAction; QAction *prevAction, *nextAction; - Q_OBJECT + void initShortcuts(); virtual void closeEvent(QCloseEvent*); diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp index 9ce84147..ef47e0d6 100644 --- a/muse2/muse/midiedit/ecanvas.cpp +++ b/muse2/muse/midiedit/ecanvas.cpp @@ -25,6 +25,7 @@ #include "event.h" #include "shortcuts.h" #include "audio.h" +#include "functions.h" //--------------------------------------------------------- // EventCanvas @@ -364,137 +365,6 @@ void EventCanvas::keyPress(QKeyEvent* event) event->ignore(); } -//--------------------------------------------------------- -// getTextDrag -//--------------------------------------------------------- - -//QDrag* EventCanvas::getTextDrag(QWidget* parent) -QMimeData* EventCanvas::getTextDrag() - { - //--------------------------------------------------- - // generate event list from selected events - //--------------------------------------------------- - - EventList el; - unsigned startTick = MAXINT; - for (iCItem i = items.begin(); i != items.end(); ++i) { - if (!i->second->isSelected()) - continue; - ///NEvent* ne = (NEvent*)(i->second); - CItem* ne = i->second; - Event e = ne->event(); - if (startTick == MAXINT) - startTick = e.tick(); - el.add(e); - } - - //--------------------------------------------------- - // write events as XML into tmp file - //--------------------------------------------------- - - FILE* tmp = tmpfile(); - if (tmp == 0) { - fprintf(stderr, "EventCanvas::getTextDrag() fopen failed: %s\n", - strerror(errno)); - return 0; - } - Xml xml(tmp); - - int level = 0; - xml.tag(level++, "eventlist"); - for (ciEvent e = el.begin(); e != el.end(); ++e) - e->second.write(level, xml, -startTick); - xml.etag(--level, "eventlist"); - - //--------------------------------------------------- - // read tmp file into drag Object - //--------------------------------------------------- - - fflush(tmp); - struct stat f_stat; - if (fstat(fileno(tmp), &f_stat) == -1) { - fprintf(stderr, "PianoCanvas::copy() fstat failes:<%s>\n", - strerror(errno)); - fclose(tmp); - return 0; - } - int n = f_stat.st_size; - char* fbuf = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE, - MAP_PRIVATE, fileno(tmp), 0); - fbuf[n] = 0; - - QByteArray data(fbuf); - QMimeData* md = new QMimeData(); - //QDrag* drag = new QDrag(parent); - - md->setData("text/x-muse-eventlist", data); - //drag->setMimeData(md); - - munmap(fbuf, n); - fclose(tmp); - - //return drag; - return md; - } - -//--------------------------------------------------------- -// pasteAt -//--------------------------------------------------------- - -void EventCanvas::pasteAt(const QString& pt, int pos) - { - QByteArray ba = pt.toLatin1(); - const char* p = ba.constData(); - Xml xml(p); - for (;;) { - Xml::Token token = xml.parse(); - const QString& tag = xml.s1(); - switch (token) { - case Xml::Error: - case Xml::End: - return; - case Xml::TagStart: - if (tag == "eventlist") { - Undo operations; - EventList* el = new EventList(); - el->read(xml, "eventlist", true); - int modified = SC_EVENT_INSERTED; - for (iEvent i = el->begin(); i != el->end(); ++i) { - Event e = i->second; - int tick = e.tick() + pos - curPart->tick(); - if (tick<0) { - printf("ERROR: trying to add event before current part!\n"); - delete el; - return; - } - - e.setTick(tick); - int diff = e.endTick()-curPart->lenTick(); - if (diff > 0) {// too short part? extend it - Part* newPart = curPart->clone(); - newPart->setLenTick(newPart->lenTick()+diff); - // Do port controller values but not clone parts. - operations.push_back(UndoOp(UndoOp::ModifyPart, curPart, newPart, true, false)); - modified=modified|SC_PART_MODIFIED; - curPart = newPart; // reassign - } - // Do not do port controller values and clone parts. - operations.push_back(UndoOp(UndoOp::AddEvent, e, curPart, false, false)); - } - song->applyOperationGroup(operations); - delete el; - return; - } - else - xml.unknown("pasteAt"); - break; - case Xml::Attribut: - case Xml::TagEnd: - default: - break; - } - } - } //--------------------------------------------------------- // dropEvent @@ -515,7 +385,7 @@ void EventCanvas::viewDropEvent(QDropEvent* event) int x = editor->rasterVal(event->pos().x()); if (x < 0) x = 0; - pasteAt(text, x); + paste_at(curPart, text, x); //event->accept(); // TODO } else { diff --git a/muse2/muse/midiedit/ecanvas.h b/muse2/muse/midiedit/ecanvas.h index b3275607..b847f0f9 100644 --- a/muse2/muse/midiedit/ecanvas.h +++ b/muse2/muse/midiedit/ecanvas.h @@ -80,9 +80,6 @@ class EventCanvas : public Canvas { void range(int* s, int* e) const { *s = start_tick; *e = end_tick; } void playEvents(bool flag) { _playEvents = flag; } void selectAtTick(unsigned int tick); - //QDrag* getTextDrag(QWidget* parent); - QMimeData* getTextDrag(); - void pasteAt(const QString& pt, int pos); void viewDropEvent(QDropEvent* event); virtual void modifySelected(NoteInfo::ValType, int) {} virtual void keyPress(QKeyEvent*); diff --git a/muse2/muse/midiedit/piano.h b/muse2/muse/midiedit/piano.h index 35106d64..f8deec52 100644 --- a/muse2/muse/midiedit/piano.h +++ b/muse2/muse/midiedit/piano.h @@ -23,6 +23,8 @@ class QPixmap; class Piano : public View { + Q_OBJECT + int curPitch; QPixmap* octave; QPixmap* c_keys[10]; @@ -34,7 +36,7 @@ class Piano : public View bool shift; int button; - Q_OBJECT + int y2pitch(int) const; int pitch2y(int) const; void viewMouseMoveEvent(QMouseEvent* event); diff --git a/muse2/muse/midiedit/pianoroll.cpp b/muse2/muse/midiedit/pianoroll.cpp index 9105a446..b2fe55ee 100644 --- a/muse2/muse/midiedit/pianoroll.cpp +++ b/muse2/muse/midiedit/pianoroll.cpp @@ -198,11 +198,11 @@ PianoRoll::PianoRoll(PartList* pl, QWidget* parent, const char* name, unsigned i mapper->setMapping(funcTransposeAction, PianoCanvas::CMD_TRANSPOSE); connect(funcTransposeAction, SIGNAL(triggered()), mapper, SLOT(map())); - funcEraseEventAction = menuFunctions->addAction(tr("Erase Event")); + funcEraseEventAction = menuFunctions->addAction(tr("Erase Events")); mapper->setMapping(funcEraseEventAction, PianoCanvas::CMD_ERASE_EVENT); connect(funcEraseEventAction, SIGNAL(triggered()), mapper, SLOT(map())); - funcNoteShiftAction = menuFunctions->addAction(tr("Note Shift")); + funcNoteShiftAction = menuFunctions->addAction(tr("Move Notes")); mapper->setMapping(funcNoteShiftAction, PianoCanvas::CMD_NOTE_SHIFT); connect(funcNoteShiftAction, SIGNAL(triggered()), mapper, SLOT(map())); @@ -213,7 +213,12 @@ PianoRoll::PianoRoll(PartList* pl, QWidget* parent, const char* name, unsigned i funcDelOverlapsAction = menuFunctions->addAction(tr("Delete Overlaps")); mapper->setMapping(funcDelOverlapsAction, PianoCanvas::CMD_DELETE_OVERLAPS); connect(funcDelOverlapsAction, SIGNAL(triggered()), mapper, SLOT(map())); - + + QAction* funcLegatoAction = menuFunctions->addAction(tr("Legato")); + mapper->setMapping(funcLegatoAction, PianoCanvas::CMD_LEGATO); + connect(funcLegatoAction, SIGNAL(triggered()), mapper, SLOT(map())); + + menuPlugins = menuBar()->addMenu(tr("&Plugins")); song->populateScriptMenu(menuPlugins, this); @@ -600,6 +605,15 @@ void PianoRoll::cmd(int cmd) { switch (cmd) { + case PianoCanvas::CMD_CUT: + copy_notes(partlist_to_set(parts()), 1); + erase_notes(partlist_to_set(parts()), 1); + break; + case PianoCanvas::CMD_COPY: copy_notes(partlist_to_set(parts()), 1); break; + case PianoCanvas::CMD_PASTE: + ((PianoCanvas*)canvas)->cmd(PianoCanvas::CMD_SELECT_NONE); + paste_notes(canvas->part()); + break; case PianoCanvas::CMD_MODIFY_GATE_TIME: modify_notelen(partlist_to_set(parts())); break; case PianoCanvas::CMD_MODIFY_VELOCITY: modify_velocity(partlist_to_set(parts())); break; case PianoCanvas::CMD_CRESCENDO: crescendo(partlist_to_set(parts())); break; @@ -610,6 +624,7 @@ void PianoRoll::cmd(int cmd) case PianoCanvas::CMD_NOTE_SHIFT: move_notes(partlist_to_set(parts())); break; case PianoCanvas::CMD_FIXED_LEN: set_notelen(partlist_to_set(parts())); break; case PianoCanvas::CMD_DELETE_OVERLAPS: delete_overlaps(partlist_to_set(parts())); break; + case PianoCanvas::CMD_LEGATO: legato(partlist_to_set(parts())); break; default: ((PianoCanvas*)canvas)->cmd(cmd); } diff --git a/muse2/muse/midiedit/pianoroll.h b/muse2/muse/midiedit/pianoroll.h index 58c2487a..1f53254d 100644 --- a/muse2/muse/midiedit/pianoroll.h +++ b/muse2/muse/midiedit/pianoroll.h @@ -51,6 +51,8 @@ class QScrollArea; //--------------------------------------------------------- class PianoRoll : public MidiEditor { + Q_OBJECT + Event selEvent; MidiPart* selPart; int selTick; @@ -125,7 +127,7 @@ class PianoRoll : public MidiEditor { //QScrollBar* infoScroll; QScrollArea* infoScroll; - Q_OBJECT + void initShortcuts(); void setEventColorMode(int); QWidget* genToolbar(QWidget* parent); diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index 05fe8252..091582ef 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -15,6 +15,8 @@ #include <QDropEvent> #include <QMouseEvent> +#include <set> + #include <values.h> #include <stdio.h> #include <math.h> @@ -84,14 +86,10 @@ PianoCanvas::PianoCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy) { colorMode = 0; playedPitch = -1; + for (int i=0;i<128;i++) noteHeldDown[i]=false; - chordTimer = new QTimer(this); - chordTimer->setSingleShot(true); - chordTimer->setInterval(CHORD_TIMEOUT); - chordTimer->stop(); + steprec=new StepRec(noteHeldDown); - connect(chordTimer, SIGNAL(timeout()), SLOT(chordTimerTimedOut())); - songChanged(SC_TRACK_INSERTED); connect(song, SIGNAL(midiNote(int, int)), SLOT(midiNote(int,int))); } @@ -669,28 +667,10 @@ void PianoCanvas::pianoPressed(int pitch, int velocity, bool shift) // play note: MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); audio->msgPlayMidiEvent(&e); - - if (_steprec && pos[0] >= start_tick && pos[0] < end_tick) { - if (curPart) { - int len = editor->raster(); - unsigned tick = pos[0] - curPart->tick(); //CDW - if (shift) - tick -= editor->rasterStep(tick); - Event e(Note); - e.setTick(tick); - e.setPitch(pitch); - e.setVelo(127); - e.setLenTick(len); - // Indicate do undo, and do not do port controller values and clone parts. - audio->msgAddEvent(e, curPart, true, false, false); - tick += editor->rasterStep(tick) + curPart->tick(); - if (tick != song->cpos()) { - Pos p(tick, true); - song->setPos(0, p, true, false, true); - } - } + + if (_steprec && pos[0] >= start_tick && pos[0] < end_tick && curPart) { + steprec->record(curPart,pitch,editor->raster(),editor->raster(),velocity,globalKeyState&Qt::ControlModifier,shift); } - } //--------------------------------------------------------- @@ -796,16 +776,6 @@ void PianoCanvas::drawCanvas(QPainter& p, const QRect& rect) void PianoCanvas::cmd(int cmd) { switch (cmd) { - case CMD_CUT: - copy(); - erase_notes(partlist_to_set(editor->parts()),1); //FINDMICH is this correct? or must i do this on current_part? - break; - case CMD_COPY: - copy(); - break; - case CMD_PASTE: - paste(); - break; case CMD_SELECT_ALL: // select all for (iCItem k = items.begin(); k != items.end(); ++k) { if (!k->second->isSelected()) @@ -904,125 +874,40 @@ void PianoCanvas::cmd(int cmd) //--------------------------------------------------------- // midiNote //--------------------------------------------------------- - void PianoCanvas::midiNote(int pitch, int velo) { - if (_midiin && _steprec && curPart - && !audio->isPlaying() && velo && pos[0] >= start_tick - && pos[0] < end_tick - && !(globalKeyState & Qt::AltModifier)) { - chordTimer->stop(); - - //len has been changed by flo: set to raster() instead of quant() - //reason: the quant-toolbar has been removed; the flexibility you - //lose with this can be re-gained by applying a "modify note len" - //on the notes you have entered. - unsigned int len = editor->raster();//prevent compiler warning: comparison singed/unsigned - unsigned tick = pos[0]; //CDW - unsigned starttick = tick; - - // - // extend len of last note? - // - EventList* events = curPart->events(); - if (globalKeyState & Qt::ControlModifier) { - for (iEvent i = events->begin(); i != events->end(); ++i) { - Event ev = i->second; - if (!ev.isNote()) - continue; - if (ev.pitch() == pitch && ((ev.tick() + ev.lenTick()) == /*(int)*/starttick)) { - Event e = ev.clone(); - e.setLenTick(ev.lenTick() + editor->rasterStep(starttick)); - // Indicate do undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(ev, e, curPart, true, false, false); - - if (! (globalKeyState & Qt::ShiftModifier)) { - chordTimer_setToTick = tick + editor->rasterStep(tick); - chordTimer->start(); - } - return; - } - } - } + if (debugMsg) printf("PianoCanvas::midiNote: pitch=%i, velo=%i\n", pitch, velo); - // - // if we already entered the note, delete it - // - EventRange range = events->equal_range(tick); - for (iEvent i = range.first; i != range.second; ++i) { - Event ev = i->second; - if (ev.isNote() && ev.pitch() == pitch) { - // Indicate do undo, and do not do port controller values and clone parts. - audio->msgDeleteEvent(ev, curPart, true, false, false); - - if (! (globalKeyState & Qt::ShiftModifier)) { - chordTimer_setToTick = tick + editor->rasterStep(tick); - chordTimer->start(); - } - - return; - } - } - Event e(Note); - e.setTick(tick - curPart->tick()); - e.setPitch(pitch); - e.setVelo(velo); - e.setLenTick(len); - // Indicate do undo, and do not do port controller values and clone parts. - audio->msgAddEvent(e, curPart, true, false, false); - - if (! (globalKeyState & Qt::ShiftModifier)) { - chordTimer_setToTick = tick + editor->rasterStep(tick); - chordTimer->start(); - } - } - } - -void PianoCanvas::chordTimerTimedOut() -{ - if (chordTimer_setToTick != song->cpos()) - { - Pos p(chordTimer_setToTick, true); - song->setPos(0, p, true, false, true); - } -} - -//--------------------------------------------------------- -// copy -// cut copy paste -//--------------------------------------------------------- + if (velo) + noteHeldDown[pitch]=true; + else + noteHeldDown[pitch]=false; -void PianoCanvas::copy() + if (heavyDebugMsg) { - //QDrag* drag = getTextDrag(); - QMimeData* drag = getTextDrag(); - - if (drag) - QApplication::clipboard()->setMimeData(drag, QClipboard::Clipboard); + printf(" held down notes are: "); + for (int i=0;i<128;i++) + if (noteHeldDown[i]) + printf("%i ",i); + printf("\n"); } - -//--------------------------------------------------------- -// paste -// paste events -//--------------------------------------------------------- - -void PianoCanvas::paste() - { - QString stype("x-muse-eventlist"); - - //QString s = QApplication::clipboard()->text(stype, QClipboard::Selection); - QString s = QApplication::clipboard()->text(stype, QClipboard::Clipboard); // TODO CHECK Tim. - pasteAt(s, song->cpos()); + if (_midiin && _steprec && curPart + && !audio->isPlaying() && velo && pos[0] >= start_tick + && pos[0] < end_tick + && !(globalKeyState & Qt::AltModifier)) { + steprec->record(curPart,pitch,editor->raster(),editor->raster(),velo,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier); + } } + //--------------------------------------------------------- // startDrag //--------------------------------------------------------- void PianoCanvas::startDrag(CItem* /* item*/, bool copymode) { - QMimeData* md = getTextDrag(); + QMimeData* md = selected_events_to_mime(partlist_to_set(editor->parts()), 1); if (md) { // "Note that setMimeData() assigns ownership of the QMimeData object to the QDrag object. diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h index 7c77b229..c6e47c9e 100644 --- a/muse2/muse/midiedit/prcanvas.h +++ b/muse2/muse/midiedit/prcanvas.h @@ -17,6 +17,8 @@ #include <QDragLeaveEvent> #include <QTimer> +#include "steprec.h" + #define KH 13 //--------------------------------------------------------- @@ -38,13 +40,16 @@ class QRect; //--------------------------------------------------------- class PianoCanvas : public EventCanvas { + Q_OBJECT + int colorMode; int playedPitch; - QTimer* chordTimer; - unsigned chordTimer_setToTick; + bool noteHeldDown[128]; + + StepRec* steprec; - Q_OBJECT + virtual void viewMouseDoubleClickEvent(QMouseEvent*); virtual void drawItem(QPainter&, const CItem*, const QRect&); void drawTopItem(QPainter &p, const QRect &rect); @@ -64,8 +69,6 @@ class PianoCanvas : public EventCanvas { int y2pitch(int) const; int pitch2y(int) const; virtual void drawCanvas(QPainter&, const QRect&); - void copy(); - void paste(); virtual void itemPressed(const CItem*); virtual void itemReleased(const CItem*, const QPoint&); virtual void itemMoved(const CItem*, const QPoint&); @@ -74,7 +77,6 @@ class PianoCanvas : public EventCanvas { private slots: void midiNote(int pitch, int velo); - void chordTimerTimedOut(); signals: void quantChanged(int); @@ -96,7 +98,7 @@ class PianoCanvas : public EventCanvas { CMD_TRANSPOSE, CMD_THIN_OUT, CMD_ERASE_EVENT, CMD_NOTE_SHIFT, CMD_MOVE_CLOCK, CMD_COPY_MEASURE, CMD_ERASE_MEASURE, CMD_DELETE_MEASURE, CMD_CREATE_MEASURE, - CMD_FIXED_LEN, CMD_DELETE_OVERLAPS + CMD_FIXED_LEN, CMD_DELETE_OVERLAPS, CMD_LEGATO }; PianoCanvas(MidiEditor*, QWidget*, int, int); diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index 7f7382f4..0eb61554 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -51,13 +51,13 @@ using namespace std; #include "icons.h" #include "audio.h" #include "functions.h" - +#include "helper.h" #include "cmd.h" #include "sig.h" #include "song.h" +#include "shortcuts.h" //#include "../ctrl/ctrledit.h" -//#include "shortcuts.h" string IntToStr(int i); @@ -211,6 +211,16 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) undo_tools->addActions(undoRedo->actions()); addToolBar(undo_tools); + QToolBar* steprec_tools=addToolBar(tr("Step recording tools")); + steprec_tools->setObjectName("Step recording tools"); + srec = new QToolButton(); + srec->setToolTip(tr("Step Record")); + srec->setIcon(*steprecIcon); + srec->setCheckable(true); + steprec_tools->addWidget(srec); + connect(srec, SIGNAL(toggled(bool)), score_canvas, SLOT(set_steprec(bool))); + + edit_tools = new EditToolBar(this, PointerTool | PencilTool | RubberTool); addToolBar(edit_tools); edit_tools->set(PointerTool); @@ -323,9 +333,59 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) quant_toolbar->addWidget(px_per_whole_spinbox); px_per_whole_spinbox->setValue(300); + QMenu* edit_menu = menuBar()->addMenu(tr("&Edit")); + + edit_menu->addActions(undoRedo->actions()); + edit_menu->addSeparator(); + + cut_action = edit_menu->addAction(QIcon(*editcutIconSet), tr("C&ut")); + menu_mapper->setMapping(cut_action, CMD_CUT); + connect(cut_action, SIGNAL(triggered()), menu_mapper, SLOT(map())); + + copy_action = edit_menu->addAction(QIcon(*editcopyIconSet), tr("&Copy")); + menu_mapper->setMapping(copy_action, CMD_COPY); + connect(copy_action, SIGNAL(triggered()), menu_mapper, SLOT(map())); + + paste_action = edit_menu->addAction(QIcon(*editpasteIconSet), tr("&Paste")); + menu_mapper->setMapping(paste_action, CMD_PASTE); + connect(paste_action, SIGNAL(triggered()), menu_mapper, SLOT(map())); + + edit_menu->addSeparator(); + + del_action = edit_menu->addAction(tr("Delete &Events")); + menu_mapper->setMapping(del_action, CMD_DEL); + connect(del_action, SIGNAL(triggered()), menu_mapper, SLOT(map())); + + edit_menu->addSeparator(); + + QMenu* select_menu = edit_menu->addMenu(QIcon(*selectIcon), tr("&Select")); + + select_all_action = select_menu->addAction(QIcon(*select_allIcon), tr("Select &All")); + menu_mapper->setMapping(select_all_action, CMD_SELECT_ALL); + connect(select_all_action, SIGNAL(triggered()), menu_mapper, SLOT(map())); + + select_none_action = select_menu->addAction(QIcon(*select_deselect_allIcon), tr("&Deselect All")); + menu_mapper->setMapping(select_none_action, CMD_SELECT_NONE); + connect(select_none_action, SIGNAL(triggered()), menu_mapper, SLOT(map())); + + select_invert_action = select_menu->addAction(QIcon(*select_invert_selectionIcon), tr("Invert &Selection")); + menu_mapper->setMapping(select_invert_action, CMD_SELECT_INVERT); + connect(select_invert_action, SIGNAL(triggered()), menu_mapper, SLOT(map())); + + select_menu->addSeparator(); + + select_iloop_action = select_menu->addAction(QIcon(*select_inside_loopIcon), tr("&Inside Loop")); + menu_mapper->setMapping(select_iloop_action, CMD_SELECT_ILOOP); + connect(select_iloop_action, SIGNAL(triggered()), menu_mapper, SLOT(map())); + + select_oloop_action = select_menu->addAction(QIcon(*select_outside_loopIcon), tr("&Outside Loop")); + menu_mapper->setMapping(select_oloop_action, CMD_SELECT_OLOOP); + connect(select_oloop_action, SIGNAL(triggered()), menu_mapper, SLOT(map())); + + QMenu* settings_menu = menuBar()->addMenu(tr("&Settings")); - QMenu* color_menu = settings_menu->addMenu(tr("Note head &colors")); + color_menu = settings_menu->addMenu(tr("Note head &colors")); color_actions = new QActionGroup(this); color_black_action = color_menu->addAction(tr("&Black"), menu_mapper, SLOT(map())); color_velo_action = color_menu->addAction(tr("&Velocity"), menu_mapper, SLOT(map())); @@ -361,14 +421,36 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) QMenu* functions_menu = menuBar()->addMenu(tr("&Functions")); - QAction* func_quantize_action = functions_menu->addAction(tr("&Quantize"), menu_mapper, SLOT(map())); - QAction* func_notelen_action = functions_menu->addAction(tr("Change note &length"), menu_mapper, SLOT(map())); - QAction* func_velocity_action = functions_menu->addAction(tr("Change note &velocity"), menu_mapper, SLOT(map())); - QAction* func_cresc_action = functions_menu->addAction(tr("Crescendo/Decrescendo"), menu_mapper, SLOT(map())); + func_quantize_action = functions_menu->addAction(tr("&Quantize"), menu_mapper, SLOT(map())); + func_notelen_action = functions_menu->addAction(tr("Change note &length"), menu_mapper, SLOT(map())); + func_velocity_action = functions_menu->addAction(tr("Change note &velocity"), menu_mapper, SLOT(map())); + func_cresc_action = functions_menu->addAction(tr("Crescendo/Decrescendo"), menu_mapper, SLOT(map())); + func_transpose_action = functions_menu->addAction(tr("Transpose"), menu_mapper, SLOT(map())); + func_erase_action = functions_menu->addAction(tr("Erase Events"), menu_mapper, SLOT(map())); + func_move_action = functions_menu->addAction(tr("Move Notes"), menu_mapper, SLOT(map())); + func_fixed_len_action = functions_menu->addAction(tr("Set Fixed Length"), menu_mapper, SLOT(map())); + func_del_overlaps_action = functions_menu->addAction(tr("Delete Overlaps"), menu_mapper, SLOT(map())); + func_legato_action = functions_menu->addAction(tr("Legato"), menu_mapper, SLOT(map())); menu_mapper->setMapping(func_quantize_action, CMD_QUANTIZE); menu_mapper->setMapping(func_notelen_action, CMD_NOTELEN); menu_mapper->setMapping(func_velocity_action, CMD_VELOCITY); menu_mapper->setMapping(func_cresc_action, CMD_CRESCENDO); + menu_mapper->setMapping(func_transpose_action, CMD_TRANSPOSE); + menu_mapper->setMapping(func_erase_action, CMD_ERASE); + menu_mapper->setMapping(func_move_action, CMD_MOVE); + menu_mapper->setMapping(func_fixed_len_action, CMD_FIXED_LEN); + menu_mapper->setMapping(func_del_overlaps_action, CMD_DELETE_OVERLAPS); + menu_mapper->setMapping(func_legato_action, CMD_LEGATO); + + init_shortcuts(); + + connect(muse, SIGNAL(configChanged()), SLOT(init_shortcuts())); + + QClipboard* cb = QApplication::clipboard(); + connect(cb, SIGNAL(dataChanged()), SLOT(clipboard_changed())); + + clipboard_changed(); + selection_changed(); if (!default_toolbar_state.isEmpty()) restoreState(default_toolbar_state); @@ -387,6 +469,32 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) apply_velo=true; } +void ScoreEdit::init_shortcuts() +{ + cut_action->setShortcut(shortcuts[SHRT_CUT].key); + copy_action->setShortcut(shortcuts[SHRT_COPY].key); + paste_action->setShortcut(shortcuts[SHRT_PASTE].key); + del_action->setShortcut(shortcuts[SHRT_DELETE].key); + + select_all_action->setShortcut(shortcuts[SHRT_SELECT_ALL].key); + select_none_action->setShortcut(shortcuts[SHRT_SELECT_NONE].key); + select_invert_action->setShortcut(shortcuts[SHRT_SELECT_INVERT].key); + select_iloop_action->setShortcut(shortcuts[SHRT_SELECT_ILOOP].key); + select_oloop_action->setShortcut(shortcuts[SHRT_SELECT_OLOOP].key); + + color_menu->menuAction()->setShortcut(shortcuts[SHRT_EVENT_COLOR].key); + + func_quantize_action->setShortcut(shortcuts[SHRT_QUANTIZE].key); + func_notelen_action->setShortcut(shortcuts[SHRT_MODIFY_GATE_TIME].key); + func_velocity_action->setShortcut(shortcuts[SHRT_MODIFY_VELOCITY].key); + func_transpose_action->setShortcut(shortcuts[SHRT_TRANSPOSE].key); + func_erase_action->setShortcut(shortcuts[SHRT_ERASE_EVENT].key); + func_move_action->setShortcut(shortcuts[SHRT_NOTE_SHIFT].key); + func_fixed_len_action->setShortcut(shortcuts[SHRT_FIXED_LEN].key); + func_del_overlaps_action->setShortcut(shortcuts[SHRT_DELETE_OVERLAPS].key); +} + + void ScoreEdit::add_parts(PartList* pl, bool all_in_one) { score_canvas->add_staves(pl, all_in_one); @@ -482,6 +590,8 @@ void ScoreEdit::song_changed(int flags) if (velo>=0) velo_spinbox->setValue(velo); if (velo_off>=0) velo_off_spinbox->setValue(velo_off); } + + selection_changed(); } } @@ -568,16 +678,51 @@ void ScoreEdit::menu_command(int cmd) } break; + case CMD_SELECT_ALL: select_all(score_canvas->get_all_parts()); break; + case CMD_SELECT_NONE: select_none(score_canvas->get_all_parts()); break; + case CMD_SELECT_INVERT: select_invert(score_canvas->get_all_parts()); break; + case CMD_SELECT_ILOOP: select_in_loop(score_canvas->get_all_parts()); break; + case CMD_SELECT_OLOOP: select_not_in_loop(score_canvas->get_all_parts()); break; + + case CMD_CUT: + copy_notes(score_canvas->get_all_parts(), 1); + erase_notes(score_canvas->get_all_parts(), 1); + break; + case CMD_COPY: copy_notes(score_canvas->get_all_parts(), 1); break; + case CMD_PASTE: + menu_command(CMD_SELECT_NONE); + paste_notes(score_canvas->get_selected_part()); + break; case CMD_QUANTIZE: quantize_notes(score_canvas->get_all_parts()); break; case CMD_VELOCITY: modify_velocity(score_canvas->get_all_parts()); break; case CMD_CRESCENDO: crescendo(score_canvas->get_all_parts()); break; case CMD_NOTELEN: modify_notelen(score_canvas->get_all_parts()); break; - + case CMD_TRANSPOSE: transpose_notes(score_canvas->get_all_parts()); break; + case CMD_ERASE: erase_notes(score_canvas->get_all_parts()); break; + case CMD_DEL: erase_notes(score_canvas->get_all_parts(),1); break; + case CMD_MOVE: move_notes(score_canvas->get_all_parts()); break; + case CMD_FIXED_LEN: set_notelen(score_canvas->get_all_parts()); break; + case CMD_DELETE_OVERLAPS: delete_overlaps(score_canvas->get_all_parts()); break; + case CMD_LEGATO: legato(score_canvas->get_all_parts()); break; + default: score_canvas->menu_command(cmd); } } +void ScoreEdit::clipboard_changed() +{ + paste_action->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-eventlist"))); +} + +void ScoreEdit::selection_changed() +{ + bool flag = !get_events(score_canvas->get_all_parts(),1).empty(); + cut_action->setEnabled(flag); + copy_action->setEnabled(flag); + del_action->setEnabled(flag); +} + //duplicated from songfile.cpp's MusE::readPart(); the only differences: //"none" is supported and tag_name is settable @@ -604,9 +749,11 @@ Part* read_part(Xml& xml, QString tag_name="part") else { sscanf(tag.toLatin1().constData(), "%d:%d", &trackIdx, &partIdx); + if (debugMsg) cout << "read_part: trackIdx="<<trackIdx<<", partIdx="<<partIdx; Track* track = song->tracks()->index(trackIdx); if (track) part = track->parts()->find(partIdx); + if (debugMsg) cout << ", track="<<track<<", part="<<part<<endl; } } break; @@ -656,12 +803,15 @@ void staff_t::read_status(Xml& xml) case Xml::TagEnd: if (tag == "staff") - return; + goto staff_readstatus_end; default: break; } } + + staff_readstatus_end: + update_part_indices(); } @@ -695,6 +845,7 @@ void ScoreEdit::writeStatus(int level, Xml& xml) const xml.strTag(level, "name", name); xml.intTag(level, "tool", edit_tools->curTool()); + xml.intTag(level, "steprec", srec->isChecked()); xml.intTag(level, "quantPower", score_canvas->quant_power2()); xml.intTag(level, "pxPerWhole", score_canvas->pixels_per_whole()); xml.intTag(level, "newNoteVelo", velo_spinbox->value()); @@ -787,6 +938,8 @@ void ScoreEdit::readStatus(Xml& xml) set_name(xml.parse1()); else if (tag == "tool") edit_tools->set(xml.parseInt()); + else if (tag == "steprec") + srec->setChecked(xml.parseInt()); else if (tag == "quantPower") quant_combobox->setCurrentIndex(xml.parseInt()-1); else if (tag == "pxPerWhole") @@ -911,55 +1064,101 @@ void ScoreEdit::write_configuration(int level, Xml& xml) void ScoreCanvas::add_staves(PartList* pl, bool all_in_one) { - staff_t staff(this); - - if (all_in_one) + if (!pl->empty()) { - staff.parts.clear(); - for (ciPart part_it=pl->begin(); part_it!=pl->end(); part_it++) - staff.parts.insert(part_it->second); - staff.cleanup_parts(); - - staff.type=GRAND_TOP; //FINDME_INITCLEF - staff.clef=VIOLIN; - staves.push_back(staff); - - staff.type=GRAND_BOTTOM; - staff.clef=BASS; - staves.push_back(staff); - } - else - { - set<Track*> tracks; - for (ciPart it=pl->begin(); it!=pl->end(); it++) - tracks.insert(it->second->track()); - - TrackList* tracklist = song->tracks(); - // this loop is used for inserting track-staves in the - // correct order. simply iterating through tracks's contents - // would sort after the pointer values, i.e. randomly - for (ciTrack track_it=tracklist->begin(); track_it!=tracklist->end(); track_it++) - if (tracks.find(*track_it)!=tracks.end()) + staff_t staff(this); + + if (all_in_one) + { + clefTypes clef=((MidiTrack*)pl->begin()->second->track())->getClef(); + + staff.parts.clear(); + for (ciPart part_it=pl->begin(); part_it!=pl->end(); part_it++) { - staff.parts.clear(); - for (ciPart part_it=pl->begin(); part_it!=pl->end(); part_it++) - if (part_it->second->track() == *track_it) - staff.parts.insert(part_it->second); - staff.cleanup_parts(); - - staff.type=GRAND_TOP; //FINDME_INITCLEF - staff.clef=VIOLIN; - staves.push_back(staff); + if (((MidiTrack*)part_it->second->track())->getClef() != clef) + clef=grandStaff; + + staff.parts.insert(part_it->second); + } + staff.cleanup_parts(); + staff.update_part_indices(); - staff.type=GRAND_BOTTOM; - staff.clef=BASS; - staves.push_back(staff); + switch (clef) + { + case trebleClef: + staff.type=NORMAL; + staff.clef=VIOLIN; + staves.push_back(staff); + break; + + case bassClef: + staff.type=NORMAL; + staff.clef=BASS; + staves.push_back(staff); + break; + + case grandStaff: + staff.type=GRAND_TOP; + staff.clef=VIOLIN; + staves.push_back(staff); + + staff.type=GRAND_BOTTOM; + staff.clef=BASS; + staves.push_back(staff); + break; } + } + else + { + set<Track*> tracks; + for (ciPart it=pl->begin(); it!=pl->end(); it++) + tracks.insert(it->second->track()); + + TrackList* tracklist = song->tracks(); + // this loop is used for inserting track-staves in the + // correct order. simply iterating through tracks's contents + // would sort after the pointer values, i.e. randomly + for (ciTrack track_it=tracklist->begin(); track_it!=tracklist->end(); track_it++) + if (tracks.find(*track_it)!=tracks.end()) + { + staff.parts.clear(); + for (ciPart part_it=pl->begin(); part_it!=pl->end(); part_it++) + if (part_it->second->track() == *track_it) + staff.parts.insert(part_it->second); + staff.cleanup_parts(); + staff.update_part_indices(); + + switch (((MidiTrack*)(*track_it))->getClef()) + { + case trebleClef: + staff.type=NORMAL; + staff.clef=VIOLIN; + staves.push_back(staff); + break; + + case bassClef: + staff.type=NORMAL; + staff.clef=BASS; + staves.push_back(staff); + break; + + case grandStaff: + staff.type=GRAND_TOP; + staff.clef=VIOLIN; + staves.push_back(staff); + + staff.type=GRAND_BOTTOM; + staff.clef=BASS; + staves.push_back(staff); + break; + } + } + } + + cleanup_staves(); + fully_recalculate(); + recalc_staff_pos(); } - - cleanup_staves(); - fully_recalculate(); - recalc_staff_pos(); } @@ -973,17 +1172,21 @@ ScoreCanvas::ScoreCanvas(ScoreEdit* pr, QWidget* parent_widget) : View(parent_wi init_pixmaps(); + srec=false; + for (int i=0;i<128;i++) held_notes[i]=false; + steprec=new StepRec(held_notes); + connect(song, SIGNAL(midiNote(int, int)), SLOT(midi_note(int,int))); + x_pos=0; x_left=0; y_pos=0; have_lasso=false; + inserting=false; dragging=false; drag_cursor_changed=false; mouse_erases_notes=false; mouse_inserts_notes=true; - undo_started=false; - undo_flags=0; selected_part=NULL; @@ -1155,6 +1358,8 @@ void ScoreCanvas::merge_staves(list<staff_t>::iterator dest, list<staff_t>::iter dest->parts.insert(src->parts.begin(), src->parts.end()); } + dest->update_part_indices(); + remove_staff(src); fully_recalculate(); @@ -1223,6 +1428,26 @@ void ScoreCanvas::fully_recalculate() void ScoreCanvas::song_changed(int flags) { + if (flags & (SC_PART_MODIFIED | SC_PART_REMOVED | SC_PART_INSERTED | SC_TRACK_REMOVED)) + { + update_parts(); + + if (flags & (SC_PART_REMOVED | SC_TRACK_REMOVED)) + { + for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++) + it->cleanup_parts(); + + cleanup_staves(); + + for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++) + it->recalculate(); + + recalc_staff_pos(); + + redraw(); + } + } + if (flags & (SC_PART_MODIFIED | SC_EVENT_INSERTED | SC_EVENT_MODIFIED | SC_EVENT_REMOVED | SC_SIG | SC_KEY) ) @@ -1238,26 +1463,6 @@ void ScoreCanvas::song_changed(int flags) emit canvas_width_changed(canvas_width()); } - if (flags & SC_PART_REMOVED) - { - bool something_changed=false; - - for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++) - { - if (it->cleanup_parts()) - something_changed=true; - } - - cleanup_staves(); - - for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++) - it->recalculate(); - - recalc_staff_pos(); - - redraw(); - } - if (flags & SC_SELECTION) { redraw(); @@ -3312,10 +3517,9 @@ int ScoreCanvas::y_to_pitch(int y, int t, clef_t clef) void ScoreCanvas::mousePressEvent (QMouseEvent* event) { - keystate=((QInputEvent*)event)->modifiers(); - + keystate=event->modifiers(); bool ctrl=keystate & Qt::ControlModifier; - + // den errechneten tick immer ABrunden! // denn der "bereich" eines schlags geht von schlag_begin bis nächsterschlag_begin-1 // noten werden aber genau in die mitte dieses bereiches gezeichnet @@ -3325,10 +3529,6 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) int y=event->y() + y_pos - staff_it->y_draw; int x=event->x()+x_pos-x_left; int tick=flo_quantize_floor(x_to_tick(x), quant_ticks()); - - if (event->button()==Qt::LeftButton) - if (!ctrl) - deselect_all(); if (staff_it!=staves.end()) { @@ -3389,7 +3589,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) int this_begin=tick; int this_end=this_begin+calc_len(set_it->len, set_it->dots); - selected_part=set_it->source_part; + set_selected_part(set_it->source_part); //that's the only note corresponding to the event? if (this_begin==total_begin && this_end==total_end) @@ -3419,9 +3619,10 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) + clicked_event_ptr=set_it->source_event; dragged_event=*set_it->source_event; + original_dragged_event=dragged_event.clone(); dragged_event_part=set_it->source_part; - dragged_event_original_pitch=dragged_event.pitch(); if ((mouse_erases_notes) || (event->button()==Qt::MidButton)) //erase? { @@ -3429,14 +3630,9 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) } else if (event->button()==Qt::LeftButton) //edit? { - set_it->source_event->setSelected(!set_it->source_event->selected()); - song_changed(SC_SELECTION); - setMouseTracking(true); dragging=true; drag_cursor_changed=false; - undo_started=false; - undo_flags=SC_EVENT_MODIFIED; } } else //we found nothing? @@ -3468,11 +3664,9 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) if (relative_tick<0) cerr << "ERROR: THIS SHOULD NEVER HAPPEN: relative_tick is negative!" << endl; song->startUndo(); - undo_started=true; - undo_flags=SC_EVENT_INSERTED | SC_EVENT_MODIFIED; - //stopping undo at the end of this function is unneccessary - //because we'll begin a drag right after it. finishing - //this drag will stop undo as well (in mouseReleaseEvent) + + if (!ctrl) + deselect_all(); Event newevent(Note); newevent.setPitch(y_to_pitch(y,tick, staff_it->clef)); @@ -3481,7 +3675,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) newevent.setTick(relative_tick); newevent.setLenTick((new_len>0)?new_len:last_len); newevent.setSelected(true); - + if (flo_quantize(newevent.lenTick(), quant_ticks()) <= 0) { newevent.setLenTick(quant_ticks()); @@ -3499,7 +3693,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) dragged_event_part=curr_part; dragged_event=newevent; - dragged_event_original_pitch=newevent.pitch(); + original_dragged_event=dragged_event.clone(); mouse_down_pos=event->pos(); mouse_operation=NO_OP; @@ -3509,9 +3703,12 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) setMouseTracking(true); dragging=true; + inserting=true; drag_cursor_changed=true; setCursor(Qt::SizeAllCursor); - //song->startUndo(); unneccessary because we have started it already above + + song->endUndo(SC_EVENT_INSERTED); + song->update(SC_SELECTION); } } else // !mouse_inserts_notes. open a lasso @@ -3525,16 +3722,16 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) } } } - - if (event->button()==Qt::LeftButton) - song->update(SC_SELECTION); } void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event) { + keystate=event->modifiers(); + bool ctrl=keystate & Qt::ControlModifier; + if (dragging && event->button()==Qt::LeftButton) { - if ((mouse_operation==LENGTH) || (mouse_operation==BEGIN)) //also BEGIN can change the len by clipping + if (mouse_operation==LENGTH) { if (flo_quantize(dragged_event.lenTick(), quant_ticks()) <= 0) { @@ -3545,15 +3742,29 @@ void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event) { last_len=flo_quantize(dragged_event.lenTick(), quant_ticks()); } + + if (undo_started) + song->endUndo(SC_EVENT_MODIFIED | SC_EVENT_REMOVED); } + - if (undo_started) - song->endUndo(undo_flags); + if (mouse_operation==NO_OP && !inserting) + { + if (event->button()==Qt::LeftButton) + if (!ctrl) + deselect_all(); + + clicked_event_ptr->setSelected(!clicked_event_ptr->selected()); + + song->update(SC_SELECTION); + } setMouseTracking(false); unsetCursor(); + inserting=false; dragging=false; drag_cursor_changed=false; + undo_started=false; x_scroll_speed=0; x_scroll_pos=0; } @@ -3583,6 +3794,9 @@ void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event) if (have_lasso && event->button()==Qt::LeftButton) { + if (!ctrl) + deselect_all(); + set<Event*> already_processed; for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++) @@ -3600,6 +3814,9 @@ void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event) void ScoreCanvas::mouseMoveEvent (QMouseEvent* event) { + keystate=event->modifiers(); + bool ctrl=keystate & Qt::ControlModifier; + if (dragging) { int dx=event->x()-mouse_down_pos.x(); @@ -3630,6 +3847,22 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event) mouse_operation=PITCH; setCursor(Qt::SizeVerCursor); } + + if (mouse_operation!=NO_OP) + { + if (!inserting && clicked_event_ptr->selected()==false) + { + if (!ctrl) + deselect_all(); + + clicked_event_ptr->setSelected(true); + + song->update(SC_SELECTION); + } + + old_pitch=-1; + old_dest_tick=MAXINT; + } } int new_pitch; @@ -3640,70 +3873,41 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event) break; case PITCH: - if (debugMsg) cout << "changing pitch, delta="<<nearbyint((float)dy/PITCH_DELTA)<<endl; - new_pitch=dragged_event_original_pitch - nearbyint((float)dy/PITCH_DELTA); + if (heavyDebugMsg) cout << "trying to change pitch, delta="<<-nearbyint((float)dy/PITCH_DELTA)<<endl; + new_pitch=original_dragged_event.pitch() - nearbyint((float)dy/PITCH_DELTA); if (new_pitch < 0) new_pitch=0; if (new_pitch > 127) new_pitch=127; - if (dragged_event.pitch()!=new_pitch) + if (new_pitch != old_pitch) { - if (!undo_started) - { - song->startUndo(); - undo_started=true; - } - - Event tmp=dragged_event.clone(); - tmp.setPitch(new_pitch); - - audio->msgChangeEvent(dragged_event, tmp, dragged_event_part, false, false, false); - dragged_event=tmp; - - fully_recalculate(); + if (debugMsg) cout << "changing pitch, delta="<<new_pitch-original_dragged_event.pitch()<<endl; + if (undo_started) song->undo(); + undo_started=transpose_notes(part_to_set(dragged_event_part),1, new_pitch-original_dragged_event.pitch()); + old_pitch=new_pitch; } break; case BEGIN: - if (dragged_event.tick()+dragged_event_part->tick() != unsigned(tick)) { - if (!undo_started) - { - song->startUndo(); - undo_started=true; - } - - Event tmp=dragged_event.clone(); signed relative_tick=tick-signed(dragged_event_part->tick()); + unsigned dest_tick; if (relative_tick >= 0) - tmp.setTick(relative_tick); + dest_tick=relative_tick; else { - tmp.setTick(0); + dest_tick=0; if (debugMsg) cout << "not moving note before begin of part; setting it directly to the begin" << endl; } - if (tmp.endTick() > dragged_event_part->lenTick()) + if (dest_tick != old_dest_tick) { - signed new_len=dragged_event_part->lenTick() - tmp.tick(); - if (new_len>=0) - { - tmp.setLenTick(dragged_event_part->lenTick() - tmp.tick()); - if (debugMsg) cout << "moved note would exceed its part; clipping length to " << tmp.lenTick() << endl; - } - else - { - tmp.setLenTick(0); - if (debugMsg) cout << "moved note would exceed its part; clipping length to 0 (actually negative)" << endl; - } + if (undo_started) song->undo(); + undo_started=move_notes(part_to_set(dragged_event_part),1, (signed)dest_tick-original_dragged_event.tick()); + old_dest_tick=dest_tick; } - - audio->msgChangeEvent(dragged_event, tmp, dragged_event_part, false, false, false); - dragged_event=tmp; - - fully_recalculate(); } break; @@ -4007,6 +4211,7 @@ void ScoreCanvas::menu_command(int cmd) case CMD_NOTELEN_16: new_len=TICKS_PER_WHOLE/16; break; case CMD_NOTELEN_32: new_len=TICKS_PER_WHOLE/32; break; case CMD_NOTELEN_LAST: new_len=-1; break; + default: cerr << "ERROR: ILLEGAL FUNCTION CALL: ScoreCanvas::menu_command called with unknown command ("<<cmd<<")"<<endl; } @@ -4123,14 +4328,6 @@ void ScoreCanvas::deselect_all() song->update(SC_SELECTION); } -void ScoreCanvas::keyPressEvent(QKeyEvent* event) -{ - if (event->key()==Qt::Key_Delete) - { - erase_notes(get_all_parts(), 1); // 1 means "all selected" - } -} - bool staff_t::cleanup_parts() { bool did_something=false; @@ -4162,6 +4359,7 @@ bool staff_t::cleanup_parts() it++; } + if (did_something) update_part_indices(); return did_something; } @@ -4191,6 +4389,48 @@ void staff_t::apply_lasso(QRect rect, set<Event*>& already_processed) } } +void ScoreCanvas::set_steprec(bool flag) +{ + srec=flag; +} + +void ScoreCanvas::midi_note(int pitch, int velo) +{ + if (velo) + held_notes[pitch]=true; + else + held_notes[pitch]=false; + + if ( srec && selected_part && !audio->isPlaying() && velo ) + steprec->record(selected_part,pitch,quant_ticks(),quant_ticks(),velo,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier); +} + + + +void ScoreCanvas::update_parts() +{ + if (selected_part!=NULL) //if it's null, let it be null + selected_part=partFromSerialNumber(selected_part_index); + + for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++) + it->update_parts(); +} + +void staff_t::update_parts() +{ + parts.clear(); + + for (set<int>::iterator it=part_indices.begin(); it!=part_indices.end(); it++) + parts.insert(partFromSerialNumber(*it)); +} + +void staff_t::update_part_indices() +{ + part_indices.clear(); + + for (set<Part*>::iterator it=parts.begin(); it!=parts.end(); it++) + part_indices.insert((*it)->sn()); +} //the following assertions are made: // pix_quarter.width() == pix_half.width() @@ -4221,29 +4461,29 @@ void staff_t::apply_lasso(QRect rect, set<Event*>& already_processed) * o rename stuff: UndoOp -> Operation, Undo -> OpList, * UndoType -> OpType, iUndoOp, riUndoOp -> iOperation, * undo.cpp/.h -> operations.cpp/.h + * o either remove these "hidden notes", or deal with them in the score editor + * o investigate with valgrind + * o controller view in score editor + * o deal with expanding parts + * o fix sigedit boxes + * o mid-click in pianoroll: change to "delete", or initiate drag and drop between windows? * * * o drum list: scroll while dragging * * IMPORTANT TODO - * o add a select-clef-toolbox for tracks - * o respect the track's clef (has to be implemented first in muse) * o do partial recalculating; recalculating can take pretty long * (0,5 sec) when displaying a whole song in scores * o transpose etc. must also transpose key-pressure events * o transpose: support in-key-transpose - * o legato: extend length to next note - * o delete: add velo and len threshold * o thin out: remove unneeded ctrl messages * * less important stuff - * o controller view in score editor * o quantize-templates (everything is forced into a specified * rhythm) * o part-templates (you specify some notes and a control-chord; * the notes are set according to the chord then) * o add functions like set velo, mod/set velo-off - * o deal with expanding parts * o use bars instead of flags over groups of 8ths / 16ths etc * o support different keys in different tracks at the same time * calc_pos_add_list and calc_item_pos will be affected by this @@ -4260,6 +4500,7 @@ void staff_t::apply_lasso(QRect rect, set<Event*>& already_processed) * o refuse to resize so that width gets smaller or equal than x_left * o draw a margin around notes which are in a bright color * o support drum tracks (x-note-heads etc.) + * o drum list: scroll while dragging: probably unneccessary with the "reorder list" function * * * stuff for the other muse developers @@ -4271,8 +4512,6 @@ void staff_t::apply_lasso(QRect rect, set<Event*>& already_processed) * ( (2+2+3)/4 or (3+2+2)/4 instead of 7/4 ) * o maybe do expanding parts inside the msgChangeEvent or * msgNewEvent functions (see my e-mail) - * - * o make quantize and other stuff faster (by assymetric communication) */ diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h index 4004452f..e7302a46 100644 --- a/muse2/muse/midiedit/scoreedit.h +++ b/muse2/muse/midiedit/scoreedit.h @@ -22,6 +22,7 @@ #include <QActionGroup> #include <QGridLayout> #include <QByteArray> +#include <QToolButton> #include <values.h> #include "noteinfo.h" @@ -32,6 +33,9 @@ #include "part.h" #include "keyevent.h" #include "mtscale_flo.h" +#include "steprec.h" +#include "cleftypes.h" +#include "helper.h" #include <set> #include <map> @@ -58,7 +62,12 @@ enum {CMD_COLOR_BLACK, CMD_COLOR_VELO, CMD_COLOR_PART, CMD_NOTELEN_1, CMD_NOTELEN_2, CMD_NOTELEN_4, CMD_NOTELEN_8, CMD_NOTELEN_16, CMD_NOTELEN_32, CMD_NOTELEN_LAST, - CMD_QUANTIZE, CMD_VELOCITY, CMD_CRESCENDO, CMD_NOTELEN }; + CMD_QUANTIZE, CMD_VELOCITY, CMD_CRESCENDO, CMD_NOTELEN, CMD_TRANSPOSE, + CMD_ERASE, CMD_MOVE, CMD_FIXED_LEN, CMD_DELETE_OVERLAPS, CMD_LEGATO, + CMD_CUT, CMD_COPY, CMD_PASTE, CMD_DEL, + CMD_SELECT_ALL, CMD_SELECT_NONE, CMD_SELECT_INVERT, + CMD_SELECT_ILOOP, CMD_SELECT_OLOOP}; + class ScoreCanvas; class EditToolBar; @@ -70,7 +79,6 @@ class EditToolBar; class ScoreEdit : public TopWin { Q_OBJECT - private: virtual void closeEvent(QCloseEvent*); virtual void resizeEvent(QResizeEvent*); @@ -106,6 +114,32 @@ class ScoreEdit : public TopWin QAction* color_black_action; QAction* color_velo_action; QAction* color_part_action; + + QMenu* color_menu; + + QAction* cut_action; + QAction* copy_action; + QAction* paste_action; + QAction* del_action; + + QAction* select_all_action; + QAction* select_none_action; + QAction* select_invert_action; + QAction* select_iloop_action; + QAction* select_oloop_action; + + QAction* func_quantize_action; + QAction* func_notelen_action; + QAction* func_velocity_action; + QAction* func_cresc_action; + QAction* func_transpose_action; + QAction* func_erase_action; + QAction* func_move_action; + QAction* func_fixed_len_action; + QAction* func_del_overlaps_action; + QAction* func_legato_action; + + QToolButton* srec; QScrollBar* xscroll; QScrollBar* yscroll; @@ -129,6 +163,9 @@ class ScoreEdit : public TopWin void menu_command(int); void velo_box_changed(); void velo_off_box_changed(); + void init_shortcuts(); + void selection_changed(); + void clipboard_changed(); signals: void deleted(unsigned long); @@ -481,6 +518,7 @@ enum staff_mode_t struct staff_t { set<Part*> parts; + set<int> part_indices; ScoreEventList eventlist; ScoreItemList itemlist; @@ -524,6 +562,7 @@ struct staff_t clef=clef_; parts=parts_; parent=parent_; + update_part_indices(); } bool cleanup_parts(); @@ -532,6 +571,9 @@ struct staff_t void read_status(Xml& xml); void write_status(int level, Xml& xml) const; + + void update_parts(); //re-populates the set<Part*> from the set<int> + void update_part_indices(); //re-populates the set<int> from the set<Part*> }; list<int> calc_accidentials(key_enum key, clef_t clef, key_enum next_key=KEY_C); @@ -612,6 +654,8 @@ class ScoreCanvas : public View list<staff_t> staves; + StepRec* steprec; + // the drawing area is split into a "preamble" containing clef, // key and time signature, and the "item's area" containing the // actual items (notes, bars, rests, etc.) @@ -633,6 +677,8 @@ class ScoreCanvas : public View float y_scroll_pos; Part* selected_part; + int selected_part_index; + int last_len; int new_len; //when zero or negative, last_len is used @@ -651,20 +697,26 @@ class ScoreCanvas : public View bool mouse_erases_notes; bool mouse_inserts_notes; + bool inserting; bool dragging; bool drag_cursor_changed; Part* dragged_event_part; Event dragged_event; - int dragged_event_original_pitch; + Event original_dragged_event; + Event* clicked_event_ptr; + + int old_pitch; + unsigned old_dest_tick; bool have_lasso; QPoint lasso_start; QRect lasso; bool undo_started; - int undo_flags; - + bool temp_undo; + bool srec; + bool held_notes[128]; enum {COLOR_MODE_BLACK, COLOR_MODE_PART, COLOR_MODE_VELO} coloring_mode; bool preamble_contains_keysig; @@ -692,6 +744,7 @@ class ScoreCanvas : public View void config_changed(); void deselect_all(); + void midi_note(int pitch, int velo); public slots: void x_scroll_event(int); @@ -711,7 +764,10 @@ class ScoreCanvas : public View void set_velo(int); void set_velo_off(int); - + + void set_steprec(bool); + + void update_parts(); //re-populates the set<Part*>s from the set<int>s signals: void xscroll_changed(int); void yscroll_changed(int); @@ -731,7 +787,6 @@ class ScoreCanvas : public View virtual void mouseMoveEvent (QMouseEvent* event); virtual void mouseReleaseEvent (QMouseEvent* event); virtual void resizeEvent(QResizeEvent*); - virtual void keyPressEvent(QKeyEvent* event); public: ScoreCanvas(ScoreEdit*, QWidget*); @@ -755,7 +810,7 @@ class ScoreCanvas : public View void set_last_len(int l) {last_len=l;} Part* get_selected_part() {return selected_part;} - void set_selected_part(Part* p) {selected_part=p;} + void set_selected_part(Part* p) {selected_part=p; if (selected_part) selected_part_index=selected_part->sn();} set<Part*> get_all_parts(); |