Class: HeadMusic::Rudiment::Scale
- Defined in:
- lib/head_music/rudiment/scale.rb
Overview
A scale contains ordered pitches starting at a tonal center.
Constant Summary collapse
- SCALE_REGEX =
/^[A-G][#b]?\s+\w+$/
Instance Attribute Summary collapse
-
#root_pitch ⇒ Object
readonly
Returns the value of attribute root_pitch.
-
#scale_type ⇒ Object
readonly
Returns the value of attribute scale_type.
Class Method Summary collapse
Instance Method Summary collapse
- #child_scale_letter_for_step(semitones_from_root) ⇒ Object private
- #degree(degree_number) ⇒ Object
- #determine_scale_pitches(direction, octaves) ⇒ Object private
- #diatonic_letter_for_step(direction, step) ⇒ Object private
- #direction_intervals(direction) ⇒ Object private
- #direction_sign(direction) ⇒ Object private
- #flat_letter_for_step(semitones_from_root) ⇒ Object private
-
#initialize(root_pitch, scale_type) ⇒ Scale
constructor
A new instance of Scale.
- #letter_for_step(step, semitones_from_root, direction) ⇒ Object private
- #octave_scale_pitches(direction, semitones_from_root) ⇒ Object private
- #parent_scale_pitch_for(semitones_from_root) ⇒ Object private
- #parent_scale_pitches ⇒ Object private
- #pitch_class_number(semitones_from_root) ⇒ Object private
- #pitch_classes ⇒ Object
- #pitch_for_step(step, semitones_from_root, direction) ⇒ Object private
- #pitch_names(direction: :ascending, octaves: 1) ⇒ Object
- #pitches(direction: :ascending, octaves: 1) ⇒ Object
- #root_pitch_number ⇒ Object
- #sharp_letter_for_step(semitones_from_root) ⇒ Object private
- #spellings(direction: :ascending, octaves: 1) ⇒ Object
Constructor Details
#initialize(root_pitch, scale_type) ⇒ Scale
Returns a new instance of Scale.
22 23 24 25 |
# File 'lib/head_music/rudiment/scale.rb', line 22 def initialize(root_pitch, scale_type) @root_pitch = HeadMusic::Rudiment::Pitch.get(root_pitch) @scale_type = HeadMusic::Rudiment::ScaleType.get(scale_type) end |
Instance Attribute Details
#root_pitch ⇒ Object (readonly)
Returns the value of attribute root_pitch.
20 21 22 |
# File 'lib/head_music/rudiment/scale.rb', line 20 def root_pitch @root_pitch end |
#scale_type ⇒ Object (readonly)
Returns the value of attribute scale_type.
20 21 22 |
# File 'lib/head_music/rudiment/scale.rb', line 20 def scale_type @scale_type end |
Class Method Details
.get(root_pitch, scale_type = nil) ⇒ Object
8 9 10 11 12 13 14 15 16 |
# File 'lib/head_music/rudiment/scale.rb', line 8 def self.get(root_pitch, scale_type = nil) root_pitch = HeadMusic::Rudiment::Pitch.get(root_pitch) scale_type = HeadMusic::Rudiment::ScaleType.get(scale_type || HeadMusic::Rudiment::ScaleType::DEFAULT) @scales ||= {} hash_key = HeadMusic::Utilities::HashKey.for( [root_pitch, scale_type].join(" ").gsub(/#|♯/, "sharp").gsub(/(\w)[b♭]/, '\\1flat') ) @scales[hash_key] ||= new(root_pitch, scale_type) end |
Instance Method Details
#child_scale_letter_for_step(semitones_from_root) ⇒ Object (private)
113 114 115 116 117 |
# File 'lib/head_music/rudiment/scale.rb', line 113 def child_scale_letter_for_step(semitones_from_root) return unless scale_type.parent parent_scale_pitch_for(semitones_from_root).letter_name end |
#degree(degree_number) ⇒ Object
49 50 51 |
# File 'lib/head_music/rudiment/scale.rb', line 49 def degree(degree_number) pitches[degree_number - 1] end |
#determine_scale_pitches(direction, octaves) ⇒ Object (private)
55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/head_music/rudiment/scale.rb', line 55 def determine_scale_pitches(direction, octaves) semitones_from_root = 0 pitches = [root_pitch] %i[ascending descending].each do |single_direction| next unless [single_direction, :both].include?(direction) (1..octaves).each do pitches += octave_scale_pitches(single_direction, semitones_from_root) semitones_from_root += 12 * direction_sign(single_direction) end end pitches end |
#diatonic_letter_for_step(direction, step) ⇒ Object (private)
107 108 109 110 111 |
# File 'lib/head_music/rudiment/scale.rb', line 107 def diatonic_letter_for_step(direction, step) return unless scale_type.diatonic? (direction == :ascending) ? letter_name_series_ascending[step % 7] : letter_name_series_descending[step % 7] end |
#direction_intervals(direction) ⇒ Object (private)
80 81 82 |
# File 'lib/head_music/rudiment/scale.rb', line 80 def direction_intervals(direction) scale_type.send("#{direction}_intervals") end |
#direction_sign(direction) ⇒ Object (private)
76 77 78 |
# File 'lib/head_music/rudiment/scale.rb', line 76 def direction_sign(direction) (direction == :descending) ? -1 : 1 end |
#flat_letter_for_step(semitones_from_root) ⇒ Object (private)
119 120 121 122 123 |
# File 'lib/head_music/rudiment/scale.rb', line 119 def flat_letter_for_step(semitones_from_root) return unless root_pitch.flat? HeadMusic::Rudiment::PitchClass::FLAT_SPELLINGS[pitch_class_number(semitones_from_root)] end |
#letter_for_step(step, semitones_from_root, direction) ⇒ Object (private)
100 101 102 103 104 105 |
# File 'lib/head_music/rudiment/scale.rb', line 100 def letter_for_step(step, semitones_from_root, direction) diatonic_letter_for_step(direction, step) || child_scale_letter_for_step(semitones_from_root) || flat_letter_for_step(semitones_from_root) || sharp_letter_for_step(semitones_from_root) end |
#octave_scale_pitches(direction, semitones_from_root) ⇒ Object (private)
69 70 71 72 73 74 |
# File 'lib/head_music/rudiment/scale.rb', line 69 def octave_scale_pitches(direction, semitones_from_root) direction_intervals(direction).map.with_index(1) do |semitones, i| semitones_from_root += semitones * direction_sign(direction) pitch_for_step(i, semitones_from_root, direction) end end |
#parent_scale_pitch_for(semitones_from_root) ⇒ Object (private)
88 89 90 91 92 |
# File 'lib/head_music/rudiment/scale.rb', line 88 def parent_scale_pitch_for(semitones_from_root) parent_scale_pitches.detect do |parent_scale_pitch| parent_scale_pitch.pitch_class == (root_pitch + semitones_from_root).to_i % 12 end end |
#parent_scale_pitches ⇒ Object (private)
84 85 86 |
# File 'lib/head_music/rudiment/scale.rb', line 84 def parent_scale_pitches HeadMusic::Rudiment::Scale.get(root_pitch, scale_type.parent_name).pitches end |
#pitch_class_number(semitones_from_root) ⇒ Object (private)
129 130 131 |
# File 'lib/head_music/rudiment/scale.rb', line 129 def pitch_class_number(semitones_from_root) (root_pitch.pitch_class.to_i + semitones_from_root) % 12 end |
#pitch_classes ⇒ Object
33 34 35 |
# File 'lib/head_music/rudiment/scale.rb', line 33 def pitch_classes pitches.map(&:pitch_class).uniq end |
#pitch_for_step(step, semitones_from_root, direction) ⇒ Object (private)
94 95 96 97 98 |
# File 'lib/head_music/rudiment/scale.rb', line 94 def pitch_for_step(step, semitones_from_root, direction) pitch_number = root_pitch_number + semitones_from_root letter_name = letter_for_step(step, semitones_from_root, direction) HeadMusic::Rudiment::Pitch.from_number_and_letter(pitch_number, letter_name) end |
#pitch_names(direction: :ascending, octaves: 1) ⇒ Object
41 42 43 |
# File 'lib/head_music/rudiment/scale.rb', line 41 def pitch_names(direction: :ascending, octaves: 1) pitches(direction: direction, octaves: octaves).map(&:name) end |
#pitches(direction: :ascending, octaves: 1) ⇒ Object
27 28 29 30 31 |
# File 'lib/head_music/rudiment/scale.rb', line 27 def pitches(direction: :ascending, octaves: 1) @pitches ||= {} @pitches[direction] ||= {} @pitches[direction][octaves] ||= determine_scale_pitches(direction, octaves) end |
#root_pitch_number ⇒ Object
45 46 47 |
# File 'lib/head_music/rudiment/scale.rb', line 45 def root_pitch_number @root_pitch_number ||= root_pitch.number end |
#sharp_letter_for_step(semitones_from_root) ⇒ Object (private)
125 126 127 |
# File 'lib/head_music/rudiment/scale.rb', line 125 def sharp_letter_for_step(semitones_from_root) HeadMusic::Rudiment::PitchClass::SHARP_SPELLINGS[pitch_class_number(semitones_from_root)] end |
#spellings(direction: :ascending, octaves: 1) ⇒ Object
37 38 39 |
# File 'lib/head_music/rudiment/scale.rb', line 37 def spellings(direction: :ascending, octaves: 1) pitches(direction: direction, octaves: octaves).map(&:spelling) end |