1 //=============================================================================
2 //  MusE Score
3 //  Linux Music Score Editor
4 //
5 //  Copyright (C) 2010 Werner Schweer and others
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License version 2.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //=============================================================================
19 
20 #include "drumroll.h"
21 #include "config.h"
22 #include "piano.h"
23 #include "ruler.h"
24 #include "drumview.h"
25 #include "libmscore/staff.h"
26 #include "libmscore/score.h"
27 #include "libmscore/measure.h"
28 #include "libmscore/note.h"
29 #include "awl/pitchlabel.h"
30 #include "awl/pitchedit.h"
31 #include "awl/poslabel.h"
32 #include "musescore.h"
33 #include "libmscore/undo.h"
34 #include "libmscore/part.h"
35 #include "libmscore/instrument.h"
36 #include "seq.h"
37 #include "preferences.h"
38 
39 namespace Ms {
40 
41 //---------------------------------------------------------
42 //   DrumrollEditor
43 //---------------------------------------------------------
44 
DrumrollEditor(QWidget * parent)45 DrumrollEditor::DrumrollEditor(QWidget* parent)
46    : QMainWindow(parent)
47       {
48       setObjectName("Drumroll");
49       setWindowTitle(QString("MuseScore"));
50 //      setIconSize(QSize(preferences.iconWidth, preferences.iconHeight));
51 
52       QWidget* mainWidget = new QWidget;
53       QGridLayout* layout = new QGridLayout;
54       mainWidget->setLayout(layout);
55       layout->setSpacing(0);
56 
57       QToolBar* tb = addToolBar("Toolbar 1");
58       if (qApp->layoutDirection() == Qt::LayoutDirection::LeftToRight) {
59             tb->addAction(getAction("undo"));
60             tb->addAction(getAction("redo"));
61             }
62       else {
63             tb->addAction(getAction("redo"));
64             tb->addAction(getAction("undo"));
65             }
66       tb->addSeparator();
67 #ifdef HAS_MIDI
68       tb->addAction(getAction("midi-on"));
69 #endif
70       QAction* a = getAction("follow");
71       a->setCheckable(true);
72       a->setChecked(preferences.getBool(PREF_APP_PLAYBACK_FOLLOWSONG));
73 
74       tb->addAction(a);
75 
76       tb->addSeparator();
77       tb->addAction(getAction("rewind"));
78       tb->addAction(getAction("play"));
79       tb->addSeparator();
80 
81       //-------------
82       tb = addToolBar("Toolbar 2");
83       layout->addWidget(tb, 1, 0, 1, 2);
84 
85       for (int i = 0; i < VOICES; ++i) {
86             QToolButton* b = new QToolButton(this);
87             b->setToolButtonStyle(Qt::ToolButtonTextOnly);
88             QPalette p(b->palette());
89             p.setColor(QPalette::Base, MScore::selectColor[i]);
90             b->setPalette(p);
91             QAction* aa = getAction(voiceActions[i]);
92             b->setDefaultAction(aa);
93             tb->addWidget(b);
94             }
95 
96       tb->addSeparator();
97       tb->addWidget(new QLabel(tr("Cursor:")));
98       pos = new Awl::PosLabel;
99       tb->addWidget(pos);
100       Awl::PitchLabel* pl = new Awl::PitchLabel();
101       tb->addWidget(pl);
102 
103       tb->addSeparator();
104       tb->addWidget(new QLabel(tr("Velocity:")));
105       veloType = new QComboBox;
106       veloType->addItem(tr("Offset"), int(Note::ValueType::OFFSET_VAL));
107       veloType->addItem(tr("User"),   int(Note::ValueType::USER_VAL));
108       tb->addWidget(veloType);
109 
110       velocity = new QSpinBox;
111       velocity->setRange(-1, 127);
112       velocity->setSpecialValueText("--");
113       velocity->setReadOnly(true);
114       tb->addWidget(velocity);
115 
116       tb->addWidget(new QLabel(tr("Pitch:")));
117       pitch = new Awl::PitchEdit;
118       pitch->setReadOnly(true);
119       tb->addWidget(pitch);
120 
121       double xmag = .1;
122       gv  = new DrumView;
123       gv->scale(xmag, 1.0);
124       layout->addWidget(gv, 3, 1);
125 
126       ruler = new Ruler;
127       ruler->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
128       ruler->setFixedHeight(rulerHeight);
129       ruler->setMag(xmag, 1.0);
130 
131       layout->addWidget(ruler, 2, 1);
132 
133       Piano* piano = new Piano;
134       piano->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
135       piano->setFixedWidth(pianoWidth);
136       layout->addWidget(piano, 3, 0);
137 
138       setCentralWidget(mainWidget);
139 
140       connect(gv->verticalScrollBar(), SIGNAL(valueChanged(int)), piano, SLOT(setYpos(int)));
141       connect(gv->horizontalScrollBar(), SIGNAL(valueChanged(int)), ruler, SLOT(setXpos(int)));
142       connect(gv,          SIGNAL(xposChanged(int)),           ruler, SLOT(setXpos(int)));
143       connect(gv,          SIGNAL(magChanged(double,double)),  ruler, SLOT(setMag(double,double)));
144       connect(gv,          SIGNAL(magChanged(double,double)),  piano, SLOT(setMag(double,double)));
145       connect(gv,          SIGNAL(pitchChanged(int)),          pl,    SLOT(setPitch(int)));
146       connect(gv,          SIGNAL(pitchChanged(int)),          piano, SLOT(setPitch(int)));
147       connect(piano,       SIGNAL(pitchChanged(int)),          pl,    SLOT(setPitch(int)));
148       connect(gv,          SIGNAL(posChanged(const Pos&)),     pos,   SLOT(setValue(const Pos&)));
149       connect(gv,          SIGNAL(posChanged(const Pos&)),     ruler, SLOT(setPos(const Pos&)));
150       connect(ruler,       SIGNAL(posChanged(const Pos&)),     pos,   SLOT(setValue(const Pos&)));
151       connect(ruler,       SIGNAL(locatorMoved(int)),                 SLOT(moveLocator(int)));
152       connect(veloType,    SIGNAL(activated(int)),                    SLOT(veloTypeChanged(int)));
153       connect(velocity,    SIGNAL(valueChanged(int)),                 SLOT(velocityChanged(int)));
154       connect(gv->scene(), SIGNAL(selectionChanged()),                SLOT(selectionChanged()));
155       connect(piano,       SIGNAL(keyPressed(int)),                   SLOT(keyPressed(int)));
156       connect(piano,       SIGNAL(keyReleased(int)),                  SLOT(keyReleased(int)));
157       resize(800, 400);
158 
159       QActionGroup* ag = new QActionGroup(this);
160       a = new QAction(this);
161       a->setData("delete");
162       a->setShortcut(Qt::Key_Delete);
163       ag->addAction(a);
164       addActions(ag->actions());
165       connect(ag, SIGNAL(triggered(QAction*)), SLOT(cmd(QAction*)));
166 
167       readSettings();
168       }
169 
170 //---------------------------------------------------------
171 //   writeSettings
172 //---------------------------------------------------------
173 
writeSettings()174 void DrumrollEditor::writeSettings()
175       {
176       MuseScore::saveGeometry(this);
177       }
178 
179 //---------------------------------------------------------
180 //   readSettings
181 //---------------------------------------------------------
182 
readSettings()183 void DrumrollEditor::readSettings()
184       {
185       MuseScore::restoreGeometry(this);
186       }
187 
188 //---------------------------------------------------------
189 //   setStaff
190 //---------------------------------------------------------
191 
setStaff(Staff * st)192 void DrumrollEditor::setStaff(Staff* st)
193       {
194       staff = st;
195       _score = staff->score();
196       setWindowTitle(tr("<%1> Staff: %2").arg(_score->masterScore()->fileInfo()->completeBaseName()).arg(st->idx()));
197       TempoMap* tl = _score->tempomap();
198       TimeSigMap*  sl = _score->sigmap();
199       for (int i = 0; i < 3; ++i)
200             locator[i].setContext(tl, sl);
201 
202       locator[0].setTick(480 * 5 + 240);  // some random test values
203       locator[1].setTick(480 * 3 + 240);
204       locator[2].setTick(480 * 12 + 240);
205 
206       gv->setStaff(staff, locator);
207       ruler->setScore(_score, locator);
208       pos->setContext(tl, sl);
209       updateSelection();
210       }
211 
212 //---------------------------------------------------------
213 //   updateSelection
214 //---------------------------------------------------------
215 
updateSelection()216 void DrumrollEditor::updateSelection()
217       {
218       QList<QGraphicsItem*> items = gv->scene()->selectedItems();
219       if (items.size() == 1) {
220             QGraphicsItem* item = items[0];
221             Note* note = static_cast<Note*>(item->data(0).value<void*>());
222             pitch->setEnabled(true);
223             pitch->setValue(note->pitch());
224             veloType->setEnabled(true);
225             velocity->setEnabled(true);
226             updateVelocity(note);
227             }
228       else if (items.size() == 0) {
229             velocity->setValue(0);
230             velocity->setEnabled(false);
231             pitch->setValue(0);
232             pitch->setEnabled(false);
233             veloType->setEnabled(false);
234             veloType->setCurrentIndex(int(Note::ValueType::OFFSET_VAL));
235             }
236       else {
237             velocity->setEnabled(true);
238             velocity->setValue(0);
239             velocity->setReadOnly(false);
240             pitch->setEnabled(true);
241             pitch->setDeltaMode(true);
242             pitch->setValue(0);
243             veloType->setEnabled(true);
244             veloType->setCurrentIndex(int(Note::ValueType::OFFSET_VAL));
245             }
246       }
247 
248 //---------------------------------------------------------
249 //   selectionChanged
250 //---------------------------------------------------------
251 
selectionChanged()252 void DrumrollEditor::selectionChanged()
253       {
254       updateSelection();
255 //      _score->blockSignals(true);
256       QList<QGraphicsItem*> items = gv->scene()->selectedItems();
257       if (items.size() == 1) {
258             QGraphicsItem* item = items[0];
259             Note* note = static_cast<Note*>(item->data(0).value<void*>());
260             if (note)
261                   _score->select(note, SelectType::SINGLE, 0);
262             }
263       else if (items.size() == 0) {
264             _score->select(0, SelectType::SINGLE, 0);
265             }
266       else {
267             _score->select(0, SelectType::SINGLE, 0);
268             foreach(QGraphicsItem* item, items) {
269                   Note* note = static_cast<Note*>(item->data(0).value<void*>());
270                   if (note)
271                         _score->select(note, SelectType::ADD, 0);
272                   }
273             }
274       _score->setUpdateAll();
275       _score->update();
276 //      _score->blockSignals(false);
277       }
278 
279 //---------------------------------------------------------
280 //   changeSelection
281 //---------------------------------------------------------
282 
changeSelection(SelState)283 void DrumrollEditor::changeSelection(SelState)
284       {
285       gv->scene()->blockSignals(true);
286       gv->scene()->clearSelection();
287       QList<QGraphicsItem*> il = gv->scene()->items();
288       foreach(QGraphicsItem* item, il) {
289             Note* note = static_cast<Note*>(item->data(0).value<void*>());
290             if (note)
291                   item->setSelected(note->selected());
292             }
293       gv->scene()->blockSignals(false);
294       }
295 
296 //---------------------------------------------------------
297 //   veloTypeChanged
298 //---------------------------------------------------------
299 
veloTypeChanged(int val)300 void DrumrollEditor::veloTypeChanged(int val)
301       {
302       QList<QGraphicsItem*> items = gv->scene()->selectedItems();
303       if (items.size() != 1)
304             return;
305       QGraphicsItem* item = items[0];
306       Note* note = (Note*)item->data(0).value<void*>();
307       if ((note == 0) || (Note::ValueType(val) == note->veloType()))
308             return;
309 
310       _score->startCmd();
311       _score->undo(new ChangeVelocity(note, Note::ValueType(val), note->veloOffset()));
312       _score->endCmd();
313       updateVelocity(note);
314       }
315 
316 //---------------------------------------------------------
317 //   updateVelocity
318 //---------------------------------------------------------
319 
updateVelocity(Note * note)320 void DrumrollEditor::updateVelocity(Note* note)
321       {
322       Note::ValueType vt = note->veloType();
323       if (vt != Note::ValueType(veloType->currentIndex())) {
324             veloType->setCurrentIndex(int(vt));
325             switch(vt) {
326                   case Note::ValueType::USER_VAL:
327                         velocity->setReadOnly(false);
328                         velocity->setSuffix("");
329                         velocity->setRange(0, 127);
330                         break;
331                   case Note::ValueType::OFFSET_VAL:
332                         velocity->setReadOnly(false);
333                         velocity->setSuffix("%");
334                         velocity->setRange(-200, 200);
335                         break;
336                   }
337             }
338       velocity->setValue(note->veloOffset());
339       }
340 
341 //---------------------------------------------------------
342 //   velocityChanged
343 //---------------------------------------------------------
344 
velocityChanged(int val)345 void DrumrollEditor::velocityChanged(int val)
346       {
347       QList<QGraphicsItem*> items = gv->scene()->selectedItems();
348       if (items.size() != 1)
349             return;
350       QGraphicsItem* item = items[0];
351       Note* note = (Note*)item->data(0).value<void*>();
352       if (note == 0)
353             return;
354       Note::ValueType vt = note->veloType();
355 
356       if (vt == Note::ValueType::OFFSET_VAL)
357             return;
358 
359       _score->startCmd();
360       _score->undo(new ChangeVelocity(note, vt, val));
361       _score->endCmd();
362       }
363 
364 //---------------------------------------------------------
365 //   keyPressed
366 //---------------------------------------------------------
367 
keyPressed(int p)368 void DrumrollEditor::keyPressed(int p)
369       {
370       seq->startNote(staff->part()->instrument()->channel(0)->channel(), p, 80, 0, 0.0);  //tick?
371       }
372 
373 //---------------------------------------------------------
374 //   keyReleased
375 //---------------------------------------------------------
376 
keyReleased(int)377 void DrumrollEditor::keyReleased(int /*pitch*/)
378       {
379       seq->stopNotes();
380       }
381 
382 //---------------------------------------------------------
383 //   heartBeat
384 //---------------------------------------------------------
385 
heartBeat(Seq * s)386 void DrumrollEditor::heartBeat(Seq* s)
387       {
388       unsigned t = s->getCurTick();
389       if (locator[0].tick() != t) {
390             locator[0].setTick(t);
391             gv->moveLocator(0);
392             ruler->update();
393             if (preferences.getBool(PREF_APP_PLAYBACK_FOLLOWSONG))
394                   gv->ensureVisible(t);
395             }
396       }
397 
398 //---------------------------------------------------------
399 //   moveLocator
400 //---------------------------------------------------------
401 
moveLocator(int i)402 void DrumrollEditor::moveLocator(int i)
403       {
404       if (locator[i].valid()) {
405             seq->seek(locator[i].tick());
406             gv->moveLocator(i);
407             }
408       }
409 
410 //---------------------------------------------------------
411 //   cmd
412 //---------------------------------------------------------
413 
cmd(QAction * a)414 void DrumrollEditor::cmd(QAction* a)
415       {
416       score()->startCmd();
417       if (a->data() == "delete") {
418             QList<QGraphicsItem*> items = gv->items();
419             foreach(QGraphicsItem* item, items) {
420                   Note* note = static_cast<Note*>(item->data(0).value<void*>());
421                   if (note) {
422                         score()->deleteItem(note);
423                         }
424                   }
425             }
426 
427       gv->setStaff(staff, locator);
428       }
429 }
430 
431