VocalEasel/Sources/VLModel.h

543 lines
14 KiB
C
Raw Normal View History

2007-04-27 06:41:34 +00:00
//
// File: VLModel.h - Represent music for a song.
//
// Author(s):
//
// (MN) Matthias Neeracher
//
2018-02-19 00:59:23 +00:00
// Copyright © 2005-2018 Matthias Neeracher
2007-04-27 06:41:34 +00:00
//
2006-09-11 02:49:56 +00:00
#include <list>
#include <vector>
#include <string>
#include <inttypes.h>
2011-09-11 21:27:53 +00:00
#ifndef __VLMODEL__
#define __VLMODEL__
2011-08-27 22:12:32 +00:00
#pragma mark -
#pragma mark class VLFraction
2006-09-11 02:49:56 +00:00
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);
2007-09-06 00:41:40 +00:00
2006-09-11 02:49:56 +00:00
VLFraction & Normalize();
2011-09-12 14:17:21 +00:00
bool IsPowerOfTwo() const;
2006-09-11 02:49:56 +00:00
};
inline float operator*(VLFraction f, float sc)
{
return sc*f.fNum/f.fDenom;
}
2006-09-11 02:49:56 +00:00
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;
}
2011-09-11 02:03:22 +00:00
inline bool operator!(VLFract fract)
{
return !fract.fNum;
}
inline bool operator==(VLFract one, VLFract other)
2006-09-11 02:49:56 +00:00
{
return one.fNum*other.fDenom == other.fNum*one.fDenom;
}
2011-09-11 02:03:22 +00:00
inline bool operator!=(VLFract one, VLFract other)
2006-09-11 02:49:56 +00:00
{
return one.fNum*other.fDenom != other.fNum*one.fDenom;
}
2011-09-11 02:03:22 +00:00
inline bool operator<(VLFract one, VLFract other)
2006-09-11 02:49:56 +00:00
{
return one.fNum*other.fDenom < other.fNum*one.fDenom;
}
2011-09-11 02:03:22 +00:00
inline bool operator>(VLFract one, VLFract other)
2006-09-11 02:49:56 +00:00
{
return one.fNum*other.fDenom > other.fNum*one.fDenom;
}
2011-09-11 02:03:22 +00:00
inline bool operator<=(VLFract one, VLFract other)
2006-09-11 02:49:56 +00:00
{
return one.fNum*other.fDenom <= other.fNum*one.fDenom;
}
2011-09-11 02:03:22 +00:00
inline bool operator>=(VLFract one, VLFract other)
2006-09-11 02:49:56 +00:00
{
return one.fNum*other.fDenom >= other.fNum*one.fDenom;
}
2011-09-11 02:03:22 +00:00
#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);
}
2011-08-27 22:12:32 +00:00
#pragma mark -
#pragma mark class VLNote
2006-10-23 07:42:53 +00:00
2006-09-11 02:49:56 +00:00
struct VLNote {
VLFraction fDuration;
int8_t fPitch; // Semitones
enum {
kNoPitch = -128,
2006-10-23 07:42:53 +00:00
kMiddleC = 60,
kOctave = 12
2006-09-11 02:49:56 +00:00
};
//
2018-02-19 00:59:23 +00:00
// We only allow ties BETWEEN measures or different pitches. Within measures, we
// just store a combined note length.
2006-09-11 02:49:56 +00:00
//
2018-02-19 00:59:23 +00:00
uint8_t fTied; // Tied with adjacent note
2006-09-11 02:49:56 +00:00
enum {
kNotTied = 0,
kTiedWithNext = 1,
2007-05-27 07:16:46 +00:00
kTiedWithPrev = 2,
2018-02-19 00:59:23 +00:00
kSlurWithNext = 4,
kSlurWithPrev = 8,
kStartSlur = 16,
kEndSlur = 32,
2006-09-11 02:49:56 +00:00
};
2007-05-21 08:18:58 +00:00
//
// Hint at visual representation (Computed in DecomposeNotes)
//
uint16_t fVisual;
2007-05-21 08:18:58 +00:00
enum {
kWhole = 0,
kHalf = 1,
kQuarter = 2,
kEighth = 3,
k16th = 4,
k32nd = 5,
2007-05-21 08:18:58 +00:00
kNoteHeadMask = 0x0007,
kWantSharp = 0x10,
kWant2Sharp = 0x20,
2011-08-31 02:02:37 +00:00
kPreferSharps = 0x30, // kWantSharp | kWant2Sharp
kWantFlat = 0x40,
kWant2Flat = 0x80,
2011-08-31 02:02:37 +00:00
kPreferFlats = 0xC0, // kWantFlat | kWant2Flat
kWantNatural = 0x50, // kWantSharp | kWantFlat
kNaturalOrSharp = 0x70, // kPreferSharps| kWantFlat
kNaturalOrFlat = 0xD0, // kPreferFlats | kWantSharp
kAccidentalsMask= 0x00F0,
2011-08-31 02:02:37 +00:00
kTriplet = 0x3200,
2011-08-27 22:12:32 +00:00
2011-08-31 02:02:37 +00:00
kTupletMask = 0xFF00
2007-05-21 08:18:58 +00:00
};
2018-02-19 00:59:23 +00:00
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); }
2011-08-27 22:12:32 +00:00
VLNote(VLFraction dur=0, int pitch=kNoPitch, uint16_t visual=0);
2006-09-11 02:49:56 +00:00
VLNote(std::string name);
2011-08-27 22:12:32 +00:00
std::string Name(uint16_t accidentals=0) const;
2007-05-21 08:18:58 +00:00
void MakeRepresentable();
void AlignToGrid(VLFraction at, VLFraction grid);
2006-09-11 02:49:56 +00:00
};
2011-08-27 22:12:32 +00:00
#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<VLSyllable> fLyrics;
};
typedef std::list<VLLyricsNote> VLNoteList;
#pragma mark -
#pragma mark VLChord
2006-09-11 02:49:56 +00:00
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),
2006-10-21 09:24:50 +00:00
kmDim7th = (1 << kDim7th),
2006-09-11 02:49:56 +00:00
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
2011-08-27 22:12:32 +00:00
uint16_t fRootAccidental;
2006-09-11 02:49:56 +00:00
2007-05-21 08:18:58 +00:00
VLChord(VLFraction dur=0, int pitch=kNoPitch, int rootPitch=kNoPitch);
2006-09-11 02:49:56 +00:00
VLChord(std::string name);
2011-08-27 22:12:32 +00:00
void Name(std::string & base, std::string & ext, std::string & root, uint16_t accidental=0) const;
2006-09-11 02:49:56 +00:00
};
2011-08-27 22:12:32 +00:00
typedef std::list<VLChord> VLChordList;
#pragma mark class VLChordModifier
2007-05-27 04:35:45 +00:00
struct VLChordModifier {
const char * fName;
uint32_t fAddSteps;
uint32_t fDelSteps;
};
2011-08-27 22:12:32 +00:00
#pragma mark -
#pragma mark class VLProperties
2006-09-11 02:49:56 +00:00
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
2011-08-27 22:12:32 +00:00
2007-01-02 07:09:06 +00:00
bool operator==(const VLProperties & other)
{ return fTime == other.fTime && fKey == other.fKey && fMode == other.fMode
2011-08-27 22:12:32 +00:00
&& fDivisions == other.fDivisions && fGroove == other.fGroove;
2007-01-02 07:09:06 +00:00
}
2006-09-11 02:49:56 +00:00
};
2011-08-27 22:12:32 +00:00
typedef std::vector<VLProperties> VLPropertyList;
2006-09-11 02:49:56 +00:00
2011-08-27 22:12:32 +00:00
#pragma mark class VLMeasure
2006-09-11 02:49:56 +00:00
struct VLMeasure {
2007-12-23 23:07:27 +00:00
enum {
kNewSystem = 1,
kNewPage = 2
};
uint8_t fBreak;
2006-12-04 07:04:24 +00:00
int8_t fPropIdx;
VLChordList fChords;
VLNoteList fMelody;
2006-09-11 02:49:56 +00:00
VLMeasure();
2006-11-04 08:15:34 +00:00
2007-05-04 05:21:16 +00:00
bool IsEmpty() const;
bool NoChords() const;
bool CanSkipRests() const;
2018-02-19 00:59:23 +00:00
bool SlurAtStart() const;
bool SlurAtEnd() const;
2007-05-21 08:18:58 +00:00
void DecomposeNotes(const VLProperties & prop, VLNoteList & decomposed) const;
2006-09-11 02:49:56 +00:00
};
2011-08-27 22:12:32 +00:00
typedef std::vector<VLMeasure> 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<Ending> fEndings;
};
typedef std::vector<VLRepeat> VLRepeatList;
2011-08-27 22:12:32 +00:00
#pragma mark -
#pragma mark class VLSong
class VLSong {
public:
2007-01-02 07:09:06 +00:00
VLSong(bool initialize = true);
2006-12-04 07:04:24 +00:00
void swap(VLSong & other);
2007-04-27 03:56:25 +00:00
void clear();
2006-09-11 02:49:56 +00:00
VLPropertyList fProperties;
VLMeasureList fMeasures;
VLRepeatList fRepeats;
2011-09-11 02:03:22 +00:00
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<Repeat> fStatus;
void AdjustStatus();
};
iterator begin() { return iterator(*this, false); }
iterator end() { return iterator(*this, true); }
2006-09-11 02:49:56 +00:00
2018-02-19 00:59:23 +00:00
// Iterate over all notes in song
class note_iterator {
public:
note_iterator(const VLMeasureList::iterator &meas, const VLNoteList::iterator &note);
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();
2011-09-26 02:49:09 +00:00
VLLyricsNote FindNote(VLLocation at);
bool PrevNote(VLLocation & at);
bool NextNote(VLLocation & at);
2011-09-11 02:03:22 +00:00
void AddChord(VLChord chord, VLLocation at);
void AddNote(VLLyricsNote note, VLLocation at);
void DelChord(VLLocation at);
void DelNote(VLLocation at);
VLNote ExtendNote(VLLocation at);
2018-02-19 00:59:23 +00:00
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;
2007-05-27 07:16:46 +00:00
bool DoesTieWithPrevRepeat(size_t measure) const;
bool DoesTieWithNextRepeat(size_t measure) const;
2007-01-21 11:32:24 +00:00
bool IsNonEmpty() const;
void ChangeKey(int section, int newKey, int newMode, bool transpose);
2008-04-12 21:33:43 +00:00
void ChangeOctave(int section, bool transposeUp);
void ChangeDivisions(int section, int newDivisions);
void ChangeTime(int section, VLFraction newTime);
2006-10-02 05:29:37 +00:00
2011-09-11 02:03:22 +00:00
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);
2006-11-27 07:07:45 +00:00
2007-01-02 07:09:06 +00:00
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);
2007-05-07 04:01:29 +00:00
void DeleteMeasures(size_t beginMeasure, size_t endMeasure, int mode = kInsert);
2011-09-08 02:10:49 +00:00
void InsertMeasure(size_t beginMeasure);
2006-10-02 05:29:37 +00:00
size_t CountMeasures() const { return fMeasures.size(); }
2007-05-04 05:21:16 +00:00
size_t EmptyEnding() const;
2006-11-27 07:07:45 +00:00
size_t CountStanzas() const;
size_t CountTopLedgers() const;
size_t CountBotLedgers() const;
VLFract TiedDuration(size_t measure);
2007-12-23 13:14:09 +00:00
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);
2007-12-25 13:12:07 +00:00
bool DoesBeginSection(size_t measure) const;
2007-12-25 13:12:07 +00:00
void AddSection(size_t measure);
void DelSection(size_t measure);
std::string PrimaryGroove() const;
2007-05-04 05:21:16 +00:00
private:
void AddMeasure();
2006-09-11 02:49:56 +00:00
};
2011-08-27 22:12:32 +00:00
#pragma mark class VLSongVisitor
class VLSongVisitor {
public:
virtual ~VLSongVisitor();
2018-02-19 00:59:23 +00:00
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);
2018-02-19 00:59:23 +00:00
private:
VLSong *fSong;
};
2011-09-11 21:27:53 +00:00
#endif
2006-09-11 02:49:56 +00:00
// Local Variables:
// mode:C++
// End: