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