|
|
|
// -*- c-basic-offset: 4 -*-
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Rosegarden
|
|
|
|
A sequencer and musical notation editor.
|
|
|
|
|
|
|
|
This program is Copyright 2000-2008
|
|
|
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
|
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
|
|
Richard Bown <bownie@bownie.com>
|
|
|
|
|
|
|
|
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 _SEGMENT_H_
|
|
|
|
#define _SEGMENT_H_
|
|
|
|
|
|
|
|
#include <set>
|
|
|
|
#include <list>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include "Track.h"
|
|
|
|
#include "Event.h"
|
|
|
|
#include "NotationTypes.h"
|
|
|
|
#include "RefreshStatus.h"
|
|
|
|
#include "RealTime.h"
|
|
|
|
#include "MidiProgram.h"
|
|
|
|
|
|
|
|
namespace Rosegarden
|
|
|
|
{
|
|
|
|
|
|
|
|
class SegmentRefreshtqStatus : public RefreshtqStatus
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SegmentRefreshtqStatus() : m_from(0), m_to(0) {}
|
|
|
|
|
|
|
|
void push(timeT from, timeT to);
|
|
|
|
|
|
|
|
timeT from() const { return m_from; }
|
|
|
|
timeT to() const { return m_to; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
timeT m_from;
|
|
|
|
timeT m_to;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Segment is the container for a set of Events that are all played on
|
|
|
|
* the same track. Each event has an absolute starting time,
|
|
|
|
* which is used as the index within the segment. Multiple events may
|
|
|
|
* have the same absolute time.
|
|
|
|
*
|
|
|
|
* (For example, chords are represented simply as a sequence of notes
|
|
|
|
* that share a starting time. The Segment can contain counterpoint --
|
|
|
|
* notes that overlap, rather than starting and ending together -- but
|
|
|
|
* in practice it's probably too hard to display so we should make
|
|
|
|
* more than one Segment if we want to represent true counterpoint.)
|
|
|
|
*
|
|
|
|
* If you want to carry out notation-related editing operations on
|
|
|
|
* a Segment, take a look at SegmentNotationHelper. If you want to play a
|
|
|
|
* Segment, try SegmentPerformanceHelper for duration calculations.
|
|
|
|
*
|
|
|
|
* The Segment owns the Events its items are pointing at.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class SegmentObserver;
|
|
|
|
class Quantizer;
|
|
|
|
class BasicQuantizer;
|
|
|
|
class Composition;
|
|
|
|
|
|
|
|
class Segment : public std::multiset<Event*, Event::EventCmp>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/// A Segment contains either Internal representation or Audio
|
|
|
|
typedef enum {
|
|
|
|
Internal,
|
|
|
|
Audio
|
|
|
|
} SegmentType;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct a Segment of a given type with a given formal starting time.
|
|
|
|
*/
|
|
|
|
Segment(SegmentType segmentType = Internal,
|
|
|
|
timeT startTime = 0);
|
|
|
|
/**
|
|
|
|
* Copy constructor
|
|
|
|
*/
|
|
|
|
Segment(const Segment&);
|
|
|
|
|
|
|
|
virtual ~Segment();
|
|
|
|
|
|
|
|
|
|
|
|
//////
|
|
|
|
//
|
|
|
|
// BASIC SEGMENT ATTRIBUTES
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the Segment type (Internal or Audio)
|
|
|
|
*/
|
|
|
|
SegmentType getType() const { return m_type; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Note that a Segment does not have to be in a Composition;
|
|
|
|
* if it isn't, this will return zero
|
|
|
|
*/
|
|
|
|
Composition *getComposition() const {
|
|
|
|
return m_composition;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the track number this Segment is associated with.
|
|
|
|
*/
|
|
|
|
TrackId getTrack() const { return m_track; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the track number this Segment is associated with.
|
|
|
|
*/
|
|
|
|
void setTrack(TrackId i);
|
|
|
|
|
|
|
|
// label
|
|
|
|
//
|
|
|
|
void setLabel(const std::string &label);
|
|
|
|
std::string getLabel() const { return m_label; }
|
|
|
|
|
|
|
|
// Colour information
|
|
|
|
void setColourIndex(const unsigned int input);
|
|
|
|
unsigned int getColourIndex() const { return m_colourIndex; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a numeric id of some sort
|
|
|
|
* The id is guaranteed to be unique within the segment, but not to
|
|
|
|
* have any other interesting properties
|
|
|
|
*/
|
|
|
|
int getNextId() const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a MIDI pitch representing the highest suggested playable note for
|
|
|
|
* notation contained in this segment, as a convenience reminder to composers.
|
|
|
|
*
|
|
|
|
* This property, and its corresponding lowest note counterpart, initialize by
|
|
|
|
* default such that no limitation is imposed. (lowest = 0, highest = 127)
|
|
|
|
*/
|
|
|
|
int getHighestPlayable() { return m_highestPlayable; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the highest suggested playable note for this segment
|
|
|
|
*/
|
|
|
|
void setHighestPlayable(int pitch) { m_highestPlayable = pitch; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a MIDI pitch representing the lowest suggested playable note for
|
|
|
|
* notation contained in this segment, as a convenience reminder to composers
|
|
|
|
*/
|
|
|
|
int getLowestPlayable() { return m_lowestPlayable; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the highest suggested playable note for this segment
|
|
|
|
*/
|
|
|
|
void setLowestPlayable(int pitch) { m_lowestPlayable = pitch; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////
|
|
|
|
//
|
|
|
|
// TIME & DURATION VALUES
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the start time of the Segment. For a non-audio
|
|
|
|
* Segment, this is the start time of the first event in it.
|
|
|
|
*/
|
|
|
|
timeT getStartTime() const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the nominal end time of the Segment. This must
|
|
|
|
* be the same as or earlier than the getEndTime() value.
|
|
|
|
* The return value will not necessarily be that last set
|
|
|
|
* with setEndMarkerTime, as if there is a Composition its
|
|
|
|
* end marker will also be used for clipping.
|
|
|
|
*/
|
|
|
|
timeT getEndMarkerTime() const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the time of the end of the last event stored in the
|
|
|
|
* Segment. This time may be outside the audible/editable
|
|
|
|
* range of the Segment, depending on the location of the end
|
|
|
|
* marker.
|
|
|
|
*/
|
|
|
|
timeT getEndTime() const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Shift the start time of the Segment by moving the start
|
|
|
|
* times of all the events in the Segment.
|
|
|
|
*/
|
|
|
|
void setStartTime(timeT);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* DO NOT USE THIS METHOD
|
|
|
|
* Simple accessor for the m_startTime member. Used by
|
|
|
|
* Composition#setSegmentStartTime
|
|
|
|
*/
|
|
|
|
void setStartTimeDataMember(timeT t) { m_startTime = t; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the end marker (nominal end time) of this Segment.
|
|
|
|
*
|
|
|
|
* If the given time is later than the current end of the
|
|
|
|
* Segment's storage, extend the Segment by filling it with
|
|
|
|
* rests; if earlier, simply move the end marker. The end
|
|
|
|
* marker time may not precede the start time.
|
|
|
|
*/
|
|
|
|
void setEndMarkerTime(timeT);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the end time of the Segment.
|
|
|
|
*
|
|
|
|
* If the given time is later than the current end of the
|
|
|
|
* Segment's storage, extend the Segment by filling it with
|
|
|
|
* rests; if earlier, shorten it by throwing away events as
|
|
|
|
* necessary (though do not truncate any events) and also move
|
|
|
|
* the end marker to the given time. The end time may not
|
|
|
|
* precede the start time.
|
|
|
|
*
|
|
|
|
* Note that simply inserting an event beyond the end of the
|
|
|
|
* Segment will also change the end time, although it does
|
|
|
|
* not fill with rests in the desirable way.
|
|
|
|
*
|
|
|
|
* Consider using setEndMarkerTime in preference to this.
|
|
|
|
*/
|
|
|
|
void setEndTime(timeT);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return an iterator pointing to the nominal end of the
|
|
|
|
* Segment. This may be earlier than the end() iterator.
|
|
|
|
*/
|
|
|
|
iterator getEndMarker();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return true if the given iterator points earlier in the
|
|
|
|
* Segment than the nominal end marker. You can use this
|
|
|
|
* as an extent test in code such as
|
|
|
|
*
|
|
|
|
* while (segment.isBeforeEndMarker(my_iterator)) {
|
|
|
|
* // ...
|
|
|
|
* ++my_iterator;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* It is not generally safe to write
|
|
|
|
*
|
|
|
|
* while (my_iterator != segment.getEndMarker()) {
|
|
|
|
* // ...
|
|
|
|
* ++my_iterator;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* as the loop will not terminate if my_iterator's initial
|
|
|
|
* value is already beyond the end marker. (Also takes the
|
|
|
|
* Composition's end marker into account.)
|
|
|
|
*/
|
|
|
|
bool isBeforeEndMarker(const_iterator) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove the end marker, thus making the Segment end
|
|
|
|
* at its storage end time (unless the Composition's
|
|
|
|
* end marker is earlier).
|
|
|
|
*/
|
|
|
|
void clearEndMarker();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the end marker in raw form, that is, a pointer to
|
|
|
|
* its value or null if none is set. Does not take the
|
|
|
|
* composition's end marker into account.
|
|
|
|
*/
|
|
|
|
const timeT *getRawEndMarkerTime() const;
|
|
|
|
|
|
|
|
|
|
|
|
//////
|
|
|
|
//
|
|
|
|
// TQUANTIZATION
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Switch quantization on or off.
|
|
|
|
*/
|
|
|
|
void setQuantization(bool quantize);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find out whether quantization is on or off.
|
|
|
|
*/
|
|
|
|
bool hasQuantization() const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the quantization level.
|
|
|
|
* (This does not switch quantization on, if it's currently off,
|
|
|
|
* it only changes the level that will be used when it's next
|
|
|
|
* switched on.)
|
|
|
|
*/
|
|
|
|
void setQuantizeLevel(timeT unit);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the quantizer currently in (or not in) use.
|
|
|
|
*/
|
|
|
|
const BasicQuantizer *getQuantizer() const;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////
|
|
|
|
//
|
|
|
|
// EVENT MANIPULATION
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inserts a single Event
|
|
|
|
*/
|
|
|
|
iterator insert(Event *e);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Erases a single Event
|
|
|
|
*/
|
|
|
|
void erase(iterator pos);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Erases a set of Events
|
|
|
|
*/
|
|
|
|
void erase(iterator from, iterator to);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clear the segment.
|
|
|
|
*/
|
|
|
|
void clear() { erase(begin(), end()); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Looks up an Event and if it finds it, erases it.
|
|
|
|
* @return true if the event was found and erased, false otherwise.
|
|
|
|
*/
|
|
|
|
bool eraseSingle(Event*);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an iterator pointing to that specific element,
|
|
|
|
* end() otherwise
|
|
|
|
*/
|
|
|
|
iterator findSingle(Event*);
|
|
|
|
|
|
|
|
const_iterator findSingle(Event *e) const {
|
|
|
|
return const_iterator(((Segment *)this)->findSingle(e));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an iterator pointing to the first element starting at
|
|
|
|
* or beyond the given absolute time
|
|
|
|
*/
|
|
|
|
iterator findTime(timeT time);
|
|
|
|
|
|
|
|
const_iterator findTime(timeT time) const {
|
|
|
|
return const_iterator(((Segment *)this)->findTime(time));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an iterator pointing to the first element starting at
|
|
|
|
* or before the given absolute time (so returns end() if the
|
|
|
|
* time precedes the first event, not if it follows the last one)
|
|
|
|
*/
|
|
|
|
iterator findNearestTime(timeT time);
|
|
|
|
|
|
|
|
const_iterator findNearestTime(timeT time) const {
|
|
|
|
return const_iterator(((Segment *)this)->findNearestTime(time));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////
|
|
|
|
//
|
|
|
|
// ADVANCED, ESOTERIC, or PLAIN STUPID MANIPULATION
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the range [start, end[ of events which are at absoluteTime
|
|
|
|
*/
|
|
|
|
void getTimeSlice(timeT absoluteTime, iterator &start, iterator &end);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the range [start, end[ of events which are at absoluteTime
|
|
|
|
*/
|
|
|
|
void getTimeSlice(timeT absoluteTime, const_iterator &start, const_iterator &end) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the starting time of the bar that contains time t. This
|
|
|
|
* differs from Composition's bar methods in that it will truncate
|
|
|
|
* to the start and end times of this Segment, and is guaranteed
|
|
|
|
* to return the start time of a bar that is at least partially
|
|
|
|
* within this Segment.
|
|
|
|
*
|
|
|
|
* (See Composition for most of the generally useful bar methods.)
|
|
|
|
*/
|
|
|
|
timeT getBarStartForTime(timeT t) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the ending time of the bar that contains time t. This
|
|
|
|
* differs from Composition's bar methods in that it will truncate
|
|
|
|
* to the start and end times of this Segment, and is guaranteed
|
|
|
|
* to return the end time of a bar that is at least partially
|
|
|
|
* within this Segment.
|
|
|
|
*
|
|
|
|
* (See Composition for most of the generally useful bar methods.)
|
|
|
|
*/
|
|
|
|
timeT getBarEndForTime(timeT t) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fill up the segment with rests, from the end of the last event
|
|
|
|
* currently on the segment to the endTime given. Actually, this
|
|
|
|
* does much the same as setEndTime does when it extends a segment.
|
|
|
|
*/
|
|
|
|
void fillWithRests(timeT endTime);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fill up a section within a segment with rests, from the
|
|
|
|
* startTime given to the endTime given. This may be useful if
|
|
|
|
* you have a pathological segment that contains notes already but
|
|
|
|
* not rests, but it is is likely to be dangerous unless you're
|
|
|
|
* quite careful about making sure the given range doesn't overlap
|
|
|
|
* any notes.
|
|
|
|
*/
|
|
|
|
void fillWithRests(timeT startTime, timeT endTime);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* For each series of contiguous rests found between the start and
|
|
|
|
* end time, replace the series of rests with another series of
|
|
|
|
* the same duration but composed of the theoretically "correct"
|
|
|
|
* rest durations to fill the gap, in the current time signature.
|
|
|
|
* The start and end time should be the raw absolute times of the
|
|
|
|
* events, not the notation-quantized versions, although the code
|
|
|
|
* will use the notation quantizations if it finds them.
|
|
|
|
*/
|
|
|
|
void normalizeRests(timeT startTime, timeT endTime);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the clef in effect at the given time. This is a
|
|
|
|
* reasonably quick call.
|
|
|
|
*/
|
|
|
|
Clef getClefAtTime(timeT time) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the clef in effect at the given time, and set ctime to
|
|
|
|
* the time of the clef change. This is a reasonably quick call.
|
|
|
|
*/
|
|
|
|
Clef getClefAtTime(timeT time, timeT &ctime) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the key signature in effect at the given time. This is
|
|
|
|
* a reasonably quick call.
|
|
|
|
*/
|
|
|
|
Key getKeyAtTime(timeT time) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the key signature in effect at the given time, and set
|
|
|
|
* ktime to the time of the key change. This is a reasonably
|
|
|
|
* quick call.
|
|
|
|
*/
|
|
|
|
Key getKeyAtTime(timeT time, timeT &ktime) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the clef and key signature in effect at the beginning of the
|
|
|
|
* segment using the following rules :
|
|
|
|
*
|
|
|
|
* - Return the default clef if no clef change is preceding the first
|
|
|
|
* note or rest event,
|
|
|
|
* - else return the first clef event in the segment,
|
|
|
|
* - else return the default clef if the segment has no note event nor
|
|
|
|
* clef change in it.
|
|
|
|
*
|
|
|
|
* - Use the same rules with the key signature.
|
|
|
|
*/
|
|
|
|
void getFirstClefAndKey(Clef &clef, Key &key);
|
|
|
|
|
|
|
|
|
|
|
|
//////
|
|
|
|
//
|
|
|
|
// REPEAT, DELAY, TRANSPOSE
|
|
|
|
|
|
|
|
// Is this Segment repeating?
|
|
|
|
//
|
|
|
|
bool isRepeating() const { return m_repeating; }
|
|
|
|
void setRepeating(bool value);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If this Segment is repeating, calculate and return the time at
|
|
|
|
* which the repeating stops. This is the start time of the
|
|
|
|
* following Segment on the same Track, if any, or else the end
|
|
|
|
* time of the Composition. If this Segment does not repeat, or
|
|
|
|
* the time calculated would precede the end time of the Segment,
|
|
|
|
* instead return the end time of the Segment.
|
|
|
|
*/
|
|
|
|
timeT getRepeatEndTime() const;
|
|
|
|
|
|
|
|
timeT getDelay() const { return m_delay; }
|
|
|
|
void setDelay(timeT delay);
|
|
|
|
|
|
|
|
RealTime getRealTimeDelay() const { return m_realTimeDelay; }
|
|
|
|
void setRealTimeDelay(RealTime delay);
|
|
|
|
|
|
|
|
int getTranspose() const { return m_transpose; }
|
|
|
|
void setTranspose(int transpose);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////
|
|
|
|
//
|
|
|
|
// AUDIO
|
|
|
|
|
|
|
|
// Get and set Audio file Id (see the AudioFileManager)
|
|
|
|
//
|
|
|
|
unsigned int getAudioFileId() const { return m_audioFileId; }
|
|
|
|
void setAudioFileId(unsigned int id);
|
|
|
|
|
|
|
|
unsigned int getUnstretchedFileId() const { return m_unstretchedFileId; }
|
|
|
|
void setUnstretchedFileId(unsigned int id);
|
|
|
|
|
|
|
|
float getStretchRatio() const { return m_stretchRatio; }
|
|
|
|
void setStretchRatio(float ratio);
|
|
|
|
|
|
|
|
// The audio start and end times tell us how far into
|
|
|
|
// audio file "m_audioFileId" this Segment starts and
|
|
|
|
// how far into the sample the Segment finishes.
|
|
|
|
//
|
|
|
|
RealTime getAudioStartTime() const { return m_audioStartTime; }
|
|
|
|
RealTime getAudioEndTime() const { return m_audioEndTime; }
|
|
|
|
void setAudioStartTime(const RealTime &time);
|
|
|
|
void setAudioEndTime(const RealTime &time);
|
|
|
|
|
|
|
|
bool isAutoFading() const { return m_autoFade; }
|
|
|
|
void setAutoFade(bool value);
|
|
|
|
|
|
|
|
RealTime getFadeInTime() const { return m_fadeInTime; }
|
|
|
|
void setFadeInTime(const RealTime &time);
|
|
|
|
|
|
|
|
RealTime getFadeOutTime() const { return m_fadeOutTime; }
|
|
|
|
void setFadeOutTime(const RealTime &time);
|
|
|
|
|
|
|
|
//////
|
|
|
|
//
|
|
|
|
// MISCELLANEOUS
|
|
|
|
|
|
|
|
/// Should only be called by Composition
|
|
|
|
void setComposition(Composition *composition) {
|
|
|
|
m_composition = composition;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The runtime id for this segment
|
|
|
|
//
|
|
|
|
int getRuntimeId() const { return m_runtimeSegmentId; }
|
|
|
|
|
|
|
|
// Grid size for matrix view (and others probably)
|
|
|
|
//
|
|
|
|
void setSnapGridSize(int size) { m_snapGridSize = size; }
|
|
|
|
int getSnapGridSize() const { return m_snapGridSize; }
|
|
|
|
|
|
|
|
// Other view features we might want to set on this Segment
|
|
|
|
//
|
|
|
|
void setViewFeatures(int features) { m_viewFeatures = features; }
|
|
|
|
int getViewFeatures() const { return m_viewFeatures; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The compare class used by Composition
|
|
|
|
*/
|
|
|
|
struct SegmentCmp
|
|
|
|
{
|
|
|
|
bool operator()(const Segment* a, const Segment* b) const
|
|
|
|
{
|
|
|
|
if (a->getTrack() == b->getTrack())
|
|
|
|
return a->getStartTime() < b->getStartTime();
|
|
|
|
|
|
|
|
return a->getTrack() < b->getTrack();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/// For use by SegmentObserver objects like Composition & Staff
|
|
|
|
void addObserver(SegmentObserver *obs) { m_observers.push_back(obs); }
|
|
|
|
|
|
|
|
/// For use by SegmentObserver objects like Composition & Staff
|
|
|
|
void removeObserver(SegmentObserver *obs) { m_observers.remove(obs); }
|
|
|
|
|
|
|
|
// List of visible EventRulers attached to this segment
|
|
|
|
//
|
|
|
|
class EventRuler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
EventRuler(const std::string &type, int controllerValue, bool active):
|
|
|
|
m_type(type), m_controllerValue(controllerValue), m_active(active) {;}
|
|
|
|
|
|
|
|
std::string m_type; // Event Type
|
|
|
|
int m_controllerValue; // if controller event, then which value
|
|
|
|
bool m_active; // is this Ruler active?
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::vector<EventRuler*> EventRulerList;
|
|
|
|
typedef std::vector<EventRuler*>::iterator EventRulerListIterator;
|
|
|
|
typedef std::vector<EventRuler*>::const_iterator EventRulerListConstIterator;
|
|
|
|
|
|
|
|
EventRulerList& getEventRulerList() { return m_eventRulerList; }
|
|
|
|
EventRuler* getEventRuler(const std::string &type, int controllerValue = -1);
|
|
|
|
|
|
|
|
void addEventRuler(const std::string &type, int controllerValue = -1, bool active = 0);
|
|
|
|
bool deleteEventRuler(const std::string &type, int controllerValue = -1);
|
|
|
|
|
|
|
|
//////
|
|
|
|
//
|
|
|
|
// REFRESH STATUS
|
|
|
|
|
|
|
|
// delegate part of the RefreshStatusArray API
|
|
|
|
|
|
|
|
unsigned int getNewRefreshStatusId() {
|
|
|
|
return m_refreshStatusArray.getNewRefreshStatusId();
|
|
|
|
}
|
|
|
|
|
|
|
|
SegmentRefreshtqStatus &getRefreshtqStatus(unsigned int id) {
|
|
|
|
return m_refreshStatusArray.getRefreshtqStatus(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateRefreshStatuses(timeT startTime, timeT endTime);
|
|
|
|
|
|
|
|
private:
|
|
|
|
Composition *m_composition; // owns me, if it exists
|
|
|
|
|
|
|
|
timeT m_startTime;
|
|
|
|
timeT *m_endMarkerTime; // points to end time, or null if none
|
|
|
|
timeT m_endTime;
|
|
|
|
|
|
|
|
void updateEndTime(); // called after erase of item at end
|
|
|
|
|
|
|
|
TrackId m_track;
|
|
|
|
SegmentType m_type; // identifies Segment type
|
|
|
|
std::string m_label; // segment label
|
|
|
|
|
|
|
|
unsigned int m_colourIndex; // identifies Colour Index (default == 0)
|
|
|
|
|
|
|
|
mutable int m_id; // not id of Segment, but a value for return by getNextId
|
|
|
|
|
|
|
|
unsigned int m_audioFileId; // audio file ID (see AudioFileManager)
|
|
|
|
unsigned int m_unstretchedFileId;
|
|
|
|
float m_stretchRatio;
|
|
|
|
RealTime m_audioStartTime; // start time relative to start of audio file
|
|
|
|
RealTime m_audioEndTime; // end time relative to start of audio file
|
|
|
|
|
|
|
|
bool m_repeating; // is this segment repeating?
|
|
|
|
|
|
|
|
BasicQuantizer *const m_quantizer;
|
|
|
|
bool m_quantize;
|
|
|
|
|
|
|
|
int m_transpose; // all Events tranpose
|
|
|
|
timeT m_delay; // all Events delay
|
|
|
|
RealTime m_realTimeDelay; // all Events delay (the delays are cumulative)
|
|
|
|
|
|
|
|
int m_highestPlayable; // suggestion for highest playable note (notation)
|
|
|
|
int m_lowestPlayable; // suggestion for lowest playable note (notation)
|
|
|
|
|
|
|
|
RefreshStatusArray<SegmentRefreshtqStatus> m_refreshStatusArray;
|
|
|
|
|
|
|
|
struct ClefKeyCmp {
|
|
|
|
bool operator()(const Event *e1, const Event *e2) const;
|
|
|
|
};
|
|
|
|
typedef std::multiset<Event*, ClefKeyCmp> ClefKeyList;
|
|
|
|
mutable ClefKeyList *m_clefKeyList;
|
|
|
|
|
|
|
|
// EventRulers currently selected as visible on this segment
|
|
|
|
//
|
|
|
|
EventRulerList m_eventRulerList;
|
|
|
|
|
|
|
|
private: // stuff to support SegmentObservers
|
|
|
|
|
|
|
|
typedef std::list<SegmentObserver *> ObserverSet;
|
|
|
|
ObserverSet m_observers;
|
|
|
|
|
|
|
|
void notifyAdd(Event *) const;
|
|
|
|
void notifyRemove(Event *) const;
|
|
|
|
void notifyAppearanceChange() const;
|
|
|
|
void notifyStartChanged(timeT);
|
|
|
|
void notifyEndMarkerChange(bool shorten);
|
|
|
|
void notifySourceDeletion() const;
|
|
|
|
|
|
|
|
private: // assignment operator not provided
|
|
|
|
|
|
|
|
Segment &operator=(const Segment &);
|
|
|
|
|
|
|
|
// Used for mapping the segment to runtime things like PlayableAudioFiles at
|
|
|
|
// the sequencer.
|
|
|
|
//
|
|
|
|
int m_runtimeSegmentId;
|
|
|
|
|
|
|
|
// Remember the last used snap grid size for this segment
|
|
|
|
//
|
|
|
|
int m_snapGridSize;
|
|
|
|
|
|
|
|
// Switch for other view-specific features we want to remember in the segment
|
|
|
|
//
|
|
|
|
int m_viewFeatures;
|
|
|
|
|
|
|
|
// Audio autofading
|
|
|
|
//
|
|
|
|
bool m_autoFade;
|
|
|
|
RealTime m_fadeInTime;
|
|
|
|
RealTime m_fadeOutTime;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class SegmentObserver
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual ~SegmentObserver() {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called after the event has been added to the segment
|
|
|
|
*/
|
|
|
|
virtual void eventAdded(const Segment *, Event *) { }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called after the event has been removed from the segment,
|
|
|
|
* and just before it is deleted
|
|
|
|
*/
|
|
|
|
virtual void eventRemoved(const Segment *, Event *) { }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called after a change in the segment that will change the way its displays,
|
|
|
|
* like a label change for instance
|
|
|
|
*/
|
|
|
|
virtual void appearanceChanged(const Segment *) { }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called after a change that affects the start time of the segment
|
|
|
|
*/
|
|
|
|
virtual void startChanged(const Segment *, timeT) { }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called after the segment's end marker time has been
|
|
|
|
* changed
|
|
|
|
*
|
|
|
|
* @param shorten true if the marker change shortens the segment's duration
|
|
|
|
*/
|
|
|
|
virtual void endMarkerTimeChanged(const Segment *, bool /*shorten*/) { }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called from the segment dtor
|
|
|
|
* MUST BE IMPLEMENTED BY ALL OBSERVERS
|
|
|
|
*/
|
|
|
|
virtual void segmentDeleted(const Segment *) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// an abstract base
|
|
|
|
|
|
|
|
class SegmentHelper
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
SegmentHelper(Segment &t) : m_segment(t) { }
|
|
|
|
virtual ~SegmentHelper();
|
|
|
|
|
|
|
|
typedef Segment::iterator iterator;
|
|
|
|
|
|
|
|
Segment &segment() { return m_segment; }
|
|
|
|
|
|
|
|
Segment::iterator begin() { return segment().begin(); }
|
|
|
|
Segment::iterator end() { return segment().end(); }
|
|
|
|
|
|
|
|
bool isBeforeEndMarker(Segment::const_iterator i) {
|
|
|
|
return segment().isBeforeEndMarker(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
Segment::iterator insert(Event *e) { return segment().insert(e); }
|
|
|
|
void erase(Segment::iterator i) { segment().erase(i); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
Segment &m_segment;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|