Class: HeadMusic::Rudiment::Scale
- Defined in:
- lib/head_music/rudiment/scale.rb
Overview
A scale contains ordered pitches starting at a tonal center.
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.
20 21 22 23 |
# File 'lib/head_music/rudiment/scale.rb', line 20 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.
18 19 20 |
# File 'lib/head_music/rudiment/scale.rb', line 18 def root_pitch @root_pitch end |
#scale_type ⇒ Object (readonly)
Returns the value of attribute scale_type.
18 19 20 |
# File 'lib/head_music/rudiment/scale.rb', line 18 def scale_type @scale_type end |
Class Method Details
.get(root_pitch, scale_type = nil) ⇒ Object
6 7 8 9 10 11 12 13 14 |
# File 'lib/head_music/rudiment/scale.rb', line 6 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 ||= {} # Pitch#to_s already emits unicode accidentals and HashKey already desymbolizes # them, so no accidental normalization is needed here. hash_key = HeadMusic::Utilities::HashKey.for([root_pitch, scale_type].join(" ")) @scales[hash_key] ||= new(root_pitch, scale_type) end |
Instance Method Details
#child_scale_letter_for_step(semitones_from_root) ⇒ Object (private)
111 112 113 114 115 |
# File 'lib/head_music/rudiment/scale.rb', line 111 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
47 48 49 |
# File 'lib/head_music/rudiment/scale.rb', line 47 def degree(degree_number) pitches[degree_number - 1] end |
#determine_scale_pitches(direction, octaves) ⇒ Object (private)
53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/head_music/rudiment/scale.rb', line 53 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)
105 106 107 108 109 |
# File 'lib/head_music/rudiment/scale.rb', line 105 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)
78 79 80 |
# File 'lib/head_music/rudiment/scale.rb', line 78 def direction_intervals(direction) scale_type.send("#{direction}_intervals") end |
#direction_sign(direction) ⇒ Object (private)
74 75 76 |
# File 'lib/head_music/rudiment/scale.rb', line 74 def direction_sign(direction) (direction == :descending) ? -1 : 1 end |
#flat_letter_for_step(semitones_from_root) ⇒ Object (private)
117 118 119 120 121 |
# File 'lib/head_music/rudiment/scale.rb', line 117 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)
98 99 100 101 102 103 |
# File 'lib/head_music/rudiment/scale.rb', line 98 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)
67 68 69 70 71 72 |
# File 'lib/head_music/rudiment/scale.rb', line 67 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)
86 87 88 89 90 |
# File 'lib/head_music/rudiment/scale.rb', line 86 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)
82 83 84 |
# File 'lib/head_music/rudiment/scale.rb', line 82 def parent_scale_pitches HeadMusic::Rudiment::Scale.get(root_pitch, scale_type.parent_name).pitches end |
#pitch_class_number(semitones_from_root) ⇒ Object (private)
127 128 129 |
# File 'lib/head_music/rudiment/scale.rb', line 127 def pitch_class_number(semitones_from_root) (root_pitch.pitch_class.to_i + semitones_from_root) % 12 end |
#pitch_classes ⇒ Object
31 32 33 |
# File 'lib/head_music/rudiment/scale.rb', line 31 def pitch_classes pitches.map(&:pitch_class).uniq end |
#pitch_for_step(step, semitones_from_root, direction) ⇒ Object (private)
92 93 94 95 96 |
# File 'lib/head_music/rudiment/scale.rb', line 92 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
39 40 41 |
# File 'lib/head_music/rudiment/scale.rb', line 39 def pitch_names(direction: :ascending, octaves: 1) pitches(direction: direction, octaves: octaves).map(&:name) end |
#pitches(direction: :ascending, octaves: 1) ⇒ Object
25 26 27 28 29 |
# File 'lib/head_music/rudiment/scale.rb', line 25 def pitches(direction: :ascending, octaves: 1) @pitches ||= {} @pitches[direction] ||= {} @pitches[direction][octaves] ||= determine_scale_pitches(direction, octaves) end |
#root_pitch_number ⇒ Object
43 44 45 |
# File 'lib/head_music/rudiment/scale.rb', line 43 def root_pitch_number @root_pitch_number ||= root_pitch.number end |
#sharp_letter_for_step(semitones_from_root) ⇒ Object (private)
123 124 125 |
# File 'lib/head_music/rudiment/scale.rb', line 123 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
35 36 37 |
# File 'lib/head_music/rudiment/scale.rb', line 35 def spellings(direction: :ascending, octaves: 1) pitches(direction: direction, octaves: octaves).map(&:spelling) end |