Class: HeadMusic::Style::Guidelines::ThirdSpeciesDissonanceTreatment

Inherits:
Annotation
  • Object
show all
Defined in:
lib/head_music/style/guidelines/third_species_dissonance_treatment.rb

Overview

A counterpoint guideline for third-species dissonance treatment. Every dissonant note on beats 2, 3, or 4 must be treated as a passing tone, neighbor tone, nota cambiata, or double neighbor figure.

Constant Summary collapse

MESSAGE =
"Treat dissonances as passing tones, neighbor tones, cambiata, or double neighbor figures."

Instance Method Summary collapse

Constructor Details

This class inherits a constructor from HeadMusic::Style::Annotation

Instance Method Details

#cambiata_as_note_2?(index) ⇒ Boolean (private)

Returns:

  • (Boolean)


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 61

def cambiata_as_note_2?(index)
  return false if index < 1 || index + 3 > notes.length - 1

  n1 = notes[index - 1]
  n2 = notes[index]
  n3 = notes[index + 1]
  n4 = notes[index + 2]
  n5 = notes[index + 3]

  approach = melodic_interval_between(n1, n2)
  leap = melodic_interval_between(n2, n3)
  step_back_1 = melodic_interval_between(n3, n4)
  step_back_2 = melodic_interval_between(n4, n5)

  approach.step? &&
    leap.number == 3 && approach.direction == leap.direction &&
    step_back_1.step? && step_back_2.step? &&
    step_back_1.direction != leap.direction &&
    step_back_2.direction != leap.direction &&
    consonant_with_cantus?(n1) && consonant_with_cantus?(n3) && consonant_with_cantus?(n5)
end

#cambiata_dissonance?(note) ⇒ Boolean (private)

Nota cambiata: a five-note figure where note 2 is dissonant, approached by step from note 1, leaps a third in the same direction to note 3, then notes 3-4-5 proceed stepwise in the opposite direction. Notes 1, 3, and 5 must be consonant with the CF.

Returns:

  • (Boolean)


54
55
56
57
58
59
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 54

def cambiata_dissonance?(note)
  index = notes.index(note)
  return false unless index

  cambiata_as_note_2?(index)
end

#cantus_firmus_positionsObject (private)



139
140
141
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 139

def cantus_firmus_positions
  @cantus_firmus_positions ||= Set.new(cantus_firmus.notes.map { |n| n.position.to_s })
end

#consonant_with_cantus?(note) ⇒ Boolean (private)

Returns:

  • (Boolean)


148
149
150
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 148

def consonant_with_cantus?(note)
  !dissonant_with_cantus?(note)
end

#dissonant_weak_beat_notesObject (private)



127
128
129
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 127

def dissonant_weak_beat_notes
  weak_beat_notes.select { |note| dissonant_with_cantus?(note) }
end

#dissonant_with_cantus?(note) ⇒ Boolean (private)

Returns:

  • (Boolean)


143
144
145
146
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 143

def dissonant_with_cantus?(note)
  interval = HeadMusic::Analysis::HarmonicInterval.new(cantus_firmus, voice, note.position)
  interval.notes.length == 2 && interval.dissonance?(:two_part_harmony)
end

#double_neighbor_as_note_2?(index) ⇒ Boolean (private)

Returns:

  • (Boolean)


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 93

def double_neighbor_as_note_2?(index)
  return false if index < 1 || index + 2 > notes.length - 1

  n1 = notes[index - 1]
  n2 = notes[index]
  n3 = notes[index + 1]
  n4 = notes[index + 2]

  approach = melodic_interval_between(n1, n2)
  middle = melodic_interval_between(n2, n3)
  departure = melodic_interval_between(n3, n4)

  approach.step? && middle.number == 3 && departure.step? &&
    n1.pitch == n4.pitch &&
    consonant_with_cantus?(n1) && consonant_with_cantus?(n4)
end

#double_neighbor_as_note_3?(index) ⇒ Boolean (private)

Returns:

  • (Boolean)


110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 110

def double_neighbor_as_note_3?(index)
  return false if index < 2 || index + 1 > notes.length - 1

  n1 = notes[index - 2]
  n2 = notes[index - 1]
  n3 = notes[index]
  n4 = notes[index + 1]

  approach = melodic_interval_between(n1, n2)
  middle = melodic_interval_between(n2, n3)
  departure = melodic_interval_between(n3, n4)

  approach.step? && middle.number == 3 && departure.step? &&
    n1.pitch == n4.pitch &&
    consonant_with_cantus?(n1) && consonant_with_cantus?(n4)
end

#double_neighbor_member?(note) ⇒ Boolean (private)

Double neighbor: a four-note figure within one bar. Beats 1 and 4 are the same pitch (consonant), beats 2 and 3 are upper and lower neighbors connected by a leap of a third.

Returns:

  • (Boolean)


86
87
88
89
90
91
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 86

def double_neighbor_member?(note)
  index = notes.index(note)
  return false unless index

  double_neighbor_as_note_2?(index) || double_neighbor_as_note_3?(index)
end

#downbeat_position?(position) ⇒ Boolean (private)

Returns:

  • (Boolean)


135
136
137
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 135

def downbeat_position?(position)
  cantus_firmus_positions.include?(position.to_s)
end

#following_note(note) ⇒ Object (private)



161
162
163
164
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 161

def following_note(note)
  index = notes.index(note)
  notes[index + 1] if index && index < notes.length - 1
end

#marksObject



10
11
12
13
14
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 10

def marks
  return [] unless cantus_firmus&.notes&.any?

  unresolved_dissonant_notes.map { |note| HeadMusic::Style::Mark.for(note) }
end

#melodic_interval_between(note1, note2) ⇒ Object (private)



152
153
154
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 152

def melodic_interval_between(note1, note2)
  HeadMusic::Analysis::MelodicInterval.new(note1, note2)
end

#neighbor_tone?(note) ⇒ Boolean (private)

Neighbor tone: approached by step, left by step in the opposite direction.

Returns:

  • (Boolean)


39
40
41
42
43
44
45
46
47
48
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 39

def neighbor_tone?(note)
  prev = preceding_note(note)
  foll = following_note(note)
  return false unless prev && foll

  approach = melodic_interval_between(prev, note)
  departure = melodic_interval_between(note, foll)

  approach.step? && departure.step? && approach.direction != departure.direction
end

#passing_tone?(note) ⇒ Boolean (private)

Passing tone: approached by step and left by step in the same direction.

Returns:

  • (Boolean)


27
28
29
30
31
32
33
34
35
36
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 27

def passing_tone?(note)
  prev = preceding_note(note)
  foll = following_note(note)
  return false unless prev && foll

  approach = melodic_interval_between(prev, note)
  departure = melodic_interval_between(note, foll)

  approach.step? && departure.step? && approach.direction == departure.direction
end

#preceding_note(note) ⇒ Object (private)



156
157
158
159
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 156

def preceding_note(note)
  index = notes.index(note)
  notes[index - 1] if index && index > 0
end

#recognized_figure?(note) ⇒ Boolean (private)

Returns:

  • (Boolean)


22
23
24
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 22

def recognized_figure?(note)
  passing_tone?(note) || neighbor_tone?(note) || cambiata_dissonance?(note) || double_neighbor_member?(note)
end

#unresolved_dissonant_notesObject (private)



18
19
20
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 18

def unresolved_dissonant_notes
  dissonant_weak_beat_notes.reject { |note| recognized_figure?(note) }
end

#weak_beat_notesObject (private)



131
132
133
# File 'lib/head_music/style/guidelines/third_species_dissonance_treatment.rb', line 131

def weak_beat_notes
  notes.reject { |note| downbeat_position?(note.position) }
end