// // File: VLModel.h - Represent music for a song. // // Author(s): // // (MN) Matthias Neeracher // // Copyright © 2005-2018 Matthias Neeracher // #include #include #include #include #ifndef __VLMODEL__ #define __VLMODEL__ #pragma mark - #pragma mark class VLFraction struct VLFract { uint16_t fNum; // Numerator uint16_t fDenom; // Denominator }; struct VLFraction : VLFract { VLFraction(uint16_t num = 0, uint16_t denom = 1, bool norm=false) { fNum = num; fDenom = denom; if (norm) Normalize(); } VLFraction(VLFract f) : VLFract(f) {} VLFraction & operator+=(VLFraction other); VLFraction & operator-=(VLFraction other); VLFraction & operator*=(VLFraction other); VLFraction & operator/=(VLFraction other); VLFraction & operator%=(VLFraction other); VLFraction & Normalize(); bool IsPowerOfTwo() const; }; inline float operator*(VLFraction f, float sc) { return sc*f.fNum/f.fDenom; } inline VLFraction operator+(VLFraction one, VLFraction other) { return one += other; } inline VLFraction operator-(VLFraction one, VLFraction other) { return one -= other; } inline VLFraction operator*(VLFraction one, VLFraction other) { return one *= other; } inline VLFraction operator/(VLFraction one, VLFraction other) { return one /= other; } inline VLFraction operator%(VLFraction one, VLFraction other) { return one %= other; } inline bool operator!(VLFract fract) { return !fract.fNum; } inline bool operator==(VLFract one, VLFract other) { return one.fNum*other.fDenom == other.fNum*one.fDenom; } inline bool operator!=(VLFract one, VLFract other) { return one.fNum*other.fDenom != other.fNum*one.fDenom; } inline bool operator<(VLFract one, VLFract other) { return one.fNum*other.fDenom < other.fNum*one.fDenom; } inline bool operator>(VLFract one, VLFract other) { return one.fNum*other.fDenom > other.fNum*one.fDenom; } inline bool operator<=(VLFract one, VLFract other) { return one.fNum*other.fDenom <= other.fNum*one.fDenom; } inline bool operator>=(VLFract one, VLFract other) { return one.fNum*other.fDenom >= other.fNum*one.fDenom; } #pragma mark - #pragma mark struct VLLocation struct VLLocation { uint32_t fMeasure; VLFract fAt; }; inline bool operator==(const VLLocation & one, const VLLocation & other) { return one.fMeasure == other.fMeasure && one.fAt == other.fAt; } inline bool operator!=(const VLLocation & one, const VLLocation & other) { return one.fMeasure != other.fMeasure || one.fAt != other.fAt; } inline bool operator<(const VLLocation & one, const VLLocation & other) { return one.fMeasure < other.fMeasure || (one.fMeasure == other.fMeasure && one.fAt < other.fAt); } inline bool operator<=(const VLLocation & one, const VLLocation & other) { return one.fMeasure < other.fMeasure || (one.fMeasure == other.fMeasure && one.fAt <= other.fAt); } inline bool operator>(const VLLocation & one, const VLLocation & other) { return one.fMeasure > other.fMeasure || (one.fMeasure == other.fMeasure && one.fAt > other.fAt); } inline bool operator>=(const VLLocation & one, const VLLocation & other) { return one.fMeasure > other.fMeasure || (one.fMeasure == other.fMeasure && one.fAt >= other.fAt); } #pragma mark - #pragma mark class VLNote struct VLNote { VLFraction fDuration; int8_t fPitch; // Semitones enum { kNoPitch = -128, kMiddleC = 60, kOctave = 12 }; // // We only allow ties BETWEEN measures or different pitches. Within measures, we // just store a combined note length. // uint8_t fTied; // Tied with adjacent note enum { kNotTied = 0, kTiedWithNext = 1, kTiedWithPrev = 2, kSlurWithNext = 4, kSlurWithPrev = 8, kStartSlur = 16, kEndSlur = 32, }; // // Hint at visual representation (Computed in DecomposeNotes) // uint16_t fVisual; enum { kWhole = 0, kHalf = 1, kQuarter = 2, kEighth = 3, k16th = 4, k32nd = 5, kNoteHeadMask = 0x0007, kWantSharp = 0x10, kWant2Sharp = 0x20, kPreferSharps = 0x30, // kWantSharp | kWant2Sharp kWantFlat = 0x40, kWant2Flat = 0x80, kPreferFlats = 0xC0, // kWantFlat | kWant2Flat kWantNatural = 0x50, // kWantSharp | kWantFlat kNaturalOrSharp = 0x70, // kPreferSharps| kWantFlat kNaturalOrFlat = 0xD0, // kPreferFlats | kWantSharp kAccidentalsMask= 0x00F0, kTriplet = 0x3200, kTupletMask = 0xFF00 }; static uint16_t TupletNum(uint16_t visual) { return visual >> 12; } static uint16_t TupletDenom(uint16_t visual) { return (visual >> 8) & 0x0F; } static uint16_t Tuplet(int num, int denom) { return (num << 12) | (denom << 8); } VLNote(VLFraction dur=0, int pitch=kNoPitch, uint16_t visual=0); VLNote(std::string name); std::string Name(uint16_t accidentals=0) const; void MakeRepresentable(); void AlignToGrid(VLFraction at, VLFraction grid); }; #pragma mark class VLSyllable struct VLSyllable { std::string fText; // Syllable text uint8_t fKind; // Adjacency information enum { kSingle = 0, kBegin = 1, kEnd = 2, kMiddle = 3, kHasNext = 1, kHasPrev = 2 }; operator bool() const { return fText.size() > 0; } }; #pragma mark class VLLyricsNote struct VLLyricsNote : VLNote { VLLyricsNote(const VLNote & note); VLLyricsNote(VLFraction dur=0, int pitch = kNoPitch, uint16_t visual=0); std::vector fLyrics; }; typedef std::list VLNoteList; #pragma mark - #pragma mark VLChord struct VLChord : VLNote { uint32_t fSteps; // Notes in chord, listed in semitones enum { kUnison = 0, kMin2nd, kMaj2nd, kMin3rd, kMaj3rd, k4th, kDim5th, k5th, kAug5th, kDim7th, kMin7th, kMaj7th, kOctave, kMin9th, kMaj9th, kAug9th, kDim11th, k11th, kAug11th, kDim13th, kMin13th, kMaj13th, kmUnison = (1 << kUnison), kmMin2nd = (1 << kMin2nd), kmMaj2nd = (1 << kMaj2nd), kmMin3rd = (1 << kMin3rd), kmMaj3rd = (1 << kMaj3rd), km4th = (1 << k4th), kmDim5th = (1 << kDim5th), km5th = (1 << k5th), kmAug5th = (1 << kAug5th), kmDim7th = (1 << kDim7th), kmMin7th = (1 << kMin7th), kmMaj7th = (1 << kMaj7th), kmOctave = (1 << kOctave), kmMin9th = (1 << kMin9th), kmMaj9th = (1 << kMaj9th), kmAug9th = (1 << kAug9th), kmDim11th = (1 << kDim11th), km11th = (1 << k11th), kmAug11th = (1 << kAug11th), kmDim13th = (1 << kDim13th), kmMin13th = (1 << kMin13th), kmMaj13th = (1 << kMaj13th) }; int8_t fRootPitch; // kNoPitch == no root uint16_t fRootAccidental; VLChord(VLFraction dur=0, int pitch=kNoPitch, int rootPitch=kNoPitch); VLChord(std::string name); void Name(std::string & base, std::string & ext, std::string & root, uint16_t accidental=0) const; }; typedef std::list VLChordList; #pragma mark class VLChordModifier struct VLChordModifier { const char * fName; uint32_t fAddSteps; uint32_t fDelSteps; }; #pragma mark - #pragma mark class VLProperties struct VLProperties { VLFraction fTime; // Time (non-normalized) int8_t fKey; // Circle of fifths from C, >0 sharps, <0 flats int8_t fMode; // 1 = major -1 = minor int8_t fDivisions; // Number of divisions per quarter note std::string fGroove; // MMA Groove bool operator==(const VLProperties & other) { return fTime == other.fTime && fKey == other.fKey && fMode == other.fMode && fDivisions == other.fDivisions && fGroove == other.fGroove; } }; typedef std::vector VLPropertyList; #pragma mark class VLMeasure struct VLMeasure { enum { kNewSystem = 1, kNewPage = 2 }; uint8_t fBreak; int8_t fPropIdx; VLChordList fChords; VLNoteList fMelody; VLMeasure(); bool IsEmpty() const; bool NoChords() const; bool CanSkipRests() const; bool SlurAtStart() const; bool SlurAtEnd() const; void DecomposeNotes(const VLProperties & prop, VLNoteList & decomposed) const; }; typedef std::vector VLMeasureList; #pragma mark class VLRepeat struct VLRepeat { int8_t fTimes; struct Ending { Ending(int8_t begin, int8_t end, uint16_t volta) : fBegin(begin), fEnd(end), fVolta(volta) {} int8_t fBegin; int8_t fEnd; uint16_t fVolta; }; std::vector fEndings; }; typedef std::vector VLRepeatList; #pragma mark - #pragma mark class VLSong class VLSong { public: VLSong(bool initialize = true); void swap(VLSong & other); void clear(); VLPropertyList fProperties; VLMeasureList fMeasures; VLRepeatList fRepeats; int16_t fGoToCoda; int16_t fCoda; // // Iterate over measures in performance order // class iterator { public: size_t operator*() { return fMeasure; } iterator & operator++(); bool operator==(const iterator & other) const { return fMeasure==other.fMeasure && fStatus == other.fStatus; } bool operator!=(const iterator & other) const { return fMeasure!=other.fMeasure || fStatus != other.fStatus; } protected: friend class VLSong; iterator(const VLSong & song, bool end); private: size_t fMeasure; const VLSong & fSong; struct Repeat { Repeat(size_t begin, int times) : fBegin(begin), fTimes(times), fVolta(0) {} size_t fBegin; int8_t fTimes; int8_t fVolta; bool operator==(const Repeat & other) const { return fBegin==other.fBegin && fVolta == other.fVolta; } bool operator!=(const Repeat & other) const { return fBegin!=other.fBegin || fVolta != other.fVolta; } }; std::vector fStatus; void AdjustStatus(); }; iterator begin() { return iterator(*this, false); } iterator end() { return iterator(*this, true); } // Iterate over all notes in song class note_iterator { public: note_iterator(const VLMeasureList::iterator &meas, const VLNoteList::iterator ¬e); VLLyricsNote &operator*() { return *fNoteIter; } VLLyricsNote *operator->() { return &*fNoteIter; } note_iterator &operator--(); note_iterator &operator++(); bool operator==(const note_iterator &other); bool operator!=(const note_iterator &other) { return !(*this == other); } private: VLNoteList::iterator fNoteIter; VLMeasureList::iterator fMeasIter; }; note_iterator begin_note(size_t measure=0); note_iterator end_note(size_t measure); note_iterator end_note(); VLLyricsNote FindNote(VLLocation at); bool PrevNote(VLLocation & at); bool NextNote(VLLocation & at); void AddChord(VLChord chord, VLLocation at); void AddNote(VLLyricsNote note, VLLocation at); void DelChord(VLLocation at); void DelNote(VLLocation at); VLNote ExtendNote(VLLocation at); VLLocation TieNote(VLLocation at, bool tieWithPrev); void AddRepeat(size_t beginMeasure, size_t endMeasure, int times); void DelRepeat(size_t beginMeasure, size_t endMeasure); void AddEnding(size_t beginMeasure, size_t endMeasure, size_t volta); void DelEnding(size_t beginMeasure, size_t endMeasure); bool CanBeRepeat(size_t beginMeasure, size_t endMeasure, int * times = 0); bool CanBeEnding(size_t beginMeasure, size_t endMeasure, size_t * volta = 0, size_t * voltaOK = 0); bool DoesBeginRepeat(size_t measure, int * times = 0) const; bool DoesEndRepeat(size_t measure, int * times = 0) const; bool DoesBeginEnding(size_t measure, bool * repeat = 0, size_t * volta = 0) const; bool DoesEndEnding(size_t measure, bool * repeat = 0, size_t * volta = 0) const; bool DoesTieWithPrevRepeat(size_t measure) const; bool DoesTieWithNextRepeat(size_t measure) const; bool IsNonEmpty() const; void ChangeKey(int section, int newKey, int newMode, bool transpose); void ChangeOctave(int section, bool transposeUp); void ChangeDivisions(int section, int newDivisions); void ChangeTime(int section, VLFraction newTime); bool FindWord(size_t stanza, VLLocation & at); bool PrevWord(size_t stanza, VLLocation & at); bool NextWord(size_t stanza, VLLocation & at); std::string GetWord(size_t stanza, VLLocation at); void SetWord(size_t stanza, VLLocation at, std::string word, VLLocation * nextAt=0); enum { kInsert, kOverwriteChords = 1, kOverwriteMelody = 2 }; VLSong CopyMeasures(size_t beginMeasure, size_t endMeasure); void PasteMeasures(size_t beginMeasure, const VLSong & measures, int mode = kInsert); void DeleteMeasures(size_t beginMeasure, size_t endMeasure, int mode = kInsert); void InsertMeasure(size_t beginMeasure); size_t CountMeasures() const { return fMeasures.size(); } size_t EmptyEnding() const; size_t CountStanzas() const; size_t CountTopLedgers() const; size_t CountBotLedgers() const; VLFract TiedDuration(size_t measure); VLProperties & Properties(size_t measure) { return fProperties[fMeasures[measure].fPropIdx]; } const VLProperties & Properties(size_t measure) const { return fProperties[fMeasures[measure].fPropIdx]; } void SetProperties(size_t measure, int propIdx); bool DoesBeginSection(size_t measure) const; void AddSection(size_t measure); void DelSection(size_t measure); std::string PrimaryGroove() const; private: void AddMeasure(); }; #pragma mark class VLSongVisitor class VLSongVisitor { public: virtual ~VLSongVisitor(); virtual void Visit(VLSong & song) {} virtual void VisitMeasure(uint32_t m, VLProperties & p, VLMeasure & meas) {} virtual void VisitNote(VLLyricsNote & n) {} virtual void VisitChord(VLChord & c) {} protected: VLSongVisitor() {} void VisitMeasures(VLSong & song, bool performanceOrder); void VisitNotes(VLMeasure & measure, const VLProperties & prop, bool decomposed); void VisitChords(VLMeasure & measure); private: VLSong *fSong; }; #endif // Local Variables: // mode:C++ // End: