/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* Rosegarden A sequencer and musical notation editor. Copyright 2000-2011 the Rosegarden development team. See the AUTHORS file for more details. 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_NOTATION_HELPER_H_ #define _SEGMENT_NOTATION_HELPER_H_ #include "base/Segment.h" namespace Rosegarden { class SegmentNotationHelper : protected SegmentHelper { public: SegmentNotationHelper(Segment &t) : SegmentHelper(t) { } virtual ~SegmentNotationHelper(); SegmentHelper::segment; /** * Set the NOTE_TYPE and NOTE_DOTS properties on the events * in the segment. If startTime and endTime are equal, operates * on the whole segment. */ void setNotationProperties(timeT startTime = 0, timeT endTime = 0); /** * Return the notation absolute time plus the notation duration. */ timeT getNotationEndTime(Event *e); /** * Return an iterator pointing at the first event in the segment * to have an absolute time of t or later. (Most of the time, the * non-notation absolute times should be used as reference * timings; this and the next function are provided for * completeness, but in most cases if you're about to call them * you should ask yourself why.) */ iterator findNotationAbsoluteTime(timeT t); /** * Return an iterator pointing at the last event in the segment * to have an absolute time of t or earlier. (Most of the time, * the non-notation absolute times should be used as reference * timings; this and the previous function are provided for * completeness, but in most cases if you're about to call them * you should ask yourself why.) */ iterator findNearestNotationAbsoluteTime(timeT t); /** * Looks for another note immediately following the one pointed to * by the given iterator, and (if matchPitch is true) of the same * pitch, and returns an iterator pointing to that note. Returns * end() if there is no such note. * * The notes are considered "adjacent" if the quantized start * time of one matches the quantized end time of the other, unless * allowOverlap is true in which case overlapping notes are also * considered adjacent so long as one does not completely enclose * the other. */ iterator getNextAdjacentNote(iterator i, bool matchPitch = true, bool allowOverlap = true); /** * Looks for another note immediately preceding the one pointed to * by the given iterator, and (if matchPitch is true) of the same * pitch, and returns an iterator pointing to that note. Returns * end() if there is no such note. * * rangeStart gives a bound to the distance that will be scanned * to find events -- no event with starting time earlier than that * will be considered. (This method has no other way to know when * to stop scanning; potentially the very first note in the segment * could turn out to be adjacent to the very last one.) * * The notes are considered "adjacent" if the quantized start * time of one matches the quantized end time of the other, unless * allowOverlap is true in which case overlapping notes are also * considered adjacent so long as one does not completely enclose * the other. */ iterator getPreviousAdjacentNote(iterator i, timeT rangeStart = 0, bool matchPitch = true, bool allowOverlap = true); /** * Returns an iterator pointing to the next contiguous element of * the same type (note or rest) as the one passed as argument, if * any. Returns end() otherwise. * * (for instance if the argument points to a note and the next * element is a rest, end() will be returned) * * Note that if the iterator points to a note, the "contiguous" * iterator returned may point to a note that follows the first * one, overlaps with it, shares a starting time (i.e. they're * both in the same chord) or anything else. "Contiguous" refers * only to their locations in the segment's event container, * which normally means what you expect for rests but not notes. * * See also SegmentNotationHelper::getNextAdjacentNote. */ iterator findContiguousNext(iterator); /** * Returns an iterator pointing to the previous contiguous element * of the same type (note or rest) as the one passed as argument, * if any. Returns end() otherwise. * * (for instance if the argument points to a note and the previous * element is a rest, end() will be returned) * * Note that if the iterator points to a note, the "contiguous" * iterator returned may point to a note that precedes the first * one, overlaps with it, shares a starting time (i.e. they're * both in the same chord) or anything else. "Contiguous" refers * only to their locations in the segment's event container, * which normally means what you expect for rests but not notes. * * See also SegmentNotationHelper::getPreviousAdjacentNote. */ iterator findContiguousPrevious(iterator); /** * Returns true if the iterator points at a note in a chord * e.g. if there are more notes at the same absolute time */ bool noteIsInChord(Event *note); /** * Returns an iterator pointing to the note that this one is tied * with, in the forward direction if goForwards or back otherwise. * Returns end() if none. * * Untested and probably marked-for-expiry -- prefer * SegmentPerformanceHelper::getTiedNotes */ iterator getNoteTiedWith(Event *note, bool goForwards); /** * Checks whether it's reasonable to split a single event * of duration a+b into two events of durations a and b, for some * working definition of "reasonable". * * You should pass note-quantized durations into this method */ bool isSplitValid(timeT a, timeT b); /** * Splits events in the [from, to[ interval into * tied events of duration baseDuration + events of duration R, * with R being equal to the events' initial duration minus baseDuration * * The events in [from, to[ must all be at the same absolute time * * Does not check "reasonableness" of expansion first * * Events may be notes or rests (rests will obviously not be tied) * * @return iterator pointing at the last inserted event. Also * modifies from to point at the first split event (the original * iterator would have been invalidated). */ iterator splitIntoTie(iterator &from, iterator to, timeT baseDuration); /** * Splits (splits) events in the same timeslice as that pointed * to by i into tied events of duration baseDuration + events of * duration R, with R being equal to the events' initial duration * minus baseDuration * * Does not check "reasonableness" of expansion first * * Events may be notes or rests (rests will obviously not be tied) * * @return iterator pointing at the last inserted event. Also * modifies i to point at the first split event (the original * iterator would have been invalidated). */ iterator splitIntoTie(iterator &i, timeT baseDuration); /** * Returns true if Events of durations a and b can reasonably be * collapsed into a single one of duration a+b, for some * definition of "reasonably". For use by collapseRestsIfValid * * You should pass note-quantized durations into this method */ bool isCollapseValid(timeT a, timeT b); /** * If possible, collapses the rest event with the following or * previous one. * * @return true if collapse was done, false if it wasn't reasonable * * collapseForward is set to true if the collapse was with the * following element, false if it was with the previous one */ bool collapseRestsIfValid(Event*, bool& collapseForward); /** * Inserts a note, doing all the clever split/merge stuff as * appropriate. Requires segment to be in a composition. Returns * iterator pointing to last event inserted (there may be more * than one, as note may have had to be split) * * This method will only work correctly if there is a note or * rest event already starting at absoluteTime. */ iterator insertNote(timeT absoluteTime, Note note, int pitch, Accidental explicitAccidental); /** * Inserts a note, doing all the clever split/merge stuff as * appropriate. Requires segment to be in a composition. Returns * iterator pointing to last event inserted (there may be more * than one, as note may have had to be split) * * This method will only work correctly if there is a note or * rest event already starting at the model event's absoluteTime. * * Passing a model event has the advantage over the previous * method of allowing additional properties to be supplied. The * model event will be copied but not itself used; the caller * continues to own it and should release it after return. */ iterator insertNote(Event *modelEvent); /** * Inserts a rest, doing all the clever split/merge stuff as * appropriate. Requires segment to be in a composition. * Returns iterator pointing to last event inserted (there * may be more than one, as rest may have had to be split) * * This method will only work correctly if there is a note or * rest event already starting at absoluteTime. */ iterator insertRest(timeT absoluteTime, Note note); /** * Insert a clef. * Returns iterator pointing to clef. */ iterator insertClef(timeT absoluteTime, Clef clef); /** * Insert a symbol. * Returns iterator pointing to symbol. */ iterator insertSymbol(timeT absoluteTime, Symbol symbol); /** * Insert a key. * Returns iterator pointing to key. */ iterator insertKey(timeT absoluteTime, Key key); /** * Insert a text event. * Returns iterator pointing to text event. */ iterator insertText(timeT absoluteTime, Text text); /** * Deletes a note, doing all the clever split/merge stuff as * appropriate. Requires segment to be in a composition. */ void deleteNote(Event *e, bool collapseRest = false); /** * Deletes a rest, doing all the clever split/merge stuff as * appropriate. Requires segment to be in a composition. * * @return whether the rest could be deleted -- a rest can only * be deleted if there's a suitable rest next to it to merge it * with. */ bool deleteRest(Event *e); /** * Deletes an event. If the event is a note or a rest, calls * deleteNote or deleteRest. * * @return whether the event was deleted (always true, unless the * event is a rest). * * @see deleteRest, deleteNote */ bool deleteEvent(Event *e, bool collapseRest = false); /** * Check whether a note or rest event has a duration that can be * represented by a single note-type. (If not, the code that's * doing the check might wish to split the event.) * * If dots is specified, a true value will only be returned if the * best-fit note has no more than that number of dots. e.g. if * dots = 0, only notes that are viable without the use of dots * will be acceptable. The default is whatever the segment's * quantizer considers acceptable (probably either 1 or 2 dots). */ bool isViable(Event *e, int dots = -1) { return isViable(e->getDuration(), dots); } /** * Check whether a duration can be represented by a single * note-type. (If not, the code that's doing the check might wish * to split the duration.) * * If dots is specified, a true value will only be returned if the * best-fit note has no more than that number of dots. e.g. if * dots = 0, only notes that are viable without the use of dots * will be acceptable. The default is whatever the segment's * quantizer considers acceptable (probably either 1 or 2 dots). */ bool isViable(timeT duration, int dots = -1); /** * Given an iterator pointing to a rest, split that rest up * according to the durations returned by TimeSignature's * getDurationListForInterval */ void makeRestViable(iterator i); /** * Split a note or rest up into tied notes or shorter rests of * viable lengths (longest possible viable duration first, then * longest possible viable component of remainder &c). Also * optionally split a note or rest at barlines -- this is * actually the most common user-visible use of this function. * * Note: no checks performed on validity of noteItr, use caution. * * Returns the original *noteItr Event if no split and tie occurs * or returns the first new event inserted if split and tie occurs */ Event * makeThisNoteViable(iterator noteItr, bool splitAtBars = true); /** * Split notes and rests up into tied notes or shorter rests of * viable lengths (longest possible viable duration first, then * longest possible viable component of remainder &c). Also * optionally splits notes and rests at barlines -- this is * actually the most common user-visible use of this function. */ void makeNotesViable(iterator i, iterator j, bool splitAtBars = true); /** * As above but given a range in time rather than iterators. */ void makeNotesViable(timeT startTime, timeT endTime, bool splitAtBars = true); /** * Give all events between the start of the timeslice containing * from and the start of the timeslice containing to the same new * group id and the given type. * * Do not use this for making tuplet groups, unless the events * in the group already have the other tuplet properties or you * intend to add those yourself. Use makeTupletGroup instead. */ void makeBeamedGroup(timeT from, timeT to, std::string type); /** * Give all events between the start of the timeslice containing * from and the start of the timeslice containing to the same new * group id and the given type. * * Do not use this for making tuplet groups, unless the events * in the group already have the other tuplet properties or you * intend to add those yourself. Use makeTupletGroup instead. */ void makeBeamedGroup(iterator from, iterator to, std::string type); /** * Give all events between from and to the same new group id and * the given type. * * Use makeBeamedGroup for normal notes. This function is usually * used for groups of grace notes, which are equal in time and * distinguished by subordering. * * Do not use this for making tuplet groups, unless the events * in the group already have the other tuplet properties or you * intend to add those yourself. */ void makeBeamedGroupExact(iterator from, iterator to, std::string type); /** * Make a beamed group of tuplet type, whose tuplet properties are * specified as "(untupled-count) notes of duration (unit) played * in the time of (tupled-count)". For example, a quaver triplet * group could be specified with untupled = 3, tupled = 2, unit = * (the duration of a quaver). * * The group will start at the beginning of the timeslice containing * the time t, and will be constructed by compressing the appropriate * number of following notes into the tuplet time, and filling the * space that this compression left behind (after the group) with * rests. The results may be unexpected if overlapping events are * present. */ void makeTupletGroup(timeT t, int untupled, int tupled, timeT unit); /** * Divide the notes between the start of the bar containing * from and the end of the bar containing to up into sensible * beamed groups and give each group the right group properties * using makeBeamedGroup. Requires segment to be in a composition. */ void autoBeam(timeT from, timeT to, std::string type); /** * Divide the notes between the start of the bar containing * from and the end of the bar containing to up into sensible * beamed groups and give each group the right group properties * using makeBeamedGroup. Requires segment to be in a composition. */ void autoBeam(iterator from, iterator to, std::string type); /** * Clear the group id and group type from all events between the * start of the timeslice containing from and the start of the * timeslice containing to */ void unbeam(timeT from, timeT to); /** * Clear the group id and group type from all events between the * start of the timeslice containing from and the start of the * timeslice containing to */ void unbeam(iterator from, iterator to); /** * Guess which clef a section of music is supposed to be in, * ignoring any clef events actually found in the section. */ Clef guessClef(iterator from, iterator to); /** * Removes all rests starting at \a time for \a duration, * splitting the last rest if needed. * * Modifies duration to the actual duration of the series * of rests that has been changed by this action (i.e. if * the last rest was split, duration will be extended to * include the second half of this rest). This is intended * to be of use when calculating the extents of a command * for undo/refresh purposes. * * If there's an event which is not a rest in this interval, * returns false and sets duration to the maximum duration * that would have succeeded. * * If testOnly is true, does not actually remove any rests; * just checks whether the rests can be removed and sets * duration and the return value appropriately. * * (Used for Event pasting.) */ bool removeRests(timeT time, timeT &duration, bool testOnly = false); /** * 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 longest possible valid * rest plus the remainder */ void collapseRestsAggressively(timeT startTime, timeT endTime); /** * Locate the given event and, if it's a note, collapse it with * any following adjacent note of the same pitch, so long as its * start time is before the the given limit. Does not care * whether the resulting note is viable. * * Returns an iterator pointing to the event that replaced the * original one if a collapse happened, segment.end() if no * collapse or event not found */ iterator collapseNoteAggressively(Event *, timeT rangeEnd); std::pair splitPreservingPerformanceTimes(Event *e, timeT q1); /** * Look for examples of overlapping notes within the given range, * and split each into chords with some tied notes. */ void deCounterpoint(timeT startTime, timeT endTime); /** * A rather specialised function: Add a slur to every beamed group. * If legatoOnly is true, add a slur only to those beamed groups * in which every note except the last has a tenuto mark already * (and remove that mark). * This is basically intended as a post-notation-quantization-auto- * beam step. */ void autoSlur(timeT startTime, timeT endTime, bool legatoOnly); protected: const Quantizer &basicQuantizer(); const Quantizer ¬ationQuantizer(); /** * Collapse multiple consecutive rests into one, in preparation * for insertion of a note (whose duration may exceed that of the * first rest) at the given position. The resulting rest event * may have a duration that is not expressible as a single note * type, and may therefore require splitting again after the * insertion. * * Returns position at which the collapse ended (i.e. the first * uncollapsed event) */ iterator collapseRestsForInsert(iterator firstRest, timeT desiredDuration); /// for use by insertNote and insertRest iterator insertSomething(iterator position, int duration, Event *modelEvent, bool tiedBack); /// for use by insertSomething iterator insertSingleSomething(iterator position, int duration, Event *modelEvent, bool tiedBack); /// for use by insertSingleSomething void setInsertedNoteGroup(Event *e, iterator i); /// for use by makeBeamedGroup void makeBeamedGroupAux(iterator from, iterator to, std::string type, bool groupGraces); /// for use by unbeam void unbeamAux(iterator from, iterator to); /// for use by autoBeam void autoBeamBar(iterator from, iterator to, TimeSignature timesig, std::string type); void autoBeamBar(iterator from, iterator to, timeT average, timeT minimum, timeT maximum, std::string type); /// used by autoBeamAux (duplicate of private method in Segment) bool hasEffectiveDuration(iterator i); typedef void (SegmentNotationHelper::*Reorganizer)(timeT, timeT, std::vector&); void reorganizeRests(timeT, timeT, Reorganizer); /// for use by normalizeRests void normalizeContiguousRests(timeT, timeT, std::vector&); /// for use by collapseRestsAggressively void mergeContiguousRests(timeT, timeT, std::vector&); /// find border of tupled int findBorderTuplet(iterator, iterator &start, iterator &end); }; } #endif