~ubuntu-branches/ubuntu/raring/muse/raring-proposed

« back to all changes in this revision

Viewing changes to muse/waveedit/wavecanvas.cpp

  • Committer: Package Import Robot
  • Author(s): Alessio Treglia
  • Date: 2012-11-22 01:16:59 UTC
  • mto: This revision was merged to the branch mainline in revision 23.
  • Revision ID: package-import@ubuntu.com-20121122011659-a2fwbf33ceqe1s0t
Tags: upstream-2.1~rc1
ImportĀ upstreamĀ versionĀ 2.1~rc1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//=========================================================
 
2
//  MusE
 
3
//  Linux Music Editor
 
4
//    wavecanvas.cpp
 
5
//  (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
 
6
//
 
7
//  Based on WaveView.cpp and PianoCanvas.cpp
 
8
//  (C) Copyright 2000 Werner Schweer (ws@seh.de)
 
9
//   and others.
 
10
//
 
11
//  This program is free software; you can redistribute it and/or
 
12
//  modify it under the terms of the GNU General Public License
 
13
//  as published by the Free Software Foundation; version 2 of
 
14
//  the License, or (at your option) any later version.
 
15
//
 
16
//  This program is distributed in the hope that it will be useful,
 
17
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
//  GNU General Public License for more details.
 
20
//
 
21
//  You should have received a copy of the GNU General Public License
 
22
//  along with this program; if not, write to the Free Software
 
23
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
24
//
 
25
//=========================================================
 
26
 
 
27
 
 
28
#include <QApplication>
 
29
#include <QClipboard>
 
30
#include <QPainter>
 
31
#include <QDrag>
 
32
#include <QDragLeaveEvent>
 
33
#include <QDragEnterEvent>
 
34
#include <QDragMoveEvent>
 
35
#include <QDropEvent>
 
36
#include <QFile>
 
37
#include <QInputDialog>
 
38
#include <QMouseEvent>
 
39
#include <QList>
 
40
#include <QPair>
 
41
#include <QMessageBox>
 
42
#include <QDir>
 
43
 
 
44
#include <set>
 
45
 
 
46
#include <limits.h>
 
47
#include <stdio.h>
 
48
#include <math.h>
 
49
#include <errno.h>
 
50
#include <sys/wait.h>
 
51
#include <set>
 
52
 
 
53
#include "app.h"
 
54
#include "xml.h"
 
55
#include "wavecanvas.h"
 
56
#include "event.h"
 
57
#include "globals.h"
 
58
#include "cmd.h"
 
59
#include "song.h"
 
60
#include "audio.h"
 
61
#include "functions.h"
 
62
#include "gconfig.h"
 
63
#include "shortcuts.h"
 
64
#include "editgain.h"
 
65
#include "wave.h"
 
66
#include "waveedit.h"
 
67
#include "fastlog.h"
 
68
#include "utils.h"
 
69
#include "tools.h"
 
70
#include "copy_on_write.h"
 
71
 
 
72
namespace MusEGui {
 
73
 
 
74
//---------------------------------------------------------
 
75
//   WEvent
 
76
//---------------------------------------------------------
 
77
 
 
78
WEvent::WEvent(MusECore::Event& e, MusECore::Part* p, int height) : MusEGui::CItem(e, p)
 
79
      {
 
80
      unsigned frame = e.frame() + p->frame();
 
81
      setPos(QPoint(frame, 0));
 
82
      unsigned len = e.lenFrame();
 
83
      if(e.frame() + e.lenFrame() >= p->lenFrame())
 
84
        len = p->lenFrame() - e.frame();
 
85
      setBBox(QRect(frame, 0, len, height));    
 
86
      }
 
87
 
 
88
//---------------------------------------------------------
 
89
//   addItem
 
90
//---------------------------------------------------------
 
91
 
 
92
CItem* WaveCanvas::addItem(MusECore::Part* part, MusECore::Event& event)
 
93
      {
 
94
      if (signed(event.frame())<0) {
 
95
            printf("ERROR: trying to add event before current part!\n");
 
96
            return NULL;
 
97
      }
 
98
 
 
99
      WEvent* ev = new WEvent(event, part, height());  
 
100
      items.add(ev);
 
101
 
 
102
      int diff = event.frame()-part->lenFrame();
 
103
      if (diff > 0)  {// too short part? extend it
 
104
            part->setLenFrame(part->lenFrame()+diff);
 
105
            }
 
106
      
 
107
      return ev;
 
108
      }
 
109
 
 
110
//---------------------------------------------------------
 
111
//   WaveCanvas
 
112
//---------------------------------------------------------
 
113
 
 
114
WaveCanvas::WaveCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy)
 
115
   : EventCanvas(pr, parent, sx, 1)
 
116
      {
 
117
      colorMode = 0;
 
118
      button = 0;
 
119
      
 
120
      editor = pr;
 
121
      setVirt(true);
 
122
      
 
123
      setBg(QColor());
 
124
      
 
125
      pos[0] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->cpos());
 
126
      pos[1] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->lpos());
 
127
      pos[2] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->rpos());
 
128
      yScale = sy;
 
129
      mode = NORMAL;
 
130
      selectionStart = 0;
 
131
      selectionStop  = 0;
 
132
      lastGainvalue = 100;
 
133
 
 
134
      songChanged(SC_TRACK_INSERTED);
 
135
      }
 
136
 
 
137
WaveCanvas::~WaveCanvas()
 
138
{
 
139
  //delete steprec;
 
140
}
 
141
 
 
142
//---------------------------------------------------------
 
143
//   songChanged(type)
 
144
//---------------------------------------------------------
 
145
 
 
146
void WaveCanvas::songChanged(MusECore::SongChangedFlags_t flags)
 
147
      {
 
148
      // Is it simply a midi controller value adjustment? Forget it.
 
149
      if(flags == SC_MIDI_CONTROLLER)
 
150
        return;
 
151
    
 
152
      if (flags & ~SC_SELECTION) {
 
153
            // TODO FIXME: don't we actually only want SC_PART_*, and maybe SC_TRACK_DELETED?
 
154
            //             (same in waveview.cpp)
 
155
            bool curItemNeedsRestore=false;
 
156
            MusECore::Event storedEvent;
 
157
            int partSn;
 
158
            if (curItem)
 
159
            {
 
160
              curItemNeedsRestore=true;
 
161
              storedEvent=curItem->event();
 
162
              partSn=curItem->part()->sn();
 
163
            }
 
164
            curItem=NULL;
 
165
            
 
166
            items.clearDelete();
 
167
            startSample  = INT_MAX;
 
168
            endSample    = 0;
 
169
            curPart = 0;
 
170
            for (MusECore::iPart p = editor->parts()->begin(); p != editor->parts()->end(); ++p) {
 
171
                  MusECore::WavePart* part = (MusECore::WavePart*)(p->second);
 
172
                  if (part->sn() == curPartId)
 
173
                        curPart = part;
 
174
                  unsigned ssample = part->frame();
 
175
                  unsigned len = part->lenFrame();
 
176
                  unsigned esample = ssample + len;
 
177
                  if (ssample < startSample)
 
178
                        startSample = ssample;
 
179
                  if (esample > endSample)
 
180
                        endSample = esample;
 
181
 
 
182
                  MusECore::EventList* el = part->events();
 
183
                  for (MusECore::iEvent i = el->begin(); i != el->end(); ++i) {
 
184
                        MusECore::Event e = i->second;
 
185
                        // Do not add events which are past the end of the part.
 
186
                        if(e.frame() > len)      
 
187
                          break;
 
188
                        
 
189
                        if (e.type() == MusECore::Wave) {
 
190
                              CItem* temp = addItem(part, e);
 
191
                              
 
192
                              if (temp && curItemNeedsRestore && e==storedEvent && part->sn()==partSn)
 
193
                              {
 
194
                                  if (curItem!=NULL)
 
195
                                    printf("THIS SHOULD NEVER HAPPEN: curItemNeedsRestore=true, event fits, but there was already a fitting event!?\n");
 
196
                                  
 
197
                                  curItem=temp;
 
198
                                  }
 
199
                              }
 
200
                        }
 
201
                  }
 
202
            }
 
203
 
 
204
      MusECore::Event event;
 
205
      MusECore::WavePart* part   = 0;
 
206
      int x            = 0;
 
207
      CItem*   nevent  = 0;
 
208
 
 
209
      int n  = 0;       // count selections
 
210
      for (iCItem k = items.begin(); k != items.end(); ++k) {
 
211
            MusECore::Event ev = k->second->event();
 
212
            bool selected = ev.selected();
 
213
            if (selected) {
 
214
                  k->second->setSelected(true);
 
215
                  ++n;
 
216
                  if (!nevent) {
 
217
                        nevent   =  k->second;
 
218
                        MusECore::Event mi = nevent->event();
 
219
                        }
 
220
                  }
 
221
            }
 
222
      
 
223
      if (flags & SC_CLIP_MODIFIED) {
 
224
            redraw(); // Boring, but the only thing possible to do
 
225
            }
 
226
      if (flags & SC_TEMPO) {
 
227
            setPos(0, MusEGlobal::song->cpos(), false);
 
228
            setPos(1, MusEGlobal::song->lpos(), false);
 
229
            setPos(2, MusEGlobal::song->rpos(), false);
 
230
            }
 
231
      
 
232
      if (n >= 1)    
 
233
      {
 
234
            x     = nevent->x();
 
235
            event = nevent->event();
 
236
            part  = (MusECore::WavePart*)nevent->part();
 
237
            if (_setCurPartIfOnlyOneEventIsSelected && n == 1 && curPart != part) {
 
238
                  curPart = part;
 
239
                  curPartId = curPart->sn();
 
240
                  curPartChanged();
 
241
                  }
 
242
      }
 
243
      
 
244
      bool f1 = flags & (SC_EVENT_INSERTED | SC_EVENT_MODIFIED | SC_EVENT_REMOVED | 
 
245
                         SC_PART_INSERTED | SC_PART_MODIFIED | SC_PART_REMOVED |
 
246
                         SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED |
 
247
                         SC_SIG | SC_TEMPO | SC_KEY | SC_MASTER | SC_CONFIG | SC_DRUMMAP); 
 
248
      bool f2 = flags & SC_SELECTION;
 
249
      if(f1 || f2)   // Try to avoid all unnecessary emissions.
 
250
        emit selectionChanged(x, event, part, !f1);
 
251
      
 
252
      if (curPart == 0)
 
253
            curPart = (MusECore::WavePart*)(editor->parts()->begin()->second);
 
254
      redraw();
 
255
      }
 
256
 
 
257
//---------------------------------------------------------
 
258
//   selectAtTick
 
259
//---------------------------------------------------------
 
260
 
 
261
void WaveCanvas::selectAtTick(unsigned int tick)
 
262
      {
 
263
      selectAtFrame(MusEGlobal::tempomap.tick2frame(tick));
 
264
      }
 
265
 
 
266
//---------------------------------------------------------
 
267
//   selectAtFrame
 
268
//---------------------------------------------------------
 
269
 
 
270
void WaveCanvas::selectAtFrame(unsigned int frame)
 
271
      {
 
272
      //Select event nearest frame, if none selected and there are any
 
273
      if (!items.empty() && selectionSize() == 0) {
 
274
            iCItem i = items.begin();
 
275
            CItem* nearest = i->second;
 
276
 
 
277
            while (i != items.end()) {
 
278
                CItem* cur=i->second;                
 
279
                unsigned int curf=abs(cur->x() + cur->part()->frame() - frame);
 
280
                unsigned int nearf=abs(nearest->x() + nearest->part()->frame() - frame);
 
281
 
 
282
                if (curf < nearf) {
 
283
                    nearest=cur;
 
284
                    }
 
285
 
 
286
                i++;
 
287
                }
 
288
 
 
289
            if (!nearest->isSelected()) {
 
290
                  selectItem(nearest, true);
 
291
                  songChanged(SC_SELECTION);
 
292
                  }
 
293
            }
 
294
      }
 
295
 
 
296
//---------------------------------------------------------
 
297
//   getCaption
 
298
//---------------------------------------------------------
 
299
 
 
300
QString WaveCanvas::getCaption() const
 
301
      {
 
302
      int bar1, bar2, xx;
 
303
      unsigned x;
 
304
      AL::sigmap.tickValues(curPart->tick(), &bar1, &xx, &x);
 
305
      AL::sigmap.tickValues(curPart->tick() + curPart->lenTick(), &bar2, &xx, &x);
 
306
 
 
307
      return QString("MusE: Part <") + curPart->name()
 
308
         + QString("> %1-%2").arg(bar1+1).arg(bar2+1);
 
309
      }
 
310
 
 
311
//---------------------------------------------------------
 
312
//   track
 
313
//---------------------------------------------------------
 
314
 
 
315
MusECore::WaveTrack* WaveCanvas::track() const
 
316
      {
 
317
      return ((MusECore::WavePart*)curPart)->track();
 
318
      }
 
319
 
 
320
 
 
321
//---------------------------------------------------------
 
322
//   keyPress
 
323
//---------------------------------------------------------
 
324
 
 
325
void WaveCanvas::keyPress(QKeyEvent* event)
 
326
      {
 
327
      int key = event->key();
 
328
      if (((QInputEvent*)event)->modifiers() & Qt::ShiftModifier)
 
329
            key += Qt::SHIFT;
 
330
      if (((QInputEvent*)event)->modifiers() & Qt::AltModifier)
 
331
            key += Qt::ALT;
 
332
      if (((QInputEvent*)event)->modifiers() & Qt::ControlModifier)
 
333
            key+= Qt::CTRL;
 
334
 
 
335
      // TODO: New WaveCanvas: Convert these to frames, and remove unneeded functions.
 
336
            
 
337
      //
 
338
      //  Shortcut for DrumEditor & PianoRoll
 
339
      //  Sets locators to selected events
 
340
      //
 
341
      if (key == shortcuts[SHRT_LOCATORS_TO_SELECTION].key) {
 
342
            int tick_max = 0;
 
343
            int tick_min = INT_MAX;
 
344
            bool found = false;
 
345
 
 
346
            for (iCItem i= items.begin(); i != items.end(); i++) {
 
347
                  if (!i->second->isSelected())
 
348
                        continue;
 
349
 
 
350
                  int tick = i->second->x();
 
351
                  int len = i->second->event().lenTick();
 
352
                  found = true;
 
353
                  if (tick + len > tick_max)
 
354
                        tick_max = tick + len;
 
355
                  if (tick < tick_min)
 
356
                        tick_min = tick;
 
357
                  }
 
358
            if (found) {
 
359
                  MusECore::Pos p1(tick_min, true);
 
360
                  MusECore::Pos p2(tick_max, true);
 
361
                  MusEGlobal::song->setPos(1, p1);
 
362
                  MusEGlobal::song->setPos(2, p2);
 
363
                  }
 
364
            }
 
365
      // Select items by key (PianoRoll & DrumEditor)
 
366
      else if (key == shortcuts[SHRT_SEL_RIGHT].key || key == shortcuts[SHRT_SEL_RIGHT_ADD].key) {
 
367
              rciCItem i;
 
368
 
 
369
              if (items.empty())
 
370
                  return;
 
371
              for (i = items.rbegin(); i != items.rend(); ++i) 
 
372
                if (i->second->isSelected()) 
 
373
                  break;
 
374
 
 
375
              if(i == items.rend())
 
376
                i = items.rbegin();
 
377
              
 
378
              if(i != items.rbegin())
 
379
                --i;
 
380
              if(i->second)
 
381
              {
 
382
                if (key != shortcuts[SHRT_SEL_RIGHT_ADD].key)
 
383
                      deselectAll();
 
384
                CItem* sel = i->second;
 
385
                sel->setSelected(true);
 
386
                updateSelection();
 
387
                if (sel->x() + sel->width() > mapxDev(width())) 
 
388
                {  
 
389
                  int mx = rmapx(sel->x());  
 
390
                  int newx = mx + rmapx(sel->width()) - width();
 
391
                  // Leave a bit of room for the specially-drawn drum notes. But good for piano too.
 
392
                  emit horizontalScroll( (newx > mx ? mx - 10: newx + 10) - rmapx(xorg) );
 
393
                }  
 
394
              }
 
395
            }
 
396
      //Select items by key: (PianoRoll & DrumEditor)
 
397
      else if (key == shortcuts[SHRT_SEL_LEFT].key || key == shortcuts[SHRT_SEL_LEFT_ADD].key) {
 
398
              ciCItem i;
 
399
              if (items.empty())
 
400
                  return;
 
401
              for (i = items.begin(); i != items.end(); ++i)
 
402
                if (i->second->isSelected()) 
 
403
                  break;
 
404
 
 
405
              if(i == items.end())
 
406
                i = items.begin();
 
407
              
 
408
              if(i != items.begin())
 
409
                --i;
 
410
              if(i->second)
 
411
              {
 
412
                if (key != shortcuts[SHRT_SEL_LEFT_ADD].key)
 
413
                      deselectAll();
 
414
                CItem* sel = i->second;
 
415
                sel->setSelected(true);
 
416
                updateSelection();
 
417
                if (sel->x() <= mapxDev(0)) 
 
418
                  emit horizontalScroll(rmapx(sel->x() - xorg) - 10);  // Leave a bit of room.
 
419
              }
 
420
            }
 
421
      //else if (key == shortcuts[SHRT_INC_PITCH].key) {
 
422
      //      modifySelected(NoteInfo::VAL_PITCH, 1);
 
423
      //      }
 
424
      //else if (key == shortcuts[SHRT_DEC_PITCH].key) {
 
425
      //      modifySelected(NoteInfo::VAL_PITCH, -1);
 
426
      //      }
 
427
      else if (key == shortcuts[SHRT_INC_POS].key) {
 
428
            // TODO: Check boundaries
 
429
            modifySelected(NoteInfo::VAL_TIME, editor->raster());
 
430
            }
 
431
      else if (key == shortcuts[SHRT_DEC_POS].key) {
 
432
            // TODO: Check boundaries
 
433
            modifySelected(NoteInfo::VAL_TIME, 0 - editor->raster());
 
434
            }
 
435
 
 
436
      else if (key == shortcuts[SHRT_INCREASE_LEN].key) {
 
437
            // TODO: Check boundaries
 
438
            modifySelected(NoteInfo::VAL_LEN, editor->raster());
 
439
            }
 
440
      else if (key == shortcuts[SHRT_DECREASE_LEN].key) {
 
441
            // TODO: Check boundaries
 
442
            modifySelected(NoteInfo::VAL_LEN, 0 - editor->raster());
 
443
            }
 
444
 
 
445
      else
 
446
            event->ignore();
 
447
      }
 
448
 
 
449
 
 
450
//---------------------------------------------------------
 
451
//   setPos
 
452
//    set one of three markers
 
453
//    idx   - 0-cpos  1-lpos  2-rpos
 
454
//    flag  - emit followEvent()
 
455
//---------------------------------------------------------
 
456
 
 
457
void WaveCanvas::setPos(int idx, unsigned val, bool adjustScrollbar)
 
458
      {
 
459
      val = MusEGlobal::tempomap.tick2frame(val);
 
460
      if (pos[idx] == val)
 
461
            return;
 
462
      int opos = mapx(pos[idx]);
 
463
      int npos = mapx(val);
 
464
 
 
465
      if (adjustScrollbar && idx == 0) {
 
466
            switch (MusEGlobal::song->follow()) {
 
467
                  case  MusECore::Song::NO:
 
468
                        break;
 
469
                  case MusECore::Song::JUMP:
 
470
                        if (npos >= width()) {
 
471
                              int ppos =  val - xorg - rmapxDev(width()/4);
 
472
                              if (ppos < 0)
 
473
                                    ppos = 0;
 
474
                              emit followEvent(ppos);
 
475
                              opos = mapx(pos[idx]);
 
476
                              npos = mapx(val);
 
477
                              }
 
478
                        else if (npos < 0) {
 
479
                              int ppos =  val - xorg - rmapxDev(width()*3/4);
 
480
                              if (ppos < 0)
 
481
                                    ppos = 0;
 
482
                              emit followEvent(ppos);
 
483
                              opos = mapx(pos[idx]);
 
484
                              npos = mapx(val);
 
485
                              }
 
486
                        break;
 
487
            case MusECore::Song::CONTINUOUS:
 
488
                        if (npos > (width()*5)/8) {
 
489
                              int ppos =  pos[idx] - xorg - rmapxDev(width()*5/8);
 
490
                              if (ppos < 0)
 
491
                                    ppos = 0;
 
492
                              emit followEvent(ppos);
 
493
                              opos = mapx(pos[idx]);
 
494
                              npos = mapx(val);
 
495
                              }
 
496
                        else if (npos < (width()*3)/8) {
 
497
                              int ppos =  pos[idx] - xorg - rmapxDev(width()*3/8);
 
498
                              if (ppos < 0)
 
499
                                    ppos = 0;
 
500
                              emit followEvent(ppos);
 
501
                              opos = mapx(pos[idx]);
 
502
                              npos = mapx(val);
 
503
                              }
 
504
                        break;
 
505
                  }
 
506
            }
 
507
 
 
508
      int x;
 
509
      int w = 1;
 
510
      if (opos > npos) {
 
511
            w += opos - npos;
 
512
            x = npos;
 
513
            }
 
514
      else {
 
515
            w += npos - opos;
 
516
            x = opos;
 
517
            }
 
518
      pos[idx] = val;
 
519
      //redraw(QRect(x, 0, w, height()));
 
520
      redraw(QRect(x-1, 0, w+2, height()));    // From Canvas::draw (is otherwise identical). Fix for corruption. (TEST: New WaveCanvas: Still true?)
 
521
      }
 
522
 
 
523
//---------------------------------------------------------
 
524
//   setYScale
 
525
//---------------------------------------------------------
 
526
 
 
527
void WaveCanvas::setYScale(int val)
 
528
      {
 
529
      yScale = val;
 
530
      redraw();
 
531
      }
 
532
 
 
533
// TODO: Overridden because markers need tick2frame. 
 
534
//       After BBT/frame mode is added to Canvas, remove this override and let Canvas::draw do it.
 
535
//       Also add the drawParts calls to Canvas::draw, and add a dummy Canvas::drawParts { }.
 
536
//---------------------------------------------------------
 
537
//   draw
 
538
//---------------------------------------------------------
 
539
 
 
540
void WaveCanvas::draw(QPainter& p, const QRect& r)
 
541
      {
 
542
      int x = r.x() < 0 ? 0 : r.x();
 
543
      int y = r.y() < 0 ? 0 : r.y();
 
544
      int w = r.width();
 
545
      int h = r.height();
 
546
      int x2 = x + w;
 
547
 
 
548
      std::vector<CItem*> list1;
 
549
      std::vector<CItem*> list2;
 
550
      //std::vector<CItem*> list3;
 
551
      std::vector<CItem*> list4;
 
552
 
 
553
      drawCanvas(p, r);
 
554
 
 
555
      //---------------------------------------------------
 
556
      // draw Canvas Items
 
557
      //---------------------------------------------------
 
558
 
 
559
      iCItem to(items.lower_bound(x2));
 
560
      
 
561
      for(iCItem i = items.begin(); i != to; ++i)
 
562
      { 
 
563
        CItem* ci = i->second;
 
564
        // NOTE Optimization: For each item call this once now, then use cached results later via cachedHasHiddenEvents().
 
565
        // Not required for now.
 
566
        //ci->part()->hasHiddenEvents();
 
567
        
 
568
        // Draw items from other parts behind all others. Only for items with events (not arranger parts).
 
569
        if(!ci->event().empty() && ci->part() != curPart)
 
570
          list1.push_back(ci);    
 
571
        else if(!ci->isMoving() && (ci->event().empty() || ci->part() == curPart))
 
572
        {
 
573
          // Draw selected parts in front of all others.
 
574
          if(ci->isSelected()) 
 
575
            list4.push_back(ci);
 
576
          // Draw clone parts, and parts with hidden events, in front of others all except selected.
 
577
          //else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1 || ci->part()->cachedHasHiddenEvents()))
 
578
          // Draw clone parts in front of others all except selected.
 
579
          //else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1))
 
580
          //  list3.push_back(ci);
 
581
          else  
 
582
            // Draw unselected parts.
 
583
            list2.push_back(ci);
 
584
        }  
 
585
      }
 
586
 
 
587
      // Draw non-current part backgrounds behind all others:
 
588
      drawParts(p, r, false);
 
589
      
 
590
      int i;
 
591
      int sz = list1.size();
 
592
      for(i = 0; i != sz; ++i) 
 
593
        drawItem(p, list1[i], r);
 
594
      
 
595
      // Draw current part background in front of all others:
 
596
      drawParts(p, r, true);
 
597
      
 
598
      sz = list2.size();
 
599
      for(i = 0; i != sz; ++i) 
 
600
        drawItem(p, list2[i], r);
 
601
 
 
602
      //sz = list3.size();
 
603
      //for(i = 0; i != sz; ++i) 
 
604
      //  drawItem(p, list3[i], rect);
 
605
      
 
606
      sz = list4.size();
 
607
      for(i = 0; i != sz; ++i) 
 
608
        drawItem(p, list4[i], r);
 
609
      
 
610
      to = moving.lower_bound(x2);
 
611
      for (iCItem i = moving.begin(); i != to; ++i) 
 
612
      {
 
613
            drawItem(p, i->second, r);
 
614
      }
 
615
 
 
616
      drawTopItem(p,r);
 
617
 
 
618
 
 
619
      //---------------------------------------------------
 
620
      //    draw marker
 
621
      //---------------------------------------------------
 
622
 
 
623
      bool wmtxen = p.worldMatrixEnabled();
 
624
      p.setWorldMatrixEnabled(false);
 
625
      
 
626
      int my = mapy(y);
 
627
      int my2 = mapy(y + h);
 
628
      
 
629
      MusECore::MarkerList* marker = MusEGlobal::song->marker();
 
630
      for (MusECore::iMarker m = marker->begin(); m != marker->end(); ++m) {
 
631
            int xp = MusEGlobal::tempomap.tick2frame(m->second.tick());
 
632
            if (xp >= x && xp < x2) {
 
633
                  p.setPen(Qt::green);
 
634
                  p.drawLine(mapx(xp), my, mapx(xp), my2);
 
635
                  }
 
636
            }
 
637
 
 
638
      //---------------------------------------------------
 
639
      //    draw location marker
 
640
      //---------------------------------------------------
 
641
 
 
642
      // Tip: These positions are already in units of frames.
 
643
      p.setPen(Qt::blue);
 
644
      int mx;
 
645
      if (pos[1] >= unsigned(x) && pos[1] < unsigned(x2)) {
 
646
            mx = mapx(pos[1]);
 
647
            p.drawLine(mx, my, mx, my2);
 
648
            }
 
649
      if (pos[2] >= unsigned(x) && pos[2] < unsigned(x2)) {
 
650
            mx = mapx(pos[2]);
 
651
            p.drawLine(mx, my, mx, my2);
 
652
            }
 
653
      p.setPen(Qt::red);
 
654
      if (pos[0] >= unsigned(x) && pos[0] < unsigned(x2)) {
 
655
            mx = mapx(pos[0]);
 
656
            p.drawLine(mx, my, mx, my2);
 
657
            }
 
658
            
 
659
      //p.restore();
 
660
      //p.setWorldMatrixEnabled(true);
 
661
      p.setWorldMatrixEnabled(wmtxen);
 
662
      
 
663
      //---------------------------------------------------
 
664
      //    draw lasso
 
665
      //---------------------------------------------------
 
666
 
 
667
      if (drag == DRAG_LASSO) {
 
668
            p.setPen(Qt::blue);
 
669
            p.setBrush(Qt::NoBrush);
 
670
            p.drawRect(lasso);
 
671
            }
 
672
      
 
673
      //---------------------------------------------------
 
674
      //    draw moving items
 
675
      //---------------------------------------------------
 
676
      
 
677
      for(iCItem i = moving.begin(); i != moving.end(); ++i) 
 
678
        drawMoving(p, i->second, r);
 
679
 
 
680
      }
 
681
 
 
682
//---------------------------------------------------------
 
683
//   drawWaveParts
 
684
//---------------------------------------------------------
 
685
 
 
686
void WaveCanvas::drawParts(QPainter& p, const QRect& r, bool do_cur_part)
 
687
{
 
688
      //QRect rr = p.transform().mapRect(r);  // Gives inconsistent positions. Source shows wrong operation for our needs.
 
689
      QRect rr = map(r);                      // Use our own map instead.        
 
690
 
 
691
      bool wmtxen = p.worldMatrixEnabled();
 
692
      p.setWorldMatrixEnabled(false);
 
693
 
 
694
      if(do_cur_part)
 
695
      {
 
696
        // Draw current part:
 
697
        if(curPart)
 
698
        {
 
699
              QRect mwpr  = map(QRect(curPart->frame(), 0, curPart->lenFrame(), height()));
 
700
              QRect mpbgr = rr & mwpr;
 
701
              if(!mpbgr.isNull())
 
702
              {
 
703
                QColor c;
 
704
                switch(colorMode)
 
705
                {
 
706
                  default:
 
707
                  case 0:
 
708
                    c = MusEGlobal::config.partColors[curPart->colorIndex()];
 
709
                    break;
 
710
                  case 1:
 
711
                    c = Qt::lightGray;
 
712
                    break;
 
713
                }
 
714
                c.setAlpha(MusEGlobal::config.globalAlphaBlend);
 
715
                QBrush part_bg_brush(MusECore::gGradientFromQColor(c, mwpr.topLeft(), mwpr.bottomLeft()));
 
716
                p.fillRect(mpbgr, part_bg_brush);
 
717
              }
 
718
        }     
 
719
      }
 
720
      else
 
721
      {
 
722
        // Draw non-current parts:
 
723
        for (MusECore::iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) 
 
724
        {
 
725
              MusECore::WavePart* wp = (MusECore::WavePart*)(ip->second);
 
726
              if(wp == curPart)
 
727
                continue;
 
728
              
 
729
              QRect mwpr  = map(QRect(wp->frame(), 0, wp->lenFrame(), height()));
 
730
              QRect mpbgr = rr & mwpr;
 
731
              if(!mpbgr.isNull())
 
732
              {
 
733
                //int cidx = wp->colorIndex();
 
734
                //QColor c(MusEGlobal::config.partColors[cidx]);
 
735
                QColor c(Qt::darkGray);
 
736
                c.setAlpha(MusEGlobal::config.globalAlphaBlend);
 
737
                QBrush part_bg_brush(MusECore::gGradientFromQColor(c, mwpr.topLeft(), mwpr.bottomLeft()));
 
738
                p.fillRect(mpbgr, part_bg_brush);
 
739
              }
 
740
        }     
 
741
      }
 
742
      
 
743
      p.setWorldMatrixEnabled(wmtxen);
 
744
}
 
745
      
 
746
// TODO: Overridden because we're in units of frames. 
 
747
//       After BBT/frame mode is added to Canvas, remove this override and let View or Canvas do it.
 
748
//---------------------------------------------------------
 
749
//   drawTickRaster
 
750
//---------------------------------------------------------
 
751
 
 
752
void WaveCanvas::drawTickRaster(QPainter& p, int x, int y, int w, int h, int raster)
 
753
      {
 
754
      // Changed to draw in device coordinate space instead of virtual, transformed space. Tim. 
 
755
      
 
756
      //int mx = mapx(x);
 
757
      int my = mapy(y);
 
758
      //int mw = mapx(x + w) - mx;
 
759
      //int mw = mapx(x + w) - mx - 1;
 
760
      //int mh = mapy(y + h) - my;
 
761
      //int mh = mapy(y + h) - my - 1;
 
762
      
 
763
      //p.save();
 
764
      bool wmtxen = p.worldMatrixEnabled();
 
765
      p.setWorldMatrixEnabled(false);
 
766
      
 
767
      int xx,bar1, bar2, beat;
 
768
      unsigned tick;
 
769
//      AL::sigmap.tickValues(x, &bar1, &beat, &tick);
 
770
//      AL::sigmap.tickValues(x+w, &bar2, &beat, &tick);
 
771
      AL::sigmap.tickValues(MusEGlobal::tempomap.frame2tick(x), &bar1, &beat, &tick);
 
772
      AL::sigmap.tickValues(MusEGlobal::tempomap.frame2tick(x+w), &bar2, &beat, &tick);
 
773
      ++bar2;
 
774
      ///int y2 = y + h;
 
775
      //int y2 = my + mh;
 
776
      int y2 = mapy(y + h) - 1;
 
777
      //printf("View::drawTickRaster x:%d y:%d w:%d h:%d mx:%d my:%d mw:%d mh:%d y2:%d bar1:%d bar2:%d\n", x, y, w, h, mx, my, mw, mh, y2, bar1, bar2);  
 
778
      //printf("View::drawTickRaster x:%d y:%d w:%d h:%d my:%d mh:%d y2:%d bar1:%d bar2:%d\n", x, y, w, h, my, mh, y2, bar1, bar2);  
 
779
      for (int bar = bar1; bar < bar2; ++bar) {
 
780
        
 
781
//            unsigned xb = AL::sigmap.bar2tick(bar, 0, 0);
 
782
            unsigned xb = AL::sigmap.bar2tick(bar, 0, 0);
 
783
            int xt = mapx(MusEGlobal::tempomap.tick2frame(xb));
 
784
            p.setPen(Qt::black);
 
785
            p.drawLine(xt, my, xt, y2);
 
786
            
 
787
            int z, n;
 
788
            AL::sigmap.timesig(xb, z, n);
 
789
            int qq = raster;
 
790
            if (rmapx(raster) < 8)        // grid too dense
 
791
                  qq *= 2;
 
792
            p.setPen(Qt::lightGray);
 
793
            if (raster>=4) {
 
794
                        xx = xb + qq;
 
795
                        int xxx = MusEGlobal::tempomap.tick2frame(AL::sigmap.bar2tick(bar, z, 0));
 
796
                        //while (MusEGlobal::tempomap.tick2frame(xx) <= xxx) {
 
797
                        while (1) {
 
798
                               int xxf = MusEGlobal::tempomap.tick2frame(xx);
 
799
                               if(xxf > xxx)
 
800
                                 break;
 
801
                               //int x = mapx(MusEGlobal::tempomap.tick2frame(xx));
 
802
                               int x = mapx(xxf);
 
803
                               p.drawLine(x, my, x, y2);
 
804
                               xx += qq;
 
805
                               }
 
806
                        }
 
807
            p.setPen(Qt::gray);
 
808
            for (int beat = 1; beat < z; beat++) {
 
809
                        xx = mapx(MusEGlobal::tempomap.tick2frame(AL::sigmap.bar2tick(bar, beat, 0)));
 
810
                        //printf(" bar:%d z:%d beat:%d xx:%d\n", bar, z, beat, xx);  
 
811
                        p.drawLine(xx, my, xx, y2);
 
812
                        }
 
813
 
 
814
            }
 
815
      p.setWorldMatrixEnabled(wmtxen);
 
816
      }
 
817
 
 
818
// TODO: Overridden because we're in units of frames. 
 
819
//       After BBT/frame mode is added to Canvas, remove this override and let Canvas do it.
 
820
//---------------------------------------------------------
 
821
//   raster
 
822
//---------------------------------------------------------
 
823
 
 
824
QPoint WaveCanvas::raster(const QPoint& p) const
 
825
      {
 
826
      int x = p.x();
 
827
      if (x < 0)
 
828
            x = 0;
 
829
      //x = editor->rasterVal(x);
 
830
      x = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x)));
 
831
      int pitch = y2pitch(p.y());
 
832
      int y = pitch2y(pitch);
 
833
      return QPoint(x, y);
 
834
      }
 
835
 
 
836
#define WHEEL_STEPSIZE 40
 
837
#define WHEEL_DELTA   120
 
838
//---------------------------------------------------------
 
839
//   wheelEvent
 
840
//---------------------------------------------------------
 
841
void WaveCanvas::wheelEvent(QWheelEvent* ev)
 
842
{
 
843
  int keyState = ev->modifiers();
 
844
 
 
845
  bool shift      = keyState & Qt::ShiftModifier;
 
846
  bool ctrl       = keyState & Qt::ControlModifier;
 
847
 
 
848
  if (shift) { // scroll vertically
 
849
      int delta       = -ev->delta() / WHEEL_DELTA;
 
850
      int xpixelscale = 5*MusECore::fast_log10(rmapxDev(1));
 
851
 
 
852
 
 
853
      if (xpixelscale <= 0)
 
854
            xpixelscale = 1;
 
855
 
 
856
      int scrollstep = WHEEL_STEPSIZE * (delta);
 
857
      ///if (ev->state() == Qt::ShiftModifier)
 
858
  //      if (((QInputEvent*)ev)->modifiers() == Qt::ShiftModifier)
 
859
      scrollstep = scrollstep / 10;
 
860
 
 
861
      int newXpos = xpos + xpixelscale * scrollstep;
 
862
 
 
863
      if (newXpos < 0)
 
864
            newXpos = 0;
 
865
 
 
866
      //setYPos(newYpos);
 
867
      emit horizontalScroll((unsigned)newXpos);
 
868
 
 
869
 
 
870
  } else if (ctrl) {  // zoom horizontally
 
871
    if (ev->delta()>0)
 
872
      emit horizontalZoomIn();
 
873
    else
 
874
      emit horizontalZoomOut();
 
875
 
 
876
  } else { // scroll horizontally
 
877
      emit mouseWheelMoved(ev->delta() / 10);
 
878
  }
 
879
 
 
880
}
 
881
 
 
882
//---------------------------------------------------------
 
883
//   viewMousePressEvent
 
884
//---------------------------------------------------------
 
885
 
 
886
bool WaveCanvas::mousePress(QMouseEvent* event)
 
887
      {
 
888
    if (event->modifiers() & Qt::ControlModifier) {
 
889
            return true;
 
890
            }
 
891
      button = event->button();
 
892
      QPoint pt = event->pos();
 
893
      //CItem* item = items.find(pt);
 
894
      unsigned x = event->x();
 
895
 
 
896
      switch (_tool) {
 
897
            default:
 
898
                  break;
 
899
             case CursorTool:
 
900
                  switch (button) {
 
901
                        case Qt::LeftButton:
 
902
                              if (mode == NORMAL) {
 
903
                                    // redraw and reset:
 
904
                                    if (selectionStart != selectionStop) {
 
905
                                          selectionStart = selectionStop = 0;
 
906
                                          redraw();
 
907
                                          }
 
908
                                    mode = DRAG;
 
909
                                    dragstartx = x;
 
910
                                    selectionStart = selectionStop = x;
 
911
                                    drag = DRAG_LASSO_START;
 
912
                                    Canvas::start = pt;
 
913
                                    return false;
 
914
                                    }
 
915
                              break;
 
916
 
 
917
                        case Qt::MidButton:
 
918
                        case Qt::RightButton:
 
919
                        default:
 
920
                              break;
 
921
                        }
 
922
 
 
923
                   break;
 
924
            }
 
925
      return true;
 
926
      }
 
927
 
 
928
//---------------------------------------------------------
 
929
//   viewMouseReleaseEvent
 
930
//---------------------------------------------------------
 
931
 
 
932
void WaveCanvas::mouseRelease(const QPoint&)
 
933
      {
 
934
      button = Qt::NoButton;
 
935
      if (mode == DRAG) {
 
936
            mode = NORMAL;
 
937
            }
 
938
      }
 
939
 
 
940
//---------------------------------------------------------
 
941
//   viewMousevent
 
942
//---------------------------------------------------------
 
943
 
 
944
void WaveCanvas::mouseMove(QMouseEvent* event)
 
945
      {
 
946
      int x = event->x();
 
947
      if (x < 0)
 
948
            x = 0;
 
949
      emit timeChanged(x);
 
950
      //emit timeChanged(editor->rasterVal(x));
 
951
      //emit timeChanged(AL::sigmap.raster(x, *_raster));
 
952
 
 
953
      switch (button) {
 
954
            case Qt::LeftButton:
 
955
                  if (mode == DRAG) {
 
956
                        int mx      = mapx(x);
 
957
                        int mstart  = mapx(selectionStart);
 
958
                        int mstop   = mapx(selectionStop);
 
959
                        //int mdstart = mapx(dragstartx);
 
960
                        QRect r(0, 0, 0, height());
 
961
                        
 
962
                        if (x < dragstartx) {
 
963
                              if(x < selectionStart)
 
964
                              {
 
965
                                r.setLeft(mx);
 
966
                                r.setWidth((selectionStop >= dragstartx ? mstop : mstart) - mx);
 
967
                              }
 
968
                              else
 
969
                              {
 
970
                                r.setLeft(mstart);
 
971
                                r.setWidth(mx - mstart);
 
972
                              }
 
973
                              selectionStart = x;
 
974
                              selectionStop = dragstartx;
 
975
                              }
 
976
                        else {
 
977
                              if(x >= selectionStop)
 
978
                              {
 
979
                                r.setLeft(selectionStart < dragstartx ? mstart : mstop);
 
980
                                r.setWidth(mx - (selectionStart < dragstartx ? mstart : mstop));
 
981
                              }
 
982
                              else
 
983
                              {
 
984
                                r.setLeft(mx);
 
985
                                r.setWidth(mstop - mx);
 
986
                              }
 
987
                              selectionStart = dragstartx;
 
988
                              selectionStop = x;
 
989
                              }
 
990
                        update(r);
 
991
                        }
 
992
                  break;
 
993
            case Qt::MidButton:
 
994
                  break;
 
995
            case Qt::RightButton:
 
996
                  break;
 
997
            default:
 
998
                  return;
 
999
            }
 
1000
      }
 
1001
      
 
1002
//---------------------------------------------------------
 
1003
//   pitch2y
 
1004
//---------------------------------------------------------
 
1005
 
 
1006
int WaveCanvas::pitch2y(int) const
 
1007
      {
 
1008
      return 0;
 
1009
      }
 
1010
 
 
1011
//---------------------------------------------------------
 
1012
//   y2pitch
 
1013
//---------------------------------------------------------
 
1014
 
 
1015
int WaveCanvas::y2pitch(int) const
 
1016
      {
 
1017
      return 0;
 
1018
      }
 
1019
 
 
1020
//---------------------------------------------------------
 
1021
//   drawItem
 
1022
//    draws a wave
 
1023
//---------------------------------------------------------
 
1024
 
 
1025
void WaveCanvas::drawItem(QPainter& p, const MusEGui::CItem* item, const QRect& rect)
 
1026
{
 
1027
      MusECore::WavePart* wp = (MusECore::WavePart*)(item->part());
 
1028
      if(!wp || !wp->track())
 
1029
        return;
 
1030
 
 
1031
      //QRect rr = p.transform().mapRect(rect);  // Gives inconsistent positions. Source shows wrong operation for our needs.
 
1032
      QRect rr = map(rect);                      // Use our own map instead.        
 
1033
 
 
1034
      QRect mwpr  = map(QRect(wp->frame(), 0, wp->lenFrame(), height()));
 
1035
      
 
1036
      QRect r = item->bbox();
 
1037
      QRect mer = map(r);                              
 
1038
      QRect mr = rr & mer & mwpr;
 
1039
      if(mr.isNull())
 
1040
        return;
 
1041
      
 
1042
      MusECore::Event event  = item->event();
 
1043
      if(event.empty())
 
1044
        return;
 
1045
      
 
1046
      int x1 = mr.x();
 
1047
      int x2 = mr.right() + 1;
 
1048
      if (x1 < 0)
 
1049
            x1 = 0;
 
1050
      if (x2 > width())
 
1051
            x2 = width();
 
1052
      int hh = height();
 
1053
      int h  = hh/2;
 
1054
      int y  = mr.y() + h;
 
1055
 
 
1056
      int xScale = xmag;
 
1057
      if (xScale < 0)
 
1058
            xScale = -xScale;
 
1059
 
 
1060
      //int t_channels = wp->track()->channels();
 
1061
      int px = wp->frame();
 
1062
 
 
1063
      bool wmtxen = p.worldMatrixEnabled();
 
1064
      p.setWorldMatrixEnabled(false);
 
1065
 
 
1066
      int sx, ex;
 
1067
      
 
1068
      sx = event.frame() + px + xScale/2;
 
1069
      ex = sx + event.lenFrame();
 
1070
      sx = sx / xScale - xpos;
 
1071
      ex = ex / xScale - xpos;
 
1072
 
 
1073
      if (sx < x1)
 
1074
            sx = x1;
 
1075
      if (ex > x2)
 
1076
            ex = x2;
 
1077
 
 
1078
      int pos = (xpos + sx) * xScale + event.spos() - event.frame() - px;
 
1079
      
 
1080
      //printf("pos=%d xpos=%d sx=%d ex=%d xScale=%d event.spos=%d event.frame=%d px=%d\n",   
 
1081
      //      pos, xpos, sx, ex, xScale, event.spos(), event.frame(), px);
 
1082
 
 
1083
      
 
1084
      QBrush brush;
 
1085
      if (item->isMoving()) 
 
1086
      {
 
1087
            QColor c(Qt::gray);
 
1088
            c.setAlpha(MusEGlobal::config.globalAlphaBlend);
 
1089
            QLinearGradient gradient(r.topLeft(), r.bottomLeft());
 
1090
            gradient.setColorAt(0, c);
 
1091
            gradient.setColorAt(1, c.darker());
 
1092
            brush = QBrush(gradient);
 
1093
            p.fillRect(sx, 0, ex - sx, hh, brush);
 
1094
      }
 
1095
      else 
 
1096
      if (item->isSelected()) 
 
1097
      {
 
1098
          QColor c(Qt::black);
 
1099
          c.setAlpha(MusEGlobal::config.globalAlphaBlend);
 
1100
          QLinearGradient gradient(r.topLeft(), r.bottomLeft());
 
1101
          // Use a colour only about 20% lighter than black, rather than the 50% we use in MusECore::gGradientFromQColor
 
1102
          //  and is used in darker()/lighter(), so that it is distinguished a bit better from grey non-part tracks.
 
1103
          //c.setRgba(64, 64, 64, c.alpha());        
 
1104
          gradient.setColorAt(0, QColor(51, 51, 51, MusEGlobal::config.globalAlphaBlend));
 
1105
          gradient.setColorAt(1, c);
 
1106
          brush = QBrush(gradient);
 
1107
          p.fillRect(sx, 0, ex - sx, hh, brush);
 
1108
      }
 
1109
      //else
 
1110
      {
 
1111
            QPen pen(Qt::DashLine);
 
1112
            pen.setColor(Qt::black);
 
1113
            pen.setCosmetic(true);
 
1114
            p.setPen(pen);
 
1115
            p.drawRect(sx, 0, ex - sx, hh);
 
1116
      }  
 
1117
      //p.fillRect(sx, 0, ex - sx, hh, brush);
 
1118
      //p.drawRect(sx, 0, ex - sx, hh, brush);
 
1119
      
 
1120
      MusECore::SndFileR f = event.sndFile();
 
1121
      if(f.isNull())
 
1122
      {
 
1123
        p.setWorldMatrixEnabled(wmtxen);
 
1124
        return;
 
1125
      }
 
1126
      
 
1127
      int ev_channels = f.channels();
 
1128
      if (ev_channels == 0) {
 
1129
            p.setWorldMatrixEnabled(wmtxen);
 
1130
            printf("WaveCnvas::drawItem: ev_channels==0! %s\n", f.name().toLatin1().constData());
 
1131
            return;
 
1132
            }
 
1133
                  
 
1134
      h       = hh / (ev_channels * 2);
 
1135
      int cc  = hh % (ev_channels * 2) ? 0 : 1;
 
1136
 
 
1137
      unsigned peoffset = px + event.frame() - event.spos();
 
1138
      
 
1139
      for (int i = sx; i < ex; i++) {
 
1140
            y  = mr.y() + h;
 
1141
            MusECore::SampleV sa[f.channels()];
 
1142
            f.read(sa, xScale, pos);
 
1143
            pos += xScale;
 
1144
            if (pos < event.spos())
 
1145
                  continue;
 
1146
 
 
1147
            int selectionStartPos = selectionStart - peoffset; // Offset transformed to event coords
 
1148
            int selectionStopPos  = selectionStop  - peoffset;
 
1149
 
 
1150
            for (int k = 0; k < ev_channels; ++k) {
 
1151
                  int kk = k % f.channels();
 
1152
                  int peak = (sa[kk].peak * (h - 1)) / yScale;
 
1153
                  int rms  = (sa[kk].rms  * (h - 1)) / yScale;
 
1154
                  if (peak > h)
 
1155
                        peak = h;
 
1156
                  if (rms > h)
 
1157
                        rms = h;
 
1158
                  QColor peak_color = QColor(Qt::darkGray);
 
1159
                  QColor rms_color  = QColor(Qt::black);
 
1160
                  
 
1161
                  // Changed by T356. Reduces (but not eliminates) drawing artifacts. (TODO Cause of artifacts gone, correct this now.)
 
1162
                  //if (pos > selectionStartPos && pos < selectionStopPos) {
 
1163
                  if (pos > selectionStartPos && pos <= selectionStopPos) {
 
1164
                        
 
1165
                        peak_color = QColor(Qt::lightGray);
 
1166
                        rms_color  = QColor(Qt::white);
 
1167
                        // Draw inverted
 
1168
                        p.setPen(QColor(Qt::black));
 
1169
                        p.drawLine(i, y - h + cc, i, y + h - cc );
 
1170
                        }
 
1171
                  p.setPen(peak_color);
 
1172
                  p.drawLine(i, y - peak - cc, i, y + peak);
 
1173
                  p.setPen(rms_color);
 
1174
                  p.drawLine(i, y - rms - cc, i, y + rms);
 
1175
                  y  += 2 * h;
 
1176
                  }
 
1177
            }
 
1178
            
 
1179
 
 
1180
      int hn = hh / ev_channels;
 
1181
      int hhn = hn / 2;
 
1182
      for (int i = 0; i < ev_channels; ++i) {
 
1183
            int h2     = hn * i;
 
1184
            int center = hhn + h2;
 
1185
            p.setPen(QColor(i & i ? Qt::red : Qt::blue));
 
1186
            p.drawLine(sx, center, ex, center);
 
1187
            p.setPen(QColor(Qt::black));
 
1188
            p.drawLine(sx, h2, ex, h2);
 
1189
            }
 
1190
            
 
1191
      p.setWorldMatrixEnabled(wmtxen);
 
1192
}
 
1193
 
 
1194
//---------------------------------------------------------
 
1195
//   drawTopItem
 
1196
//---------------------------------------------------------
 
1197
void WaveCanvas::drawTopItem(QPainter& , const QRect&)
 
1198
{}
 
1199
 
 
1200
//---------------------------------------------------------
 
1201
//   drawMoving
 
1202
//    draws moving items
 
1203
//---------------------------------------------------------
 
1204
 
 
1205
void WaveCanvas::drawMoving(QPainter& p, const MusEGui::CItem* item, const QRect& rect)
 
1206
    {
 
1207
      QRect mr = QRect(item->mp().x(), item->mp().y(), item->width(), item->height());
 
1208
      mr = mr.intersected(rect);
 
1209
      if(!mr.isValid())
 
1210
        return;
 
1211
      p.setPen(Qt::black);
 
1212
      p.setBrush(QColor(0, 128, 0, 128));  // TODO: Pick a better colour, or use part colours, or grey?
 
1213
      p.drawRect(mr);
 
1214
    }
 
1215
 
 
1216
//---------------------------------------------------------
 
1217
//   viewMouseDoubleClickEvent
 
1218
//---------------------------------------------------------
 
1219
 
 
1220
void WaveCanvas::viewMouseDoubleClickEvent(QMouseEvent* event)
 
1221
      {
 
1222
      if ((_tool != MusEGui::PointerTool) && (event->button() != Qt::LeftButton)) {
 
1223
            mousePress(event);
 
1224
            return;
 
1225
            }
 
1226
      }
 
1227
 
 
1228
//---------------------------------------------------------
 
1229
//   moveCanvasItems
 
1230
//---------------------------------------------------------
 
1231
 
 
1232
MusECore::Undo WaveCanvas::moveCanvasItems(MusEGui::CItemList& items, int /*dp*/, int dx, DragType dtype)
 
1233
{      
 
1234
  if(editor->parts()->empty())
 
1235
    return MusECore::Undo(); //return empty list
 
1236
  
 
1237
  MusECore::PartsToChangeMap parts2change;
 
1238
  MusECore::Undo operations;  
 
1239
  
 
1240
  for(MusECore::iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip)
 
1241
  {
 
1242
    MusECore::Part* part = ip->second;
 
1243
    if(!part)
 
1244
      continue;
 
1245
    
 
1246
    int npartoffset = 0;
 
1247
    for(MusEGui::iCItem ici = items.begin(); ici != items.end(); ++ici) 
 
1248
    {
 
1249
      MusEGui::CItem* ci = ici->second;
 
1250
      if(ci->part() != part)
 
1251
        continue;
 
1252
      
 
1253
      int x = ci->pos().x() + dx;
 
1254
      //int y = pitch2y(y2pitch(ci->pos().y()) + dp);
 
1255
      int y = 0;
 
1256
      QPoint newpos = raster(QPoint(x, y));
 
1257
      
 
1258
      // Test moving the item...
 
1259
      WEvent* wevent = (WEvent*) ci;
 
1260
      MusECore::Event event    = wevent->event();
 
1261
      x              = newpos.x();
 
1262
      if(x < 0)
 
1263
        x = 0;
 
1264
      int nframe = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x))) - part->frame();
 
1265
      if(nframe < 0)
 
1266
        nframe = 0;
 
1267
      int diff = nframe + event.lenFrame() - part->lenFrame();
 
1268
      
 
1269
      // If moving the item would require a new part size...
 
1270
      if(diff > npartoffset)
 
1271
        npartoffset = diff;
 
1272
    }
 
1273
        
 
1274
    if(npartoffset > 0)
 
1275
    {    
 
1276
      MusECore::iPartToChange ip2c = parts2change.find(part);
 
1277
      if(ip2c == parts2change.end())
 
1278
      {
 
1279
        MusECore::PartToChange p2c = {0, npartoffset};
 
1280
        parts2change.insert(std::pair<MusECore::Part*, MusECore::PartToChange> (part, p2c));
 
1281
      }
 
1282
      else
 
1283
        ip2c->second.xdiff = npartoffset;
 
1284
    }
 
1285
  }
 
1286
  
 
1287
  bool forbidden=false;
 
1288
  for(MusECore::iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c)
 
1289
  {
 
1290
    MusECore::Part* opart = ip2c->first;
 
1291
    if (opart->hasHiddenEvents())
 
1292
    {
 
1293
                        forbidden=true;
 
1294
                        break;
 
1295
                }
 
1296
  }    
 
1297
 
 
1298
        
 
1299
        if (!forbidden)
 
1300
        {
 
1301
                std::vector< MusEGui::CItem* > doneList;
 
1302
                typedef std::vector< MusEGui::CItem* >::iterator iDoneList;
 
1303
                
 
1304
                for(MusEGui::iCItem ici = items.begin(); ici != items.end(); ++ici) 
 
1305
                {
 
1306
                        MusEGui::CItem* ci = ici->second;
 
1307
                        
 
1308
                        int x = ci->pos().x();
 
1309
                        //int y = ci->pos().y();
 
1310
                        int nx = x + dx;
 
1311
                        //int ny = pitch2y(y2pitch(y) + dp);
 
1312
                        int ny = 0;
 
1313
                        QPoint newpos = raster(QPoint(nx, ny));
 
1314
                        selectItem(ci, true);
 
1315
                        
 
1316
                        iDoneList idl;
 
1317
                        for(idl = doneList.begin(); idl != doneList.end(); ++idl)
 
1318
                                // This compares EventBase pointers to see if they're the same...
 
1319
                                if((*idl)->event() == ci->event())
 
1320
                                        break;
 
1321
                                
 
1322
                        // Do not process if the event has already been processed (meaning it's an event in a clone part)...
 
1323
                        if (idl == doneList.end())
 
1324
                        {
 
1325
                                moveItem(operations, ci, newpos, dtype); // always returns true. if not, change is necessary here!
 
1326
                                doneList.push_back(ci);
 
1327
                        }
 
1328
                        ci->move(newpos);
 
1329
                                                
 
1330
                        if(moving.size() == 1) 
 
1331
                                                itemReleased(curItem, newpos);
 
1332
 
 
1333
                        if(dtype == MOVE_COPY || dtype == MOVE_CLONE)
 
1334
                                                selectItem(ci, false);
 
1335
                }  
 
1336
 
 
1337
    for(MusECore::iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c)
 
1338
    {
 
1339
      MusECore::Part* opart = ip2c->first;
 
1340
      int diff = ip2c->second.xdiff;
 
1341
      
 
1342
      //schedule_resize_all_same_len_clone_parts(opart, opart->lenTick() + diff, operations);
 
1343
      schedule_resize_all_same_len_clone_parts(opart, opart->lenFrame() + diff, operations);
 
1344
    }    
 
1345
                                        
 
1346
        return operations;
 
1347
  }
 
1348
  else
 
1349
  {
 
1350
                return MusECore::Undo(); //return empty list
 
1351
        }
 
1352
}
 
1353
      
 
1354
//---------------------------------------------------------
 
1355
//   moveItem
 
1356
//    called after moving an object
 
1357
//---------------------------------------------------------
 
1358
 
 
1359
bool WaveCanvas::moveItem(MusECore::Undo& operations, MusEGui::CItem* item, const QPoint& pos, DragType dtype)
 
1360
      {
 
1361
      WEvent* wevent = (WEvent*) item;
 
1362
      MusECore::Event event    = wevent->event();
 
1363
      //int npitch     = y2pitch(pos.y());
 
1364
      MusECore::Event newEvent = event.clone();
 
1365
      int x          = pos.x();
 
1366
      if (x < 0)
 
1367
            x = 0;
 
1368
      
 
1369
      MusECore::Part* part = wevent->part();
 
1370
      int nframe = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x))) - part->frame();
 
1371
      if (nframe < 0)
 
1372
            nframe = 0;
 
1373
      newEvent.setFrame(nframe);
 
1374
      newEvent.setLenFrame(event.lenFrame());
 
1375
 
 
1376
      // don't check, whether the new event is within the part
 
1377
      // at this place. with operation groups, the part isn't
 
1378
      // resized yet. (flo93)
 
1379
      
 
1380
      if (dtype == MOVE_COPY || dtype == MOVE_CLONE)
 
1381
            operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddEvent, newEvent, part, false, false));
 
1382
      else
 
1383
            operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
 
1384
      
 
1385
      return true;
 
1386
}
 
1387
 
 
1388
//---------------------------------------------------------
 
1389
//   newItem(p, state)
 
1390
//---------------------------------------------------------
 
1391
 
 
1392
MusEGui::CItem* WaveCanvas::newItem(const QPoint& p, int)
 
1393
      {
 
1394
      int frame  = MusEGlobal::tempomap.tick2frame(editor->rasterVal1(MusEGlobal::tempomap.frame2tick(p.x())));
 
1395
      int len   = p.x() - frame;
 
1396
      frame     -= curPart->frame();
 
1397
      if (frame < 0)
 
1398
            return 0;
 
1399
      MusECore::Event e =  MusECore::Event(MusECore::Wave);
 
1400
      e.setFrame(frame);
 
1401
      e.setLenFrame(len);
 
1402
      WEvent* we = new WEvent(e, curPart, height());
 
1403
      return we;
 
1404
      }
 
1405
 
 
1406
void WaveCanvas::newItem(MusEGui::CItem* item, bool noSnap)
 
1407
      {
 
1408
      WEvent* wevent = (WEvent*) item;
 
1409
      MusECore::Event event    = wevent->event();
 
1410
      int x = item->x();
 
1411
      if (x<0)
 
1412
            x=0;
 
1413
      int w = item->width();
 
1414
 
 
1415
      if (!noSnap) {
 
1416
            //x = editor->rasterVal1(x); //round down
 
1417
            x = MusEGlobal::tempomap.tick2frame(editor->rasterVal1(MusEGlobal::tempomap.frame2tick(x))); //round down
 
1418
            //w = editor->rasterVal(x + w) - x;
 
1419
            w = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x + w))) - x;
 
1420
            if (w == 0)
 
1421
                  //w = editor->raster();
 
1422
                  w = MusEGlobal::tempomap.tick2frame(editor->raster());
 
1423
            }
 
1424
      MusECore::Part* part = wevent->part();
 
1425
      event.setFrame(x - part->frame());
 
1426
      event.setLenFrame(w);
 
1427
 
 
1428
      MusECore::Undo operations;
 
1429
      int diff = event.endFrame() - part->lenFrame();
 
1430
      
 
1431
      if (! ((diff > 0) && part->hasHiddenEvents()) ) //operation is allowed
 
1432
      {
 
1433
        operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddEvent,event, part, false, false));
 
1434
        
 
1435
        if (diff > 0)// part must be extended?
 
1436
        {
 
1437
              //schedule_resize_all_same_len_clone_parts(part, event.endTick(), operations);
 
1438
              schedule_resize_all_same_len_clone_parts(part, event.endFrame(), operations);
 
1439
              printf("newItem: extending\n");
 
1440
        }
 
1441
        
 
1442
        MusEGlobal::song->applyOperationGroup(operations);
 
1443
      }
 
1444
      else // forbid action by not applying it   
 
1445
          songChanged(SC_EVENT_INSERTED); //this forces an update of the itemlist, which is neccessary
 
1446
                                          //to remove "forbidden" events from the list again
 
1447
      }
 
1448
 
 
1449
//---------------------------------------------------------
 
1450
//   resizeItem
 
1451
//---------------------------------------------------------
 
1452
 
 
1453
void WaveCanvas::resizeItem(MusEGui::CItem* item, bool noSnap, bool)         // experimental changes to try dynamically extending parts
 
1454
      {
 
1455
      WEvent* wevent = (WEvent*) item;
 
1456
      MusECore::Event event    = wevent->event();
 
1457
      MusECore::Event newEvent = event.clone();
 
1458
      int len;
 
1459
 
 
1460
      MusECore::Part* part = wevent->part();
 
1461
 
 
1462
      if (noSnap)
 
1463
            len = wevent->width();
 
1464
      else {
 
1465
            unsigned frame = event.frame() + part->frame();
 
1466
            //len = editor->rasterVal(tick + wevent->width()) - tick;
 
1467
            len = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(frame + wevent->width()))) - frame;
 
1468
            if (len <= 0)
 
1469
                  //len = editor->raster();
 
1470
                  len = MusEGlobal::tempomap.tick2frame(editor->raster());
 
1471
      }
 
1472
 
 
1473
      MusECore::Undo operations;
 
1474
      //int diff = event.tick()+len-part->lenTick();
 
1475
      int diff = event.frame() + len - part->lenFrame();
 
1476
      
 
1477
      if (! ((diff > 0) && part->hasHiddenEvents()) ) //operation is allowed
 
1478
      {
 
1479
        //newEvent.setLenTick(len);
 
1480
        newEvent.setLenFrame(len);
 
1481
        operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent,newEvent, event, wevent->part(), false, false));
 
1482
        
 
1483
        if (diff > 0)// part must be extended?
 
1484
        {
 
1485
              //schedule_resize_all_same_len_clone_parts(part, event.tick()+len, operations);
 
1486
              schedule_resize_all_same_len_clone_parts(part, event.frame() + len, operations);
 
1487
              printf("resizeItem: extending\n");
 
1488
        }
 
1489
      }
 
1490
      //else forbid action by not performing it
 
1491
      MusEGlobal::song->applyOperationGroup(operations);
 
1492
      songChanged(SC_EVENT_MODIFIED); //this forces an update of the itemlist, which is neccessary
 
1493
                                      //to remove "forbidden" events from the list again
 
1494
      }
 
1495
 
 
1496
//---------------------------------------------------------
 
1497
//   deleteItem
 
1498
//---------------------------------------------------------
 
1499
 
 
1500
bool WaveCanvas::deleteItem(MusEGui::CItem* item)
 
1501
      {
 
1502
      WEvent* wevent = (WEvent*) item;
 
1503
      if (wevent->part() == curPart) {
 
1504
            MusECore::Event ev = wevent->event();
 
1505
            // Indicate do undo, and do not do port controller values and clone parts. 
 
1506
            MusEGlobal::audio->msgDeleteEvent(ev, curPart, true, false, false);
 
1507
            return true;
 
1508
            }
 
1509
      return false;
 
1510
      }
 
1511
 
 
1512
//---------------------------------------------------------
 
1513
//   adjustWaveOffset
 
1514
//---------------------------------------------------------
 
1515
 
 
1516
void WaveCanvas::adjustWaveOffset()
 
1517
{
 
1518
  bool have_selected = false;
 
1519
  int init_offset = 0;
 
1520
  
 
1521
  for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) 
 
1522
  {
 
1523
    if (k->second->isSelected())
 
1524
    {
 
1525
      have_selected = true;
 
1526
      init_offset = k->second->event().spos();
 
1527
      break;
 
1528
    }
 
1529
  }
 
1530
 
 
1531
  if(!have_selected)
 
1532
  {
 
1533
    QMessageBox::information(this, 
 
1534
        QString("MusE"),
 
1535
        QWidget::tr("No wave events selected."));
 
1536
    return;
 
1537
  }
 
1538
 
 
1539
  bool ok = false;
 
1540
  int offset = QInputDialog::getInt(this, 
 
1541
                                    tr("Adjust Wave Offset"), 
 
1542
                                    tr("Wave offset (frames)"), 
 
1543
                                    init_offset, 
 
1544
                                    0, 2147483647, 1, 
 
1545
                                    &ok);
 
1546
  if(!ok)
 
1547
    return;    
 
1548
  
 
1549
  MusECore::Undo operations;
 
1550
 
 
1551
  // FIXME: Respect clones! If operating on two selected clones of the same part, an extra event is created!
 
1552
  //        Check - Is it really this code's problem? Seems so, other operations like moving an event seem OK.
 
1553
  for(MusEGui::iCItem ici = items.begin(); ici != items.end(); ++ici) 
 
1554
  {
 
1555
    if(ici->second->isSelected())
 
1556
    {
 
1557
      MusECore::Event oldEvent = ici->second->event();
 
1558
      if(oldEvent.spos() != offset)
 
1559
      {
 
1560
        MusECore::Part* part = ici->second->part();
 
1561
        MusECore::Event newEvent = oldEvent.clone();
 
1562
        newEvent.setSpos(offset);
 
1563
        // Do not do port controller values and clone parts. 
 
1564
        operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, oldEvent, part, false, false));
 
1565
      }
 
1566
    }
 
1567
  }
 
1568
  
 
1569
  MusEGlobal::song->applyOperationGroup(operations);
 
1570
  
 
1571
  redraw();
 
1572
}
 
1573
      
 
1574
//---------------------------------------------------------
 
1575
//   draw
 
1576
//---------------------------------------------------------
 
1577
 
 
1578
void WaveCanvas::drawCanvas(QPainter& p, const QRect& rect)
 
1579
      {
 
1580
      int x = rect.x();
 
1581
      int y = rect.y();
 
1582
      int w = rect.width();
 
1583
      int h = rect.height();
 
1584
 
 
1585
      //---------------------------------------------------
 
1586
      // vertical lines
 
1587
      //---------------------------------------------------
 
1588
 
 
1589
      drawTickRaster(p, x, y, w, h, editor->raster());
 
1590
      }
 
1591
 
 
1592
//---------------------------------------------------------
 
1593
//   waveCmd
 
1594
//---------------------------------------------------------
 
1595
 
 
1596
void WaveCanvas::waveCmd(int cmd)
 
1597
      {
 
1598
      // TODO: New WaveCanvas: Convert this routine to frames.  
 
1599
      switch(cmd) {
 
1600
            case CMD_LEFT:
 
1601
                  {
 
1602
                  int spos = pos[0];
 
1603
                  if(spos > 0) 
 
1604
                  {
 
1605
                    spos -= 1;     // Nudge by -1, then snap down with raster1.
 
1606
                    spos = AL::sigmap.raster1(spos, editor->rasterStep(pos[0]));
 
1607
                  }  
 
1608
                  if(spos < 0)
 
1609
                    spos = 0;
 
1610
                  MusECore::Pos p(spos,true);
 
1611
                  MusEGlobal::song->setPos(0, p, true, true, true);
 
1612
                  }
 
1613
                  break;
 
1614
            case CMD_RIGHT:
 
1615
                  {
 
1616
                  int spos = AL::sigmap.raster2(pos[0] + 1, editor->rasterStep(pos[0]));    // Nudge by +1, then snap up with raster2.
 
1617
                  MusECore::Pos p(spos,true);
 
1618
                  MusEGlobal::song->setPos(0, p, true, true, true); 
 
1619
                  }
 
1620
                  break;
 
1621
            case CMD_LEFT_NOSNAP:
 
1622
                  {
 
1623
                  int spos = pos[0] - editor->rasterStep(pos[0]);
 
1624
                  if (spos < 0)
 
1625
                        spos = 0;
 
1626
                  MusECore::Pos p(spos,true);
 
1627
                  MusEGlobal::song->setPos(0, p, true, true, true); //CDW
 
1628
                  }
 
1629
                  break;
 
1630
            case CMD_RIGHT_NOSNAP:
 
1631
                  {
 
1632
                  MusECore::Pos p(pos[0] + editor->rasterStep(pos[0]), true);
 
1633
                  MusEGlobal::song->setPos(0, p, true, true, true); //CDW
 
1634
                  }
 
1635
                  break;
 
1636
            case CMD_INSERT:
 
1637
                  {
 
1638
                  if (pos[0] < start() || pos[0] >= end())
 
1639
                        break;
 
1640
                  MusECore::MidiPart* part = (MusECore::MidiPart*)curPart;
 
1641
 
 
1642
                  if (part == 0)
 
1643
                        break;
 
1644
 
 
1645
                  MusECore::EventList* el = part->events();
 
1646
                  MusECore::Undo operations;
 
1647
 
 
1648
                  std::list <MusECore::Event> elist;
 
1649
                  for (MusECore::iEvent e = el->lower_bound(pos[0] - part->tick()); e != el->end(); ++e)
 
1650
                        elist.push_back((MusECore::Event)e->second);
 
1651
                  for (std::list<MusECore::Event>::iterator i = elist.begin(); i != elist.end(); ++i) {
 
1652
                        MusECore::Event event = *i;
 
1653
                        MusECore::Event newEvent = event.clone();
 
1654
                        newEvent.setTick(event.tick() + editor->raster());// - part->tick()); DELETETHIS
 
1655
                        // Do not do port controller values and clone parts. 
 
1656
                        operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
 
1657
                        }
 
1658
                  MusEGlobal::song->applyOperationGroup(operations);
 
1659
                  
 
1660
                  MusECore::Pos p(editor->rasterVal(pos[0] + editor->rasterStep(pos[0])), true);
 
1661
                  MusEGlobal::song->setPos(0, p, true, false, true);
 
1662
                  }
 
1663
                  return;
 
1664
            case CMD_BACKSPACE:
 
1665
                  if (pos[0] < start() || pos[0] >= end())
 
1666
                        break;
 
1667
                  {
 
1668
                  MusECore::MidiPart* part = (MusECore::MidiPart*)curPart;
 
1669
                  if (part == 0)
 
1670
                        break;
 
1671
                  
 
1672
                  MusECore::Undo operations;
 
1673
                  MusECore::EventList* el = part->events();
 
1674
 
 
1675
                  std::list<MusECore::Event> elist;
 
1676
                  for (MusECore::iEvent e = el->lower_bound(pos[0]); e != el->end(); ++e)
 
1677
                        elist.push_back((MusECore::Event)e->second);
 
1678
                  for (std::list<MusECore::Event>::iterator i = elist.begin(); i != elist.end(); ++i) {
 
1679
                        MusECore::Event event = *i;
 
1680
                        MusECore::Event newEvent = event.clone();
 
1681
                        newEvent.setTick(event.tick() - editor->raster() - part->tick());
 
1682
                        // Do not do port controller values and clone parts. 
 
1683
                        operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
 
1684
                        }
 
1685
                  MusEGlobal::song->applyOperationGroup(operations);
 
1686
                  MusECore::Pos p(editor->rasterVal(pos[0] - editor->rasterStep(pos[0])), true);
 
1687
                  MusEGlobal::song->setPos(0, p, true, false, true);
 
1688
                  }
 
1689
                  break;
 
1690
            }
 
1691
      }
 
1692
 
 
1693
//---------------------------------------------------------
 
1694
//   cmd
 
1695
//    pulldown menu commands
 
1696
//---------------------------------------------------------
 
1697
 
 
1698
void WaveCanvas::cmd(int cmd)
 
1699
      {
 
1700
      int modifyoperation = -1;
 
1701
      double paramA = 0.0;
 
1702
      switch (cmd) {
 
1703
            case CMD_SELECT_ALL:     // select all
 
1704
                  if (tool() == MusEGui::CursorTool) 
 
1705
                  {
 
1706
                    if (!editor->parts()->empty()) {
 
1707
                          MusECore::iPart iBeg = editor->parts()->begin();
 
1708
                          MusECore::iPart iEnd = editor->parts()->end();
 
1709
                          iEnd--;
 
1710
                          MusECore::WavePart* beg = (MusECore::WavePart*) iBeg->second;
 
1711
                          MusECore::WavePart* end = (MusECore::WavePart*) iEnd->second;
 
1712
                          selectionStart = beg->frame();
 
1713
                          selectionStop  = end->frame() + end->lenFrame();
 
1714
                          redraw();
 
1715
                          }
 
1716
                  }
 
1717
                  for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
 
1718
                        if (!k->second->isSelected())
 
1719
                              selectItem(k->second, true);
 
1720
                        }
 
1721
                  break;
 
1722
            case CMD_SELECT_NONE:     // select none
 
1723
                  selectionStart = selectionStop = 0;
 
1724
                  deselectAll();
 
1725
                  break;
 
1726
            case CMD_SELECT_INVERT:     // invert selection
 
1727
                  for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
 
1728
                        selectItem(k->second, !k->second->isSelected());
 
1729
                        }
 
1730
                  break;
 
1731
            case CMD_SELECT_ILOOP:     // select inside loop
 
1732
                  for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
 
1733
                        WEvent* wevent = (WEvent*)(k->second);
 
1734
                        MusECore::Part* part     = wevent->part();
 
1735
                        MusECore::Event event    = wevent->event();
 
1736
                        unsigned tick  = event.tick() + part->tick();
 
1737
                        if (tick < MusEGlobal::song->lpos() || tick >= MusEGlobal::song->rpos())
 
1738
                              selectItem(k->second, false);
 
1739
                        else
 
1740
                              selectItem(k->second, true);
 
1741
                        }
 
1742
                  break;
 
1743
            case CMD_SELECT_OLOOP:     // select outside loop
 
1744
                  for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
 
1745
                        WEvent* wevent = (WEvent*)(k->second);
 
1746
                        MusECore::Part* part     = wevent->part();
 
1747
                        MusECore::Event event    = wevent->event();
 
1748
                        unsigned tick  = event.tick() + part->tick();
 
1749
                        if (tick < MusEGlobal::song->lpos() || tick >= MusEGlobal::song->rpos())
 
1750
                              selectItem(k->second, true);
 
1751
                        else
 
1752
                              selectItem(k->second, false);
 
1753
                        }
 
1754
                  break;
 
1755
            case CMD_SELECT_PREV_PART:     // select previous part
 
1756
                  {
 
1757
                    MusECore::Part* pt = editor->curCanvasPart();
 
1758
                    MusECore::Part* newpt = pt;
 
1759
                    MusECore::PartList* pl = editor->parts();
 
1760
                    for(MusECore::iPart ip = pl->begin(); ip != pl->end(); ++ip)
 
1761
                      if(ip->second == pt) 
 
1762
                      {
 
1763
                        if(ip == pl->begin())
 
1764
                          ip = pl->end();
 
1765
                        --ip;
 
1766
                        newpt = ip->second;
 
1767
                        break;    
 
1768
                      }
 
1769
                    if(newpt != pt)
 
1770
                      editor->setCurCanvasPart(newpt);
 
1771
                  }
 
1772
                  break;
 
1773
            case CMD_SELECT_NEXT_PART:     // select next part
 
1774
                  {
 
1775
                    MusECore::Part* pt = editor->curCanvasPart();
 
1776
                    MusECore::Part* newpt = pt;
 
1777
                    MusECore::PartList* pl = editor->parts();
 
1778
                    for(MusECore::iPart ip = pl->begin(); ip != pl->end(); ++ip)
 
1779
                      if(ip->second == pt) 
 
1780
                      {
 
1781
                        ++ip;
 
1782
                        if(ip == pl->end())
 
1783
                          ip = pl->begin();
 
1784
                        newpt = ip->second;
 
1785
                        break;    
 
1786
                      }
 
1787
                    if(newpt != pt)
 
1788
                      editor->setCurCanvasPart(newpt);
 
1789
                  }
 
1790
                  break;
 
1791
                 
 
1792
            case CMD_ADJUST_WAVE_OFFSET:
 
1793
                  adjustWaveOffset();
 
1794
                  break;
 
1795
 
 
1796
            case CMD_EDIT_EXTERNAL:
 
1797
                  modifyoperation = EDIT_EXTERNAL;
 
1798
                  break;
 
1799
 
 
1800
            case CMD_EDIT_COPY:
 
1801
                  modifyoperation = COPY;
 
1802
                  break;
 
1803
            case CMD_EDIT_CUT:
 
1804
                  modifyoperation = CUT;
 
1805
                  break;
 
1806
            case CMD_EDIT_PASTE:
 
1807
                  modifyoperation = PASTE;
 
1808
                  break;
 
1809
 
 
1810
            case CMD_MUTE:
 
1811
                  modifyoperation = MUTE;
 
1812
                  break;
 
1813
 
 
1814
            case CMD_NORMALIZE:
 
1815
                  modifyoperation = NORMALIZE;
 
1816
                  break;
 
1817
 
 
1818
            case CMD_FADE_IN:
 
1819
                  modifyoperation = FADE_IN;
 
1820
                  break;
 
1821
 
 
1822
            case CMD_FADE_OUT:
 
1823
                  modifyoperation = FADE_OUT;
 
1824
                  break;
 
1825
 
 
1826
            case CMD_REVERSE:
 
1827
                  modifyoperation = REVERSE;
 
1828
                  break;
 
1829
 
 
1830
            case CMD_GAIN_FREE: {
 
1831
                  EditGain* editGain = new EditGain(this, lastGainvalue);
 
1832
                  if (editGain->exec() == QDialog::Accepted) {
 
1833
                        lastGainvalue = editGain->getGain();
 
1834
                        modifyoperation = GAIN;
 
1835
                        paramA = (double)lastGainvalue / 100.0;
 
1836
                        }
 
1837
                  delete editGain;
 
1838
                  }
 
1839
                  break;
 
1840
 
 
1841
            case CMD_GAIN_200:
 
1842
                  modifyoperation = GAIN;
 
1843
                  paramA = 2.0;
 
1844
                  break;
 
1845
 
 
1846
            case CMD_GAIN_150:
 
1847
                  modifyoperation = GAIN;
 
1848
                  paramA = 1.5;
 
1849
                  break;
 
1850
 
 
1851
            case CMD_GAIN_75:
 
1852
                  modifyoperation = GAIN;
 
1853
                  paramA = 0.75;
 
1854
                  break;
 
1855
 
 
1856
            case CMD_GAIN_50:
 
1857
                  modifyoperation = GAIN;
 
1858
                  paramA = 0.5;
 
1859
                  break;
 
1860
 
 
1861
            case CMD_GAIN_25:
 
1862
                  modifyoperation = GAIN;
 
1863
                  paramA = 0.25;
 
1864
                  break;
 
1865
 
 
1866
            case CMD_CREATE_PART_REGION:
 
1867
                  {
 
1868
                      // create a new part and put in the copy buffer
 
1869
                      MusECore::Part* pt = editor->curCanvasPart();
 
1870
                      if (pt == 0 || pt->track()->type() != MusECore::Track::WAVE)
 
1871
                          return;
 
1872
                      MusECore::WavePart *origPart = (MusECore::WavePart*)pt;
 
1873
                      if (MusEGlobal::song->lpos() < origPart->tick() || MusEGlobal::song->rpos() > origPart->endTick())
 
1874
                      {
 
1875
                          QMessageBox::warning(this, tr("Part creation failed"),
 
1876
                                       tr("Left and right position markers must be placed inside the current part."),
 
1877
                                       QMessageBox::Ok, QMessageBox::Ok);
 
1878
                          return;
 
1879
                      }
 
1880
                      MusECore::WavePart *tempPart = new MusECore::WavePart(origPart->track());
 
1881
                      unsigned origFrame = origPart->frame();
 
1882
                      unsigned frameDistance = MusEGlobal::song->lPos().frame() - origFrame;
 
1883
                      tempPart->setPos(MusEGlobal::song->lpos());
 
1884
                      tempPart->setLenTick(MusEGlobal::song->rpos() - MusEGlobal::song->lpos());
 
1885
                      // loop through the events and set them accordingly
 
1886
                      for (MusECore::iEvent iWaveEvent = origPart->events()->begin(); iWaveEvent != origPart->events()->end(); iWaveEvent++)
 
1887
                      {
 
1888
                          // TODO: handle multiple events correctly,
 
1889
                          // the math for subsequent events isn't correct
 
1890
                          MusECore::Event &ev = iWaveEvent->second;
 
1891
                          MusECore::Event *newEvent = new MusECore::Event(ev.clone());
 
1892
                          newEvent->setSpos(ev.spos() + frameDistance);
 
1893
                          newEvent->setLenTick(MusEGlobal::song->rpos() - MusEGlobal::song->lpos());
 
1894
                          tempPart->addEvent(*newEvent);
 
1895
                      }
 
1896
                      std::set<MusECore::Part*> partList;
 
1897
                      partList.insert(tempPart);
 
1898
 
 
1899
                      QMimeData *mimeData =  MusECore::parts_to_mime(partList);
 
1900
                      QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
 
1901
                      QMessageBox::information(this, tr("Part created"),
 
1902
                                   tr("The selected region has been copied to the clipboard and can be pasted in the arranger."),
 
1903
                                   QMessageBox::Ok, QMessageBox::Ok);
 
1904
                  }
 
1905
                  break;
 
1906
            case CMD_ERASE_MEASURE:
 
1907
            case CMD_DELETE_MEASURE:
 
1908
            case CMD_CREATE_MEASURE:
 
1909
                  break;
 
1910
            default:
 
1911
//                  printf("unknown ecanvas cmd %d\n", cmd);
 
1912
                  break;
 
1913
            }
 
1914
            
 
1915
      if (modifyoperation != -1) {
 
1916
            if (selectionStart == selectionStop && modifyoperation!=PASTE) {
 
1917
                  printf("No selection. Ignoring\n"); //@!TODO: Disable menu options when no selection
 
1918
                  QMessageBox::information(this, 
 
1919
                     QString("MusE"),
 
1920
                     QWidget::tr("No selection. Ignoring"));
 
1921
 
 
1922
                  return;
 
1923
                  }
 
1924
            
 
1925
            //if(!modifyWarnedYet)
 
1926
            //{
 
1927
            //  modifyWarnedYet = true;
 
1928
            //  if(QMessageBox::warning(this, QString("Muse"),
 
1929
            //     tr("Warning! Muse currently operates directly on the sound file.\n"
 
1930
            //        "Undo is supported, but NOT after exit, WITH OR WITHOUT A SAVE!"), tr("&Ok"), tr("&Cancel"),
 
1931
            //     QString::null, 0, 1 ) != 0)
 
1932
            //   return;
 
1933
            //}
 
1934
            modifySelection(modifyoperation, selectionStart, selectionStop, paramA);
 
1935
            }
 
1936
            
 
1937
      updateSelection();
 
1938
      redraw();
 
1939
      }
 
1940
 
 
1941
//---------------------------------------------------------
 
1942
//   getSelection
 
1943
//---------------------------------------------------------
 
1944
MusECore::WaveSelectionList WaveCanvas::getSelection(unsigned startpos, unsigned stoppos)
 
1945
      {
 
1946
      MusECore::WaveSelectionList selection;
 
1947
 
 
1948
      for (MusECore::iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) {
 
1949
            MusECore::WavePart* wp = (MusECore::WavePart*)(ip->second);
 
1950
            unsigned part_offset = wp->frame();
 
1951
            
 
1952
            MusECore::EventList* el = wp->events();
 
1953
            //printf("eventlist length=%d\n",el->size());
 
1954
 
 
1955
            for (MusECore::iEvent e = el->begin(); e != el->end(); ++e) {
 
1956
                  MusECore::Event event  = e->second;
 
1957
                  if (event.empty())
 
1958
                        continue;
 
1959
                  MusECore::SndFileR file = event.sndFile();
 
1960
                  if (file.isNull())
 
1961
                        continue;
 
1962
 
 
1963
                  // Respect part end: Don't modify stuff outside of part boundary.
 
1964
                  unsigned elen = event.lenFrame();
 
1965
                  if(event.frame() + event.lenFrame() >= wp->lenFrame())
 
1966
                  {
 
1967
                    // Adjust apparent operation length:
 
1968
                    if(event.frame() > wp->lenFrame())
 
1969
                      elen = 0;
 
1970
                    else
 
1971
                      elen = wp->lenFrame() - event.frame();
 
1972
                  }
 
1973
                  
 
1974
                  unsigned event_offset = event.frame() + part_offset;
 
1975
                  unsigned event_startpos  = event.spos();
 
1976
                  unsigned event_length = elen + event.spos();
 
1977
                  unsigned event_end    = event_offset + event_length;
 
1978
                  //printf("startpos=%d stoppos=%d part_offset=%d event_offset=%d event_startpos=%d event_length=%d event_end=%d\n", startpos, stoppos, part_offset, event_offset, event_startpos, event_length, event_end);
 
1979
 
 
1980
                  if (!(event_end <= startpos || event_offset > stoppos)) {
 
1981
                        int tmp_sx = startpos - event_offset + event_startpos;
 
1982
                        int tmp_ex = stoppos  - event_offset + event_startpos;
 
1983
                        unsigned sx;
 
1984
                        unsigned ex;
 
1985
 
 
1986
                        tmp_sx < (int)event_startpos ? sx = event_startpos : sx = tmp_sx;
 
1987
                        tmp_ex > (int)event_length   ? ex = event_length   : ex = tmp_ex;
 
1988
 
 
1989
                        //printf("Event data affected: %d->%d filename:%s\n", sx, ex, file.name().toLatin1().constData());
 
1990
                        MusECore::WaveEventSelection s;
 
1991
                        s.event = event;  
 
1992
                        s.startframe = sx;
 
1993
                        s.endframe   = ex+1;
 
1994
                        //printf("sx=%d ex=%d\n",sx,ex);
 
1995
                        selection.push_back(s);
 
1996
                        }
 
1997
                  }
 
1998
            }
 
1999
 
 
2000
            return selection;
 
2001
      }
 
2002
 
 
2003
//---------------------------------------------------------
 
2004
//   modifySelection
 
2005
//---------------------------------------------------------
 
2006
void WaveCanvas::modifySelection(int operation, unsigned startpos, unsigned stoppos, double paramA)
 
2007
      {
 
2008
        if (operation == PASTE) {
 
2009
          // we need to redefine startpos and stoppos
 
2010
          if (copiedPart =="")
 
2011
            return;
 
2012
          MusECore::SndFile pasteFile(copiedPart);
 
2013
          pasteFile.openRead();
 
2014
          startpos = pos[0];
 
2015
          stoppos = startpos+ pasteFile.samples(); // possibly this is wrong if there are tempo changes
 
2016
          pasteFile.close();
 
2017
          pos[0]=stoppos;
 
2018
        }
 
2019
 
 
2020
        //
 
2021
        // Copy on Write: Check if some files need to be copied, either because they are not 
 
2022
        //  writable, or more than one independent (non-clone) wave event shares a wave file.
 
2023
        //
 
2024
        
 
2025
        MusECore::WaveSelectionList selection = getSelection(startpos, stoppos);
 
2026
        std::vector<MusECore::SndFileR> copy_files_proj_dir;
 
2027
        for(MusECore::iWaveSelection i = selection.begin(); i != selection.end(); i++) 
 
2028
        {
 
2029
          MusECore::WaveEventSelection w = *i;
 
2030
          MusECore::SndFileR file = w.event.sndFile();
 
2031
          if(file.checkCopyOnWrite())
 
2032
          {
 
2033
            std::vector<MusECore::SndFileR>::iterator i = copy_files_proj_dir.begin();
 
2034
            for( ; i != copy_files_proj_dir.end(); ++i)
 
2035
            {
 
2036
              if(i->canonicalPath() == file.canonicalPath())
 
2037
                break; 
 
2038
            }  
 
2039
            if(i == copy_files_proj_dir.end())
 
2040
              copy_files_proj_dir.push_back(file);
 
2041
          }
 
2042
        }
 
2043
        if(!copy_files_proj_dir.empty())
 
2044
        {
 
2045
          CopyOnWriteDialog* dlg = new CopyOnWriteDialog();
 
2046
          for(std::vector<MusECore::SndFileR>::iterator i = copy_files_proj_dir.begin(); i != copy_files_proj_dir.end(); ++i)
 
2047
          {
 
2048
            qint64 sz = QFile(i->canonicalPath()).size();
 
2049
            QString s;
 
2050
            if(sz > 1048576)
 
2051
              s += QString::number(sz / 1048576) + "MB ";
 
2052
            else
 
2053
            if(sz > 1024)
 
2054
              s += QString::number(sz / 1024) + "KB ";
 
2055
            else
 
2056
              s += QString::number(sz) + "B ";
 
2057
            s += i->canonicalPath();
 
2058
            dlg->addProjDirFile(s);
 
2059
          }
 
2060
          int rv = dlg->exec();
 
2061
          delete dlg;
 
2062
          if(rv != QDialog::Accepted)
 
2063
            return;
 
2064
          // Has a project been created yet?
 
2065
          if(MusEGlobal::museProject == MusEGlobal::museProjectInitPath) // && MusEGlobal::config.useProjectSaveDialog
 
2066
          { 
 
2067
            // No project, we need to create one.
 
2068
            if(!MusEGlobal::muse->saveAs())
 
2069
              return; // No project, don't want to copy without one.
 
2070
            //setFocus(); // For some reason focus is given away to Arranger
 
2071
          }
 
2072
          for(MusECore::iWaveSelection i = selection.begin(); i != selection.end(); i++)
 
2073
          {
 
2074
            MusECore::WaveEventSelection w = *i;
 
2075
            MusECore::SndFileR file = w.event.sndFile();
 
2076
            if(!file.checkCopyOnWrite()) // Make sure to re-check
 
2077
              continue;
 
2078
            QString filePath = MusEGlobal::museProject + QString("/") + file.name();
 
2079
            QString newFilePath;
 
2080
            if(MusECore::getUniqueFileName(filePath, newFilePath))
 
2081
            {
 
2082
              {
 
2083
                QFile qf(file.canonicalPath());
 
2084
                if(!qf.copy(newFilePath)) // Copy the file
 
2085
                {
 
2086
                  printf("MusE Error: Could not copy to new sound file (file exists?): %s\n", newFilePath.toLatin1().constData());
 
2087
                  continue;  // Let's not overwrite an existing file
 
2088
                }
 
2089
              }  
 
2090
              QFile nqf(newFilePath);
 
2091
              // Need to make sure some permissions are set...
 
2092
              QFile::Permissions pm = nqf.permissions();
 
2093
              if(!(pm & QFile::ReadOwner))
 
2094
              {
 
2095
                pm |= QFile::ReadOwner;
 
2096
                if(!nqf.setPermissions(pm))
 
2097
                {
 
2098
                  printf("MusE Error: Could not set read owner permissions on new sound file: %s\n", newFilePath.toLatin1().constData());
 
2099
                  continue; 
 
2100
                }
 
2101
              }
 
2102
              if(!(pm & QFile::WriteOwner))
 
2103
              {
 
2104
                pm |= QFile::WriteOwner;
 
2105
                if(!nqf.setPermissions(pm))
 
2106
                {
 
2107
                  printf("MusE Error: Could not set write owner permissions on new sound file: %s\n", newFilePath.toLatin1().constData());
 
2108
                  continue; 
 
2109
                }
 
2110
              }
 
2111
              if(!(pm & QFile::ReadUser))
 
2112
              {
 
2113
                pm |= QFile::ReadUser;
 
2114
                if(!nqf.setPermissions(pm))
 
2115
                {
 
2116
                  printf("MusE Error: Could not set read user permissions on new sound file: %s\n", newFilePath.toLatin1().constData());
 
2117
                  continue; 
 
2118
                }
 
2119
              }
 
2120
              if(!(pm & QFile::WriteUser))
 
2121
              {
 
2122
                pm |= QFile::WriteUser;
 
2123
                if(!nqf.setPermissions(pm))
 
2124
                {
 
2125
                  printf("MusE Error: Could not set write user permissions on new sound file: %s\n", newFilePath.toLatin1().constData());
 
2126
                  continue; 
 
2127
                }
 
2128
              }
 
2129
              MusECore::SndFile* newSF = new MusECore::SndFile(newFilePath);
 
2130
              MusECore::SndFileR newSFR(newSF);  // Create a sndFileR for the new file
 
2131
              if(newSFR.openRead())  
 
2132
              {
 
2133
                printf("MusE Error: Could not open new sound file: %s\n", newSFR.canonicalPath().toLatin1().constData());
 
2134
                continue; // newSF will be deleted when newSFR goes out of scope and is deleted
 
2135
              }
 
2136
              MusEGlobal::audio->msgIdle(true); 
 
2137
              w.event.sndFile().close();             // Close the old file.
 
2138
              // NOTE: For now, don't bother providing undo for this. Reason: If the user undoes
 
2139
              //  and then modifies again, it will prompt to create new copies each time. There is
 
2140
              //  no mechanism ("touched"?) to tell if an existing copy would be suitable to just 'drop in'.
 
2141
              // It would help if we deleted the wave file copies upon undo, but not too crazy about that. 
 
2142
              // So since the copy has already been created and "there it is", we might as well use it.
 
2143
              // It means that events and even undo items BEFORE this operation will point to this 
 
2144
              //  NEW wave file (as if they always did). It also means the user CANNOT change back 
 
2145
              //  to the old file...    Oh well, this IS Copy On Write.
 
2146
              // FIXME: Find a conceptual way to make undo work with or without deleting the copies. 
 
2147
              w.event.setSndFile(newSFR);            // Set the new file.
 
2148
              MusEGlobal::audio->msgIdle(false); 
 
2149
            }
 
2150
          }
 
2151
        }
 
2152
         
 
2153
         MusEGlobal::song->startUndo();
 
2154
         for (MusECore::iWaveSelection i = selection.begin(); i != selection.end(); i++) {
 
2155
               MusECore::WaveEventSelection w = *i;
 
2156
               MusECore::SndFileR file         = w.event.sndFile();
 
2157
               unsigned sx            = w.startframe;
 
2158
               unsigned ex            = w.endframe;
 
2159
               unsigned file_channels = file.channels();
 
2160
 
 
2161
               QString tmpWavFile = QString::null;
 
2162
               if (!MusEGlobal::getUniqueTmpfileName("tmp_musewav",".wav", tmpWavFile)) {
 
2163
                     break;
 
2164
                     }
 
2165
 
 
2166
               MusEGlobal::audio->msgIdle(true); // Not good with playback during operations
 
2167
               MusECore::SndFile tmpFile(tmpWavFile);
 
2168
               tmpFile.setFormat(file.format(), file_channels, file.samplerate());
 
2169
               if (tmpFile.openWrite()) {
 
2170
                     MusEGlobal::audio->msgIdle(false);
 
2171
                     printf("Could not open temporary file...\n");
 
2172
                     break;
 
2173
                     }
 
2174
 
 
2175
               //
 
2176
               // Write out data that will be changed to temp file
 
2177
               //
 
2178
               unsigned tmpdatalen = ex - sx;
 
2179
               off_t    tmpdataoffset = sx;
 
2180
               float*   tmpdata[file_channels];
 
2181
 
 
2182
               for (unsigned i=0; i<file_channels; i++) {
 
2183
                     tmpdata[i] = new float[tmpdatalen];
 
2184
                     }
 
2185
               file.seek(tmpdataoffset, 0);
 
2186
               file.readWithHeap(file_channels, tmpdata, tmpdatalen);
 
2187
               file.close();
 
2188
               tmpFile.write(file_channels, tmpdata, tmpdatalen);
 
2189
               tmpFile.close();
 
2190
 
 
2191
               switch(operation)
 
2192
               {
 
2193
                     case MUTE:
 
2194
                           muteSelection(file_channels, tmpdata, tmpdatalen);
 
2195
                           break;
 
2196
 
 
2197
                     case NORMALIZE:
 
2198
                           normalizeSelection(file_channels, tmpdata, tmpdatalen);
 
2199
                           break;
 
2200
 
 
2201
                     case FADE_IN:
 
2202
                           fadeInSelection(file_channels, tmpdata, tmpdatalen);
 
2203
                           break;
 
2204
 
 
2205
                     case FADE_OUT:
 
2206
                           fadeOutSelection(file_channels, tmpdata, tmpdatalen);
 
2207
                           break;
 
2208
 
 
2209
                     case REVERSE:
 
2210
                           reverseSelection(file_channels, tmpdata, tmpdatalen);
 
2211
                           break;
 
2212
 
 
2213
                     case GAIN:
 
2214
                           applyGain(file_channels, tmpdata, tmpdatalen, paramA);
 
2215
                           break;
 
2216
                     case CUT:
 
2217
                           copySelection(file_channels, tmpdata, tmpdatalen, true, file.format(), file.samplerate());
 
2218
                           break;
 
2219
                     case COPY:
 
2220
                           copySelection(file_channels, tmpdata, tmpdatalen, false, file.format(), file.samplerate());
 
2221
                           break;
 
2222
                     case PASTE:
 
2223
                           {
 
2224
                           MusECore::SndFile pasteFile(copiedPart);
 
2225
                           pasteFile.openRead();
 
2226
                           pasteFile.seek(tmpdataoffset, 0);
 
2227
                           pasteFile.readWithHeap(file_channels, tmpdata, tmpdatalen);
 
2228
                           }
 
2229
                           break;
 
2230
 
 
2231
                     case EDIT_EXTERNAL:
 
2232
                           editExternal(file.format(), file.samplerate(), file_channels, tmpdata, tmpdatalen);
 
2233
                           break;
 
2234
 
 
2235
                     default:
 
2236
                           printf("Error: Default state reached in modifySelection\n");
 
2237
                           break;
 
2238
 
 
2239
               }
 
2240
 
 
2241
               file.openWrite();
 
2242
               file.seek(tmpdataoffset, 0);
 
2243
               file.write(file_channels, tmpdata, tmpdatalen);
 
2244
               file.update();
 
2245
               file.close();
 
2246
               file.openRead();
 
2247
 
 
2248
               for (unsigned i=0; i<file_channels; i++) {
 
2249
                     delete[] tmpdata[i];
 
2250
                     }
 
2251
 
 
2252
               // Undo handling
 
2253
               MusEGlobal::song->cmdChangeWave(file.dirPath() + "/" + file.name(), tmpWavFile, sx, ex);
 
2254
               MusEGlobal::audio->msgIdle(false); // Not good with playback during operations
 
2255
               }
 
2256
         MusEGlobal::song->endUndo(SC_CLIP_MODIFIED);
 
2257
         redraw();
 
2258
      }
 
2259
 
 
2260
//---------------------------------------------------------
 
2261
//   copySelection
 
2262
//---------------------------------------------------------
 
2263
void WaveCanvas::copySelection(unsigned file_channels, float** tmpdata, unsigned length, bool blankData, unsigned format, unsigned sampleRate)
 
2264
{
 
2265
      if (copiedPart!="") {
 
2266
        QFile::remove(copiedPart);
 
2267
      }
 
2268
      if (!MusEGlobal::getUniqueTmpfileName("tmp_musewav",".wav", copiedPart)) {
 
2269
            return;
 
2270
            }
 
2271
 
 
2272
      MusECore::SndFile tmpFile(copiedPart);
 
2273
      tmpFile.setFormat(format, file_channels, sampleRate);
 
2274
      tmpFile.openWrite();
 
2275
      tmpFile.write(file_channels, tmpdata, length);
 
2276
      tmpFile.close();
 
2277
 
 
2278
      if (blankData) {
 
2279
        // Set everything to 0!
 
2280
        for (unsigned i=0; i<file_channels; i++) {
 
2281
              for (unsigned j=0; j<length; j++) {
 
2282
                    tmpdata[i][j] = 0;
 
2283
                    }
 
2284
              }
 
2285
        }
 
2286
}
 
2287
 
 
2288
//---------------------------------------------------------
 
2289
//   muteSelection
 
2290
//---------------------------------------------------------
 
2291
void WaveCanvas::muteSelection(unsigned channels, float** data, unsigned length)
 
2292
      {
 
2293
      // Set everything to 0!
 
2294
      for (unsigned i=0; i<channels; i++) {
 
2295
            for (unsigned j=0; j<length; j++) {
 
2296
                  data[i][j] = 0;
 
2297
                  }
 
2298
            }
 
2299
      }
 
2300
 
 
2301
//---------------------------------------------------------
 
2302
//   normalizeSelection
 
2303
//---------------------------------------------------------
 
2304
void WaveCanvas::normalizeSelection(unsigned channels, float** data, unsigned length)
 
2305
      {
 
2306
      float loudest = 0.0;
 
2307
 
 
2308
      for (unsigned i=0; i<channels; i++) {
 
2309
            for (unsigned j=0; j<length; j++) {
 
2310
                  if (data[i][j]  > loudest)
 
2311
                        loudest = data[i][j];
 
2312
                  }
 
2313
            }
 
2314
 
 
2315
      double scale = 0.99 / (double)loudest;
 
2316
 
 
2317
      for (unsigned i=0; i<channels; i++) {
 
2318
            for (unsigned j=0; j<length; j++) {
 
2319
                  data[i][j] = (float) ((double)data[i][j] * scale);
 
2320
                  }
 
2321
            }
 
2322
      }
 
2323
 
 
2324
//---------------------------------------------------------
 
2325
//   fadeInSelection
 
2326
//---------------------------------------------------------
 
2327
void WaveCanvas::fadeInSelection(unsigned channels, float** data, unsigned length)
 
2328
      {
 
2329
      for (unsigned i=0; i<channels; i++) {
 
2330
            for (unsigned j=0; j<length; j++) {
 
2331
                  double scale = (double) j / (double)length ;
 
2332
                  data[i][j] = (float) ((double)data[i][j] * scale);
 
2333
                  }
 
2334
            }
 
2335
      }
 
2336
 
 
2337
//---------------------------------------------------------
 
2338
//   fadeOutSelection
 
2339
//---------------------------------------------------------
 
2340
void WaveCanvas::fadeOutSelection(unsigned channels, float** data, unsigned length)
 
2341
      {
 
2342
      for (unsigned i=0; i<channels; i++) {
 
2343
            for (unsigned j=0; j<length; j++) {
 
2344
                  double scale = (double) (length - j) / (double)length ;
 
2345
                  data[i][j] = (float) ((double)data[i][j] * scale);
 
2346
                  }
 
2347
            }
 
2348
      }
 
2349
 
 
2350
//---------------------------------------------------------
 
2351
//   reverseSelection
 
2352
//---------------------------------------------------------
 
2353
void WaveCanvas::reverseSelection(unsigned channels, float** data, unsigned length)
 
2354
      {
 
2355
      if(length <= 1)    
 
2356
        return;
 
2357
      for (unsigned i=0; i<channels; i++) {
 
2358
            for (unsigned j=0; j<length/2; j++) {
 
2359
                  float tmpl = data[i][j];
 
2360
                  float tmpr = data[i][length - j - 1];
 
2361
                  data[i][j] = tmpr;
 
2362
                  data[i][length - j - 1] = tmpl;
 
2363
                  }
 
2364
            }
 
2365
      }
 
2366
//---------------------------------------------------------
 
2367
//   applyGain
 
2368
//---------------------------------------------------------
 
2369
void WaveCanvas::applyGain(unsigned channels, float** data, unsigned length, double gain)
 
2370
      {
 
2371
      for (unsigned i=0; i<channels; i++) {
 
2372
            for (unsigned j=0; j<length; j++) {
 
2373
                  data[i][j] = (float) ((double)data[i][j] * gain);
 
2374
                  }
 
2375
            }
 
2376
      }
 
2377
 
 
2378
//---------------------------------------------------------
 
2379
//   editExternal
 
2380
//---------------------------------------------------------
 
2381
void WaveCanvas::editExternal(unsigned file_format, unsigned file_samplerate, unsigned file_channels, float** tmpdata, unsigned tmpdatalen)
 
2382
      {
 
2383
      // Create yet another tmp-file
 
2384
      QString exttmpFileName;
 
2385
      if (!MusEGlobal::getUniqueTmpfileName("tmp_musewav",".wav", exttmpFileName)) {
 
2386
            printf("Could not create temp file - aborting...\n");
 
2387
            return;
 
2388
            }
 
2389
 
 
2390
      MusECore::SndFile exttmpFile(exttmpFileName);
 
2391
      exttmpFile.setFormat(file_format, file_channels, file_samplerate);
 
2392
      if (exttmpFile.openWrite()) {
 
2393
            printf("Could not open temporary file...\n");
 
2394
            return;
 
2395
            }
 
2396
      // Write out change-data to this file:
 
2397
      exttmpFile.write(file_channels, tmpdata, tmpdatalen);
 
2398
      exttmpFile.close();
 
2399
 
 
2400
      // Forkaborkabork
 
2401
      int pid = fork();
 
2402
      if (pid == 0) {
 
2403
            if (execlp(MusEGlobal::config.externalWavEditor.toLatin1().constData(), MusEGlobal::config.externalWavEditor.toLatin1().constData(), exttmpFileName.toLatin1().constData(), NULL) == -1) {
 
2404
                  perror("Failed to launch external editor");
 
2405
                  // Get out of here
 
2406
                  
 
2407
                   
 
2408
                  // cannot report error through gui, we are in another fork!
 
2409
                  //@!TODO: Handle unsuccessful attempts
 
2410
                  exit(99);
 
2411
                  }
 
2412
            exit(0);
 
2413
            }
 
2414
      else if (pid == -1) {
 
2415
            perror("fork failed");
 
2416
            }
 
2417
      else {
 
2418
            int status;
 
2419
            waitpid(pid, &status, 0);
 
2420
            //printf ("status=%d\n",status);
 
2421
            if( WEXITSTATUS(status) != 0 ){
 
2422
                   QMessageBox::warning(this, tr("MusE - external editor failed"),
 
2423
                         tr("MusE was unable to launch the external editor\ncheck if the editor setting in:\n"
 
2424
                         "Global Settings->Audio:External Waveditor\nis set to a valid editor."));
 
2425
            }
 
2426
            
 
2427
            if (exttmpFile.openRead()) {
 
2428
                printf("Could not reopen temporary file!\n");
 
2429
                }
 
2430
            else {
 
2431
                // Re-read file again
 
2432
                exttmpFile.seek(0, 0);
 
2433
                size_t sz = exttmpFile.readWithHeap(file_channels, tmpdata, tmpdatalen);
 
2434
                if (sz != tmpdatalen) {
 
2435
                        // File must have been shrunken - not good. Alert user.
 
2436
                        QMessageBox::critical(this, tr("MusE - file size changed"),
 
2437
                            tr("When editing in external editor - you should not change the filesize\nsince it must fit the selected region.\n\nMissing data is muted"));
 
2438
                        for (unsigned i=0; i<file_channels; i++) {
 
2439
                            for (unsigned j=sz; j<tmpdatalen; j++) {
 
2440
                                    tmpdata[i][j] = 0;
 
2441
                                    }
 
2442
                            }
 
2443
                        }
 
2444
                }
 
2445
            QDir dir = exttmpFile.dirPath();
 
2446
            dir.remove(exttmpFileName);
 
2447
            dir.remove(exttmpFile.basename() + ".wca");
 
2448
            }
 
2449
      }
 
2450
 
 
2451
      
 
2452
      
 
2453
//---------------------------------------------------------
 
2454
//   startDrag
 
2455
//---------------------------------------------------------
 
2456
 
 
2457
void WaveCanvas::startDrag(MusEGui::CItem* /* item*/, bool copymode)
 
2458
      {
 
2459
      QMimeData* md = MusECore::selected_events_to_mime(MusECore::partlist_to_set(editor->parts()), 1);
 
2460
      
 
2461
      if (md) {
 
2462
            // "Note that setMimeData() assigns ownership of the QMimeData object to the QDrag object. 
 
2463
            //  The QDrag must be constructed on the heap with a parent QWidget to ensure that Qt can 
 
2464
            //  clean up after the drag and drop operation has been completed. "
 
2465
            QDrag* drag = new QDrag(this);
 
2466
            drag->setMimeData(md);
 
2467
            
 
2468
            if (copymode)
 
2469
                  drag->exec(Qt::CopyAction);
 
2470
            else
 
2471
                  drag->exec(Qt::MoveAction);
 
2472
            }
 
2473
      }
 
2474
 
 
2475
//---------------------------------------------------------
 
2476
//   dragEnterEvent
 
2477
//---------------------------------------------------------
 
2478
 
 
2479
void WaveCanvas::dragEnterEvent(QDragEnterEvent* event)
 
2480
      {
 
2481
      //event->accept(Q3TextDrag::canDecode(event));
 
2482
      event->acceptProposedAction();  // TODO CHECK Tim.
 
2483
      }
 
2484
 
 
2485
//---------------------------------------------------------
 
2486
//   dragMoveEvent
 
2487
//---------------------------------------------------------
 
2488
 
 
2489
void WaveCanvas::dragMoveEvent(QDragMoveEvent*)
 
2490
      {
 
2491
      //printf("drag move %x\n", this); DELETETHIS (whole function?)
 
2492
      //event->acceptProposedAction();  
 
2493
      }
 
2494
 
 
2495
//---------------------------------------------------------
 
2496
//   dragLeaveEvent
 
2497
//---------------------------------------------------------
 
2498
 
 
2499
void WaveCanvas::dragLeaveEvent(QDragLeaveEvent*)
 
2500
      {
 
2501
      //printf("drag leave\n");         DELETETHIS (whole function?)
 
2502
      //event->acceptProposedAction();  
 
2503
      }
 
2504
 
 
2505
//---------------------------------------------------------
 
2506
//   itemPressed
 
2507
//---------------------------------------------------------
 
2508
 
 
2509
void WaveCanvas::itemPressed(const MusEGui::CItem*)
 
2510
      {
 
2511
      }
 
2512
 
 
2513
//---------------------------------------------------------
 
2514
//   itemReleased
 
2515
//---------------------------------------------------------
 
2516
 
 
2517
void WaveCanvas::itemReleased(const MusEGui::CItem*, const QPoint&)
 
2518
      {
 
2519
      }
 
2520
 
 
2521
//---------------------------------------------------------
 
2522
//   itemMoved
 
2523
//---------------------------------------------------------
 
2524
 
 
2525
void WaveCanvas::itemMoved(const MusEGui::CItem*, const QPoint&)
 
2526
      {
 
2527
      }
 
2528
 
 
2529
//---------------------------------------------------------
 
2530
//   curPartChanged
 
2531
//---------------------------------------------------------
 
2532
 
 
2533
void WaveCanvas::curPartChanged()
 
2534
      {
 
2535
      EventCanvas::curPartChanged();
 
2536
      editor->setWindowTitle(getCaption());
 
2537
      }
 
2538
 
 
2539
//---------------------------------------------------------
 
2540
//   modifySelected
 
2541
//---------------------------------------------------------
 
2542
 
 
2543
void WaveCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int val, bool delta_mode)
 
2544
      {
 
2545
      // TODO: New WaveCanvas: Convert this routine to frames and remove unneeded operations. 
 
2546
      QList< QPair<MusECore::EventList*,MusECore::Event> > already_done;
 
2547
      MusEGlobal::audio->msgIdle(true);
 
2548
      MusEGlobal::song->startUndo();
 
2549
      for (MusEGui::iCItem i = items.begin(); i != items.end(); ++i) {
 
2550
            if (!(i->second->isSelected()))
 
2551
                  continue;
 
2552
            WEvent* e   = (WEvent*)(i->second);
 
2553
            MusECore::Event event = e->event();
 
2554
            if (event.type() != MusECore::Note)
 
2555
                  continue;
 
2556
 
 
2557
            MusECore::WavePart* part = (MusECore::WavePart*)(e->part());
 
2558
            
 
2559
            if (already_done.contains(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event)))
 
2560
              continue;
 
2561
            
 
2562
            MusECore::Event newEvent = event.clone();
 
2563
 
 
2564
            switch (type) {
 
2565
                  case MusEGui::NoteInfo::VAL_TIME:
 
2566
                        {
 
2567
                        int newTime = val;
 
2568
                        if(delta_mode)
 
2569
                          newTime += event.tick();
 
2570
                        else
 
2571
                          newTime -= part->tick();
 
2572
                        if (newTime < 0)
 
2573
                           newTime = 0;
 
2574
                        newEvent.setTick(newTime);
 
2575
                        }
 
2576
                        break;
 
2577
                  case MusEGui::NoteInfo::VAL_LEN:
 
2578
                        {
 
2579
                        int len = val;
 
2580
                        if(delta_mode)
 
2581
                          len += event.lenTick();
 
2582
                        if (len < 1)
 
2583
                              len = 1;
 
2584
                        newEvent.setLenTick(len);
 
2585
                        }
 
2586
                        break;
 
2587
                  case MusEGui::NoteInfo::VAL_VELON:
 
2588
                        {
 
2589
                        int velo = val;
 
2590
                        if(delta_mode)
 
2591
                          velo += event.velo();
 
2592
                        if (velo > 127)
 
2593
                              velo = 127;
 
2594
                        else if (velo < 0)
 
2595
                              velo = 0;
 
2596
                        newEvent.setVelo(velo);
 
2597
                        }
 
2598
                        break;
 
2599
                  case MusEGui::NoteInfo::VAL_VELOFF:
 
2600
                        {
 
2601
                        int velo = val;
 
2602
                        if(delta_mode)
 
2603
                          velo += event.veloOff();
 
2604
                        if (velo > 127)
 
2605
                              velo = 127;
 
2606
                        else if (velo < 0)
 
2607
                              velo = 0;
 
2608
                        newEvent.setVeloOff(velo);
 
2609
                        }
 
2610
                        break;
 
2611
                  case MusEGui::NoteInfo::VAL_PITCH:
 
2612
                        {
 
2613
                        int pitch = val;
 
2614
                        if(delta_mode)
 
2615
                          pitch += event.pitch();
 
2616
                        if (pitch > 127)
 
2617
                              pitch = 127;
 
2618
                        else if (pitch < 0)
 
2619
                              pitch = 0;
 
2620
                        newEvent.setPitch(pitch);
 
2621
                        }
 
2622
                        break;
 
2623
                  }
 
2624
            
 
2625
            MusEGlobal::song->changeEvent(event, newEvent, part);
 
2626
            // Indicate do not do port controller values and clone parts. 
 
2627
            MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
 
2628
 
 
2629
            already_done.append(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event));
 
2630
            }
 
2631
      MusEGlobal::song->endUndo(SC_EVENT_MODIFIED);
 
2632
      MusEGlobal::audio->msgIdle(false);
 
2633
      }
 
2634
 
 
2635
//---------------------------------------------------------
 
2636
//   resizeEvent
 
2637
//---------------------------------------------------------
 
2638
 
 
2639
void WaveCanvas::resizeEvent(QResizeEvent* ev)
 
2640
      {
 
2641
      // Readjust all wave canvas item heights  
 
2642
      bool do_redraw = false;
 
2643
      for (iCItem k = items.begin(); k != items.end(); ++k) 
 
2644
      {
 
2645
        if(k->second->height() != ev->size().height())
 
2646
        {
 
2647
          k->second->setHeight(ev->size().height());
 
2648
          do_redraw = true;
 
2649
        }
 
2650
      }
 
2651
  
 
2652
      if (ev->size().width() != ev->oldSize().width())
 
2653
            emit newWidth(ev->size().width());
 
2654
      EventCanvas::resizeEvent(ev);
 
2655
  
 
2656
      if(do_redraw)
 
2657
        redraw();
 
2658
      }
 
2659
 
 
2660
} // namespace MusEGui