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