// -*- c-basic-offset: 4 -*- /* Rosegarden A sequencer and musical notation editor. This program is Copyright 2000-2008 Guillaume Laurent , Chris Cannam , Richard Bown The moral right of the authors to claim authorship of this work has been asserted. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ #ifndef _COMPOSITION_H_ #define _COMPOSITION_H_ #include #include #include "FastVector.h" #include "RealTime.h" #include "Segment.h" #include "Track.h" #include "Configuration.h" #include "XmlExportable.h" #include "ColourMap.h" #include "TriggerSegment.h" #include "Marker.h" namespace Rosegarden { // We store tempo in quarter-notes per minute * 10^5 (hundred // thousandths of a quarter-note per minute). This means the maximum // tempo in a 32-bit integer is about 21400 qpm. We use a signed int // for compatibility with the Event integer type -- but note that we // use 0 (rather than -1) to indicate "tempo not set", by convention // (though see usage of target tempo in e.g. addTempoAtTime). typedef int tempoT; class Quantizer; class BasicQuantizer; class NotationQuantizer; /** * Composition contains a complete representation of a piece of music. * It is a container for multiple Segments, as well as any associated * non-Event data. * * The Composition owns the Segments it holds, and deletes them on * destruction. When Segments are removed, it will also delete them. */ class CompositionObserver; class Composition : public XmlExportable { friend class Track; // to call notifyTrackChanged() friend class Segment; // to call notifySegmentRepeatChanged() public: typedef std::multiset segmentcontainer; typedef segmentcontainer::iterator iterator; typedef segmentcontainer::const_iterator const_iterator; typedef std::map trackcontainer; typedef trackcontainer::iterator trackiterator; typedef trackcontainer::const_iterator trackconstiterator; typedef std::vector markercontainer; typedef markercontainer::iterator markeriterator; typedef markercontainer::const_iterator markerconstiterator; typedef std::set triggersegmentcontainer; typedef triggersegmentcontainer::iterator triggersegmentcontaineriterator; typedef triggersegmentcontainer::const_iterator triggersegmentcontainerconstiterator; typedef std::set recordtrackcontainer; typedef recordtrackcontainer::iterator recordtrackiterator; typedef recordtrackcontainer::const_iterator recordtrackconstiterator; Composition(); virtual ~Composition(); private: Composition(const Composition &); Composition &operator=(const Composition &); public: /** * Remove all Segments from the Composition and destroy them */ void clear(); /** * Return the absolute end time of the segment that ends last */ timeT getDuration() const; ////// // // START AND END MARKERS timeT getStartMarker() const { return m_startMarker; } timeT getEndMarker() const { return m_endMarker; } void setStartMarker(const timeT &sM); void setEndMarker(const timeT &eM); ////// // // INSTRUMENT & TRACK Track* getTrackById(TrackId track) const; Track* getTrackByPosition(int position) const; int getTrackPositionById(TrackId track) const; // -1 if not found trackcontainer& getTracks() { return m_tracks; } const trackcontainer& getTracks() const { return m_tracks; } // Reset id and position void resetTrackIdAndPosition(TrackId oldId, TrackId newId, int position); TrackId getMinTrackId() const; TrackId getMaxTrackId() const; const recordtrackcontainer &getRecordTracks() const { return m_recordTracks; } void setTrackRecording(TrackId track, bool recording); bool isTrackRecording(TrackId track) const; // Get and set Solo Track // TrackId getSelectedTrack() const { return m_selectedTrack; } void setSelectedTrack(TrackId track); // Are we soloing a Track? // bool isSolo() const { return m_solo; } void setSolo(bool value); unsigned int getNbTracks() const { return m_tracks.size(); } /** * Clear out the Track container */ void clearTracks(); /** * Insert a new Track. The Composition takes over ownership of * the track object. */ void addTrack(Track *track); /** * Delete a Track by index */ void deleteTrack(TrackId track); /** * Detach a Track (revert ownership of the Track object to the * caller). */ bool detachTrack(Track *track); /** * Get the highest running track id (generated and kept * through addTrack) */ TrackId getNewTrackId() const; ////// // // MARKERS markercontainer& getMarkers() { return m_markers; } const markercontainer& getMarkers() const { return m_markers; } /** * Add a new Marker. The Composition takes ownership of the * marker object. */ void addMarker(Marker *marker); /** * Detach a Marker (revert ownership of the Marker object to the * caller). */ bool detachMarker(Marker *marker); bool isMarkerAtPosition(timeT time) const; void clearMarkers(); ////// // // SEGMENT segmentcontainer& getSegments() { return m_segments; } const segmentcontainer& getSegments() const { return m_segments; } unsigned int getNbSegments() const { return m_segments.size(); } /** * Add a new Segment and return an iterator pointing to it * The inserted Segment is owned by the Composition object */ iterator addSegment(Segment*); /** * Delete the Segment pointed to by the specified iterator * * NOTE: The Segment is deleted from the Composition and * destroyed */ void deleteSegment(iterator); /** * Delete the Segment if it is part of the Composition * \return true if the Segment was found and deleted * * NOTE: The Segment is deleted from the composition and * destroyed */ bool deleteSegment(Segment*); /** * DO NOT USE THIS METHOD * * Set a Segment's start time while keeping the integrity of the * Composition multiset. * * The segment is removed and re-inserted from the composition * so the ordering is preserved. */ void setSegmentStartTime(Segment*, timeT); /** * Test whether a Segment exists in this Composition. */ bool contains(const Segment *); /** * Return an iterator pointing at the given Segment, or end() * if it does not exist in this Composition. */ iterator findSegment(const Segment *); /** * Remove the Segment if it is part of the Composition, * but do not destroy it (passing it to addSegment again * would restore it correctly). * \return true if the Segment was found and removed * * NOTE: Many of the Segment methods will fail if the * Segment is not in a Composition. You should not * expect to do anything meaningful with a Segment that * has been detached from the Composition in this way. */ bool detachSegment(Segment*); /** * Add a new Segment which has been "weakly detached" * * Like addSegment(), but doesn't send the segmentAdded signal * nor updating refresh statuses */ iterator weakAddSegment(Segment*); /** * Detach a segment which you're going to re-add (with weakAddSegment) * later. * Like detachSegment(), but without sending the segmentDeleted signal * nor updating refresh statuses. */ bool weakDetachSegment(Segment*); /** * Get the largest number of segments that "overlap" at any one * time on the given track. I have given this function a nice * long name to make it feel important. */ int getMaxContemporaneousSegmentsOnTrack(TrackId track) const; /** * Retrieve a "vertical" index for this segment within its track. * Currently this is based on studying the way that segments on * the track overlap and returning the lowest integer such that no * prior starting segment that overlaps with this one would use * the same integer. In future this could use proper voice * ordering. */ int getSegmentVoiceIndex(const Segment *) const; ////// // // TRIGGER SEGMENTS triggersegmentcontainer &getTriggerSegments() { return m_triggerSegments; } const triggersegmentcontainer &getTriggerSegments() const { return m_triggerSegments; } /** * Add a new trigger Segment with a given base pitch and base * velocity, and return its record. If pitch or velocity is -1, * it will be taken from the first note event in the segment */ TriggerSegmentRec *addTriggerSegment(Segment *, int pitch = -1, int velocity = -1); /** * Delete a trigger Segment. */ void deleteTriggerSegment(TriggerSegmentId); /** * Detach a trigger Segment from the Composition. */ void detachTriggerSegment(TriggerSegmentId); /** * Delete all trigger Segments. */ void clearTriggerSegments(); /** * Return the TriggerSegmentId for the given Segment, or -1 if it is * not a trigger Segment. */ int getTriggerSegmentId(Segment *); /** * Return the Segment for a given TriggerSegmentId */ Segment *getTriggerSegment(TriggerSegmentId); /** * Return the TriggerSegmentRec (with Segment, base pitch, base velocity, * references etc) for a given TriggerSegmentId */ TriggerSegmentRec *getTriggerSegmentRec(TriggerSegmentId); /** * Add a new trigger Segment with a given ID and base pitch and * velocity. Fails and returns 0 if the ID is already in use. * This is intended for use from file load or from undo/redo. */ TriggerSegmentRec *addTriggerSegment(Segment *, TriggerSegmentId, int basePitch = -1, int baseVelocity = -1); /** * Get the ID of the next trigger segment that will be inserted. */ TriggerSegmentId getNextTriggerSegmentId() const; /** * Specify the next trigger ID. This is intended for use from file * load only. Do not use this function unless you know what you're * doing. */ void setNextTriggerSegmentId(TriggerSegmentId); /** * Update the trigger segment references for all trigger segments. * To be called after file load. */ void updateTriggerSegmentReferences(); ////// // // BAR /** * Return the total number of bars in the composition */ int getNbBars() const; /** * Return the number of the bar that starts at or contains time t. * * Will happily return computed bar numbers for times before * the start or beyond the real end of the composition. */ int getBarNumber(timeT t) const; /** * Return the starting time of bar n */ timeT getBarStart(int n) const { return getBarRange(n).first; } /** * Return the ending time of bar n */ timeT getBarEnd(int n) const { return getBarRange(n).second; } /** * Return the time range of bar n. * * Will happily return theoretical timings for bars before the * start or beyond the end of composition (i.e. there is no * requirement that 0 <= n < getNbBars()). */ std::pair getBarRange(int n) const; /** * Return the starting time of the bar that contains time t */ timeT getBarStartForTime(timeT t) const { return getBarRangeForTime(t).first; } /** * Return the ending time of the bar that contains time t */ timeT getBarEndForTime(timeT t) const { return getBarRangeForTime(t).second; } /** * Return the starting and ending times of the bar that contains * time t. * * Will happily return theoretical timings for bars before the * start or beyond the end of composition. */ std::pair getBarRangeForTime(timeT t) const; /** * Get the default number of bars in a new empty composition */ static int getDefaultNbBars() { return m_defaultNbBars; } /** * Set the default number of bars in a new empty composition */ static void setDefaultNbBars(int b) { m_defaultNbBars = b; } ////// // // TIME SIGNATURE /** * Add the given time signature at the given time. Returns the * resulting index of the time signature (suitable for passing * to removeTimeSignature, for example) */ int addTimeSignature(timeT t, TimeSignature timeSig); /** * Return the time signature in effect at time t */ TimeSignature getTimeSignatureAt(timeT t) const; /** * Return the time signature in effect at time t, and the time at * which it came into effect */ timeT getTimeSignatureAt(timeT, TimeSignature &) const; /** * Return the time signature in effect in bar n. Also sets * isNew to true if the time signature is a new one that did * not appear in the previous bar. */ TimeSignature getTimeSignatureInBar(int n, bool &isNew) const; /** * Return the total number of time signature changes in the * composition. */ int getTimeSignatureCount() const; /** * Return the index of the last time signature change before * or at the given time, in a range suitable for passing to * getTimeSignatureChange. Return -1 if there has been no * time signature by this time. */ int getTimeSignatureNumberAt(timeT time) const; /** * Return the absolute time of and time signature introduced * by time-signature change n. */ std::pair getTimeSignatureChange(int n) const; /** * Remove time signature change event n from the composition. */ void removeTimeSignature(int n); ////// // // TEMPO /** * Return the (approximate) number of quarters per minute for a * given tempo. */ static double getTempoQpm(tempoT tempo) { return double(tempo) / 100000.0; } static tempoT getTempoForQpm(double qpm) { return tempoT(qpm * 100000 + 0.01); } /** * Return the tempo in effect at time t. If a ramped tempo change * is in effect at the time, it will be properly interpolated and * a computed value returned. */ tempoT getTempoAtTime(timeT t) const; /** * Return the tempo in effect at the current playback position. */ tempoT getCurrentTempo() const { return getTempoAtTime(getPosition()); } /** * Set a default tempo for the composition. This will be * overridden by any tempo events encountered during playback. */ void setCompositionDefaultTempo(tempoT tempo) { m_defaultTempo = tempo; } tempoT getCompositionDefaultTempo() const { return m_defaultTempo; } /** * Add a tempo-change event at the given time, to the given tempo. * Removes any existing tempo event at that time. Returns the * index of the new tempo event in a form suitable for passing to * removeTempoChange. * * If targetTempo == -1, adds a single constant tempo change. * If targetTempo == 0, adds a smooth tempo ramp from this tempo * change to the next. * If targetTempo > 0, adds a smooth tempo ramp from this tempo * ending at targetTempo at the time of the next tempo change. */ int addTempoAtTime(timeT time, tempoT tempo, tempoT targetTempo = -1); /** * Return the number of tempo changes in the composition. */ int getTempoChangeCount() const; /** * Return the index of the last tempo change before the given * time, in a range suitable for passing to getTempoChange. * Return -1 if the default tempo is in effect at this time. */ int getTempoChangeNumberAt(timeT time) const; /** * Return the absolute time of and tempo introduced by tempo * change number n. If the tempo is ramped, this returns only * the starting tempo. */ std::pair getTempoChange(int n) const; /** * Return whether the tempo change number n is a ramped tempo or * not, and if it is, return the target tempo for the ramp. * * If calculate is false, return a target tempo of 0 if the tempo * change is defined to ramp to the following tempo. If calculate * is true, return a target tempo equal to the following tempo in * this case. */ std::pair getTempoRamping(int n, bool calculate = true) const; /** * Remove tempo change event n from the composition. */ void removeTempoChange(int n); /** * Get the slowest assigned tempo in the composition. */ tempoT getMinTempo() const { return ((m_minTempo != 0) ? m_minTempo : m_defaultTempo); } /** * Get the fastest assigned tempo in the composition. */ tempoT getMaxTempo() const { return ((m_maxTempo != 0) ? m_maxTempo : m_defaultTempo); } ////// // // REAL TIME /** * Return the number of microseconds elapsed between * the beginning of the composition and the given timeT time. * (timeT units are independent of tempo; this takes into * account any tempo changes in the first t units of time.) * * This is a fairly efficient operation, not dependent on the * magnitude of t or the number of tempo changes in the piece. */ RealTime getElapsedRealTime(timeT t) const; /** * Return the nearest time in timeT units to the point at the * given number of microseconds after the beginning of the * composition. (timeT units are independent of tempo; this takes * into account any tempo changes in the first t microseconds.) * The result will be approximate, as timeT units are obviously * less precise than microseconds. * * This is a fairly efficient operation, not dependent on the * magnitude of t or the number of tempo changes in the piece. */ timeT getElapsedTimeForRealTime(RealTime t) const; /** * Return the number of microseconds elapsed between * the two given timeT indices into the composition, taking * into account any tempo changes between the two times. */ RealTime getRealTimeDifference(timeT t0, timeT t1) const { if (t1 > t0) return getElapsedRealTime(t1) - getElapsedRealTime(t0); else return getElapsedRealTime(t0) - getElapsedRealTime(t1); } ////// // // OTHER TIME CONVERSIONS /** * Return (by reference) the bar number and beat/division values * corresponding to a given absolute time. */ void getMusicalTimeForAbsoluteTime(timeT absoluteTime, int &bar, int &beat, int &fraction, int &remainder); /** * Return (by reference) the number of bars and beats/divisions * corresponding to a given duration. The absolute time at which * the duration starts is also required, so as to know the correct * time signature. */ void getMusicalTimeForDuration(timeT absoluteTime, timeT duration, int &bars, int &beats, int &fractions, int &remainder); /** * Return the absolute time corresponding to a given bar number * and beat/division values. */ timeT getAbsoluteTimeForMusicalTime(int bar, int beat, int fraction, int remainder); /** * Return the duration corresponding to a given number of bars and * beats/divisions. The absolute time at which the duration * starts is also required, so as to know the correct time * signature. */ timeT getDurationForMusicalTime(timeT absoluteTime, int bars, int beats, int fractions, int remainder); /** * Get the current playback position. */ timeT getPosition() const { return m_position; } /** * Set the current playback position. */ void setPosition(timeT position); ////// // // LOOP timeT getLoopStart() const { return m_loopStart; } timeT getLoopEnd() const { return m_loopEnd;} void setLoopStart(const timeT &lS) { m_loopStart = lS; } void setLoopEnd(const timeT &lE) { m_loopEnd = lE; } // Determine if we're currently looping // bool isLooping() const { return (m_loopStart != m_loopEnd); } ////// // // OTHER STUFF // Some set<> API delegation iterator begin() { return m_segments.begin(); } const_iterator begin() const { return m_segments.begin(); } iterator end() { return m_segments.end(); } const_iterator end() const { return m_segments.end(); } // XML exportable method // virtual std::string toXmlString(); // Who's making this racket? // Configuration &getMetadata() { return m_metadata; } const Configuration &getMetadata() const { return m_metadata; } std::string getCopyrightNote() const { return m_metadata.get(CompositionMetadataKeys::Copyright, ""); } void setCopyrightNote(const std::string &cr) { m_metadata.set(CompositionMetadataKeys::Copyright, cr); } // We can have the metronome on or off while playing or // recording - get and set values from here // bool usePlayMetronome() const { return m_playMetronome; } bool useRecordMetronome() const { return m_recordMetronome; } void setPlayMetronome(bool value); void setRecordMetronome(bool value); // Colour stuff ColourMap& getSegmentColourMap() { return m_segmentColourMap; } const ColourMap& getSegmentColourMap() const { return m_segmentColourMap; } void setSegmentColourMap(ColourMap &newmap); // General colourmap for non-segments // ColourMap& getGeneralColourMap() { return m_generalColourMap; } void setGeneralColourMap(ColourMap &newmap); ////// // // QUANTIZERS /** * Return a quantizer that quantizes to the our most basic * units (i.e. a unit quantizer whose unit is our shortest * note duration). */ const BasicQuantizer *getBasicQuantizer() const { return m_basicQuantizer; } /** * Return a quantizer that does quantization for notation * only. */ const NotationQuantizer *getNotationQuantizer() const { return m_notationQuantizer; } ////// // // REFRESH STATUS // delegate RefreshStatusArray API unsigned int getNewRefreshStatusId() { return m_refreshStatusArray.getNewRefreshStatusId(); } RefreshStatus& getRefreshStatus(unsigned int id) { return m_refreshStatusArray.getRefreshStatus(id); } /// Set all refresh statuses to true void updateRefreshStatuses() { m_refreshStatusArray.updateRefreshStatuses(); } void addObserver(CompositionObserver *obs) { m_observers.push_back(obs); } void removeObserver(CompositionObserver *obs) { m_observers.remove(obs); } ////// // DEBUG FACILITIES void dump(std::ostream&, bool full=false) const; protected: static const std::string TempoEventType; static const PropertyName TempoProperty; static const PropertyName TargetTempoProperty; static const PropertyName NoAbsoluteTimeProperty; static const PropertyName BarNumberProperty; static const PropertyName TempoTimestampProperty; struct ReferenceSegmentEventCmp { bool operator()(const Event &e1, const Event &e2) const; bool operator()(const Event *e1, const Event *e2) const { return operator()(*e1, *e2); } }; struct BarNumberComparator { bool operator()(const Event &e1, const Event &e2) const { return (e1.get(BarNumberProperty) < e2.get(BarNumberProperty)); } bool operator()(const Event *e1, const Event *e2) const { return operator()(*e1, *e2); } }; /** * Ensure the selected and record trackids still point to something valid * Must be called after deletion of detach of a track */ void checkSelectedAndRecordTracks(); TrackId getClosestValidTrackId(TrackId id) const; //--------------- Data members --------------------------------- // trackcontainer m_tracks; segmentcontainer m_segments; // The tracks we are armed for record on // recordtrackcontainer m_recordTracks; // Are we soloing and if so which Track? // bool m_solo; TrackId m_selectedTrack; /** * This is a bit like a segment, but can only contain one sort of * event, and can only have one event at each absolute time */ class ReferenceSegment : public FastVector // not a set: want random access for bars { typedef FastVector Impl; public: ReferenceSegment(std::string eventType); virtual ~ReferenceSegment(); private: ReferenceSegment(const ReferenceSegment &); ReferenceSegment& operator=(const ReferenceSegment &); public: typedef Impl::iterator iterator; typedef Impl::size_type size_type; typedef Impl::difference_type difference_type; void clear(); timeT getDuration() const; /// Inserts a single event, removing any existing one at that time iterator insert(Event *e); // may throw Event::BadType void erase(Event *e); iterator findTime(timeT time); iterator findNearestTime(timeT time); iterator findRealTime(RealTime time); iterator findNearestRealTime(RealTime time); std::string getEventType() const { return m_eventType; } private: iterator find(Event *e); std::string m_eventType; }; /// Contains time signature events mutable ReferenceSegment m_timeSigSegment; /// Contains tempo events mutable ReferenceSegment m_tempoSegment; /// affects m_timeSigSegment void calculateBarPositions() const; mutable bool m_barPositionsNeedCalculating; ReferenceSegment::iterator getTimeSignatureAtAux(timeT t) const; /// affects m_tempoSegment void calculateTempoTimestamps() const; mutable bool m_tempoTimestampsNeedCalculating; RealTime time2RealTime(timeT time, tempoT tempo) const; RealTime time2RealTime(timeT time, tempoT tempo, timeT targetTempoTime, tempoT targetTempo) const; timeT realTime2Time(RealTime rtime, tempoT tempo) const; timeT realTime2Time(RealTime rtime, tempoT tempo, timeT targetTempoTime, tempoT targetTempo) const; bool getTempoTarget(ReferenceSegment::const_iterator i, tempoT &target, timeT &targetTime) const; static RealTime getTempoTimestamp(const Event *e); static void setTempoTimestamp(Event *e, RealTime r); typedef std::list ObserverSet; ObserverSet m_observers; void notifySegmentAdded(Segment *) const; void notifySegmentRemoved(Segment *) const; void notifySegmentRepeatChanged(Segment *, bool) const; void notifySegmentRepeatEndChanged(Segment *, timeT) const; void notifySegmentEventsTimingChanged(Segment *s, timeT delay, RealTime rtDelay) const; void notifySegmentTransposeChanged(Segment *s, int transpose) const; void notifySegmentTrackChanged(Segment *s, TrackId oldId, TrackId newId) const; void notifySegmentStartChanged(Segment *, timeT); void notifySegmentEndMarkerChange(Segment *s, bool shorten); void notifyEndMarkerChange(bool shorten) const; void notifyTrackChanged(Track*) const; void notifyTrackDeleted(TrackId) const; void notifyMetronomeChanged() const; void notifyTimeSignatureChanged() const; void notifySoloChanged() const; void notifyTempoChanged() const; void notifySourceDeletion() const; void updateExtremeTempos(); BasicQuantizer *m_basicQuantizer; NotationQuantizer *m_notationQuantizer; timeT m_position; tempoT m_defaultTempo; tempoT m_minTempo; // cached from tempo segment tempoT m_maxTempo; // cached from tempo segment // Notional Composition markers - these define buffers for the // start and end of the piece, Segments can still exist outside // of these markers - these are for visual and playback cueing. // timeT m_startMarker; timeT m_endMarker; static int m_defaultNbBars; // Loop start and end positions. If they're both the same // value (usually 0) then there's no loop set. // timeT m_loopStart; timeT m_loopEnd; Configuration m_metadata; bool m_playMetronome; bool m_recordMetronome; RefreshStatusArray m_refreshStatusArray; // User defined markers in the composition // markercontainer m_markers; // Trigger segments (unsorted segments fired by events elsewhere) // triggersegmentcontainer m_triggerSegments; TriggerSegmentId m_nextTriggerSegmentId; ColourMap m_segmentColourMap; ColourMap m_generalColourMap; }; /** * If you subclass from CompositionObserver, you can then attach to a * Composition to receive notification when something changes. * * Normally all the methods in this class would be pure virtual. But * because there are so many, that imposes far too much work on the * subclass implementation in a case where it only really wants to * know about one thing, such as segments being deleted. So we have * empty default implementations, and you'll just have to take a bit * more care to make sure you really are making the correct * declarations in the subclass. */ class CompositionObserver { public: CompositionObserver() : m_compositionDeleted(false) {} virtual ~CompositionObserver() {} /** * Called after the segment has been added to the composition */ virtual void segmentAdded(const Composition *, Segment *) { } /** * Called after the segment has been removed from the segment, * and just before it is deleted */ virtual void segmentRemoved(const Composition *, Segment *) { } /** * Called when the segment's repeat status has changed */ virtual void segmentRepeatChanged(const Composition *, Segment *, bool) { } /** * Called when the segment's repeat end time has changed */ virtual void segmentRepeatEndChanged(const Composition *, Segment *, timeT) { } /** * Called when the segment's delay timing has changed */ virtual void segmentEventsTimingChanged(const Composition *, Segment *, timeT /* delay */, RealTime /* rtDelay */) { } /** * Called when the segment's transpose value has changed */ virtual void segmentTransposeChanged(const Composition *, Segment *, int /* transpose */) { } /** * Called when the segment's start time has changed */ virtual void segmentStartChanged(const Composition *, Segment *, timeT /* newStartTime */) { } /** * Called when the segment's end marker time has changed */ virtual void segmentEndMarkerChanged(const Composition *, Segment *, bool /* shorten */) { } /** * Called when the segment's track has changed */ virtual void segmentTrackChanged(const Composition *, Segment *, TrackId /* id */) { } /** * Called after the composition's end marker time has been * changed */ virtual void endMarkerTimeChanged(const Composition *, bool /* shorten */) { } /** * Called when a track is changed (instrument id, muted status...) */ virtual void trackChanged(const Composition *, Track*) { } /** * Called when a track has been deleted */ virtual void trackDeleted(const Composition *, TrackId) { } /** * Called when some time signature has changed */ virtual void timeSignatureChanged(const Composition *) { } /** * Called when metronome status has changed (on/off) */ virtual void metronomeChanged(const Composition *) { } /** * Called when solo status changes (solo on/off, and selected track) */ virtual void soloChanged(const Composition *, bool /* solo */, TrackId /* selectedTrack */) { } /** * Called when solo status changes (solo on/off, and selected track) */ virtual void tempoChanged(const Composition *) { } /** * Called from the composition dtor */ virtual void compositionDeleted(const Composition *) { m_compositionDeleted = true; } bool isCompositionDeleted() { return m_compositionDeleted; } protected: bool m_compositionDeleted; }; } #endif