You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rosegarden/src/base/NotationTypes.h

1340 lines
42 KiB

/*
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 _NOTATION_TYPES_H_
#define _NOTATION_TYPES_H_
#include <list>
#include <map>
#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<int> 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<Accidental> 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<Mark> 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<Mark> 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<Clef> 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<int> 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<Key> 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<int> *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<std::string, KeyDetails> 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<std::string> getUserStyles();
/**
* Return a list of available special LilyPond directives
*/
static std::vector<std::string> 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<int> &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<int, AccidentalRec> AccidentalMap;
AccidentalMap m_accidentals;
AccidentalMap m_canonicalAccidentals;
AccidentalMap m_newAccidentals;
AccidentalMap m_newCanonicalAccidentals;
};
}
#endif