~ubuntu-branches/ubuntu/karmic/muse/karmic-proposed

« back to all changes in this revision

Viewing changes to midiedit/prcanvas.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2002-04-23 17:28:23 UTC
  • Revision ID: james.westby@ubuntu.com-20020423172823-w8yplzr81a759xa3
Tags: upstream-0.5.2
ImportĀ upstreamĀ versionĀ 0.5.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//=========================================================
 
2
//  MusE
 
3
//  Linux Music Editor
 
4
//    $Id: prcanvas.cpp,v 1.2 2002/02/27 08:48:09 muse Exp $
 
5
//  (C) Copyright 1999,2000 Werner Schweer (ws@seh.de)
 
6
//=========================================================
 
7
 
 
8
#include <stdio.h>
 
9
#include <qapplication.h>
 
10
#include <qclipboard.h>
 
11
#include <qpainter.h>
 
12
#include <qdragobject.h>
 
13
#include <math.h>
 
14
#include <errno.h>
 
15
#include <sys/stat.h>
 
16
#include <sys/mman.h>
 
17
 
 
18
#include "midithread.h"
 
19
#include "xml.h"
 
20
#include "prcanvas.h"
 
21
#include "midiport.h"
 
22
#include "event.h"
 
23
#include "globals.h"
 
24
 
 
25
#include "cmd.h"
 
26
#include "gatetime.h"
 
27
#include "velocity.h"
 
28
#include "song.h"
 
29
 
 
30
//---------------------------------------------------------
 
31
//   NEvent
 
32
//---------------------------------------------------------
 
33
 
 
34
NEvent::NEvent(Event* e, Part* p, int y) : CItem(e, p)
 
35
      {
 
36
      y = y - KH/4;
 
37
      setPos(QPoint(e->posTick(), y));
 
38
      setBBox(QRect(e->posTick(), y, e->lenTick(), KH/2));
 
39
      }
 
40
 
 
41
//---------------------------------------------------------
 
42
//   addItem
 
43
//---------------------------------------------------------
 
44
 
 
45
void PianoCanvas::addItem(Part* part, Event* event)
 
46
      {
 
47
      NEvent* ev = new NEvent(event, part, pitch2y(((MidiEvent*)event)->pitch()));
 
48
      items.add(ev);
 
49
      }
 
50
 
 
51
//---------------------------------------------------------
 
52
//   PianoCanvas
 
53
//---------------------------------------------------------
 
54
 
 
55
PianoCanvas::PianoCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy)
 
56
   : EventCanvas(pr, parent, sx, sy)
 
57
      {
 
58
      colorMode = 0;
 
59
      cmdRange  = 0;     // all Events
 
60
      playedPitch = -1;
 
61
 
 
62
      songChanged(SC_TRACK_INSERTED);
 
63
      connect(midiThread, SIGNAL(midiNote(int, int)), SLOT(midiNote(int,int)));
 
64
      }
 
65
 
 
66
//---------------------------------------------------------
 
67
//   pitch2y
 
68
//---------------------------------------------------------
 
69
 
 
70
int PianoCanvas::pitch2y(int pitch) const
 
71
      {
 
72
      int tt[] = {
 
73
            5, 12, 19, 26, 33, 44, 51, 58, 64, 71, 78, 85
 
74
            };
 
75
      int y = (75 * KH) - (tt[pitch%12] + (7 * KH) * (pitch/12));
 
76
      if (y < 0)
 
77
            y = 0;
 
78
      return y;
 
79
      }
 
80
 
 
81
//---------------------------------------------------------
 
82
//   y2pitch
 
83
//---------------------------------------------------------
 
84
 
 
85
int PianoCanvas::y2pitch(int y) const
 
86
      {
 
87
      const int total = (10 * 7 + 5) * KH;       // 75 Ganztonschritte
 
88
      y = total - y;
 
89
      int oct = (y / (7 * KH)) * 12;
 
90
      char kt[] = {
 
91
            0, 0, 0, 0, 0,  0,   0, 0, 0, 0,          // 5
 
92
            1, 1, 1,      1,   1, 1, 1,               // 13
 
93
            2, 2,         2,   2, 2, 2,               // 19
 
94
            3, 3, 3,      3,   3, 3, 3,               // 26
 
95
            4, 4, 4, 4,   4,   4, 4, 4, 4,            // 34
 
96
            5, 5, 5, 5,   5,   5, 5, 5, 5, 5,         // 43
 
97
            6, 6, 6,      6,   6, 6, 6,               // 52
 
98
            7, 7,         7,   7, 7, 7,               // 58
 
99
            8, 8, 8,      8,   8, 8, 8,               // 65
 
100
            9, 9,         9,   9, 9, 9,               // 71
 
101
            10, 10, 10,  10,   10, 10, 10,            // 78
 
102
            11, 11, 11, 11, 11,   11, 11, 11, 11, 11  // 87
 
103
            };
 
104
      return kt[y % 91] + oct;
 
105
      }
 
106
 
 
107
//---------------------------------------------------------
 
108
//   drawEvent
 
109
//    draws a note
 
110
//---------------------------------------------------------
 
111
 
 
112
void PianoCanvas::drawItem(QPainter& p, const CItem* item,
 
113
   const QRect&) const
 
114
      {
 
115
      p.setPen(black);
 
116
      QRect r = item->bbox();
 
117
 
 
118
      struct Triple {
 
119
            int r, g, b;
 
120
            };
 
121
      static Triple color1[12] = {
 
122
            { 0xff, 0x3d, 0x39 },
 
123
            { 0x39, 0xff, 0x39 },
 
124
            { 0x39, 0x3d, 0xff },
 
125
            { 0xff, 0xff, 0x39 },
 
126
            { 0xff, 0x3d, 0xff },
 
127
            { 0x39, 0xff, 0xff },
 
128
            { 0xff, 0x7e, 0x7a },
 
129
            { 0x7a, 0x7e, 0xff },
 
130
            { 0x7a, 0xff, 0x7a },
 
131
            { 0xff, 0x7e, 0xbf },
 
132
            { 0x7a, 0xbf, 0xff },
 
133
            { 0xff, 0xbf, 0x7a }
 
134
            };
 
135
 
 
136
      NEvent* nevent   = (NEvent*) item;
 
137
      MidiEvent* event = (MidiEvent*)nevent->event();
 
138
 
 
139
      QColor color;
 
140
      if (nevent->part() != curPart)
 
141
            p.setBrush(lightGray);
 
142
      else {
 
143
            if (item->isMoving()) {
 
144
                  p.setBrush(gray);
 
145
                  p.drawRect(r);
 
146
                  p.setBrush(NoBrush);
 
147
                  p.drawRect(item->mp().x(), item->mp().y() - item->height()/2, item->width(), item->height());
 
148
                  return;
 
149
                  }
 
150
            else if (item->isSelected()) {
 
151
                  p.setBrush(black);
 
152
                  }
 
153
            else {
 
154
                  color.setRgb(0, 0, 255);
 
155
                  switch(colorMode) {
 
156
                        case 0:
 
157
                              break;
 
158
                        case 1:     // pitch
 
159
                              {
 
160
                              Triple* c = &color1[event->pitch() % 12];
 
161
                              color.setRgb(c->r, c->g, c->b);
 
162
                              }
 
163
                              break;
 
164
                        case 2:     // velocity
 
165
                              {
 
166
                              int velo = event->velo();
 
167
                              if (velo < 64)
 
168
                                    color.setRgb(velo*4, 0, 0xff);
 
169
                              else
 
170
                                    color.setRgb(0xff, 0, (velo-64) * 4);
 
171
                              }
 
172
                              break;
 
173
                        }
 
174
                  p.setBrush(color);
 
175
                  }
 
176
            }
 
177
      p.drawRect(r);
 
178
      }
 
179
 
 
180
//---------------------------------------------------------
 
181
//   viewMouseDoubleClickEvent
 
182
//---------------------------------------------------------
 
183
 
 
184
void PianoCanvas::viewMouseDoubleClickEvent(QMouseEvent* event)
 
185
      {
 
186
      if ((_tool != PointerTool) && (event->button() != QMouseEvent::LeftButton)) {
 
187
            mousePress(event);
 
188
            return;
 
189
            }
 
190
      }
 
191
 
 
192
//---------------------------------------------------------
 
193
//   moveItem
 
194
//    wird nach dem Moven eines Objektes aufgerufen
 
195
//---------------------------------------------------------
 
196
 
 
197
bool PianoCanvas::moveItem(CItem* item, const QPoint& pos, bool copy)
 
198
      {
 
199
      NEvent* nevent   = (NEvent*) item;
 
200
      MidiEvent* event = (MidiEvent*)nevent->event();
 
201
      int ntick        = editor->rasterVal(pos.x());
 
202
      int npitch       = y2pitch(pos.y());
 
203
      MidiEvent* newEvent = new MidiEvent(*event);
 
204
 
 
205
      if (event->pitch() != npitch && _playEvents) {
 
206
            int port         = track()->outPort();
 
207
            int channel      = track()->outChannel();
 
208
            // release note:
 
209
            MidiEvent ev1(port, channel, 0, MidiEvent::Note, event->pitch(), 0, 0, 0);
 
210
            midiThread->playMidiEvent(&ev1);
 
211
            MidiEvent ev2(port, channel, 0, MidiEvent::Note, npitch, event->velo(), 0, 0);
 
212
            midiThread->playMidiEvent(&ev2);
 
213
            }
 
214
 
 
215
      newEvent->setPitch(npitch);
 
216
      newEvent->setPosTick(ntick);
 
217
      newEvent->setLenTick(event->lenTick());
 
218
 
 
219
      if (copy) {
 
220
            midiThread->msgAddEvent(newEvent, nevent->part(), false);
 
221
            }
 
222
      else {
 
223
            midiThread->msgChangeEvent(event, newEvent, nevent->part(), false);
 
224
            }
 
225
      return true;
 
226
      }
 
227
 
 
228
//---------------------------------------------------------
 
229
//   newItem(p, state)
 
230
//---------------------------------------------------------
 
231
 
 
232
CItem* PianoCanvas::newItem(const QPoint& p, int)
 
233
      {
 
234
      int pitch = y2pitch(p.y());
 
235
      int tick  = editor->rasterVal1(p.x());
 
236
      int len   = p.x() - tick;
 
237
      MidiEvent* e = new MidiEvent(track()->outPort(),
 
238
         track()->outChannel(), tick, MidiEvent::Note,
 
239
        pitch, curVelo, 0, len);
 
240
      return new NEvent(e, curPart, pitch2y(pitch));
 
241
      }
 
242
 
 
243
void PianoCanvas::newItem(CItem* item, bool noSnap)
 
244
      {
 
245
      NEvent* nevent = (NEvent*) item;
 
246
      MidiEvent* event = (MidiEvent*)nevent->event();
 
247
      if (noSnap) {
 
248
            event->setPosTick(item->x()); //round down
 
249
            event->setLenTick(item->width());
 
250
            }
 
251
      else {
 
252
            event->setPosTick(editor->rasterVal1(item->x())); //round down
 
253
            event->setLenTick(editor->quantVal(item->width()));
 
254
            }
 
255
      event->setPitch(y2pitch(item->y()));
 
256
      midiThread->msgAddEvent(event, nevent->part());
 
257
      }
 
258
 
 
259
//---------------------------------------------------------
 
260
//   resizeItem
 
261
//---------------------------------------------------------
 
262
 
 
263
void PianoCanvas::resizeItem(CItem* item, bool noSnap)
 
264
      {
 
265
      NEvent* nevent = (NEvent*) item;
 
266
      MidiEvent* event = (MidiEvent*)(nevent->event());
 
267
      MidiEvent* newEvent = new MidiEvent(*event);
 
268
      int len;
 
269
      if (noSnap)
 
270
            len = nevent->width();
 
271
      else
 
272
            len = editor->quantVal(nevent->width());
 
273
      newEvent->setLenTick(len);
 
274
      midiThread->msgChangeEvent(event, newEvent, nevent->part());
 
275
      }
 
276
 
 
277
//---------------------------------------------------------
 
278
//   deleteItem
 
279
//---------------------------------------------------------
 
280
 
 
281
bool PianoCanvas::deleteItem(CItem* item)
 
282
      {
 
283
      NEvent* nevent = (NEvent*) item;
 
284
      if (nevent->part() == curPart) {
 
285
            midiThread->msgDeleteEvent(((NEvent*)item)->event(), ((NEvent*)item)->part());
 
286
            return true;
 
287
            }
 
288
      return false;
 
289
      }
 
290
 
 
291
//---------------------------------------------------------
 
292
//   pianoCmd
 
293
//---------------------------------------------------------
 
294
 
 
295
void PianoCanvas::pianoCmd(int cmd)
 
296
      {
 
297
      switch(cmd) {
 
298
            case CMD_LEFT:
 
299
                  song->setPos(0, pos[0] - editor->rasterStep(pos[0]),
 
300
                     true, false, true); //CDW
 
301
                  break;
 
302
            case CMD_RIGHT:
 
303
                  song->setPos(0, pos[0] + editor->rasterStep(pos[0]),
 
304
                     true, false, true); //CDW
 
305
                  break;
 
306
            case CMD_INSERT:
 
307
                  if (pos[0] < start() || pos[0] >= end())
 
308
                        break;
 
309
                  {
 
310
                  MidiPart* part = (MidiPart*)curPart;
 
311
                  if (part == 0)
 
312
                        break;
 
313
                  song->startUndo();
 
314
                  EventList* el = part->events();
 
315
 
 
316
                  std::list <MidiEvent*> elist;
 
317
                  for (iEvent e = el->lower_bound(pos[0]); e != el->end(); ++e)
 
318
                        elist.push_back((MidiEvent*)e->second);
 
319
                  for (std::list<MidiEvent*>::iterator i = elist.begin(); i != elist.end(); ++i) {
 
320
                        MidiEvent* event = *i;
 
321
                        MidiEvent* newEvent = new MidiEvent(*event);
 
322
                        newEvent->setPosTick(event->posTick() + editor->raster());
 
323
                        midiThread->msgChangeEvent(event, newEvent, part, false);
 
324
                        }
 
325
                  song->endUndo(SC_EVENT_MODIFIED);
 
326
                  song->setPos(0, editor->rasterVal(pos[0] + editor->rasterStep(pos[0])),
 
327
                     true, false, true);
 
328
                  }
 
329
                  return;
 
330
            case CMD_DELETE:
 
331
                  if (pos[0] < start() || pos[0] >= end())
 
332
                        break;
 
333
                  {
 
334
                  MidiPart* part = (MidiPart*)curPart;
 
335
                  if (part == 0)
 
336
                        break;
 
337
                  song->startUndo();
 
338
                  EventList* el = part->events();
 
339
 
 
340
                  std::list <MidiEvent*> elist;
 
341
                  for (iEvent e = el->lower_bound(pos[0]); e != el->end(); ++e)
 
342
                        elist.push_back((MidiEvent*)e->second);
 
343
                  for (std::list<MidiEvent*>::iterator i = elist.begin(); i != elist.end(); ++i) {
 
344
                        MidiEvent* event = *i;
 
345
                        MidiEvent* newEvent = new MidiEvent(*event);
 
346
                        newEvent->setPosTick(event->posTick() - editor->raster());
 
347
                        midiThread->msgChangeEvent(event, newEvent, part, false);
 
348
                        }
 
349
                  song->endUndo(SC_EVENT_MODIFIED);
 
350
                  song->setPos(0, editor->rasterVal(pos[0] - editor->rasterStep(pos[0])),
 
351
                     true, false, true);
 
352
                  }
 
353
                  break;
 
354
            }
 
355
      }
 
356
 
 
357
//---------------------------------------------------------
 
358
//   pianoPressed
 
359
//---------------------------------------------------------
 
360
 
 
361
void PianoCanvas::pianoPressed(int pitch, bool shift)
 
362
      {
 
363
      int port    = track()->outPort();
 
364
      int channel = track()->outChannel();
 
365
 
 
366
      // play note:
 
367
      MidiEvent e(port, channel, 0, MidiEvent::Note, pitch, 127, 0, 0);
 
368
      midiThread->playMidiEvent(&e);
 
369
 
 
370
      if (_steprec && pos[0] >= start_tick && pos[0] < end_tick) {
 
371
            if (curPart == 0)
 
372
                  return;
 
373
            int len  = editor->quant();
 
374
            int tick = pos[0]; //CDW
 
375
            if (shift)
 
376
                  tick -= editor->rasterStep(tick);
 
377
            MidiEvent* e = new MidiEvent(port, channel,
 
378
               tick, MidiEvent::Note, pitch, 127, 0, len);
 
379
            midiThread->msgAddEvent(e, curPart);
 
380
            tick += editor->rasterStep(tick);
 
381
            if (tick != song->cpos())
 
382
                  song->setPos(0, tick, true, false, true);
 
383
            }
 
384
      }
 
385
 
 
386
//---------------------------------------------------------
 
387
//   pianoReleased
 
388
//---------------------------------------------------------
 
389
 
 
390
void PianoCanvas::pianoReleased(int pitch, bool)
 
391
      {
 
392
      int port    = track()->outPort();
 
393
      int channel = track()->outChannel();
 
394
 
 
395
      // release key:
 
396
      MidiEvent e(port, channel, 0, MidiEvent::Note, pitch, 0, 0, 0);
 
397
      midiThread->playMidiEvent(&e);
 
398
      }
 
399
 
 
400
//---------------------------------------------------------
 
401
//   drawTickRaster
 
402
//---------------------------------------------------------
 
403
 
 
404
void drawTickRaster(QPainter& p, int x, int y, int w, int h, int quant)
 
405
      {
 
406
      int bar1, bar2, beat, tick;
 
407
      sigmap.tickValues(x, &bar1, &beat, &tick);
 
408
      sigmap.tickValues(x+w, &bar2, &beat, &tick);
 
409
      ++bar2;
 
410
      int y2 = y + h;
 
411
      for (int bar = bar1; bar < bar2; ++bar) {
 
412
            int x = sigmap.bar2tick(bar, 0, 0);
 
413
            p.setPen(Qt::black);
 
414
            p.drawLine(x, y, x, y2);
 
415
            p.setPen(Qt::gray);
 
416
            int z, n;
 
417
            sigmap.timesig(x, z, n);
 
418
            int q = p.xForm(QPoint(quant, 0)).x() - p.xForm(QPoint(0, 0)).x();
 
419
            int qq = quant;
 
420
            if (q < 8)        // grid too dense
 
421
                  qq *= 2;
 
422
            switch (quant) {
 
423
                  case 32:
 
424
                  case 48:
 
425
                  case 64:
 
426
                  case 96:
 
427
                  case 192:         // 8tel
 
428
                  case 128:         // 8tel Triolen
 
429
                  case 288:
 
430
                        {
 
431
                        int xx = x + qq;
 
432
                        for (int beat = 1; beat <= z; beat++) {
 
433
                              int xxx = sigmap.bar2tick(bar, beat, 0);
 
434
                              while (xx <= xxx) {
 
435
                                    p.drawLine(xx, y, xx, y2);
 
436
                                    xx += qq;
 
437
                                    }
 
438
                              xx = xxx;
 
439
                              }
 
440
                        }
 
441
                        break;
 
442
                  default:
 
443
                        for (int beat = 1; beat < z; beat++) {
 
444
                              int xx = sigmap.bar2tick(bar, beat, 0);
 
445
                              p.drawLine(xx, y, xx, y2);
 
446
                              }
 
447
                        break;
 
448
                  }
 
449
            }
 
450
      }
 
451
 
 
452
//---------------------------------------------------------
 
453
//   draw
 
454
//---------------------------------------------------------
 
455
 
 
456
void PianoCanvas::drawCanvas(QPainter& p, const QRect& rect)
 
457
      {
 
458
      int x = rect.x();
 
459
      int y = rect.y();
 
460
      int w = rect.width();
 
461
      int h = rect.height();
 
462
 
 
463
      //---------------------------------------------------
 
464
      //  horizontal lines
 
465
      //---------------------------------------------------
 
466
 
 
467
      int yy  = ((y-1) / KH) * KH + KH;
 
468
      int key = 75 - (yy / KH);
 
469
      for (; yy < y + h; yy += KH) {
 
470
            switch (key % 7) {
 
471
                  case 0:
 
472
                  case 3:
 
473
                        p.setPen(black);
 
474
                        break;
 
475
                  default:
 
476
                        p.setPen(gray);
 
477
                        break;
 
478
                  }
 
479
            p.drawLine(x, yy, x + w, yy);
 
480
            --key;
 
481
            }
 
482
 
 
483
      //---------------------------------------------------
 
484
      // vertical lines
 
485
      //---------------------------------------------------
 
486
 
 
487
      drawTickRaster(p, x, y, w, h, editor->quant());
 
488
      }
 
489
 
 
490
//---------------------------------------------------------
 
491
//   cmd
 
492
//    pulldown menu commands
 
493
//---------------------------------------------------------
 
494
 
 
495
void PianoCanvas::cmd(int cmd, int quantStrength,
 
496
   int quantLimit, bool quantLen, int range)
 
497
      {
 
498
      cmdRange = range;
 
499
      switch (cmd) {
 
500
            case CMD_CUT:
 
501
                  copy();
 
502
                  song->startUndo();
 
503
                  for (iCItem i = items.begin(); i != items.end(); ++i) {
 
504
                        if (!(i->second->isSelected()))
 
505
                              continue;
 
506
                        NEvent* e = (NEvent*)(i->second);
 
507
                        midiThread->msgDeleteEvent(e->event(), e->part(), false);
 
508
                        }
 
509
                  song->endUndo(SC_EVENT_REMOVED);
 
510
                  break;
 
511
            case CMD_COPY:
 
512
                  copy();
 
513
                  break;
 
514
            case CMD_PASTE:
 
515
                  paste();
 
516
                  break;
 
517
            case CMD_DEL:
 
518
                  if (selectionSize()) {
 
519
                        song->startUndo();
 
520
                        for (iCItem i = items.begin(); i != items.end(); ++i) {
 
521
                              if (!i->second->isSelected())
 
522
                                    continue;
 
523
                              midiThread->msgDeleteEvent(i->second->event(), i->second->part(), false);
 
524
                              }
 
525
                        song->endUndo(SC_EVENT_REMOVED);
 
526
                        }
 
527
                  return;
 
528
            case CMD_OVER_QUANTIZE:     // over quantize
 
529
                  quantize(100, 1, quantLen);
 
530
                  break;
 
531
            case CMD_ON_QUANTIZE:     // note on quantize
 
532
                  quantize(50, 1, false);
 
533
                  break;
 
534
            case CMD_ONOFF_QUANTIZE:     // note on/off quantize
 
535
                  quantize(50, 1, true);
 
536
                  break;
 
537
            case CMD_ITERATIVE_QUANTIZE:     // Iterative Quantize
 
538
                  quantize(quantStrength, quantLimit, quantLen);
 
539
                  break;
 
540
            case CMD_SELECT_ALL:     // select all
 
541
                  for (iCItem k = items.begin(); k != items.end(); ++k) {
 
542
                        if (!k->second->isSelected())
 
543
                              selectItem(k->second, true);
 
544
                        }
 
545
                  break;
 
546
            case CMD_SELECT_NONE:     // select none
 
547
                  deselectAll();
 
548
                  break;
 
549
            case CMD_SELECT_INVERT:     // invert selection
 
550
                  for (iCItem k = items.begin(); k != items.end(); ++k) {
 
551
                        selectItem(k->second, !k->second->isSelected());
 
552
                        }
 
553
                  break;
 
554
            case CMD_SELECT_ILOOP:     // select inside loop
 
555
                  for (iCItem k = items.begin(); k != items.end(); ++k) {
 
556
                        NEvent* nevent =(NEvent*)(k->second);
 
557
                        Event* event = nevent->event();
 
558
                        int tick  = event->posTick();
 
559
                        if (tick < song->lpos() || tick >= song->rpos())
 
560
                              selectItem(k->second, false);
 
561
                        else
 
562
                              selectItem(k->second, true);
 
563
                        }
 
564
                  break;
 
565
            case CMD_SELECT_OLOOP:     // select outside loop
 
566
                  for (iCItem k = items.begin(); k != items.end(); ++k) {
 
567
                        NEvent* nevent =(NEvent*)(k->second);
 
568
                        Event* event = nevent->event();
 
569
                        int tick  = event->posTick();
 
570
                        if (tick < song->lpos() || tick >= song->rpos())
 
571
                              selectItem(k->second, true);
 
572
                        else
 
573
                              selectItem(k->second, false);
 
574
                        }
 
575
                  break;
 
576
            case CMD_MODIFY_GATE_TIME:
 
577
                  {
 
578
                  GateTime w(this);
 
579
                  w.setRange(range);
 
580
                  if (!w.exec())
 
581
                        break;
 
582
                  int range  = w.range();        // all, selected, looped, sel+loop
 
583
                  int rate   = w.rateVal();
 
584
                  int offset = w.offsetVal();
 
585
 
 
586
                  song->startUndo();
 
587
                  for (iCItem k = items.begin(); k != items.end(); ++k) {
 
588
                        NEvent* nevent =(NEvent*)(k->second);
 
589
                        MidiEvent* event = (MidiEvent*)nevent->event();
 
590
                        if (event->type() != MidiEvent::Note)
 
591
                              continue;
 
592
                        int tick      = event->posTick();
 
593
                        bool selected = k->second->isSelected();
 
594
                        bool inLoop   = (tick >= song->lpos()) && (tick < song->rpos());
 
595
 
 
596
                        if ((range == 0)
 
597
                           || (range == 1 && selected)
 
598
                           || (range == 2 && inLoop)
 
599
                           || (range == 3 && selected && inLoop)) {
 
600
                              int len   = event->lenTick();
 
601
 
 
602
                              len = rate ? (len * 100) / rate : 1;
 
603
                              len += offset;
 
604
 
 
605
                              if (event->lenTick() != len) {
 
606
                                    MidiEvent* newEvent = new MidiEvent(*event);
 
607
                                    newEvent->setLenTick(len);
 
608
                                    midiThread->msgChangeEvent(event, newEvent, nevent->part(), false);
 
609
                                    }
 
610
                              }
 
611
                        }
 
612
                  song->endUndo(SC_EVENT_MODIFIED);
 
613
                  }
 
614
                  break;
 
615
 
 
616
            case CMD_MODIFY_VELOCITY:
 
617
                  {
 
618
                  Velocity w(this);
 
619
                  w.setRange(range);
 
620
                  if (!w.exec())
 
621
                        break;
 
622
                  int range  = w.range();        // all, selected, looped, sel+loop
 
623
                  int rate   = w.rateVal();
 
624
                  int offset = w.offsetVal();
 
625
 
 
626
                  song->startUndo();
 
627
                  for (iCItem k = items.begin(); k != items.end(); ++k) {
 
628
                        NEvent* nevent =(NEvent*)(k->second);
 
629
                        MidiEvent* event = (MidiEvent*)nevent->event();
 
630
                        if (event->type() != MidiEvent::Note)
 
631
                              continue;
 
632
                        int tick      = event->posTick();
 
633
                        bool selected = k->second->isSelected();
 
634
                        bool inLoop   = (tick >= song->lpos()) && (tick < song->rpos());
 
635
 
 
636
                        if ((range == 0)
 
637
                           || (range == 1 && selected)
 
638
                           || (range == 2 && inLoop)
 
639
                           || (range == 3 && selected && inLoop)) {
 
640
                              int velo = event->velo();
 
641
 
 
642
                              velo = rate ? (velo * 100) / rate : 64;
 
643
                              velo += offset;
 
644
 
 
645
                              if (velo <= 0)
 
646
                                    velo = 1;
 
647
                              if (velo > 127)
 
648
                                    velo = 127;
 
649
                              if (event->velo() != velo) {
 
650
                                    MidiEvent* newEvent = new MidiEvent(*event);
 
651
                                    newEvent->setVelo(velo);
 
652
                                    midiThread->msgChangeEvent(event, newEvent, nevent->part(), false);
 
653
                                    }
 
654
                              }
 
655
                        }
 
656
                  song->endUndo(SC_EVENT_MODIFIED);
 
657
                  }
 
658
                  break;
 
659
 
 
660
            case CMD_CRESCENDO:
 
661
            case CMD_TRANSPOSE:
 
662
            case CMD_THIN_OUT:
 
663
            case CMD_ERASE_EVENT:
 
664
            case CMD_NOTE_SHIFT:
 
665
            case CMD_MOVE_CLOCK:
 
666
            case CMD_COPY_MEASURE:
 
667
            case CMD_ERASE_MEASURE:
 
668
            case CMD_DELETE_MEASURE:
 
669
            case CMD_CREATE_MEASURE:
 
670
                  break;
 
671
            default:
 
672
//                  printf("unknown ecanvas cmd %d\n", cmd);
 
673
                  break;
 
674
            }
 
675
      updateSelection();
 
676
      redraw();
 
677
      }
 
678
 
 
679
//---------------------------------------------------------
 
680
//   quantize
 
681
//---------------------------------------------------------
 
682
 
 
683
void PianoCanvas::quantize(int strength, int limit, bool quantLen)
 
684
      {
 
685
      song->startUndo();
 
686
      for (iCItem k = items.begin(); k != items.end(); ++k) {
 
687
            NEvent* nevent =(NEvent*)(k->second);
 
688
            MidiEvent* event = (MidiEvent*)nevent->event();
 
689
            if (event->type() != MidiEvent::Note)
 
690
                  continue;
 
691
 
 
692
            if ((cmdRange & CMD_RANGE_SELECTED) && !k->second->isSelected())
 
693
                  continue;
 
694
 
 
695
            int tick  = event->posTick();
 
696
 
 
697
            if ((cmdRange & CMD_RANGE_LOOP)
 
698
               && ((tick < song->lpos() || tick >= song->rpos())))
 
699
                  continue;
 
700
 
 
701
            int len   = event->lenTick();
 
702
            int tick2 = tick + len;
 
703
 
 
704
            // quant start position
 
705
            int diff  = editor->rasterVal(tick) - tick;
 
706
            if (abs(diff) > limit)
 
707
                  tick += ((diff * strength) / 100);
 
708
 
 
709
            // quant len
 
710
            diff = editor->rasterVal(tick2) - tick2;
 
711
            if (quantLen && (abs(diff) > limit))
 
712
                  len += ((diff * strength) / 100);
 
713
 
 
714
            // something changed?
 
715
            if ((event->posTick() != tick) || (event->lenTick() != len)) {
 
716
                  MidiEvent* newEvent = new MidiEvent(*event);
 
717
                  newEvent->setPosTick(tick);
 
718
                  newEvent->setLenTick(len);
 
719
                  midiThread->msgChangeEvent(event, newEvent, nevent->part(), false);
 
720
                  }
 
721
            }
 
722
      song->endUndo(SC_EVENT_MODIFIED);
 
723
      }
 
724
 
 
725
//---------------------------------------------------------
 
726
//   midiNote
 
727
//---------------------------------------------------------
 
728
 
 
729
void PianoCanvas::midiNote(int pitch, int velo)
 
730
      {
 
731
      if (_midiin && _steprec && curPart
 
732
         && !song->play() && velo && pos[0] >= start_tick
 
733
         && pos[0] < end_tick
 
734
         && !(globalKeyState & AltButton)) {
 
735
            int len  = editor->quant();
 
736
            int tick = pos[0]; //CDW
 
737
            int starttick = tick;
 
738
            if (globalKeyState & ShiftButton)
 
739
                  tick -= editor->rasterStep(tick);
 
740
 
 
741
            //
 
742
            // extend len of last note?
 
743
            //
 
744
            EventList* events = curPart->events();
 
745
            if (globalKeyState & ControlButton) {
 
746
                  for (iEvent i = events->begin(); i != events->end(); ++i) {
 
747
                        MidiEvent* ev = (MidiEvent*)i->second;
 
748
                        if (!ev->isNote())
 
749
                              continue;
 
750
                        if (ev->pitch() == pitch && ((ev->posTick()+ev->lenTick()) == starttick)) {
 
751
                              MidiEvent* e = new MidiEvent(*ev);
 
752
                              e->setLenTick(ev->lenTick() + editor->rasterStep(starttick));
 
753
                              midiThread->msgChangeEvent(ev, e, curPart);
 
754
                              tick += editor->rasterStep(tick);
 
755
                              if (tick != song->cpos())
 
756
                                    song->setPos(0, tick, true, false, true);
 
757
                              return;
 
758
                              }
 
759
                        }
 
760
                  }
 
761
 
 
762
            //
 
763
            // if we already entered the note, delete it
 
764
            //
 
765
            EventRange range = events->equal_range(tick);
 
766
            for (iEvent i = range.first; i != range.second; ++i) {
 
767
                  MidiEvent* ev = (MidiEvent*)i->second;
 
768
                  if (ev->isNote() && ev->pitch() == pitch) {
 
769
                        midiThread->msgDeleteEvent(ev, curPart);
 
770
                        if (globalKeyState & ShiftButton)
 
771
                              tick += editor->rasterStep(tick);
 
772
                        return;
 
773
                        }
 
774
                  }
 
775
            MidiEvent* e = new MidiEvent(track()->outPort(),
 
776
               track()->outChannel(), tick, MidiEvent::Note, pitch, velo, 0, len);
 
777
            midiThread->msgAddEvent(e, curPart);
 
778
            tick += editor->rasterStep(tick);
 
779
            if (tick != song->cpos())
 
780
                  song->setPos(0, tick, true, false, true);
 
781
            }
 
782
      }
 
783
 
 
784
//---------------------------------------------------------
 
785
//   getTextDrag
 
786
//---------------------------------------------------------
 
787
 
 
788
QTextDrag* PianoCanvas::getTextDrag(QWidget* parent)
 
789
      {
 
790
      //---------------------------------------------------
 
791
      //   generate event list from selected events
 
792
      //---------------------------------------------------
 
793
 
 
794
      EventList el;
 
795
      int startTick = -1;
 
796
      for (iCItem i = items.begin(); i != items.end(); ++i) {
 
797
            if (!i->second->isSelected())
 
798
                  continue;
 
799
            NEvent* ne = (NEvent*)(i->second);
 
800
            MidiEvent* e = (MidiEvent*)ne->event();
 
801
            if (startTick == -1)
 
802
                  startTick = e->posTick();
 
803
            el.add(e);
 
804
            }
 
805
 
 
806
      //---------------------------------------------------
 
807
      //    write events as XML into tmp file
 
808
      //---------------------------------------------------
 
809
 
 
810
      FILE* tmp = tmpfile();
 
811
      if (tmp == 0) {
 
812
            fprintf(stderr, "PianoCanvas::copy() fopen failed: %s\n",
 
813
               strerror(errno));
 
814
            return 0;
 
815
            }
 
816
      Xml xml(tmp);
 
817
 
 
818
      int level = 0;
 
819
      for (ciEvent e = el.begin(); e != el.end(); ++e)
 
820
            e->second->write(level, xml, -startTick);
 
821
 
 
822
      //---------------------------------------------------
 
823
      //    read tmp file into QTextDrag Object
 
824
      //---------------------------------------------------
 
825
 
 
826
      fflush(tmp);
 
827
      struct stat f_stat;
 
828
      if (fstat(fileno(tmp), &f_stat) == -1) {
 
829
            fprintf(stderr, "PianoCanvas::copy() fstat failes:<%s>\n",
 
830
               strerror(errno));
 
831
            fclose(tmp);
 
832
            return 0;
 
833
            }
 
834
      int n = f_stat.st_size;
 
835
      char* fbuf  = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE,
 
836
         MAP_PRIVATE, fileno(tmp), 0);
 
837
      fbuf[n] = 0;
 
838
      QTextDrag* drag = new QTextDrag(fbuf, parent);
 
839
      drag->setSubtype("eventlist");
 
840
      munmap(fbuf, n);
 
841
      fclose(tmp);
 
842
      return drag;
 
843
      }
 
844
 
 
845
//---------------------------------------------------------
 
846
//   copy
 
847
//    cut copy paste
 
848
//---------------------------------------------------------
 
849
 
 
850
void PianoCanvas::copy()
 
851
      {
 
852
      QTextDrag* drag = getTextDrag(0);
 
853
      if (drag)
 
854
            QApplication::clipboard()->setData(drag);
 
855
      }
 
856
 
 
857
//---------------------------------------------------------
 
858
//   paste
 
859
//---------------------------------------------------------
 
860
 
 
861
int PianoCanvas::pasteAt(const QString& pt, int pos)
 
862
      {
 
863
      const char* p = pt.latin1();
 
864
      Xml xml(p);
 
865
      song->startUndo();
 
866
      for (;;) {
 
867
            Xml::Token token = xml.parse();
 
868
            const QString& tag = xml.s1();
 
869
            switch (token) {
 
870
                  case Xml::Error:
 
871
                  case Xml::End:
 
872
                        song->endUndo(SC_EVENT_INSERTED);
 
873
                        return pos;
 
874
                  case Xml::TagStart:
 
875
                        if (tag == "event") {
 
876
                              MidiEvent* e = new MidiEvent();
 
877
                              e->read(xml);
 
878
                              e->setPosTick(e->posTick() + pos);
 
879
                              e->setPort(track()->outPort());
 
880
                              e->setChannel(track()->outChannel());
 
881
                              midiThread->msgAddEvent(e, curPart, false);
 
882
                              }
 
883
                        else
 
884
                              xml.unknown("PianoCanvas::paste");
 
885
                        break;
 
886
                  case Xml::TagEnd:
 
887
                  default:
 
888
                        break;
 
889
                  }
 
890
            }
 
891
      }
 
892
 
 
893
//---------------------------------------------------------
 
894
//   paste
 
895
//    paste events
 
896
//---------------------------------------------------------
 
897
 
 
898
void PianoCanvas::paste()
 
899
      {
 
900
      QCString subtype("eventlist");
 
901
      QMimeSource* ms = QApplication::clipboard()->data();
 
902
      QString pt;
 
903
      if (!QTextDrag::decode(ms, pt, subtype)) {
 
904
            printf("cannot paste: bad data type\n");
 
905
            return;
 
906
            }
 
907
      pasteAt(pt, song->cpos());
 
908
      }
 
909
 
 
910
//---------------------------------------------------------
 
911
//   startDrag
 
912
//---------------------------------------------------------
 
913
 
 
914
void PianoCanvas::startDrag(CItem* /* item*/, bool copymode)
 
915
      {
 
916
      QTextDrag* drag = getTextDrag(this);
 
917
      if (drag) {
 
918
//            QApplication::clipboard()->setData(drag);
 
919
 
 
920
            if (copymode)
 
921
                  drag->dragCopy();
 
922
            else
 
923
                  drag->dragMove();
 
924
            }
 
925
      }
 
926
 
 
927
//---------------------------------------------------------
 
928
//   dragEnterEvent
 
929
//---------------------------------------------------------
 
930
 
 
931
void PianoCanvas::dragEnterEvent(QDragEnterEvent* event)
 
932
      {
 
933
      event->accept(QTextDrag::canDecode(event));
 
934
      }
 
935
 
 
936
//---------------------------------------------------------
 
937
//   dragMoveEvent
 
938
//---------------------------------------------------------
 
939
 
 
940
void PianoCanvas::dragMoveEvent(QDragMoveEvent*)
 
941
      {
 
942
//      printf("drag move %x\n", this);
 
943
      }
 
944
 
 
945
//---------------------------------------------------------
 
946
//   dragLeaveEvent
 
947
//---------------------------------------------------------
 
948
 
 
949
void PianoCanvas::dragLeaveEvent(QDragLeaveEvent*)
 
950
      {
 
951
//      printf("drag leave\n");
 
952
      }
 
953
 
 
954
//---------------------------------------------------------
 
955
//   dropEvent
 
956
//---------------------------------------------------------
 
957
 
 
958
void PianoCanvas::viewDropEvent(QDropEvent* event)
 
959
      {
 
960
      QString text;
 
961
      if (event->source() == this) {
 
962
            printf("local DROP\n");
 
963
            return;
 
964
            }
 
965
      if (QTextDrag::decode(event, text)) {
 
966
            printf("drop <%s>\n", text.ascii());
 
967
            int x = editor->rasterVal(event->pos().x());
 
968
            if (x < 0)
 
969
                  x = 0;
 
970
            pasteAt(text, x);
 
971
            }
 
972
      else {
 
973
            printf("cannot decode drop\n");
 
974
            }
 
975
      }
 
976
 
 
977
//---------------------------------------------------------
 
978
//   itemPressed
 
979
//---------------------------------------------------------
 
980
 
 
981
void PianoCanvas::itemPressed(const CItem* item)
 
982
      {
 
983
      if (!_playEvents)
 
984
            return;
 
985
 
 
986
      int port         = track()->outPort();
 
987
      int channel      = track()->outChannel();
 
988
      NEvent* nevent   = (NEvent*) item;
 
989
      MidiEvent* event = (MidiEvent*)nevent->event();
 
990
      playedPitch      = event->pitch();
 
991
      int velo         = event->velo();
 
992
 
 
993
      // play note:
 
994
      MidiEvent e(port, channel, 0, MidiEvent::Note, playedPitch, velo, 0, 0);
 
995
      midiThread->playMidiEvent(&e);
 
996
      }
 
997
 
 
998
//---------------------------------------------------------
 
999
//   itemReleased
 
1000
//---------------------------------------------------------
 
1001
 
 
1002
void PianoCanvas::itemReleased(const CItem* item, const QPoint&)
 
1003
      {
 
1004
      if (!_playEvents)
 
1005
            return;
 
1006
      int port         = track()->outPort();
 
1007
      int channel      = track()->outChannel();
 
1008
 
 
1009
      // release note:
 
1010
      MidiEvent ev(port, channel, 0, MidiEvent::Note, playedPitch, 0, 0, 0);
 
1011
      midiThread->playMidiEvent(&ev);
 
1012
      playedPitch = -1;
 
1013
      }
 
1014
 
 
1015
//---------------------------------------------------------
 
1016
//   itemMoved
 
1017
//---------------------------------------------------------
 
1018
 
 
1019
void PianoCanvas::itemMoved(const CItem* item, const QPoint& pos)
 
1020
      {
 
1021
      int npitch = y2pitch(pos.y());
 
1022
      if ((playedPitch != -1) && (playedPitch != npitch)) {
 
1023
            int port         = track()->outPort();
 
1024
            int channel      = track()->outChannel();
 
1025
            NEvent* nevent   = (NEvent*) item;
 
1026
            MidiEvent* event = (MidiEvent*)nevent->event();
 
1027
 
 
1028
            // release note:
 
1029
            MidiEvent ev1(port, channel, 0, MidiEvent::Note, playedPitch, 0, 0, 0);
 
1030
            midiThread->playMidiEvent(&ev1);
 
1031
            // play note:
 
1032
            MidiEvent e2(port, channel, 0, MidiEvent::Note, npitch, event->velo(), 0, 0);
 
1033
            midiThread->playMidiEvent(&e2);
 
1034
            playedPitch = npitch;
 
1035
            }
 
1036
      }
 
1037
 
 
1038
//---------------------------------------------------------
 
1039
//   curPartChanged
 
1040
//---------------------------------------------------------
 
1041
 
 
1042
void PianoCanvas::curPartChanged()
 
1043
      {
 
1044
      editor->setCaption(getCaption());
 
1045
      }
 
1046