Module: HeadMusic::Style::Guidelines::DissonanceFigureDetection

Included in:
FloridDissonanceTreatment, ThirdSpeciesDissonanceTreatment
Defined in:
lib/head_music/style/guidelines/dissonance_figure_detection.rb

Overview

Shared detection of ornamental dissonance figures (nota cambiata, double neighbor). Include in any dissonance treatment guideline that needs to recognize these figures. Expects the including class to provide: #notes, #dissonant_with_cantus?(note)

Instance Method Summary collapse

Instance Method Details

#cambiata_as_note_2?(index) ⇒ Boolean (private)

Returns:

  • (Boolean)


28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/head_music/style/guidelines/dissonance_figure_detection.rb', line 28

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

  n1, n2, n3, n4, n5 = notes[index - 1, 5]

  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)


14
15
16
17
18
19
# File 'lib/head_music/style/guidelines/dissonance_figure_detection.rb', line 14

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

  cambiata_as_note_2?(index)
end

#consonant_with_cantus?(note) ⇒ Boolean (private)

Returns:

  • (Boolean)


64
65
66
# File 'lib/head_music/style/guidelines/dissonance_figure_detection.rb', line 64

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

#double_neighbor_figure?(index, offset:) ⇒ 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)


49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/head_music/style/guidelines/dissonance_figure_detection.rb', line 49

def double_neighbor_figure?(index, offset:)
  start = index - offset
  return false if start < 0 || start + 3 > notes.length - 1

  n1, n2, n3, n4 = notes[start, 4]

  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)

Returns:

  • (Boolean)


21
22
23
24
25
26
# File 'lib/head_music/style/guidelines/dissonance_figure_detection.rb', line 21

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

  double_neighbor_figure?(index, offset: 1) || double_neighbor_figure?(index, offset: 2)
end

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



68
69
70
# File 'lib/head_music/style/guidelines/dissonance_figure_detection.rb', line 68

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