1 //=========================================================
2 // MusE
3 // Linux Music Editor
4 // operations.cpp
5 // (C) Copyright 2014, 2016 Tim E. Real (terminator356 on users dot sourceforge dot 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 "operations.h"
24 #include "song.h"
25 #include "globals.h"
26 #include "synth.h"
27 #include "muse_time.h"
28 #include "config.h"
29
30 // Forwards from header:
31 #include "tempo.h"
32 #include "sig.h"
33 #include "keyevent.h"
34 #include "midiport.h"
35 #include "metronome_class.h"
36 #include "audio_convert/audio_converter_plugin.h"
37 #include "audio_convert/audio_converter_settings_group.h"
38
39 // Enable for debugging:
40 //#define _PENDING_OPS_DEBUG_
41
42 // For debugging output: Uncomment the fprintf section.
43 #define ERROR_OPERATIONS(dev, format, args...) fprintf(dev, format, ##args)
44 #define DEBUG_OPERATIONS(dev, format, args...) //fprintf(dev, format, ##args)
45
46 namespace MusECore {
47
48 //-----------------------------------
49 // MidiCtrlValListIterators
50 //-----------------------------------
51
findList(const MidiCtrlValList * valList)52 MidiCtrlValListIterators::iterator MidiCtrlValListIterators::findList(const MidiCtrlValList* valList)
53 {
54 for(iterator i = begin(); i != end(); ++i)
55 if((*i)->second == valList)
56 return i;
57 return end();
58 }
59
findList(const MidiCtrlValList * valList) const60 MidiCtrlValListIterators::const_iterator MidiCtrlValListIterators::findList(const MidiCtrlValList* valList) const
61 {
62 for(const_iterator i = begin(); i != end(); ++i)
63 if((*i)->second == valList)
64 return i;
65 return end();
66 }
67
68 //-----------------------------------
69 // MidiCtrlValLists2bErased
70 //-----------------------------------
71
add(int port,const iMidiCtrlValList & item)72 void MidiCtrlValLists2bErased::add(int port, const iMidiCtrlValList& item)
73 {
74 iterator i = find(port);
75 if(i == end())
76 {
77 MidiCtrlValListIterators mcvli;
78 mcvli.push_back(item);
79 insert(MidiCtrlValLists2bErasedInsertPair_t(port, mcvli));
80 return;
81 }
82 MidiCtrlValListIterators& mcvli = i->second;
83 for(iMidiCtrlValListIterators_t imcvli = mcvli.begin(); imcvli != mcvli.end(); ++imcvli)
84 {
85 iMidiCtrlValList imcvl = *imcvli;
86 // Compare list pointers.
87 if(imcvl->second == item->second)
88 return; // Already exists.
89 }
90 mcvli.push_back(item);
91 }
92
findList(int port,const MidiCtrlValList * valList)93 MidiCtrlValLists2bErased::iterator MidiCtrlValLists2bErased::findList(int port, const MidiCtrlValList* valList)
94 {
95 iterator i = find(port);
96 if(i == end())
97 return end();
98 if(i->second.findList(valList) != i->second.end())
99 return i;
100 return end();
101 }
102
findList(int port,const MidiCtrlValList * valList) const103 MidiCtrlValLists2bErased::const_iterator MidiCtrlValLists2bErased::findList(int port, const MidiCtrlValList* valList) const
104 {
105 const_iterator i = find(port);
106 if(i == end())
107 return end();
108 if(i->second.findList(valList) != i->second.end())
109 return i;
110 return end();
111 }
112
113 //-----------------------------------
114 // PendingOperationItem
115 //-----------------------------------
116
isAllocationOp(const PendingOperationItem & op) const117 bool PendingOperationItem::isAllocationOp(const PendingOperationItem& op) const
118 {
119 switch(op._type)
120 {
121 case AddMidiCtrlValList:
122 // A is channel B is control.
123 if(_type == AddMidiCtrlValList && _mcvll == op._mcvll && _intA == op._intA && _intB == op._intB)
124 return true;
125 break;
126
127 // In the case of type AddMidiDevice, this searches for the name only.
128 case AddMidiDevice:
129 if(_type == AddMidiDevice && _midi_device_list == op._midi_device_list &&
130 _midi_device->name() == op._midi_device->name())
131 return true;
132 break;
133
134 default:
135 break;
136 }
137
138 return false;
139 }
140
getIndex() const141 unsigned int PendingOperationItem::getIndex() const
142 {
143 switch(_type)
144 {
145 case Uninitialized:
146 case AddAuxSendValue:
147 case AddMidiInstrument:
148 case DeleteMidiInstrument:
149 case ReplaceMidiInstrument:
150 case AddMidiDevice:
151 case DeleteMidiDevice:
152 case ModifyMidiDeviceAddress:
153 case ModifyMidiDeviceFlags:
154 case ModifyMidiDeviceName:
155 case SetInstrument:
156 case AddTrack:
157 case DeleteTrack:
158 case MoveTrack:
159 case ModifyTrackName:
160 case ModifyTrackDrumMapItem:
161 case ReplaceTrackDrumMapPatchList:
162 case RemapDrumControllers:
163 case UpdateDrumMaps:
164 case SetTrackRecord:
165 case SetTrackMute:
166 case SetTrackSolo:
167 case SetTrackRecMonitor:
168 case SetTrackOff:
169 case ModifyPartName:
170 case ModifySongLength:
171 case AddMidiCtrlValList:
172 case ModifyAudioCtrlValList:
173 case SetGlobalTempo:
174 case AddRoute:
175 case DeleteRoute:
176 case AddRouteNode:
177 case DeleteRouteNode:
178 case ModifyRouteNode:
179 case UpdateSoloStates:
180 case EnableAllAudioControllers:
181 case GlobalSelectAllEvents:
182 case SwitchMetronomeSettings:
183 case ModifyMetronomeAccentMap:
184 case SetExternalSyncFlag:
185 case SetUseJackTransport:
186 case SetUseMasterTrack:
187 case ModifyAudioSamples:
188 case SetStaticTempo:
189 case ModifyLocalAudioConverterSettings:
190 case ModifyLocalAudioConverter:
191 case ModifyDefaultAudioConverterSettings:
192 case ModifyStretchListRatio:
193 case SetAudioConverterOfflineMode:
194 case ModifyMarkerList:
195 case ModifyTempoList:
196 case ModifySigList:
197 case ModifyKeyList:
198 case ModifyEventList:
199 case ModifyMidiCtrlValList:
200
201 // To help speed up searches of these ops, let's (arbitrarily) set index = type instead of all of them being at index 0!
202 return _type;
203
204 case ModifyPartStart:
205 return _part->posValue();
206
207 case ModifyPartLength:
208 return _part->posValue();
209
210 case MovePart:
211 // _part is used here rather than _iPart since _iPart can be end().
212 return _part->posValue();
213
214 case AddPart:
215 return _part->posValue();
216
217 case DeletePart:
218 return _iPart->second->posValue();
219
220 case SelectPart:
221 return _part->posValue();
222
223
224 case AddEvent:
225 return _ev.posValue();
226
227 case DeleteEvent:
228 return _ev.posValue();
229
230 case SelectEvent:
231 return _ev.posValue();
232
233
234 case AddMidiCtrlVal:
235 return _posLenVal; // Tick
236
237 case DeleteMidiCtrlVal:
238 return _imcv->first; // Tick
239
240 case ModifyMidiCtrlVal:
241 return _imcv->first; // Tick
242
243
244 case AddAudioCtrlVal:
245 return _posLenVal; // Frame
246
247 case DeleteAudioCtrlVal:
248 return _iCtrl->first; // Frame
249
250 case ModifyAudioCtrlVal:
251 return _iCtrl->first; // Frame
252
253
254 case AddStretchListRatioAt:
255 return _museFrame; // Frame
256
257 case DeleteStretchListRatioAt:
258 return _iStretchEvent->first; // Frame
259
260 case ModifyStretchListRatioAt:
261 return _iStretchEvent->first; // Frame
262
263 default:
264 ERROR_OPERATIONS(stderr, "PendingOperationItem::getIndex unknown op type: %d\n", _type);
265 return 0;
266 break;
267 }
268 }
269
executeRTStage()270 SongChangedStruct_t PendingOperationItem::executeRTStage()
271 {
272 SongChangedStruct_t flags = 0;
273 switch(_type)
274 {
275 case ModifyDefaultAudioConverterSettings:
276 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyDefaultAudioConverterSettings: "
277 "settings:%p\n", _audio_converter_settings);
278 if(_audio_converter_settings)
279 {
280 // Grab the current settings.
281 AudioConverterSettingsGroup* cur_settings = MusEGlobal::defaultAudioConverterSettings;
282 // Now change the actual global pointer variable.
283 MusEGlobal::defaultAudioConverterSettings = _audio_converter_settings;
284 // Transfer the original pointer into the member, so it can be deleted in the non-RT stage.
285 _audio_converter_settings = cur_settings;
286 flags |= SC_AUDIO_CONVERTER;
287 }
288 break;
289
290 case ModifyLocalAudioConverterSettings:
291 {
292 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyLocalAudioConverterSettings: "
293 "sndFile:%p settings:%p\n",
294 *_sndFileR, _audio_converter_settings);
295
296 // _audio_converter_settings can be NULL meaning don't touch, settings can only be
297 // 'replaced' but not deleted.
298 if(_audio_converter_settings)
299 {
300 AudioConverterSettingsGroup* cur_settings = _sndFileR.audioConverterSettings();
301 _sndFileR.setAudioConverterSettings(_audio_converter_settings);
302 // Transfer the original pointer into the member, so it can be deleted in the non-RT stage.
303 _audio_converter_settings = cur_settings;
304 flags |= SC_AUDIO_CONVERTER;
305 }
306 }
307 break;
308
309 case ModifyLocalAudioConverter:
310 {
311 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyLocalAudioConverter: "
312 "sndFile:%p audio_converter:%p audio_converter_ui:%p\n",
313 *_sndFileR, _audio_converter, _audio_converter_ui);
314
315 // _audio_converter and _audio_converter_ui can be NULL meaning delete them.
316 AudioConverterPluginI* cur_conv = _sndFileR.staticAudioConverter(AudioConverterSettings::RealtimeMode);
317 //if(_audio_converter)
318 _sndFileR.setStaticAudioConverter(_audio_converter, AudioConverterSettings::RealtimeMode);
319 // Transfer the original pointer into the member, so it can be deleted in the non-RT stage.
320 _audio_converter = cur_conv;
321
322 AudioConverterPluginI* cur_convUI = _sndFileR.staticAudioConverter(AudioConverterSettings::GuiMode);
323 //if(_audio_converter_ui)
324 _sndFileR.setStaticAudioConverter(_audio_converter_ui, AudioConverterSettings::GuiMode);
325 // Transfer the original pointer into the member, so it can be deleted in the non-RT stage.
326 _audio_converter_ui = cur_convUI;
327 flags |= SC_AUDIO_CONVERTER;
328 }
329 break;
330
331 case SetAudioConverterOfflineMode:
332 {
333 // DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage SetAudioConverterOfflineMode: "
334 // "sndFile:%p audio_converter:%p\n",
335 // *_sndFile, _audio_converter);
336
337 AudioConverterPluginI* cur_conv = _sndFileR.staticAudioConverter(AudioConverterSettings::RealtimeMode);
338 //if(_audio_converter)
339 _sndFileR.setStaticAudioConverter(_audio_converter, AudioConverterSettings::RealtimeMode);
340 // Transfer the original pointer into the member, so it can be deleted in the non-RT stage.
341 _audio_converter = cur_conv;
342 flags |= SC_AUDIO_CONVERTER;
343 }
344 break;
345
346
347 case ModifyTrackDrumMapItem:
348 {
349 #ifdef _PENDING_OPS_DEBUG_
350 fprintf(stderr, "PendingOperationItem::executeRTStage ModifyTrackDrumMapItem drummap operation:%p\n",
351 _drum_map_track_operation);
352 #endif
353
354 MidiTrack* mt;
355 MidiTrackList& mtl = _drum_map_track_operation->_tracks;
356 for(iMidiTrack imt = mtl.begin(); imt != mtl.end(); ++imt)
357 {
358 mt = *imt;
359 // FIXME Possible non realtime-friendly allocation.
360 mt->modifyWorkingDrumMap(_drum_map_track_operation->_workingItemList,
361 _drum_map_track_operation->_isReset,
362 _drum_map_track_operation->_includeDefault,
363 _drum_map_track_operation->_isInstrumentMod,
364 _drum_map_track_operation->_doWholeMap);
365 flags |= (SC_DRUMMAP);
366 }
367
368 // If this is an instrument modification we must now do a
369 // general update of all drum track drum maps.
370 // Ideally we would like to update only the required ones,
371 // but it is too difficult to tell which maps need updating
372 // from inside the above loop (or inside modifyWorkingDrumMap).
373 if(_drum_map_track_operation->_isInstrumentMod)
374 {
375 MidiTrackList* mtlp = MusEGlobal::song->midis();
376 for(iMidiTrack imt = mtlp->begin(); imt != mtlp->end(); ++imt)
377 {
378 mt = *imt;
379 if(mt->type() != Track::DRUM)
380 continue;
381 if(mt->updateDrummap(false))
382 flags |= (SC_DRUMMAP);
383 }
384 }
385 flags |= (SC_DRUMMAP);
386 }
387 break;
388
389 case ReplaceTrackDrumMapPatchList:
390 {
391 #ifdef _PENDING_OPS_DEBUG_
392 fprintf(stderr, "PendingOperationItem::executeRTStage ReplaceTrackDrumMapPatchList drummap operation:%p\n",
393 _drum_map_track_patch_replace_operation);
394 #endif
395
396 MidiTrack* mt = _drum_map_track_patch_replace_operation->_track;
397 WorkingDrumMapPatchList* orig_wdmpl = mt->workingDrumMap();
398 // Simply switch pointers. Be sure to delete the original pointers later in the non-realtime stage.
399 // After the list pointers have been switched, swap with the replacement so that it can be deleted later.
400 mt->setWorkingDrumMap(_drum_map_track_patch_replace_operation->_workingItemPatchList,
401 _drum_map_track_patch_replace_operation->_isInstrumentMod);
402 _drum_map_track_patch_replace_operation->_workingItemPatchList = orig_wdmpl;
403
404 // If this is an instrument modification we must now do a
405 // general update of all drum track drum maps.
406 // Ideally we would like to update only the required ones,
407 // but it is too difficult to tell which maps need updating
408 // from inside the above loop (or inside modifyWorkingDrumMap).
409 if(_drum_map_track_patch_replace_operation->_isInstrumentMod)
410 {
411 MidiTrackList* mtlp = MusEGlobal::song->midis();
412 for(iMidiTrack imt = mtlp->begin(); imt != mtlp->end(); ++imt)
413 {
414 mt = *imt;
415 if(mt->type() != Track::DRUM)
416 continue;
417 if(mt->updateDrummap(false))
418 flags |= (SC_DRUMMAP);
419 }
420 }
421 flags |= (SC_DRUMMAP);
422 }
423 break;
424
425 case RemapDrumControllers:
426 {
427 #ifdef _PENDING_OPS_DEBUG_
428 fprintf(stderr, "PendingOperationItem::executeRTStage RemapDrumControllers remap operation:%p\n",
429 _midi_ctrl_val_remap_operation);
430 #endif
431
432 for(iMidiCtrlValLists2bErased_t imcvle = _midi_ctrl_val_remap_operation->_midiCtrlValLists2bErased.begin();
433 imcvle != _midi_ctrl_val_remap_operation->_midiCtrlValLists2bErased.end(); ++imcvle)
434 {
435 const int port = imcvle->first;
436 MidiCtrlValListIterators& mcvli = imcvle->second;
437 MidiPort* mp = &MusEGlobal::midiPorts[port];
438 MidiCtrlValListList* mcvll = mp->controller();
439 for(iMidiCtrlValListIterators_t imcvli = mcvli.begin(); imcvli != mcvli.end(); ++imcvli)
440 mcvll->del(*imcvli);
441 }
442
443 for(iMidiCtrlValLists2bAdded_t imcvla = _midi_ctrl_val_remap_operation->_midiCtrlValLists2bAdded.begin();
444 imcvla != _midi_ctrl_val_remap_operation->_midiCtrlValLists2bAdded.end(); ++imcvla)
445 {
446 const int port = imcvla->first;
447 MidiCtrlValListList* mcvll_a = imcvla->second;
448 MidiPort* mp = &MusEGlobal::midiPorts[port];
449 MidiCtrlValListList* mcvll = mp->controller();
450 for(iMidiCtrlValList imcvl = mcvll_a->begin(); imcvl != mcvll_a->end(); ++imcvl)
451 mcvll->add(imcvl->first >> 24, imcvl->second);
452 }
453
454 // TODO: What to use here? We don't have anything SC_* related... yet.
455 //flags |= (SC_MIDI_CONTROLLER_ADD);
456 flags |= (SC_EVERYTHING);
457 }
458 break;
459
460 case UpdateDrumMaps:
461 #ifdef _PENDING_OPS_DEBUG_
462 fprintf(stderr, "PendingOperationItem::executeRTStage UpdateDrumMaps: midi_port:%p:\n", _midi_port);
463 #endif
464 if(_midi_port->updateDrumMaps())
465 flags |= SC_DRUMMAP;
466 break;
467
468 case UpdateSoloStates:
469 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage UpdateSoloStates: track_list:%p:\n", _track_list);
470 // TODO Use the track_list, or simply keep as dummy parameter to identify UpdateSoloStates?
471 MusEGlobal::song->updateSoloStates();
472 flags |= SC_SOLO;
473 break;
474
475 // TODO: Try to break this operation down so that only the actual operation is executed stage-2.
476 case AddRoute:
477 #ifdef _PENDING_OPS_DEBUG_
478 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddRoute: src/dst routes:\n");
479 _src_route.dump();
480 _dst_route.dump();
481 #endif
482 if(addRoute(_src_route, _dst_route))
483 flags |= SC_ROUTE;
484 break;
485
486 // TODO: Try to break this operation down so that only the actual operation is executed stage-2.
487 case DeleteRoute:
488 #ifdef _PENDING_OPS_DEBUG_
489 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeleteRoute: src/dst routes:\n");
490 _src_route.dump();
491 _dst_route.dump();
492 #endif
493 if(removeRoute(_src_route, _dst_route))
494 flags |= SC_ROUTE;
495 break;
496
497 case AddRouteNode:
498 #ifdef _PENDING_OPS_DEBUG_
499 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddRouteNode: route_list:%p route:\n", _route_list);
500 _src_route.dump();
501 #endif
502 _route_list->push_back(_src_route);
503 flags |= SC_ROUTE;
504 break;
505
506 case DeleteRouteNode:
507 #ifdef _PENDING_OPS_DEBUG_
508 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeleteRouteNode: route_list:%p route:\n", _route_list);
509 _iRoute->dump();
510 #endif
511 _route_list->erase(_iRoute);
512 flags |= SC_ROUTE;
513 break;
514
515 case ModifyRouteNode:
516 #ifdef _PENDING_OPS_DEBUG_
517 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyRouteNode: src/dst routes:\n");
518 _src_route.dump();
519 _dst_route_pointer->dump();
520 #endif
521 *_dst_route_pointer = _src_route;
522 flags |= SC_ROUTE;
523 break;
524
525 case AddAuxSendValue:
526 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddAuxSendValue aux_send_value_list:%p val:%f\n", _aux_send_value_list, _aux_send_value);
527 _aux_send_value_list->push_back(_aux_send_value);
528 break;
529
530
531 case AddMidiInstrument:
532 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddMidiInstrument instrument_list:%p instrument:%p\n", _midi_instrument_list, _midi_instrument);
533 _midi_instrument_list->push_back(_midi_instrument);
534 flags |= SC_CONFIG | SC_MIDI_INSTRUMENT | SC_DRUMMAP | SC_MIDI_CONTROLLER_ADD;
535 break;
536
537 case DeleteMidiInstrument:
538 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeleteMidiInstrument instrument_list:%p instrument:%p\n", _midi_instrument_list, *_iMidiInstrument);
539 _midi_instrument_list->erase(_iMidiInstrument);
540 flags |= SC_CONFIG | SC_MIDI_INSTRUMENT | SC_DRUMMAP | SC_MIDI_CONTROLLER_ADD;
541 break;
542
543 case ReplaceMidiInstrument:
544 {
545 #ifdef _PENDING_OPS_DEBUG_
546 fprintf(stderr, "PendingOperationItem::executeRTStage ReplaceMidiInstrument instrument_list:%p instrument:%p new_ instrument:%p\n",
547 _midi_instrument_list, *_iMidiInstrument, _midi_instrument);
548 #endif
549 // Grab the existing pointer to be deleted.
550 MidiInstrument* orig = *_iMidiInstrument;
551 // Erase from the list.
552 _midi_instrument_list->erase(_iMidiInstrument);
553 // Add the new instrument.
554 _midi_instrument_list->push_back(_midi_instrument);
555
556 // Change all ports which used the original instrument.
557 for(int port = 0; port < MusECore::MIDI_PORTS; ++port)
558 {
559 MidiPort* mp = &MusEGlobal::midiPorts[port];
560 if(mp->instrument() != orig)
561 continue;
562 // Set the new instrument and nothing more (ie. don't use MidiPort::changeInstrument()).
563 // Here we will flag the initializations, and normalize and update the drum maps.
564 mp->setInstrument(_midi_instrument);
565 // Flag the port to send initializations next time it bothers to check.
566 // TODO: Optimize: We only need this if the user changed the initialization
567 // lists or sysex list. Find a way to pass that info here.
568 mp->clearInitSent();
569 }
570
571 // Since this is an instrument modification we must now do a
572 // general update of all drum track drum maps using this instrument.
573 // Ideally we would like to update only the required ones,
574 // but it is too difficult to tell which maps need updating
575 // from inside the above loop (or inside modifyWorkingDrumMap).
576 MidiTrack* mt;
577 int mt_port;
578 MidiPort* mt_mp;
579 MidiTrackList* mtlp = MusEGlobal::song->midis();
580 for(iMidiTrack imt = mtlp->begin(); imt != mtlp->end(); ++imt)
581 {
582 mt = *imt;
583 if(mt->type() != Track::DRUM)
584 continue;
585 mt_port = mt->outPort();
586 if(mt_port < 0 || mt_port >= MusECore::MIDI_PORTS)
587 continue;
588 mt_mp = &MusEGlobal::midiPorts[mt_port];
589 // We are looking for tracks which are now using the new instrument.
590 if(mt_mp->instrument() != _midi_instrument)
591 continue;
592 // Ensure there are NO duplicate enote fields.
593 //mt->normalizeWorkingDrumMapPatchList();
594 // Finally, update the track's drum map (and drum in map).
595 mt->updateDrummap(false);
596 }
597
598 // Transfer the original pointer back to _midi_instrument so it can be deleted in the non-RT stage.
599 _midi_instrument = orig;
600
601 flags |= SC_CONFIG | SC_MIDI_INSTRUMENT | SC_DRUMMAP | SC_MIDI_CONTROLLER_ADD;
602 }
603 break;
604
605 case AddMidiDevice:
606 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddMidiDevice devicelist:%p device:%p\n", _midi_device_list, _midi_device);
607 _midi_device_list->push_back(_midi_device);
608 flags |= SC_CONFIG;
609 break;
610
611 case DeleteMidiDevice:
612 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeleteMidiDevice devicelist:%p device:%p\n", _midi_device_list, *_iMidiDevice);
613 _midi_device_list->erase(_iMidiDevice);
614 flags |= SC_CONFIG;
615 break;
616
617 case ModifyMidiDeviceAddress:
618 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyMidiDeviceAddress device:%p client:%d port:%d\n", _midi_device, _address_client, _address_port);
619 _midi_device->setAddressClient(_address_client);
620 _midi_device->setAddressPort(_address_port);
621 _midi_device->setOpenFlags(_open_flags);
622 flags |= SC_CONFIG;
623 break;
624
625 case ModifyMidiDeviceFlags:
626 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyMidiDeviceFlags device:%p rwFlags:%d openFlags:%d\n", _midi_device, _rw_flags, _open_flags);
627 _midi_device->setrwFlags(_rw_flags);
628 _midi_device->setOpenFlags(_open_flags);
629 flags |= SC_CONFIG;
630 break;
631
632 case ModifyMidiDeviceName:
633 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyMidiDeviceName device:%p name:%s\n", _midi_device, _name->toLocal8Bit().data());
634 _midi_device->setName(*_name);
635 flags |= SC_CONFIG;
636 break;
637
638 case SetInstrument:
639 #ifdef _PENDING_OPS_DEBUG_
640 fprintf(stderr, "PendingOperationItem::executeRTStage SetInstrument port:%p instr:%p\n",
641 _midi_port, _midi_instrument);
642 #endif
643 _midi_port->setInstrument(_midi_instrument);
644 // Flag the port to send initializations next time it bothers to check.
645 _midi_port->clearInitSent();
646 flags |= SC_MIDI_INSTRUMENT;
647 break;
648
649 case AddTrack:
650 {
651 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddTrack track_list:%p track:%p\n", _track_list, _track);
652 if(_void_track_list)
653 {
654 switch(_track->type())
655 {
656 case Track::MIDI:
657 case Track::DRUM:
658 static_cast<MidiTrackList*>(_void_track_list)->push_back(static_cast<MidiTrack*>(_track));
659 break;
660 case Track::WAVE:
661 static_cast<WaveTrackList*>(_void_track_list)->push_back(static_cast<WaveTrack*>(_track));
662 break;
663 case Track::AUDIO_OUTPUT:
664 //--------------------------------------------------------------
665 // Connect metronome audio click
666 //--------------------------------------------------------------
667 // Are there no other existing AudioOutput tracks?
668 if(static_cast<OutputList*>(_void_track_list)->empty())
669 // Do the user a favour: Auto-connect the metronome to the track.
670 static_cast<AudioOutput*>(_track)->setSendMetronome(true);
671
672 static_cast<OutputList*>(_void_track_list)->push_back(static_cast<AudioOutput*>(_track));
673 break;
674 case Track::AUDIO_GROUP:
675 static_cast<GroupList*>(_void_track_list)->push_back(static_cast<AudioGroup*>(_track));
676 break;
677 case Track::AUDIO_AUX:
678 static_cast<AuxList*>(_void_track_list)->push_back(static_cast<AudioAux*>(_track));
679 // Special for aux, make it easier to detect their changes.
680 flags |= SC_AUX;
681 break;
682 case Track::AUDIO_INPUT:
683 static_cast<InputList*>(_void_track_list)->push_back(static_cast<AudioInput*>(_track));
684 break;
685 case Track::AUDIO_SOFTSYNTH:
686 static_cast<SynthIList*>(_void_track_list)->push_back(static_cast<SynthI*>(_track));
687 break;
688 default:
689 ERROR_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddTrack: Unknown track type %d\n", _track->type());
690 return flags;
691 }
692 }
693
694 iTrack track_it = _track_list->index2iterator(_insert_at);
695 _track_list->insert(track_it, _track);
696 flags |= SC_TRACK_INSERTED;
697
698 // Add routes:
699 if(_track->isMidiTrack())
700 {
701 // Add any port output routes to this track
702 const RouteList* rl = _track->inRoutes();
703 for(ciRoute r = rl->begin(); r != rl->end(); ++r)
704 {
705 switch(r->type)
706 {
707 case Route::MIDI_PORT_ROUTE: {
708 Route src(_track, r->channel);
709 MusEGlobal::midiPorts[r->midiPort].outRoutes()->push_back(src);
710 flags |= SC_ROUTE; }
711 break;
712 case Route::TRACK_ROUTE:
713 case Route::JACK_ROUTE:
714 case Route::MIDI_DEVICE_ROUTE:
715 break;
716 }
717 }
718 // Add any port input routes from this track
719 rl = _track->outRoutes();
720 for(ciRoute r = rl->begin(); r != rl->end(); ++r)
721 {
722 switch(r->type)
723 {
724 case Route::MIDI_PORT_ROUTE: {
725 Route src(_track, r->channel);
726 MusEGlobal::midiPorts[r->midiPort].inRoutes()->push_back(src);
727 flags |= SC_ROUTE; }
728 break;
729 case Route::TRACK_ROUTE:
730 case Route::JACK_ROUTE:
731 case Route::MIDI_DEVICE_ROUTE:
732 break;
733 }
734 }
735 }
736 else
737 {
738 // Add other tracks' output routes to this track
739 const RouteList* rl = _track->inRoutes();
740 for(ciRoute r = rl->begin(); r != rl->end(); ++r)
741 {
742 switch(r->type)
743 {
744 case Route::TRACK_ROUTE: {
745 Route src(_track, r->remoteChannel, r->channels);
746 src.remoteChannel = r->channel;
747 r->track->outRoutes()->push_back(src);
748 flags |= SC_ROUTE;
749 // Is the source an Aux Track or else does it have Aux Tracks routed to it?
750 // Update this track's aux ref count.
751 if(r->track->auxRefCount())
752 {
753 _track->updateAuxRoute(r->track->auxRefCount(), NULL);
754 }
755 else if(r->track->type() == Track::AUDIO_AUX)
756 {
757 _track->updateAuxRoute(1, NULL);
758 }
759 }
760 break;
761 case Route::MIDI_PORT_ROUTE:
762 case Route::JACK_ROUTE:
763 case Route::MIDI_DEVICE_ROUTE:
764 break;
765 }
766 }
767 // Add other tracks' input routes from this track
768 rl = _track->outRoutes();
769 for(ciRoute r = rl->begin(); r != rl->end(); ++r)
770 {
771 switch(r->type)
772 {
773 case Route::TRACK_ROUTE: {
774 Route src(_track, r->remoteChannel, r->channels);
775 src.remoteChannel = r->channel;
776 r->track->inRoutes()->push_back(src);
777 flags |= SC_ROUTE;
778 // Is this track an Aux Track or else does it have Aux Tracks routed to it?
779 // Update the other track's aux ref count and all tracks it is connected to.
780 if(_track->auxRefCount())
781 {
782 r->track->updateAuxRoute(_track->auxRefCount(), NULL);
783 }
784 else if(_track->type() == Track::AUDIO_AUX)
785 {
786 r->track->updateAuxRoute(1, NULL);
787 }
788 }
789 break;
790 case Route::MIDI_PORT_ROUTE:
791 case Route::JACK_ROUTE:
792 case Route::MIDI_DEVICE_ROUTE:
793 break;
794 }
795 }
796 }
797 chainTrackParts(_track);
798
799 // Be sure to mark the parts as not deleted if they exist in the global copy/paste clone list.
800 const PartList* pl = _track->cparts();
801 for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)
802 {
803 for(iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)
804 {
805 if(i->cp == ip->second)
806 i->is_deleted = false;
807 }
808 }
809 }
810 break;
811
812 case DeleteTrack:
813 {
814 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeleteTrack track_list:%p track:%p sec_track_list:%p\n", _track_list, _track, _void_track_list);
815 unchainTrackParts(_track);
816 if(_void_track_list)
817 {
818 switch(_track->type())
819 {
820 case Track::MIDI:
821 case Track::DRUM:
822 static_cast<MidiTrackList*>(_void_track_list)->erase(_track);
823 break;
824 case Track::WAVE:
825 static_cast<WaveTrackList*>(_void_track_list)->erase(_track);
826 break;
827 case Track::AUDIO_OUTPUT:
828 static_cast<OutputList*>(_void_track_list)->erase(_track);
829 break;
830 case Track::AUDIO_GROUP:
831 static_cast<GroupList*>(_void_track_list)->erase(_track);
832 break;
833 case Track::AUDIO_AUX:
834 static_cast<AuxList*>(_void_track_list)->erase(_track);
835 // Special for aux, make it easier to detect their changes.
836 flags |= SC_AUX;
837 break;
838 case Track::AUDIO_INPUT:
839 static_cast<InputList*>(_void_track_list)->erase(_track);
840 break;
841 case Track::AUDIO_SOFTSYNTH:
842 {
843 static_cast<SynthIList*>(_void_track_list)->erase(_track);
844
845 // Change all ports which used the instrument.
846 // FIXME TODO: We want to make this undoable but ATM a few other things can
847 // set the instrument without an undo operation so the undo sequence would
848 // not be correct. So we don't have much choice but to just reset for now.
849 // Still, everything else is in place for undoable setting of instrument...
850 const SynthI* si = static_cast<const SynthI*>(_track);
851 for(int port = 0; port < MusECore::MIDI_PORTS; ++port)
852 {
853 MidiPort* mp = &MusEGlobal::midiPorts[port];
854 if(mp->instrument() != si)
855 continue;
856 // Just revert to GM.
857 mp->setInstrument(registerMidiInstrument("GM"));
858 // Flag the port to send initializations next time it bothers to check.
859 mp->clearInitSent();
860 flags |= SC_MIDI_INSTRUMENT;
861 }
862 }
863 break;
864 default:
865 ERROR_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeleteTrack: Unknown track type %d\n", _track->type());
866 return flags;
867 }
868 }
869 _track_list->erase(_track);
870 flags |= SC_TRACK_REMOVED;
871
872 // Remove routes:
873 if(_track->type() == Track::AUDIO_OUTPUT)
874 {
875 // Clear the track's jack ports
876 for(int ch = 0; ch < _track->channels(); ++ch)
877 {
878 ((AudioOutput*)_track)->setJackPort(ch, 0);
879 flags |= SC_ROUTE;
880 }
881
882 // Clear the track's output routes' jack ports
883 RouteList* orl = _track->outRoutes();
884 for(iRoute r = orl->begin(); r != orl->end(); ++r)
885 {
886 if(r->type != Route::JACK_ROUTE)
887 continue;
888 r->jackPort = 0;
889 flags |= SC_ROUTE;
890 }
891 }
892 else if(_track->type() == Track::AUDIO_INPUT)
893 {
894 // Clear the track's jack ports
895 for(int ch = 0; ch < _track->channels(); ++ch)
896 {
897 ((AudioInput*)_track)->setJackPort(ch, 0);
898 flags |= SC_ROUTE;
899 }
900
901 // Clear the track's input routes' jack ports
902 RouteList* irl = _track->inRoutes();
903 for(iRoute r = irl->begin(); r != irl->end(); ++r)
904 {
905 if(r->type != Route::JACK_ROUTE)
906 continue;
907 r->jackPort = 0;
908 flags |= SC_ROUTE;
909 }
910 }
911
912 if(_track->isMidiTrack())
913 {
914 // Remove any port output routes to this track
915 const RouteList* rl = _track->inRoutes();
916 for(ciRoute r = rl->begin(); r != rl->end(); ++r)
917 {
918 switch(r->type)
919 {
920 case Route::MIDI_PORT_ROUTE: {
921 Route src(_track, r->channel);
922 MusEGlobal::midiPorts[r->midiPort].outRoutes()->removeRoute(src);
923 flags |= SC_ROUTE; }
924 break;
925 case Route::TRACK_ROUTE:
926 case Route::JACK_ROUTE:
927 case Route::MIDI_DEVICE_ROUTE:
928 break;
929 }
930 }
931 // Remove any port input routes from this track
932 rl = _track->outRoutes();
933 for(ciRoute r = rl->begin(); r != rl->end(); ++r)
934 {
935 switch(r->type)
936 {
937 case Route::MIDI_PORT_ROUTE: {
938 Route src(_track, r->channel);
939 MusEGlobal::midiPorts[r->midiPort].inRoutes()->removeRoute(src);
940 flags |= SC_ROUTE; }
941 break;
942 case Route::TRACK_ROUTE:
943 case Route::JACK_ROUTE:
944 case Route::MIDI_DEVICE_ROUTE:
945 break;
946 }
947 }
948 }
949 else
950 {
951 // Remove other tracks' output routes to this track
952 const RouteList* rl = _track->inRoutes();
953 for(ciRoute r = rl->begin(); r != rl->end(); ++r)
954 {
955 switch(r->type)
956 {
957 case Route::TRACK_ROUTE: {
958 Route src(_track, r->remoteChannel, r->channels);
959 src.remoteChannel = r->channel;
960 r->track->outRoutes()->removeRoute(src);
961 flags |= SC_ROUTE;
962 // Is the source an Aux Track or else does it have Aux Tracks routed to it?
963 // Update this track's aux ref count.
964 if(r->track->auxRefCount())
965 {
966 _track->updateAuxRoute(-r->track->auxRefCount(), NULL);
967 }
968 else if(r->track->type() == Track::AUDIO_AUX)
969 {
970 _track->updateAuxRoute(-1, NULL);
971 }
972 }
973 break;
974 case Route::MIDI_PORT_ROUTE:
975 case Route::JACK_ROUTE:
976 case Route::MIDI_DEVICE_ROUTE:
977 break;
978 }
979 }
980 // Remove other tracks' input routes from this track
981 rl = _track->outRoutes();
982 for(ciRoute r = rl->begin(); r != rl->end(); ++r)
983 {
984 switch(r->type)
985 {
986 case Route::TRACK_ROUTE: {
987 Route src(_track, r->remoteChannel, r->channels);
988 src.remoteChannel = r->channel;
989 r->track->inRoutes()->removeRoute(src);
990 flags |= SC_ROUTE;
991 // Is this track an Aux Track or else does it have Aux Tracks routed to it?
992 // Update the other track's aux ref count and all tracks it is connected to.
993 if(_track->auxRefCount())
994 {
995 r->track->updateAuxRoute(-_track->auxRefCount(), NULL);
996 }
997 else if(_track->type() == Track::AUDIO_AUX)
998 {
999 r->track->updateAuxRoute(-1, NULL);
1000 }
1001 }
1002 break;
1003 case Route::MIDI_PORT_ROUTE:
1004 case Route::JACK_ROUTE:
1005 case Route::MIDI_DEVICE_ROUTE:
1006 break;
1007 }
1008 }
1009 }
1010
1011 // Be sure to mark the parts as deleted if they exist in the global copy/paste clone list.
1012 const PartList* pl = _track->cparts();
1013 for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)
1014 {
1015 for(iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)
1016 {
1017 if(i->cp == ip->second)
1018 i->is_deleted = true;
1019 }
1020 }
1021 }
1022 break;
1023
1024 case MoveTrack:
1025 {
1026 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage MoveTrack from:%d to:%d\n", _from_idx, _to_idx);
1027 const int sz = _track_list->size();
1028 if(_from_idx >= sz)
1029 {
1030 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationItem::executeRTStage MoveTrack from index out of range:%d\n", _from_idx);
1031 return flags;
1032 }
1033 ciTrack fromIt = _track_list->cbegin() + _from_idx;
1034 Track* track = *fromIt;
1035 _track_list->erase(fromIt);
1036 ciTrack toIt = (_to_idx >= sz) ? _track_list->cend() : _track_list->cbegin() + _to_idx;
1037 _track_list->insert(toIt, track);
1038 flags |= SC_TRACK_MOVED;
1039 }
1040 break;
1041
1042 case ModifyTrackName:
1043 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyTrackName track:%p new_val:%s\n", _track, _name->toLocal8Bit().data());
1044 _track->setName(*_name);
1045 flags |= (SC_TRACK_MODIFIED | SC_MIDI_TRACK_PROP);
1046 // If it's an aux track, notify aux UI controls to reload, or change their names etc.
1047 if(_track->type() == Track::AUDIO_AUX)
1048 flags |= SC_AUX;
1049 break;
1050
1051 case SetTrackRecord:
1052 {
1053 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage SetTrackRecord track:%p new_val:%d\n", _track, _boolA);
1054 const bool mon = _track->setRecordFlag2AndCheckMonitor(_boolA);
1055 flags |= SC_RECFLAG;
1056 if(mon)
1057 flags |= SC_TRACK_REC_MONITOR;
1058 }
1059 break;
1060
1061 case SetTrackMute:
1062 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage SetTrackMute track:%p new_val:%d\n", _track, _boolA);
1063 _track->setMute(_boolA);
1064 flags |= SC_MUTE;
1065 break;
1066
1067 case SetTrackSolo:
1068 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage SetTrackSolo track:%p new_val:%d\n", _track, _boolA);
1069 _track->setSolo(_boolA);
1070 flags |= SC_SOLO;
1071 break;
1072
1073 case SetTrackRecMonitor:
1074 #ifdef _PENDING_OPS_DEBUG_
1075 fprintf(stderr, "PendingOperationItem::executeRTStage SetTrackRecMonitor track:%p new_val:%d\n", _track, _boolA);
1076 #endif
1077 _track->setRecMonitor(_boolA);
1078 flags |= SC_TRACK_REC_MONITOR;
1079 break;
1080
1081 case SetTrackOff:
1082 #ifdef _PENDING_OPS_DEBUG_
1083 fprintf(stderr, "PendingOperationItem::executeRTStage SetTrackOff track:%p new_val:%d\n", _track, _boolA);
1084 #endif
1085 _track->setOff(_boolA);
1086 flags |= SC_MUTE;
1087 break;
1088
1089
1090 case AddPart:
1091 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddPart part:%p\n", _part);
1092 _part_list->add(_part);
1093 _part->rechainClone();
1094 // Be sure to mark the part as not deleted if it exists in the global copy/paste clone list.
1095 for(iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)
1096 {
1097 if(i->cp == _part)
1098 i->is_deleted = false;
1099 }
1100 flags |= SC_PART_INSERTED;
1101 // If the part has events, then treat it as if they were inserted with separate AddEvent operations.
1102 // Even if some will be inserted later in this operations group with actual separate AddEvent operations,
1103 // that's an SC_EVENT_INSERTED anyway, so hopefully no harm.
1104 if(!_part->events().empty())
1105 flags |= SC_EVENT_INSERTED;
1106 break;
1107
1108 case DeletePart:
1109 {
1110 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeletePart part:%p\n", _iPart->second);
1111 Part* p = _iPart->second;
1112 _part_list->erase(_iPart);
1113 p->unchainClone();
1114 // Be sure to mark the part as deleted if it exists in the global copy/paste clone list.
1115 for(iClone i = MusEGlobal::cloneList.begin(); i != MusEGlobal::cloneList.end(); ++i)
1116 {
1117 if(i->cp == p)
1118 i->is_deleted = true;
1119 }
1120 flags |= SC_PART_REMOVED;
1121 // If the part had events, then treat it as if they were removed with separate DeleteEvent operations.
1122 // Even if they will be deleted later in this operations group with actual separate DeleteEvent operations,
1123 // that's an SC_EVENT_REMOVED anyway, so hopefully no harm. This fixes a problem with midi controller canvas
1124 // not updating after such a 'delete part with events, no separate AddEvents were used when creating the part'.
1125 if(!p->events().empty())
1126 flags |= SC_EVENT_REMOVED;
1127 }
1128 break;
1129
1130 case ModifyPartStart:
1131 {
1132 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyPartStart part:%p old_val:%d new_val:%u\n", _part, _part->posValue(), _posLenVal);
1133
1134 // Since we are modifying a part's position we must remove the part from the list
1135 // and reinsert it afterwards for proper sorting (position is the sorting key).
1136 if(_part->track() && _iPart != _part->track()->parts()->end())
1137 {
1138 _part->track()->parts()->erase(_iPart);
1139 flags |= SC_PART_REMOVED;
1140 }
1141
1142 // Was an event list supplied to be wholesale swapped?
1143 if(_event_list)
1144 {
1145 // Since the original event list is not an allocated pointer, there are no pointers to quickly exchange.
1146 // Instead use swap() which is also constant in time. Just like quickly exchanging pointers.
1147 // Transfers the original list back to _event_list so it can be deleted in the non-RT stage.
1148 (&_part->nonconst_events())->swap(*_event_list);
1149 flags |= (SC_EVENT_MODIFIED | SC_EVENT_INSERTED | SC_EVENT_REMOVED);
1150 }
1151
1152 _part->setLenValue(_lenVal);
1153 _part->setPosValue(_posLenVal);
1154 if(_part->track())
1155 {
1156 _part->track()->parts()->add(_part);
1157 flags |= SC_PART_INSERTED;
1158 }
1159 flags |= SC_PART_MODIFIED;
1160 }
1161 break;
1162
1163 case ModifyPartLength:
1164 {
1165 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyPartLength part:%p old_val:%d new_val:%u\n", _part, _part->lenValue(), _posLenVal);
1166
1167 // Was an event list supplied to be wholesale swapped?
1168 if(_event_list)
1169 {
1170 // Since the original event list is not an allocated pointer, there are no pointers to quickly exchange.
1171 // Instead use swap() which is also constant in time. Just like quickly exchanging pointers.
1172 // Transfers the original list back to _event_list so it can be deleted in the non-RT stage.
1173 (&_part->nonconst_events())->swap(*_event_list);
1174 flags |= (SC_EVENT_MODIFIED | SC_EVENT_INSERTED | SC_EVENT_REMOVED);
1175 }
1176 _part->setLenValue(_posLenVal);
1177 flags |= SC_PART_MODIFIED;
1178 }
1179 break;
1180
1181 case MovePart:
1182 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage MovePart part:%p track:%p new_pos:%u\n", _part, _track, _posLenVal);
1183 if(_track)
1184 {
1185 if(_part->track() && _iPart != _part->track()->parts()->end())
1186 {
1187 _part->track()->parts()->erase(_iPart);
1188 flags |= SC_PART_REMOVED;
1189 }
1190 _part->setTrack(_track);
1191 //_part->setTick(_posLenVal);
1192 _part->setPosValue(_posLenVal);
1193 _track->parts()->add(_part);
1194 flags |= SC_PART_INSERTED;
1195 }
1196 else
1197 {
1198 //_part->setTick(_posLenVal);
1199 _part->setPosValue(_posLenVal);
1200 }
1201 flags |= SC_PART_MODIFIED;
1202 break;
1203
1204 case SelectPart:
1205 #ifdef _PENDING_OPS_DEBUG_
1206 fprintf(stderr, "PendingOperationItem::executeRTStage SelectPart part:%p select:%u\n", _part, _boolA);
1207 #endif
1208 if(_part)
1209 _part->setSelected(_boolA);
1210
1211 flags |= SC_PART_SELECTION;
1212 break;
1213
1214 case ModifyPartName:
1215 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyPartName part:%p new_val:%s\n", _part, _name->toLocal8Bit().data());
1216 _part->setName(*_name);
1217 flags |= SC_PART_MODIFIED;
1218 break;
1219
1220
1221 case AddEvent:
1222 #ifdef _PENDING_OPS_DEBUG_
1223 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddEvent pre: ");
1224 _ev.dump();
1225 #endif
1226 _part->addEvent(_ev);
1227 #ifdef _PENDING_OPS_DEBUG_
1228 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddEvent post: ");
1229 _ev.dump();
1230 #endif
1231 flags |= SC_EVENT_INSERTED;
1232 break;
1233
1234 case DeleteEvent:
1235 #ifdef _PENDING_OPS_DEBUG_
1236 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeleteEvent pre: ");
1237 _ev.dump();
1238 #endif
1239 _part->nonconst_events().erase(_iev);
1240 #ifdef _PENDING_OPS_DEBUG_
1241 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeleteEvent post: ");
1242 _ev.dump();
1243 #endif
1244 flags |= SC_EVENT_REMOVED;
1245 break;
1246
1247 case SelectEvent:
1248 #ifdef _PENDING_OPS_DEBUG_
1249 fprintf(stderr, "PendingOperationItem::executeRTStage SelectEvent part:%p select:%d\n", _part, _intA);
1250 #endif
1251 // Make sure we let song handle this important job, it selects corresponding events in clone parts.
1252 MusEGlobal::song->selectEvent(_ev, _part, _intA);
1253 flags |= SC_SELECTION;
1254 break;
1255
1256
1257 case ModifyEventList:
1258 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyEventList: orig eventlist:%p new eventlist:%p\n",
1259 _orig_event_list, _event_list);
1260 if(_orig_event_list && _event_list)
1261 {
1262 // Since the original event list is not an allocated pointer, there are no pointers to quickly exchange.
1263 // Instead use swap() which is also constant in time. Just like quickly exchanging pointers.
1264 // Transfers the original list back to _event_list so it can be deleted in the non-RT stage.
1265 _orig_event_list->swap(*_event_list);
1266 flags |= (SC_EVENT_MODIFIED | SC_EVENT_INSERTED | SC_EVENT_REMOVED);
1267 }
1268 break;
1269
1270 case AddMidiCtrlValList:
1271 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddMidiCtrlValList: mcvll:%p mcvl:%p chan:%d\n", _mcvll, _mcvl, _intA);
1272 _mcvll->add(_intA, _mcvl);
1273 flags |= SC_MIDI_CONTROLLER_ADD;
1274 break;
1275 case ModifyMidiCtrlValList:
1276 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyMidiCtrlValList: orig_mcvl:%p mcvl:%p\n", _orig_mcvl, _mcvl);
1277 if(_orig_mcvl && _mcvl)
1278 {
1279 // Since the original list is not an allocated pointer, there are no pointers to quickly exchange.
1280 // Instead use swap() which is also constant in time. Just like quickly exchanging pointers.
1281 // Transfers the original list back to _mcvl so it can be deleted in the non-RT stage.
1282 _orig_mcvl->swap(*_mcvl);
1283 // No song changed flags are required to be set here.
1284 }
1285 break;
1286 case AddMidiCtrlVal:
1287 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddMidiCtrlVal: mcvl:%p part:%p tick:%u val:%d\n", _mcvl, _part, _posLenVal, _intB);
1288 // Do not attempt to add cached events which are outside of the part.
1289 // But do allow muted parts, and muted tracks, and 'off' tracks. Otherwise adding values
1290 // to muted parts fails to add them when unmuted. The cache mechanism catches this anyways.
1291 #ifdef ALLOW_LEFT_HIDDEN_EVENTS
1292 if((int)_posLenVal >= (int)_part->posValue() &&
1293 (int)_posLenVal < (int)_part->posValue() + (int)_part->lenValue())
1294 #else
1295 if(_posLenVal >= _part->posValue() &&
1296 _posLenVal < _part->posValue() + _part->lenValue())
1297 #endif
1298 // FIXME FINDMICHJETZT XTicks!!
1299 _mcvl->insert(MidiCtrlValListInsertPair_t(_posLenVal, MidiCtrlVal(_part, _intB)));
1300 // No song changed flags are required to be set here.
1301 break;
1302 case DeleteMidiCtrlVal:
1303 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeleteMidiCtrlVal: mcvl:%p tick:%u part:%p val:%d\n",
1304 _mcvl, _imcv->first, _imcv->second.part, _imcv->second.val);
1305 _mcvl->erase(_imcv);
1306 // No song changed flags are required to be set here.
1307 break;
1308 case ModifyMidiCtrlVal:
1309 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyMidiCtrlVal: part:%p old_val:%d new_val:%d\n",
1310 _imcv->second.part, _imcv->second.val, _intA);
1311 _imcv->second.val = _intA;
1312 break;
1313
1314
1315 case ModifyAudioCtrlValList:
1316 {
1317 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyAudioCtrlValList: old ctrl_l:%p new ctrl_l:%p\n", _iCtrlList->second, _aud_ctrl_list);
1318 CtrlList* orig = _iCtrlList->second;
1319 _iCtrlList->second = _aud_ctrl_list;
1320 // Transfer the original pointer back to _aud_ctrl_list so it can be deleted in the non-RT stage.
1321 _aud_ctrl_list = orig;
1322 flags |= SC_AUDIO_CONTROLLER_LIST;
1323 }
1324 break;
1325 case AddAudioCtrlVal:
1326 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddAudioCtrlVal: ctrl_l:%p frame:%u val:%f\n",
1327 _aud_ctrl_list, _posLenVal, _ctl_dbl_val);
1328 //_aud_ctrl_list->insert(CtrlListInsertPair_t(_posLenVal, CtrlVal(_posLenVal, _ctl_dbl_val)));
1329 // Add will replace if found.
1330 _aud_ctrl_list->add(_posLenVal, _ctl_dbl_val);
1331 flags |= SC_AUDIO_CONTROLLER;
1332 break;
1333 case DeleteAudioCtrlVal:
1334 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeleteAudioCtrlVal: ctrl_l:%p ctrl_num:%d frame:%d val:%f\n",
1335 _aud_ctrl_list, _aud_ctrl_list->id(), _iCtrl->first, _iCtrl->second.val);
1336 _aud_ctrl_list->erase(_iCtrl);
1337 flags |= SC_AUDIO_CONTROLLER;
1338 break;
1339 case ModifyAudioCtrlVal:
1340 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyAudioCtrlVal: frame:%u old_val:%f new_val:%f\n",
1341 _iCtrl->first, _iCtrl->second.val, _ctl_dbl_val);
1342 // If the frame is the same, just change the value.
1343 if(_iCtrl->second.frame == _posLenVal)
1344 {
1345 _iCtrl->second.val = _ctl_dbl_val;
1346 }
1347 // Otherwise erase + add is required.
1348 else
1349 {
1350 _aud_ctrl_list->erase(_iCtrl);
1351 _aud_ctrl_list->insert(CtrlListInsertPair_t(_posLenVal, CtrlVal(_posLenVal, _ctl_dbl_val)));
1352 }
1353 flags |= SC_AUDIO_CONTROLLER;
1354 break;
1355
1356
1357 case ModifyTempoList:
1358 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyTempoList: orig tempolist:%p new tempolist:%p\n",
1359 _orig_tempo_list, _tempo_list);
1360 if(_orig_tempo_list && _tempo_list)
1361 {
1362 // Since the original tempo list is not an allocated pointer, there are no pointers to quickly exchange.
1363 // Instead use swap() which is also constant in time. Just like quickly exchanging pointers.
1364 // Transfers the original list back to _tempo_list so it can be deleted in the non-RT stage.
1365 _orig_tempo_list->swap(*_tempo_list);
1366 flags |= SC_TEMPO;
1367 }
1368 break;
1369
1370
1371 case SetStaticTempo:
1372 #ifdef _PENDING_OPS_DEBUG_
1373 fprintf(stderr, "PendingOperationItem::executeRTStage SetStaticTempo: tempolist:%p new_tempo:%d\n", _tempo_list, _intA);
1374 #endif
1375 _tempo_list->setStaticTempo(_intA);
1376 flags |= SC_TEMPO;
1377 break;
1378
1379 case SetGlobalTempo:
1380 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage SetGlobalTempo: tempolist:%p new_tempo:%d\n", _tempo_list, _intA);
1381 _tempo_list->setGlobalTempo(_intA);
1382 flags |= SC_TEMPO;
1383 break;
1384
1385
1386 case ModifySigList:
1387 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifySigList: orig siglist:%p new siglist:%p\n",
1388 _orig_sig_list, _sig_list);
1389 if(_orig_sig_list && _sig_list)
1390 {
1391 // Since the original sig list is not an allocated pointer, there are no pointers to quickly exchange.
1392 // Instead use swap() which is also constant in time. Just like quickly exchanging pointers.
1393 // Transfers the original list back to _sig_list so it can be deleted in the non-RT stage.
1394 _orig_sig_list->swap(*_sig_list);
1395 flags |= SC_SIG;
1396 }
1397 break;
1398
1399
1400
1401 case ModifyKeyList:
1402 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyKeyList: orig keylist:%p new keylist:%p\n",
1403 _orig_key_list, _key_list);
1404 if(_orig_key_list && _key_list)
1405 {
1406 // Since the original key list is not an allocated pointer, there are no pointers to quickly exchange.
1407 // Instead use swap() which is also constant in time. Just like quickly exchanging pointers.
1408 // Transfers the original list back to _sig_list so it can be deleted in the non-RT stage.
1409 _orig_key_list->swap(*_key_list);
1410 flags |= SC_KEY;
1411 }
1412 break;
1413
1414
1415 case ModifyStretchListRatio:
1416 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyStretchListRatio: stretchType:%d stretchlist:%p new_ratio:%f\n",
1417 _stretch_type, _stretch_list, _audio_converter_value);
1418 // Defer normalize until end of stage 2.
1419 _stretch_list->setRatio(StretchListItem::StretchEventType(_stretch_type), _audio_converter_value, false);
1420 flags |= SC_AUDIO_STRETCH;
1421 break;
1422
1423 case AddStretchListRatioAt:
1424 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage AddStretchListRatioAt: stretchType:%d stretchlist:%p ratio:%f frame:%ld\n",
1425 _stretch_type, _stretch_list, _audio_converter_value, _museFrame);
1426 // Defer normalize until end of stage 2.
1427 _stretch_list->addRatioAt(StretchListItem::StretchEventType(_stretch_type), _museFrame, _audio_converter_value, false);
1428
1429 flags |= SC_AUDIO_STRETCH;
1430 break;
1431
1432 case DeleteStretchListRatioAt:
1433 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage DeleteStretchListRatioAt: stretchlist:%p frame:%ld types:%d\n",
1434 _stretch_list, _iStretchEvent->first, _stretch_type);
1435 // Defer normalize until end of stage 2.
1436 _stretch_list->del(_stretch_type, _iStretchEvent, false);
1437 flags |= SC_AUDIO_STRETCH;
1438 break;
1439
1440 case ModifyStretchListRatioAt:
1441 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifyStretchListRatioAt: "
1442 "stretchType:%d stretchlist:%p frame:%ld new_frame:%ld new_ratio:%f\n",
1443 _stretch_type, _stretch_list, _iStretchEvent->first, _museFrame, _audio_converter_value);
1444
1445 // If the frame is the same, just change the value.
1446 if(_iStretchEvent->first == _museFrame)
1447 // Defer normalize until end of stage 2.
1448 _stretch_list->setRatioAt(StretchListItem::StretchEventType(_stretch_type), _iStretchEvent, _audio_converter_value, false);
1449 // Otherwise erase + add is required.
1450 else
1451 {
1452 // Defer normalize until end of stage 2.
1453 _stretch_list->del(_stretch_type, _iStretchEvent, false);
1454 _stretch_list->add(StretchListItem::StretchEventType(_stretch_type), _museFrame, _audio_converter_value, false);
1455 }
1456
1457 flags |= SC_AUDIO_STRETCH;
1458 break;
1459
1460
1461 case ModifySongLength:
1462 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage ModifySongLength: len:%d\n", _posLenVal);
1463 MusEGlobal::song->setLen(_posLenVal, false); // false = Do not emit update signals here !
1464 flags |= SC_EVERYTHING;
1465 break;
1466
1467 case EnableAllAudioControllers:
1468 {
1469 DEBUG_OPERATIONS(stderr, "PendingOperationItem::executeRTStage EnableAllAudioControllers\n");
1470 TrackList* tl = MusEGlobal::song->tracks();
1471 for (iTrack it = tl->begin(); it != tl->end(); ++it)
1472 {
1473 Track* t = *it;
1474 if(t->isMidiTrack())
1475 continue;
1476 AudioTrack *at = static_cast<AudioTrack*>(t);
1477 // Re-enable all track and plugin controllers, and synth controllers if applicable.
1478 at->enableAllControllers();
1479 flags |= SC_AUDIO_CONTROLLER;
1480 }
1481 }
1482 break;
1483
1484 case GlobalSelectAllEvents:
1485 {
1486 #ifdef _PENDING_OPS_DEBUG_
1487 fprintf(stderr, "PendingOperationItem::executeRTStage GlobalSelectAllEvents\n");
1488 #endif
1489 for (iTrack it = _track_list->begin(); it != _track_list->end(); ++it)
1490 {
1491 //Track* t = *it;
1492 //if(t->isMidiTrack())
1493 // continue;
1494 if((*it)->selectEvents(_boolA))
1495 flags |= SC_SELECTION;
1496 }
1497 }
1498 break;
1499
1500 case ModifyAudioSamples:
1501 {
1502 #ifdef _PENDING_OPS_DEBUG_
1503 fprintf(stderr, "PendingOperationItem::executeRTStage ModifyAudioSamples: "
1504 "audioSamplesPointer:%p newAudioSamples:%p audioSamplesLen:%p newAudioSamplesLen:%d\n",
1505 _audioSamplesPointer, _newAudioSamples, _audioSamplesLen, _newAudioSamplesLen);
1506 #endif
1507 if(_audioSamplesPointer)
1508 {
1509 float* orig = *_audioSamplesPointer;
1510 *_audioSamplesPointer = _newAudioSamples;
1511 // Transfer the original pointer back to _audioSamplesPointer so it can be deleted in the non-RT stage.
1512 _newAudioSamples = orig;
1513 }
1514
1515 if(_audioSamplesLen)
1516 *_audioSamplesLen = _newAudioSamplesLen;
1517
1518 // Currently no flags for this.
1519 //flags |= SC_;
1520 }
1521 break;
1522
1523 case ModifyMarkerList:
1524 {
1525 #ifdef _PENDING_OPS_DEBUG_
1526 fprintf(stderr, "PendingOperationItem::executeRTStage ModifyMarkerList: "
1527 "orig list:%p new list:%p\n", _orig_marker_list, _marker_list);
1528 #endif
1529 if(_orig_marker_list && _marker_list)
1530 {
1531 MarkerList* orig = *_orig_marker_list;
1532 *_orig_marker_list = _marker_list;
1533 // Transfer the original pointer back to _marker_list so it can be deleted in the non-RT stage.
1534 _marker_list = orig;
1535 }
1536 // Currently no flags for this.
1537 //flags |= SC_MARKERS_REBUILT;
1538 }
1539 break;
1540
1541 case SwitchMetronomeSettings:
1542 {
1543 #ifdef _PENDING_OPS_DEBUG_
1544 fprintf(stderr, "PendingOperationItem::executeRTStage SwitchMetronomeSettings: settings:%p val:%d\n", _bool_pointer, _boolA);
1545 #endif
1546 *_bool_pointer = _boolA;
1547 flags |= SC_METRONOME;
1548 }
1549 break;
1550
1551 case ModifyMetronomeAccentMap:
1552 {
1553 #ifdef _PENDING_OPS_DEBUG_
1554 fprintf(stderr, "PendingOperationItem::executeRTStage ModifyMetronomeAccentMap: old map:%p new map:%p\n", _metroAccentsMap, _newMetroAccentsMap);
1555 #endif
1556 MetroAccentsMap* orig = *_metroAccentsMap;
1557 *_metroAccentsMap = _newMetroAccentsMap;
1558 // Transfer the original pointer back to _newMetroAccentsMap so it can be deleted in the non-RT stage.
1559 _newMetroAccentsMap = orig;
1560 flags |= SC_METRONOME;
1561 }
1562 break;
1563
1564 case SetExternalSyncFlag:
1565 {
1566 #ifdef _PENDING_OPS_DEBUG_
1567 fprintf(stderr, "PendingOperationItem::executeRTStage SetExternalSyncFlag: pointer:%p val:%d\n", _bool_pointer, _boolA);
1568 #endif
1569 *_bool_pointer = _boolA;
1570 flags |= SC_EXTERNAL_MIDI_SYNC;
1571 }
1572 break;
1573
1574 case SetUseJackTransport:
1575 {
1576 #ifdef _PENDING_OPS_DEBUG_
1577 fprintf(stderr, "PendingOperationItem::executeRTStage SetUseJackTransport: pointer:%p val:%d\n", _bool_pointer, _boolA);
1578 #endif
1579 *_bool_pointer = _boolA;
1580 flags |= SC_USE_JACK_TRANSPORT;
1581 }
1582 break;
1583
1584 case SetUseMasterTrack:
1585 {
1586 #ifdef _PENDING_OPS_DEBUG_
1587 fprintf(stderr, "PendingOperationItem::executeRTStage SetUseMasterTrack: pointer:%p val:%d\n", _tempo_list, _boolA);
1588 #endif
1589 _tempo_list->setMasterFlag(0, _boolA);
1590 flags |= SC_MASTER;
1591 }
1592 break;
1593
1594 case Uninitialized:
1595 break;
1596
1597 default:
1598 ERROR_OPERATIONS(stderr, "PendingOperationItem::executeRTStage unknown type %d\n", _type);
1599 break;
1600 }
1601 return flags;
1602 }
1603
executeNonRTStage()1604 SongChangedStruct_t PendingOperationItem::executeNonRTStage()
1605 {
1606 SongChangedStruct_t flags = 0;
1607 switch(_type)
1608 {
1609 case ModifyPartStart:
1610 case ModifyPartLength:
1611 // At this point _event_list contains all the items that were in the original event list, via swap(). Delete it now.
1612 if(_event_list)
1613 delete _event_list;
1614 break;
1615
1616 case ModifyEventList:
1617 // At this point _event_list contains all the items that were in the original event list, via swap(). Delete it now.
1618 if(_event_list)
1619 delete _event_list;
1620 break;
1621
1622 case ModifyMidiCtrlValList:
1623 // At this point _mcvl contains all the items that were in the original event list, via swap(). Delete it now.
1624 if(_mcvl)
1625 delete _mcvl;
1626 break;
1627
1628 case AddRoute:
1629 if(MusEGlobal::song->connectJackRoutes(_src_route, _dst_route))
1630 flags |= SC_ROUTE;
1631 break;
1632
1633 case DeleteRoute:
1634 if(MusEGlobal::song->connectJackRoutes(_src_route, _dst_route, true))
1635 flags |= SC_ROUTE;
1636 break;
1637
1638 case ModifyTempoList:
1639 // At this point _tempo_list contains all the items that were in the original tempo list, via swap(). Delete it now.
1640 if(_tempo_list)
1641 delete _tempo_list;
1642 break;
1643
1644
1645 case ModifySigList:
1646 // At this point _sig_list contains all the items that were in the original sig list, via swap(). Delete it now.
1647 if(_sig_list)
1648 delete _sig_list;
1649 break;
1650
1651
1652 case ModifyKeyList:
1653 // At this point _key_list contains all the items that were in the original key list, via swap(). Delete it now.
1654 if(_key_list)
1655 delete _key_list;
1656 break;
1657
1658
1659 case ModifyLocalAudioConverterSettings:
1660 // At this point these are the original pointers that were replaced. Delete the original objects now.
1661 if(_audio_converter_settings)
1662 delete _audio_converter_settings;
1663 break;
1664
1665 case ModifyLocalAudioConverter:
1666 // At this point these are the original pointers that were replaced. Delete the original objects now.
1667 if(_audio_converter)
1668 delete _audio_converter;
1669 if(_audio_converter_ui)
1670 delete _audio_converter_ui;
1671 break;
1672
1673 case SetAudioConverterOfflineMode:
1674 // At this point this is the original pointer that were replaced. Delete the original object now.
1675 if(_audio_converter)
1676 delete _audio_converter;
1677 break;
1678
1679 case ModifyDefaultAudioConverterSettings:
1680 // At this point this is the original pointer that was replaced. Delete the original object now.
1681 if(_audio_converter_settings)
1682 delete _audio_converter_settings;
1683 break;
1684
1685 case ReplaceMidiInstrument:
1686 // At this point _midi_instrument is the original instrument that was replaced. Delete it now.
1687 if(_midi_instrument)
1688 delete _midi_instrument;
1689 break;
1690
1691 case ModifyAudioCtrlValList:
1692 // At this point _aud_ctrl_list is the original list that was replaced. Delete it now.
1693 if(_aud_ctrl_list)
1694 delete _aud_ctrl_list;
1695 break;
1696
1697 case ModifyTrackDrumMapItem:
1698 // Discard the operation, it has already completed.
1699 if(_drum_map_track_operation)
1700 delete _drum_map_track_operation;
1701 break;
1702
1703 case ReplaceTrackDrumMapPatchList:
1704 // Discard the operation, it has already completed.
1705 if(_drum_map_track_patch_operation)
1706 {
1707 // At this point _workingItemPatchList is the original list that was replaced. Delete it now.
1708 if(_drum_map_track_patch_replace_operation->_workingItemPatchList)
1709 delete _drum_map_track_patch_replace_operation->_workingItemPatchList;
1710
1711 delete _drum_map_track_patch_replace_operation;
1712 }
1713 break;
1714
1715 case RemapDrumControllers:
1716 // Discard the operation, it has already completed.
1717 if(_midi_ctrl_val_remap_operation)
1718 {
1719 // At this point _midiCtrlValLists2bDeleted contains the original lists that were replaced. Delete them now.
1720 for(iMidiCtrlValLists2bDeleted_t imvld = _midi_ctrl_val_remap_operation->_midiCtrlValLists2bDeleted.begin();
1721 imvld != _midi_ctrl_val_remap_operation->_midiCtrlValLists2bDeleted.end(); ++imvld)
1722 delete *imvld;
1723
1724 delete _midi_ctrl_val_remap_operation;
1725 }
1726 break;
1727
1728 case ModifyAudioSamples:
1729 // At this point _newAudioSamples points to the original memory that was replaced. Delete it now.
1730 if(_newAudioSamples)
1731 delete _newAudioSamples;
1732 break;
1733
1734 case ModifyMarkerList:
1735 // At this point _marker_list points to the original memory that was replaced. Delete it now.
1736 if(_marker_list)
1737 delete _marker_list;
1738 break;
1739
1740 case ModifyMetronomeAccentMap:
1741 // At this point _newMetroAccentsMap is the original list that was replaced. Delete it now.
1742 if(_newMetroAccentsMap)
1743 delete _newMetroAccentsMap;
1744 break;
1745
1746 default:
1747 break;
1748 }
1749 return flags;
1750 }
1751
executeRTStage()1752 SongChangedStruct_t PendingOperationList::executeRTStage()
1753 {
1754 DEBUG_OPERATIONS(stderr, "PendingOperationList::executeRTStage executing...\n");
1755 for(iPendingOperation ip = begin(); ip != end(); ++ip)
1756 _sc_flags |= ip->executeRTStage();
1757
1758 // To avoid doing this item by item, do it here.
1759 if(_sc_flags & (SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_ROUTE))
1760 {
1761 MusEGlobal::song->updateSoloStates();
1762 _sc_flags |= SC_SOLO;
1763 }
1764
1765 // To avoid doing this item by item, do it here.
1766 StretchList* sl;
1767 for(iPendingOperation ip = begin(); ip != end(); ++ip)
1768 {
1769 const PendingOperationItem& poi = *ip;
1770 switch(poi._type)
1771 {
1772 //case PendingOperationItem::AddSamplerateRatioAt:
1773 //case PendingOperationItem::DeleteSamplerateRatioAt:
1774 //case PendingOperationItem::ModifySamplerateRatioAt:
1775 case PendingOperationItem::AddStretchListRatioAt:
1776 case PendingOperationItem::DeleteStretchListRatioAt:
1777 case PendingOperationItem::ModifyStretchListRatioAt:
1778 case PendingOperationItem::ModifyStretchListRatio:
1779 sl = poi._stretch_list;
1780 if(sl && !sl->isNormalized())
1781 {
1782 sl->normalizeListFrames();
1783 _sc_flags |= SC_AUDIO_STRETCH;
1784 }
1785 break;
1786
1787 default:
1788 break;
1789 }
1790 }
1791
1792 return _sc_flags;
1793 }
1794
executeNonRTStage()1795 SongChangedStruct_t PendingOperationList::executeNonRTStage()
1796 {
1797 DEBUG_OPERATIONS(stderr, "PendingOperationList::executeNonRTStage executing...\n");
1798 for(iPendingOperation ip = begin(); ip != end(); ++ip)
1799 _sc_flags |= ip->executeNonRTStage();
1800 return _sc_flags;
1801 }
1802
clear()1803 void PendingOperationList::clear()
1804 {
1805 _sc_flags = 0;
1806 _map.clear();
1807 std::list<PendingOperationItem>::clear();
1808 DEBUG_OPERATIONS(stderr, "PendingOperationList::clear * post map size:%d list size:%d\n", (int)_map.size(), (int)size());
1809 }
1810
add(PendingOperationItem op)1811 bool PendingOperationList::add(PendingOperationItem op)
1812 {
1813 unsigned int t = op.getIndex();
1814
1815 switch(op._type)
1816 {
1817 // For these special allocation ops, searching has already been done before hand. Just add them.
1818 case PendingOperationItem::AddMidiCtrlValList:
1819 {
1820 iPendingOperation iipo = insert(end(), op);
1821 _map.insert(std::pair<unsigned int, iPendingOperation>(t, iipo));
1822 return true;
1823 }
1824 break;
1825
1826 default:
1827 break;
1828 }
1829
1830 iPendingOperationSortedRange r = _map.equal_range(t);
1831 iPendingOperationSorted ipos = r.second;
1832 while(ipos != r.first)
1833 {
1834 --ipos;
1835 PendingOperationItem& poi = *ipos->second;
1836
1837 switch(op._type)
1838 {
1839 case PendingOperationItem::ModifyDefaultAudioConverterSettings:
1840 if(poi._type == PendingOperationItem::ModifyDefaultAudioConverterSettings &&
1841 poi._audio_converter_settings == op._audio_converter_settings)
1842 {
1843 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double ModifyDefaultAudioConverterSettings. Ignoring.\n");
1844 return false;
1845 }
1846 break;
1847
1848 case PendingOperationItem::ModifyLocalAudioConverterSettings:
1849 if(poi._type == PendingOperationItem::ModifyLocalAudioConverterSettings && *poi._sndFileR == *op._sndFileR &&
1850 poi._audio_converter_settings == op._audio_converter_settings)
1851 {
1852 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double ModifyLocalAudioConverterSettings. Ignoring.\n");
1853 return false;
1854 }
1855 break;
1856
1857 case PendingOperationItem::ModifyLocalAudioConverter:
1858 if(poi._type == PendingOperationItem::ModifyLocalAudioConverter && *poi._sndFileR == *op._sndFileR &&
1859 poi._audio_converter == op._audio_converter &&
1860 poi._audio_converter_ui == op._audio_converter_ui)
1861 {
1862 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double ModifyLocalAudioConverter. Ignoring.\n");
1863 return false;
1864 }
1865 break;
1866
1867 case PendingOperationItem::SetAudioConverterOfflineMode:
1868 if(poi._type == PendingOperationItem::SetAudioConverterOfflineMode && *poi._sndFileR == *op._sndFileR &&
1869 poi._audio_converter == op._audio_converter)
1870 {
1871 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double SetAudioConverterOfflineMode. Ignoring.\n");
1872 return false;
1873 }
1874 break;
1875
1876
1877 case PendingOperationItem::ModifyTrackDrumMapItem:
1878 if(poi._type == PendingOperationItem::ModifyTrackDrumMapItem &&
1879 poi._drum_map_track_operation == op._drum_map_track_operation)
1880 {
1881 fprintf(stderr, "MusE error: PendingOperationList::add(): Double ModifyTrackDrumMapItem. Ignoring.\n");
1882 return false;
1883 }
1884 break;
1885
1886 case PendingOperationItem::ReplaceTrackDrumMapPatchList:
1887 if(poi._type == PendingOperationItem::ReplaceTrackDrumMapPatchList &&
1888 poi._drum_map_track_patch_replace_operation == op._drum_map_track_patch_replace_operation)
1889 {
1890 fprintf(stderr, "MusE error: PendingOperationList::add(): Double ReplaceTrackDrumMapPatchList. Ignoring.\n");
1891 return false;
1892 }
1893 break;
1894
1895 case PendingOperationItem::RemapDrumControllers:
1896 if(poi._type == PendingOperationItem::RemapDrumControllers &&
1897 poi._midi_ctrl_val_remap_operation == op._midi_ctrl_val_remap_operation)
1898 {
1899 fprintf(stderr, "MusE error: PendingOperationList::add(): Double RemapDrumControllers. Ignoring.\n");
1900 return false;
1901 }
1902 break;
1903
1904 case PendingOperationItem::UpdateDrumMaps:
1905 if(poi._type == PendingOperationItem::UpdateDrumMaps && poi._midi_port == op._midi_port)
1906 {
1907 fprintf(stderr, "MusE error: PendingOperationList::add(): Double UpdateDrumMaps. Ignoring.\n");
1908 return false;
1909 }
1910 break;
1911
1912 case PendingOperationItem::UpdateSoloStates:
1913 if(poi._type == PendingOperationItem::UpdateSoloStates && poi._track_list == op._track_list)
1914 {
1915 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double UpdateSoloStates. Ignoring.\n");
1916 return false;
1917 }
1918 break;
1919
1920 case PendingOperationItem::AddRoute:
1921 if(poi._type == PendingOperationItem::AddRoute && poi._src_route == op._src_route && poi._dst_route == op._dst_route)
1922 {
1923 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double AddRoute. Ignoring.\n");
1924 return false;
1925 }
1926 break;
1927
1928 case PendingOperationItem::DeleteRoute:
1929 if(poi._type == PendingOperationItem::DeleteRoute && poi._src_route == op._src_route && poi._dst_route == op._dst_route)
1930 {
1931 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double DeleteRoute. Ignoring.\n");
1932 return false;
1933 }
1934 break;
1935
1936 case PendingOperationItem::AddRouteNode:
1937 if(poi._type == PendingOperationItem::AddRouteNode && poi._route_list == op._route_list && poi._src_route == op._src_route)
1938 {
1939 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double AddRouteNode. Ignoring.\n");
1940 return false;
1941 }
1942 break;
1943
1944 case PendingOperationItem::DeleteRouteNode:
1945 if(poi._type == PendingOperationItem::DeleteRouteNode && poi._route_list == op._route_list && poi._iRoute == op._iRoute)
1946 {
1947 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double DeleteRouteNode. Ignoring.\n");
1948 return false;
1949 }
1950 break;
1951
1952 case PendingOperationItem::ModifyRouteNode:
1953 if(poi._type == PendingOperationItem::ModifyRouteNode && poi._src_route == op._src_route && poi._dst_route_pointer == op._dst_route_pointer)
1954 {
1955 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double ModifyRouteNode. Ignoring.\n");
1956 return false;
1957 }
1958 break;
1959
1960
1961 case PendingOperationItem::AddAuxSendValue:
1962 if(poi._type == PendingOperationItem::AddAuxSendValue && poi._aux_send_value_list == op._aux_send_value_list)
1963 {
1964 // Do nothing. So far.
1965 }
1966 break;
1967
1968 case PendingOperationItem::AddMidiInstrument:
1969 if(poi._type == PendingOperationItem::AddMidiInstrument && poi._midi_instrument_list == op._midi_instrument_list &&
1970 poi._midi_instrument == op._midi_instrument)
1971 {
1972 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double AddMidiInstrument. Ignoring.\n");
1973 return false;
1974 }
1975 break;
1976
1977 case PendingOperationItem::DeleteMidiInstrument:
1978 if(poi._type == PendingOperationItem::DeleteMidiInstrument && poi._midi_instrument_list == op._midi_instrument_list &&
1979 poi._iMidiInstrument == op._iMidiInstrument)
1980 {
1981 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double DeleteMidiInstrument. Ignoring.\n");
1982 return false;
1983 }
1984 break;
1985
1986 case PendingOperationItem::ReplaceMidiInstrument:
1987 if(poi._type == PendingOperationItem::ReplaceMidiInstrument && poi._midi_instrument_list == op._midi_instrument_list &&
1988 (poi._midi_instrument == op._midi_instrument || poi._iMidiInstrument == op._iMidiInstrument))
1989 {
1990 fprintf(stderr, "MusE error: PendingOperationList::add(): Double ReplaceMidiInstrument. Ignoring.\n");
1991 return false;
1992 }
1993 break;
1994
1995 case PendingOperationItem::AddMidiDevice:
1996 if(poi._type == PendingOperationItem::AddMidiDevice && poi._midi_device_list == op._midi_device_list && poi._midi_device == op._midi_device)
1997 {
1998 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double AddMidiDevice. Ignoring.\n");
1999 return false;
2000 }
2001 break;
2002
2003 case PendingOperationItem::DeleteMidiDevice:
2004 if(poi._type == PendingOperationItem::DeleteMidiDevice && poi._midi_device_list == op._midi_device_list && poi._iMidiDevice == op._iMidiDevice)
2005 {
2006 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double DeleteMidiDevice. Ignoring.\n");
2007 return false;
2008 }
2009 break;
2010
2011 case PendingOperationItem::ModifyMidiDeviceAddress:
2012 if(poi._type == PendingOperationItem::ModifyMidiDeviceAddress && poi._midi_device == op._midi_device &&
2013 poi._address_client == op._address_client && poi._address_port == op._address_port)
2014 {
2015 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double ModifyMidiDeviceAddress. Ignoring.\n");
2016 return false;
2017 }
2018 break;
2019
2020 case PendingOperationItem::ModifyMidiDeviceFlags:
2021 if(poi._type == PendingOperationItem::ModifyMidiDeviceFlags && poi._midi_device == op._midi_device &&
2022 poi._rw_flags == op._rw_flags && poi._open_flags == op._open_flags)
2023 {
2024 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double ModifyMidiDeviceFlags. Ignoring.\n");
2025 return false;
2026 }
2027 break;
2028
2029 case PendingOperationItem::ModifyMidiDeviceName:
2030 if(poi._type == PendingOperationItem::ModifyMidiDeviceName && poi._midi_device == op._midi_device &&
2031 poi._name == op._name)
2032 {
2033 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double ModifyMidiDeviceName. Ignoring.\n");
2034 return false;
2035 }
2036 break;
2037
2038 case PendingOperationItem::SetInstrument:
2039 if(poi._type == PendingOperationItem::SetInstrument && poi._midi_port == op._midi_port &&
2040 poi._midi_instrument == op._midi_instrument)
2041 {
2042 fprintf(stderr, "MusE error: PendingOperationList::add(): Double SetInstrument. Ignoring.\n");
2043 return false;
2044 }
2045 break;
2046
2047
2048 case PendingOperationItem::AddTrack:
2049 if(poi._type == PendingOperationItem::AddTrack && poi._track_list == op._track_list && poi._track == op._track)
2050 {
2051 // Simply replace the insert point.
2052 poi._insert_at = op._insert_at;
2053 // An operation will still take place.
2054 return true;
2055 }
2056 else if(poi._type == PendingOperationItem::DeleteTrack && poi._track_list == op._track_list && poi._track == op._track)
2057 {
2058 // Delete followed by add is useless. Cancel out the delete + add by erasing the delete command.
2059 //erase(ipos->second);
2060 //_map.erase(ipos);
2061 // No operation will take place.
2062 //return false;
2063 }
2064 break;
2065
2066 case PendingOperationItem::DeleteTrack:
2067 if(poi._type == PendingOperationItem::DeleteTrack && poi._track_list == op._track_list && poi._track == op._track)
2068 {
2069 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double DeleteTrack. Ignoring.\n");
2070 return false;
2071 }
2072 else if(poi._type == PendingOperationItem::AddTrack && poi._track_list == op._track_list && poi._track == op._track)
2073 {
2074 // Add followed by delete is useless. Cancel out the add + delete by erasing the add command.
2075 //erase(ipos->second);
2076 //_map.erase(ipos);
2077 // No operation will take place.
2078 //return false;
2079 }
2080 break;
2081
2082 case PendingOperationItem::MoveTrack:
2083 if(poi._type == PendingOperationItem::MoveTrack && poi._track == op._track && poi._track_list == op._track_list)
2084 {
2085 // Simply replace the 'to' index.
2086 poi._to_idx = op._to_idx;
2087 // An operation will still take place.
2088 return true;
2089 }
2090 break;
2091
2092 case PendingOperationItem::ModifyTrackName:
2093 if(poi._type == PendingOperationItem::ModifyTrackName && poi._track == op._track &&
2094 poi._name == op._name)
2095 {
2096 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double ModifyTrackName. Ignoring.\n");
2097 return false;
2098 }
2099 break;
2100
2101 case PendingOperationItem::SetTrackRecord:
2102 if(poi._type == PendingOperationItem::SetTrackRecord && poi._track == op._track)
2103 {
2104 if(poi._boolA == op._boolA)
2105 {
2106 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double SetTrackRecord. Ignoring.\n");
2107 return false;
2108 }
2109 else
2110 {
2111 // On/off followed by off/on is useless. Cancel out the on/off + off/on by erasing the command.
2112 erase(ipos->second);
2113 _map.erase(ipos);
2114 // No operation will take place.
2115 return false;
2116 }
2117 }
2118 break;
2119
2120 case PendingOperationItem::SetTrackMute:
2121 if(poi._type == PendingOperationItem::SetTrackMute && poi._track == op._track)
2122 {
2123 if(poi._boolA == op._boolA)
2124 {
2125 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double SetTrackMute. Ignoring.\n");
2126 return false;
2127 }
2128 else
2129 {
2130 // On/off followed by off/on is useless. Cancel out the on/off + off/on by erasing the command.
2131 erase(ipos->second);
2132 _map.erase(ipos);
2133 // No operation will take place.
2134 return false;
2135 }
2136 }
2137 break;
2138
2139 case PendingOperationItem::SetTrackSolo:
2140 if(poi._type == PendingOperationItem::SetTrackSolo && poi._track == op._track)
2141 {
2142 if(poi._boolA == op._boolA)
2143 {
2144 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double SetTrackSolo. Ignoring.\n");
2145 return false;
2146 }
2147 else
2148 {
2149 // On/off followed by off/on is useless. Cancel out the on/off + off/on by erasing the command.
2150 erase(ipos->second);
2151 _map.erase(ipos);
2152 // No operation will take place.
2153 return false;
2154 }
2155 }
2156 break;
2157
2158 case PendingOperationItem::SetTrackRecMonitor:
2159 if(poi._type == PendingOperationItem::SetTrackRecMonitor && poi._track == op._track)
2160 {
2161 if(poi._boolA == op._boolA)
2162 {
2163 fprintf(stderr, "MusE error: PendingOperationList::add(): Double SetTrackRecMonitor. Ignoring.\n");
2164 return false;
2165 }
2166 else
2167 {
2168 // On/off followed by off/on is useless. Cancel out the on/off + off/on by erasing the command.
2169 erase(ipos->second);
2170 _map.erase(ipos);
2171 // No operation will take place.
2172 return false;
2173 }
2174 }
2175 break;
2176
2177 case PendingOperationItem::SetTrackOff:
2178 if(poi._type == PendingOperationItem::SetTrackOff && poi._track == op._track)
2179 {
2180 if(poi._boolA == op._boolA)
2181 {
2182 fprintf(stderr, "MusE error: PendingOperationList::add(): Double SetTrackOff. Ignoring.\n");
2183 return false;
2184 }
2185 else
2186 {
2187 // On/off followed by off/on is useless. Cancel out the on/off + off/on by erasing the command.
2188 erase(ipos->second);
2189 _map.erase(ipos);
2190 // No operation will take place.
2191 return false;
2192 }
2193 }
2194 break;
2195
2196 case PendingOperationItem::AddPart:
2197 if(poi._type == PendingOperationItem::AddPart && poi._part_list == op._part_list && poi._part == op._part)
2198 {
2199 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double AddPart. Ignoring.\n");
2200 return false;
2201 }
2202 else if(poi._type == PendingOperationItem::DeletePart && poi._part_list == op._part_list && poi._iPart->second == op._part)
2203 {
2204 // Delete followed by add is useless. Cancel out the delete + add by erasing the delete command.
2205 erase(ipos->second);
2206 _map.erase(ipos);
2207 // No operation will take place.
2208 return false;
2209 }
2210 break;
2211
2212 case PendingOperationItem::DeletePart:
2213 if(poi._type == PendingOperationItem::DeletePart && poi._part_list == op._part_list && poi._iPart->second == op._iPart->second)
2214 {
2215 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double DeletePart. Ignoring.\n");
2216 return false;
2217 }
2218 else if(poi._type == PendingOperationItem::AddPart && poi._part_list == op._part_list && poi._part == op._iPart->second)
2219 {
2220 // Add followed by delete is useless. Cancel out the add + delete by erasing the add command.
2221 erase(ipos->second);
2222 _map.erase(ipos);
2223 // No operation will take place.
2224 return false;
2225 }
2226 break;
2227
2228 case PendingOperationItem::SelectPart:
2229 if(poi._type == PendingOperationItem::SelectPart && poi._part == op._part)
2230 {
2231 // Simply replace the value.
2232 poi._boolA = op._boolA;
2233 // An operation will still take place.
2234 return true;
2235 }
2236 break;
2237
2238 case PendingOperationItem::MovePart:
2239 if(poi._type == PendingOperationItem::MovePart && poi._part == op._part)
2240 {
2241 // Simply replace the values.
2242 poi._iPart = op._iPart;
2243 poi._track = op._track;
2244 poi._posLenVal = op._posLenVal;
2245 // An operation will still take place.
2246 return true;
2247 }
2248 break;
2249
2250 case PendingOperationItem::ModifyPartStart:
2251 if(poi._type == PendingOperationItem::ModifyPartStart)
2252 {
2253 // If the given list is not null and is already part of a previous ModifyPartStart command,
2254 // it's an error, the list would be deleted twice.
2255 if(poi._part != op._part && op._event_list && op._event_list == poi._event_list)
2256 {
2257 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): ModifyPartStart: Same _event_list for two different parts. Ignoring.\n");
2258 return false;
2259 }
2260
2261 if(poi._part == op._part)
2262 {
2263 // From here on in this block no matter what, we are re-using the existing command.
2264
2265 // Simply replace the values.
2266 poi._posLenVal = op._posLenVal;
2267 poi._lenVal = op._lenVal;
2268
2269 // If a list was given use it otherwise if no list was given don't touch the existing list.
2270 if(op._event_list)
2271 {
2272 // If the given list is the same as the existing list, it's really an error. We'll let it go but don't touch the existing list.
2273 // It should be safe to proceed without worrying about deleting the existing or given list here since it would be impossible
2274 // to allocate the same pointer twice, beforehand.
2275 if(op._event_list == poi._event_list)
2276 {
2277 //ERROR_OPERATIONS(stderr, "MusE warning: PendingOperationList::add(): ModifyPartStart: Double _event_list. Ignoring second list.\n");
2278 //return false;
2279 }
2280 else
2281 {
2282 // Done with the existing original replacement list. If it exists, delete it.
2283 if(poi._event_list)
2284 delete poi._event_list;
2285 // Replace the existing list pointer with the given one.
2286 poi._event_list = op._event_list;
2287 }
2288 }
2289 // An operation will still take place.
2290 return true;
2291 }
2292 }
2293 break;
2294
2295 case PendingOperationItem::ModifyPartLength:
2296 if(poi._type == PendingOperationItem::ModifyPartLength)
2297 {
2298 // If the given list is not null and is already part of a previous ModifyPartLength command,
2299 // it's an error, the list would be deleted twice.
2300 if(poi._part != op._part && op._event_list && op._event_list == poi._event_list)
2301 {
2302 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): ModifyPartLength: Same _event_list for two different parts. Ignoring.\n");
2303 return false;
2304 }
2305
2306 if(poi._part == op._part)
2307 {
2308 // From here on in this block no matter what, we are re-using the existing command.
2309
2310 // Simply replace the value.
2311 poi._posLenVal = op._posLenVal;
2312
2313 // If a list was given use it otherwise if no list was given don't touch the existing list.
2314 if(op._event_list)
2315 {
2316 // If the given list is the same as the existing list, it's really an error. We'll let it go but don't touch the existing list.
2317 // It should be safe to proceed without worrying about deleting the existing or given list here since it would be impossible
2318 // to allocate the same pointer twice, beforehand.
2319 if(op._event_list == poi._event_list)
2320 {
2321 //ERROR_OPERATIONS(stderr, "MusE warning: PendingOperationList::add(): ModifyPartLength: Double _event_list. Ignoring second list.\n");
2322 //return false;
2323 }
2324 else
2325 {
2326 // Done with the existing original replacement list. If it exists, delete it.
2327 if(poi._event_list)
2328 delete poi._event_list;
2329 // Replace the existing list pointer with the given one.
2330 poi._event_list = op._event_list;
2331 }
2332 }
2333 // An operation will still take place.
2334 return true;
2335 }
2336 }
2337 break;
2338
2339 case PendingOperationItem::ModifyPartName:
2340 if(poi._type == PendingOperationItem::ModifyPartName && poi._part == op._part &&
2341 poi._name == op._name)
2342 {
2343 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double ModifyPartName. Ignoring.\n");
2344 return false;
2345 }
2346 break;
2347
2348
2349 case PendingOperationItem::AddEvent:
2350 if(poi._type == PendingOperationItem::AddEvent && poi._part == op._part && poi._ev == op._ev)
2351 {
2352 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double AddEvent. Ignoring.\n");
2353 return false;
2354 }
2355 else if(poi._type == PendingOperationItem::DeleteEvent && poi._part == op._part && poi._iev->second == op._ev)
2356 {
2357 // Delete followed by add is useless. Cancel out the delete + add by erasing the delete command.
2358 erase(ipos->second);
2359 _map.erase(ipos);
2360 // No operation will take place.
2361 return false;
2362 }
2363 break;
2364
2365 case PendingOperationItem::DeleteEvent:
2366 if(poi._type == PendingOperationItem::DeleteEvent && poi._part == op._part && poi._iev->second == op._iev->second)
2367 {
2368 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double DeleteEvent. Ignoring.\n");
2369 return false;
2370 }
2371 else if(poi._type == PendingOperationItem::AddEvent && poi._part == op._part && poi._ev == op._iev->second)
2372 {
2373 // Add followed by delete is useless. Cancel out the add + delete by erasing the add command.
2374 erase(ipos->second);
2375 _map.erase(ipos);
2376 // No operation will take place.
2377 return false;
2378 }
2379 break;
2380
2381 case PendingOperationItem::SelectEvent:
2382 if(poi._type == PendingOperationItem::SelectEvent &&
2383 poi._part == op._part && poi._ev == op._ev)
2384 {
2385 // Simply replace the value.
2386 poi._intA = op._intA;
2387 // An operation will still take place.
2388 return true;
2389 }
2390 break;
2391
2392 case PendingOperationItem::ModifyEventList:
2393 // TODO Not quite right yet.
2394 // if(poi._type == PendingOperationItem::ModifyEventList &&
2395 // // If attempting to repeatedly modify the same list, or, if progressively modifying (list to list to list etc).
2396 // (poi._orig_event_list == op._orig_event_list || poi._event_list == op._event_list))
2397 // {
2398 // // Simply replace the list.
2399 // poi._event_list = op._event_list;
2400 break;
2401
2402
2403 case PendingOperationItem::ModifyMidiCtrlValList:
2404 // TODO Not quite right yet.
2405 // if(poi._type == PendingOperationItem::ModifyMidiCtrlValList &&
2406 // // If attempting to repeatedly modify the same list, or, if progressively modifying (list to list to list etc).
2407 // (poi._orig_mcvl == op._orig_mcvl || poi._mcvl == op._mcvl))
2408 // {
2409 // // Simply replace the list.
2410 // poi._mcvl = op._mcvl;
2411 break;
2412
2413 case PendingOperationItem::AddMidiCtrlVal:
2414 if(poi._type == PendingOperationItem::DeleteMidiCtrlVal &&
2415 poi._mcvl == op._mcvl &&
2416 poi._imcv->second.part == op._part &&
2417 poi._imcv->second.val == op._intB)
2418 {
2419 // Delete followed by add is useless. Cancel out the delete + add by erasing the delete command.
2420 erase(ipos->second);
2421 _map.erase(ipos);
2422 // No operation will take place.
2423 return false;
2424 }
2425 break;
2426
2427 case PendingOperationItem::DeleteMidiCtrlVal:
2428 // Be sure _intB is set.
2429 if(poi._type == PendingOperationItem::AddMidiCtrlVal &&
2430 poi._mcvl == op._mcvl &&
2431 poi._part == op._imcv->second.part &&
2432 poi._intB == op._imcv->second.val)
2433 {
2434 // Add followed by delete is useless. Cancel out the add + delete by erasing the add command.
2435 erase(ipos->second);
2436 _map.erase(ipos);
2437 // No operation will take place.
2438 return false;
2439 }
2440 break;
2441
2442 case PendingOperationItem::ModifyMidiCtrlVal:
2443 // TODO FIXME Finish this
2444
2445 // Be sure _intB/A is set
2446 // if(poi._type == PendingOperationItem::ModifyMidiCtrlVal &&
2447 // poi._mcvl == op._mcvl &&
2448 // poi._imcv->second.part == op._imcv->second.part &&
2449 // poi._imcv->second.val == op._imcv->second.val)
2450 // {
2451 // // Simply replace the value.
2452 // poi._intA = op._intA;
2453 // return true;
2454 // }
2455 // else if(poi._type == PendingOperationItem::DeleteMidiCtrlVal && poi._mcvl == op._mcvl && poi._imcv->second.part == op._imcv->second.part)
2456 // {
2457 // // Transform existing delete command into a modify command.
2458 // poi._type = PendingOperationItem::ModifyMidiCtrlVal;
2459 // poi._intA = op._intA;
2460 // return true;
2461 // }
2462 // else if(poi._type == PendingOperationItem::AddMidiCtrlVal && poi._mcvl == op._mcvl && poi._part == op._imcv->second.part)
2463 // {
2464 // // Simply replace the add value with the modify value.
2465 // poi._intB = op._intA;
2466 // return true;
2467 // }
2468 break;
2469
2470
2471 case PendingOperationItem::ModifyAudioCtrlValList:
2472 if(poi._type == PendingOperationItem::ModifyAudioCtrlValList &&
2473 // If attempting to repeatedly modify the same list, or, if progressively modifying (list to list to list etc).
2474 (poi._iCtrlList->second == op._iCtrlList->second || poi._aud_ctrl_list == op._iCtrlList->second))
2475 {
2476 // Simply replace the list.
2477 poi._aud_ctrl_list = op._aud_ctrl_list;
2478 // An operation will still take place.
2479 return true;
2480 }
2481 break;
2482
2483 case PendingOperationItem::AddAudioCtrlVal:
2484 if(poi._type == PendingOperationItem::AddAudioCtrlVal && poi._aud_ctrl_list == op._aud_ctrl_list)
2485 {
2486 // Simply replace the value.
2487 poi._ctl_dbl_val = op._ctl_dbl_val;
2488 // An operation will still take place.
2489 return true;
2490 }
2491 else if(poi._type == PendingOperationItem::DeleteAudioCtrlVal && poi._aud_ctrl_list == op._aud_ctrl_list)
2492 {
2493 // Transform existing delete command into a modify command.
2494 poi._type = PendingOperationItem::ModifyAudioCtrlVal;
2495 poi._ctl_dbl_val = op._ctl_dbl_val;
2496 // An operation will still take place.
2497 return true;
2498 }
2499 else if(poi._type == PendingOperationItem::ModifyAudioCtrlVal && poi._aud_ctrl_list == op._aud_ctrl_list)
2500 {
2501 // Simply replace the value.
2502 poi._ctl_dbl_val = op._ctl_dbl_val;
2503 // An operation will still take place.
2504 return true;
2505 }
2506 break;
2507
2508 case PendingOperationItem::DeleteAudioCtrlVal:
2509 if(poi._type == PendingOperationItem::DeleteAudioCtrlVal && poi._aud_ctrl_list == op._aud_ctrl_list)
2510 {
2511 // Multiple delete commands not allowed!
2512 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double DeleteAudioCtrlVal. Ignoring.\n");
2513 return false;
2514 }
2515 else if(poi._type == PendingOperationItem::AddAudioCtrlVal && poi._aud_ctrl_list == op._aud_ctrl_list)
2516 {
2517 // Add followed by delete is useless. Cancel out the add + delete by erasing the add command.
2518 erase(ipos->second);
2519 _map.erase(ipos);
2520 // No operation will take place.
2521 return false;
2522 }
2523 else if(poi._type == PendingOperationItem::ModifyAudioCtrlVal && poi._aud_ctrl_list == op._aud_ctrl_list)
2524 {
2525 // Modify followed by delete is equivalent to just deleting.
2526 // Transform existing modify command into a delete command.
2527 poi._type = PendingOperationItem::DeleteAudioCtrlVal;
2528 // An operation will still take place.
2529 return true;
2530 }
2531 break;
2532
2533 case PendingOperationItem::ModifyAudioCtrlVal:
2534 if(poi._type == PendingOperationItem::ModifyAudioCtrlVal && poi._aud_ctrl_list == op._aud_ctrl_list)
2535 {
2536 // Simply replace the value.
2537 poi._ctl_dbl_val = op._ctl_dbl_val;
2538 // An operation will still take place.
2539 return true;
2540 }
2541 else if(poi._type == PendingOperationItem::DeleteAudioCtrlVal && poi._aud_ctrl_list == op._aud_ctrl_list)
2542 {
2543 // Transform existing delete command into a modify command.
2544 poi._type = PendingOperationItem::ModifyAudioCtrlVal;
2545 poi._ctl_dbl_val = op._ctl_dbl_val;
2546 // An operation will still take place.
2547 return true;
2548 }
2549 else if(poi._type == PendingOperationItem::AddAudioCtrlVal && poi._aud_ctrl_list == op._aud_ctrl_list)
2550 {
2551 // Simply replace the add value with the modify value.
2552 poi._ctl_dbl_val = op._ctl_dbl_val;
2553 // An operation will still take place.
2554 return true;
2555 }
2556 break;
2557
2558
2559 case PendingOperationItem::ModifyTempoList:
2560 // TODO Not quite right yet.
2561 // if(poi._type == PendingOperationItem::ModifyTempoList &&
2562 // // If attempting to repeatedly modify the same list, or, if progressively modifying (list to list to list etc).
2563 // (poi._orig_tempo_list == op._orig_tempo_list || poi._tempo_list == op._tempo_list))
2564 // {
2565 // // Simply replace the list.
2566 // poi._tempo_list = op._tempo_list;
2567 break;
2568
2569
2570 case PendingOperationItem::SetStaticTempo:
2571 #ifdef _PENDING_OPS_DEBUG_
2572 fprintf(stderr, "PendingOperationList::add() SetStaticTempo\n");
2573 #endif
2574 if(poi._type == PendingOperationItem::SetStaticTempo && poi._tempo_list == op._tempo_list)
2575 {
2576 // Simply replace the value.
2577 poi._intA = op._intA;
2578 // An operation will still take place.
2579 return true;
2580 }
2581 break;
2582
2583 case PendingOperationItem::SetGlobalTempo:
2584 DEBUG_OPERATIONS(stderr, "PendingOperationList::add() SetGlobalTempo\n");
2585 if(poi._type == PendingOperationItem::SetGlobalTempo && poi._tempo_list == op._tempo_list)
2586 {
2587 // Simply replace the new value.
2588 poi._intA = op._intA;
2589 // An operation will still take place.
2590 return true;
2591 }
2592 break;
2593
2594
2595 case PendingOperationItem::ModifySigList:
2596 // TODO Not quite right yet.
2597 // if(poi._type == PendingOperationItem::ModifySigList &&
2598 // // If attempting to repeatedly modify the same list, or, if progressively modifying (list to list to list etc).
2599 // (poi._orig_sig_list == op._orig_sig_list || poi._sig_list == op._sig_list))
2600 // {
2601 // // Simply replace the list.
2602 // poi._sig_list = op._sig_list;
2603 break;
2604
2605
2606 case PendingOperationItem::ModifyKeyList:
2607 // TODO Not quite right yet.
2608 // if(poi._type == PendingOperationItem::ModifyKeyList &&
2609 // // If attempting to repeatedly modify the same list, or, if progressively modifying (list to list to list etc).
2610 // (poi._orig_key_list == op._orig_key_list || poi._key_list == op._key_list))
2611 // {
2612 // // Simply replace the list.
2613 // poi._key_list = op._key_list;
2614 break;
2615
2616
2617 case PendingOperationItem::AddStretchListRatioAt:
2618 if(poi._type == PendingOperationItem::AddStretchListRatioAt && poi._stretch_list == op._stretch_list &&
2619 poi._stretch_type == op._stretch_type)
2620 {
2621 // Simply replace the value.
2622 poi._audio_converter_value = op._audio_converter_value;
2623 return true;
2624 }
2625 // Todo?
2626 // else if(poi._type == PendingOperationItem::DeleteStretchListRatioAt && poi._stretch_list == op._stretch_list &&
2627 // poi._stretch_type == op._stretch_type)
2628 // {
2629 // // Transform existing delete command into a modify command.
2630 // poi._type = PendingOperationItem::ModifyStretchListRatioAt;
2631 // poi._audio_converter_value = op._audio_converter_value;
2632 // return true;
2633 // }
2634 else if(poi._type == PendingOperationItem::ModifyStretchListRatioAt && poi._stretch_list == op._stretch_list &&
2635 poi._stretch_type == op._stretch_type)
2636 {
2637 // Simply replace the value.
2638 poi._audio_converter_value = op._audio_converter_value;
2639 return true;
2640 }
2641 break;
2642
2643 case PendingOperationItem::DeleteStretchListRatioAt:
2644 if(poi._type == PendingOperationItem::DeleteStretchListRatioAt && poi._stretch_list == op._stretch_list &&
2645 poi._stretch_type == op._stretch_type)
2646 {
2647 // Multiple delete commands not allowed!
2648 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double DeleteStretchRatioAt. Ignoring.\n");
2649 return false;
2650 }
2651 // Todo?
2652 // else if(poi._type == PendingOperationItem::AddStretchListRatioAt && poi._stretch_list == op._stretch_list)
2653 // {
2654 // // Add followed by delete is useless. Cancel out the add + delete by erasing the add command.
2655 // erase(ipos->second);
2656 // _map.erase(ipos);
2657 // return true;
2658 // }
2659 // else if(poi._type == PendingOperationItem::ModifyStretchListRatioAt && poi._stretch_list == op._stretch_list)
2660 // {
2661 // // Modify followed by delete is equivalent to just deleting.
2662 // // Transform existing modify command into a delete command.
2663 // poi._type = PendingOperationItem::DeleteStretchListRatioAt;
2664 // return true;
2665 // }
2666 break;
2667
2668 case PendingOperationItem::ModifyStretchListRatioAt:
2669 if(poi._type == PendingOperationItem::ModifyStretchListRatioAt && poi._stretch_list == op._stretch_list &&
2670 poi._stretch_type == op._stretch_type)
2671 {
2672 // Simply replace the value.
2673 poi._audio_converter_value = op._audio_converter_value;
2674 return true;
2675 }
2676 // Todo?
2677 // else if(poi._type == PendingOperationItem::DeleteStretchListRatioAt && poi._stretch_list == op._stretch_list &&
2678 // poi._stretch_type == op._stretch_type)
2679 // {
2680 // // Transform existing delete command into a modify command.
2681 // poi._type = PendingOperationItem::ModifyStretchListRatioAt;
2682 // poi._audio_converter_value = op._audio_converter_value;
2683 // return true;
2684 // }
2685 else if(poi._type == PendingOperationItem::AddStretchListRatioAt && poi._stretch_list == op._stretch_list &&
2686 poi._stretch_type == op._stretch_type)
2687 {
2688 // Simply replace the add value with the modify value.
2689 poi._audio_converter_value = op._audio_converter_value;
2690 return true;
2691 }
2692 break;
2693
2694
2695 case PendingOperationItem::ModifyStretchListRatio:
2696 if(poi._type == PendingOperationItem::ModifyStretchListRatio && poi._stretch_list == op._stretch_list &&
2697 poi._stretch_type == op._stretch_type)
2698 {
2699 // Simply replace the value.
2700 poi._audio_converter_value = op._audio_converter_value;
2701 return true;
2702 }
2703 break;
2704
2705
2706 case PendingOperationItem::ModifySongLength:
2707 DEBUG_OPERATIONS(stderr, "PendingOperationList::add() ModifySongLength\n");
2708 if(poi._type == PendingOperationItem::ModifySongLength)
2709 {
2710 // Simply replace the value.
2711 poi._intA = op._intA;
2712 // An operation will still take place.
2713 return true;
2714 }
2715 break;
2716
2717 case PendingOperationItem::EnableAllAudioControllers:
2718 DEBUG_OPERATIONS(stderr, "PendingOperationList::add() EnableAllAudioControllers\n");
2719 if(poi._type == PendingOperationItem::EnableAllAudioControllers)
2720 {
2721 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Double EnableAllAudioControllers. Ignoring.\n");
2722 return false;
2723 }
2724 break;
2725
2726 case PendingOperationItem::GlobalSelectAllEvents:
2727 #ifdef _PENDING_OPS_DEBUG_
2728 fprintf(stderr, "PendingOperationList::add() GlobalSelectAllEvents\n");
2729 #endif
2730 if(poi._type == PendingOperationItem::GlobalSelectAllEvents && poi._track_list == op._track_list)
2731 {
2732 if(poi._boolA == op._boolA)
2733 {
2734 fprintf(stderr, "MusE error: PendingOperationList::add(): Double GlobalSelectAllEvents. Ignoring.\n");
2735 return false;
2736 }
2737 else
2738 {
2739 // Special: Do not 'cancel' out this one. The selecions may need to affect all events.
2740 // Simply replace the value.
2741 poi._boolA = op._boolA;
2742 // An operation will still take place.
2743 return true;
2744 }
2745 }
2746 break;
2747
2748 case PendingOperationItem::ModifyAudioSamples:
2749 // TODO Not quite right yet.
2750 // if(poi._type == PendingOperationItem::ModifyAudioSamples &&
2751 // // If attempting to repeatedly modify the same list, or, if progressively modifying (list to list to list etc).
2752 // poi._audioSamplesPointer && op._audioSamplesPointer &&
2753 // (*poi._audioSamplesPointer == *op._audioSamplesPointer || poi._newAudioSamples == op._newAudioSamples))
2754 // {
2755 // // Simply replace the list.
2756 // poi._newAudioSamples = op._newAudioSamples;
2757 // poi._newAudioSamplesLen = op._newAudioSamplesLen;
2758 // return true;
2759 // }
2760 break;
2761
2762 case PendingOperationItem::ModifyMarkerList:
2763 // TODO Not quite right yet.
2764 // if(poi._type == PendingOperationItem::ModifyMarkerList &&
2765 // // If attempting to repeatedly modify the same list, or, if progressively modifying (list to list to list etc).
2766 // poi._orig_marker_list && op._orig_marker_list &&
2767 // (*poi._orig_marker_list == *op._orig_marker_list || poi._marker_list == op._marker_list))
2768 // {
2769 // // Simply replace the list.
2770 // poi._newAudioSamples = op._newAudioSamples;
2771 // poi._newAudioSamplesLen = op._newAudioSamplesLen;
2772 break;
2773
2774 case PendingOperationItem::SwitchMetronomeSettings:
2775 if(poi._type == PendingOperationItem::SwitchMetronomeSettings &&
2776 (poi._bool_pointer == op._bool_pointer))
2777 {
2778 if(poi._boolA == op._boolA)
2779 {
2780 fprintf(stderr, "MusE error: PendingOperationList::add(): Double SwitchMetronomeSettings. Ignoring.\n");
2781 // No operation will take place.
2782 return false;
2783 }
2784 else
2785 {
2786 // Enable or disable followed by disable or enable is useless. Cancel out both by erasing the command.
2787 erase(ipos->second);
2788 _map.erase(ipos);
2789 // No operation will take place.
2790 return false;
2791 }
2792 }
2793 break;
2794
2795 case PendingOperationItem::ModifyMetronomeAccentMap:
2796 // TODO Not quite right yet.
2797 // if(poi._type == PendingOperationItem::ModifyMetronomeAccentMap &&
2798 // // If attempting to repeatedly modify the same list, or, if progressively modifying (list to list to list etc).
2799 // (poi._metroAccentsMap == op._metroAccentsMap || poi._newMetroAccentsMap == op._newMetroAccentsMap))
2800 // {
2801 // // Simply replace the list.
2802 // poi._newMetroAccentsMap = op._newMetroAccentsMap;
2803 // // An operation will still take place.
2804 // return true;
2805 // }
2806 break;
2807
2808 case PendingOperationItem::SetExternalSyncFlag:
2809 if(poi._type == PendingOperationItem::SetExternalSyncFlag &&
2810 (poi._bool_pointer == op._bool_pointer))
2811 {
2812 if(poi._boolA == op._boolA)
2813 {
2814 fprintf(stderr, "MusE error: PendingOperationList::add(): Double SetExternalSyncFlag. Ignoring.\n");
2815 // No operation will take place.
2816 return false;
2817 }
2818 else
2819 {
2820 // Enable or disable followed by disable or enable is useless. Cancel out both by erasing the command.
2821 erase(ipos->second);
2822 _map.erase(ipos);
2823 // No operation will take place.
2824 return false;
2825 }
2826 }
2827 break;
2828
2829 case PendingOperationItem::SetUseJackTransport:
2830 if(poi._type == PendingOperationItem::SetUseJackTransport &&
2831 (poi._bool_pointer == op._bool_pointer))
2832 {
2833 if(poi._boolA == op._boolA)
2834 {
2835 fprintf(stderr, "MusE error: PendingOperationList::add(): Double SetUseJackTransport. Ignoring.\n");
2836 // No operation will take place.
2837 return false;
2838 }
2839 else
2840 {
2841 // Enable or disable followed by disable or enable is useless. Cancel out both by erasing the command.
2842 erase(ipos->second);
2843 _map.erase(ipos);
2844 // No operation will take place.
2845 return false;
2846 }
2847 }
2848 break;
2849
2850 case PendingOperationItem::SetUseMasterTrack:
2851 if(poi._type == PendingOperationItem::SetUseMasterTrack &&
2852 (poi._tempo_list == op._tempo_list))
2853 {
2854 if(poi._boolA == op._boolA)
2855 {
2856 fprintf(stderr, "MusE error: PendingOperationList::add(): Double SetUseMasterTrack. Ignoring.\n");
2857 // No operation will take place.
2858 return false;
2859 }
2860 else
2861 {
2862 // Enable or disable followed by disable or enable is useless. Cancel out both by erasing the command.
2863 erase(ipos->second);
2864 _map.erase(ipos);
2865 // No operation will take place.
2866 return false;
2867 }
2868 }
2869 break;
2870
2871 case PendingOperationItem::Uninitialized:
2872 ERROR_OPERATIONS(stderr, "MusE error: PendingOperationList::add(): Uninitialized item. Ignoring.\n");
2873 return false;
2874 break;
2875
2876 default:
2877 break;
2878 }
2879 }
2880
2881 iPendingOperation iipo = insert(end(), op);
2882 _map.insert(std::pair<unsigned int, iPendingOperation>(t, iipo));
2883 return true;
2884 }
2885
findAllocationOp(const PendingOperationItem & op)2886 iPendingOperation PendingOperationList::findAllocationOp(const PendingOperationItem& op)
2887 {
2888 iPendingOperationSortedRange r = _map.equal_range(op.getIndex());
2889 iPendingOperationSorted ipos = r.second;
2890 while(ipos != r.first)
2891 {
2892 --ipos;
2893 const PendingOperationItem& poi = *ipos->second;
2894 if(poi.isAllocationOp(op)) // Comparison.
2895 return ipos->second;
2896 }
2897 return end();
2898 }
2899
2900
2901 //========================================================================
2902
2903
2904 //---------------------------------------------------------
2905 // addDeviceOperation
2906 //---------------------------------------------------------
2907
addDeviceOperation(MidiDeviceList * devlist,MidiDevice * dev)2908 void PendingOperationList::addDeviceOperation(MidiDeviceList* devlist, MidiDevice* dev)
2909 {
2910 bool gotUniqueName=false;
2911 int increment = 0;
2912 const QString origname = dev->name();
2913 QString newName = origname;
2914 PendingOperationItem poi(devlist, dev, PendingOperationItem::AddMidiDevice);
2915 // check if the name's been taken
2916 while(!gotUniqueName)
2917 {
2918 if(increment >= 10000)
2919 {
2920 fprintf(stderr, "MusE Error: PendingOperationList::addDeviceOperation(): Out of 10000 unique midi device names!\n");
2921 return;
2922 }
2923 gotUniqueName = true;
2924 // In the case of type AddMidiDevice, this searches for the name only.
2925 iPendingOperation ipo = findAllocationOp(poi);
2926 if(ipo != end())
2927 {
2928 PendingOperationItem& poif = *ipo;
2929 if(poif._midi_device == poi._midi_device)
2930 return; // Device itself is already added!
2931 newName = origname + QString("_%1").arg(++increment);
2932 gotUniqueName = false;
2933 }
2934
2935 for(ciMidiDevice i = devlist->cbegin(); i != devlist->cend(); ++i)
2936 {
2937 const QString s = (*i)->name();
2938 if(s == newName)
2939 {
2940 newName = origname + QString("_%1").arg(++increment);
2941 gotUniqueName = false;
2942 }
2943 }
2944 }
2945
2946 if(origname != newName)
2947 dev->setName(newName);
2948
2949 add(poi);
2950 }
2951
2952 //---------------------------------------------------------
2953 // addPartPortCtrlEvents
2954 //---------------------------------------------------------
2955
addPartPortCtrlEvents(const Event & event,Part * part,unsigned int tick,unsigned int,Track * track)2956 void PendingOperationList::addPartPortCtrlEvents(
2957 const Event& event, Part* part, unsigned int tick, unsigned int /*len*/, Track* track)
2958 {
2959 if(!track || !track->isMidiTrack())
2960 return;
2961
2962 if(event.type() == Controller)
2963 {
2964 unsigned int tck = event.tick() + tick;
2965 int cntrl = event.dataA();
2966 int val = event.dataB();
2967 MidiTrack* mt = (MidiTrack*)track;
2968 MidiPort* mp;
2969 int ch;
2970 mt->mappedPortChanCtrl(&cntrl, nullptr, &mp, &ch);
2971
2972 MidiCtrlValListList* mcvll = mp->controller();
2973 MidiCtrlValList* mcvl = NULL;
2974 iMidiCtrlValList imcvll = mcvll->find(ch, cntrl);
2975 if(imcvll == mcvll->end())
2976 {
2977 PendingOperationItem poi(mcvll, 0, ch, cntrl, PendingOperationItem::AddMidiCtrlValList);
2978 if(findAllocationOp(poi) == end())
2979 {
2980 mcvl = new MidiCtrlValList(cntrl);
2981 poi._mcvl = mcvl;
2982 add(poi);
2983 }
2984 }
2985 else
2986 {
2987 mcvl = imcvll->second;
2988 }
2989
2990 //assert(mcvl != NULL); //FIXME: Can this happen? (danvd). UPDATE: Yes, it can (danvd)
2991 if(mcvl != NULL)
2992 {
2993 // The operation will catch and ignore events which are past the end of the part.
2994 add(PendingOperationItem(mcvl, part, tck, val, PendingOperationItem::AddMidiCtrlVal));
2995 }
2996 }
2997 }
2998
addPartPortCtrlEvents(Part * part,unsigned int tick,unsigned int len,Track * track)2999 void PendingOperationList::addPartPortCtrlEvents(Part* part, unsigned int tick, unsigned int len, Track* track)
3000 {
3001 if(!track || !track->isMidiTrack())
3002 return;
3003 for(ciEvent ie = part->events().begin(); ie != part->events().end(); ++ie)
3004 {
3005 // The operation will catch and ignore events which are past the end of the part.
3006 addPartPortCtrlEvents(ie->second, part, tick, len, track);
3007 }
3008 }
3009
3010 //---------------------------------------------------------
3011 // removePartPortCtrlEvents
3012 //---------------------------------------------------------
3013
removePartPortCtrlEvents(const Event & event,Part * part,Track * track)3014 bool PendingOperationList::removePartPortCtrlEvents(const Event& event, Part* part, Track* track)
3015 {
3016 if(!track || !track->isMidiTrack())
3017 return false;
3018
3019 if(event.type() == Controller)
3020 {
3021 MidiTrack* mt = (MidiTrack*)track;
3022 // MidiPort* mp = &MusEGlobal::midiPorts[mt->outPort()];
3023 // int ch = mt->outChannel();
3024
3025 unsigned int tck = event.tick() + part->tick();
3026 int cntrl = event.dataA();
3027 int val = event.dataB();
3028
3029 // Is it a drum controller event, according to the track port's instrument?
3030 MidiPort* mp;
3031 int ch;
3032 mt->mappedPortChanCtrl(&cntrl, nullptr, &mp, &ch);
3033
3034
3035 MidiCtrlValListList* mcvll = mp->controller();
3036 iMidiCtrlValList cl = mcvll->find(ch, cntrl);
3037 if (cl == mcvll->end()) {
3038 fprintf(stderr, "removePartPortCtrlEvents: controller %d(0x%x) for channel %d not found size %zd\n",
3039 cntrl, cntrl, ch, mcvll->size());
3040 return false;
3041 }
3042 MidiCtrlValList* mcvl = cl->second;
3043 iMidiCtrlVal imcv = mcvl->findMCtlVal(tck, part, val);
3044 if (imcv == mcvl->end()) {
3045 // Let's throw up the error only if we were expecting the cache event to be there,
3046 // as is the case when the tick is inside the part. When the tick is NOT inside the part
3047 // a cache event should really not be there. But if one is found it should be deleted anyway.
3048 #ifdef ALLOW_LEFT_HIDDEN_EVENTS
3049 if((int)tck >= (int)part->tick() && (int)tck < (int)part->tick() + (int)part->lenTick())
3050 #else
3051 if(tck < part->tick() + part->lenTick())
3052 #endif
3053 fprintf(stderr, "removePartPortCtrlEvents: (tick: %u): not found (size %zd)\n", tck, mcvl->size());
3054 return false;
3055 }
3056 return add(PendingOperationItem(mcvl, imcv, PendingOperationItem::DeleteMidiCtrlVal));
3057 }
3058 return false;
3059 }
3060
removePartPortCtrlEvents(Part * part,Track * track)3061 void PendingOperationList::removePartPortCtrlEvents(Part* part, Track* track)
3062 {
3063 if(!track || !track->isMidiTrack())
3064 return;
3065 for(ciEvent ie = part->events().begin(); ie != part->events().end(); ++ie)
3066 {
3067 removePartPortCtrlEvents(ie->second, part, track);
3068 }
3069 }
3070
3071 //---------------------------------------------------------
3072 // addPortCtrlEvents
3073 //---------------------------------------------------------
3074
addTrackPortCtrlEvents(Track * track)3075 void PendingOperationList::addTrackPortCtrlEvents(Track* track)
3076 {
3077 if(!track || !track->isMidiTrack())
3078 return;
3079 const PartList* pl = track->cparts();
3080 for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)
3081 {
3082 Part* part = ip->second;
3083 addPartPortCtrlEvents(part, part->tick(), part->lenTick(), track);
3084 }
3085 }
3086
3087 //---------------------------------------------------------
3088 // removePortCtrlEvents
3089 //---------------------------------------------------------
3090
removeTrackPortCtrlEvents(Track * track)3091 void PendingOperationList::removeTrackPortCtrlEvents(Track* track)
3092 {
3093 if(!track || !track->isMidiTrack())
3094 return;
3095 const PartList* pl = track->cparts();
3096 for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)
3097 {
3098 Part* part = ip->second;
3099 removePartPortCtrlEvents(part, track);
3100 }
3101 }
3102
modifyPartPortCtrlEvents(const Event & old_event,const Event & event,Part * part)3103 void PendingOperationList::modifyPartPortCtrlEvents(const Event& old_event, const Event& event, Part* part)
3104 {
3105 Track* t = part->track();
3106 if(!t || !t->isMidiTrack())
3107 return;
3108 if(old_event.type() != Controller || event.type() != Controller)
3109 return;
3110 MidiTrack* mt = static_cast<MidiTrack*>(t);
3111
3112 unsigned int tck_erase = old_event.tick() + part->tick();
3113 int cntrl_erase = old_event.dataA();
3114 int val_erase = old_event.dataB();
3115 iMidiCtrlVal imcv_erase;
3116 bool found_erase = false;
3117
3118 // Is it a drum controller old_event, according to the track port's instrument?
3119 int ch_erase;
3120 MidiPort* mp_erase;
3121 mt->mappedPortChanCtrl(&cntrl_erase, nullptr, &mp_erase, &ch_erase);
3122
3123
3124 MidiCtrlValListList* mcvll_erase = mp_erase->controller();
3125 MidiCtrlValList* mcvl_erase = 0;
3126 iMidiCtrlValList cl_erase = mcvll_erase->find(ch_erase, cntrl_erase);
3127 if(cl_erase == mcvll_erase->end())
3128 {
3129 if(MusEGlobal::debugMsg)
3130 printf("modifyPartPortCtrlEvents: controller %d(0x%x) for channel %d not found size %zd\n",
3131 cntrl_erase, cntrl_erase, ch_erase, mcvll_erase->size());
3132 }
3133 else
3134 {
3135 mcvl_erase = cl_erase->second;
3136 imcv_erase = mcvl_erase->findMCtlVal(tck_erase, part, val_erase);
3137 if(imcv_erase == mcvl_erase->end())
3138 {
3139 if(MusEGlobal::debugMsg)
3140 printf("modifyPartPortCtrlEvents(tick:%u val:%d): not found (size %zd)\n", tck_erase, val_erase, mcvl_erase->size());
3141 }
3142 else
3143 found_erase = true;
3144 }
3145
3146 unsigned int tck_add = event.tick() + part->tick();
3147 int cntrl_add = event.dataA();
3148 int val_add = event.dataB();
3149
3150
3151 // FIXME FIXME CHECK THIS
3152 //
3153 // Why wasn't 'ch' given its own 'ch_add' variable in the original code?
3154 // And why did 'mp_add' default to mp_erase above.
3155 // That means the channel and port would have defaulted to the ones
3156 // being erased above, not the track's. That can't be right !
3157
3158
3159 // Is it a drum controller event, according to the track port's instrument?
3160 int ch_add;
3161 MidiPort* mp_add;
3162 mt->mappedPortChanCtrl(&cntrl_add, nullptr, &mp_add, &ch_add);
3163
3164 MidiCtrlValList* mcvl_add;
3165 MidiCtrlValListList* mcvll_add = mp_add->controller();
3166 iMidiCtrlValList imcvll_add = mcvll_add->find(ch_add, cntrl_add);
3167 if(imcvll_add == mcvll_add->end())
3168 {
3169 if(found_erase)
3170 add(PendingOperationItem(mcvl_erase, imcv_erase, PendingOperationItem::DeleteMidiCtrlVal));
3171 PendingOperationItem poi(mcvll_add, 0, ch_add, cntrl_add, PendingOperationItem::AddMidiCtrlValList);
3172 if(findAllocationOp(poi) == end())
3173 {
3174 poi._mcvl = new MidiCtrlValList(cntrl_add);
3175 add(poi);
3176 }
3177 // The operation will catch and ignore events which are past the end of the part.
3178 add(PendingOperationItem(poi._mcvl, part, tck_add, val_add, PendingOperationItem::AddMidiCtrlVal));
3179 return;
3180 }
3181 else
3182 {
3183 mcvl_add = imcvll_add->second;
3184 iMidiCtrlVal imcv_add = mcvl_add->findMCtlVal(tck_add, part, val_add);
3185 if(imcv_add != mcvl_add->end())
3186 {
3187 if(tck_erase == tck_add && mcvl_erase == mcvl_add)
3188 {
3189 // The operation will catch and ignore events which are past the end of the part.
3190 add(PendingOperationItem(mcvl_add, imcv_add, val_add, PendingOperationItem::ModifyMidiCtrlVal));
3191 }
3192 else
3193 {
3194 if(found_erase)
3195 {
3196 add(PendingOperationItem(mcvl_erase, imcv_erase, PendingOperationItem::DeleteMidiCtrlVal));
3197 }
3198 // The operation will catch and ignore events which are past the end of the part.
3199 add(PendingOperationItem(mcvl_add, part, tck_add, val_add, PendingOperationItem::AddMidiCtrlVal));
3200 }
3201 return;
3202 }
3203 else
3204 {
3205 if(found_erase)
3206 add(PendingOperationItem(mcvl_erase, imcv_erase, PendingOperationItem::DeleteMidiCtrlVal));
3207 // The operation will catch and ignore events which are past the end of the part.
3208 add(PendingOperationItem(mcvl_add, part, tck_add, val_add, PendingOperationItem::AddMidiCtrlVal));
3209 }
3210 }
3211 }
3212
addPartOperation(PartList * partlist,Part * part)3213 void PendingOperationList::addPartOperation(PartList *partlist, Part* part)
3214 {
3215 // There is protection, in the catch-all Undo::insert(), from failure here (such as double add, del + add, add + del)
3216 // which might cause addPortCtrlEvents() without parts or without corresponding removePortCtrlEvents etc.
3217 add(PendingOperationItem(partlist, part, PendingOperationItem::AddPart));
3218 addPartPortCtrlEvents(part, part->posValue(), part->lenValue(), part->track());
3219 }
3220
delPartOperation(PartList * partlist,Part * part)3221 void PendingOperationList::delPartOperation(PartList *partlist, Part* part)
3222 {
3223 // There is protection, in the catch-all Undo::insert(), from failure here (such as double del, del + add, add + del)
3224 // which might cause addPortCtrlEvents() without parts or without corresponding removePortCtrlEvents etc.
3225 removePartPortCtrlEvents(part, part->track());
3226 iPart i;
3227 for (i = partlist->begin(); i != partlist->end(); ++i) {
3228 if (i->second == part) {
3229 add(PendingOperationItem(partlist, i, PendingOperationItem::DeletePart));
3230 return;
3231 }
3232 }
3233 printf("THIS SHOULD NEVER HAPPEN: could not find the part in PendingOperationList::delPartOperation()!\n");
3234 }
3235
movePartOperation(PartList * partlist,Part * part,unsigned int new_pos,Track * track)3236 void PendingOperationList::movePartOperation(PartList *partlist, Part* part, unsigned int new_pos, Track* track)
3237 {
3238 removePartPortCtrlEvents(part, part->track());
3239 iPart i = partlist->end();
3240 if(track)
3241 {
3242 for (i = partlist->begin(); i != partlist->end(); ++i) {
3243 if (i->second == part)
3244 break;
3245 }
3246 if(i == partlist->end())
3247 printf("THIS SHOULD NEVER HAPPEN: could not find the part in PendingOperationList::movePartOperation()!\n");
3248 }
3249
3250 add(PendingOperationItem(i, part, new_pos, PendingOperationItem::MovePart, track));
3251
3252 if(!track)
3253 track = part->track();
3254
3255 addPartPortCtrlEvents(part, new_pos, part->lenValue(), track);
3256 }
3257
modifyPartStartOperation(Part * part,unsigned int new_pos,unsigned int new_len,int64_t events_offset,Pos::TType events_offset_time_type)3258 void PendingOperationList::modifyPartStartOperation(
3259 Part* part, unsigned int new_pos, unsigned int new_len, int64_t events_offset, Pos::TType events_offset_time_type)
3260 {
3261 if(!part->track())
3262 return;
3263
3264 PartList* partlist = part->track()->parts();
3265 iPart ip = partlist->end();
3266 for (ip = partlist->begin(); ip != partlist->end(); ++ip) {
3267 if (ip->second == part)
3268 break;
3269 }
3270 if(ip == partlist->end())
3271 {
3272 fprintf(stderr, "THIS SHOULD NEVER HAPPEN: could not find part in PendingOperationList::modifyPartStartOperation()!\n");
3273 return;
3274 }
3275
3276 EventList* new_el = nullptr;
3277 // If we are dragging the part's events with the border, their positions relative to the border don't change.
3278 // If we are not dragging the events, their positions relative to the border change so we MUST move ALL the events.
3279 if(events_offset != 0)
3280 {
3281 // Compose a complete new list to quickly swap with the existing list.
3282 const EventList& el = part->events();
3283 new_el = new EventList();
3284 for(ciEvent ie = el.cbegin(); ie != el.cend(); ++ie)
3285 {
3286 Event e = ie->second.clone();
3287 if(e.pos().type() == events_offset_time_type)
3288 {
3289 // NOTE: Don't alter the offset here or below in the conversions. It messes with the ability of the undo system
3290 // to properly undo a movement. It also breaks the rule that all clone parts MUST have the same event times.
3291 // Checks and limits should be done before calling this function.
3292 //if((int64_t)e.posValue() + events_offset < 0)
3293 // e.setPosValue(0);
3294 //else
3295 e.setPosValue(e.posValue() + events_offset);
3296 }
3297 else
3298 {
3299 // In case the event and part pos types differ, the event dominates.
3300 const unsigned int new_part_pos_val = Pos::convert(new_pos, part->type(), e.pos().type());
3301 const unsigned int old_abs_ev_pos_val = Pos::convert(e.posValue() + new_part_pos_val, e.pos().type(), events_offset_time_type);
3302 const unsigned int new_abs_ev_pos_val = Pos::convert(old_abs_ev_pos_val + events_offset, events_offset_time_type, e.pos().type());
3303 const unsigned int new_ev_pos_val = new_abs_ev_pos_val - new_part_pos_val;
3304 e.setPosValue(new_ev_pos_val);
3305 }
3306 new_el->add(e);
3307 }
3308 }
3309
3310 // If we are dragging the part's events with the border, we must update the midi controller cache.
3311 // If we are not dragging the events, their absolute positions don't change so there should be no need to update the cache.
3312 // First half of the midi controller cache update:
3313 removePartPortCtrlEvents(part, part->track());
3314
3315 add(PendingOperationItem(ip, part, new_pos, new_len, new_el, PendingOperationItem::ModifyPartStart));
3316
3317 // Second half of the midi controller cache update:
3318 // The operation will catch and ignore events which are outside of the part.
3319 // In case the new_pos and events_offset types differ, the events_offset dominates.
3320 const unsigned int new_cache_offset =
3321 Pos::convert(events_offset + Pos::convert(new_pos, part->type(), events_offset_time_type),
3322 events_offset_time_type, Pos::TICKS);
3323 addPartPortCtrlEvents(part, new_cache_offset, part->lenValue(), part->track());
3324 }
3325
modifyPartLengthOperation(Part * part,unsigned int new_len,int64_t events_offset,Pos::TType events_offset_time_type)3326 void PendingOperationList::modifyPartLengthOperation(
3327 Part* part, unsigned int new_len, int64_t events_offset, Pos::TType events_offset_time_type)
3328 {
3329 if(!part->track())
3330 return;
3331
3332 PartList* partlist = part->track()->parts();
3333 iPart ip = partlist->end();
3334 for (ip = partlist->begin(); ip != partlist->end(); ++ip) {
3335 if (ip->second == part)
3336 break;
3337 }
3338 if(ip == partlist->end())
3339 {
3340 fprintf(stderr, "THIS SHOULD NEVER HAPPEN: could not find part in PendingOperationList::modifyPartLengthOperation()!\n");
3341 return;
3342 }
3343
3344 EventList* new_el = nullptr;
3345 // If we are dragging the part's events with the border, their positions relative to the border change so we MUST move ALL the events.
3346 // If we are not dragging the events, their positions relative to the border don't change.
3347 if(events_offset != 0)
3348 {
3349 // Compose a complete new list to quickly swap with the existing list.
3350 const EventList& el = part->events();
3351 new_el = new EventList();
3352 for(ciEvent ie = el.cbegin(); ie != el.cend(); ++ie)
3353 {
3354 Event e = ie->second.clone();
3355 if(e.pos().type() == events_offset_time_type)
3356 {
3357 // NOTE: Don't alter the offset here or below in the conversions. It messes with the ability of the undo system
3358 // to properly undo a movement. It also breaks the rule that all clone parts MUST have the same event times.
3359 // Checks and limits should be done before calling this function.
3360 //if((int64_t)e.posValue() + events_offset < 0)
3361 // e.setPosValue(0);
3362 //else
3363 e.setPosValue(e.posValue() + events_offset);
3364 }
3365 else
3366 {
3367 // In case the event and part pos types differ, the event dominates.
3368 const unsigned int part_pos_val = part->posValue(e.pos().type());
3369 const unsigned int old_abs_ev_pos_val = Pos::convert(e.posValue() + part_pos_val, e.pos().type(), events_offset_time_type);
3370 const unsigned int new_abs_ev_pos_val = Pos::convert(old_abs_ev_pos_val + events_offset, events_offset_time_type, e.pos().type());
3371 const unsigned int new_ev_pos_val = new_abs_ev_pos_val - part_pos_val;
3372 e.setPosValue(new_ev_pos_val);
3373 }
3374 new_el->add(e);
3375 }
3376 }
3377
3378 // If we are dragging the part's events with the border, we must update the midi controller cache.
3379 // If we are not dragging the events, their absolute positions don't change so there should be no need to update the cache.
3380 // First half of the midi controller cache update:
3381 removePartPortCtrlEvents(part, part->track());
3382
3383 add(PendingOperationItem(ip, part, new_len, new_el, PendingOperationItem::ModifyPartLength));
3384
3385 // Second half of the midi controller cache update:
3386 // The operation will catch and ignore events which are outside of the part.
3387 // In case the new_pos and events_offset types differ, the events_offset dominates.
3388 const unsigned int new_cache_offset =
3389 Pos::convert(events_offset + part->posValue(events_offset_time_type), events_offset_time_type, Pos::TICKS);
3390
3391 addPartPortCtrlEvents(part, new_cache_offset, part->lenValue(), part->track());
3392 }
3393
3394
3395 //---------------------------------------------------------
3396 // addTrackAuxSendOperation
3397 //---------------------------------------------------------
3398
addTrackAuxSendOperation(AudioTrack * atrack,int n)3399 void PendingOperationList::addTrackAuxSendOperation(AudioTrack *atrack, int n)
3400 {
3401 AuxSendValueList *vl = atrack->getAuxSendValueList();
3402 const int nn = vl->size();
3403 for (int i = nn; i < n; ++i)
3404 add(PendingOperationItem(vl, 0.0, PendingOperationItem::AddAuxSendValue));
3405 }
3406
3407 //---------------------------------------------------------
3408 // TrackMidiCtrlRemapOperation
3409 //---------------------------------------------------------
3410
TrackMidiCtrlRemapOperation(MidiTrack * mtrack,int index,int newPort,int newChan,int newNote,MidiCtrlValRemapOperation * rmop)3411 void TrackMidiCtrlRemapOperation(
3412 MidiTrack *mtrack, int index, int newPort, int newChan, int newNote, MidiCtrlValRemapOperation* rmop)
3413 {
3414 const int out_port = mtrack->outPort();
3415 const int out_chan = mtrack->outChannel();
3416
3417 if(mtrack->type() != Track::DRUM || out_port < 0 || out_port >= MusECore::MIDI_PORTS)
3418 return;
3419
3420 // Default to track port if -1 and track channel if -1.
3421 if(newPort == -1)
3422 newPort = out_port;
3423
3424 if(newChan == -1)
3425 newChan = out_chan;
3426
3427 MidiPort* trackmp = &MusEGlobal::midiPorts[out_port];
3428
3429 const DrumMap *drum_map = mtrack->drummap();
3430
3431 int dm_ch = drum_map[index].channel;
3432 if(dm_ch == -1)
3433 dm_ch = out_chan;
3434 int dm_port = drum_map[index].port;
3435 if(dm_port == -1)
3436 dm_port = out_port;
3437 MidiPort* dm_mp = &MusEGlobal::midiPorts[dm_port];
3438
3439 MidiCtrlValListList* dm_mcvll = dm_mp->controller();
3440 MidiCtrlValList* v_mcvl;
3441 int v_ch, v_ctrl, v_idx;
3442 for(iMidiCtrlValList idm_mcvl = dm_mcvll->begin(); idm_mcvl != dm_mcvll->end(); ++idm_mcvl)
3443 {
3444 v_ch = idm_mcvl->first >> 24;
3445 if(v_ch != dm_ch)
3446 continue;
3447 v_mcvl = idm_mcvl->second;
3448 v_ctrl = v_mcvl->num();
3449
3450 // Is it a drum controller, according to the track port's instrument?
3451 if(!trackmp->drumController(v_ctrl))
3452 continue;
3453
3454 v_idx = v_ctrl & 0xff;
3455 if(v_idx != drum_map[index].anote)
3456 continue;
3457
3458 // Does this midi control value list need to be changed (values moved etc)?
3459 iMidiCtrlVal imcv = v_mcvl->begin();
3460 for( ; imcv != v_mcvl->end(); ++imcv)
3461 {
3462 const MidiCtrlVal& mcv = imcv->second;
3463 if(mcv.part && mcv.part->track() == mtrack)
3464 break;
3465 }
3466 if(imcv != v_mcvl->end())
3467 {
3468 // A contribution from a part on this track was found.
3469 // We must compose a new list, or get an existing one and schedule the existing
3470 // one for iterator erasure and pointer deletion.
3471 // Add the erase iterator. Add will ignore if the erase iterator already exists.
3472 rmop->_midiCtrlValLists2bErased.add(dm_port, idm_mcvl);
3473 // Insert the delete pointer. Insert will ignore if the delete pointer already exists.
3474 rmop->_midiCtrlValLists2bDeleted.insert(v_mcvl);
3475
3476 MidiCtrlValListList* op_mcvll;
3477 iMidiCtrlValLists2bAdded_t imcvla = rmop->_midiCtrlValLists2bAdded.find(dm_port);
3478 if(imcvla == rmop->_midiCtrlValLists2bAdded.end())
3479 {
3480 op_mcvll = new MidiCtrlValListList();
3481 rmop->_midiCtrlValLists2bAdded.insert(MidiCtrlValLists2bAddedInsertPair_t(dm_port, op_mcvll));
3482 }
3483 else
3484 op_mcvll = imcvla->second;
3485
3486 MidiCtrlValList* op_mcvl;
3487 iMidiCtrlValList imcvl = op_mcvll->find(dm_ch, v_ctrl);
3488 if(imcvl == op_mcvll->end())
3489 {
3490 op_mcvl = new MidiCtrlValList(v_ctrl);
3491 op_mcvll->add(dm_ch, op_mcvl);
3492 // Assign the contents of the original list to the new list.
3493 *op_mcvl = *v_mcvl;
3494 }
3495 else
3496 op_mcvl = imcvl->second;
3497
3498 // Remove from the list any contributions from this track.
3499 iMidiCtrlVal iopmcv = op_mcvl->begin();
3500 for( ; iopmcv != op_mcvl->end(); )
3501 {
3502 const MidiCtrlVal& mcv = iopmcv->second;
3503 if(mcv.part && mcv.part->track() == mtrack)
3504 {
3505 iMidiCtrlVal iopmcv_save = iopmcv;
3506 ++iopmcv_save;
3507 op_mcvl->erase(iopmcv);
3508 iopmcv = iopmcv_save;
3509 }
3510 else
3511 ++iopmcv;
3512 }
3513 }
3514
3515 // We will be making changes to the list pointed to by the new settings.
3516 // We must schedule the existing one for iterator erasure and pointer deletion.
3517 MidiPort* dm_mp_new = &MusEGlobal::midiPorts[newPort];
3518 MidiCtrlValListList* dm_mcvll_new = dm_mp_new->controller();
3519 MidiCtrlValList* v_mcvl_new = 0;
3520 const int v_ctrl_new = (v_ctrl & ~0xff) | newNote;
3521 iMidiCtrlValList idm_mcvl_new = dm_mcvll_new->find(newChan, v_ctrl_new);
3522 if(idm_mcvl_new != dm_mcvll_new->end())
3523 {
3524 v_mcvl_new = idm_mcvl_new->second;
3525 // Add the erase iterator. Add will ignore if the erase iterator already exists.
3526 rmop->_midiCtrlValLists2bErased.add(newPort, idm_mcvl_new);
3527 // Insert the delete pointer. Insert will ignore if the delete pointer already exists.
3528 rmop->_midiCtrlValLists2bDeleted.insert(v_mcvl_new);
3529 }
3530
3531 // Create a new list of lists, or get an existing one.
3532 MidiCtrlValListList* op_mcvll_new;
3533 iMidiCtrlValLists2bAdded_t imcvla_new = rmop->_midiCtrlValLists2bAdded.find(newPort);
3534 if(imcvla_new == rmop->_midiCtrlValLists2bAdded.end())
3535 {
3536 op_mcvll_new = new MidiCtrlValListList();
3537 rmop->_midiCtrlValLists2bAdded.insert(MidiCtrlValLists2bAddedInsertPair_t(newPort, op_mcvll_new));
3538 }
3539 else
3540 op_mcvll_new = imcvla_new->second;
3541
3542 // Compose a new list for replacement, or get an existing one.
3543 MidiCtrlValList* op_mcvl_new;
3544 iMidiCtrlValList imcvl_new = op_mcvll_new->find(newChan, v_ctrl_new);
3545 if(imcvl_new == op_mcvll_new->end())
3546 {
3547 op_mcvl_new = new MidiCtrlValList(v_ctrl_new);
3548 op_mcvll_new->add(newChan, op_mcvl_new);
3549 // Assign the contents of the original list to the new list.
3550 if(v_mcvl_new)
3551 *op_mcvl_new = *v_mcvl_new;
3552 }
3553 else
3554 op_mcvl_new = imcvl_new->second;
3555
3556 // Add to the list any contributions from this track.
3557 for(ciMidiCtrlVal imcv_new = v_mcvl->begin(); imcv_new != v_mcvl->end(); ++imcv_new)
3558 {
3559 const MidiCtrlVal& mcv = imcv_new->second;
3560 if(mcv.part && mcv.part->track() == mtrack)
3561 {
3562 op_mcvl_new->addMCtlVal(imcv_new->first, mcv.val, mcv.part);
3563 }
3564 }
3565 }
3566 }
3567
3568 } // namespace MusECore
3569
3570