Class: Coltrane::Theory::IntervalClass

Inherits:
FrequencyInterval show all
Defined in:
lib/coltrane/theory/interval_class.rb

Overview

Interval class here is not related to the Object Oriented Programming context but to the fact that there is a class of intervals that can all be categorized as having the same quality.

This class in specific still takes into account the order of intervals. C to D is a major second, but D to C is a minor seventh.

Direct Known Subclasses

Interval

Constant Summary collapse

QUALITY_SEQUENCE =
[
  %w[P],
  %w[m M],
  %w[m M],
  %w[P A],
  %w[P],
  %w[m M],
  %w[m M]
].freeze
ALTERATIONS =
{
  'A' => +1,
  'd' => -1
}.freeze
SINGLE_DISTANCES_NAMES =
%w[
  Unison
  Second
  Third
  Fourth
  Fifth
  Sixth
  Seventh
].freeze
COMPOUND_DISTANCES_NAMES =
[
  'Octave',
  'Ninth',
  'Tenth',
  'Eleventh',
  'Twelfth',
  'Thirteenth',
  'Fourteenth',
  'Double Octave'
].freeze
DISTANCES_NAMES =
(SINGLE_DISTANCES_NAMES + COMPOUND_DISTANCES_NAMES).freeze
QUALITY_NAMES =
{
  'P' => 'Perfect',
  'm' => 'Minor',
  'M' => 'Major',
  'A' => 'Augmented',
  'd' => 'Diminished'
}.freeze

Instance Attribute Summary

Attributes inherited from FrequencyInterval

#cents

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from FrequencyInterval

#<=>, #ascending?, #descending?, #interval_class, #opposite, #semitones

Constructor Details

#initialize(arg) ⇒ IntervalClass

Returns a new instance of IntervalClass.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/coltrane/theory/interval_class.rb', line 118

def initialize(arg)
  super case arg
        when FrequencyInterval then arg.semitones
        when String
          self.class.names.index(arg) ||
            self.class.full_names.index(arg) ||
            self.class.all_names_including_compound.index(arg) ||
            self.class.full_names_including_compound.index(arg)
        when Numeric then arg
        else
          raise WrongArgumentsError,
                'Provide: [interval] || [name] || [number of semitones]'
        end % 12 * 100
end

Class Method Details

.allObject



93
94
95
# File 'lib/coltrane/theory/interval_class.rb', line 93

def all
  @all ||= names.map { |n| IntervalClass[n] }
end

.all_names_including_compoundObject



85
86
87
# File 'lib/coltrane/theory/interval_class.rb', line 85

def all_names_including_compound
  @all_names_including_compound ||= names + compound_names
end

.compound_namesObject



81
82
83
# File 'lib/coltrane/theory/interval_class.rb', line 81

def compound_names
  @compound_names ||= all.map(&:compound_name)
end

.distance_name(n) ⇒ Object



63
64
65
# File 'lib/coltrane/theory/interval_class.rb', line 63

def distance_name(n)
  DISTANCES_NAMES[n - 1]
end

.distances_namesObject



59
60
61
# File 'lib/coltrane/theory/interval_class.rb', line 59

def distances_names
  DISTANCES_NAMES
end

.expand_name(name) ⇒ Object



106
107
108
109
110
111
112
113
114
115
# File 'lib/coltrane/theory/interval_class.rb', line 106

def expand_name(name)
  q, n = split(name)
  (
    case name
    when /AA|dd/ then 'Double '
    when /AAA|ddd/ then 'Triple '
    else ''
    end
  ) + "#{quality_name(q)} #{distance_name(n.to_i)}"
end

.full_namesObject



89
90
91
# File 'lib/coltrane/theory/interval_class.rb', line 89

def full_names
  @full_names ||= names.map { |n| expand_name(n) }
end

.full_names_including_compoundObject



97
98
99
100
# File 'lib/coltrane/theory/interval_class.rb', line 97

def full_names_including_compound
  @full_names_including_compound ||=
    all_names_including_compound.map { |n| expand_name(n) }
end

.namesObject



71
72
73
74
75
76
77
78
79
# File 'lib/coltrane/theory/interval_class.rb', line 71

def names
  @names ||= begin
    SINGLE_DISTANCES_NAMES.each_with_index.reduce([]) do |i_names, (_d, i)|
      i_names + QUALITY_SEQUENCE[i % 7].reduce([]) do |qs, q|
        qs + ["#{q}#{i + 1}"]
      end
    end
  end
end

.quality_name(q) ⇒ Object



67
68
69
# File 'lib/coltrane/theory/interval_class.rb', line 67

def quality_name(q)
  QUALITY_NAMES[q]
end

.split(interval) ⇒ Object



102
103
104
# File 'lib/coltrane/theory/interval_class.rb', line 102

def split(interval)
  interval.scan(/(\w)(\d\d?)/)[0]
end

Instance Method Details

#+(other) ⇒ Object



190
191
192
# File 'lib/coltrane/theory/interval_class.rb', line 190

def +(other)
  IntervalClass[semitones + other]
end

#-(other) ⇒ Object



194
195
196
# File 'lib/coltrane/theory/interval_class.rb', line 194

def -(other)
  IntervalClass[semitones - other]
end

#-@Object



198
199
200
# File 'lib/coltrane/theory/interval_class.rb', line 198

def -@
  IntervalClass[-semitones]
end

#==(other) ⇒ Object



149
150
151
152
# File 'lib/coltrane/theory/interval_class.rb', line 149

def ==(other)
  return false unless other.is_a? FrequencyInterval
  (semitones % 12) == (other.semitones % 12)
end

#alterationObject



154
155
156
# File 'lib/coltrane/theory/interval_class.rb', line 154

def alteration
  name.chars.reduce(0) { |a, s| a + (ALTERATIONS[s] || 0) }
end

#ascendingObject



158
159
160
# File 'lib/coltrane/theory/interval_class.rb', line 158

def ascending
  self.class[semitones.abs]
end

#compound_intervalObject Also known as: compound



139
140
141
142
143
144
145
# File 'lib/coltrane/theory/interval_class.rb', line 139

def compound_interval
  Interval.new(
    letter_distance: distance,
    semitones: semitones,
    compound: true
  )
end

#compound_nameObject



178
179
180
# File 'lib/coltrane/theory/interval_class.rb', line 178

def compound_name
  "#{quality}#{distance + 7}"
end

#descendingObject



162
163
164
# File 'lib/coltrane/theory/interval_class.rb', line 162

def descending
  self.class[-semitones.abs]
end

#distanceObject



182
183
184
# File 'lib/coltrane/theory/interval_class.rb', line 182

def distance
  self.class.split(name)[1].to_i
end

#full_nameObject



170
171
172
# File 'lib/coltrane/theory/interval_class.rb', line 170

def full_name
  self.class.expand_name(name)
end

#intervalObject



135
136
137
# File 'lib/coltrane/theory/interval_class.rb', line 135

def interval
  Interval.new(letter_distance: distance, semitones: semitones)
end

#inversionObject



166
167
168
# File 'lib/coltrane/theory/interval_class.rb', line 166

def inversion
  self.class[-semitones % 12]
end

#nameObject



174
175
176
# File 'lib/coltrane/theory/interval_class.rb', line 174

def name
  self.class.names[semitones % 12]
end

#qualityObject



186
187
188
# File 'lib/coltrane/theory/interval_class.rb', line 186

def quality
  self.class.split(name)[0]
end