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.
19 20 21 22 |
# File 'lib/head_music/rudiment/scale.rb', line 19 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.
17 18 19 |
# File 'lib/head_music/rudiment/scale.rb', line 17 def root_pitch @root_pitch end |
#scale_type ⇒ Object (readonly)
Returns the value of attribute scale_type.
17 18 19 |
# File 'lib/head_music/rudiment/scale.rb', line 17 def scale_type @scale_type end |
Class Method Details
.get(root_pitch, scale_type = nil) ⇒ Object
6 7 8 9 10 11 12 13 |
# 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) # 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(" ")) fetch_or_register(hash_key, root_pitch, scale_type) end |
Instance Method Details
#child_scale_letter_for_step(semitones_from_root) ⇒ Object (private)
110 111 112 113 114 |
# File 'lib/head_music/rudiment/scale.rb', line 110 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
46 47 48 |
# File 'lib/head_music/rudiment/scale.rb', line 46 def degree(degree_number) pitches[degree_number - 1] end |
#determine_scale_pitches(direction, octaves) ⇒ Object (private)
52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/head_music/rudiment/scale.rb', line 52 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)
104 105 106 107 108 |
# File 'lib/head_music/rudiment/scale.rb', line 104 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)
77 78 79 |
# File 'lib/head_music/rudiment/scale.rb', line 77 def direction_intervals(direction) scale_type.send("#{direction}_intervals") end |
#direction_sign(direction) ⇒ Object (private)
73 74 75 |
# File 'lib/head_music/rudiment/scale.rb', line 73 def direction_sign(direction) (direction == :descending) ? -1 : 1 end |
#flat_letter_for_step(semitones_from_root) ⇒ Object (private)
116 117 118 119 120 |
# File 'lib/head_music/rudiment/scale.rb', line 116 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)
97 98 99 100 101 102 |
# File 'lib/head_music/rudiment/scale.rb', line 97 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)
66 67 68 69 70 71 |
# File 'lib/head_music/rudiment/scale.rb', line 66 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)
85 86 87 88 89 |
# File 'lib/head_music/rudiment/scale.rb', line 85 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)
81 82 83 |
# File 'lib/head_music/rudiment/scale.rb', line 81 def parent_scale_pitches HeadMusic::Rudiment::Scale.get(root_pitch, scale_type.parent_name).pitches end |
#pitch_class_number(semitones_from_root) ⇒ Object (private)
126 127 128 |
# File 'lib/head_music/rudiment/scale.rb', line 126 def pitch_class_number(semitones_from_root) (root_pitch.pitch_class.to_i + semitones_from_root) % 12 end |
#pitch_classes ⇒ Object
30 31 32 |
# File 'lib/head_music/rudiment/scale.rb', line 30 def pitch_classes pitches.map(&:pitch_class).uniq end |
#pitch_for_step(step, semitones_from_root, direction) ⇒ Object (private)
91 92 93 94 95 |
# File 'lib/head_music/rudiment/scale.rb', line 91 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
38 39 40 |
# File 'lib/head_music/rudiment/scale.rb', line 38 def pitch_names(direction: :ascending, octaves: 1) pitches(direction: direction, octaves: octaves).map(&:name) end |
#pitches(direction: :ascending, octaves: 1) ⇒ Object
24 25 26 27 28 |
# File 'lib/head_music/rudiment/scale.rb', line 24 def pitches(direction: :ascending, octaves: 1) @pitches ||= {} @pitches[direction] ||= {} @pitches[direction][octaves] ||= determine_scale_pitches(direction, octaves) end |
#root_pitch_number ⇒ Object
42 43 44 |
# File 'lib/head_music/rudiment/scale.rb', line 42 def root_pitch_number @root_pitch_number ||= root_pitch.number end |
#sharp_letter_for_step(semitones_from_root) ⇒ Object (private)
122 123 124 |
# File 'lib/head_music/rudiment/scale.rb', line 122 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
34 35 36 |
# File 'lib/head_music/rudiment/scale.rb', line 34 def spellings(direction: :ascending, octaves: 1) pitches(direction: direction, octaves: octaves).map(&:spelling) end |