1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //  $Id: song.cpp,v 1.59.2.52 2009/12/15 03:39:58 terminator356 Exp $
5 //
6 //  (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)
7 //
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU General Public License
10 //  as published by the Free Software Foundation; version 2 of
11 //  the License, or (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //  GNU General Public License for more details.
17 //
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program; if not, write to the Free Software
20 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 //
22 //=========================================================
23 
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <iostream>
28 
29 #include <QDir>
30 #include <QMessageBox>
31 #include <QPoint>
32 #include <QString>
33 #include <QTextStream>
34 #include <QProcess>
35 #include <QByteArray>
36 #include <QProgressDialog>
37 #include <QList>
38 
39 #include "app.h"
40 #include "driver/jackmidi.h"
41 #include "driver/alsamidi.h"
42 #include "song.h"
43 #include "key.h"
44 #include "globals.h"
45 #include "drummap.h"
46 #include "amixer.h"
47 #include "midiseq.h"
48 #include "gconfig.h"
49 #include "sync.h"
50 #include "midictrl.h"
51 #include "menutitleitem.h"
52 #include "midi_audio_control.h"
53 #include "tracks_duplicate.h"
54 #include "midi_consts.h"
55 #include "keyevent.h"
56 #ifndef _WIN32
57 #include <sys/wait.h>
58 #endif
59 #include "strntcpy.h"
60 #include "name_factory.h"
61 #include "synthdialog.h"
62 
63 // Forwards from header:
64 #include <QAction>
65 #include <QMenu>
66 #include "undo.h"
67 #include "track.h"
68 #include "event.h"
69 #include "xml.h"
70 #include "track.h"
71 #include "part.h"
72 #include "marker/marker.h"
73 #include "route.h"
74 #include "audio.h"
75 #include "midiport.h"
76 #include "audiodev.h"
77 
78 // For debugging output: Uncomment the fprintf section.
79 #define ERROR_TIMESTRETCH(dev, format, args...)  fprintf(dev, format, ##args)
80 #define ERROR_WAVE(dev, format, args...) fprintf(dev, format, ##args)
81 #define INFO_WAVE(dev, format, args...) // fprintf(dev, format, ##args)
82 
83 // Undefine if and when multiple output routes are added to midi tracks.
84 #define _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
85 
86 namespace MusEGlobal {
87 MusECore::Song* song = 0;
88 }
89 
90 namespace MusECore {
91 
92 extern void clearMidiTransforms();
93 extern void clearMidiInputTransforms();
94 
95 //---------------------------------------------------------
96 //   Song
97 //---------------------------------------------------------
98 
Song(const char * name)99 Song::Song(const char* name)
100    :QObject(0)
101       {
102       setObjectName(name);
103 
104       _ipcInEventBuffers = new LockFreeMPSCRingBuffer<MidiPlayEvent>(16384);
105       _ipcOutEventBuffers = new LockFreeMPSCRingBuffer<MidiPlayEvent>(16384);
106 
107       _fCpuLoad = 0.0;
108       _fDspLoad = 0.0;
109       _xRunsCount = 0;
110 
111       noteFifoSize   = 0;
112       noteFifoWindex = 0;
113       noteFifoRindex = 0;
114       undoList     = new UndoList(true);  // "true" means "this is an undoList",
115       redoList     = new UndoList(false); // "false" means "redoList"
116       _markerList  = new MarkerList;
117       _globalPitchShift = 0;
118       bounceTrack = NULL;
119       bounceOutput = NULL;
120       showSongInfo=true;
121       clearDrumMap(); // One-time only early init
122       clear(false);
123       }
124 
125 //---------------------------------------------------------
126 //   Song
127 //---------------------------------------------------------
128 
~Song()129 Song::~Song()
130       {
131       delete undoList;
132       delete redoList;
133       delete _markerList;
134       if(_ipcOutEventBuffers)
135         delete _ipcOutEventBuffers;
136       if(_ipcInEventBuffers)
137         delete _ipcInEventBuffers;
138       }
139 
140 //---------------------------------------------------------
141 //   putEvent
142 //---------------------------------------------------------
143 
putEvent(int pv)144 void Song::putEvent(int pv)
145       {
146       if (noteFifoSize < REC_NOTE_FIFO_SIZE) {
147             recNoteFifo[noteFifoWindex] = pv;
148             noteFifoWindex = (noteFifoWindex + 1) % REC_NOTE_FIFO_SIZE;
149             ++noteFifoSize;
150             }
151       }
152 
putEventCC(char cc)153 void Song::putEventCC(char cc)
154 {
155     if (MusEGlobal::rcEnableCC)
156         rcCC = cc;
157 }
158 
159 // REMOVE Tim. samplerate. Added. TODO
160 #if 0
161 //---------------------------------------------------------
162 //   setProjectSampleRate
163 //---------------------------------------------------------
164 
165 void Song::setProjectSampleRate(int rate)
166 {
167   if(rate != MusEGlobal::projectSampleRate)
168     // TODO: Do the permanent conversion.
169     convertProjectSampleRate(rate);
170 
171   // Now set the rate.
172   MusEGlobal::projectSampleRate;
173 }
174 
175 //---------------------------------------------------------
176 //   projectSampleRateDiffers
177 //---------------------------------------------------------
178 
179 bool Song::projectSampleRateDiffers() const
180 {
181   return MusEGlobal::projectSampleRate != MusEGlobal::sampleRate;
182 }
183 
184 //---------------------------------------------------------
185 //   projectSampleRateRatio
186 //---------------------------------------------------------
187 
188 double Song::projectSampleRateRatio() const
189 {
190   return (double)MusEGlobal::projectSampleRate / (double)MusEGlobal::sampleRate;
191 }
192 #endif
193 
194 //---------------------------------------------------------
195 //   setTempo
196 //    public slot
197 //---------------------------------------------------------
198 
setTempo(int newTempo)199 void Song::setTempo(int newTempo)
200       {
201       applyOperation(UndoOp(UndoOp::SetTempo, pos[0].tick(), newTempo));
202       }
203 
204 //---------------------------------------------------------
205 //   setSig
206 //    called from transport window
207 //---------------------------------------------------------
208 
setSig(int z,int n)209 void Song::setSig(int z, int n)
210       {
211             // Add will replace if found.
212             MusEGlobal::song->applyOperation(MusECore::UndoOp(MusECore::UndoOp::AddSig,
213                             pos[0].tick(), z, n));
214       }
215 
setSig(const MusECore::TimeSignature & sig)216 void Song::setSig(const MusECore::TimeSignature& sig)
217       {
218             // Add will replace if found.
219             MusEGlobal::song->applyOperation(MusECore::UndoOp(MusECore::UndoOp::AddSig,
220                             pos[0].tick(), sig.z, sig.n));
221       }
222 
223 //---------------------------------------------------------
224 //    addNewTrack
225 //    Called from GUI context
226 //    If insertAt is valid, inserts before insertAt. Else at the end after all tracks.
227 //    Besides normal track types, n includes synth menu ids from populateAddTrack()
228 //---------------------------------------------------------
229 
addNewTrack(QAction * action,Track * insertAt)230 Track* Song::addNewTrack(QAction* action, Track* insertAt)
231 {
232     int n = action->data().toInt();
233     // Ignore negative numbers since this slot could be called by a menu or list etc. passing -1.
234     if(n < 0)
235         return nullptr;
236 
237 
238     // Synth sub-menu id?
239     if(n >= MENU_ADD_SYNTH_ID_BASE || n == MusECore::Track::AUDIO_SOFTSYNTH)
240     {
241         if (n == MusECore::Track::AUDIO_SOFTSYNTH) {
242             n = MusEGui::SynthDialog().getSynthIndex(nullptr);
243             if (n < 0 || n >= static_cast<int>(MusEGlobal::synthis.size()))
244                 return nullptr;
245         }
246         else
247         {
248             n -= MENU_ADD_SYNTH_ID_BASE;
249             int ntype = n / MENU_ADD_SYNTH_ID_BASE;
250             if(ntype >= Synth::SYNTH_TYPE_END)
251                 return nullptr;
252 
253             // if we ever support Wine VSTs through some other means than through dssi-vst this must be adapted
254             if (ntype == MusECore::Synth::VST_SYNTH)
255                 ntype=MusECore::Synth::DSSI_SYNTH;
256             if (ntype == MusECore::Synth::LV2_EFFECT)
257                 ntype=MusECore::Synth::LV2_SYNTH; // the LV2_EFFECT is a specialization used in the menu only, we reassign it to regular LV2_SYNTH
258 
259             n %= MENU_ADD_SYNTH_ID_BASE;
260             if(n >= (int)MusEGlobal::synthis.size())
261                 return nullptr;
262 
263             if (MusEGlobal::debugMsg)
264                 fprintf(stderr, "Song::addNewTrack synth: type:%d idx:%d class:%s label:%s\n", ntype, n, MusEGlobal::synthis[n]->baseName().toLatin1().constData(), MusEGlobal::synthis[n]->name().toLatin1().constData());
265         }
266 
267         SynthI* si = createSynthI(MusEGlobal::synthis[n]->baseName(), MusEGlobal::synthis[n]->uri(),
268                                   MusEGlobal::synthis[n]->name(), MusEGlobal::synthis[n]->synthType(), insertAt);
269         //      SynthI* si = createSynthI(MusEGlobal::synthis[n]->baseName(), MusEGlobal::synthis[n]->uri(),
270         //                                MusEGlobal::synthis[n]->name(), (Synth::Type)ntype, insertAt);
271         if(!si)
272             return nullptr;
273 
274         if (MusEGlobal::config.unhideTracks) SynthI::setVisible(true);
275 
276         // Add instance last in midi device list.
277         for (int i = 0; i < MusECore::MIDI_PORTS; ++i)
278         {
279             MidiPort* port  = &MusEGlobal::midiPorts[i];
280             MidiDevice* dev = port->device();
281             if (dev==nullptr)
282             {
283                 // This is a brand new instance. Set the instrument as well for convenience.
284                 MusEGlobal::audio->msgSetMidiDevice(port, si, si);
285                 // Save settings. Use simple version - do NOT set style or stylesheet, this has nothing to do with that.
286                 MusEGlobal::muse->changeConfig(true);
287                 if (SynthI::visible()) {
288                     selectAllTracks(false);
289                     si->setSelected(true);
290                     update();
291                 }
292                 return si;
293             }
294         }
295         if (SynthI::visible()) {
296             selectAllTracks(false);
297             si->setSelected(true);
298             update(SC_TRACK_SELECTION);
299         }
300         return si;
301     }
302     // Normal track.
303     else
304     {
305         // Ignore AUDIO_SOFTSYNTH (or anything greater, to allow for other entries in some menu),
306         //  now that we have it as the synth menu id, since addTrack doesn't like it.
307         if((Track::TrackType)n >= Track::AUDIO_SOFTSYNTH)
308             return nullptr;
309 
310         Track* t = addTrack((Track::TrackType)n, insertAt);
311         if (t && t->isVisible()) {
312             selectAllTracks(false);
313             t->setSelected(true);
314             update(SC_TRACK_SELECTION);
315         }
316         return t;
317     }
318 }
319 
320 //---------------------------------------------------------
321 //    createTrack
322 //---------------------------------------------------------
323 
createTrack(Track::TrackType type,bool setDefaults)324 Track* Song::createTrack(Track::TrackType type, bool setDefaults)
325       {
326       Track* track = nullptr;
327       switch(type) {
328             case Track::MIDI:
329                   track = new MidiTrack();
330                   track->setType(Track::MIDI);
331                   break;
332             case Track::DRUM:
333                   track = new MidiTrack();
334                   track->setType(Track::DRUM);
335                   ((MidiTrack*)track)->setOutChannel(9);
336                   break;
337             case Track::WAVE:
338                   track = new MusECore::WaveTrack();
339                   break;
340             case Track::AUDIO_OUTPUT:
341                   track = new AudioOutput();
342                   break;
343             case Track::AUDIO_GROUP:
344                   track = new AudioGroup();
345                   break;
346             case Track::AUDIO_AUX:
347                   track = new AudioAux();
348                   break;
349             case Track::AUDIO_INPUT:
350                   track = new AudioInput();
351                   break;
352             case Track::AUDIO_SOFTSYNTH:
353                   fprintf(stderr, "not implemented: Song::createTrack(SOFTSYNTH)\n");
354                   return nullptr;
355             default:
356                   fprintf(stderr, "THIS SHOULD NEVER HAPPEN: Song::createTrack() illegal type %d. returning NULL.\n"
357                          "save your work if you can and expect soon crashes!\n", type);
358                   return nullptr;
359             }
360 
361       if(setDefaults)
362       {
363         // Add default track <-> midiport routes.
364         if(track->isMidiTrack())
365         {
366           MidiTrack* mt = (MidiTrack*)track;
367           int c;
368           bool defOutFound = false;                /// TODO: Remove this if and when multiple output routes supported.
369           const int chmask = (1 << MusECore::MUSE_MIDI_CHANNELS) - 1;
370           for(int i = 0; i < MusECore::MIDI_PORTS; ++i)
371           {
372             MidiPort* mp = &MusEGlobal::midiPorts[i];
373             if(!mp->device())  // Only if device is valid.
374               continue;
375             if(mp->device()->rwFlags() & 0x02) // Readable
376             {
377               c = mp->defaultInChannels();
378               if(c)
379               {
380                 // All channels set or Omni? Use an Omni route:
381                 if(c == -1 || c == chmask)
382                   track->inRoutes()->push_back(Route(i));
383                 else
384                 // Add individual channels:
385                 for(int ch = 0; ch < MusECore::MUSE_MIDI_CHANNELS; ++ch)
386                 {
387                   if(c & (1 << ch))
388                     track->inRoutes()->push_back(Route(i, ch));
389                 }
390               }
391             }
392 
393             if(mp->device()->rwFlags() & 0x01) // Writeable
394             {
395               if(!defOutFound)                       ///
396               {
397                 c = mp->defaultOutChannels();
398                 if(c)
399                 {
400 
401   #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
402                   if(c == -1)
403                     c = 1;  // Just to be safe, shouldn't happen, default to channel 0.
404                   for(int ch = 0; ch < MusECore::MUSE_MIDI_CHANNELS; ++ch)
405                   {
406                     if(c & (1 << ch))
407                     {
408                       defOutFound = true;
409                       mt->setOutPort(i);
410                       if(type != Track::DRUM)  // Leave drum tracks at channel 10.
411                         mt->setOutChannel(ch);
412                       //updateFlags |= SC_ROUTE;
413                       break;
414                     }
415                   }
416   #else
417                   // All channels set or Omni? Use an Omni route:
418                   if(c == -1 || c == chmask)
419                     track->outRoutes()->push_back(Route(i));
420                   else
421                   // Add individual channels:
422                   for(int ch = 0; ch < MusECore::MUSE_MIDI_CHANNELS; ++ch)
423                   {
424                     if(c & (1 << ch))
425                       track->outRoutes()->push_back(Route(i, ch));
426                   }
427   #endif
428                 }
429               }
430             }
431           }
432 
433           if (!defOutFound) { // no default port found
434             // set it to the port with highest number
435 
436             for(int i = MusECore::MIDI_PORTS-1; i >= 0; --i) {
437 
438               MidiPort* mp = &MusEGlobal::midiPorts[i];
439 
440               if (mp->device() != NULL) {
441 
442                 mt->setOutPort(i);
443                 break;
444               }
445             }
446           }
447         }
448 
449         //
450         //  add default route to master
451         //
452         OutputList* ol = MusEGlobal::song->outputs();
453         if (!ol->empty()) {
454               AudioOutput* ao = ol->front();
455               switch(type) {
456                     case Track::WAVE:
457                     case Track::AUDIO_AUX:
458                           //fprintf(stderr, "Song::addTrack(): WAVE or AUDIO_AUX type:%d name:%s pushing default route to master\n", track->type(), track->name().toLatin1().constData());
459                           track->outRoutes()->push_back(Route(ao));
460                           break;
461                     // It should actually never get here now, but just in case.
462                     case Track::AUDIO_SOFTSYNTH:
463                           track->outRoutes()->push_back(Route(ao));
464                           break;
465                     default:
466                           break;
467                     }
468               }
469       }
470 
471       return track;
472       }
473 
474 //---------------------------------------------------------
475 //    addTrack
476 //    called from GUI context
477 //    type is track type
478 //    If insertAt is valid, inserts before insertAt. Else at the end after all tracks.
479 //---------------------------------------------------------
480 
addTrack(Track::TrackType type,Track * insertAt)481 Track* Song::addTrack(Track::TrackType type, Track* insertAt)
482       {
483       // Try to generate a unique track name.
484       TrackNameFactory names(type);
485       if(names.isEmpty())
486         return nullptr;
487 
488       Track* track = createTrack(type, true);
489       if(!track)
490         return nullptr;
491 
492       switch(type) {
493             case Track::MIDI:
494                   if (MusEGlobal::config.unhideTracks) MidiTrack::setVisible(true);
495                   break;
496             case Track::DRUM:
497                   if (MusEGlobal::config.unhideTracks) MidiTrack::setVisible(true);
498                   break;
499             case Track::WAVE:
500                   if (MusEGlobal::config.unhideTracks) WaveTrack::setVisible(true);
501                   break;
502             case Track::AUDIO_OUTPUT:
503                   if (MusEGlobal::config.unhideTracks) AudioOutput::setVisible(true);
504                   break;
505             case Track::AUDIO_GROUP:
506                   if (MusEGlobal::config.unhideTracks) AudioGroup::setVisible(true);
507                   break;
508             case Track::AUDIO_AUX:
509                   if (MusEGlobal::config.unhideTracks) AudioAux::setVisible(true);
510                   break;
511             case Track::AUDIO_INPUT:
512                   if (MusEGlobal::config.unhideTracks) AudioInput::setVisible(true);
513                   break;
514             case Track::AUDIO_SOFTSYNTH:
515                   fprintf(stderr, "not implemented: Song::addTrack(SOFTSYNTH)\n");
516                   return nullptr;
517             default:
518                   fprintf(stderr, "THIS SHOULD NEVER HAPPEN: Song::addTrack() illegal type %d. returning NULL.\n"
519                          "save your work if you can and expect soon crashes!\n", type);
520                   return nullptr;
521             }
522 
523       track->setName(names.first());
524 
525       int idx = insertAt ? _tracks.index(insertAt) : -1;
526       applyOperation(UndoOp(UndoOp::AddTrack, idx, track));
527 
528       return track;
529       }
530 
531 //---------------------------------------------------------
532 //    duplicateTracks
533 //    Called from GUI context
534 //---------------------------------------------------------
535 
duplicateTracks(Track * t)536 void Song::duplicateTracks(Track *t)
537 {
538     const TrackList& tl = _tracks;
539 
540     int audio_found = 0;
541     int midi_found = 0;
542     int new_drum_found = 0;
543 
544     if (t) {
545         if (t->type() == Track::DRUM)
546             ++new_drum_found;
547         else if (t->type() == Track::MIDI)
548             ++midi_found;
549         else
550             ++audio_found;
551     } else {
552         for (ciTrack it = tl.cbegin(); it != tl.cend(); ++it)
553             if ((*it)->selected())
554             {
555                 Track::TrackType type = (*it)->type();
556                 if (type == Track::DRUM)
557                     ++new_drum_found;
558                 else if (type == Track::MIDI)
559                     ++midi_found;
560                 else
561                     ++audio_found;
562             }
563     }
564 
565     if(audio_found == 0 && midi_found == 0 && new_drum_found==0)
566         return;
567 
568     MusEGui::DuplicateTracksDialog* dlg = new MusEGui::DuplicateTracksDialog(audio_found, midi_found, new_drum_found);
569 
570     int rv = dlg->exec();
571     if(rv == QDialog::Rejected)
572     {
573         delete dlg;
574         return;
575     }
576 
577     int copies = dlg->copies();
578 
579     int flags = Track::ASSIGN_PROPERTIES;
580     if(dlg->copyStdCtrls())
581         flags |= Track::ASSIGN_STD_CTRLS;
582     if(dlg->copyPlugins())
583         flags |= Track::ASSIGN_PLUGINS;
584     if(dlg->copyPluginCtrls())
585         flags |= Track::ASSIGN_PLUGIN_CTRLS;
586     if(dlg->allRoutes())
587         flags |= Track::ASSIGN_ROUTES;
588     if(dlg->defaultRoutes())
589         flags |= Track::ASSIGN_DEFAULT_ROUTES;
590 
591     // These three are exclusive.
592     if(dlg->duplicateParts())
593         flags |= Track::ASSIGN_DUPLICATE_PARTS;
594     else if(dlg->copyParts())
595         flags |= Track::ASSIGN_COPY_PARTS;
596     else if(dlg->cloneParts())
597         flags |= Track::ASSIGN_CLONE_PARTS;
598 
599     if(dlg->copyDrumlist())
600         flags |= Track::ASSIGN_DRUMLIST;
601 
602     delete dlg;
603 
604     int idx;
605     int trackno = tl.size();
606     TrackNameFactory names;
607     Undo operations;
608 
609     if (t) {
610         if (names.genUniqueNames(t->type(), t->name(), copies))
611         {
612             for (int cp = 0; cp < copies; ++cp)
613             {
614                 Track* new_track = t->clone(flags);
615                 if (!new_track)
616                     break;
617                 new_track->setName(names.at(cp));
618                 idx = trackno + cp;
619                 operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddTrack, idx, new_track));
620             }
621         }
622         t->setSelected(false);
623 
624     } else {
625         for(TrackList::const_reverse_iterator it = tl.crbegin(); it != tl.crend(); ++it)
626         {
627             Track* track = *it;
628             if(track->selected())
629             {
630                 if(names.genUniqueNames(track->type(), track->name(), copies))
631                 {
632                     for(int cp = 0; cp < copies; ++cp)
633                     {
634                         Track* new_track = track->clone(flags);
635                         if(!new_track)
636                             break;
637                         new_track->setName(names.at(cp));
638                         idx = trackno + cp;
639                         operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddTrack, idx, new_track));
640                     }
641                 }
642                 track->setSelected(false);
643             }
644             --trackno;
645         }
646     }
647 
648     applyOperationGroup(operations);
649 }
650 
addEventOperation(const Event & event,Part * part,bool do_port_ctrls,bool do_clone_port_ctrls)651 bool Song::addEventOperation(const Event& event, Part* part, bool do_port_ctrls, bool do_clone_port_ctrls)
652 {
653 //   Event ev(event);
654   bool added = false;
655   Part* p = part;
656   while(1)
657   {
658     // This will find the event even if it has been modified. As long as the IDs AND the position are the same, it's a match.
659     // NOTE: Multiple events with the same event base pointer or the same id number, in one event list, are FORBIDDEN.
660     //       This precludes using them for 'pattern groups' such as arpeggios or chords. Instead, create a new event type.
661     ciEvent ie = p->events().findWithId(event);
662     if(ie == p->events().cend())
663     {
664       if(pendingOperations.add(PendingOperationItem(p, event, PendingOperationItem::AddEvent)))
665       {
666         added = true;
667         // Include addition of any corresponding cached controller value.
668         // By default, here we MUST include all clones so that in the case of multiple events
669         //  at the same position the cache reader can quickly look at each part and if one
670         //  is MUTED pick an event from a different unmuted part at that position.
671         if(do_port_ctrls && (do_clone_port_ctrls || (!do_clone_port_ctrls && p == part)))
672   //         addPortCtrlEvents(ev, p, p->tick(), p->lenTick(), p->track(), pendingOperations);
673           pendingOperations.addPartPortCtrlEvents(event, p, p->tick(), p->lenTick(), p->track());
674       }
675     }
676 
677     p = p->nextClone();
678     if(p == part)
679       break;
680 
681 //     ev = event.clone(); // Makes a new copy with the same id.
682   }
683   return added;
684 }
685 
changeEventOperation(const Event & oldEvent,const Event & newEvent,Part * part,bool do_port_ctrls,bool do_clone_port_ctrls)686 Event Song::changeEventOperation(const Event& oldEvent, const Event& newEvent,
687                                 Part* part, bool do_port_ctrls, bool do_clone_port_ctrls)
688 {
689   Event p_res, res;
690   // If position is changed we need to reinsert into the list, and all clone lists.
691   Part* p = part;
692   do
693   {
694     // This will find the event even if it has been modified.
695     // As long as the IDs AND the position are the same, it's a match.
696     iEvent ie = p->nonconst_events().findWithId(oldEvent);
697     if(ie == p->nonconst_events().end())
698     {
699       // The old event was not found. Just go ahead and include the addition of the new event.
700       // Make sure the new event doesn't already exist.
701       if(p->events().findWithId(newEvent) == p->events().cend())
702       {
703         if(pendingOperations.add(PendingOperationItem(p, newEvent, PendingOperationItem::AddEvent)))
704         {
705           if(do_port_ctrls && (do_clone_port_ctrls || (!do_clone_port_ctrls && p == part)))
706             pendingOperations.addPartPortCtrlEvents(newEvent, p, p->tick(), p->lenTick(), p->track());  // Port controller values.
707         }
708       }
709     }
710     else
711     {
712       // Use the actual old found event, not the given oldEvent.
713       const Event& e = ie->second;
714       // Prefer to return the event found in the given part's event list, not a clone part's.
715       if(p == part)
716         p_res = e;
717       if(res.empty())
718         res = e;
719 
720       // Go ahead and include deletion of the old event.
721       if(pendingOperations.add(PendingOperationItem(p, ie, PendingOperationItem::DeleteEvent)))
722       {
723         // If the new and old event IDs are the same we bypass looking for the new event
724         //  because it hasn't been deleted yet and would always be found.
725         // This is safe since the event is deleted then added again.
726         // But if the new and old event IDs are not the same we MUST make sure the
727         //  new event does not already exist.
728         if((newEvent.id() == oldEvent.id() || p->events().findWithId(newEvent) == p->events().cend()) &&
729            pendingOperations.add(PendingOperationItem(p, newEvent, PendingOperationItem::AddEvent)))
730         {
731           if(do_port_ctrls && (do_clone_port_ctrls || (!do_clone_port_ctrls && p == part)))
732             pendingOperations.modifyPartPortCtrlEvents(e, newEvent, p);  // Port controller values.
733         }
734         else
735         {
736           // Adding the new event failed.
737           // Just go ahead and include removal of the old cached value.
738           if(do_port_ctrls && (do_clone_port_ctrls || (!do_clone_port_ctrls && p == part)))
739             pendingOperations.removePartPortCtrlEvents(e, p, p->track());  // Port controller values.
740         }
741       }
742     }
743 
744     p = p->nextClone();
745   }
746   while(p != part);
747 
748   // Prefer to return the event found in the given part's event list, not a clone part's.
749   if(!p_res.empty())
750     return p_res;
751 
752   return res;
753 }
754 
755 //---------------------------------------------------------
756 //   deleteEvent
757 //---------------------------------------------------------
758 
deleteEventOperation(const Event & event,Part * part,bool do_port_ctrls,bool do_clone_port_ctrls)759 Event Song::deleteEventOperation(const Event& event, Part* part, bool do_port_ctrls, bool do_clone_port_ctrls)
760 {
761   Event p_res, res;
762   Part* p = part;
763   do
764   {
765    // This will find the event even if it has been modified.
766    // As long as the IDs AND the position are the same, it's a match.
767    iEvent ie = p->nonconst_events().findWithId(event);
768    if(ie != p->nonconst_events().end())
769    {
770      const Event& e = ie->second;
771      // Prefer to return the event found in the given part's event list, not a clone part's.
772      if(p == part)
773        p_res = e;
774      if(res.empty())
775        res = e;
776 
777      // Include removal of the event.
778      if(pendingOperations.add(PendingOperationItem(p, ie, PendingOperationItem::DeleteEvent)))
779      {
780        // Include removal of any corresponding cached controller value.
781        // By using the found existing event instead of the given one, this allows
782        //  us to pre-modify an event - EXCEPT the event's time and ID - before
783        //  passing it here. We will find it by ID and delete the event.
784        // Also these following cached controller values DEPEND on finding the
785        //  ORIGINAL event and cannot find a modified event.
786        if(do_port_ctrls && (do_clone_port_ctrls || (!do_clone_port_ctrls && p == part)))
787          pendingOperations.removePartPortCtrlEvents(e, p, p->track());  // Port controller values.
788      }
789    }
790 
791     p = p->nextClone();
792   }
793   while(p != part);
794 
795   // Prefer to return the event found in the given part's event list, not a clone part's.
796   if(!p_res.empty())
797     return p_res;
798 
799   return res;
800 }
801 
802 //---------------------------------------------------------
803 //   selectEvent
804 //---------------------------------------------------------
805 
selectEvent(Event & event,Part * part,bool select)806 void Song::selectEvent(Event& event, Part* part, bool select)
807 {
808   Part* p = part;
809   do
810   {
811     iEvent ie = p->nonconst_events().findWithId(event);
812     if(ie == p->nonconst_events().end())
813     {
814       // This can be normal for some (redundant) operations.
815       if(MusEGlobal::debugMsg)
816 	fprintf(stderr, "Song::selectEvent event not found in part:%s size:%zd\n", p->name().toLatin1().constData(), p->nonconst_events().size());
817     }
818     else
819       ie->second.setSelected(select);
820     p = p->nextClone();
821   }
822   while(p != part);
823 }
824 
825 //---------------------------------------------------------
826 //   selectAllEvents
827 //---------------------------------------------------------
828 
selectAllEvents(Part * part,bool select)829 void Song::selectAllEvents(Part* part, bool select)
830 {
831   Part* p = part;
832   do
833   {
834     EventList& el = p->nonconst_events();
835     for(iEvent ie = el.begin(); ie != el.end(); ++ie)
836       ie->second.setSelected(select);
837     p = p->nextClone();
838   }
839   while(p != part);
840 }
841 
842 //---------------------------------------------------------
843 //   remapPortDrumCtrlEvents
844 //   Called when drum map anote, channel, or port is changed.
845 //---------------------------------------------------------
846 
remapPortDrumCtrlEvents(int mapidx,int newnote,int newchan,int newport)847 void Song::remapPortDrumCtrlEvents(int mapidx, int newnote, int newchan, int newport)
848 {
849   if(mapidx == -1)
850    return;
851 
852   for(ciMidiTrack it = _midis.begin(); it != _midis.end(); ++it)
853   {
854     MidiTrack* mt = *it;
855     if(mt->type() != Track::DRUM)
856       continue;
857 
858     MidiPort* trackmp = &MusEGlobal::midiPorts[mt->outPort()];
859     const PartList* pl = mt->cparts();
860     for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)
861     {
862       MidiPart* part = (MidiPart*)(ip->second);
863       const EventList& el = part->events();
864       for(ciEvent ie = el.begin(); ie != el.end(); ++ie)
865       {
866         const Event& ev = ie->second;
867         if(ev.type() != Controller)
868           continue;
869 
870         int cntrl = ev.dataA();
871         int val = ev.dataB();
872 
873         // Is it a drum controller event, according to the track port's instrument?
874         MidiController* mc = trackmp->drumController(cntrl);
875         if(!mc)
876           continue;
877 
878         int note = cntrl & 0x7f;
879         // Does the index match?
880         if(note == mapidx)
881         {
882           int tick = ev.tick() + part->tick();
883 
884           if(mt->type() == Track::DRUM)
885           {
886             // Default to track port if -1 and track channel if -1.
887             int ch = mt->drummap()[note].channel;
888             if(ch == -1)
889               ch = mt->outChannel();
890             int port = mt->drummap()[note].port;
891             if(port == -1)
892               port = mt->outPort();
893             MidiPort* mp = &MusEGlobal::midiPorts[port];
894             cntrl = (cntrl & ~0xff) | mt->drummap()[note].anote;
895             // Remove the port controller value.
896             mp->deleteController(ch, tick, cntrl, val, part);
897 
898 
899             // FIXME FIXME CHECK THIS
900             //
901             //  Why wasn't 'ch' given its own 'ch_add' variable?
902             //  Why wasn't 'mp' given its own 'mp_add' variable?
903             //  That means the channel and port will default to the ones
904             //   being erased above, not the track's. That can't be right !
905             //  Checked callers: Looks OK for this routine only.
906             //  If newnote, newchan, or newport are -1 it means
907             //   "don't touch, use the original". IOW it means we only
908             //   want to change what is not -1.
909 
910 
911             if(newnote != -1 && newnote != mt->drummap()[note].anote)
912               cntrl = (cntrl & ~0xff) | newnote;
913             if(newchan != -1 && newchan != ch)
914               ch = newchan;
915             if(newport != -1 && newport != port)
916               port = newport;
917             mp = &MusEGlobal::midiPorts[port];
918             // Add the port controller value.
919             mp->setControllerVal(ch, tick, cntrl, val, part);
920           }
921         }
922       }
923     }
924   }
925 }
926 
927 //---------------------------------------------------------
928 //   changeMidiCtrlCacheEvents
929 //---------------------------------------------------------
930 
changeMidiCtrlCacheEvents(bool add,bool drum_tracks,bool midi_tracks,bool drum_ctls,bool non_drum_ctls)931 void Song::changeMidiCtrlCacheEvents(
932   bool add, bool drum_tracks, bool midi_tracks, bool drum_ctls, bool non_drum_ctls)
933 {
934   if(!drum_tracks && !midi_tracks)
935     return;
936 
937   for(ciMidiTrack it = _midis.begin(); it != _midis.end(); ++it)
938   {
939     MidiTrack* mt = *it;
940     if((mt->type() == Track::DRUM && drum_tracks) || ((mt->type() == Track::MIDI && midi_tracks)))
941     {
942       if(add)
943         addPortCtrlEvents(mt, drum_ctls, non_drum_ctls);
944       else
945         removePortCtrlEvents(mt, drum_ctls, non_drum_ctls);
946     }
947   }
948 }
949 
950 //---------------------------------------------------------
951 //   cmdAddRecordedEvents
952 //    add recorded Events into part
953 //---------------------------------------------------------
954 
cmdAddRecordedEvents(MidiTrack * mt,const EventList & events,unsigned startTick,Undo & operations)955 void Song::cmdAddRecordedEvents(MidiTrack* mt, const EventList& events, unsigned startTick, Undo& operations)
956       {
957       if (events.empty()) {
958             if (MusEGlobal::debugMsg)
959                   fprintf(stderr, "no events recorded\n");
960             return;
961             }
962       ciEvent s;
963       ciEvent e;
964       unsigned endTick;
965 
966       if((MusEGlobal::audio->loopCount() > 0 && startTick > lPos().tick()) || (punchin() && startTick < lPos().tick()))
967       {
968             startTick = lpos();
969             s = events.lower_bound(startTick);
970       }
971       else
972       {
973             s = events.begin();
974       }
975 
976       // search for last noteOff:
977       endTick = 0;
978       for (ciEvent i = events.begin(); i != events.end(); ++i) {
979             Event ev   = i->second;
980             unsigned l = ev.endTick();
981             if (l > endTick)
982                   endTick = l;
983             }
984 
985       if((MusEGlobal::audio->loopCount() > 0) || (punchout() && endTick > rPos().tick()) )
986       {
987             endTick = rpos();
988             e = events.lower_bound(endTick);
989       }
990       else
991             e = events.end();
992 
993       if (startTick > endTick) {
994             if (MusEGlobal::debugMsg)
995                   fprintf(stderr, "no events in record area\n");
996             return;
997             }
998 
999       //---------------------------------------------------
1000       //    if startTick points into a part,
1001       //          record to that part
1002       //    else
1003       //          create new part
1004       //---------------------------------------------------
1005 
1006       PartList* pl = mt->parts();
1007       const MidiPart* part = 0;
1008       iPart ip;
1009       for (ip = pl->begin(); ip != pl->end(); ++ip) {
1010             part = (MidiPart*)(ip->second);
1011             unsigned partStart = part->tick();
1012             unsigned partEnd   = part->endTick();
1013             if (startTick >= partStart && startTick < partEnd)
1014                   break;
1015             }
1016       if (ip == pl->end()) {
1017             if (MusEGlobal::debugMsg)
1018                   fprintf(stderr, "create new part for recorded events\n");
1019             // create new part
1020             MidiPart* newpart;
1021             newpart      = new MidiPart(mt);
1022 
1023             // Round the start down using the Arranger part snap raster value.
1024             startTick = MusEGlobal::sigmap.raster1(startTick, MusEGlobal::muse->arrangerRaster());
1025             // Round the end up using the Arranger part snap raster value.
1026             endTick   = MusEGlobal::sigmap.raster2(endTick, MusEGlobal::muse->arrangerRaster());
1027 
1028             newpart->setTick(startTick);
1029             newpart->setLenTick(endTick - startTick);
1030             newpart->setName(mt->name());
1031             newpart->setColorIndex(MusEGlobal::muse->currentPartColorIndex());
1032 
1033             // copy events
1034             for (ciEvent i = s; i != e; ++i) {
1035                   const Event& old = i->second;
1036                   Event event = old.clone();
1037                   event.setTick(old.tick() - startTick);
1038                   // addEvent also adds port controller values. So does msgAddPart, below. Let msgAddPart handle them.
1039                   //addEvent(event, part);
1040                   if(newpart->events().find(event) == newpart->events().end())
1041                     newpart->addEvent(event);
1042                   }
1043             operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddPart, newpart));
1044             return;
1045             }
1046 
1047       unsigned partTick = part->tick();
1048       if (endTick > part->endTick()) {
1049             // Determine new part length...
1050             endTick = 0;
1051             for (ciEvent i = s; i != e; ++i) {
1052                   const Event& event = i->second;
1053                   unsigned tick = event.tick() - partTick + event.lenTick();
1054                   if (endTick < tick)
1055                         endTick = tick;
1056                   }
1057 
1058             // Round the end up (again) using the Arranger part snap raster value.
1059             endTick   = MusEGlobal::sigmap.raster2(endTick, MusEGlobal::muse->arrangerRaster());
1060 
1061             operations.push_back(UndoOp(UndoOp::ModifyPartLength, part, part->lenValue(), endTick, 0, Pos::TICKS));
1062       }
1063 
1064 
1065       if (_recMode == REC_REPLACE) {
1066             ciEvent si = part->events().lower_bound(startTick - part->tick());
1067             ciEvent ei = part->events().lower_bound(endTick   - part->tick());
1068 
1069             for (ciEvent i = si; i != ei; ++i) {
1070                   const Event& event = i->second;
1071                   // Indicate that controller values and clone parts were handled.
1072                   operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, true, true));
1073             }
1074       }
1075       for (ciEvent i = s; i != e; ++i) {
1076             Event event = i->second.clone();
1077             event.setTick(event.tick() - partTick);
1078             // Indicate that controller values and clone parts were handled.
1079             operations.push_back(UndoOp(UndoOp::AddEvent, event, part, true, true));
1080       }
1081 }
1082 
1083 //---------------------------------------------------------
1084 //   cmdAddRecordedWave
1085 //---------------------------------------------------------
1086 
cmdAddRecordedWave(MusECore::WaveTrack * track,MusECore::Pos s,MusECore::Pos e,Undo & operations)1087 void Song::cmdAddRecordedWave(MusECore::WaveTrack* track, MusECore::Pos s, MusECore::Pos e, Undo& operations)
1088       {
1089       if (MusEGlobal::debugMsg)
1090       {
1091           INFO_WAVE(stderr, "cmdAddRecordedWave - loopCount = %d, punchin = %d",
1092                     MusEGlobal::audio->loopCount(), punchin());
1093       }
1094 
1095       // Driver should now be in transport 'stop' mode and no longer pummping the recording wave fifo,
1096       //  but the fifo may not be empty yet, it's in the prefetch thread.
1097       // Wait a few seconds for the fifo to be empty, until it has been fully transferred to the
1098       //  track's recFile sndfile, which is done via Audio::process() sending periodic 'tick' messages
1099       //  to the prefetch thread to write its fifo to the sndfile, always UNLESS in stop or idle mode.
1100       // It now sends one final tick message at stop, so we /should/ have all our buffers available here.
1101       // This GUI thread is notified of the stop condition via the audio thread sending a message
1102       //  as soon as the state change is read from the driver.
1103       // NOTE: The fifo scheme is used only if NOT in transport freewheel mode where the data is directly
1104       //  written to the sndfile and therefore stops immediately when the transport stops and thus is
1105       //  safe to read here regardless of waiting.
1106       int tout = 100; // Ten seconds. Otherwise we gotta move on.
1107       while(track->recordFifoCount() != 0)
1108       {
1109         usleep(100000);
1110         --tout;
1111         if(tout == 0)
1112         {
1113           ERROR_WAVE(stderr, "Song::cmdAddRecordedWave: Error: Timeout waiting for _tempoFifo to empty! Count:%d\n",
1114                      track->prefetchFifo()->getCount());
1115           break;
1116         }
1117       }
1118 
1119       // It should now be safe to work with the resultant sndfile here in the GUI thread.
1120       // No other thread should be touching it right now.
1121       MusECore::SndFileR f = track->recFile();
1122       if (f.isNull()) {
1123             ERROR_WAVE(stderr, "cmdAddRecordedWave: no snd file for track <%s>\n",
1124                track->name().toLocal8Bit().constData());
1125             return;
1126             }
1127 
1128       // If externally clocking (and therefore master was forced off),
1129       //  tempos may have been recorded. We really should temporarily force
1130       //  the master tempo map on in order to properly determine the ticks below.
1131       // Else internal clocking, the user decided to record either with or without
1132       //  master on, so let it be.
1133       // FIXME: We really should allow the master flag to be on at the same time as
1134       //  the external sync flag! AFAIR when external sync is on, no part of the app shall
1135       //  depend on the tempo map anyway, so it should not matter whether it's on or off.
1136       // If we do that, then we may be able to remove this section and user simply decides
1137       //  whether master is on/off, because we may be able to use the flag to determine
1138       //  whether to record external tempos at all, because we may want a switch for it!
1139       bool master_was_on = MusEGlobal::tempomap.masterFlag();
1140       if(MusEGlobal::extSyncFlag && !master_was_on)
1141         MusEGlobal::tempomap.setMasterFlag(0, true);
1142 
1143       if((MusEGlobal::audio->loopCount() > 0 && s.tick() > lPos().tick()) || (punchin() && s.tick() < lPos().tick()))
1144         s.setTick(lPos().tick());
1145       // If we are looping, just set the end to the right marker, since we don't know how many loops have occurred.
1146       // (Fixed: Added Audio::loopCount)
1147       // Otherwise if punchout is on, limit the end to the right marker.
1148       if((MusEGlobal::audio->loopCount() > 0) || (punchout() && e.tick() > rPos().tick()) )
1149         e.setTick(rPos().tick());
1150 
1151       // No part to be created? Delete the rec sound file.
1152       if(s.frame() >= e.frame())
1153       {
1154         QString st = f->path();
1155         // The function which calls this function already does this immediately after. But do it here anyway.
1156         track->setRecFile(NULL); // upon "return", f is removed from the stack, the WaveTrack::_recFile's
1157                                  // counter has dropped by 2 and _recFile will probably deleted then
1158         remove(st.toLocal8Bit().constData());
1159         if(MusEGlobal::debugMsg)
1160         {
1161           INFO_WAVE(stderr, "Song::cmdAddRecordedWave: remove file %s - startframe=%d endframe=%d\n",
1162                     st.toLocal8Bit().constData(), s.frame(), e.frame());
1163         }
1164 
1165         // Restore master flag.
1166         if(MusEGlobal::extSyncFlag && !master_was_on)
1167           MusEGlobal::tempomap.setMasterFlag(0, false);
1168 
1169         return;
1170       }
1171 // REMOVE Tim. Wave. Removed. Probably I should never have done this. It's more annoying than helpful. Look at it another way: Importing a wave DOES NOT do this.
1172 //       // Round the start down using the Arranger part snap raster value.
1173 //       int a_rast = MusEGlobal::song->arrangerRaster();
1174 //       unsigned sframe = (a_rast == 1) ? s.frame() : Pos(MusEGlobal::sigmap.raster1(s.tick(), MusEGlobal::song->arrangerRaster())).frame();
1175 //       // Round the end up using the Arranger part snap raster value.
1176 //       unsigned eframe = (a_rast == 1) ? e.frame() : Pos(MusEGlobal::sigmap.raster2(e.tick(), MusEGlobal::song->arrangerRaster())).frame();
1177 // //       unsigned etick = Pos(eframe, false).tick();
1178       unsigned sframe = s.frame();
1179       unsigned eframe = e.frame();
1180 
1181       // Done using master tempo map. Restore master flag.
1182       if(MusEGlobal::extSyncFlag && !master_was_on)
1183         MusEGlobal::tempomap.setMasterFlag(0, false);
1184 
1185       f->update();
1186 
1187       MusECore::WavePart* part = new MusECore::WavePart(track);
1188       part->setFrame(sframe);
1189       part->setLenFrame(eframe - sframe);
1190       part->setName(track->name());
1191       part->setColorIndex(MusEGlobal::muse->currentPartColorIndex());
1192 
1193       // create Event
1194       MusECore::Event event(MusECore::Wave);
1195       event.setSndFile(f);
1196       // We are done with the _recFile member. Set to zero.
1197       track->setRecFile(0);
1198 
1199       event.setSpos(0);
1200       // Since the part start was snapped down, we must apply the difference so that the
1201       //  wave event tick lines up with when the user actually started recording.
1202       event.setFrame(s.frame() - sframe);
1203       // NO Can't use this. SF reports too long samples at first part recorded in sequence. See samples() - funny business with SEEK ?
1204       //event.setLenFrame(f.samples());
1205       event.setLenFrame(e.frame() - s.frame());
1206       part->addEvent(event);
1207 
1208       operations.push_back(UndoOp(UndoOp::AddPart, part));
1209       }
1210 
1211 //---------------------------------------------------------
1212 //   cmdChangeWave
1213 //   called from GUI context
1214 //---------------------------------------------------------
1215 
cmdChangeWave(const Event & original,const QString & tmpfile,unsigned sx,unsigned ex)1216 void Song::cmdChangeWave(const Event& original, const QString& tmpfile, unsigned sx, unsigned ex)
1217       {
1218       addUndo(UndoOp(UndoOp::ModifyClip,original,tmpfile,sx,ex));
1219       temporaryWavFiles.push_back(tmpfile);
1220       }
1221 
1222 //---------------------------------------------------------
1223 //   findTrack
1224 //---------------------------------------------------------
1225 
findTrack(const Part * part) const1226 Track* Song::findTrack(const Part* part) const
1227       {
1228       for (ciTrack t = _tracks.begin(); t != _tracks.end(); ++t) {
1229             Track* track = *t;
1230             if (track == 0)
1231                   continue;
1232             PartList* pl = track->parts();
1233             for (iPart p = pl->begin(); p != pl->end(); ++p) {
1234                   if (part == p->second)
1235                         return track;
1236                   }
1237             }
1238       return 0;
1239       }
1240 
1241 //---------------------------------------------------------
1242 //   findTrack
1243 //    find track by name
1244 //---------------------------------------------------------
1245 
findTrack(const QString & name) const1246 Track* Song::findTrack(const QString& name) const
1247       {
1248       for (ciTrack i = _tracks.begin(); i != _tracks.end(); ++i) {
1249             if ((*i)->name() == name)
1250                   return *i;
1251             }
1252       return 0;
1253       }
1254 
1255 //---------------------------------------------------------
1256 //   setLoop
1257 //    set transport loop flag
1258 //---------------------------------------------------------
1259 
setLoop(bool f)1260 void Song::setLoop(bool f)
1261       {
1262       if (loopFlag != f) {
1263             loopFlag = f;
1264             MusEGlobal::loopAction->setChecked(loopFlag);
1265             emit loopChanged(loopFlag);
1266             }
1267       }
1268 
1269 //---------------------------------------------------------
1270 //   clearTrackRec
1271 //---------------------------------------------------------
clearTrackRec()1272 void Song::clearTrackRec()
1273 {
1274   // This is a minor operation easily manually undoable. Let's not clog the undo list with it.
1275   MusECore::PendingOperationList operations;
1276   for(iTrack it = tracks()->begin(); it != tracks()->end(); ++it)
1277   {
1278     if(!(*it)->setRecordFlag1(false))
1279     {
1280       //continue;
1281     }
1282     operations.add(MusECore::PendingOperationItem((*it), false, MusECore::PendingOperationItem::SetTrackRecord));
1283   }
1284   MusEGlobal::audio->msgExecutePendingOperations(operations, true);
1285 }
1286 
1287 //---------------------------------------------------------
1288 //   setRecord
1289 //---------------------------------------------------------
setRecord(bool f,bool autoRecEnable)1290 void Song::setRecord(bool f, bool autoRecEnable)
1291       {
1292       if(MusEGlobal::debugMsg)
1293         fprintf(stderr, "setRecord recordflag =%d f(record state)=%d autoRecEnable=%d\n", recordFlag, f, autoRecEnable);
1294 
1295       if (f && MusEGlobal::config.useProjectSaveDialog && MusEGlobal::museProject == MusEGlobal::museProjectInitPath ) { // check that there is a project stored before commencing
1296         // no project, we need to create one.
1297         if (!MusEGlobal::muse->saveAs()) {
1298             MusEGlobal::recordAction->setChecked(false);
1299             return; // could not store project, won't enable record
1300         }
1301       }
1302 
1303       if (recordFlag != f) {
1304             if (f && autoRecEnable) {
1305                 bool alreadyRecEnabled = false;
1306                 TrackList selectedTracks;
1307                 // loop through list and check if any track is rec enabled
1308                 // if not then rec enable the selected track
1309                 MusECore::WaveTrackList* wtl = waves();
1310                 for (MusECore::iWaveTrack i = wtl->begin(); i != wtl->end(); ++i) {
1311                       if((*i)->recordFlag())
1312                           {
1313                           alreadyRecEnabled = true;
1314                           break;
1315                           }
1316                       if((*i)->selected())
1317                           selectedTracks.push_back(*i);
1318                       }
1319                 if (!alreadyRecEnabled) {
1320                       MidiTrackList* mtl = midis();
1321                       for (iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) {
1322                             if((*it)->recordFlag())
1323                                 {
1324                                 alreadyRecEnabled = true;
1325                                 break;
1326                                 }
1327                             if((*it)->selected())
1328                                 selectedTracks.push_back(*it);
1329                             }
1330                       }
1331                 if (!alreadyRecEnabled && !selectedTracks.empty()) {
1332                       // This is a minor operation easily manually undoable. Let's not clog the undo list with it.
1333                       MusECore::PendingOperationList operations;
1334                       foreach (Track *t, selectedTracks)
1335                       {
1336                         if(!t->setRecordFlag1(true))
1337                           continue;
1338                         operations.add(MusECore::PendingOperationItem(t, true, MusECore::PendingOperationItem::SetTrackRecord));
1339                       }
1340                       MusEGlobal::audio->msgExecutePendingOperations(operations, true);
1341 
1342                       }
1343                 else if (alreadyRecEnabled)  {
1344                       // do nothing
1345                       }
1346                 else  {
1347                     // if there no tracks or no track is selected, warn the user and don't enable record
1348                     if (selectedTracks.empty()) {
1349                         QMessageBox::warning(nullptr, "MusE", tr("Record: At least one track must be armed for recording first."));
1350                         f = false;
1351                     }
1352 //                      // if there are no tracks, do not enable record
1353 //                      if (waves()->empty() && midis()->empty()) {
1354 //                            fprintf(stderr, "No track to select, won't enable record\n");
1355 //                            f = false;
1356 //                            }
1357                 }
1358                 // prepare recording of wave files for all record enabled wave tracks
1359                 for (MusECore::iWaveTrack i = wtl->begin(); i != wtl->end(); ++i) {
1360                       if((*i)->recordFlag()) // || (selectedTracks.find(*i)!=wtl->end() && autoRecEnable)) // prepare if record flag or if it is set to recenable
1361                       {                                                                  // setRecordFlag may take too long time to complete
1362                                                                                          // so we try this case specifically
1363                         (*i)->prepareRecording();
1364                       }
1365                 }
1366 
1367 // DELETETHIS? 14
1368 #if 0
1369                   // check for midi devices suitable for recording
1370                   bool portFound = false;
1371                   for (int i = 0; i < MIDI_PORTS; ++i) {
1372                         MidiDevice* dev = MusEGlobal::midiPorts[i].device();
1373                         if (dev && (dev->rwFlags() & 0x2))
1374                               portFound = true;
1375                         }
1376                   if (!portFound) {
1377                         QMessageBox::critical(qApp->mainWidget(), "MusE: Record",
1378                            "There are no midi devices configured for recording");
1379                         f = false;
1380                         }
1381 #endif
1382             }
1383             else {
1384                   bounceTrack = 0;
1385             }
1386 
1387             if (MusEGlobal::audio->isPlaying() && f)
1388                   f = false;
1389             recordFlag = f;
1390             MusEGlobal::recordAction->setChecked(recordFlag);
1391             emit recordChanged(recordFlag);
1392             }
1393       }
1394 
1395 //---------------------------------------------------------
1396 //   setPunchin
1397 //    set punchin flag
1398 //---------------------------------------------------------
1399 
setPunchin(bool f)1400 void Song::setPunchin(bool f)
1401       {
1402       if (punchinFlag != f) {
1403             punchinFlag = f;
1404             MusEGlobal::punchinAction->setChecked(punchinFlag);
1405             emit punchinChanged(punchinFlag);
1406             }
1407       }
1408 
1409 //---------------------------------------------------------
1410 //   setPunchout
1411 //    set punchout flag
1412 //---------------------------------------------------------
1413 
setPunchout(bool f)1414 void Song::setPunchout(bool f)
1415       {
1416       if (punchoutFlag != f) {
1417             punchoutFlag = f;
1418             MusEGlobal::punchoutAction->setChecked(punchoutFlag);
1419             emit punchoutChanged(punchoutFlag);
1420             }
1421       }
1422 
1423 //---------------------------------------------------------
1424 //   setClick
1425 //---------------------------------------------------------
1426 
setClick(bool val)1427 void Song::setClick(bool val)
1428       {
1429       if (_click != val) {
1430             _click = val;
1431             emit clickChanged(_click);
1432             }
1433       }
1434 
1435 //---------------------------------------------------------
1436 //   setQuantize
1437 //---------------------------------------------------------
1438 
setQuantize(bool val)1439 void Song::setQuantize(bool val)
1440       {
1441       if (_quantize != val) {
1442             _quantize = val;
1443             emit quantizeChanged(_quantize);
1444             }
1445       }
1446 
1447 //---------------------------------------------------------
1448 //   setMasterFlag
1449 //---------------------------------------------------------
1450 
setMasterFlag(bool val)1451 void Song::setMasterFlag(bool val)
1452     {
1453       // Here we have a choice of whether to allow undoing of setting the master.
1454       // TODO: Add a separate config flag just for this ?
1455       //if(MusEGlobal::config.selectionsUndoable)
1456       //  MusEGlobal::song->applyOperation(UndoOp(UndoOp::EnableMasterTrack, val, 0), MusECore::Song::OperationUndoMode);
1457       //else
1458         MusEGlobal::song->applyOperation(UndoOp(UndoOp::EnableMasterTrack, val, 0), MusECore::Song::OperationExecuteUpdate);
1459     }
1460 
1461 //---------------------------------------------------------
1462 //   setPlay
1463 //    set transport play flag
1464 //---------------------------------------------------------
1465 
setPlay(bool f)1466 void Song::setPlay(bool f)
1467 {
1468       if (MusEGlobal::extSyncFlag) {
1469           if (MusEGlobal::debugMsg)
1470             fprintf(stderr, "not allowed while using external sync");
1471           return;
1472       }
1473 
1474       // only allow the user to set the button "on"
1475       if (!f)
1476             MusEGlobal::playAction->setChecked(true);
1477       else {
1478             // keep old transport position for rewinding
1479             // position if "Rewind on Stop" option is enabled
1480             _startPlayPosition = MusEGlobal::audio->pos();
1481 
1482             MusEGlobal::audio->msgPlay(true);
1483       }
1484 }
1485 
setStop(bool f)1486 void Song::setStop(bool f)
1487 {
1488       if (MusEGlobal::extSyncFlag) {
1489           if (MusEGlobal::debugMsg)
1490             fprintf(stderr, "not allowed while using external sync");
1491           return;
1492       }
1493       // only allow the user to set the button "on"
1494       if (!f)
1495             MusEGlobal::stopAction->setChecked(true);
1496       else {
1497             MusEGlobal::audio->msgPlay(false);
1498       }
1499 }
1500 
setStopPlay(bool f)1501 void Song::setStopPlay(bool f)
1502       {
1503       MusEGlobal::playAction->blockSignals(true);
1504       MusEGlobal::stopAction->blockSignals(true);
1505 
1506       emit playChanged(f);   // signal transport window
1507 
1508       MusEGlobal::playAction->setChecked(f);
1509       MusEGlobal::stopAction->setChecked(!f);
1510 
1511       MusEGlobal::stopAction->blockSignals(false);
1512       MusEGlobal::playAction->blockSignals(false);
1513       }
1514 
1515 //---------------------------------------------------------
1516 //   seekTo
1517 //   setPos slot, only active when not doing playback
1518 //---------------------------------------------------------
seekTo(int tick)1519 void Song::seekTo(int tick)
1520 {
1521   if (!MusEGlobal::audio->isPlaying()) {
1522     Pos p(tick, true);
1523     setPos(CPOS, p);
1524   }
1525 }
1526 //---------------------------------------------------------
1527 //   setPos
1528 //   MusEGlobal::song->setPos(Song::CPOS, pos, true, true, true);
1529 //---------------------------------------------------------
1530 
setPos(POSTYPE posType,const Pos & val,bool sig,bool isSeek,bool adjustScrollbar,bool)1531 void Song::setPos(POSTYPE posType, const Pos& val, bool sig,
1532    bool isSeek, bool adjustScrollbar, bool /*force*/)
1533       {
1534       if (MusEGlobal::heavyDebugMsg)
1535       {
1536         fprintf(stderr, "setPos %d sig=%d,seek=%d,scroll=%d  ",
1537            posType, sig, isSeek, adjustScrollbar);
1538         val.dump(0);
1539         fprintf(stderr, "\n");
1540         fprintf(stderr, "Song::setPos before MusEGlobal::audio->msgSeek posType:%d isSeek:%d frame:%d\n", posType, isSeek, val.frame());
1541       }
1542 
1543       if (posType == CPOS) {
1544             _vcpos = val;
1545             if (isSeek && !MusEGlobal::extSyncFlag) {
1546                   if (val == MusEGlobal::audio->pos())
1547                   {
1548                       if (MusEGlobal::heavyDebugMsg) fprintf(stderr,
1549                         "Song::setPos seek MusEGlobal::audio->pos already == val tick:%d frame:%d\n", val.tick(), val.frame());
1550                       return;
1551                   }
1552                   MusEGlobal::audio->msgSeek(val);
1553                   if (MusEGlobal::heavyDebugMsg) fprintf(stderr,
1554                     "Song::setPos after MusEGlobal::audio->msgSeek posTYpe:%d isSeek:%d frame:%d\n", posType, isSeek, val.frame());
1555                   return;
1556                   }
1557             }
1558       if (val == pos[posType])
1559       {
1560            if (MusEGlobal::heavyDebugMsg) fprintf(stderr,
1561              "Song::setPos MusEGlobal::song->pos already == val tick:%d frame:%d\n", val.tick(), val.frame());
1562            return;
1563       }
1564       pos[posType] = val;
1565       bool swap = pos[LPOS] > pos[RPOS];
1566       if (swap) {        // swap lpos/rpos if lpos > rpos
1567             Pos tmp   = pos[LPOS];
1568             pos[LPOS] = pos[RPOS];
1569             pos[RPOS] = tmp;
1570             }
1571       if (sig) {
1572             if (swap) {
1573                   emit posChanged(LPOS, pos[LPOS].tick(), adjustScrollbar);
1574                   emit posChanged(RPOS, pos[RPOS].tick(), adjustScrollbar);
1575                   if (posType != LPOS && posType != RPOS)
1576                         emit posChanged(posType, pos[posType].tick(), adjustScrollbar);
1577                   }
1578             else
1579                   emit posChanged(posType, pos[posType].tick(), adjustScrollbar);
1580             }
1581 
1582       if(posType == CPOS)
1583       {
1584         const unsigned int vframe = val.frame();
1585         iMarker i1 = _markerList->begin();
1586         bool currentChanged = false;
1587         for(; i1 != _markerList->end(); ++i1)
1588         {
1589               const unsigned fr = i1->second.frame();
1590               // If there are multiple items at this frame and any one of them is current,
1591               //  leave it alone. It's arbitrary which one would be selected and it would
1592               //  normally choose the first one, but we'll let it stick with the one that's current,
1593               //  to avoid jumping around in the marker view window.
1594               iMarker i2 = i1;
1595               while(i2 != _markerList->end() && i2->second.frame() == fr)
1596               {
1597                 i1 = i2;
1598                 ++i2;
1599               }
1600 
1601               if(vframe >= fr && (i2==_markerList->end() || vframe < i2->second.frame()))
1602               {
1603                 if(i1->second.current())
1604                   return;
1605 
1606                 i1->second.setCurrent(true);
1607 
1608                 if(currentChanged)
1609                 {
1610                   emit markerChanged(MARKER_CUR);
1611                   return;
1612                 }
1613                 for(; i2 != _markerList->end(); ++i2)
1614                 {
1615                   if(i2->second.current())
1616                     i2->second.setCurrent(false);
1617                 }
1618                 emit markerChanged(MARKER_CUR);
1619                 return;
1620               }
1621               else
1622               {
1623                 if(i1->second.current())
1624                 {
1625                   currentChanged = true;
1626                   i1->second.setCurrent(false);
1627                 }
1628               }
1629         }
1630         if(currentChanged)
1631               emit markerChanged(MARKER_CUR);
1632       }
1633       }
1634 
1635 //---------------------------------------------------------
1636 //   forward
1637 //---------------------------------------------------------
1638 
forward()1639 void Song::forward()
1640       {
1641       unsigned newPos = pos[0].tick() + MusEGlobal::config.division;
1642       MusEGlobal::audio->msgSeek(Pos(newPos, true));
1643       }
1644 
1645 //---------------------------------------------------------
1646 //   rewind
1647 //---------------------------------------------------------
1648 
rewind()1649 void Song::rewind()
1650       {
1651       unsigned newPos;
1652       if (unsigned(MusEGlobal::config.division) > pos[0].tick())
1653             newPos = 0;
1654       else
1655             newPos = pos[0].tick() - MusEGlobal::config.division;
1656       MusEGlobal::audio->msgSeek(Pos(newPos, true));
1657       }
1658 
1659 //---------------------------------------------------------
1660 //   rewindStart
1661 //---------------------------------------------------------
1662 
rewindStart()1663 void Song::rewindStart()
1664       {
1665       MusEGlobal::audio->msgSeek(Pos(0, true));
1666       }
1667 
1668 //---------------------------------------------------------
1669 //   update
1670 //---------------------------------------------------------
1671 
update(MusECore::SongChangedStruct_t flags,bool allowRecursion)1672 void Song::update(MusECore::SongChangedStruct_t flags, bool allowRecursion)
1673       {
1674       static int level = 0;         // DEBUG
1675       if (level && !allowRecursion) {
1676             fprintf(stderr, "THIS SHOULD NEVER HAPPEN: unallowed recursion in Song::update(%08lx %08lx), level %d!\n"
1677                    "                          the songChanged() signal is NOT emitted. this will\n"
1678                    "                          probably cause windows being not up-to-date.\n", flags.flagsHi(), flags.flagsLo(), level);
1679             return;
1680             }
1681       ++level;
1682       emit songChanged(flags);
1683       --level;
1684       }
1685 
1686 //---------------------------------------------------------
1687 //   updatePos
1688 //---------------------------------------------------------
1689 
updatePos()1690 void Song::updatePos()
1691       {
1692       emit posChanged(0, pos[0].tick(), false);
1693       emit posChanged(1, pos[1].tick(), false);
1694       emit posChanged(2, pos[2].tick(), false);
1695       }
1696 
1697 //---------------------------------------------------------
1698 //   len
1699 //---------------------------------------------------------
1700 
initLen()1701 void Song::initLen()
1702       {
1703       _len = MusEGlobal::sigmap.bar2tick(40, 0, 0);    // default song len
1704       for (iTrack t = _tracks.begin(); t != _tracks.end(); ++t) {
1705             Track* track = dynamic_cast<Track*>(*t);
1706             if (track == 0)
1707                   continue;
1708             PartList* parts = track->parts();
1709             for (iPart p = parts->begin(); p != parts->end(); ++p) {
1710                   unsigned last = p->second->tick() + p->second->lenTick();
1711                   if (last > _len)
1712                         _len = last;
1713                   }
1714             }
1715       _len = roundUpBar(_len);
1716       }
1717 
1718 //---------------------------------------------------------
1719 //   roundUpBar
1720 //---------------------------------------------------------
1721 
roundUpBar(int t) const1722 int Song::roundUpBar(int t) const
1723       {
1724       int bar, beat;
1725       unsigned tick;
1726       MusEGlobal::sigmap.tickValues(t, &bar, &beat, &tick);
1727       if (beat || tick)
1728             return MusEGlobal::sigmap.bar2tick(bar+1, 0, 0);
1729       return t;
1730       }
1731 
1732 //---------------------------------------------------------
1733 //   roundUpBeat
1734 //---------------------------------------------------------
1735 
roundUpBeat(int t) const1736 int Song::roundUpBeat(int t) const
1737       {
1738       int bar, beat;
1739       unsigned tick;
1740       MusEGlobal::sigmap.tickValues(t, &bar, &beat, &tick);
1741       if (tick)
1742             return MusEGlobal::sigmap.bar2tick(bar, beat+1, 0);
1743       return t;
1744       }
1745 
1746 //---------------------------------------------------------
1747 //   roundDownBar
1748 //---------------------------------------------------------
1749 
roundDownBar(int t) const1750 int Song::roundDownBar(int t) const
1751       {
1752       int bar, beat;
1753       unsigned tick;
1754       MusEGlobal::sigmap.tickValues(t, &bar, &beat, &tick);
1755       return MusEGlobal::sigmap.bar2tick(bar, 0, 0);
1756       }
1757 
1758 //---------------------------------------------------------
1759 //   dumpMaster
1760 //---------------------------------------------------------
1761 
dumpMaster()1762 void Song::dumpMaster()
1763       {
1764       MusEGlobal::tempomap.dump();
1765       MusEGlobal::sigmap.dump();
1766       }
1767 
1768 
normalizePart(MusECore::Part * part)1769 void Song::normalizePart(MusECore::Part *part)
1770 {
1771    const MusECore::EventList& evs = part->events();
1772    for(MusECore::ciEvent it = evs.begin(); it != evs.end(); ++it)
1773    {
1774       const Event& ev = (*it).second;
1775       if(ev.empty())
1776         continue;
1777       MusECore::SndFileR file = ev.sndFile();
1778       if(file.isNull())
1779         continue;
1780 
1781       QString tmpWavFile;
1782       if (!MusEGlobal::getUniqueTmpfileName("tmp_musewav",".wav", tmpWavFile))
1783       {
1784          return;
1785       }
1786 
1787       MusEGlobal::audio->msgIdle(true); // Not good with playback during operations
1788 
1789       MusECore::SndFile tmpFile(tmpWavFile);
1790       unsigned int file_channels = file.channels();
1791       tmpFile.setFormat(file.format(), file_channels, file.samplerate());
1792       if (tmpFile.openWrite())
1793       {
1794          MusEGlobal::audio->msgIdle(false);
1795          fprintf(stderr, "Could not open temporary file...\n");
1796          return;
1797       }
1798       float*   tmpdata[file_channels];
1799       unsigned tmpdatalen = file.samples();
1800       for (unsigned i=0; i<file_channels; i++)
1801       {
1802          tmpdata[i] = new float[tmpdatalen];
1803       }
1804       file.seek(0, 0);
1805       file.readWithHeap(file_channels, tmpdata, tmpdatalen);
1806       file.close();
1807       tmpFile.write(file_channels, tmpdata, tmpdatalen, MusEGlobal::config.liveWaveUpdate);
1808       tmpFile.close();
1809 
1810       float loudest = 0.0;
1811       for (unsigned i=0; i<file_channels; i++)
1812       {
1813          for (unsigned j=0; j<tmpdatalen; j++)
1814          {
1815             if (tmpdata[i][j]  > loudest)
1816             {
1817                loudest = tmpdata[i][j];
1818             }
1819          }
1820       }
1821 
1822       double scale = 0.99 / (double)loudest;
1823       for (unsigned i=0; i<file_channels; i++)
1824       {
1825          for (unsigned j=0; j<tmpdatalen; j++)
1826          {
1827             tmpdata[i][j] = (float) ((double)tmpdata[i][j] * scale);
1828          }
1829       }
1830 
1831       file.openWrite();
1832       file.seek(0, 0);
1833       file.write(file_channels, tmpdata, tmpdatalen, MusEGlobal::config.liveWaveUpdate);
1834       file.update();
1835       file.close();
1836       file.openRead();
1837 
1838       for (unsigned i=0; i<file_channels; i++)
1839       {
1840          delete[] tmpdata[i];
1841       }
1842 
1843       // Undo handling
1844       MusEGlobal::song->cmdChangeWave(ev, tmpWavFile, 0, tmpdatalen);
1845       MusEGlobal::audio->msgIdle(false); // Not good with playback during operations
1846       //sf.update();
1847    }
1848 }
1849 
normalizeWaveParts(Part * partCursor)1850 void Song::normalizeWaveParts(Part *partCursor)
1851 {
1852    MusECore::TrackList* tracks=MusEGlobal::song->tracks();
1853    bool undoStarted = false;
1854    for (MusECore::TrackList::const_iterator t_it=tracks->begin(); t_it!=tracks->end(); t_it++)
1855    {
1856       if((*t_it)->type() != MusECore::Track::WAVE)
1857       {
1858          continue;
1859       }
1860       const MusECore::PartList* parts=(*t_it)->cparts();
1861       for (MusECore::ciPart p_it=parts->begin(); p_it!=parts->end(); p_it++)
1862       {
1863          if (p_it->second->selected())
1864          {
1865             MusECore::Part* part = p_it->second;
1866             if(!undoStarted)
1867             {
1868                undoStarted = true;
1869                MusEGlobal::song->startUndo();
1870             }
1871 
1872             normalizePart(part);
1873 
1874          }
1875       }
1876    }
1877    //if nothing selected, normilize current part under mouse (if given)
1878    if(!undoStarted && partCursor)
1879    {
1880       undoStarted = true;
1881       MusEGlobal::song->startUndo();
1882       normalizePart(partCursor);
1883    }
1884    if(undoStarted)
1885    {
1886       MusEGlobal::song->endUndo(SC_CLIP_MODIFIED);
1887    }
1888 }
1889 
1890 //---------------------------------------------------------
1891 //   beat
1892 //---------------------------------------------------------
1893 
beat()1894 void Song::beat()
1895       {
1896       // Watchdog for checking and setting timebase master state.
1897       static int _timebaseMasterCounter = 0;
1898       if(MusEGlobal::audioDevice &&
1899         MusEGlobal::audioDevice->hasOwnTransport() &&
1900         MusEGlobal::audioDevice->hasTimebaseMaster() &&
1901         MusEGlobal::config.useJackTransport &&
1902         (--_timebaseMasterCounter <= 0))
1903       {
1904         if(MusEGlobal::config.timebaseMaster)
1905         {
1906           if(!MusEGlobal::timebaseMasterState || !MusEGlobal::audio->isPlaying())
1907             MusEGlobal::audioDevice->setMaster(true);
1908         }
1909         // Set for once per second.
1910         _timebaseMasterCounter = MusEGlobal::config.guiRefresh;
1911       }
1912 
1913       //First: update cpu load toolbar
1914 
1915       _fCpuLoad = MusEGlobal::muse->getCPULoad();
1916       _fDspLoad = 0.0f;
1917       if (MusEGlobal::audioDevice)
1918         _fDspLoad = MusEGlobal::audioDevice->getDSP_Load();
1919       _xRunsCount = MusEGlobal::audio->getXruns();
1920 
1921       // Keep the sync detectors running...
1922       for(int port = 0; port < MusECore::MIDI_PORTS; ++port)
1923           MusEGlobal::midiPorts[port].syncInfo().setTime();
1924 
1925 
1926       if (MusEGlobal::audio->isPlaying())
1927         setPos(CPOS, MusEGlobal::audio->tickPos(), true, false, true);
1928 
1929       // Process external tempo changes:
1930       while(!_tempoFifo.isEmpty())
1931         MusEGlobal::tempo_rec_list.addTempo(_tempoFifo.get());
1932 
1933       // Update anything related to audio controller graphs etc.
1934       for(ciTrack it = _tracks.begin(); it != _tracks.end(); ++ it)
1935       {
1936         if((*it)->isMidiTrack())
1937           continue;
1938         AudioTrack* at = static_cast<AudioTrack*>(*it);
1939         CtrlListList* cll = at->controller();
1940         for(ciCtrlList icl = cll->begin(); icl != cll->end(); ++icl)
1941         {
1942           CtrlList* cl = icl->second;
1943           if(cl->isVisible() && !cl->dontShow() && cl->guiUpdatePending())
1944             emit controllerChanged(at, cl->id());
1945           cl->setGuiUpdatePending(false);
1946         }
1947       }
1948 
1949       // Update synth native guis at the heartbeat rate.
1950       for(ciSynthI is = _synthIs.begin(); is != _synthIs.end(); ++is)
1951         (*is)->guiHeartBeat();
1952 
1953       while (noteFifoSize) {
1954           int pv = recNoteFifo[noteFifoRindex];
1955           noteFifoRindex = (noteFifoRindex + 1) % REC_NOTE_FIFO_SIZE;
1956           int pitch = (pv >> 8) & 0xff;
1957           int velo = pv & 0xff;
1958 
1959           //---------------------------------------------------
1960           // filter midi remote control events
1961           //---------------------------------------------------
1962 
1963           bool consumed = false;
1964           if (MusEGlobal::rcEnable && velo != 0) {
1965               if (pitch == MusEGlobal::rcStopNote) {
1966                   setStop(true);
1967                   consumed = true;
1968               } else if (pitch == MusEGlobal::rcRecordNote) {
1969                   setRecord(true);
1970                   consumed = true;
1971               } else if (pitch == MusEGlobal::rcGotoLeftMarkNote) {
1972                   setPos(CPOS, pos[LPOS].tick(), true, true, true);
1973                   consumed = true;
1974               } else if (pitch == MusEGlobal::rcPlayNote) {
1975                   setPlay(true);
1976                   consumed = true;
1977               } else if (pitch == MusEGlobal::rcForwardNote) {
1978                   forward();
1979                   consumed = true;
1980               } else if (pitch == MusEGlobal::rcBackwardNote) {
1981                   rewind();
1982                   consumed = true;
1983               }
1984           }
1985 
1986           if (!consumed)
1987               emit MusEGlobal::song->midiNote(pitch, velo);
1988 
1989           --noteFifoSize;
1990       }
1991 
1992       if (MusEGlobal::rcEnableCC && rcCC > -1) {
1993 
1994           int cc = rcCC & 0xff;
1995           printf("*** CC in: %d\n", cc);
1996           if (cc == MusEGlobal::rcStopCC)
1997               setStop(true);
1998           else if (cc == MusEGlobal::rcPlayCC)
1999               setPlay(true);
2000           else if (cc == MusEGlobal::rcRecordCC)
2001               setRecord(true);
2002           else if (cc == MusEGlobal::rcGotoLeftMarkCC)
2003               setPos(CPOS, pos[LPOS].tick(), true, true, true);
2004           else if (cc == MusEGlobal::rcForwardCC)
2005               forward();
2006           else if (cc == MusEGlobal::rcBackwardCC)
2007               rewind();
2008 
2009           rcCC = -1;
2010       }
2011 }
2012 
2013 //---------------------------------------------------------
2014 //   setLen
2015 //---------------------------------------------------------
2016 
setLen(unsigned l,bool do_update)2017 void Song::setLen(unsigned l, bool do_update)
2018       {
2019       _len = l;
2020       if(do_update)
2021         update();
2022       }
2023 
2024 //---------------------------------------------------------
2025 //   addMarker
2026 //---------------------------------------------------------
2027 
addMarker(const QString & s,unsigned t,bool lck)2028 void Song::addMarker(const QString& s, unsigned t, bool lck)
2029       {
2030       Marker m(s);
2031       m.setType(lck ? Pos::FRAMES : Pos::TICKS);
2032       m.setTick(t);
2033       MusEGlobal::song->applyOperation(MusECore::UndoOp(MusECore::UndoOp::AddMarker, m));
2034       }
2035 
addMarker(const QString & s,const Pos & p)2036 void Song::addMarker(const QString& s, const Pos& p)
2037 {
2038       Marker m(s);
2039       m.setType(p.type());
2040       m.setPos(p);
2041       MusEGlobal::song->applyOperation(MusECore::UndoOp(MusECore::UndoOp::AddMarker, m));
2042 }
2043 
2044 //---------------------------------------------------------
2045 //   addMarker
2046 //---------------------------------------------------------
2047 
getMarkerAt(unsigned t)2048 iMarker Song::getMarkerAt(unsigned t)
2049       {
2050       return _markerList->find(t);
2051       }
2052 
2053 //---------------------------------------------------------
2054 //   removeMarker
2055 //---------------------------------------------------------
2056 
removeMarker(const Marker & marker)2057 void Song::removeMarker(const Marker& marker)
2058       {
2059       MusEGlobal::song->applyOperation(MusECore::UndoOp(MusECore::UndoOp::DeleteMarker, marker));
2060       }
2061 
setMarkerName(const Marker & marker,const QString & s)2062 void Song::setMarkerName(const Marker& marker, const QString& s)
2063       {
2064       Marker m(marker);
2065       m.setName(s);
2066       MusEGlobal::song->applyOperation(MusECore::UndoOp(MusECore::UndoOp::ModifyMarker, marker, m));
2067       }
2068 
setMarkerPos(const Marker & marker,const Pos & pos)2069 void Song::setMarkerPos(const Marker& marker, const Pos& pos)
2070       {
2071       // Here we use the separate SetMarkerPos operation, which is 'combo-breaker' aware, to optimize repeated adjustments.
2072       MusEGlobal::song->applyOperation(MusECore::UndoOp(MusECore::UndoOp::SetMarkerPos, marker, pos.posValue(), pos.type()));
2073       }
2074 
setMarkerLock(const Marker & marker,bool f)2075 void Song::setMarkerLock(const Marker& marker, bool f)
2076       {
2077       Marker m(marker);
2078       m.setType(f ? Pos::FRAMES : Pos::TICKS);
2079       MusEGlobal::song->applyOperation(MusECore::UndoOp(MusECore::UndoOp::ModifyMarker, marker, m));
2080       }
2081 
2082 //---------------------------------------------------------
2083 //   setRecordFlag
2084 //---------------------------------------------------------
2085 
setRecordFlag(Track * track,bool val,Undo * operations)2086 void Song::setRecordFlag(Track* track, bool val, Undo* operations)
2087 {
2088   if(operations)
2089   {
2090     // The undo system calls setRecordFlag1 for us.
2091     operations->push_back(UndoOp(UndoOp::SetTrackRecord, track, val));
2092     //operations->push_back(UndoOp(UndoOp::SetTrackRecord, track, val, true)); // No undo.
2093   }
2094   else
2095   {
2096     // The pending operations system does not call setRecordFlag1 for us. Call it now.
2097     if(!track->setRecordFlag1(val))
2098       return;
2099     // This is a minor operation easily manually undoable. Let's not clog the undo list with it.
2100     MusECore::PendingOperationList operations;
2101     operations.add(MusECore::PendingOperationItem(track, val, MusECore::PendingOperationItem::SetTrackRecord));
2102     MusEGlobal::audio->msgExecutePendingOperations(operations, true);
2103   }
2104 }
2105 
2106 //---------------------------------------------------------
2107 //   endMsgCmd
2108 //---------------------------------------------------------
2109 
endMsgCmd()2110 void Song::endMsgCmd()
2111       {
2112       if (updateFlags) {
2113             redoList->clearDelete();
2114 
2115             // It is possible the undo list is empty after removal of an empty undo,
2116             //  either by optimization or no given operations.
2117             if(MusEGlobal::undoAction)
2118               MusEGlobal::undoAction->setEnabled(!undoList->empty());
2119 
2120             if(MusEGlobal::redoAction)
2121               MusEGlobal::redoAction->setEnabled(false);
2122             setUndoRedoText();
2123             emit songChanged(updateFlags);
2124             }
2125       }
2126 
2127 //---------------------------------------------------------
2128 //   undo
2129 //---------------------------------------------------------
2130 
undo()2131 void Song::undo()
2132 {
2133       if (MusEGlobal::audio->isRecording()) {
2134         return;
2135       }
2136 
2137       updateFlags = SongChangedStruct_t();
2138 
2139       Undo& opGroup = undoList->back();
2140 
2141       if (opGroup.empty())
2142             return;
2143 
2144       MusEGlobal::audio->msgRevertOperationGroup(opGroup);
2145 
2146       redoList->push_back(opGroup);
2147       undoList->pop_back();
2148 
2149       if(MusEGlobal::redoAction)
2150         MusEGlobal::redoAction->setEnabled(true);
2151       if(MusEGlobal::undoAction)
2152         MusEGlobal::undoAction->setEnabled(!undoList->empty());
2153       setUndoRedoText();
2154 
2155       emit songChanged(updateFlags);
2156       emit sigDirty();
2157 }
2158 
2159 //---------------------------------------------------------
2160 //   redo
2161 //---------------------------------------------------------
2162 
redo()2163 void Song::redo()
2164 {
2165       if (MusEGlobal::audio->isRecording()) {
2166         return;
2167       }
2168 
2169       updateFlags = SongChangedStruct_t();
2170 
2171       Undo& opGroup = redoList->back();
2172 
2173       if (opGroup.empty())
2174             return;
2175 
2176       MusEGlobal::audio->msgExecuteOperationGroup(opGroup);
2177 
2178       undoList->push_back(opGroup);
2179       redoList->pop_back();
2180 
2181       if(MusEGlobal::undoAction)
2182         MusEGlobal::undoAction->setEnabled(true);
2183       if(MusEGlobal::redoAction)
2184         MusEGlobal::redoAction->setEnabled(!redoList->empty());
2185       setUndoRedoText();
2186 
2187       emit songChanged(updateFlags);
2188       emit sigDirty();
2189 }
2190 
2191 //---------------------------------------------------------
2192 //   processMsg
2193 //    executed in realtime thread context
2194 //---------------------------------------------------------
2195 
processMsg(AudioMsg * msg)2196 void Song::processMsg(AudioMsg* msg)
2197       {
2198       switch(msg->id) {
2199             case SEQM_UPDATE_SOLO_STATES:
2200                   updateSoloStates();
2201                   break;
2202             case SEQM_EXECUTE_PENDING_OPERATIONS:
2203                   msg->pendingOps->executeRTStage();
2204                   break;
2205             case SEQM_EXECUTE_OPERATION_GROUP:
2206                   executeOperationGroup2(*msg->operations);
2207                   break;
2208             case SEQM_REVERT_OPERATION_GROUP:
2209                   revertOperationGroup2(*msg->operations);
2210                   break;
2211             default:
2212                   fprintf(stderr, "unknown seq message %d\n", msg->id);
2213                   break;
2214             }
2215       }
2216 
2217 //---------------------------------------------------------
2218 //   panic
2219 //---------------------------------------------------------
2220 
panic()2221 void Song::panic()
2222       {
2223       MusEGlobal::audio->msgPanic();
2224       }
2225 
2226 //---------------------------------------------------------
2227 //   clear
2228 //    signal - emit signals for changes if true
2229 //    called from constructor as clear(false) and
2230 //    from MusE::clearSong() as clear(false)
2231 //    If clear_all is false, it will not touch things like midi ports.
2232 //---------------------------------------------------------
2233 
clear(bool signal,bool clear_all)2234 void Song::clear(bool signal, bool clear_all)
2235       {
2236       if(MusEGlobal::debugMsg)
2237         fprintf(stderr, "Song::clear\n");
2238 
2239       bounceTrack    = 0;
2240 
2241       _tracks.clear();
2242       _midis.clearDelete();
2243       _waves.clearDelete();
2244       _inputs.clearDelete();     // audio input ports
2245       _outputs.clearDelete();    // audio output ports
2246       _groups.clearDelete();     // mixer groups
2247       _auxs.clearDelete();       // aux sends
2248 
2249       // p3.3.45 Clear all midi port devices.
2250       for(int i = 0; i < MusECore::MIDI_PORTS; ++i)
2251       {
2252         // p3.3.50 Since midi ports are not deleted, clear all midi port in/out routes. They point to non-existant tracks now.
2253         MusEGlobal::midiPorts[i].inRoutes()->clear();
2254         MusEGlobal::midiPorts[i].outRoutes()->clear();
2255 
2256         // p3.3.50 Reset this.
2257         MusEGlobal::midiPorts[i].setFoundInSongFile(false);
2258 
2259         if(clear_all)  // Allow not touching devices. p4.0.17  TESTING: Maybe some problems...
2260           // This will also close the device.
2261           MusEGlobal::midiPorts[i].setMidiDevice(0);
2262       }
2263 
2264       _synthIs.clearDelete();
2265 
2266       // p3.3.45 Make sure to delete Jack midi devices, and remove all ALSA midi device routes...
2267       // Otherwise really nasty things happen when loading another song when one is already loaded.
2268       // The loop is a safe way to delete while iterating.
2269       bool loop;
2270       do
2271       {
2272         loop = false;
2273         for(iMidiDevice imd = MusEGlobal::midiDevices.begin(); imd != MusEGlobal::midiDevices.end(); ++imd)
2274         {
2275           if(dynamic_cast< MidiJackDevice* >(*imd))
2276           {
2277             if(clear_all)  // Allow not touching devices. p4.0.17  TESTING: Maybe some problems...
2278             {
2279               // Remove the device from the list.
2280               MusEGlobal::midiDevices.erase(imd);
2281               // Since Jack midi devices are created dynamically, we must delete them.
2282               // The destructor unregisters the device from Jack, which also disconnects all device-to-jack routes.
2283               // This will also delete all midi-track-to-device routes, they point to non-existant midi tracks
2284               //  which were all deleted above
2285               delete (*imd);
2286               loop = true;
2287               break;
2288             }
2289           }
2290 #ifdef ALSA_SUPPORT
2291           else if(dynamic_cast< MidiAlsaDevice* >(*imd))
2292           {
2293             // With alsa devices, we must not delete them (they're always in the list). But we must
2294             //  clear all routes. They point to non-existant midi tracks, which were all deleted above.
2295             (*imd)->inRoutes()->clear();
2296             (*imd)->outRoutes()->clear();
2297           }
2298 #endif
2299         }
2300       }
2301       while (loop);
2302 
2303       MusEGlobal::tempomap.clear();
2304       MusEGlobal::tempo_rec_list.clear();
2305       MusEGlobal::sigmap.clear();
2306       MusEGlobal::keymap.clear();
2307 
2308       // Clear these metronome settings.
2309       // A loaded song can override these if it chooses.
2310       MusEGlobal::metroUseSongSettings = false;
2311       if(MusEGlobal::metroSongSettings.metroAccentsMap)
2312         MusEGlobal::metroSongSettings.metroAccentsMap->clear();
2313 
2314       undoList->clearDelete();
2315       redoList->clearDelete();
2316       if(MusEGlobal::undoAction)
2317         MusEGlobal::undoAction->setEnabled(false);
2318       if(MusEGlobal::redoAction)
2319         MusEGlobal::redoAction->setEnabled(false);
2320       setUndoRedoText();
2321 
2322       _markerList->clear();
2323       pos[0].setTick(0);
2324       pos[1].setTick(0);
2325       pos[2].setTick(0);
2326       _vcpos.setTick(0);
2327 
2328       Track::clearSoloRefCounts();
2329       clearMidiTransforms();
2330       clearMidiInputTransforms();
2331 
2332       // Clear all midi port controller values.
2333       for(int i = 0; i < MusECore::MIDI_PORTS; ++i)
2334       {
2335         // Remove the controllers AND the values so we start with a clean slate.
2336         MusEGlobal::midiPorts[i].controller()->clearDelete(true);
2337         // Don't forget to re-add the default managed controllers.
2338         MusEGlobal::midiPorts[i].addDefaultControllers();
2339       }
2340 
2341       MusEGlobal::tempomap.setMasterFlag(0, true);
2342       loopFlag       = false;
2343       loopFlag       = false;
2344       punchinFlag    = false;
2345       punchoutFlag   = false;
2346       recordFlag     = false;
2347       soloFlag       = false;
2348       _recMode       = REC_OVERDUP;
2349       _cycleMode     = CYCLE_NORMAL;
2350       _click         = false;
2351       _quantize      = false;
2352       _len           = MusEGlobal::sigmap.bar2tick(150, 0, 0);  // default song len in ticks set for 150 bars
2353       _follow        = JUMP;
2354       dirty          = false;
2355       initDrumMap();
2356       initNewDrumMap();
2357       if (signal) {
2358             emit loopChanged(false);
2359             emit recordChanged(false);
2360             emit songChanged(-1);
2361             }
2362       }
2363 
2364 //---------------------------------------------------------
2365 //   cleanupForQuit
2366 //   called from Muse::closeEvent
2367 //---------------------------------------------------------
2368 
cleanupForQuit()2369 void Song::cleanupForQuit()
2370 {
2371       bounceTrack = nullptr;
2372 
2373       if(MusEGlobal::debugMsg)
2374         fprintf(stderr, "MusE: Song::cleanupForQuit...\n");
2375 
2376       _tracks.clear();
2377 
2378       if(MusEGlobal::debugMsg)
2379         fprintf(stderr, "deleting _midis\n");
2380       _midis.clearDelete();
2381 
2382       if(MusEGlobal::debugMsg)
2383         fprintf(stderr, "deleting _waves\n");
2384       _waves.clearDelete();
2385 
2386       if(MusEGlobal::debugMsg)
2387         fprintf(stderr, "deleting _inputs\n");
2388       _inputs.clearDelete();     // audio input ports
2389 
2390       if(MusEGlobal::debugMsg)
2391         fprintf(stderr, "deleting _outputs\n");
2392       _outputs.clearDelete();    // audio output ports
2393 
2394       if(MusEGlobal::debugMsg)
2395         fprintf(stderr, "deleting _groups\n");
2396       _groups.clearDelete();     // mixer groups
2397 
2398       if(MusEGlobal::debugMsg)
2399         fprintf(stderr, "deleting _auxs\n");
2400       _auxs.clearDelete();       // aux sends
2401 
2402       if(MusEGlobal::debugMsg)
2403         fprintf(stderr, "deleting _synthIs\n");
2404       _synthIs.clearDelete();    // each ~SynthI() -> deactivate3() -> ~SynthIF()
2405 
2406       MusEGlobal::tempomap.clear();
2407       MusEGlobal::sigmap.clear();
2408       MusEGlobal::keymap.clear();
2409 
2410       if(MusEGlobal::debugMsg)
2411         fprintf(stderr, "deleting undoList and redoList\n");
2412       undoList->clearDelete();
2413       redoList->clearDelete();
2414 
2415       _markerList->clear();
2416 
2417       if(MusEGlobal::debugMsg)
2418         fprintf(stderr, "deleting transforms\n");
2419       clearMidiTransforms(); // Deletes stuff.
2420       clearMidiInputTransforms(); // Deletes stuff.
2421 
2422       if(MusEGlobal::debugMsg)
2423         fprintf(stderr, "deleting midiport controllers\n");
2424 
2425       // Clear all midi port controllers and values.
2426       for(int i = 0; i < MusECore::MIDI_PORTS; ++i)
2427       {
2428         MusEGlobal::midiPorts[i].controller()->clearDelete(true); // Remove the controllers and the values.
2429         MusEGlobal::midiPorts[i].setMidiDevice(0);
2430       }
2431 
2432       // Can't do this here. Jack isn't running. Fixed. Test OK so far. DELETETHIS (the comment and #if/#endif)
2433       #if 1
2434       if(MusEGlobal::debugMsg)
2435         fprintf(stderr, "deleting midi devices except synths\n");
2436       for(iMidiDevice imd = MusEGlobal::midiDevices.begin(); imd != MusEGlobal::midiDevices.end(); ++imd)
2437       {
2438         // Close the device. Handy to do all devices here, including synths.
2439         (*imd)->close();
2440         // Since Syntis are midi devices, there's no need to delete them below.
2441         if((*imd)->isSynti())
2442           continue;
2443         delete (*imd);
2444       }
2445       MusEGlobal::midiDevices.clear();     // midi devices
2446       #endif
2447 
2448       if(MusEGlobal::debugMsg)
2449         fprintf(stderr, "deleting global available synths\n");
2450 
2451       // Delete all synths.
2452       std::vector<Synth*>::iterator is;
2453       for(is = MusEGlobal::synthis.begin(); is != MusEGlobal::synthis.end(); ++is)
2454       {
2455         Synth* s = *is;
2456 
2457         if(s)
2458           delete s;
2459       }
2460       MusEGlobal::synthis.clear();
2461 
2462       if(MusEGlobal::debugMsg)
2463         fprintf(stderr, "deleting midi instruments\n");
2464       for(iMidiInstrument imi = midiInstruments.begin(); imi != midiInstruments.end(); ++imi)
2465       {
2466         // Since Syntis are midi instruments, there's no need to delete them below.
2467         // Tricky, must cast as SynthI*.
2468         SynthI* s = dynamic_cast <SynthI*> (*imi);
2469         if(s)
2470           continue;
2471         delete (*imi);
2472       }
2473       midiInstruments.clear();     // midi instruments
2474 
2475       // Nothing required for ladspa plugin list, and rack instances of them
2476       //  are handled by ~AudioTrack.
2477 
2478       if(MusEGlobal::debugMsg)
2479         fprintf(stderr, "...finished cleaning up.\n");
2480 }
2481 
seqSignal(int fd)2482 void Song::seqSignal(int fd)
2483       {
2484       const int buf_size = 256;
2485       char buffer[buf_size];
2486 
2487       int n = ::read(fd, buffer, buf_size);
2488       if (n < 0) {
2489             fprintf(stderr, "Song: seqSignal(): READ PIPE failed: %s\n",
2490                strerror(errno));
2491             return;
2492             }
2493       bool do_set_sync_timeout = false;
2494       for (int i = 0; i < n; ++i) {
2495             switch(buffer[i]) {
2496                   case '0':         // STOP
2497                         do_set_sync_timeout = true;
2498                         stopRolling();
2499                         break;
2500                   case '1':         // PLAY
2501                         do_set_sync_timeout = true;
2502                         setStopPlay(true);
2503                         break;
2504                   case '2':   // record
2505                         setRecord(true);
2506                         break;
2507                   case '3':   // START_PLAY + jack STOP
2508                         do_set_sync_timeout = true;
2509                         abortRolling();
2510                         break;
2511                   case 'P':   // alsa ports changed
2512                         alsaScanMidiPorts();
2513                         break;
2514                   case 'G':   // Seek
2515                         // Hm, careful here, will multiple seeks cause this
2516                         //  to interfere with Jack's transport timeout countdown?
2517                         do_set_sync_timeout = true;
2518                         clearRecAutomation(true);
2519                         setPos(CPOS, MusEGlobal::audio->tickPos(), true, false, true);
2520                         _startPlayPosition = MusEGlobal::audio->pos(); // update start position
2521                         break;
2522                   case 'S':   // shutdown audio
2523                         MusEGlobal::muse->seqStop();
2524 
2525                         {
2526                         // give the user a sensible explanation
2527                         int btn = QMessageBox::critical( MusEGlobal::muse, tr("Jack shutdown!"),
2528                             tr("Jack has detected a performance problem which has lead to\n"
2529                             "MusE being disconnected.\n"
2530                             "This could happen due to a number of reasons:\n"
2531                             "- a performance issue with your particular setup.\n"
2532                             "- a bug in MusE (or possibly in another connected software).\n"
2533                             "- a random hiccup which might never occur again.\n"
2534                             "- jack was voluntary stopped by you or someone else\n"
2535                             "- jack crashed\n"
2536                             "If there is a persisting problem you are much welcome to discuss it\n"
2537                             "on the MusE mailinglist.\n"
2538                             "(there is information about joining the mailinglist on the MusE\n"
2539                             " homepage which is available through the help menu)\n"
2540                             "\n"
2541                             "To proceed check the status of Jack and try to restart it and then .\n"
2542                             "click on the Restart button."), "restart", "cancel");
2543                         if (btn == 0) {
2544                               fprintf(stderr, "restarting!\n");
2545                               MusEGlobal::muse->seqRestart();
2546                               }
2547                         }
2548 
2549                         break;
2550 // REMOVE Tim. latency. Removed. We now do this in MusE::bounceToFile() and MusE::bounceToTrack(), BEFORE the transport is started.
2551 //                   case 'f':   // start freewheel
2552 //                         if(MusEGlobal::debugMsg)
2553 //                           fprintf(stderr, "Song: seqSignal: case f: setFreewheel start\n");
2554 //
2555 //                         if(MusEGlobal::config.freewheelMode)
2556 //                           MusEGlobal::audioDevice->setFreewheel(true);
2557 //
2558 //                         break;
2559 
2560                   case 'F':   // stop freewheel
2561                         if(MusEGlobal::debugMsg)
2562                           fprintf(stderr, "Song: seqSignal: case F: setFreewheel stop\n");
2563 
2564                         if(MusEGlobal::config.freewheelMode)
2565                           MusEGlobal::audioDevice->setFreewheel(false);
2566                         break;
2567 
2568                   case 'A': // Abort rolling + Special stop bounce (offline) mode
2569                           do_set_sync_timeout = true;
2570                           abortRolling();
2571                           // Switch all the wave converters back to online mode.
2572                           setAudioConvertersOfflineOperation(false);
2573                         break;
2574 
2575                   case 'B': // Stop + Special stop bounce mode
2576                           do_set_sync_timeout = true;
2577                           stopRolling();
2578                           // Switch all the wave converters back to online mode.
2579                           setAudioConvertersOfflineOperation(false);
2580                         break;
2581 
2582                   case 'C': // Graph changed
2583                         if (MusEGlobal::audioDevice)
2584                             MusEGlobal::audioDevice->graphChanged();
2585                         break;
2586 
2587                   case 'R': // Registration changed
2588                         if (MusEGlobal::audioDevice)
2589                             MusEGlobal::audioDevice->registrationChanged();
2590                         break;
2591 
2592                   case 'J': // Port connections changed
2593                         if (MusEGlobal::audioDevice)
2594                             MusEGlobal::audioDevice->connectionsChanged();
2595                         break;
2596 
2597 //                   case 'U': // Send song changed signal
2598 //                         {
2599 //                           int d_len = sizeof(SongChangedStruct_t);
2600 //                           if((n - (i + 1)) < d_len)  // i + 1 = data after this 'U'
2601 //                           {
2602 //                             fprintf(stderr, "Song: seqSignal: case U: Not enough bytes read for SongChangedStruct_t !\n");
2603 //                             break;
2604 //                           }
2605 //                           SongChangedStruct_t f;
2606 //                           memcpy(&f, &buffer[i + 1], d_len);
2607 //                           i += d_len; // Move pointer ahead. Loop will also add one ++i.
2608 //                           update(f);
2609 //                         }
2610 //                         break;
2611 
2612                   case 'D': // Drum map changed
2613                         update(SC_DRUMMAP);
2614                         break;
2615 
2616 //                   case 'E': // Midi events are available in the ipc event buffer.
2617 //                         if(MusEGlobal::song)
2618 //                           MusEGlobal::song->processIpcInEventBuffers();
2619 //                         break;
2620 
2621                   case 'T': // We are now the timebase master.
2622                         MusEGlobal::timebaseMasterState = true;
2623                         update(SC_TIMEBASE_MASTER);
2624                         break;
2625 
2626                   case 't': // We are no longer the timebase master.
2627                         MusEGlobal::timebaseMasterState = false;
2628                         update(SC_TIMEBASE_MASTER);
2629                         break;
2630 
2631                   default:
2632                         fprintf(stderr, "unknown Seq Signal <%c>\n", buffer[i]);
2633                         break;
2634                   }
2635             }
2636 
2637             // Since other Jack clients might also set the sync timeout at any time,
2638             //  we need to be constantly enforcing our desired limit!
2639             // Since setSyncTimeout() may not be realtime friendly (Jack driver),
2640             //  we set the driver's sync timeout here in the gui thread.
2641             // Sadly, we likely cannot get away with setting it in the audio sync callback.
2642             // So whenever stop, start or seek occurs, we'll try to casually enforce the timeout here.
2643             // It's casual, unfortunately we can't set the EXACT timeout amount when we really need to
2644             //  (that's in audio sync callback) so we try this for now...
2645             if(do_set_sync_timeout && MusEGlobal::checkAudioDevice())
2646             {
2647               // Enforce a 30 second timeout.
2648               // TODO: Split this up and have user adjustable normal (2 or 10 second default) value,
2649               //        plus a contribution from the total required precount time.
2650               //       Too bad we likely can't set it dynamically in the audio sync callback.
2651               MusEGlobal::audioDevice->setSyncTimeout(30000000);
2652             }
2653       }
2654 
2655 //---------------------------------------------------------
2656 //   recordEvent
2657 //---------------------------------------------------------
2658 
recordEvent(MidiTrack * mt,Event & event)2659 void Song::recordEvent(MidiTrack* mt, Event& event)
2660       {
2661       //---------------------------------------------------
2662       //    if tick points into a part,
2663       //          record to that part
2664       //    else
2665       //          create new part
2666       //---------------------------------------------------
2667 
2668       unsigned tick  = event.tick();
2669       PartList* pl   = mt->parts();
2670       const MidiPart* part = 0;
2671       iPart ip;
2672       for (ip = pl->begin(); ip != pl->end(); ++ip) {
2673             part = (MidiPart*)(ip->second);
2674             unsigned partStart = part->tick();
2675             unsigned partEnd   = partStart + part->lenTick();
2676             if (tick >= partStart && tick < partEnd)
2677                   break;
2678             }
2679       updateFlags |= SC_EVENT_INSERTED;
2680       if (ip == pl->end()) {
2681             // create new part
2682             MidiPart* part = new MidiPart(mt);
2683             int startTick = roundDownBar(tick);
2684             int endTick   = roundUpBar(tick + 1);
2685             part->setTick(startTick);
2686             part->setLenTick(endTick - startTick);
2687             part->setName(mt->name());
2688             event.move(-startTick);
2689             part->addEvent(event);
2690             MusEGlobal::song->applyOperation(UndoOp(UndoOp::AddPart, part));
2691             return;
2692             }
2693       part = (MidiPart*)(ip->second);
2694       tick -= part->tick();
2695       event.setTick(tick);
2696 
2697       Event ev;
2698       if(event.type() == Controller)
2699       {
2700         cEventRange range = part->events().equal_range(tick);
2701         for(ciEvent i = range.first; i != range.second; ++i)
2702         {
2703           ev = i->second;
2704           if(ev.type() == Controller && ev.dataA() == event.dataA())
2705           {
2706             if(ev.dataB() == event.dataB()) // Don't bother if already set.
2707               return;
2708             MusEGlobal::song->applyOperation(UndoOp(UndoOp::ModifyEvent,event,ev,part,true,true));
2709             return;
2710           }
2711         }
2712       }
2713 
2714       MusEGlobal::song->applyOperation(UndoOp(UndoOp::AddEvent, event, part, true,true));
2715       }
2716 
2717 //---------------------------------------------------------
2718 //   execAutomationCtlPopup
2719 //---------------------------------------------------------
2720 
execAutomationCtlPopup(AudioTrack * track,const QPoint & menupos,int acid)2721 int Song::execAutomationCtlPopup(AudioTrack* track, const QPoint& menupos, int acid)
2722 {
2723   enum { PREV_EVENT=0, NEXT_EVENT, ADD_EVENT, CLEAR_EVENT, CLEAR_RANGE, CLEAR_ALL_EVENTS, MIDI_ASSIGN, MIDI_CLEAR };
2724   QMenu* menu = new QMenu;
2725 
2726   int count = 0;
2727   bool isEvent = false, canSeekPrev = false, canSeekNext = false, canEraseRange = false;
2728   bool canAdd = false;
2729   double ctlval = 0.0;
2730   unsigned int frame = 0;
2731   if(track)
2732   {
2733     ciCtrlList icl = track->controller()->find(acid);
2734     if(icl != track->controller()->end())
2735     {
2736       CtrlList *cl = icl->second;
2737       canAdd = true;
2738       frame = MusEGlobal::audio->pos().frame();
2739       bool en = track->controllerEnabled(acid);
2740       AutomationType at = track->automationType();
2741       if(!MusEGlobal::automation || at == AUTO_OFF || !en)
2742         ctlval = cl->curVal();
2743       else
2744         ctlval = cl->value(frame);
2745 
2746       count = cl->size();
2747       if(count)
2748       {
2749         iCtrl s = cl->lower_bound(frame);
2750         iCtrl e = cl->upper_bound(frame);
2751 
2752         isEvent = (s != cl->end() && s->second.frame == frame);
2753 
2754         canSeekPrev = s != cl->begin();
2755         canSeekNext = e != cl->end();
2756 
2757         s = cl->lower_bound(pos[1].frame());
2758 
2759         canEraseRange = s != cl->end()
2760                         && pos[2].frame() > s->second.frame;
2761       }
2762     }
2763   }
2764 
2765   menu->addAction(new MusEGui::MenuTitleItem(tr("Automation"), menu));
2766 
2767   QAction* prevEvent = menu->addAction(tr("Previous event"));
2768   prevEvent->setData(PREV_EVENT);
2769   prevEvent->setEnabled(canSeekPrev);
2770 
2771   QAction* nextEvent = menu->addAction(tr("Next event"));
2772   nextEvent->setData(NEXT_EVENT);
2773   nextEvent->setEnabled(canSeekNext);
2774 
2775   menu->addSeparator();
2776 
2777   QAction* addEvent = new QAction(menu);
2778   menu->addAction(addEvent);
2779   if(isEvent)
2780     addEvent->setText(tr("Set event"));
2781   else
2782     addEvent->setText(tr("Add event"));
2783   addEvent->setData(ADD_EVENT);
2784   addEvent->setEnabled(canAdd);
2785 
2786   QAction* eraseEventAction = menu->addAction(tr("Erase event"));
2787   eraseEventAction->setData(CLEAR_EVENT);
2788   eraseEventAction->setEnabled(isEvent);
2789 
2790   QAction* eraseRangeAction = menu->addAction(tr("Erase range"));
2791   eraseRangeAction->setData(CLEAR_RANGE);
2792   eraseRangeAction->setEnabled(canEraseRange);
2793 
2794   QAction* clearAction = menu->addAction(tr("Clear automation"));
2795   clearAction->setData(CLEAR_ALL_EVENTS);
2796   clearAction->setEnabled((bool)count);
2797 
2798 
2799   menu->addSeparator();
2800   menu->addAction(new MusEGui::MenuTitleItem(tr("Midi control"), menu));
2801 
2802   QAction *assign_act = menu->addAction(tr("Assign"));
2803   assign_act->setCheckable(false);
2804   assign_act->setData(MIDI_ASSIGN);
2805 
2806   MidiAudioCtrlMap* macm = track->controller()->midiControls();
2807   AudioMidiCtrlStructMap amcs;
2808   macm->find_audio_ctrl_structs(acid, &amcs);
2809 
2810   if(!amcs.empty())
2811   {
2812     QAction *cact = menu->addAction(tr("Clear"));
2813     cact->setData(MIDI_CLEAR);
2814     menu->addSeparator();
2815   }
2816 
2817   for(iAudioMidiCtrlStructMap iamcs = amcs.begin(); iamcs != amcs.end(); ++iamcs)
2818   {
2819     int port, chan, mctrl;
2820     macm->hash_values((*iamcs)->first, &port, &chan, &mctrl);
2821     //QString s = QString("Port:%1 Chan:%2 Ctl:%3-%4").arg(port + 1)
2822     QString s = QString("Port:%1 Chan:%2 Ctl:%3").arg(port + 1)
2823                                                   .arg(chan + 1)
2824                                                   //.arg((mctrl >> 8) & 0xff)
2825                                                   //.arg(mctrl & 0xff);
2826                                                   .arg(midiCtrlName(mctrl, true));
2827     QAction *mact = menu->addAction(s);
2828     mact->setEnabled(false);
2829     mact->setData(-1); // Not used
2830   }
2831 
2832   QAction* act = menu->exec(menupos);
2833   if (!act || !track)
2834   {
2835     delete menu;
2836     return -1;
2837   }
2838 
2839   int sel = act->data().toInt();
2840   delete menu;
2841 
2842   Undo operations;
2843 
2844   switch(sel)
2845   {
2846     case ADD_EVENT:
2847           MusEGlobal::song->applyOperation(UndoOp(UndoOp::AddAudioCtrlVal, track, acid, frame, ctlval));
2848     break;
2849     case CLEAR_EVENT:
2850           MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeleteAudioCtrlVal, track, acid, frame));
2851     break;
2852 
2853     case CLEAR_RANGE:
2854           MusEGlobal::audio->msgEraseRangeACEvents(track, acid, pos[1].frame(), pos[2].frame());
2855     break;
2856 
2857     case CLEAR_ALL_EVENTS:
2858           if(QMessageBox::question(MusEGlobal::muse, QString("Muse"),
2859               tr("Clear all controller events?"), tr("&Ok"), tr("&Cancel"),
2860               QString(), 0, 1 ) == 0)
2861             MusEGlobal::audio->msgClearControllerEvents(track, acid);
2862     break;
2863 
2864     case PREV_EVENT:
2865           MusEGlobal::audio->msgSeekPrevACEvent(track, acid);
2866     break;
2867 
2868     case NEXT_EVENT:
2869           MusEGlobal::audio->msgSeekNextACEvent(track, acid);
2870     break;
2871 
2872     case MIDI_ASSIGN:
2873           {
2874             int port = -1, chan = 0, ctrl = 0;
2875             for(MusECore::iAudioMidiCtrlStructMap iamcs = amcs.begin(); iamcs != amcs.end(); ++iamcs)
2876             {
2877               macm->hash_values((*iamcs)->first, &port, &chan, &ctrl);
2878               break; // Only a single item for now, thanks!
2879             }
2880 
2881             MusEGui::MidiAudioControl* pup = new MusEGui::MidiAudioControl(port, chan, ctrl);
2882 
2883             if(pup->exec() == QDialog::Accepted)
2884             {
2885               MusEGlobal::audio->msgIdle(true);  // Gain access to structures, and sync with audio
2886               // Erase all for now.
2887               for(MusECore::iAudioMidiCtrlStructMap iamcs = amcs.begin(); iamcs != amcs.end(); ++iamcs)
2888                 macm->erase(*iamcs);
2889 
2890               port = pup->port(); chan = pup->chan(); ctrl = pup->ctrl();
2891               if(port >= 0 && chan >=0 && ctrl >= 0)
2892                 // Add will replace if found.
2893                 macm->add_ctrl_struct(port, chan, ctrl, MusECore::MidiAudioCtrlStruct(acid));
2894 
2895               MusEGlobal::audio->msgIdle(false);
2896             }
2897 
2898             delete pup;
2899           }
2900           break;
2901 
2902     case MIDI_CLEAR:
2903           if(!amcs.empty())
2904             MusEGlobal::audio->msgIdle(true);  // Gain access to structures, and sync with audio
2905           for(MusECore::iAudioMidiCtrlStructMap iamcs = amcs.begin(); iamcs != amcs.end(); ++iamcs)
2906             macm->erase(*iamcs);
2907           if(!amcs.empty())
2908             MusEGlobal::audio->msgIdle(false);
2909     break;
2910 
2911     default:
2912           return -1;
2913     break;
2914   }
2915 
2916   if(!operations.empty())
2917     MusEGlobal::song->applyOperationGroup(operations);
2918 
2919   return sel;
2920 }
2921 
2922 //---------------------------------------------------------
2923 //   execMidiAutomationCtlPopup
2924 //---------------------------------------------------------
2925 
execMidiAutomationCtlPopup(MidiTrack * track,MidiPart * part,const QPoint & menupos,int ctlnum)2926 int Song::execMidiAutomationCtlPopup(MidiTrack* track, MidiPart* part, const QPoint& menupos, int ctlnum)
2927 {
2928   if(!track && !part)
2929     return -1;
2930 
2931   enum { BYPASS_CONTROLLER, ADD_EVENT, CLEAR_EVENT };
2932   bool isEvent = false;
2933 
2934   MidiTrack* mt;
2935   if(track)
2936     mt = track;
2937   else
2938     mt = (MidiTrack*)part->track();
2939 
2940   int dctl = ctlnum;
2941 
2942   // Is it a drum controller, according to the track port's instrument?
2943   int channel;
2944   MidiPort* mp;
2945   mt->mappedPortChanCtrl(&dctl, nullptr, &mp, &channel);
2946 
2947   unsigned tick = cpos();
2948 
2949   if(!part)
2950   {
2951     PartList* pl = mt->parts();
2952     iPart ip;
2953     for(ip = pl->begin(); ip != pl->end(); ++ip)
2954     {
2955       MidiPart* tpart = (MidiPart*)(ip->second);
2956       unsigned partStart = tpart->tick();
2957       unsigned partEnd   = partStart + tpart->lenTick();
2958       if(tick >= partStart && tick < partEnd)
2959       {
2960         // Prefer a selected part, otherwise keep looking...
2961         if(tpart->selected())
2962         {
2963           part = tpart;
2964           break;
2965         }
2966         else
2967         // Remember the first part found...
2968         if(!part)
2969           part = tpart;
2970       }
2971     }
2972   }
2973 
2974   Event ev;
2975   if(part)
2976   {
2977     unsigned partStart = part->tick();
2978     unsigned partEnd   = partStart + part->lenTick();
2979     if(tick >= partStart && tick < partEnd)
2980     {
2981             cEventRange range = part->events().equal_range(tick - partStart);
2982       for(ciEvent i = range.first; i != range.second; ++i)
2983       {
2984         ev = i->second;
2985         if(ev.type() == Controller)
2986         {
2987           if(ev.dataA() == ctlnum)
2988           {
2989             isEvent = true;
2990             break;
2991           }
2992         }
2993       }
2994     }
2995   }
2996 
2997   int initval = 0;
2998   MidiController* mc = mp->midiController(ctlnum, channel, false);
2999   if(mc)
3000   {
3001     const int bias = mc->bias();
3002     initval = mc->initVal();
3003     if(initval == CTRL_VAL_UNKNOWN)
3004     {
3005       if(ctlnum == CTRL_PROGRAM)
3006         // Special for program controller: Set HBank and LBank off (0xff), and program to 0.
3007         initval = 0xffff00;
3008       else
3009        // Otherwise start with the bias.
3010        initval = bias;
3011     }
3012     else
3013      // Auto bias.
3014      initval += bias;
3015   }
3016   const int cur_val = mp->hwCtrlState(channel, dctl);
3017 
3018   QMenu* menu = new QMenu;
3019 
3020   menu->addAction(new MusEGui::MenuTitleItem(tr("Controller"), menu));
3021   QAction* bypassEvent = new QAction(menu);
3022   menu->addAction(bypassEvent);
3023   bypassEvent->setText(tr("Bypass"));
3024   bypassEvent->setData(BYPASS_CONTROLLER);
3025   bypassEvent->setEnabled(true);
3026   bypassEvent->setCheckable(true);
3027   bypassEvent->setChecked(cur_val == CTRL_VAL_UNKNOWN);
3028 
3029   menu->addAction(new MusEGui::MenuTitleItem(tr("Automation"), menu));
3030 
3031   QAction* addEvent = new QAction(menu);
3032   menu->addAction(addEvent);
3033   if(isEvent)
3034     addEvent->setText(tr("Set event"));
3035   else
3036     addEvent->setText(tr("Add event"));
3037   addEvent->setData(ADD_EVENT);
3038   addEvent->setEnabled(true);
3039 
3040   QAction* eraseEventAction = menu->addAction(tr("Erase event"));
3041   eraseEventAction->setData(CLEAR_EVENT);
3042   eraseEventAction->setEnabled(isEvent);
3043 
3044   QAction* act = menu->exec(menupos);
3045   if (!act)
3046   {
3047     delete menu;
3048     return -1;
3049   }
3050 
3051   const int sel = act->data().toInt();
3052   const bool checked = act->isChecked();
3053   delete menu;
3054 
3055   switch(sel)
3056   {
3057     case BYPASS_CONTROLLER:
3058     {
3059       if(checked)
3060         MusEGlobal::audio->msgSetHwCtrlState(mp, channel, dctl, MusECore::CTRL_VAL_UNKNOWN);
3061       else
3062       {
3063         int v = mp->lastValidHWCtrlState(channel, dctl);
3064         if(v == MusECore::CTRL_VAL_UNKNOWN)
3065           v = initval;
3066         MusEGlobal::audio->msgSetHwCtrlState(mp, channel, dctl, v);
3067       }
3068     }
3069     break;
3070 
3071     case ADD_EVENT:
3072     {
3073           int v = cur_val;
3074           if(v == CTRL_VAL_UNKNOWN)
3075           {
3076             v = mp->lastValidHWCtrlState(channel, dctl);
3077             if(v == MusECore::CTRL_VAL_UNKNOWN)
3078               v = initval;
3079           }
3080           Event e(Controller);
3081           e.setA(ctlnum);
3082           e.setB(v);
3083           // Do we replace an old event?
3084           if(isEvent)
3085           {
3086             if(ev.dataB() == v) // Don't bother if already set.
3087               return -1;
3088 
3089             e.setTick(tick - part->tick());
3090             // Indicate do undo, and do port controller values and clone parts.
3091             MusEGlobal::song->applyOperation(UndoOp(UndoOp::ModifyEvent, e, ev, part, true, true));
3092           }
3093           else
3094           {
3095             // Store a new event...
3096             if(part)
3097             {
3098               e.setTick(tick - part->tick());
3099               // Indicate do undo, and do port controller values and clone parts.
3100               MusEGlobal::song->applyOperation(UndoOp(UndoOp::AddEvent,
3101                               e, part, true, true));
3102             }
3103             else
3104             {
3105               // Create a new part...
3106               part = new MidiPart(mt);
3107               int startTick = roundDownBar(tick);
3108               int endTick = roundUpBar(tick + 1);
3109               part->setTick(startTick);
3110               part->setLenTick(endTick - startTick);
3111               part->setName(mt->name());
3112               e.setTick(tick - startTick);
3113               part->addEvent(e);
3114               MusEGlobal::song->applyOperation(UndoOp(UndoOp::AddPart, part));
3115             }
3116           }
3117     }
3118     break;
3119     case CLEAR_EVENT:
3120           // Indicate do undo, and do port controller values and clone parts.
3121           MusEGlobal::song->applyOperation(UndoOp(UndoOp::DeleteEvent,
3122                             ev, part, true, true));
3123     break;
3124 
3125     default:
3126           return -1;
3127     break;
3128   }
3129 
3130   return sel;
3131 }
3132 
3133 //---------------------------------------------------------
3134 // putIpcInEvent
3135 //  Put an event into the IPC event ring buffer for the gui thread to process. Returns true on success.
3136 //  NOTE: Although the ring buffer is multi-writer, call this from audio thread only for now, unless
3137 //   you know what you are doing because the thread needs to ask whether the controller exists before
3138 //   calling, and that may not be safe from threads other than gui or audio.
3139 //---------------------------------------------------------
3140 
putIpcInEvent(const MidiPlayEvent & ev)3141 bool Song::putIpcInEvent(const MidiPlayEvent& ev)
3142 {
3143   if(!_ipcInEventBuffers->put(ev))
3144   {
3145     fprintf(stderr, "Error: Song::putIpcInEvent: Buffer overflow\n");
3146     return false;
3147   }
3148   return true;
3149 }
3150 
3151 //---------------------------------------------------------
3152 // putIpcOutEvent
3153 //  Put an event into the IPC event ring buffer for the audio thread to process.
3154 //  Called by gui thread only. Returns true on success.
3155 //---------------------------------------------------------
3156 
putIpcOutEvent(const MidiPlayEvent & ev)3157 bool Song::putIpcOutEvent(const MidiPlayEvent& ev)
3158 {
3159   if(!_ipcOutEventBuffers->put(ev))
3160   {
3161     fprintf(stderr, "Error: Song::putIpcOutEvent: Buffer overflow\n");
3162     return false;
3163   }
3164   return true;
3165 }
3166 
3167 //---------------------------------------------------------
3168 //   processIpcInEventBuffers
3169 //   Called by gui thread only.
3170 //   Returns true on success.
3171 //---------------------------------------------------------
3172 
processIpcInEventBuffers()3173 bool Song::processIpcInEventBuffers()
3174 {
3175   PendingOperationList operations;
3176   MidiPlayEvent buf_ev;
3177   int port, chan, ctrl;
3178   MidiPort* mp;
3179   iMidiCtrlValList imcvl;
3180   MidiCtrlValListList* mcvll;
3181   MidiCtrlValList* mcvl;
3182 
3183   //-----------------------------------------------------------
3184   // First pass: Peek into the buffers and find out if any
3185   //  controllers need to be created here in the gui thread.
3186   //-----------------------------------------------------------
3187 
3188   // False = don't use the size snapshot, but update it.
3189   const unsigned int sz = _ipcInEventBuffers->getSize(false);
3190   for(unsigned int i = 0; i < sz; ++i)
3191   {
3192     buf_ev = _ipcInEventBuffers->peek(i);
3193     port = buf_ev.port();
3194     if(port < 0 || port >= MusECore::MIDI_PORTS)
3195       continue;
3196     chan = buf_ev.channel();
3197     if(chan < 0 || chan >= MusECore::MUSE_MIDI_CHANNELS)
3198       continue;
3199 
3200     ctrl = buf_ev.translateCtrlNum();
3201     // Event translates to a controller?
3202     if(ctrl < 0)
3203       continue;
3204 
3205     mp = &MusEGlobal::midiPorts[port];
3206     mcvll = mp->controller();
3207 
3208     // Does the controller exist?
3209     imcvl = mcvll->find(chan, ctrl);
3210     if(imcvl == mcvll->end())
3211     {
3212       // Controller does not exist. Prepare a pending operation.
3213       PendingOperationItem poi(mcvll, 0, chan, ctrl, PendingOperationItem::AddMidiCtrlValList);
3214       // Have we already created and prepared this controller? Look in the operations list.
3215       iPendingOperation ipos = operations.findAllocationOp(poi);
3216       if(ipos == operations.end())
3217       {
3218         // We have not created and prepared the controller. Create it now.
3219         mcvl = new MidiCtrlValList(ctrl);
3220         // Set the operation controller member now.
3221         poi._mcvl = mcvl;
3222         // Add the operation to the pending operations.
3223         operations.add(poi);
3224       }
3225     }
3226   }
3227 
3228   // Execute any operations to create controllers.
3229   // This waits for audio process thread to execute it.
3230   if(!operations.empty())
3231     MusEGlobal::audio->msgExecutePendingOperations(operations, true);
3232 
3233   //-----------------------------------------------------------
3234   // Second pass: Read the buffers and set the controller values.
3235   // For the moment, the writer threads may have also put some more events
3236   //  into these buffers while they checked if the controller existed.
3237   //-----------------------------------------------------------
3238 
3239   for(unsigned int i = 0; i < sz; ++i)
3240   {
3241     if(!_ipcInEventBuffers->get(buf_ev))
3242       continue;
3243 
3244     port = buf_ev.port();
3245     if(port < 0 || port >= MusECore::MIDI_PORTS)
3246       continue;
3247     chan = buf_ev.channel();
3248     if(chan < 0 || chan >= MusECore::MUSE_MIDI_CHANNELS)
3249       continue;
3250 
3251     ctrl = buf_ev.translateCtrlNum();
3252     // Event translates to a controller?
3253     if(ctrl < 0)
3254       continue;
3255 
3256     mp = &MusEGlobal::midiPorts[port];
3257     mcvll = mp->controller();
3258 
3259     // Put the event BACK INTO the midi port's event buffer so that
3260     //  the port will process it 'where it left off' before it put
3261     //  this controller creation event into this ring buffer.
3262     // It also allows the port to call updateDrumMap in the audio thread.
3263     // Keep the time intact, so the driver will at least play them in
3264     //  sequence even though they will all be 'bunched up' at frame zero.
3265     // Make sure the controller REALLY was created before proceeding,
3266     //  otherwise the mechanism might get stuck in a continuous loop.
3267 //     imcvl = mcvll->find(chan, ctrl);
3268 //     if(imcvl != mcvll->end())
3269     {
3270       //mp->putHwCtrlEvent(buf_ev);
3271       // Let's bypass the putHwCtrlEvent and save some time -
3272       //  put directly into the midi port's controller event buffers.
3273       // This will also prevent getting stuck in continuous loop.
3274       if(!_ipcOutEventBuffers->put(buf_ev))
3275       {
3276         fprintf(stderr, "Error: Song::processIpcInEventBuffers(): Midi port controller fifo overflow\n");
3277         continue;
3278       }
3279     }
3280   }
3281 
3282   return true;
3283 }
3284 
3285 //---------------------------------------------------------
3286 //   processIpcOutEventBuffers
3287 //   Called from audio thread only.
3288 //   Returns true on success.
3289 //---------------------------------------------------------
3290 
processIpcOutEventBuffers()3291 bool Song::processIpcOutEventBuffers()
3292 {
3293   // Receive hardware state events sent from various threads to this audio thread.
3294   // Update hardware state so gui controls are updated.
3295   // False = don't use the size snapshot, but update it.
3296   const int sz = _ipcOutEventBuffers->getSize(false);
3297   MidiPlayEvent ev;
3298   for(int i = 0; i < sz; ++i)
3299   {
3300     if(!_ipcOutEventBuffers->get(ev))
3301       continue;
3302     const int port = ev.port();
3303     if(port < 0 || port >= MusECore::MIDI_PORTS)
3304       continue;
3305     // Handle the event. Tell the gui NOT to create controllers as needed,
3306     //  that should be done before it ever gets here.
3307     MusEGlobal::midiPorts[port].handleGui2AudioEvent(ev, false);
3308   }
3309   return true;
3310 }
3311 
3312 //---------------------------------------------------------
3313 //   updateSoloStates
3314 //    This will properly set all soloing variables (including other tracks) based entirely
3315 //     on the current values of all the tracks' _solo members.
3316 //---------------------------------------------------------
3317 
updateSoloStates()3318 void Song::updateSoloStates()
3319 {
3320   Track::clearSoloRefCounts();
3321   for(ciTrack i = _tracks.begin(); i != _tracks.end(); ++i)
3322     (*i)->setInternalSolo(0);
3323   for(ciTrack i = _tracks.begin(); i != _tracks.end(); ++i)
3324     (*i)->updateSoloStates(true);
3325 }
3326 
3327 //---------------------------------------------------------
3328 //   reenableTouchedControllers
3329 //   Enable all track and plugin controllers, and synth controllers if applicable, which are NOT in AUTO_WRITE mode.
3330 //---------------------------------------------------------
3331 
reenableTouchedControllers()3332 void Song::reenableTouchedControllers()
3333 {
3334   for(iTrack it = _tracks.begin(); it != _tracks.end(); ++it)
3335   {
3336     if((*it)->isMidiTrack())
3337       continue;
3338     AudioTrack* t = static_cast<AudioTrack*>(*it);
3339     AutomationType at = t->automationType();
3340     if(at == AUTO_WRITE)  // Exclude write mode because controls need to remain disabled if pressed before play.
3341       continue;
3342     t->enableAllControllers();
3343   }
3344 }
3345 
3346 //---------------------------------------------------------
3347 //   clearRecAutomation
3348 //---------------------------------------------------------
3349 
clearRecAutomation(bool clearList)3350 void Song::clearRecAutomation(bool clearList)
3351 {
3352   // Clear all pan/vol pressed and touched flags, and all rec event lists, if needed.
3353   for (iTrack it = tracks()->begin(); it != tracks()->end(); ++it)
3354     ((Track*)(*it))->clearRecAutomation(clearList);
3355 }
3356 
3357 //---------------------------------------------------------
3358 //   processAutomationEvents
3359 //---------------------------------------------------------
3360 
processAutomationEvents(Undo * operations)3361 void Song::processAutomationEvents(Undo* operations)
3362 {
3363   Undo ops;
3364   Undo* opsp = operations ? operations : &ops;
3365 
3366   // Clear all pressed and touched flags.
3367   // This is a non-undoable 'one-time' operation, removed after execution.
3368   opsp->push_back(UndoOp(UndoOp::EnableAllAudioControllers));
3369 
3370   for(iTrack i = _tracks.begin(); i != _tracks.end(); ++i)
3371   {
3372     if(!(*i)->isMidiTrack())
3373       // Process (and clear) rec events.
3374       processTrackAutomationEvents((AudioTrack*)*i, opsp);
3375   }
3376 
3377   if(!operations)
3378     MusEGlobal::song->applyOperationGroup(ops);
3379 }
3380 
3381 //---------------------------------------------------------
3382 //   processMasterRec
3383 //---------------------------------------------------------
3384 
processMasterRec()3385 void Song::processMasterRec()
3386 {
3387 //   bool do_tempo = false;
3388 
3389   // Wait a few seconds for the tempo fifo to be empty.
3390   int tout = 100; // Ten seconds. Otherwise we gotta move on.
3391   while(!_tempoFifo.isEmpty())
3392   {
3393     usleep(100000);
3394     --tout;
3395     if(tout == 0)
3396     {
3397       fprintf(stderr, "Song::processMasterRec: Error: Timeout waiting for _tempoFifo to empty!\n");
3398       break;
3399     }
3400   }
3401 
3402   const int tempo_rec_list_sz = MusEGlobal::tempo_rec_list.size();
3403   if(tempo_rec_list_sz != 0)
3404   {
3405     if(QMessageBox::question(MusEGlobal::muse,
3406                           tr("MusE: Tempo list"),
3407                           tr("External tempo changes were recorded.\nTransfer them to master tempo list?"),
3408                           QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Ok)
3409     {
3410       // FIXME TODO: Change the tempomap and tempo_rec_list to allocated pointers so they can be quickly swapped in realtime without idling.
3411       MusEGlobal::audio->msgIdle(true); // gain access to all data structures
3412 
3413       // Erase from master tempo the (approximate) recording start/end tick range according to the recorded tempo map,
3414       //MusEGlobal::tempomap.eraseRange(MusEGlobal::tempo_rec_list.frame2tick(MusEGlobal::audio->getStartRecordPos().frame()),
3415       //                                MusEGlobal::tempo_rec_list.frame2tick(MusEGlobal::audio->getEndRecordPos().frame()));
3416       // This is more accurate but lacks resolution:
3417       MusEGlobal::tempomap.eraseRange(MusEGlobal::audio->getStartExternalRecTick(), MusEGlobal::audio->getEndExternalRecTick());
3418 
3419       // Add the recorded tempos to the master tempo list:
3420       for(int i = 0; i < tempo_rec_list_sz; ++i)
3421         MusEGlobal::tempomap.addTempo(MusEGlobal::tempo_rec_list[i].tick,
3422                                       MusEGlobal::tempo_rec_list[i].tempo,
3423                                       false);  // False: Defer normalize
3424       MusEGlobal::tempomap.normalize();
3425       MusEGlobal::audio->msgIdle(false);
3426       update(SC_TEMPO);
3427     }
3428     // It should be safe to do this here in the GUI thread, the driver should not be touching it anymore.
3429     MusEGlobal::tempo_rec_list.clear();
3430   }
3431 }
3432 
3433 //---------------------------------------------------------
3434 //   abortRolling
3435 //---------------------------------------------------------
3436 
abortRolling()3437 void Song::abortRolling()
3438 {
3439   if(MusEGlobal::audio->freewheel())
3440     MusEGlobal::audioDevice->setFreewheel(false);
3441 
3442   if (record())
3443         MusEGlobal::audio->recordStop();
3444   setStopPlay(false);
3445 }
3446 
3447 //---------------------------------------------------------
3448 //   stopRolling
3449 //---------------------------------------------------------
3450 
stopRolling(Undo * operations)3451 void Song::stopRolling(Undo* operations)
3452       {
3453       if(MusEGlobal::audio->freewheel())
3454         MusEGlobal::audioDevice->setFreewheel(false);
3455 
3456       Undo ops;
3457       Undo* opsp = operations ? operations : &ops;
3458 
3459       if (record())
3460             MusEGlobal::audio->recordStop(false, opsp);
3461       setStopPlay(false);
3462 
3463       processAutomationEvents(opsp);
3464 
3465       if (MusEGlobal::config.useRewindOnStop) {
3466         setPos(Song::CPOS, _startPlayPosition);
3467       }
3468 
3469       if(!operations)
3470         MusEGlobal::song->applyOperationGroup(ops);
3471       }
3472 
3473 //---------------------------------------------------------
3474 //   connectJackRoutes
3475 //---------------------------------------------------------
3476 
connectJackRoutes(const MusECore::Route & src,const MusECore::Route & dst,bool disconnect)3477 bool Song::connectJackRoutes(const MusECore::Route& src, const MusECore::Route& dst, bool disconnect)
3478 {
3479   //fprintf(stderr, "connectJackRoutes:\n");
3480 
3481   if(!MusEGlobal::checkAudioDevice() || !MusEGlobal::audio->isRunning())
3482     return false;
3483 
3484   switch(src.type)
3485   {
3486     case Route::JACK_ROUTE:
3487       switch(dst.type)
3488       {
3489         case Route::JACK_ROUTE:
3490           if(disconnect)
3491             return MusEGlobal::audioDevice->disconnect(src.persistentJackPortName, dst.persistentJackPortName);
3492           else
3493             return MusEGlobal::audioDevice->connect(src.persistentJackPortName, dst.persistentJackPortName);
3494         break;
3495         case Route::MIDI_DEVICE_ROUTE:
3496           if(dst.device && dst.device->deviceType() == MidiDevice::JACK_MIDI && dst.device->inClientPort())
3497           {
3498             if(disconnect)
3499               return MusEGlobal::audioDevice->disconnect(src.persistentJackPortName, MusEGlobal::audioDevice->canonicalPortName(dst.device->inClientPort()));
3500             else
3501               return MusEGlobal::audioDevice->connect(src.persistentJackPortName, MusEGlobal::audioDevice->canonicalPortName(dst.device->inClientPort()));
3502           }
3503         break;
3504         case Route::TRACK_ROUTE:
3505           if(dst.track && dst.track->type() == Track::AUDIO_INPUT && dst.channel >= 0)
3506           {
3507             AudioInput* ai = static_cast<AudioInput*>(dst.track);
3508             if(ai->jackPort(dst.channel))
3509             {
3510               if(disconnect)
3511                 return MusEGlobal::audioDevice->disconnect(src.persistentJackPortName, MusEGlobal::audioDevice->canonicalPortName(ai->jackPort(dst.channel)));
3512               else
3513                 return MusEGlobal::audioDevice->connect(src.persistentJackPortName, MusEGlobal::audioDevice->canonicalPortName(ai->jackPort(dst.channel)));
3514             }
3515           }
3516         break;
3517         case Route::MIDI_PORT_ROUTE:
3518         break;
3519       }
3520     break;
3521 
3522     case Route::MIDI_DEVICE_ROUTE:
3523       switch(dst.type)
3524       {
3525         case Route::JACK_ROUTE:
3526           if(src.device && src.device->deviceType() == MidiDevice::JACK_MIDI && src.device->outClientPort())
3527           {
3528             if(disconnect)
3529               return MusEGlobal::audioDevice->disconnect(MusEGlobal::audioDevice->canonicalPortName(src.device->outClientPort()), dst.persistentJackPortName);
3530             else
3531               return MusEGlobal::audioDevice->connect(MusEGlobal::audioDevice->canonicalPortName(src.device->outClientPort()), dst.persistentJackPortName);
3532           }
3533         break;
3534         case Route::MIDI_DEVICE_ROUTE:
3535         case Route::TRACK_ROUTE:
3536         case Route::MIDI_PORT_ROUTE:
3537         break;
3538       }
3539     break;
3540     case Route::TRACK_ROUTE:
3541       switch(dst.type)
3542       {
3543         case Route::JACK_ROUTE:
3544           if(src.track && src.track->type() == Track::AUDIO_OUTPUT && src.channel >= 0)
3545           {
3546             AudioOutput* ao = static_cast<AudioOutput*>(src.track);
3547             if(ao->jackPort(src.channel))
3548             {
3549               if(disconnect)
3550                 return MusEGlobal::audioDevice->disconnect(MusEGlobal::audioDevice->canonicalPortName(ao->jackPort(src.channel)), dst.persistentJackPortName);
3551               else
3552                 return MusEGlobal::audioDevice->connect(MusEGlobal::audioDevice->canonicalPortName(ao->jackPort(src.channel)), dst.persistentJackPortName);
3553             }
3554           }
3555         break;
3556         case Route::MIDI_DEVICE_ROUTE:
3557         case Route::TRACK_ROUTE:
3558         case Route::MIDI_PORT_ROUTE:
3559         break;
3560       }
3561     break;
3562     case Route::MIDI_PORT_ROUTE:
3563     break;
3564   }
3565 
3566   return false;
3567 }
3568 
3569 //---------------------------------------------------------
3570 //   connectMidiPorts
3571 //---------------------------------------------------------
3572 
connectMidiPorts()3573 void Song::connectMidiPorts()
3574 {
3575   // Connect midi device ports to Jack ports...
3576   for(iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i)
3577   {
3578     MidiDevice* md = *i;
3579     if(md->deviceType() != MidiDevice::JACK_MIDI)
3580       continue;
3581 
3582     // Midi outputs...
3583     if(md->rwFlags() & 1)
3584     {
3585       void* our_port = md->outClientPort();
3586       if(our_port)
3587       {
3588         const char* our_port_name = MusEGlobal::audioDevice->canonicalPortName(our_port);
3589         if(our_port_name)
3590         {
3591           RouteList* rl = md->outRoutes();
3592           for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)
3593           {
3594             if(ir->type != Route::JACK_ROUTE)
3595               continue;
3596             const char* route_name = ir->persistentJackPortName;
3597             if(!MusEGlobal::audioDevice->findPort(route_name))
3598               continue;
3599             //if(!MusEGlobal::audioDevice->portConnectedTo(our_port, route_name))
3600             MusEGlobal::audioDevice->connect(our_port_name, route_name);
3601           }
3602         }
3603       }
3604     }
3605 
3606     // Midi inputs...
3607     if(md->rwFlags() & 2)
3608     {
3609       void* our_port = md->inClientPort();
3610       if(our_port)
3611       {
3612         const char* our_port_name = MusEGlobal::audioDevice->canonicalPortName(our_port);
3613         if(our_port_name)
3614         {
3615           RouteList* rl = md->inRoutes();
3616           for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)
3617           {
3618             if(ir->type != Route::JACK_ROUTE)
3619               continue;
3620             const char* route_name = ir->persistentJackPortName;
3621             if(!MusEGlobal::audioDevice->findPort(route_name))
3622               continue;
3623             //if(!MusEGlobal::audioDevice->portConnectedTo(our_port, route_name))
3624             MusEGlobal::audioDevice->connect(route_name, our_port_name);
3625           }
3626         }
3627       }
3628     }
3629   }
3630 }
3631 
3632 //---------------------------------------------------------
3633 //   connectAudioPorts
3634 //---------------------------------------------------------
3635 
connectAudioPorts()3636 void Song::connectAudioPorts()
3637 {
3638   if(!MusEGlobal::audioDevice)
3639     return;
3640 
3641   // Connect audio output ports to Jack ports...
3642   OutputList* ol = outputs();
3643   for(iAudioOutput i = ol->begin(); i != ol->end(); ++i)
3644   {
3645     AudioOutput* ao = *i;
3646     int channel = ao->channels();
3647     for(int ch = 0; ch < channel; ++ch)
3648     {
3649       void* our_port = ao->jackPort(ch);
3650       if(!our_port)
3651         continue;
3652       const char* our_port_name = MusEGlobal::audioDevice->canonicalPortName(our_port);
3653       if(!our_port_name)
3654         continue;
3655       RouteList* rl = ao->outRoutes();
3656       for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)
3657       {
3658         if(ir->type != Route::JACK_ROUTE || ir->channel != ch)
3659           continue;
3660         const char* route_name = ir->persistentJackPortName;
3661         if(!MusEGlobal::audioDevice->findPort(route_name))
3662           continue;
3663         //if(!MusEGlobal::audioDevice->portConnectedTo(our_port, route_name))
3664         MusEGlobal::audioDevice->connect(our_port_name, route_name);
3665       }
3666     }
3667   }
3668 
3669   // Connect Jack ports to audio input ports...
3670   InputList* il = inputs();
3671   for(iAudioInput i = il->begin(); i != il->end(); ++i)
3672   {
3673     AudioInput* ai = *i;
3674     int channel = ai->channels();
3675     for(int ch = 0; ch < channel; ++ch)
3676     {
3677       void* our_port = ai->jackPort(ch);
3678       if(!our_port)
3679         continue;
3680       const char* our_port_name = MusEGlobal::audioDevice->canonicalPortName(our_port);
3681       if(!our_port_name)
3682         continue;
3683       RouteList* rl = ai->inRoutes();
3684       for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)
3685       {
3686         if(ir->type != Route::JACK_ROUTE || ir->channel != ch)
3687           continue;
3688         const char* route_name = ir->persistentJackPortName;
3689         if(!MusEGlobal::audioDevice->findPort(route_name))
3690           continue;
3691         //if(!MusEGlobal::audioDevice->portConnectedTo(our_port, route_name))
3692         MusEGlobal::audioDevice->connect(route_name, our_port_name);
3693       }
3694     }
3695   }
3696 }
3697 
3698 //---------------------------------------------------------
3699 //   insertTrack0
3700 //---------------------------------------------------------
3701 
insertTrack0(Track * track,int idx)3702 void Song::insertTrack0(Track* track, int idx)
3703       {
3704       int n;
3705       switch(track->type()) {
3706             case Track::MIDI:
3707             case Track::DRUM:
3708                   _midis.push_back((MidiTrack*)track);
3709                   break;
3710             case Track::WAVE:
3711                   _waves.push_back((MusECore::WaveTrack*)track);
3712                   break;
3713             case Track::AUDIO_OUTPUT:
3714                   _outputs.push_back((AudioOutput*)track);
3715                   break;
3716             case Track::AUDIO_GROUP:
3717                   _groups.push_back((AudioGroup*)track);
3718                   break;
3719             case Track::AUDIO_AUX:
3720                   _auxs.push_back((AudioAux*)track);
3721                   break;
3722             case Track::AUDIO_INPUT:
3723                   _inputs.push_back((AudioInput*)track);
3724                   break;
3725             case Track::AUDIO_SOFTSYNTH:
3726                   {
3727                   SynthI* s = (SynthI*)track;
3728                   Synth* sy = s->synth();
3729                   if (!s->isActivated()) {
3730                         // Persistent storage: If the synth is not found allow the track to load.
3731                         // It's OK if s is NULL. initInstance needs to do a few things.
3732                         s->initInstance(sy, s->name());
3733                         }
3734                   MusEGlobal::midiDevices.add(s);
3735                   midiInstruments.push_back(s);
3736                   _synthIs.push_back(s);
3737                   }
3738                   break;
3739             default:
3740                   fprintf(stderr, "unknown track type %d\n", track->type());
3741                   return;
3742             }
3743 
3744       // initialize missing aux send
3745       iTrack i = _tracks.index2iterator(idx);
3746 
3747       _tracks.insert(i, track);
3748 
3749       n = _auxs.size();
3750       for (iTrack i = _tracks.begin(); i != _tracks.end(); ++i) {
3751             if ((*i)->isMidiTrack())
3752                   continue;
3753             MusECore::AudioTrack* wt = (MusECore::AudioTrack*)*i;
3754             if (wt->hasAuxSend()) {
3755                   wt->addAuxSend(n);
3756                   }
3757             }
3758 
3759       //  add routes
3760 
3761       if (track->isMidiTrack())          // p3.3.50
3762       {
3763             const RouteList* rl = track->inRoutes();
3764             for (ciRoute r = rl->begin(); r != rl->end(); ++r)
3765             {
3766                   switch(r->type)
3767                   {
3768                     case Route::MIDI_PORT_ROUTE:  {
3769                       Route src(track, r->channel);
3770                       MusEGlobal::midiPorts[r->midiPort].outRoutes()->push_back(src);  }
3771                     break;
3772                     case Route::TRACK_ROUTE:
3773                     case Route::JACK_ROUTE:
3774                     case Route::MIDI_DEVICE_ROUTE:
3775                     break;
3776                   }
3777             }
3778             rl = track->outRoutes();
3779             for (ciRoute r = rl->begin(); r != rl->end(); ++r)
3780             {
3781                   switch(r->type)
3782                   {
3783                     case Route::MIDI_PORT_ROUTE:  {
3784                       Route src(track, r->channel);
3785                       MusEGlobal::midiPorts[r->midiPort].inRoutes()->push_back(src);  }
3786                     break;
3787                     case Route::TRACK_ROUTE:
3788                     case Route::JACK_ROUTE:
3789                     case Route::MIDI_DEVICE_ROUTE:
3790                     break;
3791                   }
3792             }
3793       }
3794       else
3795       {
3796             const RouteList* rl = track->inRoutes();
3797             for (ciRoute r = rl->begin(); r != rl->end(); ++r)
3798             {
3799                   switch(r->type)
3800                   {
3801                     case Route::TRACK_ROUTE: {
3802                       Route src(track, r->remoteChannel, r->channels);
3803                       src.remoteChannel = r->channel;
3804                       r->track->outRoutes()->push_back(src);
3805                       // Is the source an Aux Track or else does it have Aux Tracks routed to it?
3806                       // Update this track's aux ref count.     p4.0.37
3807                       if(r->track->auxRefCount())
3808                         track->updateAuxRoute( r->track->auxRefCount(), NULL );
3809                       else if(r->track->type() == Track::AUDIO_AUX)
3810                         track->updateAuxRoute( 1, NULL );
3811                     }
3812                     break;
3813                     case Route::MIDI_PORT_ROUTE:
3814                     case Route::JACK_ROUTE:
3815                     case Route::MIDI_DEVICE_ROUTE:
3816                     break;
3817                   }
3818             }
3819             rl = track->outRoutes();
3820             for (ciRoute r = rl->begin(); r != rl->end(); ++r)
3821             {
3822                   switch(r->type)
3823                   {
3824                     case Route::TRACK_ROUTE: {
3825                       Route src(track, r->remoteChannel, r->channels);
3826                       src.remoteChannel = r->channel;
3827                       r->track->inRoutes()->push_back(src);
3828                       // Is this track an Aux Track or else does it have Aux Tracks routed to it?
3829                       // Update the other track's aux ref count and all tracks it is connected to.
3830                       if(track->auxRefCount())
3831                         r->track->updateAuxRoute( track->auxRefCount(), NULL );
3832                       else if(track->type() == Track::AUDIO_AUX)
3833                         r->track->updateAuxRoute( 1, NULL );
3834                     }
3835                     break;
3836                     case Route::MIDI_PORT_ROUTE:
3837                     case Route::JACK_ROUTE:
3838                     case Route::MIDI_DEVICE_ROUTE:
3839                     break;
3840                   }
3841             }
3842       }
3843       }
3844 
3845 //---------------------------------------------------------
3846 //   insertTrackOperation
3847 //---------------------------------------------------------
3848 
insertTrackOperation(Track * track,int idx,PendingOperationList & ops)3849 void Song::insertTrackOperation(Track* track, int idx, PendingOperationList& ops)
3850 {
3851       //int n;
3852       void* sec_track_list = 0;
3853       switch(track->type()) {
3854             case Track::MIDI:
3855             case Track::DRUM:
3856                   sec_track_list = &_midis;
3857                   break;
3858             case Track::WAVE:
3859                   sec_track_list = &_waves;
3860                   break;
3861             case Track::AUDIO_OUTPUT:
3862                   sec_track_list = &_outputs;
3863                   break;
3864             case Track::AUDIO_GROUP:
3865                   sec_track_list = &_groups;
3866                   break;
3867             case Track::AUDIO_AUX:
3868                   sec_track_list = &_auxs;
3869                   break;
3870             case Track::AUDIO_INPUT:
3871                   sec_track_list = &_inputs;
3872                   break;
3873             case Track::AUDIO_SOFTSYNTH:
3874                   {
3875                   SynthI* s = static_cast<SynthI*>(track);
3876                   ops.addDeviceOperation(&MusEGlobal::midiDevices, s);
3877                   ops.add(PendingOperationItem(&midiInstruments, s, PendingOperationItem::AddMidiInstrument));
3878                   sec_track_list = &_synthIs;
3879                   }
3880                   break;
3881             default:
3882                   fprintf(stderr, "unknown track type %d\n", track->type());
3883                   return;
3884             }
3885 
3886       ops.add(PendingOperationItem(&_tracks, track, idx, PendingOperationItem::AddTrack, sec_track_list));
3887 
3888       ops.addTrackPortCtrlEvents(track);
3889 
3890       // NOTE: Aux sends:
3891       // Initializing of this track and/or others' aux sends is done at the end of Song::execute/revertOperationGroup2().
3892       // NOTE: Routes:
3893       // Routes are added in the PendingOperationItem::AddTrack section of PendingOperationItem::executeRTStage().
3894 }
3895 
3896 //void writeStringToFile(FILE *filePointer, const char *writeString)
3897 //{
3898 //  if (MusEGlobal::debugMsg)
3899 //    std::cout << writeString;
3900 //  fputs(writeString, filePointer);
3901 //}
3902 
3903 //---------------------------------------------------------
3904 //   removeTrackOperation
3905 //---------------------------------------------------------
3906 
removeTrackOperation(Track * track,PendingOperationList & ops)3907 void Song::removeTrackOperation(Track* track, PendingOperationList& ops)
3908 {
3909       ops.removeTrackPortCtrlEvents(track);
3910       void* sec_track_list = 0;
3911       switch(track->type()) {
3912             case Track::MIDI:
3913             case Track::DRUM:
3914                     sec_track_list = &_midis;
3915             break;
3916             case Track::WAVE:
3917                     sec_track_list = &_waves;
3918             break;
3919             case Track::AUDIO_OUTPUT:
3920                     sec_track_list = &_outputs;
3921             break;
3922             case Track::AUDIO_INPUT:
3923                     sec_track_list = &_inputs;
3924             break;
3925             case Track::AUDIO_GROUP:
3926                     sec_track_list = &_groups;
3927             break;
3928             case Track::AUDIO_AUX:
3929                     sec_track_list = &_auxs;
3930             break;
3931             case Track::AUDIO_SOFTSYNTH:
3932             {
3933                   SynthI* s = static_cast<SynthI*>(track);
3934                   iMidiInstrument imi = midiInstruments.find(s);
3935                   if(imi != midiInstruments.end())
3936                     ops.add(PendingOperationItem(&midiInstruments, imi, PendingOperationItem::DeleteMidiInstrument));
3937 
3938                   iMidiDevice imd = MusEGlobal::midiDevices.find(s);
3939                   if(imd != MusEGlobal::midiDevices.end())
3940                     ops.add(PendingOperationItem(&MusEGlobal::midiDevices, imd, PendingOperationItem::DeleteMidiDevice));
3941 
3942                   if(s->midiPort() != -1)
3943                   {
3944                     // synthi is attached
3945                     // Oops, hey this was wrong before, should have been zero.
3946                     MusEGlobal::audio->msgSetMidiDevice(&MusEGlobal::midiPorts[s->midiPort()], 0);
3947                   }
3948 
3949                   sec_track_list = &_synthIs;
3950             }
3951             break;
3952       }
3953 
3954       ops.add(PendingOperationItem(&_tracks, track, PendingOperationItem::DeleteTrack, sec_track_list));
3955 
3956       // NOTE: Routes:
3957       // Routes are removed in the PendingOperationItem::DeleteTrack section of PendingOperationItem::executeRTStage().
3958 }
3959 
3960 //---------------------------------------------------------
3961 //   restartRecording
3962 //   Called from gui thread only.
3963 //---------------------------------------------------------
3964 
restartRecording(bool discard)3965 void Song::restartRecording(bool discard)
3966 {
3967   // FIXME After recording, it never makes it past here because recording has long since stopped.
3968   //       Although, it should work WHILE recording.
3969   //       We may need a track flag like 'justRecorded' or 'lastRecorded' something...
3970   if(!MusEGlobal::audio->isRecording() || !MusEGlobal::audio->isRunning())
3971     return;
3972 
3973   // Do not copy parts or controller graphs. When ASSIGN_STD_CTRLS is NOT included, it will
3974   //  copy just the standard controller current values, but not the graphs.
3975   // FIXME: Although we would like to copy plugins, that may get expensive after a while.
3976   //        So instead try to create a group track with the plugins and route the track and all
3977   //         the retake tracks through the group track.
3978   const int clone_flags = Track::ASSIGN_PROPERTIES | Track::ASSIGN_ROUTES | Track::ASSIGN_DEFAULT_ROUTES | Track::ASSIGN_DRUMLIST;
3979 
3980   MusECore::Undo operations;
3981 
3982   if(!discard)
3983   {
3984       MusEGlobal::audio->recordStop(true /*restart record*/, &operations);
3985       processAutomationEvents(&operations);
3986   }
3987 
3988   //clear all recorded midi events and wave files
3989   TrackNameFactory new_track_names;
3990 
3991   int idx_cnt = 0;
3992   for(size_t i = 0; i < _tracks.size(); i++)
3993   {
3994       Track *cTrk = _tracks[i];
3995       if(!cTrk->recordFlag())
3996         continue;
3997       Track *nTrk = NULL;
3998       if(!discard)
3999       {
4000         if(!new_track_names.genUniqueNames(cTrk->type(), cTrk->name(), 1))
4001           continue;
4002 
4003         nTrk = cTrk->clone(clone_flags);
4004         nTrk->setName(new_track_names.first());
4005 
4006         const int idx = _tracks.index(cTrk) + idx_cnt++;
4007         operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddTrack, idx + 1, nTrk));
4008         operations.push_back(UndoOp(UndoOp::SetTrackMute, cTrk, true));
4009         operations.push_back(UndoOp(UndoOp::SetTrackRecord, cTrk, false));
4010         setRecordFlag(nTrk, true, &operations);
4011       }
4012       if (cTrk->isMidiTrack())
4013       {
4014         if(discard)
4015         {
4016             ((MidiTrack *)cTrk)->mpevents.clear();
4017         }
4018       }
4019       else if (cTrk->type() == Track::WAVE)
4020       {
4021         if(discard)
4022         {
4023             ((WaveTrack*)cTrk)->setRecFile(NULL);
4024             ((WaveTrack*)cTrk)->resetMeter();
4025             ((WaveTrack*)cTrk)->prepareRecording();
4026         }
4027         else
4028         {
4029             ((WaveTrack*)nTrk)->prepareRecording();
4030         }
4031       }
4032   }
4033 
4034   applyOperationGroup(operations);
4035 
4036   setPos(Song::CPOS, MusEGlobal::audio->getStartRecordPos());
4037   //MusEGlobal::audioDevice->startTransport();
4038 }
4039 
4040 
informAboutNewParts(const std::map<const Part *,std::set<const Part * >> & param)4041 void Song::informAboutNewParts(const std::map< const Part*, std::set<const Part*> >& param)
4042 {
4043   emit newPartsCreated(param);
4044 }
4045 
informAboutNewParts(const Part * orig,const Part * p1,const Part * p2,const Part * p3,const Part * p4,const Part * p5,const Part * p6,const Part * p7,const Part * p8,const Part * p9)4046 void Song::informAboutNewParts(const Part* orig, const Part* p1, const Part* p2, const Part* p3, const Part* p4, const Part* p5, const Part* p6, const Part* p7, const Part* p8, const Part* p9)
4047 {
4048   std::map<const Part*, std::set<const Part*> > temp;
4049 
4050   temp[orig].insert(p1);
4051   temp[orig].insert(p2);
4052   temp[orig].insert(p3);
4053   temp[orig].insert(p4);
4054   temp[orig].insert(p5);
4055   temp[orig].insert(p6);
4056   temp[orig].insert(p7);
4057   temp[orig].insert(p8);
4058   temp[orig].insert(p9);
4059   temp[orig].erase(static_cast<const Part*>(NULL));
4060   temp[orig].erase(orig);
4061 
4062   informAboutNewParts(temp);
4063 }
4064 
4065 //---------------------------------------------------------
4066 //   StretchList operations
4067 //---------------------------------------------------------
4068 
stretchModifyOperation(StretchList * stretch_list,StretchListItem::StretchEventType type,double value,PendingOperationList & ops) const4069 void Song::stretchModifyOperation(
4070   StretchList* stretch_list, StretchListItem::StretchEventType type, double value, PendingOperationList& ops) const
4071 {
4072   ops.add(PendingOperationItem(type, stretch_list, value, PendingOperationItem::ModifyStretchListRatio));
4073 }
4074 
stretchListAddOperation(StretchList * stretch_list,StretchListItem::StretchEventType type,MuseFrame_t frame,double value,PendingOperationList & ops) const4075 void Song::stretchListAddOperation(
4076   StretchList* stretch_list, StretchListItem::StretchEventType type, MuseFrame_t frame, double value, PendingOperationList& ops) const
4077 {
4078   iStretchListItem ie = stretch_list->find(frame);
4079   if(ie != stretch_list->end())
4080     ops.add(PendingOperationItem(type, stretch_list, ie, frame, value, PendingOperationItem::ModifyStretchListRatioAt));
4081   else
4082     ops.add(PendingOperationItem(type, stretch_list, frame, value, PendingOperationItem::AddStretchListRatioAt));
4083 }
4084 
stretchListDelOperation(StretchList * stretch_list,int types,MuseFrame_t frame,PendingOperationList & ops) const4085 void Song::stretchListDelOperation(
4086   StretchList* stretch_list, int types, MuseFrame_t frame, PendingOperationList& ops) const
4087 {
4088   // Do not delete the item at zeroth frame.
4089   if(frame == 0)
4090     return;
4091 
4092   iStretchListItem e = stretch_list->find(frame);
4093   if (e == stretch_list->end()) {
4094         ERROR_TIMESTRETCH(stderr, "Song::stretchListDelOperation frame:%ld not found\n", frame);
4095         return;
4096         }
4097   PendingOperationItem poi(types, stretch_list, e, PendingOperationItem::DeleteStretchListRatioAt);
4098   // NOTE: Deletion is done in post-RT stage 3.
4099   ops.add(poi);
4100 }
4101 
stretchListModifyOperation(StretchList * stretch_list,StretchListItem::StretchEventType type,MuseFrame_t frame,double value,PendingOperationList & ops) const4102 void Song::stretchListModifyOperation(
4103   StretchList* stretch_list, StretchListItem::StretchEventType type, MuseFrame_t frame, double value, PendingOperationList& ops) const
4104 {
4105   iStretchListItem ie = stretch_list->find(frame);
4106   if(ie == stretch_list->end()) {
4107         ERROR_TIMESTRETCH(stderr, "Song::stretchListModifyOperation frame:%ld not found\n", frame);
4108         return;
4109         }
4110   ops.add(PendingOperationItem(type, stretch_list, ie, frame, value, PendingOperationItem::ModifyStretchListRatioAt));
4111 }
4112 
setAudioConvertersOfflineOperation(bool isOffline)4113 void Song::setAudioConvertersOfflineOperation(
4114   bool isOffline
4115   )
4116 {
4117   WaveTrackList* wtl = waves();
4118   if(wtl->empty())
4119     return;
4120 
4121   PendingOperationList ops;
4122 
4123   AudioConverterSettingsGroup* settings;
4124   bool isLocalSettings;
4125   bool doStretch;
4126   bool doResample;
4127   AudioConverterSettings::ModeType cur_mode;
4128   AudioConverterPluginI* cur_converter;
4129   AudioConverterPluginI* converter;
4130   const WaveTrack* wt;
4131   const PartList* pl;
4132   const Part* pt;
4133   ciPart pl_end;
4134   ciEvent el_end;
4135   SndFileR sndfile;
4136   ciWaveTrack wtl_end = wtl->cend();
4137   for(ciWaveTrack iwt = wtl->cbegin(); iwt != wtl_end; ++iwt)
4138   {
4139     wt = *iwt;
4140     pl = wt->cparts();
4141     pl_end = pl->cend();
4142     for(ciPart ip = pl->cbegin(); ip != pl_end; ++ip)
4143     {
4144       pt = ip->second;
4145       const EventList& el = pt->events();
4146       el_end = el.end();
4147       for(ciEvent ie = el.cbegin(); ie != el_end; ++ie)
4148       {
4149         const Event& e = ie->second;
4150         sndfile = e.sndFile();
4151         //if(sndfile.isNull())
4152         //  continue;
4153 
4154         // Check if we are to use any converters at all.
4155         if(!sndfile.useConverter())
4156           continue;
4157 
4158         // Check if the current realtime converter is already in offline mode.
4159         cur_converter = sndfile.staticAudioConverter(AudioConverterSettings::RealtimeMode);
4160         if(cur_converter)
4161         {
4162           cur_mode = cur_converter->mode();
4163           if((isOffline && cur_mode == AudioConverterSettings::OfflineMode) ||
4164             (!isOffline && cur_mode == AudioConverterSettings::RealtimeMode))
4165             continue;
4166         }
4167 
4168         settings = sndfile.audioConverterSettings()->useSettings() ?
4169           sndfile.audioConverterSettings() : MusEGlobal::defaultAudioConverterSettings;
4170         isLocalSettings = sndfile.audioConverterSettings()->useSettings();
4171 
4172         doStretch = sndfile.isStretched();
4173         doResample = sndfile.isResampled();
4174 
4175         // For offline mode, we COULD create a third converter just for it, apart from the main
4176         //  and UI converters. But our system doesn't have a third converter (yet) - and it may
4177         //  or may not get one, we'll see. Still, the operation supports setting it, in case.
4178         // So instead, in offline mode we switch out the main converter for one with with offline settings.
4179         converter = sndfile.setupAudioConverter(
4180           settings,
4181           MusEGlobal::defaultAudioConverterSettings,
4182           isLocalSettings,
4183           isOffline ?
4184             AudioConverterSettings::OfflineMode :
4185             AudioConverterSettings::RealtimeMode,
4186           doResample,
4187           doStretch);
4188 
4189           // No point if there's already no converter.
4190           if(!converter && !cur_converter)
4191             continue;
4192 
4193           // REMOVE Tim. samplerate. Added. Diagnostics.
4194           fprintf(stderr, "Song::setAudioConvertersOfflineOperation Setting sndfile:%s to isOffline:%d\n",
4195                   sndfile.name().toLocal8Bit().constData(), isOffline);
4196 
4197           ops.add(PendingOperationItem(
4198             sndfile,
4199             converter,   // Main converter.
4200             PendingOperationItem::SetAudioConverterOfflineMode));
4201       }
4202     }
4203   }
4204 
4205   MusEGlobal::audio->msgExecutePendingOperations(ops, true);
4206 }
4207 
modifyAudioConverterSettingsOperation(SndFileR sndfile,AudioConverterSettingsGroup * settings,AudioConverterSettingsGroup * defaultSettings,bool isLocalSettings,PendingOperationList & ops) const4208 void Song::modifyAudioConverterSettingsOperation(
4209   SndFileR sndfile,
4210   AudioConverterSettingsGroup* settings,
4211   AudioConverterSettingsGroup* defaultSettings,
4212   bool isLocalSettings,
4213   PendingOperationList& ops
4214   ) const
4215 {
4216   if(!sndfile.useConverter())
4217     return;
4218   const bool isOffline = sndfile.isOffline();
4219   const bool doStretch = sndfile.isStretched();
4220   const bool doResample = sndfile.isResampled();
4221   // For offline mode, we COULD create a third converter just for it, apart from the main
4222   //  and UI converters. But our system doesn't have a third converter (yet) - and it may
4223   //  or may not get one, we'll see. Still, the operation supports setting it, in case.
4224   // So instead, in offline mode we switch out the main converter for one with with offline settings.
4225   AudioConverterPluginI* converter = sndfile.setupAudioConverter(
4226     settings,
4227     defaultSettings,
4228     isLocalSettings,
4229     isOffline ?
4230       AudioConverterSettings::OfflineMode :
4231       AudioConverterSettings::RealtimeMode,
4232     doResample,
4233     doStretch);
4234 
4235   AudioConverterPluginI* converterUI = sndfile.setupAudioConverter(
4236     settings,
4237     defaultSettings,
4238     isLocalSettings,
4239     AudioConverterSettings::GuiMode,
4240     doResample,
4241     doStretch);
4242 
4243 //   if(!converter && !converterUI)
4244 //     return;
4245 
4246   // We want to change the settings, and the converters if necessary...
4247   ops.add(PendingOperationItem(
4248     sndfile,
4249     settings,
4250     PendingOperationItem::ModifyLocalAudioConverterSettings));
4251 
4252   ops.add(PendingOperationItem(
4253     sndfile,
4254     converter,   // Main converter.
4255     converterUI, // UI converter.
4256     PendingOperationItem::ModifyLocalAudioConverter));
4257 }
4258 
modifyAudioConverterOperation(SndFileR sndfile,PendingOperationList & ops,bool doResample,bool doStretch) const4259 void Song::modifyAudioConverterOperation(
4260   SndFileR sndfile,
4261   PendingOperationList& ops,
4262   bool doResample,
4263   bool doStretch) const
4264 {
4265   if(!sndfile.useConverter())
4266     return;
4267   const bool isOffline = sndfile.isOffline();
4268   AudioConverterSettingsGroup* settings = sndfile.audioConverterSettings()->useSettings() ?
4269     sndfile.audioConverterSettings() : MusEGlobal::defaultAudioConverterSettings;
4270 
4271   const bool isLocalSettings = sndfile.audioConverterSettings()->useSettings();
4272 
4273   // For offline mode, we COULD create a third converter just for it, apart from the main
4274   //  and UI converters. But our system doesn't have a third converter (yet) - and it may
4275   //  or may not get one, we'll see. Still, the operation supports setting it, in case.
4276   // So instead, in offline mode we switch out the main converter for one with with offline settings.
4277   AudioConverterPluginI* converter = sndfile.setupAudioConverter(
4278     settings,
4279     MusEGlobal::defaultAudioConverterSettings,
4280     isLocalSettings,
4281     isOffline ?
4282       AudioConverterSettings::OfflineMode :
4283       AudioConverterSettings::RealtimeMode,
4284     doResample,
4285     doStretch);
4286 
4287   AudioConverterPluginI* converterUI = sndfile.setupAudioConverter(
4288     settings,
4289     MusEGlobal::defaultAudioConverterSettings,
4290     isLocalSettings,
4291     AudioConverterSettings::GuiMode,
4292     doResample,
4293     doStretch);
4294 
4295 //   if(!converter && !converterUI)
4296 //     return;
4297 
4298   ops.add(PendingOperationItem(
4299     sndfile,
4300     converter,   // Main converter.
4301     converterUI, // UI converter.
4302     PendingOperationItem::ModifyLocalAudioConverter));
4303 }
4304 
modifyStretchListOperation(SndFileR sndfile,int type,double value,PendingOperationList & ops) const4305 void Song::modifyStretchListOperation(SndFileR sndfile, int type, double value, PendingOperationList& ops) const
4306 {
4307   if(!sndfile.useConverter())
4308     return;
4309   ops.add(PendingOperationItem(type, sndfile.stretchList(), value, PendingOperationItem::ModifyStretchListRatio));
4310 }
4311 
addAtStretchListOperation(SndFileR sndfile,int type,MuseFrame_t frame,double value,PendingOperationList & ops) const4312 void Song::addAtStretchListOperation(SndFileR sndfile, int type, MuseFrame_t frame, double value, PendingOperationList& ops) const
4313 {
4314   if(!sndfile.useConverter())
4315     return;
4316   StretchList* sl = sndfile.stretchList();
4317   stretchListAddOperation(sl, StretchListItem::StretchEventType(type), frame, value, ops);
4318 
4319   bool wantStretch = false;
4320   bool wantResample = sndfile.sampleRateDiffers();
4321   bool wantPitch = false;
4322   const bool haveStretch = sndfile.isStretched();
4323   const bool haveResample = sndfile.isResampled() || wantResample;
4324   const bool havePitch = sndfile.isPitchShifted();
4325 
4326   //// If the requested value is anything other than 1.0, request converters.
4327   //if(value != 1.0)
4328   //{
4329     switch(type)
4330     {
4331       case StretchListItem::StretchEvent:
4332         wantStretch = true;
4333       break;
4334       case StretchListItem::SamplerateEvent:
4335         wantResample = true;
4336       break;
4337       case StretchListItem::PitchEvent:
4338         wantPitch = true;
4339       break;
4340     }
4341   //}
4342 
4343   if((wantStretch  && !haveStretch) ||
4344      (wantResample && !haveResample) ||
4345      (wantPitch    && !havePitch))
4346   {
4347     const bool doStretch  = wantStretch  ? true : haveStretch;
4348     const bool doResample = wantResample ? true : haveResample;
4349   //const bool doPitch    = wantPitch    ? true : havePitch;
4350 
4351     modifyAudioConverterOperation(sndfile, ops, doResample, doStretch);
4352   }
4353 }
4354 
delAtStretchListOperation(SndFileR sndfile,int types,MuseFrame_t frame,PendingOperationList & ops) const4355 void Song::delAtStretchListOperation(SndFileR sndfile, int types, MuseFrame_t frame, PendingOperationList& ops) const
4356 {
4357   if(!sndfile.useConverter())
4358     return;
4359   // Do not delete the item at zeroth frame.
4360   if(frame == 0)
4361     return;
4362 
4363   StretchList* sl = sndfile.stretchList();
4364   stretchListDelOperation(sl, types, frame, ops);
4365 
4366   StretchListInfo info =  sl->testDelListOperation(types, frame);
4367 
4368   const bool srdiffers = sndfile.sampleRateDiffers();
4369   const bool wantStretch  = info._isStretched;
4370   const bool wantResample = info._isResampled || srdiffers;
4371   const bool wantPitch    = info._isPitchShifted;
4372 
4373   const bool haveStretch  = sndfile.isStretched();
4374   const bool haveResample = sndfile.isResampled() || srdiffers;
4375   const bool havePitch    = sndfile.isPitchShifted();
4376 
4377   if((!wantStretch  && haveStretch) ||
4378      (!wantResample && haveResample) ||
4379      (!wantPitch    && havePitch))
4380   {
4381     const bool doStretch  = !wantStretch  ? false : haveStretch;
4382     const bool doResample = !wantResample ? false : haveResample;
4383   //const bool doPitch    = !wantPitch    ? false : havePitch;
4384 
4385     modifyAudioConverterOperation(sndfile, ops, doResample, doStretch);
4386   }
4387 }
4388 
modifyAtStretchListOperation(SndFileR sndfile,int type,MuseFrame_t frame,double value,PendingOperationList & ops) const4389 void Song::modifyAtStretchListOperation(SndFileR sndfile, int type, MuseFrame_t frame, double value, PendingOperationList& ops) const
4390 {
4391   if(!sndfile.useConverter())
4392     return;
4393   StretchList* sl = sndfile.stretchList();
4394   stretchListModifyOperation(sl, StretchListItem::StretchEventType(type), frame, value, ops);
4395 
4396   bool wantStretch = false;
4397   bool wantResample = sndfile.sampleRateDiffers();
4398   bool wantPitch = false;
4399   const bool haveStretch = sndfile.isStretched();
4400   const bool haveResample = sndfile.isResampled() || wantResample;
4401   const bool havePitch = sndfile.isPitchShifted();
4402 
4403   //// If the requested value is anything other than 1.0, request converters.
4404   //if(value != 1.0)
4405   //{
4406     switch(type)
4407     {
4408       case StretchListItem::StretchEvent:
4409         wantStretch = true;
4410       break;
4411       case StretchListItem::SamplerateEvent:
4412         wantResample = true;
4413       break;
4414       case StretchListItem::PitchEvent:
4415         wantPitch = true;
4416       break;
4417     }
4418   //}
4419 
4420   if((wantStretch  && !haveStretch) ||
4421      (wantResample && !haveResample) ||
4422      (wantPitch    && !havePitch))
4423   {
4424     const bool doStretch  = wantStretch  ? true : haveStretch;
4425     const bool doResample = wantResample ? true : haveResample;
4426   //const bool doPitch    = wantPitch    ? true : havePitch;
4427 
4428     modifyAudioConverterOperation(sndfile, ops, doResample, doStretch);
4429   }
4430 }
4431 
modifyDefaultAudioConverterSettingsOperation(AudioConverterSettingsGroup * settings,PendingOperationList & ops)4432 void Song::modifyDefaultAudioConverterSettingsOperation(AudioConverterSettingsGroup* settings,
4433                                                         PendingOperationList& ops)
4434 {
4435   // First, schedule the change to the actual default settings pointer variable.
4436   ops.add(PendingOperationItem(settings, PendingOperationItem::ModifyDefaultAudioConverterSettings));
4437 
4438   // Now, schedule changes to each wave event if necessary.
4439   // Note that at this point the above default change has not occurred yet,
4440   //  so we must tell it to use what the settings WILL BE, not what they are now.
4441   for(ciWaveTrack it = MusEGlobal::song->waves()->cbegin(); it != MusEGlobal::song->waves()->cend(); ++it)
4442   {
4443     const WaveTrack* wtrack = *it;
4444     for(ciPart ip = wtrack->cparts()->cbegin(); ip != wtrack->cparts()->cend(); ++ip)
4445     {
4446       const Part* part = ip->second;
4447       for(ciEvent ie = part->events().cbegin(); ie != part->events().cend(); ++ie)
4448       {
4449         const Event& e = ie->second;
4450         if(e.type() != Wave)
4451           continue;
4452         SndFileR sndfile = e.sndFile();
4453         if(!sndfile.useConverter())
4454           continue;
4455         const AudioConverterSettingsGroup* cur_ev_settings = sndfile.audioConverterSettings();
4456         // Is the event using its own local settings? Ignore.
4457         if(!cur_ev_settings || cur_ev_settings->useSettings())
4458           continue;
4459 
4460         const bool isOffline = sndfile.isOffline();
4461         const bool doStretch = sndfile.isStretched();
4462         const bool doResample = sndfile.isResampled();
4463         // For offline mode, we COULD create a third converter just for it, apart from the main
4464         //  and UI converters. But our system doesn't have a third converter (yet) - and it may
4465         //  or may not get one, we'll see. Still, the operation supports setting it, in case.
4466         // So instead, in offline mode we switch out the main converter for one with with offline settings.
4467         AudioConverterPluginI* converter = sndfile.setupAudioConverter(
4468           settings,
4469           settings,
4470           false,  // false = Default, non-local settings.
4471           isOffline ?
4472             AudioConverterSettings::OfflineMode :
4473             AudioConverterSettings::RealtimeMode,
4474           doResample,
4475           doStretch);
4476 
4477         AudioConverterPluginI* converterUI = sndfile.setupAudioConverter(
4478           settings,
4479           settings,
4480           false,  // false = Default, non-local settings.
4481           AudioConverterSettings::GuiMode,
4482           doResample,
4483           doStretch);
4484 
4485       //   if(!converter && !converterUI)
4486       //     return;
4487 
4488         // We only want to change the converters, if necessary.
4489         ops.add(PendingOperationItem(
4490           sndfile,
4491           converter,   // Main converter.
4492           converterUI, // UI converter.
4493           PendingOperationItem::ModifyLocalAudioConverter));
4494       }
4495     }
4496   }
4497 }
4498 
4499 //---------------------------------------------------------
4500 //   updateTransportPos
4501 //   called from GUI context
4502 // SPECIAL for tempo or master changes: In stop mode we want
4503 //  the transport to locate to the correct frame. In play mode
4504 //  we simply let the transport progress naturally but we 'fake'
4505 //  a new representation of transport position (_pos) in Audio::reSyncAudio()
4506 //  as part of the realtime part of the tempo change operation.
4507 ////// By now, our audio transport position (_pos) has the new tick and frame.
4508 // We need to seek AFTER any song changed slots are called in case widgets
4509 //  are removed etc. etc. before the posChanged signal is emitted when setPos()
4510 //  is called from the seek recognition.
4511 //---------------------------------------------------------
4512 
updateTransportPos(const SongChangedStruct_t & flags)4513 void Song::updateTransportPos(const SongChangedStruct_t& flags)
4514 {
4515   if(!MusEGlobal::audio->isPlaying() && (flags & (SC_TEMPO | SC_MASTER)))
4516   {
4517     //const MusECore::Pos ap = MusEGlobal::audio->tickAndFramePos();
4518     // Don't touch Audio::_pos, make a copy.
4519     //const MusECore::Pos ap = MusEGlobal::audio->pos();
4520 
4521     // Don't touch Audio::_pos, make a copy or take the tick.
4522     // Note that this is only tick accurate, not frame accurate,
4523     //  ie. it can only recalculate a new frame from the given tick.
4524     const MusECore::Pos p(MusEGlobal::audio->tickPos());
4525 
4526 //     // Don't touch the original, make a copy.
4527 //     const MusECore::Pos p(cPos());
4528 
4529     MusEGlobal::audioDevice->seekTransport(p.frame());
4530   }
4531 }
4532 
4533 //---------------------------------------------------------
4534 //   adjustMarkerListOperation
4535 //   Items between startPos and startPos + diff are removed.
4536 //   Items after startPos + diff are adjusted 'diff' number of ticks.
4537 //---------------------------------------------------------
4538 
adjustMarkerListOperation(MarkerList * markerlist,unsigned int startPos,int diff,PendingOperationList & ops)4539 bool Song::adjustMarkerListOperation(MarkerList* markerlist, unsigned int startPos, int diff, PendingOperationList& ops)
4540 {
4541   if(!markerlist || markerlist->empty() || diff == 0)
4542     return false;
4543 
4544   MarkerList* new_markerlist = new MarkerList();
4545   for(ciMarker i = markerlist->begin(); i != markerlist->end(); ++i)
4546   {
4547     const Marker& m = i->second;
4548     unsigned int tick = m.tick();
4549     if(tick >= startPos)
4550     {
4551       if(tick >= startPos + diff)
4552       {
4553         // Grab a copy but with a new ID.
4554         Marker newMarker = m.copy();
4555         newMarker.setTick(tick - diff);
4556         new_markerlist->add(newMarker);
4557       }
4558     }
4559     else
4560     {
4561       // Grab a copy but with a new ID.
4562       new_markerlist->add(m.copy());
4563     }
4564   }
4565 
4566   PendingOperationItem poi(markerlist, new_markerlist, PendingOperationItem::ModifyMarkerList);
4567   ops.add(poi);
4568 
4569   return true;
4570 }
4571 
4572 //---------------------------------------------------------
4573 //   processTrackAutomationEvents
4574 //---------------------------------------------------------
4575 
processTrackAutomationEvents(AudioTrack * atrack,Undo * operations)4576 void Song::processTrackAutomationEvents(AudioTrack *atrack, Undo* operations)
4577 {
4578   const AutomationType atype = atrack->automationType();
4579   if(atype != AUTO_TOUCH && atype != AUTO_WRITE)
4580     return;
4581 
4582   // Use either the supplied operations list or a local one.
4583   Undo ops;
4584   Undo& opsr = operations ? (*operations) : ops;
4585 
4586   CtrlListList *cll =  atrack->controller();
4587   CtrlRecList *crl = atrack->recEvents();
4588   for(ciCtrlList icl = cll->cbegin(); icl != cll->cend(); ++icl)
4589   {
4590     CtrlList* cl = icl->second;
4591     CtrlList& clr = *icl->second;
4592     int id = cl->id();
4593 
4594     // Were there any recorded events for this controller?
4595     bool do_it = false;
4596     for(ciCtrlRec icr = crl->cbegin(); icr != crl->cend(); ++icr)
4597     {
4598       if(icr->id == id)
4599       {
4600         do_it = true;
4601         break;
4602       }
4603     }
4604     if(!do_it)
4605       continue;
4606 
4607     // The Undo system will take 'ownership' of these and delete them at the appropriate time.
4608     CtrlList* erased_list_items = new CtrlList(clr, CtrlList::ASSIGN_PROPERTIES);
4609     CtrlList* added_list_items = new CtrlList(clr, CtrlList::ASSIGN_PROPERTIES);
4610 
4611     // Remove old events from record region.
4612     if(atype == AUTO_WRITE)
4613     {
4614       int start = MusEGlobal::audio->getStartRecordPos().frame();
4615       int end   = MusEGlobal::audio->getEndRecordPos().frame();
4616       iCtrl   s = cl->lower_bound(start);
4617       iCtrl   e = cl->lower_bound(end);
4618       erased_list_items->insert(s, e);
4619     }
4620     else
4621     {  // type AUTO_TOUCH
4622       for(ciCtrlRec icr = crl->cbegin(); icr != crl->cend(); ++icr)
4623       {
4624         // Don't bother looking for start, it's OK, just take the first one.
4625         // Needed for mousewheel and paging etc.
4626         if(icr->id != id)
4627           continue;
4628 
4629         int start = icr->frame;
4630 
4631         if(icr == crl->cend())
4632         {
4633           int end = MusEGlobal::audio->getEndRecordPos().frame();
4634           iCtrl s = cl->lower_bound(start);
4635           iCtrl e = cl->lower_bound(end);
4636           erased_list_items->insert(s, e);
4637           break;
4638         }
4639 
4640         ciCtrlRec icrlast = icr;
4641         ++icr;
4642         for(; ; ++icr)
4643         {
4644           if(icr == crl->cend())
4645           {
4646             int end = icrlast->frame;
4647             iCtrl s = cl->lower_bound(start);
4648             iCtrl e = cl->lower_bound(end);
4649             erased_list_items->insert(s, e);
4650             break;
4651           }
4652 
4653           if(icr->id == id && icr->type == ARVT_STOP)
4654           {
4655             int end = icr->frame;
4656             iCtrl s = cl->lower_bound(start);
4657             iCtrl e = cl->lower_bound(end);
4658             erased_list_items->insert(s, e);
4659             break;
4660           }
4661 
4662           if(icr->id == id)
4663             icrlast = icr;
4664         }
4665         if(icr == crl->end())
4666               break;
4667       }
4668     }
4669 
4670     // Extract all recorded events for controller "id"
4671     //  from CtrlRecList and put into new_list.
4672     for(ciCtrlRec icr = crl->cbegin(); icr !=crl->cend(); ++icr)
4673     {
4674           if(icr->id == id)
4675           {
4676                 // Must optimize these types otherwise multiple vertices appear on flat straight lines in the graphs.
4677                 CtrlValueType vtype = cl->valueType();
4678                 if(!cl->empty() && (cl->mode() == CtrlList::DISCRETE || vtype == VAL_BOOL || vtype == VAL_INT))
4679                 {
4680                   iCtrl icl_prev = cl->lower_bound(icr->frame);
4681                   if(icl_prev != cl->begin())
4682                     --icl_prev;
4683                   if(icl_prev->second.val == icr->val)
4684                     continue;
4685                 }
4686                 // Now add the value.
4687                 added_list_items->add(icr->frame, icr->val);
4688           }
4689     }
4690 
4691     if(erased_list_items->empty() && added_list_items->empty())
4692     {
4693       delete erased_list_items;
4694       delete added_list_items;
4695     }
4696     else
4697       opsr.push_back(UndoOp(UndoOp::ModifyAudioCtrlValList, cll, erased_list_items, added_list_items));
4698   }
4699 
4700   // Done with the recorded automation event list. Clear it.
4701   crl->clear();
4702 
4703   if(!operations)
4704     MusEGlobal::song->applyOperationGroup(ops);
4705 }
4706 
setRecMode(int val)4707 void Song::setRecMode(int val) {
4708     _recMode = val;
4709     emit recModeChanged(val);
4710 }
4711 
setCycleMode(int val)4712 void Song::setCycleMode(int val) {
4713     _cycleMode = val;
4714     emit cycleModeChanged(val);
4715 }
4716 
4717 } // namespace MusECore
4718