class Coltrane::Theory::Scale

Musical scale creation and manipulation

Attributes

interval_sequence[R]
tone[R]

Public Class Methods

new(*relative_intervals, tone: 'C', mode: 1, name: nil, notes: nil) click to toggle source
# File lib/coltrane/theory/scale.rb, line 14
def initialize(*relative_intervals, tone: 'C',
               mode: 1,
               name: nil,
               notes: nil)
  @name = name
  if relative_intervals.any? && tone
    @tone              = Note[tone]
    relative_intervals = relative_intervals.rotate(mode - 1)
    @interval_sequence = IntervalSequence.new(
      relative_intervals: relative_intervals
    )
  elsif notes
    @notes             = NoteSet[*notes]
    @tone              = @notes.first
    ds                 = @notes.interval_sequence.relative_intervals
    @interval_sequence = IntervalSequence.new(relative_intervals: ds)
  else
    raise WrongKeywordsError,
          '[*relative_intervals, tone: "C", mode: 1] || [notes:]'
  end
end

Public Instance Methods

&(other) click to toggle source
# File lib/coltrane/theory/scale.rb, line 88
def &(other)
  raise HasNoNotesError unless other.respond_to?(:notes)
  notes & other
end
==(other) click to toggle source
# File lib/coltrane/theory/scale.rb, line 40
def ==(other)
  id == other.id
end
[](d)
Alias for: degree
all_chords(size = 3..12)
Alias for: chords
chords(size = 3..12) click to toggle source
# File lib/coltrane/theory/scale.rb, line 141
def chords(size = 3..12)
  size = (size..size) if size.is_a?(Integer)
  scale_rotations = interval_sequence.inversions
  ChordQuality.intervals_per_name.reduce([]) do |memo1, (qname, qintervals)|
    next memo1 unless size.include?(qintervals.size)
    memo1 + scale_rotations.each_with_index
                           .reduce([]) do |memo2, (rot, index)|
              if (rot & qintervals).size == qintervals.size
                memo2 + [Chord.new(root_note: degree(index + 1),
                                   quality: ChordQuality.new(name: qname))]
              else
                memo2
              end
            end
  end
end
Also aliased as: all_chords
degree(d) click to toggle source
# File lib/coltrane/theory/scale.rb, line 68
def degree(d)
  raise WrongDegreeError, d if d < 1 || d > size
  tone + interval_sequence[d - 1].semitones
end
Also aliased as: []
degree_of_chord(chord) click to toggle source
# File lib/coltrane/theory/scale.rb, line 79
def degree_of_chord(chord)
  return if chords(chord.size).map(&:name).include?(chord.name)
  degree_of_note(chord.root_note)
end
degree_of_note(note) click to toggle source
# File lib/coltrane/theory/scale.rb, line 84
def degree_of_note(note)
  notes.index(note)
end
degrees() click to toggle source
# File lib/coltrane/theory/scale.rb, line 75
def degrees
  (1..size)
end
full_name() click to toggle source
# File lib/coltrane/theory/scale.rb, line 56
def full_name
  "#{tone} #{name}"
end
Also aliased as: to_s
id() click to toggle source
# File lib/coltrane/theory/scale.rb, line 36
def id
  [(name || @interval_sequence), tone.number]
end
include?(arg)
Alias for: include_notes?
include_notes?(arg) click to toggle source
# File lib/coltrane/theory/scale.rb, line 93
def include_notes?(arg)
  noteset = arg.is_a?(Note) ? NoteSet[arg] : arg
  (self & noteset).size == noteset.size
end
Also aliased as: include?
interval(i) click to toggle source
# File lib/coltrane/theory/scale.rb, line 104
def interval(i)
  interval_sequence[(i - 1) % size]
end
name() click to toggle source
# File lib/coltrane/theory/scale.rb, line 44
def name
  @name ||= begin
    is = interval_sequence.relative_intervals
    (0...is.size).each do |i|
      if (scale_name = ClassicScales::SCALES.key(is.rotate(i)))
        return scale_name
      end
    end
    nil
  end
end
notes() click to toggle source
# File lib/coltrane/theory/scale.rb, line 100
def notes
  @notes ||= NoteSet[*degrees.map { |d| degree(d) }]
end
pentads() click to toggle source
# File lib/coltrane/theory/scale.rb, line 133
def pentads
  tertians(5)
end
pretty_name() click to toggle source
# File lib/coltrane/theory/scale.rb, line 62
def pretty_name
  "#{tone.pretty_name} #{name}"
end
Also aliased as: full_name
progression(*degrees) click to toggle source
# File lib/coltrane/theory/scale.rb, line 137
def progression(*degrees)
  Progression.new(self, degrees)
end
sevenths() click to toggle source
# File lib/coltrane/theory/scale.rb, line 129
def sevenths
  tertians(4)
end
size() click to toggle source
# File lib/coltrane/theory/scale.rb, line 108
def size
  interval_sequence.size
end
tertians(n = 3) click to toggle source
# File lib/coltrane/theory/scale.rb, line 112
def tertians(n = 3)
  degrees.size.times.reduce([]) do |memo, d|
    ns = NoteSet[ *Array.new(n) { |i| notes[(d + (i * 2)) % size] } ]
    begin
      chord = Chord.new(notes: ns)
    rescue ChordNotFoundError
      memo
    else
      memo + [chord]
    end
  end
end
to_s()
Alias for: full_name
triads() click to toggle source
# File lib/coltrane/theory/scale.rb, line 125
def triads
  tertians(3)
end