Class: HeadMusic::Style::Annotation

Inherits:
Object
  • Object
show all
Defined in:
lib/head_music/style/annotation.rb

Overview

An Annotation encapsulates an issue with or comment on a voice

Defined Under Namespace

Classes: Configured

Constant Summary collapse

MESSAGE =
"Write music."

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(voice, **options) ⇒ Annotation

Returns a new instance of Annotation.



26
27
28
29
# File 'lib/head_music/style/annotation.rb', line 26

def initialize(voice, **options)
  @voice = voice
  @options = options
end

Instance Attribute Details

#optionsObject (readonly, protected)

Returns the value of attribute options.



92
93
94
# File 'lib/head_music/style/annotation.rb', line 92

def options
  @options
end

#voiceObject (readonly)

Returns the value of attribute voice.



5
6
7
# File 'lib/head_music/style/annotation.rb', line 5

def voice
  @voice
end

Class Method Details

.with(**options) ⇒ Object

Wraps a guideline class with preset options so it can live in a RULESET and still be instantiated with just a voice, e.g. MinimumNotes.with(minimum: 5).



33
34
35
# File 'lib/head_music/style/annotation.rb', line 33

def self.with(**options)
  Configured.new(self, options)
end

Instance Method Details

#adherent?Boolean

Returns:

  • (Boolean)


62
63
64
# File 'lib/head_music/style/annotation.rb', line 62

def adherent?
  fitness == 1
end

#bass_voice?Boolean (protected)

Returns:

  • (Boolean)


120
121
122
# File 'lib/head_music/style/annotation.rb', line 120

def bass_voice?
  lower_voices.empty?
end

#cantus_firmusObject (protected)



102
103
104
# File 'lib/head_music/style/annotation.rb', line 102

def cantus_firmus
  @cantus_firmus ||= other_voices.detect(&:cantus_firmus?) || other_voices.first
end

#diatonic_interval_from_tonic(note) ⇒ Object (protected)



114
115
116
117
118
# File 'lib/head_music/style/annotation.rb', line 114

def diatonic_interval_from_tonic(note)
  tonic_to_use = tonic_pitch
  tonic_to_use -= HeadMusic::Rudiment::ChromaticInterval.get(:perfect_octave) while tonic_to_use > note.pitch
  HeadMusic::Analysis::DiatonicInterval.new(tonic_to_use, note.pitch)
end

#downbeat_harmonic_intervalsObject (protected)



134
135
136
137
138
139
# File 'lib/head_music/style/annotation.rb', line 134

def downbeat_harmonic_intervals
  @downbeat_harmonic_intervals ||=
    cantus_firmus.notes
      .map { |note| HeadMusic::Analysis::HarmonicInterval.new(note.voice, voice, note.position) }
      .reject { |interval| interval.notes.length < 2 }
end

#end_positionObject



74
75
76
# File 'lib/head_music/style/annotation.rb', line 74

def end_position
  [marks].flatten.compact.map(&:end_position).max
end

#first_noteObject



82
83
84
# File 'lib/head_music/style/annotation.rb', line 82

def first_note
  notes.first
end

#fitnessObject



58
59
60
# File 'lib/head_music/style/annotation.rb', line 58

def fitness
  [marks].flatten.compact.map(&:fitness).reduce(1, :*)
end

#harmonic_intervalsObject (protected)



141
142
143
144
145
146
# File 'lib/head_music/style/annotation.rb', line 141

def harmonic_intervals
  @harmonic_intervals ||=
    positions
      .map { |position| HeadMusic::Analysis::HarmonicInterval.new(cantus_firmus, voice, position) }
      .reject { |harmonic_interval| harmonic_interval.notes.length < 2 }
end

#has_notes?Boolean

Returns:

  • (Boolean)


66
67
68
# File 'lib/head_music/style/annotation.rb', line 66

def has_notes?
  !!first_note
end

#higher_voicesObject (protected)



106
107
108
# File 'lib/head_music/style/annotation.rb', line 106

def higher_voices
  @higher_voices ||= unsorted_higher_voices.sort_by(&:highest_pitch).reverse
end

#last_noteObject



86
87
88
# File 'lib/head_music/style/annotation.rb', line 86

def last_note
  notes.last
end

#lower_voicesObject (protected)



110
111
112
# File 'lib/head_music/style/annotation.rb', line 110

def lower_voices
  @lower_voices ||= unsorted_lower_voices.sort_by(&:lowest_pitch).reverse
end

#messageObject



78
79
80
# File 'lib/head_music/style/annotation.rb', line 78

def message
  self.class::MESSAGE
end

#motionsObject (protected)



128
129
130
131
132
# File 'lib/head_music/style/annotation.rb', line 128

def motions
  downbeat_harmonic_intervals.each_cons(2).map do |harmonic_interval_pair|
    HeadMusic::Analysis::Motion.new(*harmonic_interval_pair)
  end
end

#other_voicesObject (protected)



98
99
100
# File 'lib/head_music/style/annotation.rb', line 98

def other_voices
  @other_voices ||= voices.reject { |part| part == voice }
end

#positionsObject (protected)



148
149
150
151
# File 'lib/head_music/style/annotation.rb', line 148

def positions
  @positions ||=
    voices.map(&:notes).flatten.map(&:position).sort.uniq(&:to_s)
end

#start_positionObject



70
71
72
# File 'lib/head_music/style/annotation.rb', line 70

def start_position
  [marks].flatten.compact.map(&:start_position).min
end

#starts_on_tonic?Boolean (protected)

Returns:

  • (Boolean)


124
125
126
# File 'lib/head_music/style/annotation.rb', line 124

def starts_on_tonic?
  tonic_spelling == first_note.spelling
end

#tonic_pitchObject (protected)



161
162
163
# File 'lib/head_music/style/annotation.rb', line 161

def tonic_pitch
  @tonic_pitch ||= HeadMusic::Rudiment::Pitch.get(tonic_spelling)
end

#unsorted_higher_voicesObject (protected)



153
154
155
# File 'lib/head_music/style/annotation.rb', line 153

def unsorted_higher_voices
  other_voices.select { |part| part.highest_pitch && highest_pitch && part.highest_pitch > highest_pitch }
end

#unsorted_lower_voicesObject (protected)



157
158
159
# File 'lib/head_music/style/annotation.rb', line 157

def unsorted_lower_voices
  other_voices.select { |part| part.lowest_pitch && lowest_pitch && part.lowest_pitch < lowest_pitch }
end

#voicesObject (protected)



94
95
96
# File 'lib/head_music/style/annotation.rb', line 94

def voices
  @voices ||= voice.composition.voices
end