1 //========================================================= 2 // MusE 3 // Linux Music Editor 4 // $Id: song.h,v 1.35.2.25 2009/12/15 03:39:58 terminator356 Exp $ 5 // 6 // (C) Copyright 1999/2000 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 #ifndef __SONG_H__ 25 #define __SONG_H__ 26 27 #include <QObject> 28 #include <QStringList> 29 #include <QFont> 30 31 #include <map> 32 #include <set> 33 #include <list> 34 35 #include "type_defs.h" 36 #include "pos.h" 37 #include "globaldefs.h" 38 #include "tempo.h" 39 #include "sig.h" 40 #include "synth.h" 41 #include "operations.h" 42 #include "lock_free_buffer.h" 43 #include "mpevent.h" 44 #include "wave.h" 45 46 47 #define IPC_EVENT_FIFO_SIZE ( std::min( std::max(size_t(256), size_t(MusEGlobal::segmentSize * 16)), size_t(16384)) ) 48 49 #include "time_stretch.h" 50 #include "audio_convert/audio_converter_settings_group.h" 51 52 53 // Forward declarations: 54 class QAction; 55 class QMenu; 56 57 namespace MusECore { 58 59 class Event; 60 class Xml; 61 class Track; 62 class Part; 63 class PartList; 64 class EventList; 65 class MarkerList; 66 class Marker; 67 class Route; 68 struct AudioMsg; 69 class MidiPart; 70 class Undo; 71 struct UndoOp; 72 class UndoList; 73 74 #define REC_NOTE_FIFO_SIZE 16 75 76 //--------------------------------------------------------- 77 // Song 78 //--------------------------------------------------------- 79 80 class Song : public QObject { 81 Q_OBJECT 82 83 public: 84 enum POSTYPE { CPOS = 0, LPOS, RPOS }; 85 enum FollowMode { NO, JUMP, CONTINUOUS }; 86 enum { REC_OVERDUP, REC_REPLACE }; 87 enum { CYCLE_NORMAL, CYCLE_MIX, CYCLE_REPLACE }; 88 enum { MARKER_CUR }; 89 enum OperationType { 90 // Execute the operation only, the operation is not un-doable. No song update. 91 OperationExecute, 92 // Execute the operation only, the operation is not un-doable. Song is updated. 93 OperationExecuteUpdate, 94 // Execute the operation, the operation is un-doable, 95 // and do not 'start' and 'end' the undo mode. No song update. 96 OperationUndoable, 97 // Execute the operation, the operation is un-doable, 98 // and do not 'start' and 'end' the undo mode. Song is updated. 99 OperationUndoableUpdate, 100 // Execute the operation, the operation is un-doable, 101 // and 'start' and 'end' the undo mode. Song is updated. 102 OperationUndoMode 103 }; 104 105 private: 106 // fifo for note-on events 107 // - this events are read by the heart beat interrupt 108 // - used for single step recording in midi editors 109 110 int recNoteFifo[REC_NOTE_FIFO_SIZE]; 111 volatile int noteFifoSize; 112 int noteFifoWindex; 113 int noteFifoRindex; 114 115 volatile char rcCC = -1; // CC remote control 116 117 TempoFifo _tempoFifo; // External tempo changes, processed in heartbeat. 118 119 MusECore::SongChangedStruct_t updateFlags; 120 121 TrackList _tracks; // tracklist as seen by arranger 122 MidiTrackList _midis; 123 WaveTrackList _waves; 124 InputList _inputs; // audio input ports 125 OutputList _outputs; // audio output ports 126 GroupList _groups; // mixer groups 127 AuxList _auxs; // aux sends 128 SynthIList _synthIs; 129 130 UndoList* undoList; 131 UndoList* redoList; 132 // New items created in GUI thread awaiting addition in audio thread. 133 PendingOperationList pendingOperations; 134 135 Pos pos[3]; 136 Pos _vcpos; // virtual CPOS (locate in progress) 137 MarkerList* _markerList; 138 139 float _fCpuLoad; 140 float _fDspLoad; 141 long _xRunsCount; 142 143 // Receives events from any threads. For now, specifically for creating new 144 // controllers in the gui thread and adding them safely to the controller lists. 145 LockFreeMPSCRingBuffer<MidiPlayEvent> *_ipcInEventBuffers; 146 LockFreeMPSCRingBuffer<MidiPlayEvent> *_ipcOutEventBuffers; 147 148 bool loopFlag; 149 bool punchinFlag; 150 bool punchoutFlag; 151 bool recordFlag; 152 bool soloFlag; 153 int _recMode; 154 int _cycleMode; 155 Pos _startPlayPosition; 156 bool _click; 157 bool _quantize; 158 unsigned _len; // song len in ticks 159 FollowMode _follow; 160 int _globalPitchShift; 161 void readMarker(Xml&); 162 163 QString songInfoStr; // contains user supplied song information, stored in song file. 164 bool showSongInfo; 165 166 // Private: Update the audio device's real transport position after a tempo or master change for ex. 167 void updateTransportPos(const SongChangedStruct_t& flags); 168 169 // These are called from non-RT thread operations execution stage 1. 170 void insertTrackOperation(Track* track, int idx, PendingOperationList& ops); 171 bool adjustMarkerListOperation(MarkerList* markerlist, unsigned int startPos, int diff, PendingOperationList& ops); 172 void removeTrackOperation(Track* track, PendingOperationList& ops); 173 bool addEventOperation(const Event&, Part*, bool do_port_ctrls = true, bool do_clone_port_ctrls = true); 174 // Special: Returns the real actual event to be deleted found in the event lists. 175 // This way even a modified event can be passed in, and as long as 176 // the ID AND position values match it will find and return the ORIGINAL event. 177 // Useful for example for passing a pre-modified event to a DeleteEvent or ModyfyEvent operation 178 // in the Undo system, and it will automatically replace the Undo item's event with 179 // the real one returned here. (Otherwise when the user hits 'undo' it would restore 180 // that modified passed-in event sitting in the Undo item. That's not the right event!) 181 Event changeEventOperation(const Event& oldEvent, const Event& newEvent, 182 Part*, bool do_port_ctrls = true, bool do_clone_port_ctrls = true); 183 Event deleteEventOperation(const Event&, Part*, bool do_port_ctrls = true, bool do_clone_port_ctrls = true); 184 185 void checkSongSampleRate(); 186 187 void normalizePart(MusECore::Part *part); 188 189 // Fills operations if given, otherwise creates and executes its own operations list. 190 void processTrackAutomationEvents(AudioTrack *atrack, Undo* operations = 0); 191 192 public: 193 Song(const char* name = 0); 194 ~Song(); 195 196 /** It is not allowed nor checked(!) to AddPart a clone, and 197 * to AddEvent/DeleteEvent/ModifyEvent/SelectEvent events which 198 * would need to be replicated to the newly added clone part! 199 */ 200 // group may be changed! prepareOperationGroup is called on group! 201 // Sender can be set to the caller object and used by it 202 // to ignore self-generated songChanged signals. 203 // The songChanged structure will contain this pointer. 204 bool applyOperationGroup(Undo& group, OperationType type = OperationUndoMode, void* sender = 0); 205 bool applyOperation(const UndoOp& op, OperationType type = OperationUndoMode, void* sender = 0); 206 207 /** this sends emits a signal to each MidiEditor or whoever is interested. 208 * For each part which is 1) opened in this MidiEditor and 2) which is 209 * a key in this map, the Editors shall no more edit this part, but instead 210 * all parts in the_map[old_part] (which is a std::set<Part*>) 211 */ 212 void informAboutNewParts(const std::map< const Part*, std::set<const Part*> >&); 213 /** this sends emits a signal to each MidiEditor or whoever is interested. 214 * For each part which is 1) opened in this MidiEditor and 2) which is 215 * a key in this map, the Editors shall no more edit this part, but instead 216 * all parts in the_map[old_part] (which is a std::set<Part*>) 217 * this is a special case of the general function, which only replaces one part 218 * by up to nine different. 219 */ 220 void informAboutNewParts(const Part* orig, const Part* p1, const Part* p2=NULL, const Part* p3=NULL, const Part* p4=NULL, const Part* p5=NULL, const Part* p6=NULL, const Part* p7=NULL, const Part* p8=NULL, const Part* p9=NULL); 221 222 void putEvent(int pv); 223 void putEventCC(char cc); 224 void endMsgCmd(); 225 void processMsg(AudioMsg* msg); 226 setFollow(FollowMode m)227 void setFollow(FollowMode m) { _follow = m; } follow()228 FollowMode follow() const { return _follow; } 229 230 bool dirty; 231 WaveTrack* bounceTrack; 232 AudioOutput* bounceOutput; 233 void updatePos(); 234 235 void read(Xml&, bool isTemplate=false); 236 void write(int, Xml&) const; 237 // void writeFont(int level, Xml& xml, const char* name, 238 // const QFont& font) const; 239 // QFont readFont(Xml& xml, const char* name); 240 // After a song file is successfully loaded with read(), some items which 241 // reference other items in the file need to be resolved. (Mixer strip configs etc.) 242 void resolveSongfileReferences(); 243 getSongInfo()244 QString getSongInfo() { return songInfoStr; } setSongInfo(QString info,bool show)245 void setSongInfo(QString info, bool show) { songInfoStr = info; showSongInfo = show; } showSongInfoOnStartup()246 bool showSongInfoOnStartup() { return showSongInfo; } 247 248 // If clear_all is false, it will not touch things like midi ports. 249 void clear(bool signal, bool clear_all = true); 250 void cleanupForQuit(); 251 globalPitchShift()252 int globalPitchShift() const { return _globalPitchShift; } setGlobalPitchShift(int val)253 void setGlobalPitchShift(int val) { _globalPitchShift = val; } 254 255 // REMOVE Tim. samplerate. Added. TODO 256 #if 0 257 // Set the project's sample rate. This can be different than the current actual sample rate. 258 void setProjectSampleRate(int rate); 259 // Ratio of the project's sample rate to the current audio sample rate. 260 double projectSampleRateRatio() const; 261 // Whether the project's sample rate ratio is exactly 1. 262 bool projectSampleRateDiffers() const; 263 // This scales the sample rate, by scaling the frame values of all objects or properties that use or store 264 // a value in 'frames', such as wave parts/events position and length, and audio automation graphs. 265 // It does NOT resample audio files, that is another function. 266 // Caution: Slight rounding errors can degrade timing accuracy, especially if repeated scalings are done. 267 void convertProjectSampleRate(int newRate); 268 #endif 269 270 //----------------------------------------- 271 // Marker 272 //----------------------------------------- 273 marker()274 MarkerList* marker() const { return _markerList; } 275 // For wholesale swapping of a new list. Takes ownership of the given list. setMarkerList(MarkerList * ml)276 void setMarkerList(MarkerList* ml) { _markerList = ml; } 277 void addMarker(const QString& s, unsigned t, bool lck); 278 void addMarker(const QString& s, const Pos& p); 279 iMarker getMarkerAt(unsigned t); 280 void removeMarker(const Marker&); 281 void setMarkerName(const Marker&, const QString&); 282 void setMarkerPos(const Marker&, const Pos& pos); 283 void setMarkerLock(const Marker&, bool); 284 285 //----------------------------------------- 286 // transport 287 //----------------------------------------- 288 289 void setPos(POSTYPE posType, const Pos&, bool sig = true, bool isSeek = true, 290 bool adjustScrollbar = false, bool force = false); cPos()291 const Pos& cPos() const { return pos[0]; } lPos()292 const Pos& lPos() const { return pos[1]; } rPos()293 const Pos& rPos() const { return pos[2]; } cpos()294 unsigned cpos() const { return pos[0].tick(); } vcpos()295 unsigned vcpos() const { return _vcpos.tick(); } vcPos()296 const Pos& vcPos() const { return _vcpos; } lpos()297 unsigned lpos() const { return pos[1].tick(); } rpos()298 unsigned rpos() const { return pos[2].tick(); } 299 loop()300 bool loop() const { return loopFlag; } record()301 bool record() const { return recordFlag; } punchin()302 bool punchin() const { return punchinFlag; } punchout()303 bool punchout() const { return punchoutFlag; } 304 void setRecMode(int val); recMode()305 int recMode() const { return _recMode; } 306 void setCycleMode(int val); cycleMode()307 int cycleMode() const { return _cycleMode; } click()308 bool click() const { return _click; } quantize()309 bool quantize() const { return _quantize; } 310 void setStopPlay(bool); 311 // Fills operations if given, otherwise creates and executes its own operations list. 312 void stopRolling(Undo* operations = 0); 313 void abortRolling(); 314 cpuLoad()315 float cpuLoad() const { return _fCpuLoad; } dspLoad()316 float dspLoad() const { return _fDspLoad; } xRunsCount()317 long xRunsCount() const { return _xRunsCount; } 318 319 //----------------------------------------- 320 // access tempomap/MusEGlobal::sigmap (Mastertrack) 321 //----------------------------------------- 322 len()323 unsigned len() const { return _len; } 324 void setLen(unsigned l, bool do_update = true); // set songlen in ticks 325 int roundUpBar(int tick) const; 326 int roundUpBeat(int tick) const; 327 int roundDownBar(int tick) const; 328 void initLen(); 329 330 //----------------------------------------- 331 // event manipulations 332 //----------------------------------------- 333 334 void cmdAddRecordedWave(WaveTrack* track, Pos s, Pos e, Undo& operations); 335 void cmdAddRecordedEvents(MidiTrack*, const EventList&, unsigned, Undo& operations); 336 337 // May be called from GUI or audio thread. Also selects events in clone parts. Safe for now because audio/midi processing doesn't 338 // depend on it, and all calls to part altering functions from GUI are synchronized with (wait for) audio thread. 339 void selectEvent(Event&, Part*, bool select); 340 void selectAllEvents(Part*, bool select); // See selectEvent(). 341 342 void cmdChangeWave(const Event& original, const QString& tmpfile, unsigned sx, unsigned ex); 343 void remapPortDrumCtrlEvents(int mapidx, int newnote, int newchan, int newport); // called from GUI thread 344 // Adds or removes midi event controller cache values. 345 // Called from GUI thread 346 // add true: add events. false: remove events 347 // drum_tracks: Include drum tracks. midi_tracks: Include midi tracks. 348 // drum_ctls: Do drum (per-note) controller events. non_drum_ctls: Do non-drum controller events. 349 void changeMidiCtrlCacheEvents( 350 bool add, bool drum_tracks = true, bool midi_tracks = true, bool drum_ctls = true, bool non_drum_ctls = true); 351 addExternalTempo(const TempoRecEvent & e)352 void addExternalTempo(const TempoRecEvent& e) { _tempoFifo.put(e); } 353 354 //-------------------------------------------- 355 // Time-stretch / samplerate manipulations 356 //-------------------------------------------- 357 358 void stretchModifyOperation( 359 StretchList* stretch_list, StretchListItem::StretchEventType type, double value, 360 PendingOperationList& ops) const; 361 void stretchListAddOperation( 362 StretchList* stretch_list, StretchListItem::StretchEventType type, MuseFrame_t frame, 363 double value, PendingOperationList& ops) const; 364 void stretchListDelOperation( 365 StretchList* stretch_list, int types, MuseFrame_t frame, PendingOperationList& ops) const; 366 void stretchListModifyOperation( 367 StretchList* stretch_list, StretchListItem::StretchEventType type, MuseFrame_t frame, 368 double value, PendingOperationList& ops) const; 369 370 void setAudioConvertersOfflineOperation( 371 bool isOffline 372 ); 373 374 void modifyAudioConverterSettingsOperation( 375 SndFileR sndfile, 376 AudioConverterSettingsGroup* settings, 377 AudioConverterSettingsGroup* defaultSettings, 378 bool isLocalSettings, 379 PendingOperationList& ops 380 ) const; 381 382 void modifyAudioConverterOperation( 383 SndFileR sndfile, 384 PendingOperationList& ops, 385 bool doResample, 386 bool doStretch 387 ) const; 388 389 void modifyStretchListOperation( 390 SndFileR sndfile, int type, double value, PendingOperationList& ops) const; 391 void addAtStretchListOperation( 392 SndFileR sndfile, int type, MuseFrame_t frame, double value, PendingOperationList& ops) const; 393 void delAtStretchListOperation( 394 SndFileR sndfile, int types, MuseFrame_t frame, PendingOperationList& ops) const; 395 void modifyAtStretchListOperation( 396 SndFileR sndfile, int type, MuseFrame_t frame, double value, PendingOperationList& ops) const; 397 void modifyDefaultAudioConverterSettingsOperation( 398 AudioConverterSettingsGroup* settings, PendingOperationList& ops); 399 400 //----------------------------------------- 401 // part manipulations 402 //----------------------------------------- 403 404 void addPart(Part* part); 405 void removePart(Part* part); 406 void changePart(Part*, Part*); 407 408 void normalizeWaveParts(Part *partCursor = NULL); 409 410 //----------------------------------------- 411 // track manipulations 412 //----------------------------------------- 413 tracks()414 TrackList* tracks() { return &_tracks; } midis()415 MidiTrackList* midis() { return &_midis; } waves()416 WaveTrackList* waves() { return &_waves; } inputs()417 InputList* inputs() { return &_inputs; } outputs()418 OutputList* outputs() { return &_outputs; } groups()419 GroupList* groups() { return &_groups; } auxs()420 AuxList* auxs() { return &_auxs; } syntis()421 SynthIList* syntis() { return &_synthIs; } 422 423 Track* findTrack(const Part* part) const; 424 Track* findTrack(const QString& name) const; trackExists(Track * t)425 bool trackExists(Track* t) const { return _tracks.find(t) != _tracks.cend(); } 426 427 void setRecordFlag(Track*, bool val, Undo* operations = 0); 428 // This is a non- realtime safe operation mainly used when loading files, while the engine is paused or idle. 429 void insertTrack0(Track*, int idx); 430 431 // The currently selected track (in a multi-selection the last one selected), or null. selectedTrack()432 Track* selectedTrack() const { return _tracks.currentSelection(); } 433 // Total number of selected tracks. countSelectedTracks()434 int countSelectedTracks() const { return _tracks.countSelected(); } 435 // Selects or deselects all tracks. selectAllTracks(bool select)436 void selectAllTracks(bool select) 437 { 438 _tracks.selectAll(select); 439 if(!select) // Not essential, but if unselecting ALL tracks, clear the static counter. 440 Track::clearSelectionOrderCounter(); 441 } 442 443 void readRoute(Xml& xml); 444 void recordEvent(MidiTrack*, Event&); 445 // Enable all track and plugin controllers, and synth controllers if applicable, which are NOT in AUTO_WRITE mode. 446 void reenableTouchedControllers(); 447 void clearRecAutomation(bool clearList); 448 // Fills operations if given, otherwise creates and executes its own operations list. 449 void processAutomationEvents(Undo* operations = 0); 450 void processMasterRec(); 451 int execAutomationCtlPopup(AudioTrack*, const QPoint&, int); 452 int execMidiAutomationCtlPopup(MidiTrack*, MidiPart*, const QPoint&, int); 453 bool connectJackRoutes(const MusECore::Route& src, const MusECore::Route& dst, bool disconnect = false); 454 void connectAudioPorts(); 455 void connectMidiPorts(); connectAllPorts()456 void connectAllPorts() { connectAudioPorts(); connectMidiPorts(); } 457 void updateSoloStates(); 458 // Put an event into the IPC event ring buffer for the gui thread to process. Returns true on success. 459 // NOTE: Although the ring buffer is multi-writer, call this from audio thread only for now, unless 460 // you know what you are doing because the thread needs to ask whether the controller exists before 461 // calling, and that may not be safe from threads other than gui or audio. 462 bool putIpcInEvent(const MidiPlayEvent& ev); 463 // Put an event into the IPC event ring buffer for the audio thread to process. 464 // Called by gui thread only. Returns true on success. 465 bool putIpcOutEvent(const MidiPlayEvent& ev); 466 // Process any special IPC audio thread - to - gui thread messages. 467 // Called by gui thread only. Returns true on success. 468 bool processIpcInEventBuffers(); 469 // Process any special gui thread - to - IPC audio thread messages. 470 // Called by audio thread only. Returns true on success. 471 bool processIpcOutEventBuffers(); 472 473 //----------------------------------------- 474 // undo, redo, operation groups 475 //----------------------------------------- 476 477 // Sender can be set to the caller object and used by it 478 // to ignore self-generated songChanged signals. 479 // The songChanged structure will contain this pointer. 480 void startUndo(void* sender = 0); 481 void endUndo(MusECore::SongChangedStruct_t); 482 483 void executeOperationGroup1(Undo& operations); 484 void executeOperationGroup2(Undo& operations); 485 void executeOperationGroup3(Undo& operations); 486 void revertOperationGroup1(Undo& operations); 487 void revertOperationGroup2(Undo& operations); 488 void revertOperationGroup3(Undo& operations); 489 490 void addUndo(UndoOp i); 491 void setUndoRedoText(); 492 493 //----------------------------------------- 494 // Configuration 495 //----------------------------------------- 496 497 SynthI* createSynthI(const QString& sclass, const QString& uri, const QString& label = QString(), 498 Synth::Type type = Synth::SYNTH_TYPE_END, Track* insertAt = 0); 499 500 //----------------------------------------- 501 // Debug 502 //----------------------------------------- 503 504 void dumpMaster(); addUpdateFlags(MusECore::SongChangedStruct_t f)505 void addUpdateFlags(MusECore::SongChangedStruct_t f) { updateFlags |= f; } 506 507 //----------------------------------------- 508 // Python bridge related 509 //----------------------------------------- 510 #ifdef PYTHON_SUPPORT 511 virtual bool event (QEvent* e ); 512 #endif 513 514 public slots: 515 void seekTo(int tick); 516 // use allowRecursion with care! this could lock up muse if you 517 // aren't sure that your recursion will be finite! 518 void update(SongChangedStruct_t flags = SongChangedStruct_t(SC_EVERYTHING), 519 bool allowRecursion=false); 520 void beat(); 521 522 void undo(); 523 void redo(); 524 525 void setTempo(int t); 526 void setSig(int a, int b); 527 void setSig(const MusECore::TimeSignature&); setTempo(double tempo)528 void setTempo(double tempo) { setTempo(int(60000000.0/tempo)); } 529 530 void setMasterFlag(bool flag); getLoop()531 bool getLoop() { return loopFlag; } 532 void setLoop(bool f); 533 void setRecord(bool f, bool autoRecEnable = true); 534 void clearTrackRec(); 535 void setPlay(bool f); 536 void setStop(bool); 537 void forward(); 538 void rewindStart(); 539 void rewind(); 540 void setPunchin(bool f); 541 void setPunchout(bool f); 542 void setClick(bool val); 543 void setQuantize(bool val); 544 void panic(); 545 void seqSignal(int fd); 546 // Creates a track but does not add it to the track list, the caller must do that. 547 // The track name is not set and must be set by the caller. 548 // If setDefaults is true, adds default in/out routes/channels to the track. 549 Track* createTrack(Track::TrackType type, bool setDefaults = true); 550 Track* addTrack(Track::TrackType type, Track* insertAt = 0); 551 Track* addNewTrack(QAction* action, Track* insertAt = 0); 552 void duplicateTracks(Track* t = nullptr); setDirty()553 void setDirty() { emit sigDirty(); } 554 555 /* restarts recording from last start position 556 * if discard is true (default) then 557 * recording will start on existing tracks, 558 * else new copies of armed tracks will be created 559 * and current armed tracks will be muted and unarmed 560 * Called from gui thread only. */ 561 void restartRecording(bool discard = true); 562 563 signals: 564 void songChanged(MusECore::SongChangedStruct_t); 565 void posChanged(int, unsigned, bool); 566 void posChanged(int, const MusECore::Pos, bool); 567 void loopChanged(bool); 568 void recordChanged(bool); 569 void playChanged(bool); 570 void punchinChanged(bool); 571 void punchoutChanged(bool); 572 void clickChanged(bool); 573 void quantizeChanged(bool); 574 void markerChanged(int); 575 void midiNote(int pitch, int velo); 576 void controllerChanged(MusECore::Track*, int); 577 void newPartsCreated(const std::map< const MusECore::Part*, std::set<const MusECore::Part*> >&); 578 void sigDirty(); 579 void recModeChanged(int); 580 void cycleModeChanged(int); 581 }; 582 583 } // namespace MusECore 584 585 namespace MusEGlobal { 586 extern MusECore::Song* song; 587 } 588 589 #endif 590 591