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,2013 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 "helper.h"
26 
27 #include "event.h"
28 #include "audio.h"
29 #include "gconfig.h"
30 #include "sig.h"
31 
32 #include "function_dialogs/velocity.h"
33 #include "function_dialogs/quantize.h"
34 #include "function_dialogs/crescendo.h"
35 #include "function_dialogs/gatetime.h"
36 #include "function_dialogs/remove.h"
37 #include "function_dialogs/transpose.h"
38 #include "function_dialogs/setlen.h"
39 #include "function_dialogs/move.h"
40 #include "function_dialogs/deloverlaps.h"
41 #include "function_dialogs/legato.h"
42 #include "components/pasteeventsdialog.h"
43 
44 #include <limits.h>
45 #include <iostream>
46 #include <errno.h>
47 #include <sys/stat.h>
48 #include <sys/types.h>
49 #include <stdint.h>
50 #ifdef _WIN32
51 #include "mman.h"
52 #include "mman.c"
53 #else
54 #include <sys/mman.h>
55 #endif
56 #include "muse_math.h"
57 
58 #include <QTemporaryFile>
59 #include <QByteArray>
60 #include <QDrag>
61 #include <QMessageBox>
62 #include <QClipboard>
63 #include <QSet>
64 
65 // Forwards from header:
66 #include <QMimeData>
67 #include "track.h"
68 #include "part.h"
69 
70 using namespace std;
71 
72 using MusEGlobal::config;
73 
74 
75 namespace MusEGui {
76 
erase_items_dialog(const FunctionDialogMode & mode)77 FunctionDialogReturnErase erase_items_dialog(const FunctionDialogMode& mode)
78 {
79   erase_dialog->setElements(mode._buttons);
80   if(!erase_dialog->exec())
81     return FunctionDialogReturnErase();
82 
83   const int flags = erase_dialog->_ret_flags;
84   return FunctionDialogReturnErase(flags & FunctionReturnAllEvents,
85                                      flags & FunctionReturnAllParts,
86                                      flags & FunctionReturnLooped,
87                                      MusEGlobal::song->lPos(), MusEGlobal::song->rPos(),
88                                      erase_dialog->velo_thres_used, erase_dialog->velo_threshold,
89                                      erase_dialog->len_thres_used, erase_dialog->len_threshold);
90 }
91 
crescendo_items_dialog(const FunctionDialogMode & mode)92 FunctionDialogReturnCrescendo crescendo_items_dialog(const FunctionDialogMode& mode)
93 {
94   if (MusEGlobal::song->rPos() <= MusEGlobal::song->lPos())
95   {
96     QMessageBox::warning(NULL, QObject::tr("Error"), QObject::tr("Please first select the range for crescendo with the loop markers."));
97     return FunctionDialogReturnCrescendo();
98   }
99 
100   crescendo_dialog->setElements(mode._buttons);
101   if(!crescendo_dialog->exec())
102     return FunctionDialogReturnCrescendo();
103 
104   const int flags = crescendo_dialog->_ret_flags;
105   return FunctionDialogReturnCrescendo(flags & FunctionReturnAllEvents,
106                                      flags & FunctionReturnAllParts,
107                                      flags & FunctionReturnLooped,
108                                      MusEGlobal::song->lPos(), MusEGlobal::song->rPos(),
109                                      crescendo_dialog->start_val, crescendo_dialog->end_val,
110                                      crescendo_dialog->absolute);
111 }
112 
deloverlaps_items_dialog(const FunctionDialogMode & mode)113 FunctionDialogReturnDelOverlaps deloverlaps_items_dialog(const FunctionDialogMode& mode)
114 {
115   del_overlaps_dialog->setElements(mode._buttons);
116   if(!del_overlaps_dialog->exec())
117     return FunctionDialogReturnDelOverlaps();
118 
119   const int flags = del_overlaps_dialog->_ret_flags;
120   return FunctionDialogReturnDelOverlaps(flags & FunctionReturnAllEvents,
121                                      flags & FunctionReturnAllParts,
122                                      flags & FunctionReturnLooped,
123                                      MusEGlobal::song->lPos(), MusEGlobal::song->rPos());
124 }
125 
gatetime_items_dialog(const FunctionDialogMode & mode)126 FunctionDialogReturnGateTime gatetime_items_dialog(const FunctionDialogMode& mode)
127 {
128   gatetime_dialog->setElements(mode._buttons);
129   if(!gatetime_dialog->exec())
130     return FunctionDialogReturnGateTime();
131 
132   const int flags = gatetime_dialog->_ret_flags;
133   return FunctionDialogReturnGateTime(flags & FunctionReturnAllEvents,
134                                      flags & FunctionReturnAllParts,
135                                      flags & FunctionReturnLooped,
136                                      MusEGlobal::song->lPos(), MusEGlobal::song->rPos(),
137                                      gatetime_dialog->rateVal, gatetime_dialog->offsetVal);
138 }
139 
legato_items_dialog(const FunctionDialogMode & mode)140 FunctionDialogReturnLegato legato_items_dialog(const FunctionDialogMode& mode)
141 {
142   legato_dialog->setElements(mode._buttons);
143   if(!legato_dialog->exec())
144     return FunctionDialogReturnLegato();
145 
146   const int flags = legato_dialog->_ret_flags;
147   return FunctionDialogReturnLegato(flags & FunctionReturnAllEvents,
148                                      flags & FunctionReturnAllParts,
149                                      flags & FunctionReturnLooped,
150                                      MusEGlobal::song->lPos(), MusEGlobal::song->rPos(),
151                                      legato_dialog->min_len, legato_dialog->allow_shortening);
152 }
153 
move_items_dialog(const FunctionDialogMode & mode)154 FunctionDialogReturnMove move_items_dialog(const FunctionDialogMode& mode)
155 {
156   move_notes_dialog->setElements(mode._buttons);
157   if(!move_notes_dialog->exec())
158     return FunctionDialogReturnMove();
159 
160   const int flags = move_notes_dialog->_ret_flags;
161   return FunctionDialogReturnMove(flags & FunctionReturnAllEvents,
162                                      flags & FunctionReturnAllParts,
163                                      flags & FunctionReturnLooped,
164                                      MusEGlobal::song->lPos(), MusEGlobal::song->rPos(),
165                                      move_notes_dialog->amount);
166 }
167 
quantize_items_dialog(const FunctionDialogMode & mode)168 FunctionDialogReturnQuantize quantize_items_dialog(const FunctionDialogMode& mode)
169 {
170   quantize_dialog->setElements(mode._buttons);
171   if(!quantize_dialog->exec())
172     return FunctionDialogReturnQuantize();
173 
174   const int flags = quantize_dialog->_ret_flags;
175   return FunctionDialogReturnQuantize(flags & FunctionReturnAllEvents,
176                                      flags & FunctionReturnAllParts,
177                                      flags & FunctionReturnLooped,
178                                      MusEGlobal::song->lPos(), MusEGlobal::song->rPos(),
179                                      quantize_dialog->strength, quantize_dialog->threshold,
180                                      quantize_dialog->raster_index, quantize_dialog->swing,
181                                      quantize_dialog->quant_len);
182 }
183 
setlen_items_dialog(const FunctionDialogMode & mode)184 FunctionDialogReturnSetLen setlen_items_dialog(const FunctionDialogMode& mode)
185 {
186   set_notelen_dialog->setElements(mode._buttons);
187   if(!set_notelen_dialog->exec())
188     return FunctionDialogReturnSetLen();
189 
190   const int flags = set_notelen_dialog->_ret_flags;
191   return FunctionDialogReturnSetLen(flags & FunctionReturnAllEvents,
192                                      flags & FunctionReturnAllParts,
193                                      flags & FunctionReturnLooped,
194                                      MusEGlobal::song->lPos(), MusEGlobal::song->rPos(),
195                                      set_notelen_dialog->len);
196 }
197 
transpose_items_dialog(const FunctionDialogMode & mode)198 FunctionDialogReturnTranspose transpose_items_dialog(const FunctionDialogMode& mode)
199 {
200   transpose_dialog->setElements(mode._buttons);
201   if(!transpose_dialog->exec())
202     return FunctionDialogReturnTranspose();
203 
204   const int flags = transpose_dialog->_ret_flags;
205   return FunctionDialogReturnTranspose(flags & FunctionReturnAllEvents,
206                                      flags & FunctionReturnAllParts,
207                                      flags & FunctionReturnLooped,
208                                      MusEGlobal::song->lPos(), MusEGlobal::song->rPos(),
209                                      transpose_dialog->amount);
210 }
211 
velocity_items_dialog(const FunctionDialogMode & mode)212 FunctionDialogReturnVelocity velocity_items_dialog(const FunctionDialogMode& mode)
213 {
214   velocity_dialog->setElements(mode._buttons);
215   if(!velocity_dialog->exec())
216     return FunctionDialogReturnVelocity();
217 
218   const int flags = velocity_dialog->_ret_flags;
219   return FunctionDialogReturnVelocity(flags & FunctionReturnAllEvents,
220                                      flags & FunctionReturnAllParts,
221                                      flags & FunctionReturnLooped,
222                                      MusEGlobal::song->lPos(), MusEGlobal::song->rPos(),
223                                      velocity_dialog->rateVal, velocity_dialog->offsetVal);
224 }
225 
226 
227 } // namespace MusEGui
228 
229 
230 namespace MusECore {
231 
232 // unit private functions:
233 
234 bool read_eventlist_and_part(Xml& xml, EventList* el, int* part_id);
235 
236 // -----------------------
237 
238 typedef map<const Part*, unsigned> expand_map_t;
239 typedef map<const Part*, set<const Part*> > new_part_map_t;
240 
241 
partlist_to_set(PartList * pl)242 set<const Part*> partlist_to_set(PartList* pl)
243 {
244 	set<const Part*> result;
245 
246 	for (PartList::iterator it=pl->begin(); it!=pl->end(); it++)
247 		result.insert(it->second);
248 
249 	return result;
250 }
251 
part_to_set(const Part * p)252 set<const Part*> part_to_set(const Part* p)
253 {
254 	set<const Part*> result;
255 	result.insert(p);
256 	return result;
257 }
258 
get_all_parts()259 set<const Part*> get_all_parts()
260 {
261 	set<const Part*> result;
262 
263 	TrackList* tracks=MusEGlobal::song->tracks();
264 	for (TrackList::const_iterator t_it=tracks->begin(); t_it!=tracks->end(); t_it++)
265 	{
266 		const PartList* parts=(*t_it)->cparts();
267 		for (ciPart p_it=parts->begin(); p_it!=parts->end(); p_it++)
268 			result.insert(p_it->second);
269 	}
270 
271 	return result;
272 }
273 
get_all_selected_parts()274 set<const Part*> get_all_selected_parts()
275 {
276 	set<const Part*> result;
277 
278 	TrackList* tracks=MusEGlobal::song->tracks();
279 	for (TrackList::const_iterator t_it=tracks->begin(); t_it!=tracks->end(); t_it++)
280 	{
281 		const PartList* parts=(*t_it)->cparts();
282 		for (ciPart p_it=parts->begin(); p_it!=parts->end(); p_it++)
283 			if (p_it->second->selected())
284 				result.insert(p_it->second);
285 	}
286 
287 	return result;
288 }
289 
is_relevant(const Event & event,const Part * part,int range,RelevantSelectedEvents_t relevant)290 bool is_relevant(const Event& event, const Part* part, int range, RelevantSelectedEvents_t relevant)
291 {
292 	unsigned tick;
293 
294   switch(event.type())
295   {
296     case Note:
297       if(!(relevant & NotesRelevant))
298         return false;
299     break;
300 
301     case Controller:
302       if(!(relevant & ControllersRelevant))
303         return false;
304     break;
305 
306     case Sysex:
307       if(!(relevant & SysexRelevant))
308         return false;
309     break;
310 
311     case Meta:
312       if(!(relevant & MetaRelevant))
313         return false;
314     break;
315 
316     case Wave:
317       if(!(relevant & WaveRelevant))
318         return false;
319     break;
320   }
321 
322 	switch (range)
323 	{
324 		case 0: return true;
325 		case 1: return event.selected();
326 		case 2: tick=event.tick()+part->tick(); return (tick >= MusEGlobal::song->lpos()) && (tick < MusEGlobal::song->rpos());
327 		case 3: return is_relevant(event,part,1, relevant) && is_relevant(event,part,2, relevant);
328 		default: cout << "ERROR: ILLEGAL FUNCTION CALL in is_relevant: range is illegal: "<<range<<endl;
329 		         return false;
330 	}
331 }
332 
333 
get_events(const set<const Part * > & parts,int range,RelevantSelectedEvents_t relevant)334 map<const Event*, const Part*> get_events(const set<const Part*>& parts, int range, RelevantSelectedEvents_t relevant)
335 {
336 	map<const Event*, const Part*> events;
337 
338 	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
339 		for (ciEvent event=(*part)->events().begin(); event!=(*part)->events().end(); event++)
340 			if (is_relevant(event->second, *part, range, relevant))
341 				events.insert(pair<const Event*, const Part*>(&event->second, *part));
342 
343 	return events;
344 }
345 
346 
modify_velocity(const set<const Part * > & parts,int range,int rate,int offset)347 bool modify_velocity(const set<const Part*>& parts, int range, int rate, int offset)
348 {
349 	map<const Event*, const Part*> events = get_events(parts, range);
350 	Undo operations;
351 
352 	if ( (!events.empty()) && ((rate!=100) || (offset!=0)) )
353 	{
354 		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)
355 		{
356 			const Event& event=*(it->first);
357 			// This operation can only apply to notes.
358 			if(event.type() != Note)
359 			  continue;
360 
361 			const Part* part=it->second;
362 
363 			int velo = event.velo();
364 
365 			velo = (velo * rate) / 100;
366 			velo += offset;
367 
368 			if (velo <= 0)
369 				velo = 1;
370 			else if (velo > 127)
371 				velo = 127;
372 
373 			if (event.velo() != velo)
374 			{
375 				Event newEvent = event.clone();
376 				newEvent.setVelo(velo);
377 				operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
378 			}
379 		}
380 
381 		return MusEGlobal::song->applyOperationGroup(operations);
382 	}
383 	else
384 		return false;
385 }
386 
modify_off_velocity(const set<const Part * > & parts,int range,int rate,int offset)387 bool modify_off_velocity(const set<const Part*>& parts, int range, int rate, int offset)
388 {
389 	map<const Event*, const Part*> events = get_events(parts, range);
390 	Undo operations;
391 
392 	if ( (!events.empty()) && ((rate!=100) || (offset!=0)) )
393 	{
394 		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)
395 		{
396 			const Event& event=*(it->first);
397 			// This operation can only apply to notes.
398 			if(event.type() != Note)
399 			  continue;
400 			const Part* part=it->second;
401 
402 			int velo = event.veloOff();
403 
404 			velo = (velo * rate) / 100;
405 			velo += offset;
406 
407 			if (velo <= 0)
408 				velo = 1;
409 			else if (velo > 127)
410 				velo = 127;
411 
412 			if (event.veloOff() != velo)
413 			{
414 				Event newEvent = event.clone();
415 				newEvent.setVeloOff(velo);
416 				operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
417 			}
418 		}
419 
420 		return MusEGlobal::song->applyOperationGroup(operations);
421 	}
422 	else
423 		return false;
424 }
425 
modify_notelen(const set<const Part * > & parts,int range,int rate,int offset)426 bool modify_notelen(const set<const Part*>& parts, int range, int rate, int offset)
427 {
428 	map<const Event*, const Part*> events = get_events(parts, range);
429 	Undo operations;
430 	map<const Part*, int> partlen;
431 
432 	if ( (!events.empty()) && ((rate!=100) || (offset!=0)) )
433 	{
434 		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)
435 		{
436 			const Event& event=*(it->first);
437 			// This operation can only apply to notes.
438 			if(event.type() != Note)
439 			  continue;
440 			const Part* part=it->second;
441 
442 			unsigned int len = event.lenTick(); //prevent compiler warning: comparison signed/unsigned
443 
444 			len = (len * rate) / 100;
445 			len += offset;
446 
447 			if (len <= 0)
448 				len = 1;
449 
450 			if ((event.tick()+len > part->lenTick()) && (!(part->hasHiddenEvents() & Part::RightEventsHidden)))
451 				partlen[part]=event.tick()+len; // schedule auto-expanding
452 
453 			if (event.lenTick() != len)
454 			{
455 				Event newEvent = event.clone();
456 				newEvent.setLenTick(len);
457 				operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
458 			}
459 		}
460 
461 		for (map<const Part*, int>::iterator it=partlen.begin(); it!=partlen.end(); it++)
462 			schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);
463 
464 		return MusEGlobal::song->applyOperationGroup(operations);
465 	}
466 	else
467 		return false;
468 }
469 
set_notelen(const set<const Part * > & parts,int range,int len)470 bool set_notelen(const set<const Part*>& parts, int range, int len)
471 {
472 	return modify_notelen(parts, range, 0, len);
473 }
474 
quantize_tick(unsigned tick,unsigned raster,int swing)475 unsigned quantize_tick(unsigned tick, unsigned raster, int swing)
476 {
477 	//find out the nearest tick and the distance to it:
478 	//this is so complicated because this function supports
479 	//swing: if swing is 50, the resulting rhythm is not
480 	//"daa daa daa daa" but "daaaa da daaaa da"...
481 	int tick_dest1 = MusEGlobal::sigmap.raster1(tick, raster*2); //round down
482 	int tick_dest2 = tick_dest1 + raster + raster*swing/100;
483 	int tick_dest3 = tick_dest1 + raster*2;
484 
485 	int tick_diff1 = abs(tick_dest1 - (int)tick);
486 	int tick_diff2 = abs(tick_dest2 - (int)tick);
487 	int tick_diff3 = abs(tick_dest3 - (int)tick);
488 
489 	if ((tick_diff3 <= tick_diff1) && (tick_diff3 <= tick_diff2)) //tick_dest3 is the nearest tick
490 		return tick_dest3;
491 	else if ((tick_diff2 <= tick_diff1) && (tick_diff2 <= tick_diff3)) //tick_dest2 is the nearest tick
492 		return tick_dest2;
493 	else
494 		return tick_dest1;
495 }
496 
quantize_notes(const set<const Part * > & parts,int range,int raster,bool quant_len,int strength,int swing,int threshold)497 bool quantize_notes(const set<const Part*>& parts, int range, int raster, bool quant_len, int strength, int swing, int threshold)
498 {
499 	map<const Event*, const Part*> events = get_events(parts, range);
500 	Undo operations;
501 
502 	if (!events.empty())
503 	{
504 		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)
505 		{
506 			const Event& event=*(it->first);
507 			// This operation can only apply to notes.
508 			if(event.type() != Note)
509 			  continue;
510 			const Part* part=it->second;
511 
512 			unsigned begin_tick = event.tick() + part->tick();
513 			int begin_diff = quantize_tick(begin_tick, raster, swing) - begin_tick;
514 
515 			if (abs(begin_diff) > threshold)
516 				begin_tick = begin_tick + begin_diff*strength/100;
517 
518 
519 			unsigned len=event.lenTick();
520 
521 			unsigned end_tick = begin_tick + len;
522 			int len_diff = quantize_tick(end_tick, raster, swing) - end_tick;
523 
524 			if ((abs(len_diff) > threshold) && quant_len)
525 				len = len + len_diff*strength/100;
526 
527 			if (len <= 0)
528 				len = 1;
529 
530 
531 			if ( (event.lenTick() != len) || (event.tick() + part->tick() != begin_tick) )
532 			{
533 				Event newEvent = event.clone();
534 				newEvent.setTick(begin_tick - part->tick());
535 				newEvent.setLenTick(len);
536 				operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
537 			}
538 		}
539 
540 		return MusEGlobal::song->applyOperationGroup(operations);
541 	}
542 	else
543 		return false;
544 }
545 
erase_notes(const set<const Part * > & parts,int range,int velo_threshold,bool velo_thres_used,int len_threshold,bool len_thres_used)546 bool erase_notes(const set<const Part*>& parts, int range, int velo_threshold, bool velo_thres_used, int len_threshold, bool len_thres_used)
547 {
548 	map<const Event*, const Part*> events = get_events(parts, range);
549 	Undo operations;
550 
551 	if (!events.empty())
552 	{
553 		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)
554 		{
555 			// This operation can apply to any event...
556 			const Event& event=*(it->first);
557 			const Part* part=it->second;
558 
559 			if ( (!velo_thres_used && !len_thres_used) ||
560 			     (velo_thres_used && event.velo() < velo_threshold) ||
561 			     (len_thres_used && int(event.lenTick()) < len_threshold) )
562 				operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, false, false));
563 		}
564 
565 		return MusEGlobal::song->applyOperationGroup(operations);
566 	}
567 	else
568 		return false;
569 }
570 
transpose_notes(const set<const Part * > & parts,int range,signed int halftonesteps)571 bool transpose_notes(const set<const Part*>& parts, int range, signed int halftonesteps)
572 {
573 	map<const Event*, const Part*> events = get_events(parts, range);
574 	Undo operations;
575 
576 	if ( (!events.empty()) && (halftonesteps!=0) )
577 	{
578 		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)
579 		{
580 			const Event& event=*(it->first);
581 			// This operation can only apply to notes.
582 			if(event.type() != Note)
583 			  continue;
584 			const Part* part=it->second;
585 
586 			Event newEvent = event.clone();
587 			int pitch = event.pitch()+halftonesteps;
588 			if (pitch > 127) pitch=127;
589 			if (pitch < 0) pitch=0;
590 			newEvent.setPitch(pitch);
591 			operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
592 		}
593 
594 		return MusEGlobal::song->applyOperationGroup(operations);
595 	}
596 	else
597 		return false;
598 }
599 
crescendo(const set<const Part * > & parts,int range,int start_val,int end_val,bool absolute)600 bool crescendo(const set<const Part*>& parts, int range, int start_val, int end_val, bool absolute)
601 {
602 	map<const Event*, const Part*> events = get_events(parts, range);
603 	Undo operations;
604 
605 	int from=MusEGlobal::song->lpos();
606 	int to=MusEGlobal::song->rpos();
607 
608 	if ( (!events.empty()) && (to>from) )
609 	{
610 		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)
611 		{
612 			const Event& event=*(it->first);
613 			// This operation can only apply to notes.
614 			if(event.type() != Note)
615 			  continue;
616 			const Part* part=it->second;
617 
618 			unsigned tick = event.tick() + part->tick();
619 			float curr_val= (float)start_val  +  (float)(end_val-start_val) * (tick-from) / (to-from);
620 
621 			Event newEvent = event.clone();
622 			int velo = event.velo();
623 
624 			if (absolute)
625 				velo=curr_val;
626 			else
627 				velo=curr_val*velo/100;
628 
629 			if (velo > 127) velo=127;
630 			if (velo <= 0) velo=1;
631 			newEvent.setVelo(velo);
632 			operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
633 		}
634 
635 		return MusEGlobal::song->applyOperationGroup(operations);
636 	}
637 	else
638 		return false;
639 }
640 
move_notes(const set<const Part * > & parts,int range,signed int ticks)641 bool move_notes(const set<const Part*>& parts, int range, signed int ticks)
642 {
643 	map<const Event*, const Part*> events = get_events(parts, range);
644 	Undo operations;
645 	map<const Part*, int> partlen;
646 
647 	if ( (!events.empty()) && (ticks!=0) )
648 	{
649 		for (map<const Event*, const Part*>::iterator it=events.begin(); it!=events.end(); it++)
650 		{
651 			const Event& event=*(it->first);
652 			// This operation can only apply to notes.
653 			if(event.type() != Note)
654 			  continue;
655 
656 			const Part* part=it->second;
657 			bool del=false;
658 
659 			Event newEvent = event.clone();
660 			if ((signed)event.tick()+ticks < 0) //don't allow moving before the part's begin
661 				newEvent.setTick(0);
662 			else
663 				newEvent.setTick(event.tick()+ticks);
664 
665 			if (newEvent.endTick() > part->lenTick()) //if exceeding the part's end:
666 			{
667 				if (part->hasHiddenEvents() & Part::RightEventsHidden) // auto-expanding is forbidden, clip
668 				{
669 					if (part->lenTick() > newEvent.tick())
670 						newEvent.setLenTick(part->lenTick() - newEvent.tick());
671 					else
672 						del=true; //if the new length would be <= 0, erase the note
673 				}
674 				else
675 					partlen[part]=newEvent.endTick(); // schedule auto-expanding
676 			}
677 
678 			if (del==false)
679 				operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
680 			else
681 				operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, false, false));
682 		}
683 
684 		for (map<const Part*, int>::iterator it=partlen.begin(); it!=partlen.end(); it++)
685 			schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);
686 
687 		return MusEGlobal::song->applyOperationGroup(operations);
688 	}
689 	else
690 		return false;
691 }
692 
delete_overlaps(const set<const Part * > & parts,int range)693 bool delete_overlaps(const set<const Part*>& parts, int range)
694 {
695 	map<const Event*, const Part*> events = get_events(parts, range);
696 	Undo operations;
697 
698 	set<const Event*> deleted_events;
699 
700 	if (!events.empty())
701 	{
702 		for (map<const Event*, const Part*>::iterator it1=events.begin(); it1!=events.end(); it1++)
703 		{
704 			const Event& event1=*(it1->first);
705 			// This operation can only apply to notes.
706 			if(event1.type() != Note)
707 			  continue;
708 			const Part* part1=it1->second;
709 
710 			// we may NOT optimize by letting it2 start at (it1 +1); this optimisation
711 			// is only allowed when events was sorted by time. it is, however, sorted
712 			// randomly by pointer.
713 			for (map<const Event*, const Part*>::iterator it2=events.begin(); it2!=events.end(); it2++)
714 			{
715 				const Event& event2=*(it2->first);
716 				// This operation can only apply to notes.
717 				if(event2.type() != Note)
718 				  continue;
719 				const Part* part2=it2->second;
720 
721 				if ( (part1->isCloneOf(part2)) &&          // part1 and part2 are the same or are duplicates
722 				     (&event1 != &event2) &&               // and event1 and event2 aren't the same
723 				     (deleted_events.find(&event2) == deleted_events.end()) ) //and event2 hasn't been deleted before
724 				{
725 					if ( (event1.pitch() == event2.pitch()) &&
726 					     (event1.tick() <= event2.tick()) &&
727 						   (event1.endTick() > event2.tick()) ) //they overlap
728 					{
729 						int new_len = event2.tick() - event1.tick();
730 
731 						if (new_len==0)
732 						{
733 							operations.push_back(UndoOp(UndoOp::DeleteEvent, event2, part2, false, false));
734 							deleted_events.insert(&event2);
735 						}
736 						else
737 						{
738 							Event new_event1 = event1.clone();
739 							new_event1.setLenTick(new_len);
740 
741 							operations.push_back(UndoOp(UndoOp::ModifyEvent, new_event1, event1, part1, false, false));
742 						}
743 					}
744 				}
745 			}
746 		}
747 
748 		return MusEGlobal::song->applyOperationGroup(operations);
749 	}
750 	else
751 		return false;
752 }
753 
legato(const set<const Part * > & parts,int range,int min_len,bool dont_shorten)754 bool legato(const set<const Part*>& parts, int range, int min_len, bool dont_shorten)
755 {
756 	map<const Event*, const Part*> events = get_events(parts, range);
757 	Undo operations;
758 
759 	if (min_len<=0) min_len=1;
760 
761 	if (!events.empty())
762 	{
763 		for (map<const Event*, const Part*>::iterator it1=events.begin(); it1!=events.end(); it1++)
764 		{
765 			const Event& event1=*(it1->first);
766 			// This operation can only apply to notes.
767 			if(event1.type() != Note)
768 			  continue;
769 			const Part* part1=it1->second;
770 
771 			unsigned len=INT_MAX;
772 			// we may NOT optimize by letting it2 start at (it1 +1); this optimisation
773 			// is only allowed when events was sorted by time. it is, however, sorted
774 			// randomly by pointer.
775 			for (map<const Event*, const Part*>::iterator it2=events.begin(); it2!=events.end(); it2++)
776 			{
777 				const Event& event2=*(it2->first);
778 				// This operation can only apply to notes.
779 				if(event2.type() != Note)
780 				  continue;
781 				const Part* part2=it2->second;
782 
783 				bool relevant = (event2.tick() >= event1.tick() + min_len);
784 				if (dont_shorten)
785 					relevant = relevant && (event2.tick() >= event1.endTick());
786 
787 				if ( (part1->isCloneOf(part2)) &&           // part1 and part2 are the same or are duplicates
788 				      relevant &&                           // they're not too near (respect min_len and dont_shorten)
789 				     (event2.tick()-event1.tick() < len ) ) // that's the nearest relevant following note
790 					len=event2.tick()-event1.tick();
791 			}
792 
793 			if (len==INT_MAX) len=event1.lenTick(); // if no following note was found, keep the length
794 
795 			if (event1.lenTick() != len)
796 			{
797 				Event new_event1 = event1.clone();
798 				new_event1.setLenTick(len);
799 
800 				operations.push_back(UndoOp(UndoOp::ModifyEvent, new_event1, event1, part1, false, false));
801 			}
802 		}
803 
804 		return MusEGlobal::song->applyOperationGroup(operations);
805 	}
806 	else
807 		return false;
808 }
809 
810 // if nothing is selected/relevant, this function returns NULL
selected_events_to_mime(const set<const Part * > & parts,int range)811 QMimeData* selected_events_to_mime(const set<const Part*>& parts, int range)
812 {
813     unsigned start_tick = INT_MAX; //will be the tick of the first event or INT_MAX if no events are there
814 
815     for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
816         for (ciEvent ev=(*part)->events().begin(); ev!=(*part)->events().end(); ev++)
817             if (is_relevant(ev->second, *part, range, AllEventsRelevant))
818                 if (ev->second.tick() < start_tick)
819                     start_tick=ev->second.tick();
820 
821     if (start_tick == INT_MAX)
822         return NULL;
823 
824     //---------------------------------------------------
825     //    write events as XML into tmp file
826     //---------------------------------------------------
827 
828     FILE* tmp = tmpfile();
829     if (tmp == 0)
830     {
831         fprintf(stderr, "EventCanvas::getTextDrag() fopen failed: %s\n", strerror(errno));
832         return 0;
833     }
834 
835     Xml xml(tmp);
836     int level = 0;
837 
838     for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
839     {
840         xml.tag(level++, "eventlist part_id=\"%d\"", (*part)->sn());
841         for (ciEvent ev=(*part)->events().begin(); ev!=(*part)->events().end(); ev++)
842             if (is_relevant(ev->second, *part, range, AllEventsRelevant))
843                 ev->second.write(level, xml, -start_tick);
844         xml.etag(--level, "eventlist");
845     }
846 
847     QMimeData *mimeData =  file_to_mimedata(tmp, "text/x-muse-groupedeventlists" );
848     fclose(tmp);
849     return mimeData;
850 }
851 
copy_notes(const set<const Part * > & parts,int range)852 void copy_notes(const set<const Part*>& parts, int range)
853 {
854 	QMimeData* drag = selected_events_to_mime(parts,range);
855 
856 	if (drag)
857 		QApplication::clipboard()->setMimeData(drag, QClipboard::Clipboard);
858 }
859 
get_groupedevents_len(const QString & pt)860 unsigned get_groupedevents_len(const QString& pt)
861 {
862 	unsigned maxlen=0;
863 
864 	QByteArray pt_= pt.toLatin1();
865 	Xml xml(pt_.constData());
866 	for (;;)
867 	{
868 		Xml::Token token = xml.parse();
869 		const QString& tag = xml.s1();
870 		switch (token)
871 		{
872 			case Xml::Error:
873 			case Xml::End:
874 				return maxlen;
875 
876 			case Xml::TagStart:
877 				if (tag == "eventlist")
878 				{
879 					EventList el;
880 					int part_id;
881 					if (read_eventlist_and_part(xml, &el, &part_id))
882 					{
883 						unsigned len = el.rbegin()->first;
884 						if (len > maxlen) maxlen=len;
885 					}
886 				}
887 				else
888 					xml.unknown("get_clipboard_len");
889 				break;
890 
891 			case Xml::Attribut:
892 			case Xml::TagEnd:
893 			default:
894 				break;
895 		}
896 	}
897 
898 	return maxlen; // see also the return statement above!
899 }
900 
get_clipboard_len()901 unsigned get_clipboard_len()
902 {
903 	QString tmp="x-muse-groupedeventlists"; // QClipboard::text() expects a QString&, not a QString :(
904 	QString s = QApplication::clipboard()->text(tmp, QClipboard::Clipboard);
905 
906 	return get_groupedevents_len(s);
907 }
908 
paste_notes(const Part * paste_into_part)909 bool paste_notes(const Part* paste_into_part)
910 {
911 	unsigned temp_begin = MusEGlobal::sigmap.raster1(MusEGlobal::song->cpos(),0);
912 	unsigned temp_end = MusEGlobal::sigmap.raster2(temp_begin + get_clipboard_len(), 0);
913 	MusEGui::paste_events_dialog->raster = temp_end - temp_begin;
914 	MusEGui::paste_events_dialog->into_single_part_allowed = (paste_into_part!=NULL);
915 
916 	if (!MusEGui::paste_events_dialog->exec())
917 		return false;
918 
919 	paste_notes(MusEGui::paste_events_dialog->max_distance, MusEGui::paste_events_dialog->always_new_part,
920 	            MusEGui::paste_events_dialog->never_new_part, MusEGui::paste_events_dialog->into_single_part ? paste_into_part : NULL,
921 	            MusEGui::paste_events_dialog->number, MusEGui::paste_events_dialog->raster);
922 
923 	return true;
924 }
925 
paste_notes(int max_distance,bool always_new_part,bool never_new_part,const Part * paste_into_part,int amount,int raster)926 void paste_notes(int max_distance, bool always_new_part, bool never_new_part, const Part* paste_into_part, int amount, int raster)
927 {
928 	QString tmp="x-muse-groupedeventlists"; // QClipboard::text() expects a QString&, not a QString :(
929 	QString s = QApplication::clipboard()->text(tmp, QClipboard::Clipboard);
930 	paste_at(s, MusEGlobal::song->cpos(), max_distance, always_new_part, never_new_part, paste_into_part, amount, raster);
931 }
932 
933 // if nothing is selected/relevant, this function returns NULL
parts_to_mime(const set<const Part * > & parts)934 QMimeData* parts_to_mime(const set<const Part*>& parts)
935 {
936 
937 	//---------------------------------------------------
938 	//    write events as XML into tmp file
939 	//---------------------------------------------------
940 
941 	FILE* tmp = tmpfile();
942 	if (tmp == 0)
943 	{
944 		fprintf(stderr, "EventCanvas::getTextDrag() fopen failed: %s\n", strerror(errno));
945 		return 0;
946 	}
947 
948 	Xml xml(tmp);
949 	int level = 0;
950 
951     bool midi=false;
952     bool wave=false;
953 	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
954 	{
955         if ((*part)->track()->type() == MusECore::Track::MIDI)
956             midi=true;
957         else
958             wave=true;
959         (*part)->write(level, xml, true, true);
960     }
961     QString mimeString = "text/x-muse-mixedpartlist";
962     if (!midi)
963         mimeString = "text/x-muse-wavepartlist";
964     else if (!wave)
965         mimeString = "text/x-muse-midipartlist";
966     QMimeData *mimeData =  file_to_mimedata(tmp, mimeString );
967     fclose(tmp);
968     return mimeData;
969 }
970 
971 //---------------------------------------------------
972 //    read datafile into mime Object
973 //---------------------------------------------------
file_to_mimedata(FILE * datafile,QString mimeType)974 QMimeData* file_to_mimedata(FILE *datafile, QString mimeType)
975 {
976 
977     fflush(datafile);
978 	struct stat f_stat;
979     if (fstat(fileno(datafile), &f_stat) == -1)
980 	{
981 		fprintf(stderr, "copy_notes() fstat failed:<%s>\n",
982 		strerror(errno));
983         fclose(datafile);
984 		return 0;
985 	}
986 	int n = f_stat.st_size;
987 	char* fbuf  = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE,
988     MAP_PRIVATE, fileno(datafile), 0);
989 	fbuf[n] = 0;
990 
991 	QByteArray data(fbuf);
992 
993     QMimeData* md = new QMimeData();
994     md->setData(mimeType, data);
995 
996 	munmap(fbuf, n);
997 
998 	return md;
999 }
1000 
read_eventlist_and_part(Xml & xml,EventList * el,int * part_id)1001 bool read_eventlist_and_part(Xml& xml, EventList* el, int* part_id) // true on success, false on failure
1002 {
1003 	*part_id = -1;
1004 
1005 	for (;;)
1006 	{
1007 		Xml::Token token = xml.parse();
1008 		const QString& tag = xml.s1();
1009 		switch (token)
1010 		{
1011 			case Xml::Error:
1012 			case Xml::End:
1013 				return false;
1014 
1015 			case Xml::Attribut:
1016 				if (tag == "part_id")
1017 					*part_id = xml.s2().toInt();
1018 				else
1019 					printf("unknown attribute '%s' in read_eventlist_and_part(), ignoring it...\n", tag.toLatin1().data());
1020 				break;
1021 
1022 			case Xml::TagStart:
1023 				if (tag == "event")
1024 				{
1025 					Event e(Note);
1026 					e.read(xml);
1027 					el->add(e);
1028 				}
1029 				else
1030 					xml.unknown("read_eventlist_and_part");
1031 				break;
1032 
1033 			case Xml::TagEnd:
1034 				if (tag == "eventlist")
1035 					return true;
1036 
1037 			default:
1038 				break;
1039 		}
1040 	}
1041 }
1042 
paste_at(const QString & pt,int pos,int max_distance,bool always_new_part,bool never_new_part,const Part * paste_into_part,int amount,int raster)1043 void paste_at(const QString& pt, int pos, int max_distance, bool always_new_part, bool never_new_part, const Part* paste_into_part, int amount, int raster)
1044 {
1045 	Undo operations;
1046 	map<const Part*, unsigned> expand_map;
1047 	map<const Part*, set<const Part*> > new_part_map;
1048 
1049 	QByteArray pt_= pt.toLatin1();
1050 	Xml xml(pt_.constData());
1051 	for (;;)
1052 	{
1053 		Xml::Token token = xml.parse();
1054 		const QString& tag = xml.s1();
1055 		switch (token)
1056 		{
1057 			case Xml::Error:
1058 			case Xml::End:
1059 				goto out_of_paste_at_for;
1060 
1061 			case Xml::TagStart:
1062 				if (tag == "eventlist")
1063 				{
1064 					EventList el;
1065 					int part_id;
1066 
1067 					if (read_eventlist_and_part(xml, &el, &part_id))
1068 					{
1069 						const Part* dest_part;
1070 						Track* dest_track;
1071 						const Part* old_dest_part;
1072 
1073 						if (paste_into_part == NULL)
1074 							dest_part = partFromSerialNumber(part_id);
1075 						else
1076 							dest_part=paste_into_part;
1077 
1078 						if (dest_part == NULL)
1079 						{
1080 							printf("ERROR: destination part wasn't found. ignoring these events\n");
1081 						}
1082 						else
1083 						{
1084 							dest_track=dest_part->track();
1085 							old_dest_part=dest_part;
1086 							unsigned first_paste_tick = el.begin()->first + pos;
1087 							bool create_new_part = ( (dest_part->tick() > first_paste_tick) ||   // dest_part begins too late
1088 									 ( ( (dest_part->endTick() + max_distance < first_paste_tick) || // dest_part is too far away
1089 										                  always_new_part ) && !never_new_part ) );    // respect function arguments
1090 
1091 							for (int i=0;i<amount;i++)
1092 							{
1093 								unsigned curr_pos = pos + i*raster;
1094 								first_paste_tick = el.begin()->first + curr_pos;
1095 
1096 								if (create_new_part)
1097 								{
1098 									dest_part = NULL;
1099 									Part* newpart = dest_track->newPart();
1100 									if(newpart)
1101 									{
1102 										newpart->setTick(MusEGlobal::sigmap.raster1(first_paste_tick, config.division));
1103 										dest_part = newpart;
1104 										new_part_map[old_dest_part].insert(dest_part);
1105 										operations.push_back(UndoOp(UndoOp::AddPart, dest_part));
1106 									}
1107 								}
1108 
1109 								if(dest_part)
1110 								{
1111 									for (iEvent i = el.begin(); i != el.end(); ++i)
1112 									{
1113 										// If the destination part is a midi part, any midi event is allowed.
1114 										// If the destination part is a wave part, any wave event is allowed.
1115 										switch(i->second.type())
1116 										{
1117 											case Note:
1118 											case Controller:
1119 											case Sysex:
1120 											case Meta:
1121 												if(dest_part->type() == Pos::FRAMES)
1122 													continue;
1123 											break;
1124 
1125 											case Wave:
1126 												// FIXME TODO: To support pasting wave events, some code below must be made agnostic.
1127 												//             For now just ignore wave events.
1128 												//if(dest_part->type() == Pos::TICKS)
1129 													continue;
1130 											break;
1131 										}
1132 
1133 // FIXME TODO: To support pasting wave events, this code block and some code below it MUST be made position-agnostic.
1134 										Event e = i->second.clone();
1135 										int tick = e.tick() + curr_pos - dest_part->tick();
1136 										if (tick<0)
1137 										{
1138 											printf("ERROR: trying to add event before current part! ignoring this event\n");
1139 											continue;
1140 										}
1141 
1142 										e.setTick(tick);
1143 										e.setSelected(true);  // No need to select clones, AddEvent operation below will take care of that.
1144 
1145 										if (e.endTick() > dest_part->lenTick()) // event exceeds part?
1146 										{
1147 											if (dest_part->hasHiddenEvents() & Part::RightEventsHidden) // auto-expanding is forbidden?
1148 											{
1149 												if (e.tick() < dest_part->lenTick())
1150 													e.setLenTick(dest_part->lenTick() - e.tick()); // clip
1151 												else
1152 													e.setLenTick(0); // don't insert that note at all
1153 											}
1154 											else
1155 											{
1156 												if (e.endTick() > expand_map[dest_part])
1157 													expand_map[dest_part]=e.endTick();
1158 											}
1159 										}
1160 
1161 										switch(e.type())
1162 										{
1163 											case Note:
1164 												// Don't add Note event types if they have no length.
1165 												// Notes are allowed to overlap. There is no DeleteEvent or ModifyEvent first.
1166 												if(e.lenTick() != 0)
1167 													operations.push_back(UndoOp(UndoOp::AddEvent, e, dest_part, false, false));
1168 											break;
1169 
1170 											case Wave:
1171 												// Don't add Wave event types if they have no length.
1172 												if(e.lenFrame() != 0)
1173 												{
1174 													EventList el;
1175 													// Compare time, and wave position, path, and start position.
1176 													dest_part->events().findSimilarType(e, el, true, false, false, false,
1177 																															true, true, true);
1178 													// Do NOT add the new wave event if it already exists at the position.
1179 													// Don't event bother replacing it using DeletEvent or ModifyEvent.
1180 													if(el.empty())
1181 													{
1182 														operations.push_back(UndoOp(UndoOp::AddEvent, e, dest_part, false, false));
1183 													}
1184 													else
1185 													{
1186 														// Delete all but one of them. There shouldn't be more than one wave event
1187 														//  at a time for a given wave event anyway.
1188 														iEvent nie;
1189 														for(iEvent ie = el.begin(); ie != el.end(); ++ie)
1190 														{
1191 															// Break on the second-last one, to leave one item intact.
1192 															nie = ie;
1193 															++nie;
1194 															if(nie == el.end())
1195 															{
1196 																break;
1197 															}
1198 
1199 															operations.push_back(UndoOp(UndoOp::DeleteEvent, ie->second, dest_part, false, false));
1200 														}
1201 													}
1202 
1203 												}
1204 											break;
1205 
1206 											case Controller:
1207 											{
1208 												EventList el;
1209 												// Compare time and controller number (data A) only.
1210 												dest_part->events().findSimilarType(e, el, true, true);
1211 												// Delete them all. There shouldn't be more than one controller event
1212 												//  at a time for a given controller number anyway.
1213 												for(iEvent ie = el.begin(); ie != el.end(); ++ie)
1214 												{
1215 													operations.push_back(UndoOp(UndoOp::DeleteEvent, ie->second, dest_part, true, true));
1216 												}
1217 
1218 												// Do port controller values and clone parts.
1219 												operations.push_back(UndoOp(UndoOp::AddEvent, e, dest_part, true, true));
1220 											}
1221 											break;
1222 
1223 											case Sysex:
1224 											{
1225 												EventList el;
1226 												// Compare time and sysex data only.
1227 												dest_part->events().findSimilarType(e, el, true);
1228 												// Do NOT add the new sysex if it already exists at the position.
1229 												// Don't even bother replacing it using DeletEvent or ModifyEvent.
1230 												if(el.empty())
1231 												{
1232 													operations.push_back(UndoOp(UndoOp::AddEvent, e, dest_part, false, false));
1233 												}
1234 												else
1235 												{
1236 													// Delete all but one of them. There shouldn't be more than one sysex event
1237 													//  at a time for a given sysex anyway.
1238 													iEvent nie;
1239 													for(iEvent ie = el.begin(); ie != el.end(); ++ie)
1240 													{
1241 														// Break on the second-last one, to leave one item intact.
1242 														nie = ie;
1243 														++nie;
1244 														if(nie == el.end())
1245 														{
1246 															break;
1247 														}
1248 
1249 														operations.push_back(UndoOp(UndoOp::DeleteEvent, ie->second, dest_part, false, false));
1250 													}
1251 												}
1252 											}
1253 											break;
1254 
1255 											case Meta:
1256 											{
1257 												EventList el;
1258 												// Compare time and meta data only.
1259 												dest_part->events().findSimilarType(e, el, true);
1260 												// Do NOT add the new meta if it already exists at the position.
1261 												// Don't even bother replacing it using DeletEvent or ModifyEvent.
1262 												if(el.empty())
1263 												{
1264 													operations.push_back(UndoOp(UndoOp::AddEvent, e, dest_part, false, false));
1265 												}
1266 												else
1267 												{
1268 													// Delete all but one of them. There shouldn't be more than one meta event
1269 													//  at a time for a given meta anyway.
1270 													iEvent nie;
1271 													for(iEvent ie = el.begin(); ie != el.end(); ++ie)
1272 													{
1273 														// Break on the second-last one, to leave one item intact.
1274 														nie = ie;
1275 														++nie;
1276 														if(nie == el.end())
1277 														{
1278 															break;
1279 														}
1280 
1281 														operations.push_back(UndoOp(UndoOp::DeleteEvent, ie->second, dest_part, false, false));
1282 													}
1283 												}
1284 											}
1285 											break;
1286 										}
1287 									}
1288 								}
1289 							}
1290 						}
1291 					}
1292 					else
1293 					{
1294 						printf("ERROR: reading eventlist from clipboard failed. ignoring this one...\n");
1295 					}
1296 				}
1297 				else
1298 					xml.unknown("paste_at");
1299 				break;
1300 
1301 			case Xml::Attribut:
1302 			case Xml::TagEnd:
1303 			default:
1304 				break;
1305 		}
1306 	}
1307 
1308 	out_of_paste_at_for:
1309 
1310 	for (map<const Part*, unsigned>::iterator it = expand_map.begin(); it!=expand_map.end(); it++)
1311 		if (it->second != it->first->lenTick())
1312 			schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);
1313 
1314 	MusEGlobal::song->informAboutNewParts(new_part_map); // must be called before apply. otherwise
1315 	                                                     // pointer changes (by resize) screw it up
1316 	MusEGlobal::song->applyOperationGroup(operations);
1317 	MusEGlobal::song->update(SC_SELECTION | SC_PART_SELECTION);
1318 }
1319 
select_all(const set<const Part * > & parts)1320 void select_all(const set<const Part*>& parts)
1321 {
1322 	Undo operations;
1323 	operations.combobreaker=true;
1324 
1325 	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
1326 		for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++)
1327 		{
1328 			const Event& event=ev_it->second;
1329 			operations.push_back(UndoOp(UndoOp::SelectEvent,event, *part, true, event.selected()));
1330 		}
1331 	MusEGlobal::song->applyOperationGroup(operations, MusECore::Song::OperationExecuteUpdate);
1332 }
1333 
select_none(const set<const Part * > & parts)1334 void select_none(const set<const Part*>& parts)
1335 {
1336 	Undo operations;
1337 	operations.combobreaker=true;
1338 
1339 	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
1340 		for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++)
1341 		{
1342 			const Event& event=ev_it->second;
1343 			operations.push_back(UndoOp(UndoOp::SelectEvent,event, *part, false, event.selected()));
1344 		}
1345 	MusEGlobal::song->applyOperationGroup(operations, MusECore::Song::OperationExecuteUpdate);
1346 }
1347 
select_invert(const set<const Part * > & parts)1348 void select_invert(const set<const Part*>& parts)
1349 {
1350 	Undo operations;
1351 	operations.combobreaker=true;
1352 
1353 	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
1354 		for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++)
1355 		{
1356 			const Event& event=ev_it->second;
1357 			operations.push_back(UndoOp(UndoOp::SelectEvent,event, *part, !event.selected(), event.selected()));
1358 		}
1359 	MusEGlobal::song->applyOperationGroup(operations, MusECore::Song::OperationExecuteUpdate);
1360 }
1361 
select_in_loop(const set<const Part * > & parts)1362 void select_in_loop(const set<const Part*>& parts)
1363 {
1364 	select_none(parts);
1365 	Undo operations;
1366 	operations.combobreaker=true;
1367 
1368 	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
1369 		for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++)
1370 		{
1371 			const Event& event=ev_it->second;
1372 			operations.push_back(UndoOp(UndoOp::SelectEvent,event, *part,
1373          (event.tick()>=MusEGlobal::song->lpos() && event.endTick()<=MusEGlobal::song->rpos()), event.selected()));
1374 		}
1375 	MusEGlobal::song->applyOperationGroup(operations, MusECore::Song::OperationExecuteUpdate);
1376 }
1377 
select_not_in_loop(const set<const Part * > & parts)1378 void select_not_in_loop(const set<const Part*>& parts)
1379 {
1380 	select_none(parts);
1381 	Undo operations;
1382 	operations.combobreaker=true;
1383 
1384 	for (set<const Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
1385 		for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++)
1386 		{
1387 			const Event& event=ev_it->second;
1388 			operations.push_back(UndoOp(UndoOp::SelectEvent,event, *part,
1389         !(event.tick()>=MusEGlobal::song->lpos() && event.endTick()<=MusEGlobal::song->rpos()), event.selected()));
1390 		}
1391 	MusEGlobal::song->applyOperationGroup(operations, MusECore::Song::OperationExecuteUpdate);
1392 }
1393 
tracks_are_selected()1394 bool tracks_are_selected()
1395 {
1396   const TrackList* tl = MusEGlobal::song->tracks();
1397   for(ciTrack it = tl->begin(); it != tl->end(); ++it)
1398     if((*it)->selected())
1399       return true;
1400   return false;
1401 }
1402 
parts_are_selected()1403 bool parts_are_selected()
1404 {
1405   const TrackList* tl = MusEGlobal::song->tracks();
1406   for(ciTrack it = tl->begin(); it != tl->end(); ++it)
1407   {
1408     const PartList* pl = (*it)->cparts();
1409     for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)
1410       if(ip->second->selected())
1411         return true;
1412   }
1413   return false;
1414 }
1415 
1416 
1417 
shrink_parts(int raster)1418 void shrink_parts(int raster)
1419 {
1420 	Undo operations;
1421 
1422 	unsigned min_len;
1423 	if (raster<0) raster=MusEGlobal::config.division;
1424 	if (raster>=0) min_len=raster; else min_len=MusEGlobal::config.division;
1425 
1426 	TrackList* tracks = MusEGlobal::song->tracks();
1427 	for (iTrack track = tracks->begin(); track != tracks->end(); track++)
1428 		for (iPart part = (*track)->parts()->begin(); part != (*track)->parts()->end(); part++)
1429 			if (part->second->selected())
1430 			{
1431 				unsigned len=0;
1432 
1433 				for (ciEvent ev=part->second->events().begin(); ev!=part->second->events().end(); ev++)
1434 					if (ev->second.endTick() > len)
1435 						len=ev->second.endTick();
1436 
1437 				if (raster) len=ceil((float)len/raster)*raster;
1438 				if (len<min_len) len=min_len;
1439 
1440 				if (len < part->second->lenTick())
1441 					operations.push_back(UndoOp(UndoOp::ModifyPartLength, part->second, part->second->lenValue(), len, 0, Pos::TICKS));
1442 			}
1443 
1444 	MusEGlobal::song->applyOperationGroup(operations);
1445 }
1446 
1447 
schedule_resize_all_same_len_clone_parts(const Part * part,unsigned new_len,Undo & operations)1448 void schedule_resize_all_same_len_clone_parts(const Part* part, unsigned new_len, Undo& operations)
1449 {
1450 	QSet<const Part*> already_done;
1451 
1452 	for (Undo::iterator op_it=operations.begin(); op_it!=operations.end();op_it++)
1453 		if (op_it->type==UndoOp::DeletePart)
1454       already_done.insert(op_it->part);
1455 
1456 	unsigned old_len = part->lenValue();
1457 	if (old_len!=new_len)
1458 	{
1459 		const Part* part_it=part;
1460 		do
1461 		{
1462 			if (part_it->lenValue()==old_len && !already_done.contains(part_it))
1463 				operations.push_back(UndoOp(UndoOp::ModifyPartLength, part_it, old_len, new_len, 0, part->type()));
1464 
1465 			part_it=part_it->nextClone();
1466 		} while (part_it!=part);
1467 	}
1468 }
1469 
expand_parts(int raster)1470 void expand_parts(int raster)
1471 {
1472 	Undo operations;
1473 
1474 	unsigned min_len;
1475 	if (raster<0) raster=MusEGlobal::config.division;
1476 	if (raster>=0) min_len=raster; else min_len=MusEGlobal::config.division;
1477 
1478 	TrackList* tracks = MusEGlobal::song->tracks();
1479 	for (iTrack track = tracks->begin(); track != tracks->end(); track++)
1480 		for (iPart part = (*track)->parts()->begin(); part != (*track)->parts()->end(); part++)
1481 			if (part->second->selected())
1482 			{
1483 				unsigned len=part->second->lenTick();
1484 
1485 				for (ciEvent ev=part->second->events().begin(); ev!=part->second->events().end(); ev++)
1486 					if (ev->second.endTick() > len)
1487 						len=ev->second.endTick();
1488 
1489 				if (raster) len=ceil((float)len/raster)*raster;
1490 				if (len<min_len) len=min_len;
1491 
1492 				if (len > part->second->lenTick())
1493 					operations.push_back(UndoOp(UndoOp::ModifyPartLength, part->second, part->second->lenValue(), len, 0, Pos::TICKS));
1494 			}
1495 
1496 	MusEGlobal::song->applyOperationGroup(operations);
1497 }
1498 
clean_parts()1499 void clean_parts()
1500 {
1501 	Undo operations;
1502 	set<const Part*> already_processed;
1503 
1504 	TrackList* tracks = MusEGlobal::song->tracks();
1505 	for (iTrack track = tracks->begin(); track != tracks->end(); track++)
1506 		for (iPart part = (*track)->parts()->begin(); part != (*track)->parts()->end(); part++)
1507 			if ((part->second->selected()) && (already_processed.find(part->second)==already_processed.end()))
1508 			{
1509 				// find out the length of the longest clone of this part;
1510 				// avoid processing eventlist multiple times (because of
1511 				// multiple clones)
1512 				unsigned len=0;
1513 
1514 				const Part* part_it=part->second;
1515 				do
1516 				{
1517 					if (part_it->lenTick() > len)
1518 						len=part_it->lenTick();
1519 
1520 					already_processed.insert(part_it);
1521 					part_it=part_it->nextClone();
1522 				} while ((part_it!=part->second) && (part_it!=NULL));
1523 
1524 
1525 				// erase all events exceeding the longest clone of this part
1526 				// (i.e., erase all hidden events) or shorten them
1527 				for (ciEvent ev=part->second->events().begin(); ev!=part->second->events().end(); ev++)
1528 					if (ev->second.tick() >= len)
1529 						operations.push_back(UndoOp(UndoOp::DeleteEvent, ev->second, part->second, true, true));
1530 					else if (ev->second.endTick() > len)
1531 					{
1532 						Event new_event = ev->second.clone();
1533 						new_event.setLenTick(len - ev->second.tick());
1534 
1535 						operations.push_back(UndoOp(UndoOp::ModifyEvent, new_event, ev->second, part->second, true, true));
1536 					}
1537 			}
1538 
1539 	MusEGlobal::song->applyOperationGroup(operations);
1540 }
1541 
1542 
merge_with_next_part(const Part * oPart)1543 bool merge_with_next_part(const Part* oPart)
1544 {
1545 	const Track* track = oPart->track();
1546 
1547 	if(track->type() != Track::WAVE && !track->isMidiTrack())
1548 		return false;
1549 
1550 	const PartList* pl   = track->cparts();
1551 	const Part* nextPart = 0;
1552 
1553 	for (ciPart ip = pl->begin(); ip != pl->end(); ++ip)
1554 	{
1555 			if (ip->second == oPart)
1556 			{
1557 				++ip;
1558 				if (ip == pl->end())
1559 						return false;
1560 				nextPart = ip->second;
1561 				break;
1562 				}
1563 			}
1564 
1565 	if (nextPart)
1566 	{
1567 		set<const Part*> parts;
1568 		parts.insert(oPart);
1569 		parts.insert(nextPart);
1570 		return merge_parts(parts);
1571 	}
1572 	else
1573 		return false;
1574 }
1575 
merge_selected_parts()1576 bool merge_selected_parts()
1577 {
1578 	set<const Part*> temp = get_all_selected_parts();
1579 	return merge_parts(temp);
1580 }
1581 
merge_parts(const set<const Part * > & parts)1582 bool merge_parts(const set<const Part*>& parts)
1583 {
1584 	set<const Track*> tracks;
1585 	for (set<const Part*>::iterator it=parts.begin(); it!=parts.end(); it++)
1586 		tracks.insert( (*it)->track() );
1587 
1588 	Undo operations;
1589 
1590 	// process tracks separately
1591 	for (set<const Track*>::iterator t_it=tracks.begin(); t_it!=tracks.end(); t_it++)
1592 	{
1593 		const Track* track=*t_it;
1594 
1595 		unsigned begin=INT_MAX, end=0;
1596 		const Part* first_part=NULL;
1597 
1598 		// find begin of the first and end of the last part
1599 		for (set<const Part*>::iterator it=parts.begin(); it!=parts.end(); it++)
1600 			if ((*it)->track()==track)
1601 			{
1602 				const Part* p=*it;
1603 				if (p->tick() < begin)
1604 				{
1605 					begin=p->tick();
1606 					first_part=p;
1607 				}
1608 
1609 				if (p->endTick() > end)
1610 					end=p->endTick();
1611 			}
1612 
1613 		if (begin==INT_MAX || end==0)
1614 		{
1615 			printf("THIS SHOULD NEVER HAPPEN: begin==INT_MAX || end==0 in merge_parts()\n");
1616 			continue; // skip the actual work, as we cannot work under errornous conditions.
1617 		}
1618 
1619 		// create and prepare the new part
1620 		Part* new_part = first_part->duplicateEmpty();
1621 		new_part->setTick(begin);
1622 		new_part->setLenTick(end-begin);
1623 
1624 		// copy all events from the source parts into the new part
1625 		for (set<const Part*>::iterator p_it=parts.begin(); p_it!=parts.end(); p_it++)
1626 			if ((*p_it)->track()==track)
1627 			{
1628 				const EventList& old_el= (*p_it)->events();
1629 				for (ciEvent ev_it=old_el.begin(); ev_it!=old_el.end(); ev_it++)
1630 				{
1631 					Event new_event=ev_it->second.clone();
1632 					new_event.setTick( new_event.tick() + (*p_it)->tick() - new_part->tick() );
1633 					new_part->addEvent(new_event);
1634 				}
1635 			}
1636 
1637 		// delete all the source parts
1638 		for (set<const Part*>::iterator it=parts.begin(); it!=parts.end(); it++)
1639 			if ((*it)->track()==track)
1640 				operations.push_back( UndoOp(UndoOp::DeletePart, *it) );
1641 		// and add the new one
1642 		operations.push_back( UndoOp(UndoOp::AddPart, new_part) );
1643 	}
1644 
1645 	return MusEGlobal::song->applyOperationGroup(operations);
1646 }
1647 
split_part(const Part * part,int tick)1648 bool split_part(const Part* part, int tick)
1649 {
1650 	int l1 = tick - part->tick();
1651 	int l2 = part->lenTick() - l1;
1652 	if (l1 <= 0 || l2 <= 0)
1653 			return false;
1654 	Part* p1;
1655 	Part* p2;
1656 	part->splitPart(tick, p1, p2);
1657 
1658 	MusEGlobal::song->informAboutNewParts(part, p1);
1659 	MusEGlobal::song->informAboutNewParts(part, p2);
1660 
1661 	Undo operations;
1662 	operations.push_back(UndoOp(UndoOp::DeletePart, part));
1663 	operations.push_back(UndoOp(UndoOp::AddPart, p1));
1664 	operations.push_back(UndoOp(UndoOp::AddPart, p2));
1665 	return MusEGlobal::song->applyOperationGroup(operations);
1666 }
1667 
delete_selected_parts()1668 bool delete_selected_parts()
1669 {
1670 	Undo operations;
1671 	bool partSelected = false;
1672 
1673 	TrackList* tl = MusEGlobal::song->tracks();
1674 
1675 	for (iTrack it = tl->begin(); it != tl->end(); ++it)
1676 	{
1677 		PartList* pl = (*it)->parts();
1678 		for (iPart ip = pl->begin(); ip != pl->end(); ++ip)
1679 		{
1680 				if (ip->second->selected())
1681 				{
1682 					operations.push_back(UndoOp(UndoOp::DeletePart,ip->second));
1683 					partSelected = true;
1684 					}
1685 				}
1686 		}
1687 
1688 	MusEGlobal::song->applyOperationGroup(operations);
1689 
1690 	return partSelected;
1691 }
1692 
1693 
1694 //=============================================================================
1695 // BEGIN item-based functions
1696 //=============================================================================
1697 
1698 
1699 // For erasing existing target controller events before pasting source controller events.
1700 typedef std::pair<unsigned long /*t0*/, unsigned long /*t1*/ > PasteEraseMapInsertPair_t;
1701 typedef std::map<unsigned long /*t0*/, unsigned long /*t1*/> PasteEraseMap_t;
1702 typedef PasteEraseMap_t::iterator iPasteEraseMap;
1703 typedef PasteEraseMap_t::const_iterator ciPasteEraseMap;
1704 typedef std::pair<int /*ctlnum*/, PasteEraseMap_t > PasteEraseCtlMapPair_t;
1705 typedef std::map<int /*ctlnum*/, PasteEraseMap_t> PasteEraseCtlMap_t;
1706 typedef PasteEraseCtlMap_t::iterator iPasteEraseCtlMap;
1707 typedef PasteEraseCtlMap_t::const_iterator ciPasteEraseCtlMap;
1708 
1709 class PasteEraseCtlMap : public PasteEraseCtlMap_t
1710 {
1711   private:
1712     bool _erase_controllers_wysiwyg;
1713     bool _erase_controllers_inclusive;
1714 
1715   public:
PasteEraseCtlMap(bool erase_controllers_wysiwyg,bool erase_controllers_inclusive)1716     PasteEraseCtlMap(bool erase_controllers_wysiwyg,
1717                      bool erase_controllers_inclusive) :
1718                      _erase_controllers_wysiwyg(erase_controllers_wysiwyg),
1719                      _erase_controllers_inclusive(erase_controllers_inclusive) { }
1720 
1721     // Add an item. All ctl_time must be sorted beforehand.
1722     // Be sure to call tidy() after all items have been added.
1723     void add(int ctl_num, unsigned int ctl_time,
1724              unsigned int len_val);
1725     // Tidy up the very last items in the list.
1726     void tidy();
1727 };
1728 
add(int ctl_num,unsigned int ctl_time,unsigned int len_val)1729 void PasteEraseCtlMap::add(int ctl_num, unsigned int ctl_time,
1730                            unsigned int len_val)
1731 {
1732   unsigned long ctl_end_time;
1733 
1734   if(len_val > 0)
1735     ctl_end_time = ctl_time + len_val;
1736   else
1737     ctl_end_time = ctl_time + 1;
1738 
1739   iPasteEraseCtlMap icm = find(ctl_num);
1740   if(icm == end())
1741   {
1742     PasteEraseMap_t new_tmap;
1743     new_tmap.insert(PasteEraseMapInsertPair_t(ctl_time, ctl_end_time));
1744     insert(PasteEraseCtlMapPair_t(ctl_num, new_tmap));
1745   }
1746   else
1747   {
1748     PasteEraseMap_t& tmap = icm->second;
1749     // The event times must be sorted already. So this would always return end().
1750     //iPasteEraseMap itm = tmap.upper_bound(ctl_time);
1751     iPasteEraseMap itm = tmap.end();
1752 
1753     if(itm != tmap.begin())
1754     {
1755       --itm;
1756 
1757       iPasteEraseMap prev_itm_2 = tmap.end();
1758       if(itm != tmap.begin())
1759       {
1760         prev_itm_2 = itm;
1761         --prev_itm_2;
1762       }
1763 
1764       if((itm->second >= ctl_time) || _erase_controllers_inclusive)
1765       {
1766         if(_erase_controllers_inclusive)
1767                     itm->second = ctl_time;
1768 
1769         if(prev_itm_2 != tmap.end())
1770         {
1771           if((prev_itm_2->second >= itm->first) || _erase_controllers_inclusive)
1772           {
1773             prev_itm_2->second = itm->second;
1774             tmap.erase(itm);
1775           }
1776         }
1777 
1778         tmap.insert(PasteEraseMapInsertPair_t(ctl_time, ctl_end_time));
1779       }
1780       else
1781       {
1782         // If we want wysiwyg pasting, we erase existing events up to
1783         //  the end-time of the last tmap item which ended a contiguous
1784         //  'cluster' of items. Otherwise we ONLY erase UP TO AND INCLUDING
1785         //  the start-time of that last tmap item. So we 'truncate' that
1786         //  last item in the cluster by setting the end-time to the start-time,
1787         //  so that the gathering routine below knows to erase that last
1788         //  single-time position.
1789 
1790         if(!_erase_controllers_wysiwyg)
1791           itm->second = itm->first + 1;
1792 
1793         if(prev_itm_2 != tmap.end())
1794         {
1795           if(prev_itm_2->second >= itm->first)
1796           {
1797             prev_itm_2->second = itm->second;
1798             tmap.erase(itm);
1799           }
1800         }
1801 
1802         tmap.insert(PasteEraseMapInsertPair_t(ctl_time, ctl_end_time));
1803       }
1804     }
1805   }
1806 }
1807 
tidy()1808 void PasteEraseCtlMap::tidy()
1809 {
1810   // Tidy up the very last items in the list.
1811   for(iPasteEraseCtlMap icm = begin(); icm != end(); ++icm)
1812   {
1813     PasteEraseMap_t& tmap = icm->second;
1814     iPasteEraseMap itm = tmap.end();
1815     if(itm != tmap.begin())
1816     {
1817       --itm;
1818 
1819       if(!_erase_controllers_wysiwyg)
1820         itm->second = itm->first + 1;
1821 
1822       if(itm != tmap.begin())
1823       {
1824         iPasteEraseMap itm_2 = itm;
1825         --itm_2;
1826         if((itm_2->second >= itm->second) || _erase_controllers_inclusive)
1827         {
1828           itm_2->second = itm->second;
1829           tmap.erase(itm);
1830         }
1831       }
1832     }
1833   }
1834 }
1835 
erase_items(TagEventList * tag_list,int velo_threshold,bool velo_thres_used,int len_threshold,bool len_thres_used)1836 bool erase_items(TagEventList* tag_list, int velo_threshold, bool velo_thres_used, int len_threshold, bool len_thres_used)
1837 {
1838   Undo operations;
1839 
1840   const Part* part;
1841 
1842   for(ciTagEventList itl = tag_list->begin(); itl != tag_list->end(); ++itl)
1843   {
1844     part = itl->first;
1845     const EventList& el = itl->second.evlist();
1846     for(ciEvent ie = el.begin(); ie != el.end(); ie++)
1847     {
1848       // This operation can apply to any event.
1849       const Event& e = ie->second;
1850 
1851       // FIXME TODO Likely need agnostic Pos or frames rather than ticks if WaveCanvas is to use this.
1852       if ( e.type() != Note || (!velo_thres_used && !len_thres_used) ||
1853               (velo_thres_used && e.velo() < velo_threshold) ||
1854             (len_thres_used && int(e.lenTick()) < len_threshold) )
1855       {
1856         operations.push_back(UndoOp(UndoOp::DeleteEvent, e, part, true, true));
1857       }
1858     }
1859   }
1860 
1861   return MusEGlobal::song->applyOperationGroup(operations);
1862 }
1863 
crescendo_items(TagEventList * tag_list,int start_val,int end_val,bool absolute)1864 bool crescendo_items(TagEventList* tag_list, int start_val, int end_val, bool absolute)
1865 {
1866   const Pos& from = MusEGlobal::song->lPos();
1867   const Pos& to = MusEGlobal::song->rPos();
1868   if(to <= from)
1869     return false;
1870 
1871   Undo operations;
1872   Pos pos;
1873   float curr_val;
1874   unsigned int pos_val = (to - from).posValue();
1875   const Part* part;
1876 
1877   for(ciTagEventList itl = tag_list->begin(); itl != tag_list->end(); ++itl)
1878   {
1879     part = itl->first;
1880     const EventList& el = itl->second.evlist();
1881     for(ciEvent ie = el.begin(); ie != el.end(); ie++)
1882     {
1883       const Event& e = ie->second;
1884 
1885       // This operation can only apply to notes.
1886       if(e.type() != Note)
1887         continue;
1888 
1889       pos = e.pos() + *part;
1890       curr_val = (float)start_val + (float)(end_val - start_val) * (pos - from).posValue() / pos_val;
1891 
1892       Event newEvent = e.clone();
1893       int velo = e.velo();
1894 
1895       if (absolute)
1896         velo=curr_val;
1897       else
1898         velo=curr_val*velo/100;
1899 
1900       if (velo > 127) velo=127;
1901       if (velo <= 0) velo=1;
1902       newEvent.setVelo(velo);
1903 
1904       operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, e, part, false, false));
1905     }
1906   }
1907 
1908   return MusEGlobal::song->applyOperationGroup(operations);
1909 }
1910 
delete_overlaps_items(TagEventList * tag_list)1911 bool delete_overlaps_items(TagEventList* tag_list)
1912 {
1913   Undo operations;
1914 
1915   set<const Event*> deleted_events;
1916   int new_len;
1917   Event new_event1;
1918   const Part* part;
1919 
1920   for(ciTagEventList itl = tag_list->begin(); itl != tag_list->end(); ++itl)
1921   {
1922     part = itl->first;
1923     const EventList& el = itl->second.evlist();
1924     for(ciEvent ie = el.begin(); ie != el.end(); ie++)
1925     {
1926       const Event& e = ie->second;
1927 
1928       // This operation can only apply to notes.
1929       if(e.type() != Note)
1930         continue;
1931 
1932       // Has this event already been scheduled for deletion? Ignore it.
1933       if(deleted_events.find(&e) != deleted_events.end())
1934         continue;
1935 
1936       ciEvent ie2 = ie;
1937       ++ie2;
1938       for( ; ie2 != el.end(); ++ie2)
1939       {
1940         const Event& e2 = ie2->second;
1941         // This operation can only apply to notes.
1942         if(e2.type() != Note)
1943           continue;
1944 
1945         // Do e2 and e point to the same event? Or has e2 already been scheduled for deletion? Ignore it.
1946         if(e == e2 || deleted_events.find(&e2) != deleted_events.end())
1947           continue;
1948 
1949         if ( (e.pitch() == e2.pitch()) &&
1950             (e.tick() <= e2.tick()) &&
1951             (e.endTick() > e2.tick()) ) //they overlap
1952         {
1953           new_len = e2.tick() - e.tick();
1954 
1955           if(new_len==0)
1956           {
1957             operations.push_back(UndoOp(UndoOp::DeleteEvent, e2, part, false, false));
1958             deleted_events.insert(&e2);
1959           }
1960           else
1961           {
1962             new_event1 = e.clone();
1963             new_event1.setLenTick(new_len);
1964 
1965             operations.push_back(UndoOp(UndoOp::ModifyEvent, new_event1, e, part, false, false));
1966 
1967             // After resizing the event, it should not be necessary to continue with any further
1968             //  events in this loop since any more sorted events will come at or AFTER e2's position
1969             //  which we have just resized the end of e to.
1970             break;
1971           }
1972         }
1973       }
1974     }
1975   }
1976 
1977   return MusEGlobal::song->applyOperationGroup(operations);
1978 }
1979 
modify_notelen_items(TagEventList * tag_list,int rate,int offset)1980 bool modify_notelen_items(TagEventList* tag_list, int rate, int offset)
1981 {
1982   if(rate == 100 && offset == 0)
1983     return false;
1984 
1985   Undo operations;
1986 
1987   unsigned int len;
1988   map<const Part*, int> partlen;
1989   Event newEvent;
1990   const Part* part;
1991 
1992   for(ciTagEventList itl = tag_list->begin(); itl != tag_list->end(); ++itl)
1993   {
1994     part = itl->first;
1995     const EventList& el = itl->second.evlist();
1996     for(ciEvent ie = el.begin(); ie != el.end(); ie++)
1997     {
1998       const Event& e = ie->second;
1999 
2000       // This operation can only apply to notes.
2001       if(e.type() != Note)
2002         continue;
2003 
2004       len = e.lenTick(); //prevent compiler warning: comparison signed/unsigned
2005 
2006       len = (len * rate) / 100;
2007       len += offset;
2008 
2009       if (len <= 0)
2010         len = 1;
2011 
2012       if ((e.tick()+len > part->lenTick()) && (!(part->hasHiddenEvents() & Part::RightEventsHidden)))
2013         partlen[part] = e.tick() + len; // schedule auto-expanding
2014 
2015       if (e.lenTick() != len)
2016       {
2017         newEvent = e.clone();
2018         newEvent.setLenTick(len);
2019         operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, e, part, false, false));
2020       }
2021     }
2022 
2023     for (map<const Part*, int>::iterator it=partlen.begin(); it!=partlen.end(); it++)
2024       schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);
2025   }
2026 
2027   return MusEGlobal::song->applyOperationGroup(operations);
2028 }
2029 
legato_items(TagEventList * tag_list,int min_len,bool dont_shorten)2030 bool legato_items(TagEventList* tag_list, int min_len, bool dont_shorten)
2031 {
2032   Undo operations;
2033 
2034   if (min_len<=0) min_len=1;
2035 
2036   unsigned len = INT_MAX;
2037   bool relevant;
2038   Event new_event1;
2039   const Part* part;
2040 
2041   for(ciTagEventList itl = tag_list->begin(); itl != tag_list->end(); ++itl)
2042   {
2043     part = itl->first;
2044     const EventList& el = itl->second.evlist();
2045     for(ciEvent ie = el.begin(); ie != el.end(); ie++)
2046     {
2047       const Event& e = ie->second;
2048 
2049       // This operation can only apply to notes.
2050       if(e.type() != Note)
2051         continue;
2052 
2053       ciEvent ie2 = ie;
2054       ++ie2;
2055       for( ; ie2 != el.end(); ++ie2)
2056       {
2057         const Event& e2 = ie2->second;
2058         // This operation can only apply to notes.
2059         if(e2.type() != Note)
2060           continue;
2061 
2062         relevant = (e2.tick() >= e.tick() + min_len);
2063         if (dont_shorten)
2064           relevant = relevant && (e2.tick() >= e.endTick());
2065 
2066         if ( relevant &&                      // they're not too near (respect min_len and dont_shorten)
2067               (e2.tick() - e.tick() < len ) )  // that's the nearest relevant following note
2068           len = e2.tick() - e.tick();
2069       }
2070 
2071       if (len==INT_MAX) len = e.lenTick(); // if no following note was found, keep the length
2072 
2073       if (e.lenTick() != len)
2074       {
2075         new_event1 = e.clone();
2076         new_event1.setLenTick(len);
2077 
2078         operations.push_back(UndoOp(UndoOp::ModifyEvent, new_event1, e, part, false, false));
2079       }
2080     }
2081   }
2082 
2083   return MusEGlobal::song->applyOperationGroup(operations);
2084 }
2085 
move_items(TagEventList * tag_list,signed int ticks)2086 bool move_items(TagEventList* tag_list, signed int ticks)
2087 {
2088   if(ticks == 0)
2089     return false;
2090 
2091   Undo operations;
2092   map<const Part*, int> partlen;
2093 
2094   bool del;
2095   Event newEvent;
2096   const Part* part;
2097 
2098   for(ciTagEventList itl = tag_list->begin(); itl != tag_list->end(); ++itl)
2099   {
2100     part = itl->first;
2101     const EventList& el = itl->second.evlist();
2102     for(ciEvent ie = el.begin(); ie != el.end(); ie++)
2103     {
2104       const Event& e = ie->second;
2105 
2106       del = false;
2107 
2108       // This operation can only apply to notes.
2109       if(e.type() != Note)
2110         continue;
2111 
2112       newEvent = e.clone();
2113       if ((signed)e.tick() + ticks < 0) //don't allow moving before the part's begin
2114         newEvent.setTick(0);
2115       else
2116         newEvent.setTick(e.tick() + ticks);
2117 
2118       if (newEvent.endTick() > part->lenTick()) //if exceeding the part's end:
2119       {
2120         if (part->hasHiddenEvents() & Part::RightEventsHidden) // auto-expanding is forbidden, clip
2121         {
2122           if (part->lenTick() > newEvent.tick())
2123             newEvent.setLenTick(part->lenTick() - newEvent.tick());
2124           else
2125             del = true; //if the new length would be <= 0, erase the note
2126         }
2127         else
2128           partlen[part] = newEvent.endTick(); // schedule auto-expanding
2129       }
2130 
2131       if (del == false)
2132         operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, e, part, false, false));
2133       else
2134         operations.push_back(UndoOp(UndoOp::DeleteEvent, e, part, false, false));
2135     }
2136 
2137     for (map<const Part*, int>::iterator it=partlen.begin(); it!=partlen.end(); it++)
2138       schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);
2139   }
2140 
2141   return MusEGlobal::song->applyOperationGroup(operations);
2142 }
2143 
quantize_items(TagEventList * tag_list,int raster_idx,bool quant_len,int strength,int swing,int threshold)2144 bool quantize_items(TagEventList* tag_list, int raster_idx, bool quant_len, int strength, int swing, int threshold)
2145 {
2146   const int rv = MusEGui::functionQuantizeRasterVals[raster_idx];
2147   if(rv <= 0)
2148     return false;
2149 
2150   const int raster = (MusEGlobal::config.division*4) / rv;
2151 
2152   Undo operations;
2153 
2154   unsigned begin_tick;
2155   int begin_diff;
2156   unsigned len;
2157   unsigned end_tick;
2158   int len_diff;
2159   Event newEvent;
2160   const Part* part;
2161 
2162   for(ciTagEventList itl = tag_list->begin(); itl != tag_list->end(); ++itl)
2163   {
2164     part = itl->first;
2165     const EventList& el = itl->second.evlist();
2166     for(ciEvent ie = el.begin(); ie != el.end(); ie++)
2167     {
2168       const Event& e = ie->second;
2169 
2170       // This operation can only apply to notes.
2171       if(e.type() != Note)
2172         continue;
2173 
2174       begin_tick = e.tick() + part->tick();
2175       begin_diff = quantize_tick(begin_tick, raster, swing) - begin_tick;
2176 
2177       if (abs(begin_diff) > threshold)
2178         begin_tick = begin_tick + begin_diff*strength/100;
2179 
2180       len = e.lenTick();
2181 
2182       end_tick = begin_tick + len;
2183       len_diff = quantize_tick(end_tick, raster, swing) - end_tick;
2184 
2185       if ((abs(len_diff) > threshold) && quant_len)
2186         len = len + len_diff*strength/100;
2187 
2188       if (len <= 0)
2189         len = 1;
2190 
2191 
2192       if ( (e.lenTick() != len) || (e.tick() + part->tick() != begin_tick) )
2193       {
2194         newEvent = e.clone();
2195         newEvent.setTick(begin_tick - part->tick());
2196         newEvent.setLenTick(len);
2197         operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, e, part, false, false));
2198       }
2199     }
2200   }
2201 
2202   return MusEGlobal::song->applyOperationGroup(operations);
2203 }
2204 
set_notelen_items(TagEventList * tag_list,int len)2205 bool set_notelen_items(TagEventList* tag_list, int len)
2206 {
2207   return modify_notelen_items(tag_list, 0, len);
2208 }
2209 
transpose_items(TagEventList * tag_list,signed int halftonesteps)2210 bool transpose_items(TagEventList* tag_list, signed int halftonesteps)
2211 {
2212   if(halftonesteps == 0)
2213     return false;
2214 
2215   Undo operations;
2216 
2217   Event newEvent;
2218   int pitch;
2219   const Part* part;
2220 
2221   for(ciTagEventList itl = tag_list->begin(); itl != tag_list->end(); ++itl)
2222   {
2223     part = itl->first;
2224     const EventList& el = itl->second.evlist();
2225     for(ciEvent ie = el.begin(); ie != el.end(); ie++)
2226     {
2227       const Event& e = ie->second;
2228 
2229       // This operation can only apply to notes.
2230       if(e.type() != Note)
2231         continue;
2232 
2233       newEvent = e.clone();
2234       pitch = e.pitch() + halftonesteps;
2235       if (pitch > 127) pitch = 127;
2236       if (pitch < 0) pitch = 0;
2237       newEvent.setPitch(pitch);
2238       operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, e, part, false, false));
2239     }
2240   }
2241 
2242   return MusEGlobal::song->applyOperationGroup(operations);
2243 }
2244 
modify_velocity_items(TagEventList * tag_list,int rate,int offset)2245 bool modify_velocity_items(TagEventList* tag_list, int rate, int offset)
2246 {
2247   if(rate == 100 && offset == 0)
2248     return false;
2249 
2250   Undo operations;
2251   int velo;
2252   Event newEvent;
2253   const Part* part;
2254 
2255   for(ciTagEventList itl = tag_list->begin(); itl != tag_list->end(); ++itl)
2256   {
2257     part = itl->first;
2258     const EventList& el = itl->second.evlist();
2259     for(ciEvent ie = el.begin(); ie != el.end(); ie++)
2260     {
2261       const Event& e = ie->second;
2262 
2263       // This operation can only apply to notes.
2264       if(e.type() != Note)
2265         continue;
2266 
2267       velo = e.velo();
2268 
2269       velo = (velo * rate) / 100;
2270       velo += offset;
2271 
2272       if (velo <= 0)
2273         velo = 1;
2274       else if (velo > 127)
2275         velo = 127;
2276 
2277       if (e.velo() != velo)
2278       {
2279         newEvent = e.clone();
2280         newEvent.setVelo(velo);
2281         operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, e, part, false, false));
2282       }
2283     }
2284   }
2285 
2286   return MusEGlobal::song->applyOperationGroup(operations);
2287 }
2288 
modify_off_velocity_items(TagEventList * tag_list,int rate,int offset)2289 bool modify_off_velocity_items(TagEventList* tag_list, int rate, int offset)
2290 {
2291   if(rate == 100 && offset == 0)
2292     return false;
2293 
2294   Undo operations;
2295   int velo;
2296   Event newEvent;
2297   const Part* part;
2298 
2299   for(ciTagEventList itl = tag_list->begin(); itl != tag_list->end(); ++itl)
2300   {
2301     part = itl->first;
2302     const EventList& el = itl->second.evlist();
2303     for(ciEvent ie = el.begin(); ie != el.end(); ie++)
2304     {
2305       const Event& e = ie->second;
2306 
2307       // This operation can only apply to notes.
2308       if(e.type() != Note)
2309         continue;
2310 
2311       velo = e.veloOff();
2312 
2313       velo = (velo * rate) / 100;
2314       velo += offset;
2315 
2316       if (velo <= 0)
2317         velo = 1;
2318       else if (velo > 127)
2319         velo = 127;
2320 
2321       if (e.veloOff() != velo)
2322       {
2323         newEvent = e.clone();
2324         newEvent.setVeloOff(velo);
2325         operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, e, part, false, false));
2326       }
2327     }
2328   }
2329 
2330   return MusEGlobal::song->applyOperationGroup(operations);
2331 }
2332 
copy_items(TagEventList * tag_list)2333 void copy_items(TagEventList* tag_list)
2334 {
2335  QMimeData* drag = cut_or_copy_tagged_items_to_mime(tag_list);
2336 
2337  if (drag)
2338    QApplication::clipboard()->setMimeData(drag, QClipboard::Clipboard);
2339 }
2340 
cut_items(TagEventList * tag_list)2341 bool cut_items(TagEventList* tag_list)
2342 {
2343   QMimeData* drag = cut_or_copy_tagged_items_to_mime(tag_list, true);
2344 
2345   if(drag)
2346   {
2347     QApplication::clipboard()->setMimeData(drag, QClipboard::Clipboard);
2348     return true;
2349   }
2350 
2351   return false;
2352 }
2353 
2354 // if nothing is selected/relevant, this function returns NULL
cut_or_copy_tagged_items_to_mime(TagEventList * tag_list,bool cut_mode)2355 QMimeData* cut_or_copy_tagged_items_to_mime(TagEventList* tag_list, bool cut_mode)
2356 {
2357     if(tag_list->empty())
2358       return NULL;
2359 
2360     QTemporaryFile tmp;
2361     if(!tmp.open())
2362     {
2363         fprintf(stderr, "cut_or_copy_tagged_items_to_mime(): ERROR: Failed to open temporary file\n");
2364         return NULL;
2365     }
2366 
2367     const Pos start_pos = tag_list->globalStats().evrange();
2368 
2369     Undo operations;
2370 
2371     bool changed = false;
2372     const Part* part;
2373 
2374     //---------------------------------------------------
2375     //    write events as XML into tmp file
2376     //---------------------------------------------------
2377 
2378     Xml xml(&tmp);
2379     int level = 0;
2380 
2381     for(ciTagEventList itl = tag_list->begin(); itl != tag_list->end(); ++itl)
2382     {
2383       part = itl->first;
2384       const EventList& el = itl->second.evlist();
2385       if(el.empty())
2386         continue;
2387 
2388       xml.tag(level++, "eventlist part_id=\"%d\"", part->sn());
2389       for(ciEvent ie = el.begin(); ie != el.end(); ie++)
2390       {
2391         const Event& e = ie->second;
2392         Event ne = e.clone();
2393         ne.setPos(ne.pos() - start_pos);
2394         ne.write(level, xml, Pos(0, e.pos().type() == Pos::TICKS));
2395         if(cut_mode)
2396         {
2397           changed = true;
2398           operations.push_back(UndoOp(UndoOp::DeleteEvent, e, part, true, true));
2399         }
2400       }
2401       xml.etag(--level, "eventlist");
2402     }
2403 
2404     tmp.flush();
2405     tmp.seek(0);
2406     const QByteArray data = tmp.readAll();
2407     QMimeData* mimeData = new QMimeData();
2408     mimeData->setData("text/x-muse-groupedeventlists", data);
2409 
2410     if(changed)
2411       MusEGlobal::song->applyOperationGroup(operations);
2412 
2413     return mimeData;
2414 }
2415 
paste_items(const std::set<const Part * > & parts,const Part * paste_into_part)2416 bool paste_items(const std::set<const Part*>& parts, const Part* paste_into_part)
2417 {
2418 	unsigned temp_begin = MusEGlobal::sigmap.raster1(MusEGlobal::song->cpos(),0);
2419 	unsigned temp_end = MusEGlobal::sigmap.raster2(temp_begin + get_clipboard_len(), 0);
2420 	MusEGui::paste_events_dialog->raster = temp_end - temp_begin;
2421 	MusEGui::paste_events_dialog->into_single_part_allowed = (paste_into_part!=NULL);
2422 
2423 	if (!MusEGui::paste_events_dialog->exec())
2424 		return false;
2425 
2426 	paste_items(parts, MusEGui::paste_events_dialog->max_distance,
2427 							FunctionOptionsStruct(
2428 								(MusEGui::paste_events_dialog->ctrl_erase ?             FunctionEraseItems : FunctionNoOptions)
2429 								| (MusEGui::paste_events_dialog->ctrl_erase_wysiwyg ?   FunctionEraseItemsWysiwyg : FunctionNoOptions)
2430 								| (MusEGui::paste_events_dialog->ctrl_erase_inclusive ? FunctionEraseItemsInclusive : FunctionNoOptions)
2431 								| (MusEGui::paste_events_dialog->always_new_part ?      FunctionPasteAlwaysNewPart : FunctionNoOptions)
2432 								| (MusEGui::paste_events_dialog->never_new_part ?       FunctionPasteNeverNewPart : FunctionNoOptions)),
2433 							MusEGui::paste_events_dialog->into_single_part ? paste_into_part : NULL,
2434 							MusEGui::paste_events_dialog->number, MusEGui::paste_events_dialog->raster,
2435 							AllEventsRelevant,
2436 							-1 /*paste to ctrl num*/
2437 							);
2438 
2439 	return true;
2440 }
2441 
paste_items(const set<const Part * > & parts,int max_distance,const FunctionOptionsStruct & options,const Part * paste_into_part,int amount,int raster,RelevantSelectedEvents_t relevant,int paste_to_ctrl_num)2442 void paste_items(const set<const Part*>& parts, int max_distance,
2443 								 const FunctionOptionsStruct& options,
2444 								 const Part* paste_into_part, int amount, int raster,
2445 								 RelevantSelectedEvents_t relevant,
2446 								 int paste_to_ctrl_num
2447 								 )
2448 {
2449 	QString tmp="x-muse-groupedeventlists"; // QClipboard::text() expects a QString&, not a QString :(
2450 	QString s = QApplication::clipboard()->text(tmp, QClipboard::Clipboard);
2451 	paste_items_at(parts, s, MusEGlobal::song->cPos(), max_distance, options,
2452 								paste_into_part, amount, raster, relevant, paste_to_ctrl_num
2453 								);
2454 }
2455 
pasteEventList(const EventList & el,const Pos & pos,Part * dest_part,Undo & operations,Undo & add_operations,expand_map_t & expand_map,new_part_map_t & new_part_map,const Part * source_part=nullptr,bool erase_source=false,const Pos & start_pos=Pos (),int max_distance=3072,const FunctionOptionsStruct & options=FunctionOptionsStruct (),int amount=1,int raster=3072,const RelevantSelectedEvents_t relevant=AllEventsRelevant,int paste_to_ctrl_num=-1)2456 void pasteEventList(
2457   const EventList& el,
2458   const Pos& pos,
2459   Part* dest_part,
2460   Undo& operations,
2461   Undo& add_operations,
2462   expand_map_t& expand_map,
2463   new_part_map_t& new_part_map,
2464   // The source part where the event list came from, in case
2465   //  the erase_source argument is true.
2466   const Part* source_part = nullptr,
2467   // Whether to erase ('cut') the source events after pasting.
2468   bool erase_source = false,
2469   const Pos& start_pos = Pos(),
2470   int max_distance=3072,
2471   // Options. Default is erase target existing controllers first + erase wysiwyg.
2472   const FunctionOptionsStruct& options = FunctionOptionsStruct(),
2473   // Number of copies to paste.
2474   int amount=1,
2475   // Separation between copies.
2476   int raster=3072,
2477   // Choose which events to paste.
2478   const RelevantSelectedEvents_t relevant = AllEventsRelevant,
2479   // If pasting controllers, paste into this controller number if not -1.
2480   // If the source has multiple controllers, user will be asked which one to paste.
2481   int paste_to_ctrl_num = -1
2482   )
2483 {
2484   const bool wave_mode = dest_part->partType() == Part::WavePartType;
2485 
2486   int num_events;
2487   PosLen el_range = el.evrange(wave_mode, relevant, &num_events, paste_to_ctrl_num);
2488   if(num_events <= 0)
2489     return;
2490 
2491   const bool always_new_part             = options._flags & FunctionPasteAlwaysNewPart;
2492   const bool never_new_part              = options._flags & FunctionPasteNeverNewPart;
2493   const bool erase_controllers           = options._flags & FunctionEraseItems;
2494   const bool erase_controllers_wysiwyg   = options._flags & FunctionEraseItemsWysiwyg;
2495   const bool erase_controllers_inclusive = options._flags & FunctionEraseItemsInclusive;
2496 
2497   const Pos::TType time_type = wave_mode ? Pos::FRAMES : Pos::TICKS;
2498   Track* dest_track = NULL;
2499   const Part* old_dest_part = NULL;
2500 
2501   // Be sure to subtract the position of the very first event of interest.
2502   // This is exactly what the copy/cut functions do before they write the results
2503   //  to an output file. But here the events in the directly-passed source list
2504   //  cannot be time-modified beforehand. So here we subtract this start position:
2505   el_range -= start_pos;
2506 
2507   const unsigned pos_value = pos.posValue(time_type);
2508   unsigned dest_part_pos_value = dest_part->posValue(time_type);
2509   unsigned dest_part_end_value = dest_part->end().posValue(time_type);
2510   dest_track=dest_part->track();
2511   old_dest_part=dest_part;
2512   unsigned first_paste_pos_value = el_range.posValue() + pos_value;
2513   bool create_new_part = ( (first_paste_pos_value < dest_part_pos_value) || // dest_part begins too late
2514       ( ( (dest_part_end_value + max_distance < first_paste_pos_value) ||   // dest_part is too far away
2515                           always_new_part ) && !never_new_part ) );    // respect function arguments
2516 
2517   for (int i=0;i<amount;i++)
2518   {
2519     unsigned curr_pos = pos_value + i*raster;
2520     first_paste_pos_value = el_range.posValue() + curr_pos;
2521 
2522     if (create_new_part)
2523     {
2524       dest_part = NULL;
2525       Part* newpart = dest_track->newPart();
2526       if(newpart)
2527       {
2528         // TODO: Shouldn't we snap to frames for wave parts? But snap to what exactly?
2529         const unsigned pos_tick = Pos(first_paste_pos_value, !wave_mode).tick();
2530         const unsigned rast_pos_tick = MusEGlobal::sigmap.raster1(pos_tick, config.division);
2531         newpart->setTick(rast_pos_tick);
2532         const unsigned len_rast_off_value = pos_tick >= rast_pos_tick ? pos_tick - rast_pos_tick : 0;
2533         newpart->setLenValue(el_range.lenValue() + len_rast_off_value, time_type);
2534         dest_part = newpart;
2535         dest_part_pos_value = dest_part->posValue(time_type);
2536         dest_part_end_value = dest_part->end().posValue(time_type);
2537         new_part_map[old_dest_part].insert(dest_part);
2538         add_operations.push_back(UndoOp(UndoOp::AddPart, dest_part));
2539       }
2540     }
2541 
2542     if(!dest_part)
2543       continue;
2544 
2545     // This will be filled as we go.
2546     PasteEraseCtlMap ctl_map(erase_controllers_wysiwyg, erase_controllers_inclusive);
2547 
2548     const unsigned dest_part_len_value = dest_part->lenValue(time_type);
2549     for (ciEvent i = el.cbegin(); i != el.cend(); ++i)
2550     {
2551       const Event& old_e = i->second;
2552 
2553       // If the destination part is a midi part, any midi event is allowed.
2554       // If the destination part is a wave part, any wave event is allowed.
2555       switch(old_e.type())
2556       {
2557         case Note:
2558           if(!(relevant & NotesRelevant) || dest_part->type() == Pos::FRAMES)
2559             continue;
2560         break;
2561 
2562         case Controller:
2563           if(!(relevant & ControllersRelevant) || dest_part->type() == Pos::FRAMES ||
2564               (paste_to_ctrl_num >= 0 && paste_to_ctrl_num != old_e.dataA()))
2565             continue;
2566         break;
2567 
2568         case Sysex:
2569           if(!(relevant & SysexRelevant) || dest_part->type() == Pos::FRAMES)
2570             continue;
2571         break;
2572 
2573         case Meta:
2574           if(!(relevant & MetaRelevant) || dest_part->type() == Pos::FRAMES)
2575             continue;
2576         break;
2577 
2578         case Wave:
2579           if(!(relevant & WaveRelevant) || dest_part->type() == Pos::TICKS)
2580             continue;
2581         break;
2582       }
2583 
2584       Event e = old_e.clone();
2585       unsigned tick = e.posValue(time_type) + curr_pos;
2586 
2587       // Be sure to subtract the position of the very first event of interest.
2588       const unsigned sp_val = start_pos.posValue(time_type);
2589       if(tick >= sp_val)
2590         tick -= sp_val;
2591       else
2592       {
2593         printf("WARNING: paste_items_at(): Should not happen: event pos value: %u less than start pos value: %u\n",
2594                 tick, sp_val);
2595         tick = 0;
2596       }
2597 
2598       if (tick < dest_part_pos_value)
2599       //if (tick.posValue() < 0)
2600       {
2601         printf("ERROR: paste_items_at(): trying to add event before current part! ignoring this event\n");
2602         continue;
2603       }
2604       tick -= dest_part_pos_value;
2605 
2606       e.setPosValue(tick, time_type);
2607       e.setSelected(true);  // No need to select clones, AddEvent operation below will take care of that.
2608 
2609       // Don't bother with expansion if these are new parts.
2610       if (!create_new_part && e.endPosValue() > dest_part_len_value) // event exceeds part?
2611       {
2612         if (dest_part->hasHiddenEvents() & Part::RightEventsHidden) // auto-expanding is forbidden?
2613         {
2614           if (e.posValue(time_type) < dest_part_len_value)
2615             e.setLenValue(dest_part_len_value - e.posValue(time_type), time_type); // clip
2616           else
2617             e.setLenValue(0, time_type); // don't insert that note at all
2618         }
2619         else
2620         {
2621           if (e.endPosValue() > expand_map[dest_part])
2622             expand_map[dest_part]=e.endPosValue();
2623         }
2624       }
2625 
2626       switch(e.type())
2627       {
2628         case Note:
2629           // Don't add Note event types if they have no length.
2630           // Notes are allowed to overlap. There is no DeleteEvent or ModifyEvent first.
2631           //if(e.lenTick() != 0)
2632           //{
2633             // If this is a fresh new part, to avoid double operation warnings when undoing
2634             //  just add the event directly to the part instead of an operation.
2635             if(create_new_part)
2636               ((Part*)dest_part)->addEvent(e);
2637             else
2638               add_operations.push_back(UndoOp(UndoOp::AddEvent, e, dest_part, false, false));
2639           //}
2640         break;
2641 
2642         case Wave:
2643           // Don't add Wave event types if they have no length.
2644           //if(e.lenFrame() != 0)
2645           //{
2646             // If this is a fresh new part, to avoid double operation warnings when undoing
2647             //  just add the event directly to the part instead of an operation.
2648             if(create_new_part)
2649             {
2650               ((Part*)dest_part)->addEvent(e);
2651             }
2652             else
2653             {
2654               EventList s_el;
2655               // Compare time, and wave position, path, and start position.
2656               dest_part->events().findSimilarType(e, s_el, true, false, false, false,
2657                                                   true, true, true);
2658               // Do NOT add the new wave event if it already exists at the position.
2659               // Don't event bother replacing it using DeletEvent or ModifyEvent.
2660               if(s_el.empty())
2661               {
2662                 add_operations.push_back(UndoOp(UndoOp::AddEvent, e, dest_part, false, false));
2663               }
2664               else
2665               {
2666                 // Delete all but one of them. There shouldn't be more than one wave event
2667                 //  at a time for a given wave event anyway.
2668                 ciEvent nie;
2669                 for(ciEvent ie = s_el.cbegin(); ie != s_el.cend(); ++ie)
2670                 {
2671                   // Break on the second-last one, to leave one item intact.
2672                   nie = ie;
2673                   ++nie;
2674                   if(nie == s_el.end())
2675                   {
2676                     break;
2677                   }
2678 
2679                   // If we are 'cutting' the source events, and the source and destination parts
2680                   //  are the same, and the cut and erase events are the same, don't push the
2681                   //  deletes here. Let the cutting section at the end of the routine take do it.
2682                   if(!erase_source || source_part != dest_part || el.findId(ie->second) == el.end())
2683                     operations.push_back(UndoOp(UndoOp::DeleteEvent, ie->second, dest_part, false, false));
2684                 }
2685               }
2686             }
2687           //}
2688         break;
2689 
2690         case Controller:
2691         {
2692           // HACK Grab the event length since we use it for indicating
2693           //       the visual width when tagging controller items.
2694           const unsigned int len_val = e.lenValue();
2695           // Be sure to reset this always since we use it for the above hack.
2696           e.setLenValue(0);
2697 
2698           // If this is a fresh new part, to avoid double DeleteMidiCtrlVal warnings when undoing
2699           //  just add the event directly to the part instead of an operation.
2700           if(create_new_part)
2701           {
2702             ((Part*)dest_part)->addEvent(e);
2703           }
2704           else
2705           {
2706             // If we are erasing existing controller values first, this block will
2707             //  take care of all of the erasures. But even if we are NOT specifically
2708             //  erasing first, we still MUST erase any existing controller values found
2709             //  at that exact time value. So that is done in the next block.
2710             if(erase_controllers)
2711             {
2712               ctl_map.add(e.dataA(), e.posValue(), len_val);
2713             }
2714             else
2715             // Here we are not specifically erasing first. But we still MUST erase any
2716             //  existing controller values found at that exact time value.
2717             {
2718               EventList s_el;
2719               // Compare time and controller number (data A) only.
2720               dest_part->events().findSimilarType(e, s_el, true, true);
2721               // Delete them all. There shouldn't be more than one controller event
2722               //  at a time for a given controller number anyway.
2723               for(ciEvent ie = s_el.cbegin(); ie != s_el.cend(); ++ie)
2724               {
2725                 // If we are 'cutting' the source events, and the source and destination parts
2726                 //  are the same, and the cut and erase events are the same, don't push the
2727                 //  deletes here. Let the cutting section at the end of the routine take do it.
2728                 if(!erase_source || source_part != dest_part || el.findId(ie->second) == el.end())
2729                   // Do port controller values and clone parts.
2730                   operations.push_back(UndoOp(UndoOp::DeleteEvent, ie->second, dest_part, true, true));
2731               }
2732             }
2733             // Do port controller values and clone parts.
2734             add_operations.push_back(UndoOp(UndoOp::AddEvent, e, dest_part, true, true));
2735           }
2736         }
2737         break;
2738 
2739         case Sysex:
2740         {
2741           // If this is a fresh new part, to avoid double operation warnings when undoing
2742           //  just add the event directly to the part instead of an operation.
2743           if(create_new_part)
2744           {
2745             ((Part*)dest_part)->addEvent(e);
2746           }
2747           else
2748           {
2749             EventList s_el;
2750             // Compare time and sysex data only.
2751             dest_part->events().findSimilarType(e, s_el, true);
2752             // Do NOT add the new sysex if it already exists at the position.
2753             // Don't event bother replacing it using DeletEvent or ModifyEvent.
2754             if(s_el.empty())
2755             {
2756               add_operations.push_back(UndoOp(UndoOp::AddEvent, e, dest_part, false, false));
2757             }
2758             else
2759             {
2760               // Delete all but one of them. There shouldn't be more than one sysex event
2761               //  at a time for a given sysex anyway.
2762               ciEvent nie;
2763               for(ciEvent ie = s_el.cbegin(); ie != s_el.cend(); ++ie)
2764               {
2765                 // Break on the second-last one, to leave one item intact.
2766                 nie = ie;
2767                 ++nie;
2768                 if(nie == s_el.end())
2769                 {
2770                   break;
2771                 }
2772 
2773                 // If we are 'cutting' the source events, and the source and destination parts
2774                 //  are the same, and the cut and erase events are the same, don't push the
2775                 //  deletes here. Let the cutting section at the end of the routine take do it.
2776                 if(!erase_source || source_part != dest_part || el.findId(ie->second) == el.end())
2777                   operations.push_back(UndoOp(UndoOp::DeleteEvent, ie->second, dest_part, false, false));
2778               }
2779             }
2780           }
2781         }
2782         break;
2783 
2784         case Meta:
2785         {
2786           // If this is a fresh new part, to avoid double operation warnings when undoing
2787           //  just add the event directly to the part instead of an operation.
2788           if(create_new_part)
2789           {
2790             ((Part*)dest_part)->addEvent(e);
2791           }
2792           else
2793           {
2794             EventList s_el;
2795             // Compare time and meta data only.
2796             dest_part->events().findSimilarType(e, s_el, true);
2797             // Do NOT add the new meta if it already exists at the position.
2798             // Don't event bother replacing it using DeletEvent or ModifyEvent.
2799             if(s_el.empty())
2800             {
2801               add_operations.push_back(UndoOp(UndoOp::AddEvent, e, dest_part, false, false));
2802             }
2803             else
2804             {
2805               // Delete all but one of them. There shouldn't be more than one meta event
2806               //  at a time for a given meta anyway.
2807               ciEvent nie;
2808               for(ciEvent ie = s_el.cbegin(); ie != s_el.cend(); ++ie)
2809               {
2810                 // Break on the second-last one, to leave one item intact.
2811                 nie = ie;
2812                 ++nie;
2813                 if(nie == s_el.end())
2814                 {
2815                   break;
2816                 }
2817 
2818                 // If we are 'cutting' the source events, and the source and destination parts
2819                 //  are the same, and the cut and erase events are the same, don't push the
2820                 //  deletes here. Let the cutting section at the end of the routine take do it.
2821                 if(!erase_source || source_part != dest_part || el.findId(ie->second) == el.end())
2822                   operations.push_back(UndoOp(UndoOp::DeleteEvent, ie->second, dest_part, false, false));
2823               }
2824             }
2825           }
2826         }
2827         break;
2828       }
2829     }
2830 
2831     // If this is not a fresh new part, gather the operations to
2832     //  erase existing controller events in the destination part.
2833     if(erase_controllers && !create_new_part && dest_part && !ctl_map.empty())
2834     {
2835       // Tidy up the very last items in the list.
2836       ctl_map.tidy();
2837 
2838       unsigned e_pos;
2839       const EventList& er_el = dest_part->events();
2840       for(ciEvent ie = er_el.cbegin(); ie != er_el.cend(); ++ie)
2841       {
2842         const Event& er_e = ie->second;
2843         if(er_e.type() != Controller)
2844           continue;
2845 
2846         ciPasteEraseCtlMap icm = ctl_map.find(er_e.dataA());
2847         if(icm == ctl_map.end())
2848           continue;
2849 
2850         const PasteEraseMap_t& tmap = icm->second;
2851         e_pos = er_e.posValue();
2852         ciPasteEraseMap itm = tmap.upper_bound(e_pos);
2853         if(itm == tmap.begin())
2854           continue;
2855 
2856         --itm;
2857         if(e_pos >= itm->first && e_pos < itm->second)
2858         {
2859           // If we are 'cutting' the source events, and the source and destination parts
2860           //  are the same, and the cut and erase events are the same, don't push the
2861           //  deletes here. Let the cutting section at the end of the routine take do it.
2862           if(!erase_source || source_part != dest_part || el.findId(er_e) == el.end())
2863             operations.push_back(UndoOp(UndoOp::DeleteEvent, er_e, dest_part, true, true));
2864         }
2865       }
2866     }
2867   }
2868 
2869   // Do we want to cut the items as well?
2870   if(erase_source && source_part)
2871   {
2872     for(ciEvent i = el.cbegin(); i != el.cend(); ++i)
2873     {
2874       const Event& old_e = i->second;
2875       operations.push_back(UndoOp(UndoOp::DeleteEvent, old_e, source_part, true, true));
2876     }
2877   }
2878 }
2879 
paste_items_at(const std::set<const Part * > & parts,const QString & pt,const Pos & pos,int max_distance,const FunctionOptionsStruct & options,const Part * paste_into_part,int amount,int raster,RelevantSelectedEvents_t relevant,int paste_to_ctrl_num)2880 void paste_items_at(const std::set<const Part*>& parts, const QString& pt, const Pos& pos, int max_distance,
2881                     const FunctionOptionsStruct& options,
2882                     const Part* paste_into_part, int amount, int raster,
2883                     RelevantSelectedEvents_t relevant,
2884                     int paste_to_ctrl_num)
2885 {
2886   // To maximize speed and minimize memory use, the processing below
2887   //  can only find any delete operations AFTER it has gathered
2888   //  add operations. So we keep two separate operations lists and
2889   //  combine them later so that all the deletes come BEFORE all the adds.
2890   Undo add_operations, operations;
2891 
2892   map<const Part*, unsigned> expand_map;
2893   map<const Part*, set<const Part*> > new_part_map;
2894 
2895   QByteArray pt_= pt.toLatin1();
2896   Xml xml(pt_.constData());
2897   for (;;)
2898   {
2899     Xml::Token token = xml.parse();
2900     const QString& tag = xml.s1();
2901     switch (token)
2902     {
2903       case Xml::Error:
2904       case Xml::End:
2905         goto out_of_paste_at_for;
2906 
2907       case Xml::TagStart:
2908         if (tag == "eventlist")
2909         {
2910           EventList el;
2911           int part_id;
2912 
2913           if (!read_eventlist_and_part(xml, &el, &part_id))
2914           {
2915             printf("ERROR: reading eventlist from clipboard failed. ignoring this one...\n");
2916             break;
2917           }
2918 
2919           const Part* dest_part;
2920           if (paste_into_part == NULL)
2921             dest_part = partFromSerialNumber(part_id);
2922           else
2923             dest_part=paste_into_part;
2924 
2925           if (dest_part == NULL)
2926           {
2927             printf("ERROR: destination part wasn't found. ignoring these events\n");
2928             break;
2929           }
2930 
2931           // Paste into the destination part ONLY if it is included in the given set of parts,
2932           //  typically the parts used by an editor window instance's canvas. (WYSIWYG).
2933           // Override if paste_into_part is given, to allow 'Paste to current part' to work.
2934           if(!paste_into_part && parts.find(dest_part) == parts.end())
2935             break;
2936 
2937           const bool wave_mode = dest_part->partType() == Part::WavePartType;
2938 
2939           FindMidiCtlsList_t ctrlList;
2940           el.findControllers(wave_mode, &ctrlList);
2941           int ctrlsFound = 0;
2942           if(!ctrlList.empty())
2943             ctrlsFound = ctrlList.size();
2944           if(paste_to_ctrl_num >= 0 && ctrlsFound > 0)
2945           {
2946             // TODO Dialog for choosing which controller to paste.
2947           }
2948 
2949           pasteEventList(
2950             el, pos, ((Part*)dest_part), operations, add_operations,
2951             expand_map, new_part_map, nullptr, false,
2952             Pos(), max_distance, options, amount, raster, relevant, paste_to_ctrl_num);
2953         }
2954         else
2955           xml.unknown("paste_items_at");
2956         break;
2957 
2958       case Xml::Attribut:
2959       case Xml::TagEnd:
2960       default:
2961         break;
2962     }
2963   }
2964 
2965   out_of_paste_at_for:
2966 
2967   // Push any part resizing operations onto the operations list now, before merging
2968   //  the add operations.
2969   for (map<const Part*, unsigned>::iterator it = expand_map.begin(); it!=expand_map.end(); it++)
2970     if (it->second != it->first->lenValue())
2971       schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);
2972 
2973   // Now merge the add operations into the operations so that all of the 'deletes' come first.
2974   //add_operations.splice(add_operations.begin(), delete_operations);
2975   for(ciUndoOp iuo = add_operations.begin(); iuo != add_operations.end(); ++iuo)
2976     operations.push_back(*iuo);
2977 
2978   MusEGlobal::song->informAboutNewParts(new_part_map); // must be called before apply. otherwise
2979                                                       // pointer changes (by resize) screw it up
2980 
2981   MusEGlobal::song->applyOperationGroup(operations);
2982   MusEGlobal::song->update(SC_SELECTION | SC_PART_SELECTION);
2983 }
2984 
paste_items_at(const std::set<const Part * > & parts,const TagEventList * tag_list,const Pos & pos,int max_distance,const FunctionOptionsStruct & options,const Part * paste_into_part,int amount,int raster,RelevantSelectedEvents_t relevant,int paste_to_ctrl_num)2985 void paste_items_at(
2986   const std::set<const Part*>& parts,
2987   const TagEventList* tag_list,
2988   const Pos& pos,
2989   int max_distance,
2990   const FunctionOptionsStruct& options,
2991   const Part* paste_into_part,
2992   int amount,
2993   int raster,
2994   RelevantSelectedEvents_t relevant,
2995   int paste_to_ctrl_num
2996   )
2997   {
2998     const bool cut_mode                    = options._flags & FunctionCutItems;
2999 
3000     // To maximize speed and minimize memory use, the processing below
3001     //  can only find any delete operations AFTER it has gathered
3002     //  add operations. So we keep two separate operations lists and
3003     //  combine them later so that all the deletes come BEFORE all the adds.
3004     Undo add_operations, operations;
3005 
3006     expand_map_t expand_map;
3007     new_part_map_t new_part_map;
3008 
3009     // Find the lowest position of all the events - the 'start' position.
3010     const Pos start_pos = tag_list->globalStats().evrange(relevant);
3011 
3012     // At this point the tag list's event list will still have any controller
3013     //  visual lengths HACK applied.
3014     // Those lengths will be reset below. But for now we could use them...
3015     FindMidiCtlsList_t globalCtrlList;
3016     int globalCtrlsFound = 0;
3017     if(!globalCtrlList.empty())
3018       globalCtrlsFound = globalCtrlList.size();
3019     if(paste_to_ctrl_num >= 0)
3020     {
3021       tag_list->globalCtlStats(&globalCtrlList, paste_to_ctrl_num);
3022       if(!globalCtrlList.empty())
3023         globalCtrlsFound = globalCtrlList.size();
3024       if(globalCtrlsFound > 0)
3025       {
3026         // Prompt user to choose controller...
3027 
3028       }
3029     }
3030 
3031     for(ciTagEventList itl = tag_list->cbegin(); itl != tag_list->cend(); ++itl)
3032     {
3033       const Part* dest_part = NULL;
3034       const Part* src_part = itl->first;
3035 
3036       if (paste_into_part == NULL)
3037         // Paste to original source part.
3038         dest_part = src_part;
3039       else
3040         // Paste to specific part.
3041         dest_part=paste_into_part;
3042 
3043       if (dest_part == NULL)
3044       {
3045         printf("paste_items_at(): ERROR: destination part wasn't found. ignoring these events\n");
3046         continue;
3047       }
3048 
3049       // Paste into the destination part ONLY if it is included in the given set of parts,
3050       //  typically the parts used by an editor window instance's canvas. (WYSIWYG).
3051       // Override if paste_into_part is given, to allow 'Paste to current part' to work.
3052       if(!paste_into_part && parts.find(dest_part) == parts.end())
3053         continue;
3054 
3055       // Grab the event list and find the number of relevant events.
3056       const EventList& el = itl->second.evlist();
3057 
3058       pasteEventList(
3059         el, pos, ((Part*)dest_part), operations, add_operations,
3060         expand_map, new_part_map, src_part, cut_mode, start_pos, max_distance, options,
3061         amount, raster, relevant, paste_to_ctrl_num);
3062     }
3063 
3064     // Push any part resizing operations onto the operations list now, before merging
3065     //  the add operations.
3066     for (map<const Part*, unsigned>::iterator it = expand_map.begin(); it!=expand_map.end(); it++)
3067       if (it->second != it->first->lenValue())
3068         schedule_resize_all_same_len_clone_parts(it->first, it->second, operations);
3069 
3070     // Now merge the add operations into the operations so that all of the 'deletes' come first.
3071     //add_operations.splice(add_operations.begin(), delete_operations);
3072     for(ciUndoOp iuo = add_operations.begin(); iuo != add_operations.end(); ++iuo)
3073       operations.push_back(*iuo);
3074 
3075     MusEGlobal::song->informAboutNewParts(new_part_map); // must be called before apply. otherwise
3076                                                         // pointer changes (by resize) screw it up
3077 
3078     MusEGlobal::song->applyOperationGroup(operations);
3079     MusEGlobal::song->update(SC_SELECTION | SC_PART_SELECTION);
3080 }
3081 
3082 //---------------------------------------------------------
3083 //   getSelectedParts
3084 //---------------------------------------------------------
getSelectedParts()3085 PartList* getSelectedParts()
3086 {
3087   PartList* parts1;
3088   PartList* parts2;
3089 
3090   parts1 = getSelectedMidiParts();
3091   parts2 = getSelectedWaveParts();
3092 
3093   for (ciPart p = parts2->begin(); p != parts2->end(); ++p) {
3094     parts1->add(p->second);
3095   }
3096 
3097   return parts1;
3098 }
3099 
getSelectedMidiParts()3100 PartList* getSelectedMidiParts()
3101       {
3102       PartList* parts = new PartList();
3103 
3104       /*
3105             If a part is selected, edit that.
3106             If a track is selected, edit the first
3107              part of the track, the rest are
3108              'ghost parts'
3109             When multiple parts are selected, then edit the first,
3110               the rest are 'ghost parts'
3111       */
3112 
3113 
3114        // collect marked parts
3115       for (ciMidiTrack t = MusEGlobal::song->midis()->begin(); t != MusEGlobal::song->midis()->end(); ++t) {
3116             PartList* pl = (*t)->parts();
3117             for (iPart p = pl->begin(); p != pl->end(); ++p) {
3118                   if (p->second->selected()) {
3119                         parts->add(p->second);
3120                         }
3121                   }
3122             }
3123       // if no part is selected, then search for selected track
3124       // and collect all parts of this track
3125 
3126       if (parts->empty()) {
3127             for (ciMidiTrack t = MusEGlobal::song->midis()->begin(); t != MusEGlobal::song->midis()->end(); ++t) {
3128                   if ((*t)->selected()) {
3129                         PartList* pl = (*t)->parts();
3130                         for (iPart p = pl->begin(); p != pl->end(); ++p)
3131                               parts->add(p->second);
3132                         break;
3133                         }
3134                   }
3135             }
3136 
3137       return parts;
3138       }
3139 
getSelectedWaveParts()3140 PartList* getSelectedWaveParts()
3141       {
3142       PartList* parts = new PartList();
3143 
3144       /*
3145             If a part is selected, edit that.
3146             If a track is selected, edit the first
3147              part of the track, the rest are
3148              'ghost parts'
3149             When multiple parts are selected, then edit the first,
3150               the rest are 'ghost parts'
3151       */
3152 
3153       // collect selected parts
3154       for (ciWaveTrack t = MusEGlobal::song->waves()->begin(); t != MusEGlobal::song->waves()->end(); ++t) {
3155             PartList* pl = (*t)->parts();
3156             for (ciPart p = pl->begin(); p != pl->end(); ++p) {
3157                   if (p->second->selected()) {
3158                         parts->add(p->second);
3159                         }
3160                   }
3161             }
3162       // if no parts are selected, then search the selected track
3163       // and collect all parts in this track
3164 
3165       if (parts->empty()) {
3166             for (ciWaveTrack t = MusEGlobal::song->waves()->begin(); t != MusEGlobal::song->waves()->end(); ++t) {
3167                   if ((*t)->selected()) {
3168                         PartList* pl = (*t)->parts();
3169                         for (ciPart p = pl->begin(); p != pl->end(); ++p)
3170                               parts->add(p->second);
3171                         break;
3172                         }
3173                   }
3174             }
3175       return parts;
3176 }
3177 
3178 //---------------------------------------------------------
3179 //   resize_part
3180 //---------------------------------------------------------
3181 
resize_part(Track * track,Part * originalPart,unsigned int newTickPosOrLen,MusECore::ResizeDirection resizeDirection,bool doClones,bool dragEvents)3182 void resize_part(
3183   Track* track, Part* originalPart, unsigned int newTickPosOrLen, MusECore::ResizeDirection resizeDirection,
3184   bool doClones, bool dragEvents)
3185       {
3186 
3187       // Are the events to be offset?
3188       const bool use_events_offset =
3189         (resizeDirection == MusECore::ResizeDirection::RESIZE_TO_THE_RIGHT && dragEvents) ||
3190         (resizeDirection == MusECore::ResizeDirection::RESIZE_TO_THE_LEFT && !dragEvents);
3191 
3192       // Under this condition we MUST do all clones. The RULE is that event times, which are relative to the part start,
3193       //   must be the same in all clones.
3194       if(use_events_offset)
3195         doClones = true;
3196 
3197       switch(track->type()) {
3198             case Track::WAVE:
3199             case Track::MIDI:
3200             case Track::DRUM:
3201                   {
3202                   Undo operations;
3203 
3204 #ifdef ALLOW_LEFT_HIDDEN_EVENTS
3205                   const Pos::TType newPosOrLenType = Pos::TType::TICKS;
3206                   const unsigned int origPosValue = originalPart->posValue();
3207                   const unsigned int newOrigPosValue = Pos::convert(newTickPosOrLen, newPosOrLenType, originalPart->type());
3208                   // The amount to shift a part. The int64_t cast ensures we preserve the unsigned range.
3209                   const int64_t origPosValueDiff = (int64_t)newOrigPosValue - (int64_t)origPosValue;
3210                   const unsigned int origPosValueConverted = originalPart->posValue(newPosOrLenType);
3211                   const unsigned int newOrigEndPosValue =
3212                     Pos::convert(origPosValueConverted + newTickPosOrLen, newPosOrLenType, originalPart->type());
3213                   const unsigned int newOrigLenValue = newOrigEndPosValue - origPosValue;
3214 
3215                   const unsigned int origLenValue = originalPart->lenValue();
3216                   const int64_t origLenValueDiff = (int64_t)newOrigLenValue - (int64_t)origLenValue;
3217 
3218                   int64_t events_offset = 0L;
3219                   if(use_events_offset)
3220                   {
3221                     switch(resizeDirection)
3222                     {
3223                       case MusECore::ResizeDirection::RESIZE_TO_THE_RIGHT:
3224                         events_offset = origLenValueDiff;
3225                       break;
3226                       case MusECore::ResizeDirection::RESIZE_TO_THE_LEFT:
3227                         events_offset = -origPosValueDiff;
3228                       break;
3229                     }
3230                   }
3231 
3232                   auto currentPart = originalPart;
3233 
3234                   do
3235                   {
3236                       if(resizeDirection == MusECore::ResizeDirection::RESIZE_TO_THE_RIGHT)
3237                       {
3238                         const unsigned int pos_val = currentPart->posValue(originalPart->type());
3239                         const unsigned int new_end_pos_val = Pos::convert(pos_val + newOrigLenValue, originalPart->type(), currentPart->type());
3240                         const unsigned int new_len_val = new_end_pos_val - pos_val;
3241                         operations.push_back(
3242                           UndoOp(UndoOp::ModifyPartLength, currentPart,
3243                                 currentPart->lenValue(),
3244                                 new_len_val,
3245                                 // The amount to shift all events in the part.
3246                                 events_offset,
3247                                 // The position type of the amount to shift all events in the part.
3248                                 originalPart->type()));
3249                       }
3250                       else if(resizeDirection == MusECore::ResizeDirection::RESIZE_TO_THE_LEFT)
3251                       {
3252                           const unsigned int pos_val = currentPart->posValue(originalPart->type());
3253                           const unsigned int end_pos_val = currentPart->endValue(originalPart->type());
3254                           unsigned int new_pos_val, new_len_val;
3255                           if((int64_t)pos_val + origPosValueDiff < 0L)
3256                           {
3257                             new_pos_val = 0;
3258                             new_len_val = Pos::convert((int64_t)end_pos_val - ((int64_t)pos_val + origPosValueDiff),
3259                                                       originalPart->type(), currentPart->type()) - new_pos_val;
3260                           }
3261                           else
3262                           {
3263                             new_pos_val = Pos::convert((int64_t)pos_val + origPosValueDiff, originalPart->type(), currentPart->type());
3264                             new_len_val = currentPart->endValue() - new_pos_val;
3265                           }
3266                           operations.push_back(
3267                             UndoOp(UndoOp::ModifyPartStart, currentPart,
3268                                     currentPart->posValue(),
3269                                     new_pos_val,
3270                                     currentPart->lenValue(),
3271                                     new_len_val,
3272                                     // The amount to shift all events in the part.
3273                                     events_offset,
3274                                     // The position type of the amount to shift all events in the part.
3275                                     originalPart->type()));
3276                       }
3277 
3278                       currentPart = currentPart->nextClone();
3279 
3280                   } while (doClones && (currentPart != originalPart));
3281 #else
3282                   const Pos::TType newPosOrLenType = Pos::TType::TICKS;
3283                   const unsigned int origPosValue = originalPart->posValue();
3284                   const unsigned int newOrigPosValue = Pos::convert(newTickPosOrLen, newPosOrLenType, originalPart->type());
3285                   // The amount to shift a part. The int64_t cast ensures we preserve the unsigned range.
3286                   const int64_t origPosValueDiff = (int64_t)newOrigPosValue - (int64_t)origPosValue;
3287                   const Pos::TType events_offset_time_type = originalPart->type();
3288                   const unsigned int origPosValueConverted = originalPart->posValue(newPosOrLenType);
3289                   const unsigned int newOrigEndPosValue = Pos::convert(origPosValueConverted + newTickPosOrLen, newPosOrLenType, originalPart->type());
3290                   const unsigned int newOrigLenValue = newOrigEndPosValue - origPosValue;
3291 
3292                   const unsigned int origLenValue = originalPart->lenValue();
3293                   const int64_t origLenValueDiff = (int64_t)newOrigLenValue - (int64_t)origLenValue;
3294 
3295                   int64_t events_offset = 0L;
3296                   if(use_events_offset)
3297                   {
3298                     switch(resizeDirection)
3299                     {
3300                       case MusECore::ResizeDirection::RESIZE_TO_THE_RIGHT:
3301                         events_offset = origLenValueDiff;
3302                       break;
3303                       case MusECore::ResizeDirection::RESIZE_TO_THE_LEFT:
3304                         events_offset = -origPosValueDiff;
3305                       break;
3306                     }
3307                   }
3308 
3309                   // Check to see if the events offset would move events before time zero, and limit if so.
3310                   if(use_events_offset)
3311                   {
3312                     const EventList& el = originalPart->events();
3313                     const ciEvent iev = el.cbegin();
3314                     if(iev != el.cend())
3315                     {
3316                       const Event first_ev = iev->second;
3317 
3318                       // In case the event and part pos types differ, the event dominates.
3319                       unsigned int new_part_pos_val;
3320                       switch(resizeDirection)
3321                       {
3322                         // If resizing to the right, just use the original part position, converted.
3323                         case MusECore::ResizeDirection::RESIZE_TO_THE_RIGHT:
3324                           new_part_pos_val = originalPart->posValue(first_ev.pos().type());
3325                         break;
3326                         // If resizing to the left, use the new part position, converted.
3327                         case MusECore::ResizeDirection::RESIZE_TO_THE_LEFT:
3328                           new_part_pos_val = Pos::convert(newTickPosOrLen, newPosOrLenType, first_ev.pos().type());
3329                         break;
3330                       }
3331 
3332                       const unsigned int old_abs_ev_pos_val =
3333                         Pos::convert(first_ev.posValue() + new_part_pos_val, first_ev.pos().type(), events_offset_time_type);
3334 
3335                       if((int64_t)old_abs_ev_pos_val + events_offset < 0L)
3336                         events_offset = -(int64_t)old_abs_ev_pos_val;
3337 
3338                       const unsigned int new_abs_ev_pos_val =
3339                         Pos::convert((int64_t)old_abs_ev_pos_val + events_offset, events_offset_time_type, first_ev.pos().type());
3340 
3341                       if(new_abs_ev_pos_val < new_part_pos_val)
3342                         events_offset = -(int64_t)first_ev.pos().posValue();
3343                     }
3344                   }
3345 
3346                   auto currentPart = originalPart;
3347 
3348                   do
3349                   {
3350                       if(resizeDirection == MusECore::ResizeDirection::RESIZE_TO_THE_RIGHT)
3351                       {
3352                         const unsigned int pos_val = currentPart->posValue(originalPart->type());
3353                         const unsigned int new_end_pos_val = Pos::convert(pos_val + newOrigLenValue, originalPart->type(), currentPart->type());
3354                         const unsigned int new_len_val = new_end_pos_val - pos_val;
3355                         operations.push_back(
3356                           UndoOp(UndoOp::ModifyPartLength, currentPart,
3357                                 currentPart->lenValue(),
3358                                 new_len_val,
3359                                 // The amount to shift all events in the part.
3360                                 events_offset,
3361                                 // The position type of the amount to shift all events in the part.
3362                                 originalPart->type()));
3363                       }
3364                       else if(resizeDirection == MusECore::ResizeDirection::RESIZE_TO_THE_LEFT)
3365                       {
3366                           const unsigned int pos_val = currentPart->posValue(originalPart->type());
3367                           const unsigned int end_pos_val = currentPart->endValue(originalPart->type());
3368                           unsigned int new_pos_val, new_len_val;
3369                           if((int64_t)pos_val + origPosValueDiff < 0L)
3370                           {
3371                             new_pos_val = 0;
3372                             new_len_val = Pos::convert((int64_t)end_pos_val - ((int64_t)pos_val + origPosValueDiff),
3373                                                       originalPart->type(), currentPart->type()) - new_pos_val;
3374                           }
3375                           else
3376                           {
3377                             new_pos_val = Pos::convert((int64_t)pos_val + origPosValueDiff, originalPart->type(), currentPart->type());
3378                             new_len_val = currentPart->endValue() - new_pos_val;
3379                           }
3380                           operations.push_back(
3381                             UndoOp(UndoOp::ModifyPartStart, currentPart,
3382                                     currentPart->posValue(),
3383                                     new_pos_val,
3384                                     currentPart->lenValue(),
3385                                     new_len_val,
3386                                     // The amount to shift all events in the part.
3387                                     events_offset,
3388                                     // The position type of the amount to shift all events in the part.
3389                                     originalPart->type()));
3390                       }
3391 
3392                       currentPart = currentPart->nextClone();
3393 
3394                   } while (doClones && (currentPart != originalPart));
3395 #endif
3396 
3397                   MusEGlobal::song->applyOperationGroup(operations);
3398                   break;
3399                 }
3400 
3401             default:
3402                   break;
3403             }
3404       }
3405 
3406 
3407 } // namespace MusECore
3408