head_music 0.19.0 → 0.19.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/lib/head_music/chord.rb +29 -3
- data/lib/head_music/functional_interval.rb +175 -94
- data/lib/head_music/octave.rb +8 -0
- data/lib/head_music/style/analysis.rb +7 -7
- data/lib/head_music/style/{annotations → guidelines}/always_move.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/approach_perfection_contrarily.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/at_least_eight_notes.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/avoid_crossing_voices.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/avoid_overlapping_voices.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/consonant_climax.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/consonant_downbeats.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/diatonic.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/direction_changes.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/end_on_perfect_consonance.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/end_on_tonic.rb +3 -3
- data/lib/head_music/style/guidelines/frequent_direction_changes.rb +13 -0
- data/lib/head_music/style/{annotations → guidelines}/limit_octave_leaps.rb +3 -3
- data/lib/head_music/style/guidelines/moderate_direction_changes.rb +13 -0
- data/lib/head_music/style/{annotations → guidelines}/mostly_conjunct.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/no_rests.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/no_unisons_in_middle.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/notes_same_length.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/one_to_one.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/prefer_contrary_motion.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/prefer_imperfect.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/prepare_octave_leaps.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/recover_large_leaps.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/singable_intervals.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/singable_range.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/single_large_leaps.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/start_on_perfect_consonance.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/start_on_tonic.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/step_down_to_final_note.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/step_out_of_unison.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/step_to_final_note.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/step_up_to_final_note.rb +3 -3
- data/lib/head_music/style/{annotations → guidelines}/up_to_fourteen_notes.rb +3 -3
- data/lib/head_music/style/guides/first_species_harmony.rb +22 -0
- data/lib/head_music/style/guides/first_species_melody.rb +28 -0
- data/lib/head_music/style/guides/fux_cantus_firmus.rb +30 -0
- data/lib/head_music/style/guides/modern_cantus_firmus.rb +31 -0
- data/lib/head_music/style/mark.rb +1 -1
- data/lib/head_music/version.rb +1 -1
- data/lib/head_music.rb +39 -39
- metadata +39 -39
- data/lib/head_music/style/annotations/frequent_direction_changes.rb +0 -13
- data/lib/head_music/style/annotations/moderate_direction_changes.rb +0 -13
- data/lib/head_music/style/rulesets/first_species_harmony.rb +0 -22
- data/lib/head_music/style/rulesets/first_species_melody.rb +0 -28
- data/lib/head_music/style/rulesets/fux_cantus_firmus.rb +0 -30
- data/lib/head_music/style/rulesets/modern_cantus_firmus.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 838a7ebfc5a6873d62ac2d484b655bcc5fe37302
|
4
|
+
data.tar.gz: 669f4f3f9ab721dc93208b39ef22ac7170951ba9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ca1b44616d4aed6f76e5838b99a546b28889fed30802fec1c8e5ee713af89352e1326e89bf9e5195104722a574c7f8db47755fa6b561685c1b18b190fc38525
|
7
|
+
data.tar.gz: cc2a14f96a3ec7e7590c59e2b81023ed41a5e9b2f7fb8fd5d25a860c929ece23fa8e2df32adf15faa508b1ed21856a774642d3e4ba40ec4299ce3d2d640df6dd
|
data/LICENSE.txt
CHANGED
data/lib/head_music/chord.rb
CHANGED
@@ -11,7 +11,7 @@ class HeadMusic::Chord
|
|
11
11
|
|
12
12
|
def consonant_triad?
|
13
13
|
return false unless three_pitches?
|
14
|
-
root_triad? || first_inversion_triad? || second_inversion_triad?
|
14
|
+
reduction.root_triad? || reduction.first_inversion_triad? || reduction.second_inversion_triad?
|
15
15
|
end
|
16
16
|
|
17
17
|
def root_triad?
|
@@ -26,8 +26,9 @@ class HeadMusic::Chord
|
|
26
26
|
invert.intervals.map(&:shorthand).sort == %w[M3 m3]
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
def reduction
|
30
|
+
@reduction ||= HeadMusic::Chord.new(reduction_pitches)
|
31
|
+
end
|
31
32
|
|
32
33
|
def three_pitches?
|
33
34
|
pitches.length == 3
|
@@ -44,4 +45,29 @@ class HeadMusic::Chord
|
|
44
45
|
new_pitches = pitches.drop(1) + [inverted_pitch]
|
45
46
|
HeadMusic::Chord.new(new_pitches)
|
46
47
|
end
|
48
|
+
|
49
|
+
def bass_pitch
|
50
|
+
@bass_pitch ||= pitches.first
|
51
|
+
end
|
52
|
+
|
53
|
+
def inspect
|
54
|
+
pitches.map(&:to_s).join(' ')
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_s
|
58
|
+
pitches.map(&:to_s).join(' ')
|
59
|
+
end
|
60
|
+
|
61
|
+
def ==(other)
|
62
|
+
pitches & other.pitches == pitches
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def reduction_pitches
|
68
|
+
pitches.map do |pitch|
|
69
|
+
pitch = HeadMusic::Pitch.fetch_or_create(pitch.spelling, pitch.octave - 1) while pitch > bass_pitch + 12
|
70
|
+
pitch
|
71
|
+
end.sort
|
72
|
+
end
|
47
73
|
end
|
@@ -36,8 +36,8 @@ class HeadMusic::FunctionalInterval
|
|
36
36
|
delegate :to_s, to: :name
|
37
37
|
delegate :perfect?, :major?, :minor?, :diminished?, :augmented?, :doubly_diminished?, :doubly_augmented?, to: :quality
|
38
38
|
|
39
|
-
#
|
40
|
-
class
|
39
|
+
# Interprets a string or symbol
|
40
|
+
class Parser
|
41
41
|
attr_reader :identifier
|
42
42
|
|
43
43
|
def initialize(identifier)
|
@@ -65,114 +65,197 @@ class HeadMusic::FunctionalInterval
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
68
|
+
# Accepts a name and a quality and returns the number of semitones
|
69
|
+
class Semitones
|
70
|
+
attr_reader :count
|
71
|
+
|
72
|
+
def initialize(name, quality_name)
|
73
|
+
@count ||= Semitones.degree_quality_semitones.dig(name, quality_name)
|
74
|
+
end
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
76
|
+
def self.degree_quality_semitones
|
77
|
+
@_degree_quality_semitones ||= begin
|
78
|
+
{}.tap do |degree_quality_semitones|
|
79
|
+
QUALITY_SEMITONES.each do |degree_name, qualities|
|
80
|
+
default_quality = qualities.keys.first
|
81
|
+
default_semitones = qualities[default_quality]
|
82
|
+
degree_quality_semitones[degree_name] = _semitones_for_degree(default_quality, default_semitones)
|
83
|
+
end
|
82
84
|
end
|
83
85
|
end
|
84
86
|
end
|
85
|
-
end
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
def self._semitones_for_degree(quality, default_semitones)
|
89
|
+
{}.tap do |semitones|
|
90
|
+
_degree_quality_modifications(quality).each do |current_quality, delta|
|
91
|
+
semitones[current_quality] = default_semitones + delta
|
92
|
+
end
|
91
93
|
end
|
92
94
|
end
|
93
|
-
end
|
94
95
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
96
|
+
def self._degree_quality_modifications(quality)
|
97
|
+
if quality == :perfect
|
98
|
+
HeadMusic::Quality::PERFECT_INTERVAL_MODIFICATION.invert
|
99
|
+
else
|
100
|
+
HeadMusic::Quality::MAJOR_INTERVAL_MODIFICATION.invert
|
101
|
+
end
|
100
102
|
end
|
101
103
|
end
|
102
104
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
@lower_pitch, @higher_pitch = [pitch1, pitch2].sort
|
107
|
-
end
|
105
|
+
# Accepts the letter name count between two notes and categorizes the interval
|
106
|
+
class Category
|
107
|
+
attr_reader :number
|
108
108
|
|
109
|
-
|
110
|
-
|
111
|
-
|
109
|
+
def initialize(number)
|
110
|
+
@number = number
|
111
|
+
end
|
112
112
|
|
113
|
-
|
114
|
-
|
115
|
-
|
113
|
+
def step?
|
114
|
+
number == 2
|
115
|
+
end
|
116
116
|
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
def skip?
|
118
|
+
number == 3
|
119
|
+
end
|
120
120
|
|
121
|
-
|
122
|
-
|
123
|
-
|
121
|
+
def leap?
|
122
|
+
number >= 3
|
123
|
+
end
|
124
124
|
|
125
|
-
|
126
|
-
|
125
|
+
def large_leap?
|
126
|
+
number > 3
|
127
|
+
end
|
127
128
|
end
|
128
129
|
|
129
|
-
|
130
|
-
|
131
|
-
|
130
|
+
# Encapsulate the distance methods of the interval
|
131
|
+
class Size
|
132
|
+
attr_reader :low_pitch, :high_pitch
|
132
133
|
|
133
|
-
|
134
|
-
|
135
|
-
|
134
|
+
def initialize(pitch1, pitch2)
|
135
|
+
@low_pitch, @high_pitch = *[pitch1, pitch2].sort
|
136
|
+
end
|
136
137
|
|
137
|
-
|
138
|
-
|
139
|
-
|
138
|
+
def simple_number
|
139
|
+
@simple_number ||= @low_pitch.letter_name.steps_to(@high_pitch.letter_name) + 1
|
140
|
+
end
|
140
141
|
|
141
|
-
|
142
|
-
|
143
|
-
|
142
|
+
def octaves
|
143
|
+
@octaves ||= (high_pitch.number - low_pitch.number) / 12
|
144
|
+
end
|
144
145
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
146
|
+
# returns the ordinality of the interval
|
147
|
+
def number
|
148
|
+
simple_number + octaves * 7
|
149
|
+
end
|
150
|
+
|
151
|
+
def simple?
|
152
|
+
octaves.zero?
|
153
|
+
end
|
154
|
+
|
155
|
+
def compound?
|
156
|
+
!simple?
|
152
157
|
end
|
153
|
-
end
|
154
158
|
|
155
|
-
|
156
|
-
|
157
|
-
|
159
|
+
def simple_semitones
|
160
|
+
@simple_semitones ||= semitones % 12
|
161
|
+
end
|
162
|
+
|
163
|
+
def semitones
|
164
|
+
(high_pitch - low_pitch).to_i
|
165
|
+
end
|
166
|
+
|
167
|
+
def steps
|
168
|
+
number - 1
|
169
|
+
end
|
158
170
|
end
|
159
171
|
|
160
|
-
|
161
|
-
|
172
|
+
# Accepts a number and number of semitones and privides the naming methods.
|
173
|
+
class Naming
|
174
|
+
attr_reader :number, :semitones
|
175
|
+
|
176
|
+
def initialize(number:, semitones:)
|
177
|
+
@number = number
|
178
|
+
@semitones = semitones
|
179
|
+
end
|
180
|
+
|
181
|
+
def simple_semitones
|
182
|
+
@simple_semitones ||= semitones % 12
|
183
|
+
end
|
184
|
+
|
185
|
+
def simple_number
|
186
|
+
@simple_number ||= (number - 1) % 7 + 1
|
187
|
+
end
|
188
|
+
|
189
|
+
def simple_name
|
190
|
+
[quality_name, simple_number_name].join(' ')
|
191
|
+
end
|
192
|
+
|
193
|
+
def quality_name
|
194
|
+
starting_quality = QUALITY_SEMITONES[simple_number_name.to_sym].keys.first
|
195
|
+
delta = simple_semitones - QUALITY_SEMITONES[simple_number_name.to_sym][starting_quality]
|
196
|
+
HeadMusic::Quality.from(starting_quality, delta)
|
197
|
+
end
|
198
|
+
|
199
|
+
def simple_number_name
|
200
|
+
NUMBER_NAMES[simple_number - 1]
|
201
|
+
end
|
202
|
+
|
203
|
+
def number_name
|
204
|
+
NUMBER_NAMES[number - 1] || (number.to_s + NAME_SUFFIXES[number % 10])
|
205
|
+
end
|
206
|
+
|
207
|
+
def name
|
208
|
+
if named_number?
|
209
|
+
[quality_name, number_name].join(' ')
|
210
|
+
elsif simple_name == 'perfect unison'
|
211
|
+
"#{octaves.humanize} octaves"
|
212
|
+
else
|
213
|
+
"#{octaves.humanize} octaves and #{quality.article} #{simple_name}"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def shorthand
|
218
|
+
step_shorthand = number == 1 ? 'U' : number
|
219
|
+
[quality.shorthand, step_shorthand].join
|
220
|
+
end
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
def named_number?
|
225
|
+
number < NUMBER_NAMES.length
|
226
|
+
end
|
227
|
+
|
228
|
+
def quality
|
229
|
+
@quality ||= HeadMusic::Quality.get(quality_name)
|
230
|
+
end
|
231
|
+
|
232
|
+
def octaves
|
233
|
+
@octaves ||= semitones / 12
|
234
|
+
end
|
162
235
|
end
|
163
236
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
237
|
+
delegate :step?, :skip?, :leap?, :large_leap?, to: :category
|
238
|
+
delegate :simple_number, :octaves, :number, :simple?, :compound?, :semitones, :simple_semitones, :steps, to: :size
|
239
|
+
delegate(
|
240
|
+
:simple_semitones, :simple_name, :quality_name, :simple_number_name, :number_name, :name, :shorthand, to: :naming
|
241
|
+
)
|
242
|
+
|
243
|
+
# Accepts a name and returns the interval with middle c on the bottom
|
244
|
+
def self.get(identifier)
|
245
|
+
name = Parser.new(identifier)
|
246
|
+
semitones = Semitones.new(name.degree_name.to_sym, name.quality_name).count
|
247
|
+
higher_pitch = HeadMusic::Pitch.from_number_and_letter(HeadMusic::Pitch.middle_c + semitones, name.higher_letter)
|
248
|
+
new(HeadMusic::Pitch.middle_c, higher_pitch)
|
168
249
|
end
|
169
250
|
|
170
|
-
def
|
171
|
-
|
251
|
+
def initialize(pitch1, pitch2)
|
252
|
+
pitch1 = HeadMusic::Pitch.get(pitch1)
|
253
|
+
pitch2 = HeadMusic::Pitch.get(pitch2)
|
254
|
+
@lower_pitch, @higher_pitch = [pitch1, pitch2].sort
|
172
255
|
end
|
173
256
|
|
174
|
-
def
|
175
|
-
|
257
|
+
def quality
|
258
|
+
HeadMusic::Quality.get(quality_name)
|
176
259
|
end
|
177
260
|
|
178
261
|
def inversion
|
@@ -180,6 +263,7 @@ class HeadMusic::FunctionalInterval
|
|
180
263
|
inverted_low_pitch += 12 while inverted_low_pitch < higher_pitch
|
181
264
|
HeadMusic::FunctionalInterval.new(higher_pitch, inverted_low_pitch)
|
182
265
|
end
|
266
|
+
alias invert inversion
|
183
267
|
|
184
268
|
def consonance(style = :standard_practice)
|
185
269
|
consonance_for_perfect(style) ||
|
@@ -190,6 +274,7 @@ class HeadMusic::FunctionalInterval
|
|
190
274
|
def consonance?(style = :standard_practice)
|
191
275
|
consonance(style).perfect? || consonance(style).imperfect?
|
192
276
|
end
|
277
|
+
alias consonant? consonance?
|
193
278
|
|
194
279
|
def perfect_consonance?(style = :standard_practice)
|
195
280
|
consonance(style).perfect?
|
@@ -203,22 +288,6 @@ class HeadMusic::FunctionalInterval
|
|
203
288
|
consonance(style).dissonant?
|
204
289
|
end
|
205
290
|
|
206
|
-
def step?
|
207
|
-
number == 2
|
208
|
-
end
|
209
|
-
|
210
|
-
def skip?
|
211
|
-
number == 3
|
212
|
-
end
|
213
|
-
|
214
|
-
def leap?
|
215
|
-
number >= 3
|
216
|
-
end
|
217
|
-
|
218
|
-
def large_leap?
|
219
|
-
number > 3
|
220
|
-
end
|
221
|
-
|
222
291
|
def <=>(other)
|
223
292
|
other = self.class.get(other) unless other.is_a?(HeadMusic::FunctionalInterval)
|
224
293
|
semitones <=> other.semitones
|
@@ -234,6 +303,18 @@ class HeadMusic::FunctionalInterval
|
|
234
303
|
|
235
304
|
private
|
236
305
|
|
306
|
+
def size
|
307
|
+
@size ||= Size.new(@lower_pitch, @higher_pitch)
|
308
|
+
end
|
309
|
+
|
310
|
+
def category
|
311
|
+
@category ||= Category.new(number)
|
312
|
+
end
|
313
|
+
|
314
|
+
def naming
|
315
|
+
@naming ||= Naming.new(number: number, semitones: semitones)
|
316
|
+
end
|
317
|
+
|
237
318
|
def named_number?
|
238
319
|
number < NUMBER_NAMES.length
|
239
320
|
end
|
data/lib/head_music/octave.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# A module for style analysis and
|
3
|
+
# A module for style analysis and guidelines.
|
4
4
|
module HeadMusic::Style; end
|
5
5
|
|
6
|
-
# An analysis of music according to a
|
6
|
+
# An analysis of music according to a style guide.
|
7
7
|
class HeadMusic::Style::Analysis
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :guide, :voice
|
9
9
|
|
10
|
-
def initialize(
|
11
|
-
@
|
12
|
-
@
|
10
|
+
def initialize(guide, voice)
|
11
|
+
@guide = guide
|
12
|
+
@voice = voice
|
13
13
|
end
|
14
14
|
|
15
15
|
def messages
|
@@ -18,7 +18,7 @@ class HeadMusic::Style::Analysis
|
|
18
18
|
alias annotation_messages messages
|
19
19
|
|
20
20
|
def annotations
|
21
|
-
@annotations ||= @
|
21
|
+
@annotations ||= @guide.analyze(voice)
|
22
22
|
end
|
23
23
|
|
24
24
|
def fitness
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# A counterpoint guideline
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::AlwaysMove < HeadMusic::Style::Annotation
|
8
8
|
MESSAGE = 'Always move to a different note.'
|
9
9
|
|
10
10
|
def marks
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# A counterpoint guideline
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::ApproachPerfectionContrarily < HeadMusic::Style::Annotation
|
8
8
|
MESSAGE = 'Approach perfect consonances by contrary motion.'
|
9
9
|
|
10
10
|
def marks
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# A counterpoint guideline
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::AtLeastEightNotes < HeadMusic::Style::Annotation
|
8
8
|
MINIMUM_NOTES = 8
|
9
9
|
|
10
10
|
MESSAGE = 'Write at least eight notes.'
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# A counterpoint guideline
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::AvoidCrossingVoices < HeadMusic::Style::Annotation
|
8
8
|
MESSAGE = 'Avoid crossing voices. Maintain the high-low relationship between voices.'
|
9
9
|
|
10
10
|
def marks
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# A counterpoint guideline
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::AvoidOverlappingVoices < HeadMusic::Style::Annotation
|
8
8
|
MESSAGE = 'Avoid overlapping voices. Maintain the high-low relationship between voices even for adjacent notes.'
|
9
9
|
|
10
10
|
def marks
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# A counterpoint guideline
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::ConsonantClimax < HeadMusic::Style::Annotation
|
8
8
|
MESSAGE = 'Peak on a consonant high or low note one time or twice with a step between.'
|
9
9
|
|
10
10
|
def marks
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# A counterpoint guideline
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::ConsonantDownbeats < HeadMusic::Style::Annotation
|
8
8
|
MESSAGE = 'Use consonant harmonic intervals on every downbeat.'
|
9
9
|
|
10
10
|
def marks
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# A counterpoint guideline
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::Diatonic < HeadMusic::Style::Annotation
|
8
8
|
MESSAGE = 'Use only notes in the key signature.'
|
9
9
|
|
10
10
|
def marks
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# A melodic line should have direction changes.
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::DirectionChanges < HeadMusic::Style::Annotation
|
8
8
|
def marks
|
9
9
|
return unless overage.positive?
|
10
10
|
penalty_exponent = overage**0.5
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# marks the voice if the first note is not the first or fifth scale degree of the key.
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::EndOnPerfectConsonance < HeadMusic::Style::Annotation
|
8
8
|
MESSAGE = 'End on the first or the fifth scale degree.'
|
9
9
|
|
10
10
|
def marks
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# A counterpoint guideline
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::EndOnTonic < HeadMusic::Style::Annotation
|
8
8
|
MESSAGE = 'End on the first scale degree.'
|
9
9
|
|
10
10
|
def marks
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
|
+
|
6
|
+
# A counterpoint guideline
|
7
|
+
class HeadMusic::Style::Guidelines::FrequentDirectionChanges < HeadMusic::Style::Guidelines::DirectionChanges
|
8
|
+
MESSAGE = 'Change melodic direction frequently.'
|
9
|
+
|
10
|
+
def self.maximum_notes_per_direction
|
11
|
+
3
|
12
|
+
end
|
13
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Module for
|
4
|
-
module HeadMusic::Style::
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
5
|
|
6
6
|
# A counterpoint guideline: Use a maximum of one octave leap.
|
7
|
-
class HeadMusic::Style::
|
7
|
+
class HeadMusic::Style::Guidelines::LimitOctaveLeaps < HeadMusic::Style::Annotation
|
8
8
|
MESSAGE = 'Use a maximum of one octave leap.'
|
9
9
|
|
10
10
|
def marks
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Module for style guidelines.
|
4
|
+
module HeadMusic::Style::Guidelines; end
|
5
|
+
|
6
|
+
# A counterpoint guideline
|
7
|
+
class HeadMusic::Style::Guidelines::ModerateDirectionChanges < HeadMusic::Style::Guidelines::DirectionChanges
|
8
|
+
MESSAGE = 'Change melodic direction occasionally.'
|
9
|
+
|
10
|
+
def self.maximum_notes_per_direction
|
11
|
+
5
|
12
|
+
end
|
13
|
+
end
|