Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) Music

 

STLQt CreatorLubuntu

 

Music contains music classes.

Technical facts

 

 

 

 

 

 

./CppMusic/CppMusic.pri

 

INCLUDEPATH += \
    ../../Classes/CppMusic

SOURCES += \
    ../../Classes/CppMusic/musicchord.cpp \
    ../../Classes/CppMusic/musicnote.cpp \
    ../../Classes/CppMusic/musicscale.cpp

HEADERS  += \
    ../../Classes/CppMusic/musicchord.h \
    ../../Classes/CppMusic/musicnote.h \
    ../../Classes/CppMusic/musicscale.h

OTHER_FILES += \
    ../../Classes/CppMusic/Licence.txt

 

 

 

 

 

./CppMusic/musicbar.h

 

#ifndef MUSICBAR_H
#define MUSICBAR_H

#include "musicnote.h"

namespace ribi {
namespace Music {

///A Bar is a collection of Note instances ensuring that
///the sum of the length of the Notes equals the time signature of the bar.
///Note that rests are not supported
struct Bar
{
  Bar(
    const std::pair<int,int> time_signature,
    const std::vector<Note>& notes);

  private:
  const std::vector<Note> m_notes;
  const std::pair<int,int> m_time_signature;
};

} //~namespace Music
} //~namespace ribi

#endif // MUSICBAR_H

 

 

 

 

 

./CppMusic/musicbar.cpp

 

#include "musicbar.h"

#include <cassert>


ribi::Music::Bar::Bar(
  const std::pair<int,int> time_signature,
  const std::vector<Note>& notes)
  : m_notes(notes),
    m_time_signature(time_signature)
{
  assert(!"TODO: Check that the num of lengths of the notes equals the time signature");
}

 

 

 

 

 

./CppMusic/musicchord.h

 

#ifndef MUSICCHORD_H
#define MUSICCHORD_H

#include <string>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include <boost/shared_ptr.hpp>
#include "musicnote.h"
#pragma GCC diagnostic pop

namespace ribi {

namespace Music {

struct Chord
{

  ///Create any Chord from its root (e.g. 'C'), postfix (e.g. 'm7') and its intervals
  explicit Chord(
    const Note root,
    const std::string& postfix,
    const std::vector<int>& intervals);

  virtual ~Chord() noexcept {}

  ///Count the number of notes two chords share
  static int CountSameNotes(const boost::shared_ptr<Chord>& lhs, const boost::shared_ptr<Chord>& rhs);

  ///A Factory member function: create all Chords
  static std::vector<boost::shared_ptr<Chord> > CreateAllChords() noexcept;

  ///A Factory member function: create all Chords from a root
  static std::vector<boost::shared_ptr<Chord> > CreateChords(const Note root) noexcept;

  ///A Factory member function: create a Chord from its name (which includes its root)
  static boost::shared_ptr<Chord> CreateChord(const std::string& chord_name) noexcept;

  ///Obtain the Chord its name
  ///For example, 'C' (for C major) or 'D#m'
  virtual std::string GetName() const noexcept = 0;

  ///Obtain a Chord its Notes
  ///For example, the chord C major will returnn {C,E,G}
  const std::vector<Note> GetNotes() const noexcept;

  ///Obtain the version of this class
  static std::string GetVersion() noexcept;

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory() noexcept;

  ///Test this class
  static void Test() noexcept;

  ///Return the Chord as a music notation string
  std::string ToStr() const noexcept;

  private:

  ///The root of a chord. For example, the Cm7 chord has C as its root
  Note m_root;

  ///The postfix of a chord. For example, the Cm7 chord has 'm7' as its postfix
  const std::string m_postfix;

  const std::vector<int> m_intervals;
};

///The aug or plus chord
///For example, 'C+', 'D#aug"
struct ChordAug : public Chord
{
  ///Create the Chord from its root
  ChordAug(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "aug"; }
};

///The dim chord
///For example, 'Cdim', 'D#dim"
struct ChordDim : public Chord
{
  ///Create the Chord from its root
  ChordDim(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "dim"; }
};

///The major chord
///For example, 'C', 'D#"
struct ChordMajor : public Chord
{
  ///Create the Chords from its root
  ChordMajor(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "major"; }
};

///The minor chord
///For example, 'Cm', 'D#m"
struct ChordMinor : public Chord
{
  ///Create the Chord from its root
  ChordMinor(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "minor"; }
};

///The 6 chord
///For example, 'C6', 'D#6"
struct Chord6 : public Chord
{
  ///Create the Chord from its root
  Chord6(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "6"; }
};

///The minor 6 chord
///For example, 'Cm6', 'D#m6"
struct ChordMinor6 : public Chord
{
  ///Create the Chord from its root
  ChordMinor6(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "m6"; }
};

///The 7 chord
///For example, 'C7', 'D#7"
struct Chord7 : public Chord
{
  ///Create the Chord from its root
  Chord7(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "7"; }
};

///The minor 7 chord
///For example, 'C7', 'D#7"
struct ChordMinor7 : public Chord
{
  ///Create the Chord from its root
  ChordMinor7(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "m7"; }
};

} //~namespace Music

} //~namespace ribi

#endif // MUSICCHORD_H

 

 

 

 

 

./CppMusic/musicchord.cpp

 

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "musicchord.h"
#include <set>
#include <boost/make_shared.hpp>
#pragma GCC diagnostic pop

ribi::Music::Chord::Chord(
  const Note root,
  const std::string& postfix,
  const std::vector<int>& intervals)
  : m_root(root), m_postfix(postfix), m_intervals(intervals)
{
  #ifndef NDEBUG
  Test();
  #endif

}

int ribi::Music::Chord::CountSameNotes(const boost::shared_ptr<Chord>& lhs, const boost::shared_ptr<Chord>& rhs)
{
  assert(lhs);
  assert(rhs);
  //The indices of the notes
  std::set<int> x;
  {
    const std::vector<Music::Note> tmp = lhs->GetNotes();
    std::transform(tmp.begin(),tmp.end(),std::inserter(x,x.begin()),
      [](const Music::Note& note) { return note.ToInt(); } );
  }
  std::set<int> y;
  {
    const std::vector<Music::Note> tmp = rhs->GetNotes();
    std::transform(tmp.begin(),tmp.end(),std::inserter(y,y.begin()),
      [](const Music::Note& note) { return note.ToInt(); } );
  }
  std::set<int> z;
  std::set_intersection(x.begin(),x.end(),y.begin(),y.end(),std::inserter(z,z.begin()));
  return static_cast<int>(z.size());
}


std::vector<boost::shared_ptr<ribi::Music::Chord> > ribi::Music::Chord::CreateAllChords() noexcept
{
  std::vector<boost::shared_ptr<Chord> > v;
  std::vector<Note> notes = Note::GetAllNotes();
  std::for_each(notes.begin(),notes.end(),
    [&v](const Note& note)
    {
      const std::vector<boost::shared_ptr<Chord> > w = CreateChords(note);
      v.insert(v.end(),w.begin(),w.end());
    }
  );
  return v;
}

std::vector<boost::shared_ptr<ribi::Music::Chord> > ribi::Music::Chord::CreateChords(const Note root) noexcept
{

  return
  {
    boost::make_shared<ChordAug   >(root),
    boost::make_shared<ChordDim   >(root),
    boost::make_shared<ChordMajor >(root),
    boost::make_shared<ChordMinor >(root),
    boost::make_shared<Chord6     >(root),
    boost::make_shared<ChordMinor6>(root),
    boost::make_shared<Chord7     >(root),
    boost::make_shared<ChordMinor7>(root)
  };
}

boost::shared_ptr<ribi::Music::Chord> ribi::Music::Chord::CreateChord(const std::string& chord_name) noexcept
{
  std::vector<boost::shared_ptr<Chord> > v = CreateAllChords();
  const auto i = std::find_if(v.begin(),v.end(),
    [chord_name](const boost::shared_ptr<Chord>& chord)
    {
      return chord->ToStr() == chord_name;
    }
  );
  assert(i != v.end());
  return *i;

  /*
  assert(!chord_name.empty());
  //Get the root
  Note root = Note(chord_name.substr(0,1);
  try
  {
    //Even if the chord_name was 'C' (so a substring of length 2 is not possible),
    //also this exception is caught
    Note perhaps_root = Note(chord_name.substr(0,2);
    root = perhaps_root;
  }
  catch (std::exception&)
  {
    //No worries
  }
  //Read the chord type
  const std::string chord_type
    = chord_name.substr(
      root.ToStr().size(),
      chord_name.size() - root.ToStr().size());
  if (chord_type.empty()) return boost::shared_ptr<Chord>(new ChordMajor(root));
  */
}

const std::vector<ribi::Music::Note> ribi::Music::Chord::GetNotes() const noexcept
{
  std::vector<Note> notes;
  Note cur = m_root;
  notes.push_back(cur);
  std::for_each(m_intervals.begin(),m_intervals.end(),
    [&cur,&notes](const int interval)
    {
      cur = Note( (cur.ToInt() + interval) % 12);
      notes.push_back(cur);
    }
  );
  return notes;
}

std::string ribi::Music::Chord::GetVersion() noexcept
{
  return "1.0";
}

std::vector<std::string> ribi::Music::Chord::GetVersionHistory() noexcept
{
  return {
    "2012-08-10: version 1.0: initial version"
  };
}

void ribi::Music::Chord::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
}

std::string ribi::Music::Chord::ToStr() const noexcept
{
  return m_root.ToStr() + m_postfix;
}

ribi::Music::ChordAug::ChordAug(const Note root) noexcept
  : Chord(root,"+",{4,4})
{

}

ribi::Music::ChordDim::ChordDim(const Note root) noexcept
  : Chord(Note(root.ToInt() + 3),"dim",{3,3})
{

}

ribi::Music::ChordMajor::ChordMajor(const Note root) noexcept
  : Chord(root,"",{4,3})
{

}

ribi::Music::ChordMinor::ChordMinor(const Note root) noexcept
  : Chord(root,"m",{3,4})
{

}

ribi::Music::Chord6::Chord6(const Note root) noexcept
  : Chord(root,"6",{4,3,2})
{

}

ribi::Music::ChordMinor6::ChordMinor6(const Note root) noexcept
  : Chord(root,"m6",{3,4,2})
{

}

ribi::Music::Chord7::Chord7(const Note root) noexcept
  : Chord(Note(root.ToInt() + 4),"7",{3,3})
{

}

ribi::Music::ChordMinor7::ChordMinor7(const Note root) noexcept
  : Chord(Note(root.ToInt() + 3),"m7",{4,3})
{

}

 

 

 

 

 

./CppMusic/musicfwd.h

 

#ifndef MUSICFWD_H
#define MUSICFWD_H

namespace Music {

struct Chord;
struct Note;
struct Scale;

} //~namespace Music

#endif // MUSICFWD_H

 

 

 

 

 

./CppMusic/musicnote.h

 

#ifndef MUSICNOTE_H
#define MUSICNOTE_H

#include <string>
#include <vector>

namespace ribi {

namespace Music {

///Note class, e.g. 'C with length 1/1'
struct Note
{
  enum class Letter { A,B,C,D,E,F,G };
  enum class Accidental { none, flat, sharp };

  ///Create a Note from an integer, always uses the sharp for an accidental
  ///Examples: 0 = C, 1 = C#, 2 = D, 3 = D#
  ///Throws an exception when i is out of range
  explicit Note(const int i, const std::pair<int,int>& length = {0,1} );

  ///Create a Note from a std::string.
  ///Throws an exception when string is invalid
  explicit Note(const std::string& s, const std::pair<int,int>& length = {0,1} );

  ///Create a Note from a Letter and Accidental, will always succeed
  explicit Note(
    const Letter letter = Letter::C,
    const Accidental accidental = Accidental::none,
    const std::pair<int,int>& length = {0,1}
  ) noexcept;

  ///A Factory member function to create all notes
  static const std::vector<Note> GetAllNotes() noexcept;

  ///Obtain the version of this class
  static std::string GetVersion() noexcept;

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory() noexcept;

  #ifndef NDEBUG
  ///Test this class
  static void Test() noexcept;
  #endif

  ///Convert a note to an integer
  ///Examples: C = 0, C# = 1, Db = 1, D = 2
  int ToInt() const noexcept;

  ///Convert a note to a string
  std::string ToStr() const noexcept;


  private:
  Accidental m_accidental;

  ///An x/yth note, e.g 1/4th
  std::pair<int,int> m_length;


  Letter m_letter;
};

bool operator==(const Note& lhs, const Note& rhs) noexcept;
bool operator<(const Note& lhs, const Note& rhs) noexcept;

} //~namespace Music

} //~namespace ribi

#endif // MUSICNOTE_H

 

 

 

 

 

./CppMusic/musicnote.cpp

 



#include "musicnote.h"

#include <cassert>
#include <stdexcept>
#include <vector>

#include "trace.h"

ribi::Music::Note::Note(const int i, const std::pair<int,int>& length)
  : m_accidental(ribi::Music::Note::Accidental::none),
    m_length(length),
    m_letter(ribi::Music::Note::Letter::C)
{
  #ifndef NDEBUG
  Test();
  #endif

  switch (i % 12)
  {
    case  0: m_letter = Letter::C; m_accidental = Accidental::none ; break;
    case  1: m_letter = Letter::C; m_accidental = Accidental::sharp; break;
    case  2: m_letter = Letter::D; m_accidental = Accidental::none ; break;
    case  3: m_letter = Letter::D; m_accidental = Accidental::sharp; break;
    case  4: m_letter = Letter::E; m_accidental = Accidental::none ; break;
    case  5: m_letter = Letter::F; m_accidental = Accidental::none ; break;
    case  6: m_letter = Letter::F; m_accidental = Accidental::sharp; break;
    case  7: m_letter = Letter::G; m_accidental = Accidental::none ; break;
    case  8: m_letter = Letter::G; m_accidental = Accidental::sharp; break;
    case  9: m_letter = Letter::A; m_accidental = Accidental::none ; break;
    case 10: m_letter = Letter::A; m_accidental = Accidental::sharp; break;
    case 11: m_letter = Letter::B; m_accidental = Accidental::none ; break;
    default:
      TRACE(i);
      assert(!"Should not get here");
      throw std::logic_error("Invalid value for note; must be in range [0,12>");
  }
}

ribi::Music::Note::Note(const std::string& s, const std::pair<int,int>& length)
  : m_accidental(ribi::Music::Note::Accidental::none),
    m_length(length),
    m_letter(ribi::Music::Note::Letter::C)
{
  #ifndef NDEBUG
  Test();
  #endif
  if (s.empty()) throw std::logic_error("A music note must not be empty");
  if (s[0] < 'A' || s[0] > 'G') throw std::logic_error("A music note must start with a capital letter from A to and including G");
  if (s.size() > 2) throw std::logic_error("A music note cannot consist of more than two character");
  if (s.size() == 2 && (s[1] != '#' && s[1] != 'b'))
  {
    TRACE(s);
    throw std::logic_error("A music note's second character must be either absent, '#' or 'b'");
  }
  switch (s[0])
  {
    case 'C': m_letter = Letter::C; break;
    case 'D': m_letter = Letter::D; break;
    case 'E': m_letter = Letter::E; break;
    case 'F': m_letter = Letter::F; break;
    case 'G': m_letter = Letter::G; break;
    case 'A': m_letter = Letter::A; break;
    case 'B': m_letter = Letter::B; break;
  }
  if (s.size() == 2)
  {
    switch (s[1])
    {
      case '#': m_accidental = Accidental::sharp; break;
      case 'b': m_accidental = Accidental::flat; break;
    }
  }
  else
  {
    m_accidental = Accidental::none;
  }
}

ribi::Music::Note::Note(
  const Letter letter,
  const Accidental accidental,
  const std::pair<int,int>& length) noexcept
  : m_accidental(accidental),
    m_length(length),
    m_letter(letter)

{
  #ifndef NDEBUG
  Test();
  #endif

}

const std::vector<ribi::Music::Note> ribi::Music::Note::GetAllNotes() noexcept
{
  std::vector<Note> v;
  for (int i=0; i!=12; ++i)
  {
    v.push_back(Note(i));
  }
  return v;
}

std::string ribi::Music::Note::GetVersion() noexcept
{
  return "1.0";
}

std::vector<std::string> ribi::Music::Note::GetVersionHistory() noexcept
{
  return {
    "2012-08-10: version 1.0: initial version"
  };
}

#ifndef NDEBUG
void ribi::Music::Note::Test() noexcept
{
  //Test exactly once
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  //Test ToInt
  {
    assert(Note(Letter::C).ToInt() == 0);
    assert(Note(0).ToInt() == 0);
    assert(Note(0).ToStr() == "C");
  }
}
#endif

int ribi::Music::Note::ToInt() const noexcept
{
  int x = 0;
  switch (m_letter)
  {
    case Letter::C: x =  0; break;
    case Letter::D: x =  2; break;
    case Letter::E: x =  4; break;
    case Letter::F: x =  5; break;
    case Letter::G: x =  7; break;
    case Letter::A: x =  9; break;
    case Letter::B: x = 11; break;
  }
  switch (m_accidental)
  {
    case Accidental::none : break;
    case Accidental::sharp: ++x; break;
    case Accidental::flat : --x; break;
  }
  x += 12;
  x %= 12;
  assert(x >= 0); assert(x < 12);
  return x;
}

std::string ribi::Music::Note::ToStr() const noexcept
{
  std::string s;
  switch (m_letter)
  {
    case Letter::C: s = "C"; break;
    case Letter::D: s = "D"; break;
    case Letter::E: s = "E"; break;
    case Letter::F: s = "F"; break;
    case Letter::G: s = "G"; break;
    case Letter::A: s = "A"; break;
    case Letter::B: s = "B"; break;
  }
  switch (m_accidental)
  {
    case Accidental::none : break;
    case Accidental::sharp: s+="#"; break;
    case Accidental::flat : s+="b"; break;
  }
  return s;
}

bool ribi::Music::operator==(const Note& lhs, const Note& rhs) noexcept
{
  return lhs.ToInt() == rhs.ToInt();
}

bool ribi::Music::operator<(const Note& lhs, const Note& rhs) noexcept
{
  return lhs.ToInt() < rhs.ToInt();
}

 

 

 

 

 

./CppMusic/musicscale.h

 

#ifndef MUSICSCALE_H
#define MUSICSCALE_H

#include <vector>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include <boost/shared_ptr.hpp>
#include "musicnote.h"
#pragma GCC diagnostic pop

namespace ribi {

namespace Music {

struct Chord;

struct Scale
{
  ///Create a Scale from its root and its intervals
  explicit Scale(const Note root, const std::vector<int>& intervals);

  virtual ~Scale() noexcept {}

  ///A Factory member function: create all Scales from a root
  static std::vector<boost::shared_ptr<Scale> > CreateScales(const Note root) noexcept;

  ///A Factory member function: create a Scale from its name and root
  static boost::shared_ptr<Scale> CreateScale(
    const std::string& scale_name,
    const Note root);

  ///Does the Chord fit in this Scale?
  bool Fits(const boost::shared_ptr<Chord>& chord) const noexcept;

  ///Obtain the Scale its name
  ///For example, 'Major' or 'Moll-Dur subdominant'
  virtual std::string GetName() const noexcept = 0;

  ///Obtain a Scale its Notes
  ///For example, C major will returnn {A,B,C,D,E,F,G}
  const std::vector<Note> GetNotes() const noexcept;

  const Note& GetRoot() const noexcept { return m_root; }

  ///Obtain the version of this class
  static std::string GetVersion() noexcept;

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory() noexcept;

  ///Test this class
  static void Test() noexcept;

  private:
  const Note m_root;

  ///The intervals between two successive notes
  ///For example, the C major scale (notes: C-D-E-F-G-A-B)
  ///has intervals 2-2-1-2-2-2
  ///The sum of the intervals must always be lower than twelve
  const std::vector<int> m_intervals;
};

///The blues scale
struct ScaleBlues : public Scale
{
  ///Create the Scale from its root
  ScaleBlues(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const  noexcept{ return "blues"; }
};

///The harminic minor scale
struct ScaleHarmonicMinor : public Scale
{
  ///Create the Scale from its root
  ScaleHarmonicMinor(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "harmonic minor"; }
};

///The hexatonic scale
struct ScaleHexatonic : public Scale
{
  ///Create the Scale from its root
  ScaleHexatonic(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "hexatonic"; }
};

///The hypermajor scale
struct ScaleHyperMajor : public Scale
{
  ///Create the Scale from its root
  ScaleHyperMajor(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "hypermajor"; }
};

///The major scale
struct ScaleMajor : public Scale
{
  ///Create the Scale from its root
  ScaleMajor(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "major"; }
};

///The major pentatonic scale
struct ScaleMajorPentatonic : public Scale
{
  ///Create the Scale from its root
  ScaleMajorPentatonic(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "major pentatonic"; }
};

///The minor pentatonic scale
struct ScaleMinorPentatonic : public Scale
{
  ///Create the Scale from its root
  ScaleMinorPentatonic(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "minor pentatonic"; }
};

///The Moll-dur dominant scale
struct ScaleMollDurDominant : public Scale
{
  ///Create the Scale from its root
  ScaleMollDurDominant(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "moll-dur dominant"; }
};

///The Moll-dur subdominant scale
struct ScaleMollDurSubdominant : public Scale
{
  ///Create the Scale from its root
  ScaleMollDurSubdominant(const Note root) noexcept;

  ///Obtain the Scale its name
  std::string GetName() const noexcept { return "moll-dur subdominant"; }
};

} //~namespace Music

} //~namespace ribi

#endif // MUSICSCALE_H

 

 

 

 

 

./CppMusic/musicscale.cpp

 

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "musicscale.h"

#include <stdexcept>
#include "musicchord.h"
#include "trace.h"

#pragma GCC diagnostic pop

ribi::Music::Scale::Scale(const Note root, const std::vector<int>& intervals)
  : m_root(root),
    m_intervals(intervals)
{
  #ifndef NDEBUG
  Test();
  #endif

}

boost::shared_ptr<ribi::Music::Scale> ribi::Music::Scale::CreateScale(
    const std::string& scale_name,
    const Note root)
{
  const std::vector<boost::shared_ptr<Scale> > v = CreateScales(root);
  const auto i = std::find_if(v.begin(),v.end(),
    [scale_name](const boost::shared_ptr<Scale>& scale)
    {
      return scale->GetName() == scale_name;
    }
  );
  if (i == v.end())
  {
    TRACE(scale_name);
    throw std::logic_error("Scale name is not found");
  }
  return *i;
}

std::vector<boost::shared_ptr<ribi::Music::Scale> > ribi::Music::Scale::CreateScales(const Note root) noexcept
{
  return
  {
    boost::shared_ptr<Scale>(new ScaleBlues(root)),
    boost::shared_ptr<Scale>(new ScaleHarmonicMinor(root)),
    boost::shared_ptr<Scale>(new ScaleHexatonic(root)),
    boost::shared_ptr<Scale>(new ScaleHyperMajor(root)),
    boost::shared_ptr<Scale>(new ScaleMajor(root)),
    boost::shared_ptr<Scale>(new ScaleMajorPentatonic(root)),
    boost::shared_ptr<Scale>(new ScaleMinorPentatonic(root)),
    boost::shared_ptr<Scale>(new ScaleMollDurDominant(root)),
    boost::shared_ptr<Scale>(new ScaleMollDurSubdominant(root)),
  };
}

bool ribi::Music::Scale::Fits(const boost::shared_ptr<Chord>& chord) const noexcept
{
  const std::vector<Note> notes_chord = chord->GetNotes();
  const std::vector<Note> notes_scale = this->GetNotes();

  //Count mismatches
  const int n_mismatch
    = std::count_if(notes_chord.begin(),notes_chord.end(),
    [notes_scale](const Note& note)
    {
      //If note from chord cannot be found in scale, return true
      return std::find(notes_scale.begin(),notes_scale.end(),note) == notes_scale.end();
    }
  );
  return n_mismatch == 0;
}


const std::vector<ribi::Music::Note> ribi::Music::Scale::GetNotes() const noexcept
{
  std::vector<Note> notes;
  Note cur = m_root;
  notes.push_back(cur);
  std::for_each(m_intervals.begin(),m_intervals.end(),
    [&cur,&notes](const int interval)
    {
      cur = Note( (cur.ToInt() + interval) % 12);
      notes.push_back(cur);
    }
  );
  return notes;
}

std::string ribi::Music::Scale::GetVersion() noexcept
{
  return "1.1";
}

std::vector<std::string> ribi::Music::Scale::GetVersionHistory() noexcept
{
  return {
    "2012-08-10: version 1.0: initial version with five different scales",
    "2012-08-11: version 1.1: added four scales"
  };
}

void ribi::Music::Scale::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
}

ribi::Music::ScaleBlues::ScaleBlues(const Note root) noexcept
  : Scale(root, {3,2,1,1,3} )
{

}

//C-D-Eb-F-G-Ab-B
// 2 1  2 2 1  3
ribi::Music::ScaleHarmonicMinor::ScaleHarmonicMinor(const Note root) noexcept
  : Scale(root, {2,1,2,2,1,3} )
{

}

ribi::Music::ScaleHexatonic::ScaleHexatonic(const Note root) noexcept
  : Scale(root, {2,2,2,2,2} )
{

}

ribi::Music::ScaleHyperMajor::ScaleHyperMajor(const Note root) noexcept
  : Scale(root, {1,3,1,3,1} )
{

}


ribi::Music::ScaleMajor::ScaleMajor(const Note root) noexcept
  : Scale(root, {2,2,1,2,2,2} )
{

}

//C-D-E-G-A
// 2 2 3 2
ribi::Music::ScaleMajorPentatonic::ScaleMajorPentatonic(const Note root) noexcept
  : Scale(root, {2,2,3,2} )
{

}

//C-Eb-F-G_Bb
// 3  2 2 3
ribi::Music::ScaleMinorPentatonic::ScaleMinorPentatonic(const Note root) noexcept
  : Scale(root, {3,2,2,3} )
{

}

ribi::Music::ScaleMollDurDominant::ScaleMollDurDominant(const Note root) noexcept
  : Scale(root, {2,2,1,2,1,3} )
{

}

ribi::Music::ScaleMollDurSubdominant::ScaleMollDurSubdominant(const Note root) noexcept
  : Scale(root, {2,2,1,2,1,2} )
{

}

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict

This page has been created by the tool CodeToHtml