// -*- 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 _NOTATION_TYPES_H_ #define _NOTATION_TYPES_H_ #include #include #include "Event.h" #include "Instrument.h" /* * NotationTypes.h * * This file contains definitions of several classes to assist in * creating and manipulating certain event types. The classes are: * * Accidental * Clef * Key * Indication * Pitch * Note * TimeSignature * AccidentalTable * * The classes in this file are _not_ actually used for storing * events. Events are always stored in Event objects (see Event.h). * * These classes are usually constructed on-the-fly when a particular * operation specific to a single sort of event is required, and * usually destroyed as soon as they go out of scope. The most common * usages are for creating events (create an instance of one of these * classes with the data you require, then call getAsEvent on it), for * doing notation-related calculations from existing events (such as * the bar duration of a time signature), and for doing calculations * that are independent of any particular instance of an event (such * as the Note methods that calculate duration-related values without * reference to any specific pitch or other note-event properties; or * everything in Pitch). * * This file also defines the event types and standard property names * for the basic events. */ namespace Rosegarden { extern const int MIN_SUBORDERING; typedef std::list DurationList; /** * Accidentals are stored in the event as string properties, purely * for clarity. (They aren't manipulated _all_ that often, so this * probably isn't a great inefficiency.) Originally we used an enum * for the Accidental type with conversion functions to and from * strings, but making Accidental a string seems simpler. */ typedef std::string Accidental; namespace Accidentals { extern const Accidental NoAccidental; extern const Accidental Sharp; extern const Accidental Flat; extern const Accidental Natural; extern const Accidental DoubleSharp; extern const Accidental DoubleFlat; typedef std::vector AccidentalList; /** * When no accidental is specified for a pitch, there are several * strategies to determine what accidental to display for an * out-of-key pitch */ enum NoAccidentalStrategy { /** always use sharps */ UseSharps, /** always use flats */ UseFlats, /** always use sharps or always use flats depending on of what * type of accidentals the current key is made up */ UseKeySharpness, /** use the most likely accidental for this key */ UseKey }; /** * Get the predefined accidentals (i.e. the ones listed above) * in their defined order. */ extern AccidentalList getStandardAccidentals(); /** * Get the change in pitch resulting from an accidental: -1 for * flat, 2 for double-sharp, 0 for natural or NoAccidental etc. * This is not as useful as it may seem, as in reality the * effect of an accidental depends on the key as well -- see * the Key and Pitch classes. */ extern int getPitchOffset(const Accidental &accidental); /** * Get the Accidental corresponding to a change in pitch: flat * for -1, double-sharp for 2, natural for 0 etc. * * Useful for tying to code that represents accidentals by * their pitch change. */ extern Accidental getAccidental(int pitchChange); } /** * Marks, like Accidentals, are stored in the event as string properties. */ typedef std::string Mark; namespace Marks //!!! This would be better as a class, these days { extern const Mark NoMark; // " " extern const Mark Accent; // ">" extern const Mark Tenuto; // "-" ("legato" in RG2.1) extern const Mark Staccato; // "." extern const Mark Staccatissimo; // "'" extern const Mark Marcato; // "^" extern const Mark Sforzando; // "sf" extern const Mark Rinforzando; // "rf" extern const Mark Trill; // "tr" extern const Mark LongTrill; // with wiggly line extern const Mark TrillLine; // line on its own extern const Mark Turn; // "~" extern const Mark Pause; // aka "fermata" extern const Mark UpBow; // "v" extern const Mark DownBow; // a square with the bottom side missing extern const Mark Mordent; extern const Mark MordentInverted; extern const Mark MordentLong; extern const Mark MordentLongInverted; /** * Given a string, return a mark that will be recognised as a * text mark containing that string. For example, the Sforzando * mark is actually defined as getTextMark("sf"). */ extern Mark getTextMark(std::string text); /** * Return true if the given mark is a text mark. */ extern bool isTextMark(Mark mark); /** * Extract the string from a text mark. */ extern std::string getTextFromMark(Mark mark); /** * Given a string, return a mark that will be recognised as a * fingering mark containing that string. (We use a string * instead of a number to permit "fingering" marks containing * labels like "+".) */ extern Mark getFingeringMark(std::string fingering); /** * Return true if the given mark is a fingering mark. */ extern bool isFingeringMark(Mark mark); /** * Extract the string from a fingering mark. */ extern std::string getFingeringFromMark(Mark mark); /** * Extract the number of marks from an event. */ extern int getMarkCount(const Event &e); /** * Extract the marks from an event. */ extern std::vector getMarks(const Event &e); /** * Return the first fingering mark on an event (or NoMark, if none). */ extern Mark getFingeringMark(const Event &e); /** * Add a mark to an event. If unique is true, add the mark only * if the event does not already have it (otherwise permit * multiple identical marks). */ extern void addMark(Event &e, const Mark &mark, bool unique); /** * Remove a mark from an event. Returns true if the mark was * there to remove. If the mark was not unique, removes only * the first instance of it. */ extern bool removeMark(Event &e, const Mark &mark); /** * Returns true if the event has the given mark. */ extern bool hasMark(const Event &e, const Mark &mark); /** * Get the predefined marks (i.e. the ones listed above) in their * defined order. */ extern std::vector getStandardMarks(); } /** * Clefs are represented as one of a set of standard strings, stored * within a clef Event. The Clef class defines those standards and * provides a few bits of information about the clefs. */ class Clef { public: static const std::string EventType; static const int EventSubOrdering; static const PropertyName ClefPropertyName; static const PropertyName OctaveOffsetPropertyName; static const Clef DefaultClef; typedef Exception BadClefName; static const std::string Treble; static const std::string French; static const std::string Soprano; static const std::string Mezzosoprano; static const std::string Alto; static const std::string Tenor; static const std::string Baritone; static const std::string Varbaritone; static const std::string Bass; static const std::string Subbass; /** * Construct the default clef (treble). */ Clef() : m_clef(DefaultClef.m_clef), m_octaveOffset(0) { } /** * Construct a Clef from the clef data in the given event. If the * event is not of clef type or contains insufficient data, this * returns the default clef (with a warning). You should normally * test Clef::isValid() to catch that before construction. */ Clef(const Event &e); /** * Construct a Clef from the given data. Throws a BadClefName * exception if the given string does not match one of the above * clef name constants. */ Clef(const std::string &s, int octaveOffset = 0); Clef(const Clef &c) : m_clef(c.m_clef), m_octaveOffset(c.m_octaveOffset) { } Clef &operator=(const Clef &c); bool operator==(const Clef &c) const { return c.m_clef == m_clef && c.m_octaveOffset == m_octaveOffset; } bool operator!=(const Clef &c) const { return !(c == *this); } ~Clef() { } /** * Test whether the given event is a valid Clef event. */ static bool isValid(const Event &e); /** * Return the basic clef type (Treble, French, Soprano, Mezzosoprano, Alto, Tenor, Baritone, Varbaritone, Bass, Subbass) */ std::string getClefType() const { return m_clef; } /** * Return any additional octave offset, that is, return 1 for * a clef shifted an 8ve up, etc */ int getOctaveOffset() const { return m_octaveOffset; } /** * Return the number of semitones a pitch in the treble clef would * have to be lowered by in order to be drawn with the same height * and accidental in this clef */ int getTranspose() const; /** * Return the octave component of getTranspose(), i.e. the number * of octaves difference in pitch between this clef and the treble */ int getOctave() const; /** * Return the intra-octave component of getTranspose(), i.e. the * number of semitones this clef is distinct in pitch from the treble * besides the difference in octaves */ int getPitchOffset() const; /** * Return the height-on-staff (in Pitch terminology) * of the clef's axis -- the line around which the clef is drawn. */ int getAxisHeight() const; typedef std::vector ClefList; /** * Return all the clefs, in ascending order of pitch */ static ClefList getClefs(); /// Returned event is on heap; caller takes responsibility for ownership Event *getAsEvent(timeT absoluteTime) const; private: std::string m_clef; int m_octaveOffset; }; /** * All we store in a key Event is the name of the key. A Key object * can be constructed from such an Event or just from its name, and * will return all the properties of the key. The Key class also * provides some useful mechanisms for getting information about and * transposing between keys. */ class Key { public: static const std::string EventType; static const int EventSubOrdering; static const PropertyName KeyPropertyName; static const Key DefaultKey; typedef Exception BadKeyName; typedef Exception BadKeySpec; /** * Construct the default key (C major). */ Key(); /** * Construct a Key from the key data in the given event. If the * event is not of key type or contains insufficient data, this * returns the default key (with a warning). You should normally * test Key::isValid() to catch that before construction. */ Key(const Event &e); /** * Construct the named key. Throws a BadKeyName exception if the * given string does not match one of the known key names. */ Key(const std::string &name); /** * Construct a key from signature and mode. May throw a * BadKeySpec exception. */ Key(int accidentalCount, bool isSharp, bool isMinor); /** * Construct the key with the given tonic and mode. (Ambiguous.) * May throw a BadKeySpec exception. */ Key(int tonicPitch, bool isMinor); Key(const Key &kc); ~Key() { delete m_accidentalHeights; } Key &operator=(const Key &kc); bool operator==(const Key &k) const { return k.m_name == m_name; } bool operator!=(const Key &k) const { return !(k == *this); } /** * Test whether the given event is a valid Key event. */ static bool isValid(const Event &e); /** * Return true if this is a minor key. Unlike in RG2.1, * we distinguish between major and minor keys with the * same signature. */ bool isMinor() const { return m_keyDetailMap[m_name].m_minor; } /** * Return true if this key's signature is made up of * sharps, false if flats. */ bool isSharp() const { return m_keyDetailMap[m_name].m_sharps; } /** * Return the pitch of the tonic note in this key, as a * MIDI (or RG4) pitch modulo 12 (i.e. in the range 0-11). * This is the pitch of the note named in the key's name, * e.g. 0 for the C in C major. */ int getTonicPitch() const { return m_keyDetailMap[m_name].m_tonicPitch; } /** * Return the number of sharps or flats in the key's signature. */ int getAccidentalCount() const { return m_keyDetailMap[m_name].m_sharpCount; } /** * Return the key with the same signature but different * major/minor mode. For example if called on C major, * returns A minor. */ Key getEquivalent() const { return Key(m_keyDetailMap[m_name].m_equivalence); } /** * Return the name of the key, in a human-readable form * also suitable for passing to the Key constructor. */ std::string getName() const { return m_name; } /** * Return the name of the key, in the form used by RG2.1. */ std::string getRosegarden2Name() const { return m_keyDetailMap[m_name].m_rg2name; } /** * Return the accidental at the given height-on-staff * (in Pitch terminology) in the given clef. */ Accidental getAccidentalAtHeight(int height, const Clef &clef) const; /** * Return the accidental for the the given number of steps * from the tonic. For example: for F major, step '3' is the * Bb, so getAccidentalForStep(3) will yield a Flat. */ Accidental getAccidentalForStep(int steps) const; /** * Return the heights-on-staff (in Pitch * terminology) of all accidentals in the key's signature, * in the given clef. */ std::vector getAccidentalHeights(const Clef &clef) const; /** * Return the result of applying this key to the given * pitch, that is, modifying the pitch so that it has the * same status in terms of accidentals as it had when * found in the given previous key. */ int convertFrom(int pitch, const Key &previousKey, const Accidental &explicitAccidental = Accidentals::NoAccidental) const; /** * Return the result of transposing the given pitch into * this key, that is, modifying the pitch by the difference * between the tonic pitches of this and the given previous * key. */ int transposeFrom(int pitch, const Key &previousKey) const; /** * Reduce a height-on-staff to a single octave, so that it * can be compared against the accidental heights returned * by the preceding method. */ static inline unsigned int canonicalHeight(int height) { return (height > 0) ? (height % 7) : ((7 - (-height % 7)) % 7); } typedef std::vector KeyList; /** * Return all the keys in the given major/minor mode, in * no particular order. */ static KeyList getKeys(bool minor = false); /// Returned event is on heap; caller takes responsibility for ownership Event *getAsEvent(timeT absoluteTime) const; /** * Transpose this key by the specified interval given in pitch and steps * * For example: transposing F major by a major triad (4,2) yields * A major. */ Key transpose(int pitchDelta, int heightDelta); private: std::string m_name; mutable std::vector *m_accidentalHeights; struct KeyDetails { bool m_sharps; bool m_minor; int m_sharpCount; std::string m_equivalence; std::string m_rg2name; int m_tonicPitch; KeyDetails(); // ctor needed in order to live in a map KeyDetails(bool sharps, bool minor, int sharpCount, std::string equivalence, std::string rg2name, int m_tonicPitch); KeyDetails(const KeyDetails &d); KeyDetails &operator=(const KeyDetails &d); }; typedef std::map KeyDetailMap; static KeyDetailMap m_keyDetailMap; static void checkMap(); void checkAccidentalHeights() const; }; /** * Indication is a collective name for graphical marks that span a * series of events, such as slurs, dynamic marks etc. These are * stored in indication Events with a type and duration. The * Indication class gives a basic set of indication types. */ class Indication { public: static const std::string EventType; static const int EventSubOrdering; static const PropertyName IndicationTypePropertyName; typedef Exception BadIndicationName; static const std::string Slur; static const std::string PhrasingSlur; static const std::string Crescendo; static const std::string Decrescendo; static const std::string Glissando; static const std::string QuindicesimaUp; static const std::string OttavaUp; static const std::string OttavaDown; static const std::string QuindicesimaDown; Indication(const Event &e) /* throw (Event::NoData, Event::BadType) */; Indication(const std::string &s, timeT indicationDuration) /* throw (BadIndicationName) */; Indication(const Indication &m) : m_indicationType(m.m_indicationType), m_duration(m.m_duration) { } Indication &operator=(const Indication &m); ~Indication() { } std::string getIndicationType() const { return m_indicationType; } timeT getIndicationDuration() const { return m_duration; } bool isOttavaType() const { return m_indicationType == QuindicesimaUp || m_indicationType == OttavaUp || m_indicationType == OttavaDown || m_indicationType == QuindicesimaDown; } int getOttavaShift() const { return (m_indicationType == QuindicesimaUp ? 2 : m_indicationType == OttavaUp ? 1 : m_indicationType == OttavaDown ? -1 : m_indicationType == QuindicesimaDown ? -2 : 0); } /// Returned event is on heap; caller takes responsibility for ownership Event *getAsEvent(timeT absoluteTime) const; private: bool isValid(const std::string &s) const; std::string m_indicationType; timeT m_duration; }; /** * Definitions for use in the text Event type. */ class Text { public: static const std::string EventType; static const int EventSubOrdering; static const PropertyName TextPropertyName; static const PropertyName TextTypePropertyName; static const PropertyName LyricVersePropertyName; /** * Text styles */ static const std::string UnspecifiedType; static const std::string StaffName; static const std::string ChordName; static const std::string KeyName; static const std::string Lyric; static const std::string Chord; static const std::string Dynamic; static const std::string Direction; static const std::string LocalDirection; static const std::string Tempo; static const std::string LocalTempo; static const std::string Annotation; static const std::string LilyPondDirective; /** * Special LilyPond directives */ static const std::string Segno; // print segno here static const std::string Coda; // print coda sign here static const std::string Alternate1; // first alternative ending static const std::string Alternate2; // second alternative ending static const std::string BarDouble; // next barline is double static const std::string BarEnd; // next barline is final double static const std::string BarDot; // next barline is dotted static const std::string Gliss; // \glissando on this note (to next note) static const std::string Arpeggio; // \arpeggio on this chord // static const std::string ArpeggioUp; // \ArpeggioUp on this chord // static const std::string ArpeggioDn; // \ArpeggioDown on this chord static const std::string Tiny; // begin \tiny font section static const std::string Small; // begin \small font section static const std::string NormalSize; // begin \normalsize font section Text(const Event &e) /* throw (Event::NoData, Event::BadType) */; Text(const std::string &text, const std::string &textType = UnspecifiedType); Text(const Text &); Text &operator=(const Text &); ~Text(); std::string getText() const { return m_text; } std::string getTextType() const { return m_type; } int getVerse() const { return m_verse; } // only relevant for lyrics void setVerse(int verse) { m_verse = verse; } static bool isTextOfType(Event *, std::string type); /** * Return those text types that the user should be allowed to * specify directly and visually */ static std::vector getUserStyles(); /** * Return a list of available special LilyPond directives */ static std::vector getLilyPondDirectives(); /// Returned event is on heap; caller takes responsibility for ownership Event *getAsEvent(timeT absoluteTime) const; private: std::string m_text; std::string m_type; long m_verse; }; /** * Pitch stores a note's pitch and provides information about it in * various different ways, notably in terms of the position of the * note on the staff and its associated accidental. * * (See docs/discussion/units.txt for explanation of pitch units.) * * This completely replaces the older NotationDisplayPitch class. */ class Pitch { public: /** * Construct a Pitch object based on the given Event, which must * have a BaseProperties::PITCH property. If the property is * absent, NoData is thrown. The BaseProperties::ACCIDENTAL * property will also be used if present. */ Pitch(const Event &e) /* throw Event::NoData */; /** * Construct a Pitch object based on the given performance (MIDI) pitch. */ Pitch(int performancePitch, const Accidental &explicitAccidental = Accidentals::NoAccidental); /** * Construct a Pitch based on octave and pitch in octave. The * lowest permissible octave number is octaveBase, and middle C is * in octave octaveBase + 5. pitchInOctave must be in the range * 0-11 where 0 is C, 1 is C sharp, etc. */ Pitch(int pitchInOctave, int octave, const Accidental &explicitAccidental = Accidentals::NoAccidental, int octaveBase = -2); /** * Construct a Pitch based on octave and note in scale. The * lowest permissible octave number is octaveBase, and middle C is * in octave octaveBase + 5. The octave supplied should be that * of the root note in the given key, which may be in a different * MIDI octave from the resulting pitch (as MIDI octaves always * begin at C). noteInScale must be in the range 0-6 where 0 is * the root of the key and so on. The accidental is relative to * noteInScale: if there is an accidental in the key for this note * already, explicitAccidental will be "added" to it. * * For minor keys, the harmonic scale is used. */ Pitch(int noteInScale, int octave, const Key &key, const Accidental &explicitAccidental = Accidentals::NoAccidental, int octaveBase = -2); /** * Construct a Pitch based on (MIDI) octave, note in the C major scale and * performance pitch. The accidental is calculated based on these * properties. */ Pitch(int noteInCMajor, int octave, int pitch, int octaveBase = -2); /** * Construct a Pitch based on octave and note name. The lowest * permissible octave number is octaveBase, and middle C is in * octave octaveBase + 5. noteName must be a character in the * range [CDEFGAB] or lower-case equivalents. The key is supplied * so that we know how to interpret the NoAccidental case. */ Pitch(char noteName, int octave, const Key &key, const Accidental &explicitAccidental = Accidentals::NoAccidental, int octaveBase = -2); /** * Construct a Pitch corresponding a staff line or space on a * classical 5-line staff. The bottom staff line has height 0, * the top has height 8, and both positive and negative values are * permissible. */ Pitch(int heightOnStaff, const Clef &clef, const Key &key, const Accidental &explicitAccidental = Accidentals::NoAccidental); Pitch(const Pitch &); Pitch &operator=(const Pitch &); /** * Return the MIDI pitch for this Pitch object. */ int getPerformancePitch() const; /** * Return the accidental for this pitch using a bool to prefer sharps over * flats if there is any doubt. This is the accidental * that would be used to display this pitch outside of the context * of any key; that is, it may duplicate an accidental actually in * the current key. This should not be used if you need to get an * explicit accidental returned for E#, Fb, B# or Cb. * * This version of the function exists to avoid breaking old code. */ Accidental getAccidental(bool useSharps) const; /** * Return the accidental for this pitch, using a key. This should be used * if you need an explicit accidental returned for E#, Fb, B# or Cb, which * can't be resolved correctly without knowing that their key requires * them to take an accidental. The provided key will also be used to * determine whether to prefer sharps over flats. */ Accidental getAccidental(const Key &key) const; /** * Return the accidental that should be used to display this pitch * in a given key. For example, if the pitch is F-sharp in a key * in which F has a sharp, NoAccidental will be returned. (This * is in contrast to getAccidental, which would return Sharp.) * This obviously can't take into account things like which * accidentals have already been displayed in the bar, etc. */ Accidental getDisplayAccidental(const Key &key) const; /** * Return the accidental that should be used to display this pitch * in a given key, using the given strategy to resolve pitches where * an accidental is needed but not specified. */ Accidental getDisplayAccidental(const Key &key, Accidentals::NoAccidentalStrategy) const; /** * Return the position in the scale for this pitch, as a number in * the range 0 to 6 where 0 is the root of the key. */ int getNoteInScale(const Key &key) const; /** * Return the note name for this pitch, as a single character in * the range A to G. (This is a reference value that should not * normally be shown directly to the user, for i18n reasons.) */ char getNoteName(const Key &key) const; /** * Return the height at which this pitch should display on a * conventional 5-line staff. 0 is the bottom line, 1 the first * space, etc., so for example middle-C in the treble clef would * return -2. * * Chooses the most likely accidental for this pitch in this key. */ int getHeightOnStaff(const Clef &clef, const Key &key) const; /** * Return the height at which this pitch should display on a * conventional 5-line staff. 0 is the bottom line, 1 the first * space, etc., so for example middle-C in the treble clef would * return -2. * * Chooses the accidental specified by the 'useSharps' parameter */ int getHeightOnStaff(const Clef &clef, bool useSharps) const; /** * Return the octave containing this pitch. The octaveBase argument * specifies the octave containing MIDI pitch 0; middle-C is in octave * octaveBase + 5. */ int getOctave(int octaveBase = -2) const; /** * Return the pitch within the octave, in the range 0 to 11. */ int getPitchInOctave() const; /** * Return whether this pitch is diatonic in the given key. */ bool isDiatonicInKey(const Key &key) const; /** * Return a reference name for this pitch. (C4, Bb2, etc...) * according to http://www.harmony-central.com/MIDI/Doc/table2.html * * Note that this does not take into account the stored accidental * -- this string is purely an encoding of the MIDI pitch, with * the accidental in the string selected according to the * useSharps flag (which may be expected to have come from a call * to Key::isSharp). * * If inclOctave is false, this will return C, Bb, etc. */ std::string getAsString(bool useSharps, bool inclOctave = true, int octaveBase = -2) const; /** * Return a number 0-6 corresponding to the given note name, which * must be in the range [CDEFGAB] or lower-case equivalents. The * return value is in the range 0-6 with 0 for C, 1 for D etc. */ static int getIndexForNote(char noteName); /** * Return a note name corresponding to the given note index, which * must be in the range 0-6 with 0 for C, 1 for D etc. */ static char getNoteForIndex(int index); /** * Calculate and return the performance (MIDI) pitch corresponding * to the stored height and accidental, interpreting them as * Rosegarden-2.1-style values (for backward compatibility use), * in the given clef and key */ static int getPerformancePitchFromRG21Pitch(int heightOnStaff, const Accidental &accidental, const Clef &clef, const Key &key); /** * return the result of transposing the given pitch by the * specified interval in the given key. The key is left unchanged, * only the pitch is transposed. */ Pitch transpose(const Key &key, int pitchDelta, int heightDelta); /** * checks whether the accidental specified for this pitch (if any) * is valid - for example, a Sharp for pitch 11 is invalid, as * it's between A# and B#. */ bool validAccidental() const; /** * Returned event is on heap; caller takes responsibility for ownership */ Event *getAsNoteEvent(timeT absoluteTime, timeT duration) const; private: int m_pitch; Accidental m_accidental; static void rawPitchToDisplayPitch (int, const Clef &, const Key &, int &, Accidental &, Accidentals::NoAccidentalStrategy); static void displayPitchToRawPitch (int, Accidental, const Clef &, const Key &, int &, bool ignoreOffset = false); }; class TimeSignature; /** * The Note class represents note durations only, not pitch or * accidental; it's therefore just as relevant to rest events as to * note events. You can construct one of these from either. */ class Note { public: static const std::string EventType; static const std::string EventRestType; static const int EventRestSubOrdering; typedef int Type; // not an enum, too much arithmetic at stake // define both sorts of names; some people prefer the American // names, but I just can't remember which of them is which static const Type SixtyFourthNote = 0, ThirtySecondNote = 1, SixteenthNote = 2, EighthNote = 3, QuarterNote = 4, HalfNote = 5, WholeNote = 6, DoubleWholeNote = 7, Hemidemisemiquaver = 0, Demisemiquaver = 1, Semiquaver = 2, Quaver = 3, Crotchet = 4, Minim = 5, Semibreve = 6, Breve = 7, Shortest = 0, Longest = 7; /** * Create a Note object of the given type, representing a * particular sort of duration. Note objects are strictly * durational; they don't represent pitch, and may be as * relevant to rests as actual notes. */ Note(Type type, int dots = 0) : m_type(type < Shortest ? Shortest : type > Longest ? Longest : type), m_dots(dots) { } Note(const Note &n) : m_type(n.m_type), m_dots(n.m_dots) { } ~Note() { } Note &operator=(const Note &n); Type getNoteType() const { return m_type; } int getDots() const { return m_dots; } /** * Return the duration of this note type. */ timeT getDuration() const { return m_dots ? getDurationAux() : (m_shortestTime * (1 << m_type)); } /** * Return the Note whose duration is closest to (but shorter than or * equal to) the given duration, permitting at most maxDots dots. */ static Note getNearestNote(timeT duration, int maxDots = 2); /// Returned event is on heap; caller takes responsibility for ownership Event *getAsNoteEvent(timeT absoluteTime, int pitch) const; /// Returned event is on heap; caller takes responsibility for ownership Event *getAsRestEvent(timeT absoluteTime) const; private: Type m_type; int m_dots; timeT getDurationAux() const; // a time & effort saving device; if changing this, change // TimeSignature::m_crotchetTime etc too static const timeT m_shortestTime; }; /** * TimeSignature contains arithmetic methods relevant to time * signatures and bar durations, including code for splitting long * rest intervals into bite-sized chunks. Although there is a time * signature Event type, these Events don't appear in regular Segments * but only in the Composition's reference segment. */ class TimeSignature { public: static const TimeSignature DefaultTimeSignature; typedef Exception BadTimeSignature; TimeSignature() : m_numerator(DefaultTimeSignature.m_numerator), m_denominator(DefaultTimeSignature.m_denominator), m_common(false), m_hidden(false), m_hiddenBars(false) { } /** * Construct a TimeSignature object describing a time signature * with the given numerator and denominator. If preferCommon is * true and the time signature is a common or cut-common time, the * constructed object will return true for isCommon; if hidden is * true, the time signature is intended not to be displayed and * isHidden will return true; if hiddenBars is true, the bar lines * between this time signature and the next will not be shown. */ TimeSignature(int numerator, int denominator, bool preferCommon = false, bool hidden = false, bool hiddenBars = false) /* throw (BadTimeSignature) */; TimeSignature(const TimeSignature &ts) : m_numerator(ts.m_numerator), m_denominator(ts.m_denominator), m_common(ts.m_common), m_hidden(ts.m_hidden), m_hiddenBars(ts.m_hiddenBars) { } ~TimeSignature() { } TimeSignature &operator=(const TimeSignature &ts); bool operator==(const TimeSignature &ts) const { return ts.m_numerator == m_numerator && ts.m_denominator == m_denominator; } bool operator!=(const TimeSignature &ts) const { return !operator==(ts); } int getNumerator() const { return m_numerator; } int getDenominator() const { return m_denominator; } bool isCommon() const { return m_common; } bool isHidden() const { return m_hidden; } bool hasHiddenBars() const { return m_hiddenBars; } timeT getBarDuration() const; /** * Return the unit of the time signature. This is the note * implied by the denominator. For example, the unit of 4/4 time * is the crotchet, and that of 6/8 is the quaver. (The numerator * of the time signature gives the number of units per bar.) */ Note::Type getUnit() const; /** * Return the duration of the unit of the time signature. * See also getUnit(). In most cases getBeatDuration() gives * a more meaningful value. */ timeT getUnitDuration() const; /** * Return true if this time signature indicates dotted time. */ bool isDotted() const; /** * Return the duration of the beat of the time signature. For * example, the beat of 4/4 time is the crotchet, the same as its * unit, but that of 6/8 is the dotted crotchet (there are only * two beats in a 6/8 bar). The beat therefore depends on whether * the signature indicates dotted or undotted time. */ timeT getBeatDuration() const; /** * Return the number of beats in a complete bar. */ int getBeatsPerBar() const { return getBarDuration() / getBeatDuration(); } /** * Get the "optimal" list of rest durations to make up a bar in * this time signature. */ void getDurationListForBar(DurationList &dlist) const; /** * Get the "optimal" list of rest durations to make up a time * interval of the given total duration, starting at the given * offset after the start of a bar, assuming that the interval * is entirely in this time signature. */ void getDurationListForInterval(DurationList &dlist, timeT intervalDuration, timeT startOffset = 0) const; /** * Get the level of emphasis for a position in a bar. 4 is lots * of emphasis, 0 is none. */ int getEmphasisForTime(timeT offset); /** * Return a list of divisions, subdivisions, subsubdivisions * etc of a bar in this time, up to the given depth. For example, * if the time signature is 6/8 and the depth is 3, return a list * containing 2, 3, and 2 (there are 2 beats to the bar, each of * which is best subdivided into 3 subdivisions, each of which * divides most neatly into 2). */ void getDivisions(int depth, std::vector &divisions) const; private: friend class Composition; friend class TimeTempoSelection; TimeSignature(const Event &e) /* throw (Event::NoData, Event::BadType, BadTimeSignature) */; static const std::string EventType; static const int EventSubOrdering; static const PropertyName NumeratorPropertyName; static const PropertyName DenominatorPropertyName; static const PropertyName ShowAsCommonTimePropertyName; static const PropertyName IsHiddenPropertyName; static const PropertyName HasHiddenBarsPropertyName; /// Returned event is on heap; caller takes responsibility for ownership Event *getAsEvent(timeT absoluteTime) const; private: int m_numerator; int m_denominator; bool m_common; bool m_hidden; bool m_hiddenBars; mutable int m_barDuration; mutable int m_beatDuration; mutable int m_beatDivisionDuration; mutable bool m_dotted; void setInternalDurations() const; // a time & effort saving device static const timeT m_crotchetTime; static const timeT m_dottedCrotchetTime; }; /** * AccidentalTable represents a set of accidentals in force at a * given time. * * Keep an AccidentalTable variable on-hand as you track through a * staff; then when reading a chord, call processDisplayAccidental * on the accidentals found in the chord to obtain the actual * displayed accidentals and to tell the AccidentalTable to * remember the accidentals that have been found in the chord. * Then when the chord ends, call update() on the AccidentalTable * so that that chord's accidentals are taken into account for the * next one. * * Create a new AccidentalTable whenever a new key is encountered, * and call newBar() or newClef() when a new bar happens or a new * clef is encountered. */ class AccidentalTable { public: enum OctaveType { OctavesIndependent, // if c' and c'' sharp, mark them both sharp OctavesCautionary, // if c' and c'' sharp, put the second one in brackets OctavesEquivalent // if c' and c'' sharp, only mark the first one }; enum BarResetType { BarResetNone, // c# | c -> omit natural BarResetCautionary, // c# | c -> add natural to c in brackets BarResetExplicit // c# | c -> add natural to c }; AccidentalTable(const Key &, const Clef &, OctaveType = OctavesCautionary, BarResetType = BarResetCautionary); AccidentalTable(const AccidentalTable &); AccidentalTable &operator=(const AccidentalTable &); Accidental processDisplayAccidental(const Accidental &displayAcc, int heightOnStaff, bool &cautionary); void update(); void newBar(); void newClef(const Clef &); private: Key m_key; Clef m_clef; OctaveType m_octaves; BarResetType m_barReset; struct AccidentalRec { AccidentalRec() : accidental(Accidentals::NoAccidental), previousBar(false) { } AccidentalRec(Accidental a, bool p) : accidental(a), previousBar(p) { } Accidental accidental; bool previousBar; }; typedef std::map AccidentalMap; AccidentalMap m_accidentals; AccidentalMap m_canonicalAccidentals; AccidentalMap m_newAccidentals; AccidentalMap m_newCanonicalAccidentals; }; } #endif