Class: HeadMusic::Style::Guidelines::AllowFifthSpeciesRhythmicValues
Overview
Validates that counterpoint notes use only permitted rhythmic values for fifth species.
Whole notes (final bar only), half notes, quarter notes, and paired stepwise eighth notes
on weak beats are allowed. No dotted rhythms.
Constant Summary
collapse
- PERMITTED_UNIT_NAMES =
%w[whole half quarter eighth].freeze
Instance Method Summary
collapse
Instance Method Details
#bars_with_excess_eighth_pairs ⇒ Object
80
81
82
83
84
85
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 80
def bars_with_excess_eighth_pairs
eighth_notes
.group_by { |note| note.position.bar_number }
.select { |_bar, bar_eighths| bar_eighths.length > 2 }
.keys
end
|
#disallowed_unit_marks ⇒ Object
23
24
25
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 23
def disallowed_unit_marks
mark_each(notes.reject { |note| PERMITTED_UNIT_NAMES.include?(note.rhythmic_value.unit_name) })
end
|
#dotted_rhythm_marks ⇒ Object
27
28
29
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 27
def dotted_rhythm_marks
mark_each(notes.select { |note| note.rhythmic_value.dots > 0 })
end
|
#eighth_notes ⇒ Object
61
62
63
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 61
def eighth_notes
@eighth_notes ||= notes.select { |note| note.rhythmic_value.unit_name == "eighth" }
end
|
#eighth_notes_in_bar(bar_number) ⇒ Object
87
88
89
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 87
def eighth_notes_in_bar(bar_number)
eighth_notes.select { |note| note.position.bar_number == bar_number }
end
|
#excess_eighth_note_pair_marks ⇒ Object
51
52
53
54
55
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 51
def excess_eighth_note_pair_marks
bars_with_excess_eighth_pairs.flat_map do |bar_number|
mark_each(eighth_notes_in_bar(bar_number)[2..])
end
end
|
#final_bar_number ⇒ Object
91
92
93
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 91
def final_bar_number
last_note&.position&.bar_number
end
|
#mark_each(violating_notes) ⇒ Object
57
58
59
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 57
def mark_each(violating_notes)
violating_notes.map { |note| HeadMusic::Style::Mark.for(note) }
end
|
#marks ⇒ Object
10
11
12
13
14
15
16
17
18
19
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 10
def marks
[
*disallowed_unit_marks,
*dotted_rhythm_marks,
*whole_note_not_in_final_bar_marks,
*unpaired_eighth_note_marks,
*non_stepwise_eighth_note_marks,
*excess_eighth_note_pair_marks
]
end
|
#non_stepwise_eighth_note_marks ⇒ Object
43
44
45
46
47
48
49
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 43
def non_stepwise_eighth_note_marks
mark_each(
eighth_notes
.select { |note| paired_eighth?(note) }
.reject { |note| stepwise_eighth?(note) }
)
end
|
#paired_eighth?(note) ⇒ Boolean
65
66
67
68
69
70
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 65
def paired_eighth?(note)
prev = preceding_note(note)
foll = following_note(note)
(prev && prev.rhythmic_value.unit_name == "eighth") ||
(foll && foll.rhythmic_value.unit_name == "eighth")
end
|
#stepwise_eighth?(note) ⇒ Boolean
72
73
74
75
76
77
78
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 72
def stepwise_eighth?(note)
prev = preceding_note(note)
foll = following_note(note)
stepwise_from_prev = prev && HeadMusic::Analysis::MelodicInterval.new(prev, note).step?
stepwise_to_foll = foll && HeadMusic::Analysis::MelodicInterval.new(note, foll).step?
stepwise_from_prev || stepwise_to_foll
end
|
#unpaired_eighth_note_marks ⇒ Object
39
40
41
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 39
def unpaired_eighth_note_marks
mark_each(eighth_notes.reject { |note| paired_eighth?(note) })
end
|
#whole_note_not_in_final_bar_marks ⇒ Object
31
32
33
34
35
36
37
|
# File 'lib/head_music/style/guidelines/allow_fifth_species_rhythmic_values.rb', line 31
def whole_note_not_in_final_bar_marks
mark_each(
notes
.select { |note| note.rhythmic_value.unit_name == "whole" }
.reject { |note| note.position.bar_number == final_bar_number }
)
end
|