summaryrefslogtreecommitdiff
path: root/muse2/muse/midiedit
diff options
context:
space:
mode:
Diffstat (limited to 'muse2/muse/midiedit')
-rw-r--r--muse2/muse/midiedit/dcanvas.cpp79
-rw-r--r--muse2/muse/midiedit/dcanvas.h13
-rw-r--r--muse2/muse/midiedit/dlist.cpp158
-rw-r--r--muse2/muse/midiedit/dlist.h27
-rw-r--r--muse2/muse/midiedit/drumedit.cpp19
-rw-r--r--muse2/muse/midiedit/drumedit.h4
-rw-r--r--muse2/muse/midiedit/ecanvas.cpp134
-rw-r--r--muse2/muse/midiedit/ecanvas.h3
-rw-r--r--muse2/muse/midiedit/piano.h4
-rw-r--r--muse2/muse/midiedit/pianoroll.cpp21
-rw-r--r--muse2/muse/midiedit/pianoroll.h4
-rw-r--r--muse2/muse/midiedit/prcanvas.cpp167
-rw-r--r--muse2/muse/midiedit/prcanvas.h16
-rw-r--r--muse2/muse/midiedit/scoreedit.cpp563
-rw-r--r--muse2/muse/midiedit/scoreedit.h71
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();