Class: HeadMusic::ScaleType

Inherits:
Object
  • Object
show all
Defined in:
lib/head_music/scale_type.rb

Overview

A ScaleType represents a particular scale pattern, such as major, lydian, or minor pentatonic.

Constant Summary collapse

H =

whole step

1
W =

half step

2
I =

Modal

[W, W, H, W, W, W, H].freeze
II =
I.rotate
III =
I.rotate(2)
IV =
I.rotate(3)
V =
I.rotate(4)
VI =
I.rotate(5)
VII =
I.rotate(6)
HARMONIC_MINOR =

Tonal

[W, H, W, W, H, 3, H].freeze
MELODIC_MINOR_ASCENDING =
[W, H, W, W, W, W, H].freeze
MODE_NAMES =
{
  i: %i[ionian major],
  ii: [:dorian],
  iii: [:phrygian],
  iv: [:lydian],
  v: [:mixolydian],
  vi: %i[aeolian minor natural_minor],
  vii: [:locrian]
}.freeze
CHROMATIC =
([H] * 12)
MINOR_PENTATONIC =
[3, 2, 2, 3, 2].freeze
SCALE_TYPES =
{}.tap do |scales|
  scales.merge!(_modes)
  scales.merge!(_minor_scales)
  scales.merge!(_chromatic_scales)
  scales.merge!(_pentatonic_scales)
  scales.merge!(_exotic_scales)
end.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, attributes) ⇒ ScaleType

Returns a new instance of ScaleType.



106
107
108
109
110
111
# File 'lib/head_music/scale_type.rb', line 106

def initialize(name, attributes)
  @name = name
  @ascending_intervals = attributes[:ascending]
  @descending_intervals = attributes[:descending] || ascending_intervals.reverse
  @parent_name = attributes[:parent_name]
end

Instance Attribute Details

#ascending_intervalsObject (readonly) Also known as: intervals

Returns the value of attribute ascending_intervals.



101
102
103
# File 'lib/head_music/scale_type.rb', line 101

def ascending_intervals
  @ascending_intervals
end

#descending_intervalsObject (readonly)

Returns the value of attribute descending_intervals.



101
102
103
# File 'lib/head_music/scale_type.rb', line 101

def descending_intervals
  @descending_intervals
end

#nameObject (readonly)

Returns the value of attribute name.



101
102
103
# File 'lib/head_music/scale_type.rb', line 101

def name
  @name
end

#parent_nameObject (readonly)

Returns the value of attribute parent_name.



101
102
103
# File 'lib/head_music/scale_type.rb', line 101

def parent_name
  @parent_name
end

Class Method Details

._chromatic_scalesObject



52
53
54
# File 'lib/head_music/scale_type.rb', line 52

def self._chromatic_scales
  {chromatic: {ascending: CHROMATIC}}
end

._exotic_scalesObject



66
67
68
69
70
71
72
# File 'lib/head_music/scale_type.rb', line 66

def self._exotic_scales
  # 'octatonic' is also called the 'whole-half diminished scale'
  {
    octatonic: {ascending: [W, H, W, H, W, H, W, H]},
    whole_tone: {ascending: [W, W, W, W, W, W]}
  }
end

._minor_scalesObject



45
46
47
48
49
50
# File 'lib/head_music/scale_type.rb', line 45

def self._minor_scales
  {
    harmonic_minor: {ascending: HARMONIC_MINOR},
    melodic_minor: {ascending: MELODIC_MINOR_ASCENDING, descending: VI.reverse}
  }
end

._modesObject



35
36
37
38
39
40
41
42
43
# File 'lib/head_music/scale_type.rb', line 35

def self._modes
  {}.tap do |modes|
    MODE_NAMES.each do |roman_numeral, aliases|
      intervals = {ascending: const_get(roman_numeral.upcase)}
      modes[roman_numeral] = intervals
      aliases.each { |name| modes[name] = intervals }
    end
  end
end

._pentatonic_scalesObject



56
57
58
59
60
61
62
63
64
# File 'lib/head_music/scale_type.rb', line 56

def self._pentatonic_scales
  {
    minor_pentatonic: {ascending: MINOR_PENTATONIC, parent_name: :minor},
    major_pentatonic: {ascending: MINOR_PENTATONIC.rotate, parent_name: :major},
    egyptian_pentatonic: {ascending: MINOR_PENTATONIC.rotate(2), parent_name: :minor},
    blues_minor_pentatonic: {ascending: MINOR_PENTATONIC.rotate(3), parent_name: :minor},
    blues_major_pentatonic: {ascending: MINOR_PENTATONIC.rotate(4), parent_name: :major}
  }
end

.defaultObject



97
98
99
# File 'lib/head_music/scale_type.rb', line 97

def self.default
  get(:major)
end

.get(name) ⇒ Object



90
91
92
93
94
95
# File 'lib/head_music/scale_type.rb', line 90

def self.get(name)
  @scale_types ||= {}
  identifier = HeadMusic::Utilities::HashKey.for(name)
  attributes = SCALE_TYPES[identifier]
  @scale_types[identifier] ||= new(identifier, attributes)
end

Instance Method Details

#==(other) ⇒ Object



113
114
115
# File 'lib/head_music/scale_type.rb', line 113

def ==(other)
  state == other.state
end

#chromatic?Boolean

Returns:

  • (Boolean)


137
138
139
# File 'lib/head_music/scale_type.rb', line 137

def chromatic?
  intervals.length == 12
end

#diatonic?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/head_music/scale_type.rb', line 125

def diatonic?
  intervals.length == 7
end

#parentObject



121
122
123
# File 'lib/head_music/scale_type.rb', line 121

def parent
  @parent ||= self.class.get(parent_name) if parent_name
end

#pentatonic?Boolean

Returns:

  • (Boolean)


133
134
135
# File 'lib/head_music/scale_type.rb', line 133

def pentatonic?
  intervals.length == 5
end

#stateObject



117
118
119
# File 'lib/head_music/scale_type.rb', line 117

def state
  [ascending_intervals, descending_intervals]
end

#whole_tone?Boolean

Returns:

  • (Boolean)


129
130
131
# File 'lib/head_music/scale_type.rb', line 129

def whole_tone?
  intervals.length == 6 && intervals.uniq == [2]
end