lib/head_music/scale.rb in head_music-0.3.1 vs lib/head_music/scale.rb in head_music-0.4.0

- old
+ new

@@ -13,52 +13,57 @@ def initialize(root_pitch, scale_type) @root_pitch = HeadMusic::Pitch.get(root_pitch) @scale_type = HeadMusic::ScaleType.get(scale_type) end - def pitches - @pitches ||= begin + def pitches(direction: :ascending, octaves: 1) + @pitches ||= {} + @pitches[direction] ||= {} + @pitches[direction][octaves] ||= begin letter_cycle = root_pitch.letter_cycle semitones_from_root = 0 [root_pitch].tap do |pitches| - scale_type.intervals.each_with_index do |semitones, i| - semitones_from_root += semitones - pitches << pitch_for_step(i+1, semitones_from_root) + if [:ascending, :both].include?(direction) + (1..octaves).each do |i| + scale_type.ascending_intervals.each_with_index do |semitones, i| + semitones_from_root += semitones + pitches << pitch_for_step(i+1, semitones_from_root, :ascending) + end + end end + if [:descending, :both].include?(direction) + (1..octaves).each do |i| + scale_type.descending_intervals.each_with_index do |semitones, i| + semitones_from_root -= semitones + pitches << pitch_for_step(i+1, semitones_from_root, :descending) + end + end + end end end end - def pitch_names + def spellings pitches.map(&:spelling).map(&:to_s) end - def in(spelling) - spelling = HeadMusic::Spelling.get(spelling.to_s) - spellings = [] - letter_index = HeadMusic::Letter::all.index(spelling.letter) - starting_pitch_class = spelling.pitch_class - pattern.each do |interval_from_tonic| - letter = HeadMusic::Letter.all[letter_index] - if interval_from_tonic - accidental_interval = letter.pitch_class.smallest_interval_to(HeadMusic::PitchClass.get(starting_pitch_class + interval_from_tonic)) - accidental = HeadMusic::Accidental.for_interval(accidental_interval) - spellings << HeadMusic::Spelling.get([letter, accidental].join) - end - letter_index = (letter_index + 1) % 7 - end - spellings + def pitch_names(direction: :ascending, octaves: 1) + pitches(direction: direction, octaves: octaves).map(&:name) end def letter_cycle @letter_cycle ||= root_pitch.letter_cycle end - def root_pitch_class - @root_pitch_class ||= root_pitch.pitch_class + def root_pitch_number + @root_pitch_number ||= root_pitch.number end + def degree(degree_number) + pitches[degree_number - 1] + end + private def parent_scale_pitches HeadMusic::Scale.get(root_pitch, scale_type.parent_name).pitches if scale_type.parent end @@ -67,24 +72,24 @@ parent_scale_pitches.detect { |parent_scale_pitch| parent_scale_pitch.pitch_class == (root_pitch + semitones_from_root).to_i % 12 } end - def letter_for_step(step, semitones_from_root) + def letter_for_step(step, semitones_from_root, direction) pitch_class_number = (root_pitch.pitch_class.to_i + semitones_from_root) % 12 if scale_type.intervals.length == 7 - letter_cycle[step % 7] + direction == :ascending ? letter_cycle[step % 7] : letter_cycle[-step % 7] elsif scale_type.intervals.length < 7 && parent_scale_pitches parent_scale_pitch_for(semitones_from_root).letter elsif root_pitch.flat? HeadMusic::PitchClass::FLAT_SPELLINGS[pitch_class_number] else HeadMusic::PitchClass::SHARP_SPELLINGS[pitch_class_number] end end - def pitch_for_step(step, semitones_from_root) - pitch_number = root_pitch_class.to_i + semitones_from_root - letter = letter_for_step(step, semitones_from_root) + def pitch_for_step(step, semitones_from_root, direction) + pitch_number = root_pitch_number + semitones_from_root + letter = letter_for_step(step, semitones_from_root, direction) HeadMusic::Pitch.from_number_and_letter(pitch_number, letter) end end