Class: HeadMusic::Content::Voice
- Inherits:
-
Object
- Object
- HeadMusic::Content::Voice
- Includes:
- Comparable
- Defined in:
- lib/head_music/content/voice.rb
Overview
A Voice is a stream of music with some indepedence that is conceptually one part or for one performer. The melodic lines in counterpoint are each a voice.
Defined Under Namespace
Classes: MelodicNotePair
Instance Attribute Summary collapse
-
#composition ⇒ Object
readonly
Returns the value of attribute composition.
-
#placements ⇒ Object
readonly
Returns the value of attribute placements.
-
#role ⇒ Object
readonly
Returns the value of attribute role.
Instance Method Summary collapse
-
#bar_start_position(placement) ⇒ Object
private
-
#cantus_firmus? ⇒ Boolean
-
#earliest_bar_number ⇒ Object
-
#first_gap ⇒ Object
Returns nil if placements are contiguous, or [expected_position, found_placement] for the first gap: either the first placement not starting its bar, or the first pair of consecutive placements where the second doesn’t begin where the first one ends.
-
#highest_notes ⇒ Object
-
#highest_pitch ⇒ Object
-
#initialize(composition: nil, role: nil) ⇒ Voice
constructor
A new instance of Voice.
-
#insert_into_placements(placement) ⇒ Object
private
-
#large_leaps ⇒ Object
-
#last_placement ⇒ Object
-
#latest_bar_number ⇒ Object
-
#leaps ⇒ Object
-
#lowest_notes ⇒ Object
-
#lowest_pitch ⇒ Object
-
#melodic_intervals ⇒ Object
-
#melodic_note_pairs ⇒ Object
-
#next_position ⇒ Object
-
#note_at(position) ⇒ Object
-
#note_following(position) ⇒ Object
-
#note_preceding(position) ⇒ Object
-
#notes ⇒ Object
-
#notes_during(placement) ⇒ Object
-
#notes_not_in_key ⇒ Object
-
#pitches ⇒ Object
-
#pitches_string ⇒ Object
private
-
#place(position, rhythmic_value, pitch = nil) ⇒ Object
-
#range ⇒ Object
-
#rests ⇒ Object
-
#to_s ⇒ Object
Constructor Details
#initialize(composition: nil, role: nil) ⇒ Voice
Returns a new instance of Voice.
13 14 15 16 17 |
# File 'lib/head_music/content/voice.rb', line 13 def initialize(composition: nil, role: nil) @composition = composition || HeadMusic::Content::Composition.new @role = role @placements = [] end |
Instance Attribute Details
#composition ⇒ Object (readonly)
Returns the value of attribute composition.
9 10 11 |
# File 'lib/head_music/content/voice.rb', line 9 def composition @composition end |
#placements ⇒ Object (readonly)
Returns the value of attribute placements.
9 10 11 |
# File 'lib/head_music/content/voice.rb', line 9 def placements @placements end |
#role ⇒ Object (readonly)
Returns the value of attribute role.
9 10 11 |
# File 'lib/head_music/content/voice.rb', line 9 def role @role end |
Instance Method Details
#bar_start_position(placement) ⇒ Object (private)
145 146 147 |
# File 'lib/head_music/content/voice.rb', line 145 def (placement) HeadMusic::Content::Position.new(composition, placement.position., 1, 0) end |
#cantus_firmus? ⇒ Boolean
81 82 83 |
# File 'lib/head_music/content/voice.rb', line 81 def cantus_firmus? role.to_s =~ /cantus.?firmus/i end |
#earliest_bar_number ⇒ Object
101 102 103 104 105 |
# File 'lib/head_music/content/voice.rb', line 101 def return 1 if notes.empty? placements.first.position. end |
#first_gap ⇒ Object
Returns nil if placements are contiguous, or [expected_position, found_placement] for the first gap: either the first placement not starting its bar, or the first pair of consecutive placements where the second doesn’t begin where the first one ends.
125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/head_music/content/voice.rb', line 125 def first_gap first = placements.first return unless first return [(first), first] unless first.position.count == 1 && first.position.tick.zero? placements.each_cons(2) do |previous, current| return [previous.next_position, current] unless current.position == previous.next_position end nil end |
#highest_notes ⇒ Object
50 51 52 |
# File 'lib/head_music/content/voice.rb', line 50 def highest_notes notes.select { |note| note.pitch == highest_pitch } end |
#highest_pitch ⇒ Object
42 43 44 |
# File 'lib/head_music/content/voice.rb', line 42 def highest_pitch pitches.max end |
#insert_into_placements(placement) ⇒ Object (private)
149 150 151 152 |
# File 'lib/head_music/content/voice.rb', line 149 def insert_into_placements(placement) @placements << placement @placements = @placements.sort end |
#large_leaps ⇒ Object
77 78 79 |
# File 'lib/head_music/content/voice.rb', line 77 def large_leaps melodic_note_pairs.select(&:large_leap?) end |
#last_placement ⇒ Object
113 114 115 |
# File 'lib/head_music/content/voice.rb', line 113 def last_placement placements.last end |
#latest_bar_number ⇒ Object
107 108 109 110 111 |
# File 'lib/head_music/content/voice.rb', line 107 def return 1 if notes.empty? placements.last.position. end |
#leaps ⇒ Object
73 74 75 |
# File 'lib/head_music/content/voice.rb', line 73 def leaps melodic_note_pairs.select(&:leap?) end |
#lowest_notes ⇒ Object
54 55 56 |
# File 'lib/head_music/content/voice.rb', line 54 def lowest_notes notes.select { |note| note.pitch == lowest_pitch } end |
#lowest_pitch ⇒ Object
46 47 48 |
# File 'lib/head_music/content/voice.rb', line 46 def lowest_pitch pitches.min end |
#melodic_intervals ⇒ Object
68 69 70 71 |
# File 'lib/head_music/content/voice.rb', line 68 def melodic_intervals @melodic_intervals ||= melodic_note_pairs.map { |note_pair| HeadMusic::Analysis::MelodicInterval.new(*note_pair.notes) } end |
#melodic_note_pairs ⇒ Object
62 63 64 65 66 |
# File 'lib/head_music/content/voice.rb', line 62 def melodic_note_pairs @melodic_note_pairs ||= notes.each_cons(2).map do |first_note, second_note| HeadMusic::Content::Voice::MelodicNotePair.new(first_note, second_note) end end |
#next_position ⇒ Object
117 118 119 |
# File 'lib/head_music/content/voice.rb', line 117 def next_position last_placement ? last_placement.next_position : HeadMusic::Content::Position.new(composition, 1, 1, 0) end |
#note_at(position) ⇒ Object
85 86 87 |
# File 'lib/head_music/content/voice.rb', line 85 def note_at(position) notes.detect { |note| position.within_placement?(note) } end |
#note_following(position) ⇒ Object
97 98 99 |
# File 'lib/head_music/content/voice.rb', line 97 def note_following(position) notes.detect { |note| note.position > position } end |
#note_preceding(position) ⇒ Object
93 94 95 |
# File 'lib/head_music/content/voice.rb', line 93 def note_preceding(position) notes.reverse.find { |note| note.position < position } end |
#notes ⇒ Object
25 26 27 |
# File 'lib/head_music/content/voice.rb', line 25 def notes @placements.select(&:note?).sort_by(&:position) end |
#notes_during(placement) ⇒ Object
89 90 91 |
# File 'lib/head_music/content/voice.rb', line 89 def notes_during(placement) notes.select { |note| note.during?(placement) } end |
#notes_not_in_key ⇒ Object
29 30 31 32 |
# File 'lib/head_music/content/voice.rb', line 29 def notes_not_in_key key_spellings = key_signature.pitches.map(&:spelling).uniq notes.reject { |note| key_spellings.include? note.pitch.spelling } end |
#pitches ⇒ Object
34 35 36 |
# File 'lib/head_music/content/voice.rb', line 34 def pitches notes.map(&:pitch) end |
#pitches_string ⇒ Object (private)
154 155 156 |
# File 'lib/head_music/content/voice.rb', line 154 def pitches_string pitches.first(10).map(&:to_s).join(" ") end |
#place(position, rhythmic_value, pitch = nil) ⇒ Object
19 20 21 22 23 |
# File 'lib/head_music/content/voice.rb', line 19 def place(position, rhythmic_value, pitch = nil) HeadMusic::Content::Placement.new(self, position, rhythmic_value, pitch).tap do |placement| insert_into_placements(placement) end end |
#range ⇒ Object
58 59 60 |
# File 'lib/head_music/content/voice.rb', line 58 def range HeadMusic::Analysis::DiatonicInterval.new(lowest_pitch, highest_pitch) end |
#rests ⇒ Object
38 39 40 |
# File 'lib/head_music/content/voice.rb', line 38 def rests @placements.select(&:rest?) end |
#to_s ⇒ Object
137 138 139 140 141 |
# File 'lib/head_music/content/voice.rb', line 137 def to_s return pitches_string if role.to_s.strip == "" [role, pitches_string].join(": ") end |