~ubuntu-branches/ubuntu/wily/muse/wily-proposed

« back to all changes in this revision

Viewing changes to muse/functions.cpp

  • Committer: Package Import Robot
  • Author(s): Alessio Treglia
  • Date: 2011-12-03 17:12:54 UTC
  • mfrom: (1.1.8)
  • Revision ID: package-import@ubuntu.com-20111203171254-28b1j4lpb46r5jtl
Tags: 2.0~rc1-1
* New upstream RC release.
* Refresh patches, remove those patches not needed anymore.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//=========================================================
 
2
//  MusE
 
3
//  Linux Music Editor
 
4
//    $Id: functions.cpp,v 1.20.2.19 2011/05/05 20:10 flo93 Exp $
 
5
//  (C) Copyright 2011 Florian Jung (flo93@sourceforge.net)
 
6
//
 
7
//  This program is free software; you can redistribute it and/or
 
8
//  modify it under the terms of the GNU General Public License
 
9
//  as published by the Free Software Foundation; version 2 of
 
10
//  the License, or (at your option) any later version.
 
11
//
 
12
//  This program is distributed in the hope that it will be useful,
 
13
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
//  GNU General Public License for more details.
 
16
//
 
17
//  You should have received a copy of the GNU General Public License
 
18
//  along with this program; if not, write to the Free Software
 
19
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
20
//
 
21
//=========================================================
 
22
 
 
23
#include "functions.h"
 
24
#include "song.h"
 
25
#include "undo.h"
 
26
#include "helper.h"
 
27
 
 
28
#include "event.h"
 
29
#include "audio.h"
 
30
#include "gconfig.h"
 
31
 
 
32
#include "widgets/function_dialogs/velocity.h"
 
33
#include "widgets/function_dialogs/quantize.h"
 
34
#include "widgets/function_dialogs/crescendo.h"
 
35
#include "widgets/function_dialogs/gatetime.h"
 
36
#include "widgets/function_dialogs/remove.h"
 
37
#include "widgets/function_dialogs/transpose.h"
 
38
#include "widgets/function_dialogs/setlen.h"
 
39
#include "widgets/function_dialogs/move.h"
 
40
#include "widgets/function_dialogs/deloverlaps.h"
 
41
#include "widgets/function_dialogs/legato.h"
 
42
#include "widgets/pasteeventsdialog.h"
 
43
 
 
44
#include <values.h>
 
45
#include <iostream>
 
46
#include <errno.h>
 
47
#include <values.h>
 
48
#include <sys/stat.h>
 
49
#include <sys/types.h>
 
50
#include <sys/mman.h>
 
51
#include <math.h>
 
52
 
 
53
#include <QMimeData>
 
54
#include <QByteArray>
 
55
#include <QDrag>
 
56
#include <QMessageBox>
 
57
#include <QClipboard>
 
58
#include <QSet>
 
59
 
 
60
 
 
61
using namespace std;
 
62
 
 
63
using MusEGlobal::config;
 
64
 
 
65
namespace MusECore {
 
66
 
 
67
// unit private functions:
 
68
 
 
69
bool read_eventlist_and_part(Xml& xml, EventList* el, int* part_id);
 
70
 
 
71
// -----------------------
 
72
 
 
73
 
 
74
 
 
75
set<Part*> partlist_to_set(PartList* pl)
 
76
{
 
77
        set<Part*> result;
 
78
        
 
79
        for (PartList::iterator it=pl->begin(); it!=pl->end(); it++)
 
80
                result.insert(it->second);
 
81
        
 
82
        return result;
 
83
}
 
84
 
 
85
set<Part*> part_to_set(Part* p)
 
86
{
 
87
        set<Part*> result;
 
88
        result.insert(p);
 
89
        return result;
 
90
}
 
91
 
 
92
set<Part*> get_all_parts()
 
93
{
 
94
        set<Part*> result;
 
95
        
 
96
        TrackList* tracks=MusEGlobal::song->tracks();
 
97
        for (TrackList::const_iterator t_it=tracks->begin(); t_it!=tracks->end(); t_it++)
 
98
        {
 
99
                const PartList* parts=(*t_it)->cparts();
 
100
                for (ciPart p_it=parts->begin(); p_it!=parts->end(); p_it++)
 
101
                        result.insert(p_it->second);
 
102
        }
 
103
        
 
104
        return result;
 
105
}
 
106
 
 
107
set<Part*> get_all_selected_parts()
 
108
{
 
109
        set<Part*> result;
 
110
        
 
111
        TrackList* tracks=MusEGlobal::song->tracks();
 
112
        for (TrackList::const_iterator t_it=tracks->begin(); t_it!=tracks->end(); t_it++)
 
113
        {
 
114
                const PartList* parts=(*t_it)->cparts();
 
115
                for (ciPart p_it=parts->begin(); p_it!=parts->end(); p_it++)
 
116
                        if (p_it->second->selected())
 
117
                                result.insert(p_it->second);
 
118
        }
 
119
        
 
120
        return result;
 
121
}
 
122
 
 
123
bool is_relevant(const Event& event, const Part* part, int range)
 
124
{
 
125
        unsigned tick;
 
126
        
 
127
        if (event.type()!=Note) return false;
 
128
        
 
129
        switch (range)
 
130
        {
 
131
                case 0: return true;
 
132
                case 1: return event.selected();
 
133
                case 2: tick=event.tick()+part->tick(); return (tick >= MusEGlobal::song->lpos()) && (tick < MusEGlobal::song->rpos());
 
134
                case 3: return is_relevant(event,part,1) && is_relevant(event,part,2);
 
135
                default: cout << "ERROR: ILLEGAL FUNCTION CALL in is_relevant: range is illegal: "<<range<<endl;
 
136
                         return false;
 
137
        }
 
138
}
 
139
 
 
140
 
 
141
map<Event*, Part*> get_events(const set<Part*>& parts, int range)
 
142
{
 
143
        map<Event*, Part*> events;
 
144
        
 
145
        for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
 
146
                for (iEvent event=(*part)->events()->begin(); event!=(*part)->events()->end(); event++)
 
147
                        if (is_relevant(event->second, *part, range))
 
148
                                events.insert(pair<Event*, Part*>(&event->second, *part));
 
149
        
 
150
        return events;
 
151
}
 
152
 
 
153
 
 
154
 
 
155
 
 
156
bool modify_notelen(const set<Part*>& parts)
 
157
{
 
158
        if (!MusEGui::gatetime_dialog->exec())
 
159
                return false;
 
160
                
 
161
        modify_notelen(parts,MusEGui::gatetime_dialog->range,MusEGui::gatetime_dialog->rateVal,MusEGui::gatetime_dialog->offsetVal);
 
162
        
 
163
        return true;
 
164
}
 
165
 
 
166
bool modify_velocity(const set<Part*>& parts)
 
167
{
 
168
        if (!MusEGui::velocity_dialog->exec())
 
169
                return false;
 
170
                
 
171
        modify_velocity(parts,MusEGui::velocity_dialog->range,MusEGui::velocity_dialog->rateVal,MusEGui::velocity_dialog->offsetVal);
 
172
        
 
173
        return true;
 
174
}
 
175
 
 
176
bool quantize_notes(const set<Part*>& parts)
 
177
{
 
178
        if (!MusEGui::quantize_dialog->exec())
 
179
                return false;
 
180
//  (1<<MusEGui::quantize_dialog->raster_power2)
 
181
  int raster = MusEGui::rasterVals[MusEGui::quantize_dialog->raster_index];
 
182
  quantize_notes(parts, MusEGui::quantize_dialog->range, (MusEGlobal::config.division*4)/raster,
 
183
                       MusEGui::quantize_dialog->quant_len, MusEGui::quantize_dialog->strength, MusEGui::quantize_dialog->swing,
 
184
                       MusEGui::quantize_dialog->threshold);
 
185
        
 
186
        return true;
 
187
}
 
188
 
 
189
bool erase_notes(const set<Part*>& parts)
 
190
{
 
191
        if (!MusEGui::erase_dialog->exec())
 
192
                return false;
 
193
                
 
194
        erase_notes(parts,MusEGui::erase_dialog->range, MusEGui::erase_dialog->velo_threshold, MusEGui::erase_dialog->velo_thres_used, 
 
195
                                               MusEGui::erase_dialog->len_threshold, MusEGui::erase_dialog->len_thres_used );
 
196
        
 
197
        return true;
 
198
}
 
199
 
 
200
bool delete_overlaps(const set<Part*>& parts)
 
201
{
 
202
        if (!MusEGui::del_overlaps_dialog->exec())
 
203
                return false;
 
204
                
 
205
        delete_overlaps(parts,MusEGui::erase_dialog->range);
 
206
        
 
207
        return true;
 
208
}
 
209
 
 
210
bool set_notelen(const set<Part*>& parts)
 
211
{
 
212
        if (!MusEGui::set_notelen_dialog->exec())
 
213
                return false;
 
214
                
 
215
        set_notelen(parts,MusEGui::set_notelen_dialog->range,MusEGui::set_notelen_dialog->len);
 
216
        
 
217
        return true;
 
218
}
 
219
 
 
220
bool move_notes(const set<Part*>& parts)
 
221
{
 
222
        if (!MusEGui::move_notes_dialog->exec())
 
223
                return false;
 
224
                
 
225
        move_notes(parts,MusEGui::move_notes_dialog->range,MusEGui::move_notes_dialog->amount);
 
226
        
 
227
        return true;
 
228
}
 
229
 
 
230
bool transpose_notes(const set<Part*>& parts)
 
231
{
 
232
        if (!MusEGui::transpose_dialog->exec())
 
233
                return false;
 
234
                
 
235
        transpose_notes(parts,MusEGui::transpose_dialog->range,MusEGui::transpose_dialog->amount);
 
236
        
 
237
        return true;
 
238
}
 
239
 
 
240
bool crescendo(const set<Part*>& parts)
 
241
{
 
242
        if (MusEGlobal::song->rpos() <= MusEGlobal::song->lpos())
 
243
        {
 
244
                QMessageBox::warning(NULL, QObject::tr("Error"), QObject::tr("Please first select the range for crescendo with the loop markers."));
 
245
                return false;
 
246
        }
 
247
        
 
248
        if (!MusEGui::crescendo_dialog->exec())
 
249
                return false;
 
250
                
 
251
        crescendo(parts,MusEGui::crescendo_dialog->range,MusEGui::crescendo_dialog->start_val,MusEGui::crescendo_dialog->end_val,MusEGui::crescendo_dialog->absolute);
 
252
        
 
253
        return true;
 
254
}
 
255
 
 
256
bool legato(const set<Part*>& parts)
 
257
{
 
258
        if (!MusEGui::legato_dialog->exec())
 
259
                return false;
 
260
                
 
261
        legato(parts,MusEGui::legato_dialog->range, MusEGui::legato_dialog->min_len, !MusEGui::legato_dialog->allow_shortening);
 
262
        
 
263
        return true;
 
264
}
 
265
 
 
266
 
 
267
 
 
268
bool modify_notelen()
 
269
{
 
270
        if (!MusEGui::gatetime_dialog->exec())
 
271
                return false;
 
272
                
 
273
        set<Part*> parts;
 
274
        if (MusEGui::gatetime_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)
 
275
                parts=get_all_selected_parts();
 
276
        else
 
277
                parts=get_all_parts();
 
278
                
 
279
        modify_notelen(parts,MusEGui::gatetime_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS, MusEGui::gatetime_dialog->rateVal,MusEGui::gatetime_dialog->offsetVal);
 
280
        
 
281
        return true;
 
282
}
 
283
 
 
284
bool modify_velocity()
 
285
{
 
286
        if (!MusEGui::velocity_dialog->exec())
 
287
                return false;
 
288
                
 
289
        set<Part*> parts;
 
290
        if (MusEGui::velocity_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)
 
291
                parts=get_all_selected_parts();
 
292
        else
 
293
                parts=get_all_parts();
 
294
                
 
295
        modify_velocity(parts,MusEGui::velocity_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS,MusEGui::velocity_dialog->rateVal,MusEGui::velocity_dialog->offsetVal);
 
296
        
 
297
        return true;
 
298
}
 
299
 
 
300
bool quantize_notes()
 
301
{
 
302
        if (!MusEGui::quantize_dialog->exec())
 
303
                return false;
 
304
                
 
305
        set<Part*> parts;
 
306
        if (MusEGui::quantize_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)
 
307
                parts=get_all_selected_parts();
 
308
        else
 
309
                parts=get_all_parts();
 
310
 
 
311
  int raster = MusEGui::rasterVals[MusEGui::quantize_dialog->raster_index];
 
312
  quantize_notes(parts, MusEGui::quantize_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS, (config.division*4)/raster,
 
313
                       MusEGui::quantize_dialog->quant_len, MusEGui::quantize_dialog->strength, MusEGui::quantize_dialog->swing,
 
314
                       MusEGui::quantize_dialog->threshold);
 
315
        
 
316
        return true;
 
317
}
 
318
 
 
319
bool erase_notes()
 
320
{
 
321
        if (!MusEGui::erase_dialog->exec())
 
322
                return false;
 
323
                
 
324
        set<Part*> parts;
 
325
        if (MusEGui::erase_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)
 
326
                parts=get_all_selected_parts();
 
327
        else
 
328
                parts=get_all_parts();
 
329
                
 
330
        erase_notes(parts,MusEGui::erase_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS, MusEGui::erase_dialog->velo_threshold, MusEGui::erase_dialog->velo_thres_used, 
 
331
                    MusEGui::erase_dialog->len_threshold, MusEGui::erase_dialog->len_thres_used );
 
332
        
 
333
        return true;
 
334
}
 
335
 
 
336
bool delete_overlaps()
 
337
{
 
338
        if (!MusEGui::del_overlaps_dialog->exec())
 
339
                return false;
 
340
                
 
341
        set<Part*> parts;
 
342
        if (MusEGui::del_overlaps_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)
 
343
                parts=get_all_selected_parts();
 
344
        else
 
345
                parts=get_all_parts();
 
346
                
 
347
        delete_overlaps(parts,MusEGui::erase_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS);
 
348
        
 
349
        return true;
 
350
}
 
351
 
 
352
bool set_notelen()
 
353
{
 
354
        if (!MusEGui::set_notelen_dialog->exec())
 
355
                return false;
 
356
                
 
357
        set<Part*> parts;
 
358
        if (MusEGui::set_notelen_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)
 
359
                parts=get_all_selected_parts();
 
360
        else
 
361
                parts=get_all_parts();
 
362
                
 
363
        set_notelen(parts,MusEGui::set_notelen_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS, MusEGui::set_notelen_dialog->len);
 
364
        
 
365
        return true;
 
366
}
 
367
 
 
368
bool move_notes()
 
369
{
 
370
        if (!MusEGui::move_notes_dialog->exec())
 
371
                return false;
 
372
                
 
373
        set<Part*> parts;
 
374
        if (MusEGui::move_notes_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)
 
375
                parts=get_all_selected_parts();
 
376
        else
 
377
                parts=get_all_parts();
 
378
                
 
379
        move_notes(parts,MusEGui::move_notes_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS, MusEGui::move_notes_dialog->amount);
 
380
        
 
381
        return true;
 
382
}
 
383
 
 
384
bool transpose_notes()
 
385
{
 
386
        if (!MusEGui::transpose_dialog->exec())
 
387
                return false;
 
388
                
 
389
        set<Part*> parts;
 
390
        if (MusEGui::transpose_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)
 
391
                parts=get_all_selected_parts();
 
392
        else
 
393
                parts=get_all_parts();
 
394
                
 
395
        transpose_notes(parts,MusEGui::transpose_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS, MusEGui::transpose_dialog->amount);
 
396
        
 
397
        return true;
 
398
}
 
399
 
 
400
bool crescendo()
 
401
{
 
402
        if (MusEGlobal::song->rpos() <= MusEGlobal::song->lpos())
 
403
        {
 
404
                QMessageBox::warning(NULL, QObject::tr("Error"), QObject::tr("Please first select the range for crescendo with the loop markers."));
 
405
                return false;
 
406
        }
 
407
        
 
408
        if (!MusEGui::crescendo_dialog->exec())
 
409
                return false;
 
410
                
 
411
        set<Part*> parts;
 
412
        if (MusEGui::crescendo_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)
 
413
                parts=get_all_selected_parts();
 
414
        else
 
415
                parts=get_all_parts();
 
416
                
 
417
        crescendo(parts,MusEGui::crescendo_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS, MusEGui::crescendo_dialog->start_val,MusEGui::crescendo_dialog->end_val,MusEGui::crescendo_dialog->absolute);
 
418
        
 
419
        return true;
 
420
}
 
421
 
 
422
bool legato()
 
423
{
 
424
        if (!MusEGui::legato_dialog->exec())
 
425
                return false;
 
426
                
 
427
        set<Part*> parts;
 
428
        if (MusEGui::legato_dialog->range & FUNCTION_RANGE_ONLY_SELECTED)
 
429
                parts=get_all_selected_parts();
 
430
        else
 
431
                parts=get_all_parts();
 
432
                
 
433
        legato(parts,MusEGui::legato_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS, MusEGui::legato_dialog->min_len, !MusEGui::legato_dialog->allow_shortening);
 
434
        
 
435
        return true;
 
436
}
 
437
 
 
438
 
 
439
 
 
440
 
 
441
 
 
442
 
 
443
bool modify_velocity(const set<Part*>& parts, int range, int rate, int offset)
 
444
{
 
445
        map<Event*, Part*> events = get_events(parts, range);
 
446
        Undo operations;
 
447
        
 
448
        if ( (!events.empty()) && ((rate!=100) || (offset!=0)) )
 
449
        {
 
450
                for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++)
 
451
                {
 
452
                        Event& event=*(it->first);
 
453
                        Part* part=it->second;
 
454
                        
 
455
                        int velo = event.velo();
 
456
 
 
457
                        velo = (velo * rate) / 100;
 
458
                        velo += offset;
 
459
 
 
460
                        if (velo <= 0)
 
461
                                velo = 1;
 
462
                        else if (velo > 127)
 
463
                                velo = 127;
 
464
                                
 
465
                        if (event.velo() != velo)
 
466
                        {
 
467
                                Event newEvent = event.clone();
 
468
                                newEvent.setVelo(velo);
 
469
                                operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
 
470
                        }
 
471
                }
 
472
                
 
473
                return MusEGlobal::song->applyOperationGroup(operations);
 
474
        }
 
475
        else
 
476
                return false;
 
477
}
 
478
 
 
479
bool modify_off_velocity(const set<Part*>& parts, int range, int rate, int offset)
 
480
{
 
481
        map<Event*, Part*> events = get_events(parts, range);
 
482
        Undo operations;
 
483
        
 
484
        if ( (!events.empty()) && ((rate!=100) || (offset!=0)) )
 
485
        {
 
486
                for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++)
 
487
                {
 
488
                        Event& event=*(it->first);
 
489
                        Part* part=it->second;
 
490
                        
 
491
                        int velo = event.veloOff();
 
492
 
 
493
                        velo = (velo * rate) / 100;
 
494
                        velo += offset;
 
495
 
 
496
                        if (velo <= 0)
 
497
                                velo = 1;
 
498
                        else if (velo > 127)
 
499
                                velo = 127;
 
500
                                
 
501
                        if (event.veloOff() != velo)
 
502
                        {
 
503
                                Event newEvent = event.clone();
 
504
                                newEvent.setVeloOff(velo);
 
505
                                operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
 
506
                        }
 
507
                }
 
508
 
 
509
                return MusEGlobal::song->applyOperationGroup(operations);
 
510
        }
 
511
        else
 
512
                return false;
 
513
}
 
514
 
 
515
bool modify_notelen(const set<Part*>& parts, int range, int rate, int offset)
 
516
{
 
517
        map<Event*, Part*> events = get_events(parts, range);
 
518
        Undo operations;
 
519
        map<Part*, int> partlen;
 
520
        
 
521
        if ( (!events.empty()) && ((rate!=100) || (offset!=0)) )
 
522
        {
 
523
                for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++)
 
524
                {
 
525
                        Event& event=*(it->first);
 
526
                        Part* part=it->second;
 
527
 
 
528
                        unsigned int len = event.lenTick(); //prevent compiler warning: comparison singed/unsigned
 
529
 
 
530
                        len = (len * rate) / 100;
 
531
                        len += offset;
 
532
 
 
533
                        if (len <= 0)
 
534
                                len = 1;
 
535
                        
 
536
                        if ((event.tick()+len > part->lenTick()) && (!part->hasHiddenEvents()))
 
537
                                partlen[part]=event.tick()+len; // schedule auto-expanding
 
538
                                
 
539
                        if (event.lenTick() != len)
 
540
                        {
 
541
                                Event newEvent = event.clone();
 
542
                                newEvent.setLenTick(len);
 
543
                                operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
 
544
                        }
 
545
                }
 
546
                
 
547
                for (map<Part*, int>::iterator it=partlen.begin(); it!=partlen.end(); it++)
 
548
                        schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);
 
549
 
 
550
                return MusEGlobal::song->applyOperationGroup(operations);
 
551
        }
 
552
        else
 
553
                return false;
 
554
}
 
555
 
 
556
bool set_notelen(const set<Part*>& parts, int range, int len)
 
557
{
 
558
        return modify_notelen(parts, range, 0, len);
 
559
}
 
560
 
 
561
unsigned quantize_tick(unsigned tick, unsigned raster, int swing)
 
562
{
 
563
        //find out the nearest tick and the distance to it:
 
564
        //this is so complicated because this function supports
 
565
        //swing: if swing is 50, the resulting rhythm is not
 
566
        //"daa daa daa daa" but "daaaa da daaaa da"...
 
567
        int tick_dest1 = AL::sigmap.raster1(tick, raster*2); //round down
 
568
        int tick_dest2 = tick_dest1 + raster + raster*swing/100;
 
569
        int tick_dest3 = tick_dest1 + raster*2;
 
570
 
 
571
        int tick_diff1 = tick_dest1 - tick;
 
572
        int tick_diff2 = tick_dest2 - tick;
 
573
        int tick_diff3 = tick_dest3 - tick;
 
574
        
 
575
        if ((abs(tick_diff1) <= abs(tick_diff2)) && (abs(tick_diff1) <= abs(tick_diff3))) //tick_dest1 is the nearest tick
 
576
                return tick_dest1;
 
577
        else if ((abs(tick_diff2) <= abs(tick_diff1)) && (abs(tick_diff2) <= abs(tick_diff3))) //tick_dest2 is the nearest tick
 
578
                return tick_dest2;
 
579
        else
 
580
                return tick_dest3;
 
581
}
 
582
 
 
583
bool quantize_notes(const set<Part*>& parts, int range, int raster, bool quant_len, int strength, int swing, int threshold)
 
584
{
 
585
        map<Event*, Part*> events = get_events(parts, range);
 
586
        Undo operations;
 
587
        
 
588
        if (!events.empty())
 
589
        {
 
590
                for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++)
 
591
                {
 
592
                        Event& event=*(it->first);
 
593
                        Part* part=it->second;
 
594
 
 
595
                        unsigned begin_tick = event.tick() + part->tick();
 
596
                        int begin_diff = quantize_tick(begin_tick, raster, swing) - begin_tick;
 
597
 
 
598
                        if (abs(begin_diff) > threshold)
 
599
                                begin_tick = begin_tick + begin_diff*strength/100;
 
600
 
 
601
 
 
602
                        unsigned len=event.lenTick();
 
603
                        
 
604
                        unsigned end_tick = begin_tick + len;
 
605
                        int len_diff = quantize_tick(end_tick, raster, swing) - end_tick;
 
606
                                
 
607
                        if ((abs(len_diff) > threshold) && quant_len)
 
608
                                len = len + len_diff*strength/100;
 
609
 
 
610
                        if (len <= 0)
 
611
                                len = 1;
 
612
 
 
613
                                
 
614
                        if ( (event.lenTick() != len) || (event.tick() + part->tick() != begin_tick) )
 
615
                        {
 
616
                                Event newEvent = event.clone();
 
617
                                newEvent.setTick(begin_tick - part->tick());
 
618
                                newEvent.setLenTick(len);
 
619
                                operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
 
620
                        }
 
621
                }
 
622
                
 
623
                return MusEGlobal::song->applyOperationGroup(operations);
 
624
        }
 
625
        else
 
626
                return false;
 
627
}
 
628
 
 
629
bool erase_notes(const set<Part*>& parts, int range, int velo_threshold, bool velo_thres_used, int len_threshold, bool len_thres_used)
 
630
{
 
631
        map<Event*, Part*> events = get_events(parts, range);
 
632
        Undo operations;
 
633
        
 
634
        if (!events.empty())
 
635
        {
 
636
                for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++)
 
637
                {
 
638
                        Event& event=*(it->first);
 
639
                        Part* part=it->second;
 
640
 
 
641
                        if ( (!velo_thres_used && !len_thres_used) ||
 
642
                             (velo_thres_used && event.velo() < velo_threshold) ||
 
643
                             (len_thres_used && int(event.lenTick()) < len_threshold) )
 
644
                                operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, false, false));
 
645
                }
 
646
                
 
647
                return MusEGlobal::song->applyOperationGroup(operations);
 
648
        }
 
649
        else
 
650
                return false;
 
651
}
 
652
 
 
653
bool transpose_notes(const set<Part*>& parts, int range, signed int halftonesteps)
 
654
{
 
655
        map<Event*, Part*> events = get_events(parts, range);
 
656
        Undo operations;
 
657
        
 
658
        if ( (!events.empty()) && (halftonesteps!=0) )
 
659
        {
 
660
                for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++)
 
661
                {
 
662
                        Event& event=*(it->first);
 
663
                        Part* part=it->second;
 
664
 
 
665
                        Event newEvent = event.clone();
 
666
                        int pitch = event.pitch()+halftonesteps;
 
667
                        if (pitch > 127) pitch=127;
 
668
                        if (pitch < 0) pitch=0;
 
669
                        newEvent.setPitch(pitch);
 
670
                        operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
 
671
                }
 
672
                
 
673
                return MusEGlobal::song->applyOperationGroup(operations);
 
674
        }
 
675
        else
 
676
                return false;
 
677
}
 
678
 
 
679
bool crescendo(const set<Part*>& parts, int range, int start_val, int end_val, bool absolute)
 
680
{
 
681
        map<Event*, Part*> events = get_events(parts, range);
 
682
        Undo operations;
 
683
        
 
684
        int from=MusEGlobal::song->lpos();
 
685
        int to=MusEGlobal::song->rpos();
 
686
        
 
687
        if ( (!events.empty()) && (to>from) )
 
688
        {
 
689
                for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++)
 
690
                {
 
691
                        Event& event=*(it->first);
 
692
                        Part* part=it->second;
 
693
                        
 
694
                        unsigned tick = event.tick() + part->tick();
 
695
                        float curr_val= (float)start_val  +  (float)(end_val-start_val) * (tick-from) / (to-from);
 
696
                        
 
697
                        Event newEvent = event.clone();
 
698
                        int velo = event.velo();
 
699
 
 
700
                        if (absolute)
 
701
                                velo=curr_val;
 
702
                        else
 
703
                                velo=curr_val*velo/100;
 
704
 
 
705
                        if (velo > 127) velo=127;
 
706
                        if (velo <= 0) velo=1;
 
707
                        newEvent.setVelo(velo);
 
708
                        operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
 
709
                }
 
710
                
 
711
                return MusEGlobal::song->applyOperationGroup(operations);
 
712
        }
 
713
        else
 
714
                return false;
 
715
}
 
716
 
 
717
bool move_notes(const set<Part*>& parts, int range, signed int ticks)
 
718
{
 
719
        map<Event*, Part*> events = get_events(parts, range);
 
720
        Undo operations;
 
721
        map<Part*, int> partlen;
 
722
        
 
723
        if ( (!events.empty()) && (ticks!=0) )
 
724
        {
 
725
                for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++)
 
726
                {
 
727
                        Event& event=*(it->first);
 
728
                        Part* part=it->second;
 
729
                        bool del=false;
 
730
 
 
731
                        Event newEvent = event.clone();
 
732
                        if ((signed)event.tick()+ticks < 0) //don't allow moving before the part's begin
 
733
                                newEvent.setTick(0);
 
734
                        else
 
735
                                newEvent.setTick(event.tick()+ticks);
 
736
                        
 
737
                        if (newEvent.endTick() > part->lenTick()) //if exceeding the part's end:
 
738
                        {
 
739
                                if (part->hasHiddenEvents()) // auto-expanding is forbidden, clip
 
740
                                {
 
741
                                        if (part->lenTick() > newEvent.tick())
 
742
                                                newEvent.setLenTick(part->lenTick() - newEvent.tick());
 
743
                                        else
 
744
                                                del=true; //if the new length would be <= 0, erase the note
 
745
                                }
 
746
                                else
 
747
                                        partlen[part]=newEvent.endTick(); // schedule auto-expanding
 
748
                        }
 
749
                        
 
750
                        if (del==false)
 
751
                                operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
 
752
                        else
 
753
                                operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, false, false));
 
754
                }
 
755
                
 
756
                for (map<Part*, int>::iterator it=partlen.begin(); it!=partlen.end(); it++)
 
757
                        schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);
 
758
                
 
759
                return MusEGlobal::song->applyOperationGroup(operations);
 
760
        }
 
761
        else
 
762
                return false;
 
763
}
 
764
 
 
765
 
 
766
bool delete_overlaps(const set<Part*>& parts, int range)
 
767
{
 
768
        map<Event*, Part*> events = get_events(parts, range);
 
769
        Undo operations;
 
770
        
 
771
        set<Event*> deleted_events;
 
772
        
 
773
        if (!events.empty())
 
774
        {
 
775
                for (map<Event*, Part*>::iterator it1=events.begin(); it1!=events.end(); it1++)
 
776
                {
 
777
                        Event& event1=*(it1->first);
 
778
                        Part* part1=it1->second;
 
779
                        
 
780
                        // we may NOT optimize by letting it2 start at (it1 +1); this optimisation
 
781
                        // is only allowed when events was sorted by time. it is, however, sorted
 
782
                        // randomly by pointer.
 
783
                        for (map<Event*, Part*>::iterator it2=events.begin(); it2!=events.end(); it2++)
 
784
                        {
 
785
                                Event& event2=*(it2->first);
 
786
                                Part* part2=it2->second;
 
787
                                
 
788
                                if ( (part1->events()==part2->events()) && // part1 and part2 are the same or are duplicates
 
789
                                     (&event1 != &event2) &&               // and event1 and event2 aren't the same
 
790
                                     (deleted_events.find(&event2) == deleted_events.end()) ) //and event2 hasn't been deleted before
 
791
                                {
 
792
                                        if ( (event1.pitch() == event2.pitch()) &&
 
793
                                             (event1.tick() <= event2.tick()) &&
 
794
                                                   (event1.endTick() > event2.tick()) ) //they overlap
 
795
                                        {
 
796
                                                int new_len = event2.tick() - event1.tick();
 
797
 
 
798
                                                if (new_len==0)
 
799
                                                {
 
800
                                                        operations.push_back(UndoOp(UndoOp::DeleteEvent, event1, part1, false, false));
 
801
                                                        deleted_events.insert(&event1);
 
802
                                                }
 
803
                                                else
 
804
                                                {
 
805
                                                        Event new_event1 = event1.clone();
 
806
                                                        new_event1.setLenTick(new_len);
 
807
                                                        
 
808
                                                        operations.push_back(UndoOp(UndoOp::ModifyEvent, new_event1, event1, part1, false, false));
 
809
                                                }
 
810
                                        }
 
811
                                }
 
812
                        }
 
813
                }
 
814
                
 
815
                return MusEGlobal::song->applyOperationGroup(operations);
 
816
        }
 
817
        else
 
818
                return false;
 
819
}
 
820
 
 
821
bool legato(const set<Part*>& parts, int range, int min_len, bool dont_shorten)
 
822
{
 
823
        map<Event*, Part*> events = get_events(parts, range);
 
824
        Undo operations;
 
825
        
 
826
        if (min_len<=0) min_len=1;
 
827
        
 
828
        if (!events.empty())
 
829
        {
 
830
                for (map<Event*, Part*>::iterator it1=events.begin(); it1!=events.end(); it1++)
 
831
                {
 
832
                        Event& event1=*(it1->first);
 
833
                        Part* part1=it1->second;
 
834
                        
 
835
                        unsigned len=MAXINT;
 
836
                        // we may NOT optimize by letting it2 start at (it1 +1); this optimisation
 
837
                        // is only allowed when events was sorted by time. it is, however, sorted
 
838
                        // randomly by pointer.
 
839
                        for (map<Event*, Part*>::iterator it2=events.begin(); it2!=events.end(); it2++)
 
840
                        {
 
841
                                Event& event2=*(it2->first);
 
842
                                Part* part2=it2->second;
 
843
                                
 
844
                                bool relevant = (event2.tick() >= event1.tick() + min_len);
 
845
                                if (dont_shorten)
 
846
                                        relevant = relevant && (event2.tick() >= event1.endTick());
 
847
                                
 
848
                                if ( (part1->events()==part2->events()) &&  // part1 and part2 are the same or are duplicates
 
849
                                      relevant &&                           // they're not too near (respect min_len and dont_shorten)
 
850
                                     (event2.tick()-event1.tick() < len ) ) // that's the nearest relevant following note
 
851
                                        len=event2.tick()-event1.tick();
 
852
                        }
 
853
                        
 
854
                        if (len==MAXINT) len=event1.lenTick(); // if no following note was found, keep the length
 
855
                        
 
856
                        if (event1.lenTick() != len)
 
857
                        {
 
858
                                Event new_event1 = event1.clone();
 
859
                                new_event1.setLenTick(len);
 
860
                                
 
861
                                operations.push_back(UndoOp(UndoOp::ModifyEvent, new_event1, event1, part1, false, false));
 
862
                        }
 
863
                }
 
864
                
 
865
                return MusEGlobal::song->applyOperationGroup(operations);
 
866
        }
 
867
        else
 
868
                return false;
 
869
}
 
870
 
 
871
 
 
872
 
 
873
void copy_notes(const set<Part*>& parts, int range)
 
874
{
 
875
        QMimeData* drag = selected_events_to_mime(parts,range);
 
876
 
 
877
        if (drag)
 
878
                QApplication::clipboard()->setMimeData(drag, QClipboard::Clipboard);
 
879
}
 
880
 
 
881
unsigned get_groupedevents_len(const QString& pt)
 
882
{
 
883
        unsigned maxlen=0;
 
884
        
 
885
        QByteArray pt_= pt.toLatin1();
 
886
        Xml xml(pt_.constData());
 
887
        for (;;) 
 
888
        {
 
889
                Xml::Token token = xml.parse();
 
890
                const QString& tag = xml.s1();
 
891
                switch (token) 
 
892
                {
 
893
                        case Xml::Error:
 
894
                        case Xml::End:
 
895
                                return maxlen;
 
896
                                
 
897
                        case Xml::TagStart:
 
898
                                if (tag == "eventlist")
 
899
                                {
 
900
                                        EventList el;
 
901
                                        int part_id;
 
902
                                        if (read_eventlist_and_part(xml, &el, &part_id))
 
903
                                        {
 
904
                                                unsigned len = el.rbegin()->first;
 
905
                                                if (len > maxlen) maxlen=len;
 
906
                                        }
 
907
                                }
 
908
                                else
 
909
                                        xml.unknown("get_clipboard_len");
 
910
                                break;
 
911
                                
 
912
                        case Xml::Attribut:
 
913
                        case Xml::TagEnd:
 
914
                        default:
 
915
                                break;
 
916
                }
 
917
        }
 
918
        
 
919
        return maxlen; // see also the return statement above!
 
920
}
 
921
 
 
922
unsigned get_clipboard_len()
 
923
{
 
924
        QString tmp="x-muse-groupedeventlists"; // QClipboard::text() expects a QString&, not a QString :(
 
925
        QString s = QApplication::clipboard()->text(tmp, QClipboard::Clipboard);  // TODO CHECK Tim.
 
926
        
 
927
        return get_groupedevents_len(s);
 
928
}
 
929
 
 
930
bool paste_notes(Part* paste_into_part)
 
931
{
 
932
        unsigned temp_begin = AL::sigmap.raster1(MusEGlobal::song->cpos(),0);
 
933
        unsigned temp_end = AL::sigmap.raster2(temp_begin + get_clipboard_len(), 0);
 
934
        MusEGui::paste_events_dialog->raster = temp_end - temp_begin;
 
935
        MusEGui::paste_events_dialog->into_single_part_allowed = (paste_into_part!=NULL);
 
936
        
 
937
        if (!MusEGui::paste_events_dialog->exec())
 
938
                return false;
 
939
                
 
940
        paste_notes(MusEGui::paste_events_dialog->max_distance, MusEGui::paste_events_dialog->always_new_part,
 
941
                    MusEGui::paste_events_dialog->never_new_part, MusEGui::paste_events_dialog->into_single_part ? paste_into_part : NULL,
 
942
                    MusEGui::paste_events_dialog->number, MusEGui::paste_events_dialog->raster);
 
943
        
 
944
        return true;
 
945
}
 
946
 
 
947
void paste_notes(int max_distance, bool always_new_part, bool never_new_part, Part* paste_into_part, int amount, int raster)
 
948
{
 
949
        QString tmp="x-muse-groupedeventlists"; // QClipboard::text() expects a QString&, not a QString :(
 
950
        QString s = QApplication::clipboard()->text(tmp, QClipboard::Clipboard);  // TODO CHECK Tim.
 
951
        paste_at(s, MusEGlobal::song->cpos(), max_distance, always_new_part, never_new_part, paste_into_part, amount, raster);
 
952
}
 
953
 
 
954
 
 
955
// if nothing is selected/relevant, this function returns NULL
 
956
QMimeData* selected_events_to_mime(const set<Part*>& parts, int range)
 
957
{
 
958
        unsigned start_tick = MAXINT; //will be the tick of the first event or MAXINT if no events are there
 
959
        
 
960
        for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
 
961
                for (iEvent ev=(*part)->events()->begin(); ev!=(*part)->events()->end(); ev++)
 
962
                        if (is_relevant(ev->second, *part, range))
 
963
                                if (ev->second.tick() < start_tick)
 
964
                                        start_tick=ev->second.tick();
 
965
        
 
966
        if (start_tick == MAXINT)
 
967
                return NULL;
 
968
        
 
969
        //---------------------------------------------------
 
970
        //    write events as XML into tmp file
 
971
        //---------------------------------------------------
 
972
 
 
973
        FILE* tmp = tmpfile();
 
974
        if (tmp == 0) 
 
975
        {
 
976
                fprintf(stderr, "EventCanvas::getTextDrag() fopen failed: %s\n", strerror(errno));
 
977
                return 0;
 
978
        }
 
979
        
 
980
        Xml xml(tmp);
 
981
        int level = 0;
 
982
        
 
983
        for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
 
984
        {
 
985
                xml.tag(level++, "eventlist part_id=\"%d\"", (*part)->sn());
 
986
                for (iEvent ev=(*part)->events()->begin(); ev!=(*part)->events()->end(); ev++)
 
987
                        if (is_relevant(ev->second, *part, range))
 
988
                                ev->second.write(level, xml, -start_tick);
 
989
                xml.etag(--level, "eventlist");
 
990
        }
 
991
 
 
992
        //---------------------------------------------------
 
993
        //    read tmp file into drag Object
 
994
        //---------------------------------------------------
 
995
 
 
996
        fflush(tmp);
 
997
        struct stat f_stat;
 
998
        if (fstat(fileno(tmp), &f_stat) == -1)
 
999
        {
 
1000
                fprintf(stderr, "copy_notes() fstat failed:<%s>\n",
 
1001
                strerror(errno));
 
1002
                fclose(tmp);
 
1003
                return 0;
 
1004
        }
 
1005
        int n = f_stat.st_size;
 
1006
        char* fbuf  = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE,
 
1007
        MAP_PRIVATE, fileno(tmp), 0);
 
1008
        fbuf[n] = 0;
 
1009
 
 
1010
        QByteArray data(fbuf);
 
1011
        QMimeData* md = new QMimeData();
 
1012
 
 
1013
        md->setData("text/x-muse-groupedeventlists", data);
 
1014
 
 
1015
        munmap(fbuf, n);
 
1016
        fclose(tmp);
 
1017
 
 
1018
        return md;
 
1019
}
 
1020
 
 
1021
bool read_eventlist_and_part(Xml& xml, EventList* el, int* part_id) // true on success, false on failure
 
1022
{
 
1023
        *part_id = -1;
 
1024
        
 
1025
        for (;;)
 
1026
        {
 
1027
                Xml::Token token = xml.parse();
 
1028
                const QString& tag = xml.s1();
 
1029
                switch (token)
 
1030
                {
 
1031
                        case Xml::Error:
 
1032
                        case Xml::End:
 
1033
                                return false;
 
1034
                                
 
1035
                        case Xml::Attribut:
 
1036
                                if (tag == "part_id")
 
1037
                                        *part_id = xml.s2().toInt();
 
1038
                                else
 
1039
                                        printf("unknown attribute '%s' in read_eventlist_and_part(), ignoring it...\n", tag.toAscii().data());
 
1040
                                break;
 
1041
                                
 
1042
                        case Xml::TagStart:
 
1043
                                if (tag == "event")
 
1044
                                {
 
1045
                                        Event e(Note);
 
1046
                                        e.read(xml);
 
1047
                                        el->add(e);
 
1048
                                }
 
1049
                                else
 
1050
                                        xml.unknown("read_eventlist_and_part");
 
1051
                                break;
 
1052
                                
 
1053
                        case Xml::TagEnd:
 
1054
                                if (tag == "eventlist")
 
1055
                                        return true;
 
1056
                                
 
1057
                        default:
 
1058
                                break;
 
1059
                }
 
1060
        }
 
1061
}
 
1062
 
 
1063
void paste_at(const QString& pt, int pos, int max_distance, bool always_new_part, bool never_new_part, Part* paste_into_part, int amount, int raster)
 
1064
{
 
1065
        Undo operations;
 
1066
        map<Part*, unsigned> expand_map;
 
1067
        map<Part*, set<Part*> > new_part_map;
 
1068
        
 
1069
        QByteArray pt_= pt.toLatin1();
 
1070
        Xml xml(pt_.constData());
 
1071
        for (;;) 
 
1072
        {
 
1073
                Xml::Token token = xml.parse();
 
1074
                const QString& tag = xml.s1();
 
1075
                switch (token) 
 
1076
                {
 
1077
                        case Xml::Error:
 
1078
                        case Xml::End:
 
1079
                                goto out_of_paste_at_for;
 
1080
                                
 
1081
                        case Xml::TagStart:
 
1082
                                if (tag == "eventlist")
 
1083
                                {
 
1084
                                        EventList el;
 
1085
                                        int part_id;
 
1086
                
 
1087
                                        if (read_eventlist_and_part(xml, &el, &part_id))
 
1088
                                        {
 
1089
                                                Part* dest_part;
 
1090
                                                Track* dest_track;
 
1091
                                                Part* old_dest_part;
 
1092
                                                
 
1093
                                                if (paste_into_part == NULL)
 
1094
                                                        dest_part = partFromSerialNumber(part_id);
 
1095
                                                else
 
1096
                                                        dest_part=paste_into_part;
 
1097
                                                
 
1098
                                                if (dest_part == NULL)
 
1099
                                                {
 
1100
                                                        printf("ERROR: destination part wasn't found. ignoring these events\n");
 
1101
                                                }
 
1102
                                                else
 
1103
                                                {
 
1104
                                                        dest_track=dest_part->track();
 
1105
                                                        old_dest_part=dest_part;
 
1106
                                                        unsigned first_paste_tick = el.begin()->first + pos;
 
1107
                                                        bool create_new_part = ( (dest_part->tick() > first_paste_tick) ||   // dest_part begins too late
 
1108
                                                                         ( ( (dest_part->endTick() + max_distance < first_paste_tick) || // dest_part is too far away
 
1109
                                                                                                  always_new_part ) && !never_new_part ) );    // respect function arguments
 
1110
                                                        
 
1111
                                                        for (int i=0;i<amount;i++)
 
1112
                                                        {
 
1113
                                                                unsigned curr_pos = pos + i*raster;
 
1114
                                                                first_paste_tick = el.begin()->first + curr_pos;
 
1115
                                                                
 
1116
                                                                if (create_new_part)
 
1117
                                                                {
 
1118
                                                                        dest_part = dest_track->newPart();
 
1119
                                                                        dest_part->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it
 
1120
                                                                                                                                                                                                                // so we must decrement it first :/
 
1121
                                                                        dest_part->setTick(AL::sigmap.raster1(first_paste_tick, config.division));
 
1122
 
 
1123
                                                                        new_part_map[old_dest_part].insert(dest_part);
 
1124
                                                                        operations.push_back(UndoOp(UndoOp::AddPart, dest_part));
 
1125
                                                                }
 
1126
                                                                
 
1127
                                                                for (iEvent i = el.begin(); i != el.end(); ++i)
 
1128
                                                                {
 
1129
                                                                        Event e = i->second.clone();
 
1130
                                                                        int tick = e.tick() + curr_pos - dest_part->tick();
 
1131
                                                                        if (tick<0)
 
1132
                                                                        {
 
1133
                                                                                printf("ERROR: trying to add event before current part! ignoring this event\n");
 
1134
                                                                                continue;
 
1135
                                                                        }
 
1136
 
 
1137
                                                                        e.setTick(tick);
 
1138
                                                                        e.setSelected(true);
 
1139
                                                                        
 
1140
                                                                        if (e.endTick() > dest_part->lenTick()) // event exceeds part?
 
1141
                                                                        {
 
1142
                                                                                if (dest_part->hasHiddenEvents()) // auto-expanding is forbidden?
 
1143
                                                                                {
 
1144
                                                                                        if (e.tick() < dest_part->lenTick())
 
1145
                                                                                                e.setLenTick(dest_part->lenTick() - e.tick()); // clip
 
1146
                                                                                        else
 
1147
                                                                                                e.setLenTick(0); // don't insert that note at all
 
1148
                                                                                }
 
1149
                                                                                else
 
1150
                                                                                {
 
1151
                                                                                        if (e.endTick() > expand_map[dest_part])
 
1152
                                                                                                expand_map[dest_part]=e.endTick();
 
1153
                                                                                }
 
1154
                                                                        }
 
1155
                                                                        
 
1156
                                                                        if (e.lenTick() != 0) operations.push_back(UndoOp(UndoOp::AddEvent,e, dest_part, false, false));
 
1157
                                                                }
 
1158
                                                        }
 
1159
                                                }
 
1160
                                        }
 
1161
                                        else
 
1162
                                        {
 
1163
                                                printf("ERROR: reading eventlist from clipboard failed. ignoring this one...\n");
 
1164
                                        }
 
1165
                                }
 
1166
                                else
 
1167
                                        xml.unknown("paste_at");
 
1168
                                break;
 
1169
                                
 
1170
                        case Xml::Attribut:
 
1171
                        case Xml::TagEnd:
 
1172
                        default:
 
1173
                                break;
 
1174
                }
 
1175
        }
 
1176
        
 
1177
        out_of_paste_at_for:
 
1178
        
 
1179
        for (map<Part*, unsigned>::iterator it = expand_map.begin(); it!=expand_map.end(); it++)
 
1180
                if (it->second != it->first->lenTick())
 
1181
                        schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);
 
1182
 
 
1183
        MusEGlobal::song->informAboutNewParts(new_part_map); // must be called before apply. otherwise
 
1184
                                                 // pointer changes (by resize) screw it up
 
1185
        MusEGlobal::song->applyOperationGroup(operations);
 
1186
        MusEGlobal::song->update(SC_SELECTION);
 
1187
}
 
1188
 
 
1189
void select_all(const std::set<Part*>& parts)
 
1190
{
 
1191
        for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
 
1192
                for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
 
1193
                {
 
1194
                        Event& event=ev_it->second;
 
1195
                        event.setSelected(true);
 
1196
                }
 
1197
        MusEGlobal::song->update(SC_SELECTION);
 
1198
}
 
1199
 
 
1200
void select_none(const std::set<Part*>& parts)
 
1201
{
 
1202
        for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
 
1203
                for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
 
1204
                {
 
1205
                        Event& event=ev_it->second;
 
1206
                        event.setSelected(false);
 
1207
                }
 
1208
        MusEGlobal::song->update(SC_SELECTION);
 
1209
}
 
1210
 
 
1211
void select_invert(const std::set<Part*>& parts)
 
1212
{
 
1213
        for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
 
1214
                for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
 
1215
                {
 
1216
                        Event& event=ev_it->second;
 
1217
                        event.setSelected(!event.selected());
 
1218
                }
 
1219
        MusEGlobal::song->update(SC_SELECTION);
 
1220
}
 
1221
 
 
1222
void select_in_loop(const std::set<Part*>& parts)
 
1223
{
 
1224
        select_none(parts);
 
1225
        for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
 
1226
                for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
 
1227
                {
 
1228
                        Event& event=ev_it->second;
 
1229
                        event.setSelected((event.tick()>=MusEGlobal::song->lpos() && event.endTick()<=MusEGlobal::song->rpos()));
 
1230
                }
 
1231
        MusEGlobal::song->update(SC_SELECTION);
 
1232
}
 
1233
 
 
1234
void select_not_in_loop(const std::set<Part*>& parts)
 
1235
{
 
1236
        select_none(parts);
 
1237
        for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
 
1238
                for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
 
1239
                {
 
1240
                        Event& event=ev_it->second;
 
1241
                        event.setSelected(!(event.tick()>=MusEGlobal::song->lpos() && event.endTick()<=MusEGlobal::song->rpos()));
 
1242
                }
 
1243
        MusEGlobal::song->update(SC_SELECTION);
 
1244
}
 
1245
 
 
1246
 
 
1247
void shrink_parts(int raster)
 
1248
{
 
1249
        Undo operations;
 
1250
        
 
1251
        unsigned min_len;
 
1252
        if (raster<0) raster=MusEGlobal::config.division;
 
1253
        if (raster>=0) min_len=raster; else min_len=MusEGlobal::config.division;
 
1254
        
 
1255
        TrackList* tracks = MusEGlobal::song->tracks();
 
1256
        for (iTrack track = tracks->begin(); track != tracks->end(); track++)
 
1257
                for (iPart part = (*track)->parts()->begin(); part != (*track)->parts()->end(); part++)
 
1258
                        if (part->second->selected())
 
1259
                        {
 
1260
                                EventList* events=part->second->events();
 
1261
                                unsigned len=0;
 
1262
                                
 
1263
                                for (iEvent ev=events->begin(); ev!=events->end(); ev++)
 
1264
                                        if (ev->second.endTick() > len)
 
1265
                                                len=ev->second.endTick();
 
1266
                                
 
1267
                                if (raster) len=ceil((float)len/raster)*raster;
 
1268
                                if (len<min_len) len=min_len;
 
1269
                                
 
1270
                                if (len < part->second->lenTick())
 
1271
                                {
 
1272
                                        MidiPart* new_part = new MidiPart(*(MidiPart*)part->second);
 
1273
                                        new_part->setLenTick(len);
 
1274
                                        operations.push_back(UndoOp(UndoOp::ModifyPart, part->second, new_part, true, false));
 
1275
                                }
 
1276
                        }
 
1277
        
 
1278
        MusEGlobal::song->applyOperationGroup(operations);
 
1279
}
 
1280
 
 
1281
 
 
1282
void schedule_resize_all_same_len_clone_parts(Part* part, unsigned new_len, Undo& operations)
 
1283
{
 
1284
        QSet<const Part*> already_done;
 
1285
        
 
1286
        for (Undo::iterator op_it=operations.begin(); op_it!=operations.end();op_it++)
 
1287
                if (op_it->type==UndoOp::ModifyPart || op_it->type==UndoOp::DeletePart)
 
1288
                        already_done.insert(op_it->nPart);
 
1289
                        
 
1290
        unsigned old_len=part->lenTick();
 
1291
        if (old_len!=new_len)
 
1292
        {
 
1293
                Part* part_it=part;
 
1294
                do
 
1295
                {
 
1296
                        if (part_it->lenTick()==old_len && !already_done.contains(part_it))
 
1297
                        {
 
1298
                                MidiPart* new_part = new MidiPart(*(MidiPart*)part_it);
 
1299
                                new_part->setLenTick(new_len);
 
1300
                                operations.push_back(UndoOp(UndoOp::ModifyPart, part_it, new_part, true, false));
 
1301
                        }
 
1302
                        
 
1303
                        part_it=part_it->nextClone();
 
1304
                } while (part_it!=part);
 
1305
        }
 
1306
}
 
1307
 
 
1308
void expand_parts(int raster)
 
1309
{
 
1310
        Undo operations;
 
1311
        
 
1312
        unsigned min_len;
 
1313
        if (raster<0) raster=MusEGlobal::config.division;
 
1314
        if (raster>=0) min_len=raster; else min_len=MusEGlobal::config.division;
 
1315
 
 
1316
        TrackList* tracks = MusEGlobal::song->tracks();
 
1317
        for (iTrack track = tracks->begin(); track != tracks->end(); track++)
 
1318
                for (iPart part = (*track)->parts()->begin(); part != (*track)->parts()->end(); part++)
 
1319
                        if (part->second->selected())
 
1320
                        {
 
1321
                                EventList* events=part->second->events();
 
1322
                                unsigned len=part->second->lenTick();
 
1323
                                
 
1324
                                for (iEvent ev=events->begin(); ev!=events->end(); ev++)
 
1325
                                        if (ev->second.endTick() > len)
 
1326
                                                len=ev->second.endTick();
 
1327
 
 
1328
                                if (raster) len=ceil((float)len/raster)*raster;
 
1329
                                if (len<min_len) len=min_len;
 
1330
                                                                
 
1331
                                if (len > part->second->lenTick())
 
1332
                                {
 
1333
                                        MidiPart* new_part = new MidiPart(*(MidiPart*)part->second);
 
1334
                                        new_part->setLenTick(len);
 
1335
                                        operations.push_back(UndoOp(UndoOp::ModifyPart, part->second, new_part, true, false));
 
1336
                                }
 
1337
                        }
 
1338
                        
 
1339
        MusEGlobal::song->applyOperationGroup(operations);
 
1340
}
 
1341
 
 
1342
void clean_parts()
 
1343
{
 
1344
        Undo operations;
 
1345
        set<Part*> already_processed;
 
1346
        
 
1347
        TrackList* tracks = MusEGlobal::song->tracks();
 
1348
        for (iTrack track = tracks->begin(); track != tracks->end(); track++)
 
1349
                for (iPart part = (*track)->parts()->begin(); part != (*track)->parts()->end(); part++)
 
1350
                        if ((part->second->selected()) && (already_processed.find(part->second)==already_processed.end()))
 
1351
                        { 
 
1352
                                // find out the length of the longest clone of this part;
 
1353
                                // avoid processing eventlist multiple times (because of
 
1354
                                // multiple clones)
 
1355
                                unsigned len=0;
 
1356
                                
 
1357
                                Part* part_it=part->second;
 
1358
                                do
 
1359
                                {
 
1360
                                        if (part_it->lenTick() > len)
 
1361
                                                len=part_it->lenTick();
 
1362
                                                
 
1363
                                        already_processed.insert(part_it);
 
1364
                                        part_it=part_it->nextClone();
 
1365
                                } while ((part_it!=part->second) && (part_it!=NULL));
 
1366
 
 
1367
                                
 
1368
                                // erase all events exceeding the longest clone of this part
 
1369
                                // (i.e., erase all hidden events) or shorten them
 
1370
                                EventList* el = part->second->events();
 
1371
                                for (iEvent ev=el->begin(); ev!=el->end(); ev++)
 
1372
                                        if (ev->second.tick() >= len)
 
1373
                                                operations.push_back(UndoOp(UndoOp::DeleteEvent, ev->second, part->second, true, true));
 
1374
                                        else if (ev->second.endTick() > len)
 
1375
                                        {
 
1376
                                                Event new_event = ev->second.clone();
 
1377
                                                new_event.setLenTick(len - ev->second.tick());
 
1378
                                                
 
1379
                                                operations.push_back(UndoOp(UndoOp::ModifyEvent, new_event, ev->second, part->second, true, true));
 
1380
                                        }
 
1381
                        }
 
1382
        
 
1383
        MusEGlobal::song->applyOperationGroup(operations);
 
1384
}
 
1385
 
 
1386
} // namespace MusECore