2007-04-27 06:41:34 +00:00
|
|
|
//
|
|
|
|
// File: VLModel.h - Represent music for a song.
|
|
|
|
//
|
|
|
|
// Author(s):
|
|
|
|
//
|
|
|
|
// (MN) Matthias Neeracher
|
|
|
|
//
|
|
|
|
// Copyright © 2005-2007 Matthias Neeracher
|
|
|
|
//
|
2006-09-11 02:49:56 +00:00
|
|
|
|
|
|
|
#include <list>
|
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
|
|
|
#include <inttypes.h>
|
|
|
|
|
2006-10-24 07:15:46 +00:00
|
|
|
const int kVLSharpChar = 0x266F;
|
|
|
|
const int kVLFlatChar = 0x266D;
|
2006-10-28 09:18:55 +00:00
|
|
|
#define kVLSharpStr "\xE2\x99\xAF"
|
|
|
|
#define kVLFlatStr "\xE2\x99\xAD"
|
2006-10-24 07:15:46 +00:00
|
|
|
|
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);
|
|
|
|
private:
|
|
|
|
VLFraction & Normalize();
|
|
|
|
};
|
|
|
|
|
2006-10-02 08:32:25 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator==(VLFraction one, VLFraction other)
|
|
|
|
{
|
|
|
|
return one.fNum*other.fDenom == other.fNum*one.fDenom;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator!=(VLFraction one, VLFraction other)
|
|
|
|
{
|
|
|
|
return one.fNum*other.fDenom != other.fNum*one.fDenom;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator<(VLFraction one, VLFraction other)
|
|
|
|
{
|
|
|
|
return one.fNum*other.fDenom < other.fNum*one.fDenom;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator>(VLFraction one, VLFraction other)
|
|
|
|
{
|
|
|
|
return one.fNum*other.fDenom > other.fNum*one.fDenom;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator<=(VLFraction one, VLFraction other)
|
|
|
|
{
|
|
|
|
return one.fNum*other.fDenom <= other.fNum*one.fDenom;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator>=(VLFraction one, VLFraction other)
|
|
|
|
{
|
|
|
|
return one.fNum*other.fDenom >= other.fNum*one.fDenom;
|
|
|
|
}
|
|
|
|
|
2006-10-23 07:42:53 +00:00
|
|
|
class VLProperties;
|
|
|
|
|
2006-11-27 07:07:45 +00:00
|
|
|
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; }
|
|
|
|
};
|
|
|
|
|
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
|
|
|
};
|
|
|
|
//
|
|
|
|
// We only allow ties BETWEEN measures. Within measures, we just store
|
|
|
|
// a combined note length.
|
|
|
|
//
|
|
|
|
uint8_t fTied; // Tied with note in adjacent measure
|
|
|
|
enum {
|
|
|
|
kNotTied = 0,
|
|
|
|
kTiedWithNext = 1,
|
|
|
|
kTiedWithPrev = 2
|
|
|
|
};
|
2006-11-27 07:07:45 +00:00
|
|
|
|
2006-09-11 02:49:56 +00:00
|
|
|
VLNote() : fPitch(kNoPitch) {}
|
|
|
|
VLNote(VLFraction dur, int8_t pitch)
|
|
|
|
: fDuration(dur), fPitch(pitch), fTied(kNotTied)
|
|
|
|
{}
|
|
|
|
VLNote(std::string name);
|
|
|
|
|
|
|
|
void Name(std::string & name, bool useSharps = false) const;
|
2007-01-01 05:02:17 +00:00
|
|
|
void LilypondName(std::string & name, VLFraction at, VLFraction prevDur, VLFraction nextDur, bool & triplet, const VLProperties & prop) const;
|
2007-04-22 06:20:17 +00:00
|
|
|
void MMAName(std::string & name, VLFraction at, VLFraction dur, VLFraction prevDur, VLFraction nextDur, const VLProperties & prop) const;
|
2006-09-11 02:49:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct VLRest : VLNote {
|
|
|
|
VLRest(VLFraction duration) : VLNote(duration, kNoPitch) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
VLChord() {}
|
|
|
|
VLChord(std::string name);
|
|
|
|
void Name(std::string & base, std::string & ext, std::string & root, bool useSharps = false) const;
|
2006-10-21 09:24:50 +00:00
|
|
|
void LilypondName(std::string & name, bool useSharps = false) const;
|
2007-04-23 05:46:37 +00:00
|
|
|
bool MMAName(std::string & name, bool useSharps, bool initial) const;
|
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
|
|
|
|
|
|
|
|
//
|
|
|
|
// Subdivide a note and adjust for swing
|
|
|
|
//
|
2007-01-01 05:02:17 +00:00
|
|
|
void PartialNote(VLFraction at, VLFraction totalDuration, bool grouped, VLFraction * noteDuration) const;
|
2006-10-23 07:42:53 +00:00
|
|
|
//
|
|
|
|
// Determine visual representation of note head
|
|
|
|
//
|
2007-01-01 05:02:17 +00:00
|
|
|
void VisualNote(VLFraction at, VLFraction actualDur, bool prevTriplet, VLFraction *visualDur, bool * triplet) const;
|
2007-01-02 07:09:06 +00:00
|
|
|
|
|
|
|
bool operator==(const VLProperties & other)
|
|
|
|
{ return fTime == other.fTime && fKey == other.fKey && fMode == other.fMode
|
|
|
|
&& fDivisions == other.fDivisions;
|
|
|
|
}
|
2006-09-11 02:49:56 +00:00
|
|
|
};
|
|
|
|
|
2006-11-27 07:07:45 +00:00
|
|
|
struct VLLyricsNote : VLNote {
|
|
|
|
VLLyricsNote() {}
|
|
|
|
explicit VLLyricsNote(const VLNote & note)
|
|
|
|
{ *static_cast<VLNote *>(this) = note; }
|
|
|
|
|
|
|
|
std::vector<VLSyllable> fLyrics;
|
2006-09-11 02:49:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::list<VLChord> VLChordList;
|
2006-11-27 07:07:45 +00:00
|
|
|
typedef std::list<VLLyricsNote> VLNoteList;
|
2006-09-11 02:49:56 +00:00
|
|
|
|
|
|
|
struct VLMeasure {
|
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-04-22 06:20:17 +00:00
|
|
|
void MMANotes(std::string & notes, const VLProperties & prop, VLFraction extra) const;
|
2007-04-23 05:46:37 +00:00
|
|
|
void MMAChords(std::string & chords, const VLProperties & prop, bool initial) const;
|
2006-09-11 02:49:56 +00:00
|
|
|
};
|
|
|
|
|
2006-12-30 09:57:40 +00:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2006-09-11 02:49:56 +00:00
|
|
|
struct VLSong {
|
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
|
|
|
|
2006-12-04 07:04:24 +00:00
|
|
|
std::vector<VLProperties> fProperties;
|
|
|
|
std::vector<VLMeasure> fMeasures;
|
2006-12-30 09:57:40 +00:00
|
|
|
std::vector<VLRepeat> fRepeats;
|
2007-01-21 11:32:24 +00:00
|
|
|
int8_t fGoToCoda;
|
|
|
|
int8_t fCoda;
|
2006-12-30 09:57:40 +00:00
|
|
|
|
2006-12-31 10:31:29 +00:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
|
|
|
void AddChord(VLChord chord, size_t measure, VLFraction at);
|
2006-11-27 07:07:45 +00:00
|
|
|
void AddNote(VLLyricsNote note, size_t measure, VLFraction at);
|
2006-09-11 02:49:56 +00:00
|
|
|
void DelChord(size_t measure, VLFraction at);
|
|
|
|
void DelNote(size_t measure, VLFraction at);
|
2007-04-22 02:59:52 +00:00
|
|
|
void ExtendNote(size_t measure, VLFraction at);
|
2006-12-30 09:57:40 +00:00
|
|
|
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);
|
2006-12-31 10:31:29 +00:00
|
|
|
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-01-21 11:32:24 +00:00
|
|
|
bool IsNonEmpty() const;
|
2006-10-14 10:09:42 +00:00
|
|
|
void Transpose(int semitones);
|
2006-10-02 05:29:37 +00:00
|
|
|
|
2006-12-02 03:35:21 +00:00
|
|
|
bool FindWord(size_t stanza, size_t & measure, VLFraction & at);
|
|
|
|
bool PrevWord(size_t stanza, size_t & measure, VLFraction & at);
|
|
|
|
bool NextWord(size_t stanza, size_t & measure, VLFraction & at);
|
2006-12-02 09:02:44 +00:00
|
|
|
std::string GetWord(size_t stanza, size_t measure, VLFraction at);
|
2007-04-13 04:26:35 +00:00
|
|
|
void SetWord(size_t stanza, size_t measure, VLFraction at, std::string word,
|
|
|
|
size_t * nextMeas=0, VLFract * 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);
|
|
|
|
void DeleteMeasures(size_t beginMeasure, size_t endMeasure);
|
|
|
|
|
2006-10-02 05:29:37 +00:00
|
|
|
size_t CountMeasures() const { return fMeasures.size(); }
|
2006-11-27 07:07:45 +00:00
|
|
|
size_t CountStanzas() const;
|
2007-04-21 07:09:52 +00:00
|
|
|
size_t CountTopLedgers() const;
|
|
|
|
size_t CountBotLedgers() const;
|
2006-10-23 07:42:53 +00:00
|
|
|
void LilypondNotes(std::string & notes) const;
|
|
|
|
void LilypondChords(std::string & chords) const;
|
2006-11-27 07:07:45 +00:00
|
|
|
void LilypondStanza(std::string & lyrics, size_t stanza) const;
|
2007-04-22 06:20:17 +00:00
|
|
|
VLFract TiedDuration(size_t measure);
|
2006-09-11 02:49:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Local Variables:
|
|
|
|
// mode:C++
|
|
|
|
// End:
|