head_music 12.5.0 → 12.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +110 -0
- data/CLAUDE.md +2 -2
- data/Gemfile.lock +2 -1
- data/Rakefile +2 -2
- data/lib/head_music/style/annotation.rb +31 -1
- data/lib/head_music/style/guidelines/at_least_eight_notes.rb +2 -24
- data/lib/head_music/style/guidelines/direction_changes.rb +10 -2
- data/lib/head_music/style/guidelines/four_per_bar.rb +2 -12
- data/lib/head_music/style/guidelines/frequent_direction_changes.rb +1 -4
- data/lib/head_music/style/guidelines/limit_octave_leaps.rb +11 -2
- data/lib/head_music/style/guidelines/maximum_notes.rb +24 -0
- data/lib/head_music/style/guidelines/minimum_notes.rb +34 -0
- data/lib/head_music/style/guidelines/moderate_direction_changes.rb +1 -4
- data/lib/head_music/style/guidelines/mostly_conjunct.rb +7 -2
- data/lib/head_music/style/guidelines/note_count_per_bar.rb +26 -1
- data/lib/head_music/style/guidelines/one_per_bar.rb +2 -12
- data/lib/head_music/style/guidelines/second_species_break.rb +5 -1
- data/lib/head_music/style/guidelines/singable_range.rb +18 -2
- data/lib/head_music/style/guidelines/three_per_bar.rb +2 -12
- data/lib/head_music/style/guidelines/two_per_bar.rb +2 -12
- data/lib/head_music/style/guidelines/up_to_fourteen_notes.rb +2 -14
- data/lib/head_music/style/guides/base.rb +10 -0
- data/lib/head_music/style/guides/combined_first_second_third_species_harmony.rb +1 -7
- data/lib/head_music/style/guides/combined_first_second_third_species_melody.rb +4 -9
- data/lib/head_music/style/guides/diatonic_melody.rb +11 -0
- data/lib/head_music/style/guides/fifth_species_harmony.rb +2 -8
- data/lib/head_music/style/guides/fifth_species_melody.rb +5 -10
- data/lib/head_music/style/guides/first_species_harmony.rb +2 -8
- data/lib/head_music/style/guides/first_species_melody.rb +2 -7
- data/lib/head_music/style/guides/fourth_species_harmony.rb +1 -7
- data/lib/head_music/style/guides/fourth_species_melody.rb +4 -9
- data/lib/head_music/style/guides/fux_cantus_firmus.rb +1 -6
- data/lib/head_music/style/guides/modern_cantus_firmus.rb +1 -6
- data/lib/head_music/style/guides/second_species_harmony.rb +1 -7
- data/lib/head_music/style/guides/second_species_melody.rb +4 -9
- data/lib/head_music/style/guides/species_harmony.rb +14 -5
- data/lib/head_music/style/guides/species_melody.rb +13 -5
- data/lib/head_music/style/guides/third_species_harmony.rb +1 -7
- data/lib/head_music/style/guides/third_species_melody.rb +4 -9
- data/lib/head_music/style/guides/third_species_triple_meter_harmony.rb +1 -7
- data/lib/head_music/style/guides/third_species_triple_meter_melody.rb +4 -9
- data/lib/head_music/version.rb +1 -1
- data/lib/head_music.rb +5 -0
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: db91f6ff65b081bb369f3d2a85e2bc6e6cd092bb0018c2c416bf36bcfc4d4e9d
|
|
4
|
+
data.tar.gz: 266914dfbc382dc27591ea37302b57571b8693f2e0e4bd5189d2fffdff2a7c00
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d53ea28ee01b301ae1070a94fe8929d00b649c7d581976183d20e0bbfd080ccf4c08003719f2280001fb7d6ed00cfe1a5a634bd69b046d5859db56dfab6c6bb5
|
|
7
|
+
data.tar.gz: 9cd2929bddff0033d3caa84832e97a77a920cfc61e4e2d55d4d0be338f1ef7904beaad73748f6d6cc4ef93aea5a3b06292e16b285d0b61d5ad78b4ba2818932b
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,116 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [12.6.0] - 2026-07-03
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `DiatonicMelody` guide: a free diatonic melody not bound to cantus firmus start/end constraints (note-count range configurable, defaulting to 5–24)
|
|
15
|
+
- Configurable guidelines — a guideline can now carry configuration into a `RULESET` via `Annotation.with(...)` (wrapped in `Annotation::Configured`):
|
|
16
|
+
- `MinimumNotes` / `MaximumNotes` — configurable note-count floor and ceiling (`AtLeastEightNotes` / `UpToFourteenNotes` retained as named defaults)
|
|
17
|
+
- `NoteCountPerBar` — configurable `count` and `rhythmic_value` (unifies `OnePerBar`, `TwoPerBar`, `ThreePerBar`, `FourPerBar`)
|
|
18
|
+
- `DirectionChanges` — configurable `maximum_notes_per_direction` (unifies `ModerateDirectionChanges` and `FrequentDirectionChanges`)
|
|
19
|
+
- Configurable thresholds on `SingableRange`, `MostlyConjunct`, `LimitOctaveLeaps`, and `SecondSpeciesBreak`
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Extracted `HeadMusic::Style::Guides::Base` for shared guide analysis behavior; `SpeciesMelody` and `SpeciesHarmony` now inherit from it
|
|
24
|
+
- Hoisted the guidelines common to every guide into `MELODIC_CORE` / `HARMONIC_CORE` constants on the species base classes
|
|
25
|
+
- `SingableRange`'s message now reflects the configured range
|
|
26
|
+
- Renamed the `quality` rake task to `validate`
|
|
27
|
+
|
|
28
|
+
## [12.5.0] - 2026-04-08
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Improved fifth-species counterpoint guidelines
|
|
33
|
+
- Code quality improvements
|
|
34
|
+
|
|
35
|
+
### Removed
|
|
36
|
+
|
|
37
|
+
- Combined 2+3+4 species guides and their guidelines
|
|
38
|
+
|
|
39
|
+
## [12.4.0] - 2026-04-06
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- Fifth-species (florid) counterpoint guides
|
|
44
|
+
- Standard and alternate instrument tunings
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- Ukulele family stringings, tunings, and range data
|
|
49
|
+
|
|
50
|
+
## [12.3.0] - 2026-02-25
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- Fourth-species counterpoint guides
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- Code quality pass
|
|
59
|
+
|
|
60
|
+
## [12.2.0] - 2026-02-24
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
|
|
64
|
+
- Improved guidelines for first-bar entry
|
|
65
|
+
|
|
66
|
+
## [12.1.0] - 2026-02-24
|
|
67
|
+
|
|
68
|
+
### Changed
|
|
69
|
+
|
|
70
|
+
- Refactored species guidelines into separate first-bar, middle-bar, and final-bar rules
|
|
71
|
+
- Unified `FinalBarWholeNote` and `FinalBarDottedHalfNote` into `NoteFillsFinalBar`
|
|
72
|
+
|
|
73
|
+
## [12.0.1] - 2026-02-23
|
|
74
|
+
|
|
75
|
+
### Changed
|
|
76
|
+
|
|
77
|
+
- Renamed triple-meter guides
|
|
78
|
+
|
|
79
|
+
## [12.0.0] - 2026-02-21
|
|
80
|
+
|
|
81
|
+
### Added
|
|
82
|
+
|
|
83
|
+
- Third-species 3:1 guidelines
|
|
84
|
+
- Allow a descending minor sixth as a singable interval
|
|
85
|
+
|
|
86
|
+
### Changed
|
|
87
|
+
|
|
88
|
+
- Extracted shared base classes for guides and step-to-final-note guidelines
|
|
89
|
+
- Refactored third-species dissonance handling and other files to reduce code smells
|
|
90
|
+
|
|
91
|
+
## [11.8.0] - 2026-02-16
|
|
92
|
+
|
|
93
|
+
### Added
|
|
94
|
+
|
|
95
|
+
- `ThirdSpeciesMelody` and `ThirdSpeciesHarmony` guides
|
|
96
|
+
- `ThirdSpeciesDissonanceTreatment` guideline
|
|
97
|
+
- `FourToOne` guideline
|
|
98
|
+
- Third-species counterpoint reference document
|
|
99
|
+
|
|
100
|
+
## [11.7.0] - 2026-02-13
|
|
101
|
+
|
|
102
|
+
### Added
|
|
103
|
+
|
|
104
|
+
- Parallel-perfect check for first species
|
|
105
|
+
|
|
106
|
+
### Changed
|
|
107
|
+
|
|
108
|
+
- `Analysis#fitness` now uses the geometric mean
|
|
109
|
+
|
|
110
|
+
## [11.6.1] - 2026-02-12
|
|
111
|
+
|
|
112
|
+
### Added
|
|
113
|
+
|
|
114
|
+
- Additional test coverage for the two-to-one guideline
|
|
115
|
+
|
|
116
|
+
### Fixed
|
|
117
|
+
|
|
118
|
+
- Accept an implied rest in the first bar of second-species counterpoint
|
|
119
|
+
|
|
10
120
|
## [11.6.0] - 2026-02-10
|
|
11
121
|
|
|
12
122
|
### Added
|
data/CLAUDE.md
CHANGED
|
@@ -26,8 +26,8 @@ bundle exec rspec spec/head_music/rudiments/pitch_spec.rb
|
|
|
26
26
|
# Run linting
|
|
27
27
|
bundle exec rubocop
|
|
28
28
|
|
|
29
|
-
# Run all
|
|
30
|
-
bundle exec rake
|
|
29
|
+
# Run all validation checks (tests, linting, security)
|
|
30
|
+
bundle exec rake validate
|
|
31
31
|
|
|
32
32
|
# Open interactive console with gem loaded
|
|
33
33
|
bin/console
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
head_music (12.
|
|
4
|
+
head_music (12.6.0)
|
|
5
5
|
activesupport (>= 7.0, < 10)
|
|
6
6
|
humanize (~> 2.0)
|
|
7
7
|
i18n (~> 1.8)
|
|
@@ -211,6 +211,7 @@ GEM
|
|
|
211
211
|
PLATFORMS
|
|
212
212
|
arm64-darwin-22
|
|
213
213
|
arm64-darwin-23
|
|
214
|
+
arm64-darwin-25
|
|
214
215
|
x86_64-linux
|
|
215
216
|
|
|
216
217
|
DEPENDENCIES
|
data/Rakefile
CHANGED
|
@@ -33,8 +33,8 @@ end
|
|
|
33
33
|
|
|
34
34
|
task default: :spec
|
|
35
35
|
|
|
36
|
-
desc "Run all
|
|
37
|
-
task
|
|
36
|
+
desc "Run all validation checks (tests, linting, security audit, code quality)"
|
|
37
|
+
task validate: [:spec, :standard, "bundle:audit:check", :rubycritic]
|
|
38
38
|
|
|
39
39
|
desc "Open an irb session preloaded with this library"
|
|
40
40
|
task :console do
|
|
@@ -23,8 +23,36 @@ class HeadMusic::Style::Annotation
|
|
|
23
23
|
delegate :key_signature, to: :composition
|
|
24
24
|
delegate :tonic_spelling, to: :key_signature
|
|
25
25
|
|
|
26
|
-
def initialize(voice)
|
|
26
|
+
def initialize(voice, **options)
|
|
27
27
|
@voice = voice
|
|
28
|
+
@options = options
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Wraps a guideline class with preset options so it can live in a RULESET
|
|
32
|
+
# and still be instantiated with just a voice, e.g. MinimumNotes.with(minimum: 5).
|
|
33
|
+
def self.with(**options)
|
|
34
|
+
Configured.new(self, options)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# A RULESET entry pairing a guideline class with configuration. Quacks like a
|
|
38
|
+
# class to the analyze loop by responding to #new(voice).
|
|
39
|
+
class Configured
|
|
40
|
+
attr_reader :guideline_class, :options
|
|
41
|
+
|
|
42
|
+
def initialize(guideline_class, options)
|
|
43
|
+
@guideline_class = guideline_class
|
|
44
|
+
@options = options
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def new(voice)
|
|
48
|
+
guideline_class.new(voice, **options)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def name
|
|
52
|
+
guideline_class.name
|
|
53
|
+
end
|
|
54
|
+
alias_method :to_s, :name
|
|
55
|
+
alias_method :inspect, :name
|
|
28
56
|
end
|
|
29
57
|
|
|
30
58
|
def fitness
|
|
@@ -61,6 +89,8 @@ class HeadMusic::Style::Annotation
|
|
|
61
89
|
|
|
62
90
|
protected
|
|
63
91
|
|
|
92
|
+
attr_reader :options
|
|
93
|
+
|
|
64
94
|
def voices
|
|
65
95
|
@voices ||= voice.composition.voices
|
|
66
96
|
end
|
|
@@ -1,29 +1,7 @@
|
|
|
1
1
|
# Module for style guidelines.
|
|
2
2
|
module HeadMusic::Style::Guidelines; end
|
|
3
3
|
|
|
4
|
-
# A counterpoint guideline
|
|
5
|
-
class HeadMusic::Style::Guidelines::AtLeastEightNotes < HeadMusic::Style::
|
|
4
|
+
# A counterpoint guideline: the cantus firmus should have at least eight notes.
|
|
5
|
+
class HeadMusic::Style::Guidelines::AtLeastEightNotes < HeadMusic::Style::Guidelines::MinimumNotes
|
|
6
6
|
MINIMUM_NOTES = 8
|
|
7
|
-
|
|
8
|
-
MESSAGE = "Write at least eight notes."
|
|
9
|
-
|
|
10
|
-
def marks
|
|
11
|
-
placements.empty? ? no_placements_mark : deficiency_mark
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
def no_placements_mark
|
|
17
|
-
HeadMusic::Style::Mark.new(
|
|
18
|
-
HeadMusic::Content::Position.new(composition, "1:1"),
|
|
19
|
-
HeadMusic::Content::Position.new(composition, "2:1"),
|
|
20
|
-
fitness: 0
|
|
21
|
-
)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def deficiency_mark
|
|
25
|
-
return unless notes.length < MINIMUM_NOTES
|
|
26
|
-
|
|
27
|
-
HeadMusic::Style::Mark.for_all(placements, fitness: notes.length.to_f / MINIMUM_NOTES)
|
|
28
|
-
end
|
|
29
7
|
end
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# Module for style guidelines.
|
|
2
2
|
module HeadMusic::Style::Guidelines; end
|
|
3
3
|
|
|
4
|
-
# A melodic line should
|
|
4
|
+
# A melodic line should change direction often enough. Configurable via the
|
|
5
|
+
# `maximum_notes_per_direction:` option; subclasses may set a
|
|
6
|
+
# MAXIMUM_NOTES_PER_DIRECTION default and their own MESSAGE.
|
|
5
7
|
class HeadMusic::Style::Guidelines::DirectionChanges < HeadMusic::Style::Annotation
|
|
8
|
+
MESSAGE = "Change melodic direction regularly."
|
|
9
|
+
|
|
6
10
|
def marks
|
|
7
11
|
return unless overage.positive?
|
|
8
12
|
|
|
@@ -15,7 +19,11 @@ class HeadMusic::Style::Guidelines::DirectionChanges < HeadMusic::Style::Annotat
|
|
|
15
19
|
def overage
|
|
16
20
|
return 0 if notes.length < 2
|
|
17
21
|
|
|
18
|
-
[notes_per_direction -
|
|
22
|
+
[notes_per_direction - maximum_notes_per_direction, 0].max
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def maximum_notes_per_direction
|
|
26
|
+
options.fetch(:maximum_notes_per_direction) { self.class::MAXIMUM_NOTES_PER_DIRECTION }
|
|
19
27
|
end
|
|
20
28
|
|
|
21
29
|
def notes_per_direction
|
|
@@ -3,16 +3,6 @@ module HeadMusic::Style::Guidelines; end
|
|
|
3
3
|
|
|
4
4
|
# Checks that each middle bar contains exactly four quarter notes.
|
|
5
5
|
class HeadMusic::Style::Guidelines::FourPerBar < HeadMusic::Style::Guidelines::NoteCountPerBar
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
QUARTER = HeadMusic::Rudiment::RhythmicValue.get(:quarter)
|
|
9
|
-
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
def check_middle_bar(bar_number)
|
|
13
|
-
bar_notes = notes_in_bar(bar_number)
|
|
14
|
-
return if bar_notes.length == 4 && bar_notes.all? { |note| note.rhythmic_value == QUARTER }
|
|
15
|
-
|
|
16
|
-
mark_bar(bar_number)
|
|
17
|
-
end
|
|
6
|
+
COUNT = 4
|
|
7
|
+
RHYTHMIC_VALUE = :quarter
|
|
18
8
|
end
|
|
@@ -4,8 +4,5 @@ module HeadMusic::Style::Guidelines; end
|
|
|
4
4
|
# A counterpoint guideline
|
|
5
5
|
class HeadMusic::Style::Guidelines::FrequentDirectionChanges < HeadMusic::Style::Guidelines::DirectionChanges
|
|
6
6
|
MESSAGE = "Change melodic direction frequently."
|
|
7
|
-
|
|
8
|
-
def self.maximum_notes_per_direction
|
|
9
|
-
3
|
|
10
|
-
end
|
|
7
|
+
MAXIMUM_NOTES_PER_DIRECTION = 3
|
|
11
8
|
end
|
|
@@ -2,19 +2,28 @@
|
|
|
2
2
|
module HeadMusic::Style::Guidelines; end
|
|
3
3
|
|
|
4
4
|
# A counterpoint guideline: Use a maximum of one octave leap.
|
|
5
|
+
# Configurable via the `maximum_leaps:` option.
|
|
5
6
|
class HeadMusic::Style::Guidelines::LimitOctaveLeaps < HeadMusic::Style::Annotation
|
|
6
|
-
|
|
7
|
+
MAXIMUM_LEAPS = 1
|
|
7
8
|
|
|
8
9
|
def marks
|
|
9
|
-
return if octave_leaps.length <=
|
|
10
|
+
return if octave_leaps.length <= maximum_leaps
|
|
10
11
|
|
|
11
12
|
octave_leaps.map do |leap|
|
|
12
13
|
HeadMusic::Style::Mark.for_all(leap.notes)
|
|
13
14
|
end
|
|
14
15
|
end
|
|
15
16
|
|
|
17
|
+
def message
|
|
18
|
+
"Use a maximum of #{maximum_leaps.humanize} octave #{(maximum_leaps == 1) ? "leap" : "leaps"}."
|
|
19
|
+
end
|
|
20
|
+
|
|
16
21
|
private
|
|
17
22
|
|
|
23
|
+
def maximum_leaps
|
|
24
|
+
options.fetch(:maximum_leaps) { self.class::MAXIMUM_LEAPS }
|
|
25
|
+
end
|
|
26
|
+
|
|
18
27
|
def octave_leaps
|
|
19
28
|
melodic_note_pairs.select(&:octave?)
|
|
20
29
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Module for style guidelines.
|
|
2
|
+
module HeadMusic::Style::Guidelines; end
|
|
3
|
+
|
|
4
|
+
# Flags a melody with more than the allowed number of notes.
|
|
5
|
+
# Configurable via the `maximum:` option; subclasses may set a MAXIMUM_NOTES default.
|
|
6
|
+
class HeadMusic::Style::Guidelines::MaximumNotes < HeadMusic::Style::Annotation
|
|
7
|
+
def marks
|
|
8
|
+
HeadMusic::Style::Mark.for_each(notes[maximum..]) if overage.positive?
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def message
|
|
12
|
+
"Write up to #{maximum.humanize} notes."
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def maximum
|
|
18
|
+
options.fetch(:maximum) { self.class::MAXIMUM_NOTES }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def overage
|
|
22
|
+
[notes.length - maximum, 0].max
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Module for style guidelines.
|
|
2
|
+
module HeadMusic::Style::Guidelines; end
|
|
3
|
+
|
|
4
|
+
# Flags a melody with fewer than the required number of notes.
|
|
5
|
+
# Configurable via the `minimum:` option; subclasses may set a MINIMUM_NOTES default.
|
|
6
|
+
class HeadMusic::Style::Guidelines::MinimumNotes < HeadMusic::Style::Annotation
|
|
7
|
+
def marks
|
|
8
|
+
placements.empty? ? no_placements_mark : deficiency_mark
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def message
|
|
12
|
+
"Write at least #{minimum.humanize} notes."
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def minimum
|
|
18
|
+
options.fetch(:minimum) { self.class::MINIMUM_NOTES }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def no_placements_mark
|
|
22
|
+
HeadMusic::Style::Mark.new(
|
|
23
|
+
HeadMusic::Content::Position.new(composition, "1:1"),
|
|
24
|
+
HeadMusic::Content::Position.new(composition, "2:1"),
|
|
25
|
+
fitness: 0
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def deficiency_mark
|
|
30
|
+
return unless notes.length < minimum
|
|
31
|
+
|
|
32
|
+
HeadMusic::Style::Mark.for_all(placements, fitness: notes.length.to_f / minimum)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -4,8 +4,5 @@ module HeadMusic::Style::Guidelines; end
|
|
|
4
4
|
# A counterpoint guideline
|
|
5
5
|
class HeadMusic::Style::Guidelines::ModerateDirectionChanges < HeadMusic::Style::Guidelines::DirectionChanges
|
|
6
6
|
MESSAGE = "Change melodic direction occasionally."
|
|
7
|
-
|
|
8
|
-
def self.maximum_notes_per_direction
|
|
9
|
-
5
|
|
10
|
-
end
|
|
7
|
+
MAXIMUM_NOTES_PER_DIRECTION = 5
|
|
11
8
|
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Module for style guidelines.
|
|
2
2
|
module HeadMusic::Style::Guidelines; end
|
|
3
3
|
|
|
4
|
-
# A counterpoint guideline
|
|
4
|
+
# A counterpoint guideline. Configurable via the `minimum_conjunct_portion:`
|
|
5
|
+
# option (the minimum fraction of melodic motion that must be stepwise).
|
|
5
6
|
class HeadMusic::Style::Guidelines::MostlyConjunct < HeadMusic::Style::Annotation
|
|
6
7
|
MESSAGE = "Use mostly conjunct motion."
|
|
7
8
|
|
|
@@ -10,11 +11,15 @@ class HeadMusic::Style::Guidelines::MostlyConjunct < HeadMusic::Style::Annotatio
|
|
|
10
11
|
# Fux is 5/13 for lydian cantus firmus
|
|
11
12
|
|
|
12
13
|
def marks
|
|
13
|
-
marks_for_skips_and_leaps if conjunct_ratio <
|
|
14
|
+
marks_for_skips_and_leaps if conjunct_ratio < minimum_conjunct_portion
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
private
|
|
17
18
|
|
|
19
|
+
def minimum_conjunct_portion
|
|
20
|
+
options.fetch(:minimum_conjunct_portion) { self.class::MINIMUM_CONJUNCT_PORTION }
|
|
21
|
+
end
|
|
22
|
+
|
|
18
23
|
def marks_for_skips_and_leaps
|
|
19
24
|
melodic_note_pairs
|
|
20
25
|
.reject(&:step?)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# Module for style guidelines.
|
|
2
2
|
module HeadMusic::Style::Guidelines; end
|
|
3
3
|
|
|
4
|
-
#
|
|
4
|
+
# Checks that each middle bar (not first or last) contains an exact number of
|
|
5
|
+
# notes of a given rhythmic value. Configurable via the `count:` and
|
|
6
|
+
# `rhythmic_value:` options; subclasses may set COUNT and RHYTHMIC_VALUE defaults.
|
|
5
7
|
class HeadMusic::Style::Guidelines::NoteCountPerBar < HeadMusic::Style::Annotation
|
|
6
8
|
def marks
|
|
7
9
|
return [] unless cantus_firmus&.notes&.any?
|
|
@@ -9,8 +11,31 @@ class HeadMusic::Style::Guidelines::NoteCountPerBar < HeadMusic::Style::Annotati
|
|
|
9
11
|
middle_bars.filter_map { |bar_number| check_middle_bar(bar_number) }
|
|
10
12
|
end
|
|
11
13
|
|
|
14
|
+
def message
|
|
15
|
+
"Use #{count.humanize} #{rhythmic_unit} #{(count == 1) ? "note" : "notes"} in each middle bar."
|
|
16
|
+
end
|
|
17
|
+
|
|
12
18
|
private
|
|
13
19
|
|
|
20
|
+
def count
|
|
21
|
+
options.fetch(:count) { self.class::COUNT }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def rhythmic_unit
|
|
25
|
+
options.fetch(:rhythmic_value) { self.class::RHYTHMIC_VALUE }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def rhythmic_value
|
|
29
|
+
@rhythmic_value ||= HeadMusic::Rudiment::RhythmicValue.get(rhythmic_unit)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def check_middle_bar(bar_number)
|
|
33
|
+
bar_notes = notes_in_bar(bar_number)
|
|
34
|
+
return if bar_notes.length == count && bar_notes.all? { |note| note.rhythmic_value == rhythmic_value }
|
|
35
|
+
|
|
36
|
+
mark_bar(bar_number)
|
|
37
|
+
end
|
|
38
|
+
|
|
14
39
|
def middle_bars
|
|
15
40
|
cf_notes = cantus_firmus.notes
|
|
16
41
|
return [] if cf_notes.length <= 2
|
|
@@ -3,16 +3,6 @@ module HeadMusic::Style::Guidelines; end
|
|
|
3
3
|
|
|
4
4
|
# Checks that each middle bar contains exactly one whole note.
|
|
5
5
|
class HeadMusic::Style::Guidelines::OnePerBar < HeadMusic::Style::Guidelines::NoteCountPerBar
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
WHOLE = HeadMusic::Rudiment::RhythmicValue.get(:whole)
|
|
9
|
-
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
def check_middle_bar(bar_number)
|
|
13
|
-
bar_notes = notes_in_bar(bar_number)
|
|
14
|
-
return if bar_notes.length == 1 && bar_notes.first.rhythmic_value == WHOLE
|
|
15
|
-
|
|
16
|
-
mark_bar(bar_number)
|
|
17
|
-
end
|
|
6
|
+
COUNT = 1
|
|
7
|
+
RHYTHMIC_VALUE = :whole
|
|
18
8
|
end
|
|
@@ -25,9 +25,13 @@ class HeadMusic::Style::Guidelines::SecondSpeciesBreak < HeadMusic::Style::Guide
|
|
|
25
25
|
.map { |note| HeadMusic::Style::Mark.for(note) }
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
def max_break_ratio
|
|
29
|
+
options.fetch(:max_break_ratio) { self.class::MAX_BREAK_RATIO }
|
|
30
|
+
end
|
|
31
|
+
|
|
28
32
|
def frequency_marks
|
|
29
33
|
return [] if total_bars <= 0
|
|
30
|
-
return [] if break_bars.length <= total_bars *
|
|
34
|
+
return [] if break_bars.length <= total_bars * max_break_ratio
|
|
31
35
|
|
|
32
36
|
break_bar_notes = break_bars.flat_map { |bar| notes_in_bar(bar) }
|
|
33
37
|
[HeadMusic::Style::Mark.for_all(break_bar_notes, fitness: HeadMusic::SMALL_PENALTY_FACTOR)]
|
|
@@ -2,19 +2,35 @@
|
|
|
2
2
|
module HeadMusic::Style::Guidelines; end
|
|
3
3
|
|
|
4
4
|
# A voice shouldn't expend the range of a 10th.
|
|
5
|
+
# Configurable via the `maximum_range:` option (a diatonic interval number).
|
|
5
6
|
class HeadMusic::Style::Guidelines::SingableRange < HeadMusic::Style::Annotation
|
|
6
7
|
MAXIMUM_RANGE = 10
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
# Ordinals whose spoken form begins with a vowel sound take "an" instead of
|
|
10
|
+
# "a" (an eighth, an eleventh, an eighteenth). Others in the singable range
|
|
11
|
+
# take "a".
|
|
12
|
+
VOWEL_SOUND_ORDINALS = [8, 11, 18].freeze
|
|
9
13
|
|
|
10
14
|
def marks
|
|
11
15
|
HeadMusic::Style::Mark.for_each(extremes, fitness: HeadMusic::PENALTY_FACTOR**overage) if overage.positive?
|
|
12
16
|
end
|
|
13
17
|
|
|
18
|
+
def message
|
|
19
|
+
"Limit melodic range to #{indefinite_article} #{maximum_range.ordinalize}."
|
|
20
|
+
end
|
|
21
|
+
|
|
14
22
|
private
|
|
15
23
|
|
|
24
|
+
def maximum_range
|
|
25
|
+
options.fetch(:maximum_range) { self.class::MAXIMUM_RANGE }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def indefinite_article
|
|
29
|
+
VOWEL_SOUND_ORDINALS.include?(maximum_range) ? "an" : "a"
|
|
30
|
+
end
|
|
31
|
+
|
|
16
32
|
def overage
|
|
17
|
-
notes.any? ? [range.number -
|
|
33
|
+
notes.any? ? [range.number - maximum_range, 0].max : 0
|
|
18
34
|
end
|
|
19
35
|
|
|
20
36
|
def extremes
|
|
@@ -3,16 +3,6 @@ module HeadMusic::Style::Guidelines; end
|
|
|
3
3
|
|
|
4
4
|
# Checks that each middle bar contains exactly three quarter notes.
|
|
5
5
|
class HeadMusic::Style::Guidelines::ThreePerBar < HeadMusic::Style::Guidelines::NoteCountPerBar
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
QUARTER = HeadMusic::Rudiment::RhythmicValue.get(:quarter)
|
|
9
|
-
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
def check_middle_bar(bar_number)
|
|
13
|
-
bar_notes = notes_in_bar(bar_number)
|
|
14
|
-
return if bar_notes.length == 3 && bar_notes.all? { |note| note.rhythmic_value == QUARTER }
|
|
15
|
-
|
|
16
|
-
mark_bar(bar_number)
|
|
17
|
-
end
|
|
6
|
+
COUNT = 3
|
|
7
|
+
RHYTHMIC_VALUE = :quarter
|
|
18
8
|
end
|
|
@@ -3,16 +3,6 @@ module HeadMusic::Style::Guidelines; end
|
|
|
3
3
|
|
|
4
4
|
# Checks that each middle bar contains exactly two half notes.
|
|
5
5
|
class HeadMusic::Style::Guidelines::TwoPerBar < HeadMusic::Style::Guidelines::NoteCountPerBar
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
HALF = HeadMusic::Rudiment::RhythmicValue.get(:half)
|
|
9
|
-
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
def check_middle_bar(bar_number)
|
|
13
|
-
bar_notes = notes_in_bar(bar_number)
|
|
14
|
-
return if bar_notes.length == 2 && bar_notes.all? { |note| note.rhythmic_value == HALF }
|
|
15
|
-
|
|
16
|
-
mark_bar(bar_number)
|
|
17
|
-
end
|
|
6
|
+
COUNT = 2
|
|
7
|
+
RHYTHMIC_VALUE = :half
|
|
18
8
|
end
|
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
# Module for style guidelines.
|
|
2
2
|
module HeadMusic::Style::Guidelines; end
|
|
3
3
|
|
|
4
|
-
# A counterpoint guideline
|
|
5
|
-
class HeadMusic::Style::Guidelines::UpToFourteenNotes < HeadMusic::Style::
|
|
4
|
+
# A counterpoint guideline: the cantus firmus should have at most fourteen notes.
|
|
5
|
+
class HeadMusic::Style::Guidelines::UpToFourteenNotes < HeadMusic::Style::Guidelines::MaximumNotes
|
|
6
6
|
MAXIMUM_NOTES = 14
|
|
7
|
-
|
|
8
|
-
MESSAGE = "Write up to fourteen notes."
|
|
9
|
-
|
|
10
|
-
def marks
|
|
11
|
-
HeadMusic::Style::Mark.for_each(notes[MAXIMUM_NOTES..]) if overage.positive?
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
def overage
|
|
17
|
-
[notes.length - MAXIMUM_NOTES, 0].max
|
|
18
|
-
end
|
|
19
7
|
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Module for guides
|
|
2
|
+
module HeadMusic::Style::Guides; end
|
|
3
|
+
|
|
4
|
+
# Base class for style guides. A guide analyzes a voice against its RULESET,
|
|
5
|
+
# producing one annotation per rule.
|
|
6
|
+
class HeadMusic::Style::Guides::Base
|
|
7
|
+
def self.analyze(voice)
|
|
8
|
+
self::RULESET.map { |rule| rule.new(voice) }
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -4,13 +4,7 @@ module HeadMusic::Style::Guides; end
|
|
|
4
4
|
# Rules for combined first, second, and third species harmony
|
|
5
5
|
class HeadMusic::Style::Guides::CombinedFirstSecondThirdSpeciesHarmony < HeadMusic::Style::Guides::SpeciesHarmony
|
|
6
6
|
RULESET = [
|
|
7
|
-
|
|
8
|
-
HeadMusic::Style::Guidelines::AvoidCrossingVoices,
|
|
9
|
-
HeadMusic::Style::Guidelines::AvoidOverlappingVoices,
|
|
10
|
-
HeadMusic::Style::Guidelines::ConsonantDownbeats,
|
|
11
|
-
HeadMusic::Style::Guidelines::NoParallelPerfectOnDownbeats,
|
|
12
|
-
HeadMusic::Style::Guidelines::PreferContraryMotion,
|
|
13
|
-
HeadMusic::Style::Guidelines::PreferImperfect,
|
|
7
|
+
*HARMONIC_CORE,
|
|
14
8
|
HeadMusic::Style::Guidelines::FloridDissonanceTreatment
|
|
15
9
|
].freeze
|
|
16
10
|
end
|
|
@@ -4,19 +4,14 @@ module HeadMusic::Style::Guides; end
|
|
|
4
4
|
# Rules for combined first, second, and third species melodies
|
|
5
5
|
class HeadMusic::Style::Guides::CombinedFirstSecondThirdSpeciesMelody < HeadMusic::Style::Guides::SpeciesMelody
|
|
6
6
|
RULESET = [
|
|
7
|
+
*MELODIC_CORE,
|
|
8
|
+
HeadMusic::Style::Guidelines::AllowedRhythmicValuesForCombined123,
|
|
7
9
|
HeadMusic::Style::Guidelines::AlwaysMove,
|
|
8
|
-
HeadMusic::Style::Guidelines::ConsonantClimax,
|
|
9
|
-
HeadMusic::Style::Guidelines::Diatonic,
|
|
10
10
|
HeadMusic::Style::Guidelines::EndOnTonic,
|
|
11
11
|
HeadMusic::Style::Guidelines::FrequentDirectionChanges,
|
|
12
|
-
HeadMusic::Style::Guidelines::
|
|
13
|
-
HeadMusic::Style::Guidelines::MostlyConjunct,
|
|
12
|
+
HeadMusic::Style::Guidelines::NoRestsAfterNote,
|
|
14
13
|
HeadMusic::Style::Guidelines::PrepareOctaveLeaps,
|
|
15
|
-
HeadMusic::Style::Guidelines::SingableIntervals,
|
|
16
|
-
HeadMusic::Style::Guidelines::SingableRange,
|
|
17
14
|
HeadMusic::Style::Guidelines::StartOnPerfectConsonance,
|
|
18
|
-
HeadMusic::Style::Guidelines::StepUpToFinalNote
|
|
19
|
-
HeadMusic::Style::Guidelines::AllowedRhythmicValuesForCombined123,
|
|
20
|
-
HeadMusic::Style::Guidelines::NoRestsAfterNote
|
|
15
|
+
HeadMusic::Style::Guidelines::StepUpToFinalNote
|
|
21
16
|
].freeze
|
|
22
17
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Guidelines for a free diatonic melody (not bound to cantus firmus start/end constraints).
|
|
2
|
+
class HeadMusic::Style::Guides::DiatonicMelody < HeadMusic::Style::Guides::SpeciesMelody
|
|
3
|
+
RULESET = [
|
|
4
|
+
*MELODIC_CORE,
|
|
5
|
+
HeadMusic::Style::Guidelines::ModerateDirectionChanges,
|
|
6
|
+
HeadMusic::Style::Guidelines::PrepareOctaveLeaps,
|
|
7
|
+
HeadMusic::Style::Guidelines::SingleLargeLeaps,
|
|
8
|
+
HeadMusic::Style::Guidelines::MinimumNotes.with(minimum: 5),
|
|
9
|
+
HeadMusic::Style::Guidelines::MaximumNotes.with(maximum: 24)
|
|
10
|
+
].freeze
|
|
11
|
+
end
|
|
@@ -4,17 +4,11 @@ module HeadMusic::Style::Guides; end
|
|
|
4
4
|
# Rules for fifth species (florid) harmony
|
|
5
5
|
class HeadMusic::Style::Guides::FifthSpeciesHarmony < HeadMusic::Style::Guides::SpeciesHarmony
|
|
6
6
|
RULESET = [
|
|
7
|
-
|
|
8
|
-
HeadMusic::Style::Guidelines::
|
|
9
|
-
HeadMusic::Style::Guidelines::AvoidOverlappingVoices,
|
|
10
|
-
HeadMusic::Style::Guidelines::ConsonantDownbeats,
|
|
7
|
+
*HARMONIC_CORE,
|
|
8
|
+
HeadMusic::Style::Guidelines::FloridDissonanceTreatment,
|
|
11
9
|
HeadMusic::Style::Guidelines::NoParallelPerfectAcrossBarline,
|
|
12
|
-
HeadMusic::Style::Guidelines::NoParallelPerfectOnDownbeats,
|
|
13
10
|
HeadMusic::Style::Guidelines::NoParallelPerfectWithSyncopation,
|
|
14
11
|
HeadMusic::Style::Guidelines::NoStrongBeatUnisons,
|
|
15
|
-
HeadMusic::Style::Guidelines::PreferContraryMotion,
|
|
16
|
-
HeadMusic::Style::Guidelines::PreferImperfect,
|
|
17
|
-
HeadMusic::Style::Guidelines::FloridDissonanceTreatment,
|
|
18
12
|
HeadMusic::Style::Guidelines::SuspensionTreatment
|
|
19
13
|
].freeze
|
|
20
14
|
end
|
|
@@ -4,22 +4,17 @@ module HeadMusic::Style::Guides; end
|
|
|
4
4
|
# Rules for fifth species (florid) melodies
|
|
5
5
|
class HeadMusic::Style::Guides::FifthSpeciesMelody < HeadMusic::Style::Guides::SpeciesMelody
|
|
6
6
|
RULESET = [
|
|
7
|
+
*MELODIC_CORE,
|
|
8
|
+
HeadMusic::Style::Guidelines::AllowedRhythmicValuesForFifthSpecies,
|
|
7
9
|
HeadMusic::Style::Guidelines::AlwaysMove,
|
|
8
|
-
HeadMusic::Style::Guidelines::ConsonantClimax,
|
|
9
|
-
HeadMusic::Style::Guidelines::Diatonic,
|
|
10
10
|
HeadMusic::Style::Guidelines::EndOnTonic,
|
|
11
11
|
HeadMusic::Style::Guidelines::FrequentDirectionChanges,
|
|
12
|
-
HeadMusic::Style::Guidelines::
|
|
13
|
-
HeadMusic::Style::Guidelines::
|
|
12
|
+
HeadMusic::Style::Guidelines::MixedRhythmicValues,
|
|
13
|
+
HeadMusic::Style::Guidelines::NoRestsAfterNote,
|
|
14
14
|
HeadMusic::Style::Guidelines::NoteFillsFinalBar,
|
|
15
15
|
HeadMusic::Style::Guidelines::PrepareOctaveLeaps,
|
|
16
|
-
HeadMusic::Style::Guidelines::SingableIntervals,
|
|
17
|
-
HeadMusic::Style::Guidelines::SingableRange,
|
|
18
16
|
HeadMusic::Style::Guidelines::StartOnPerfectConsonance,
|
|
19
17
|
HeadMusic::Style::Guidelines::StepOutOfUnison,
|
|
20
|
-
HeadMusic::Style::Guidelines::StepUpToFinalNote
|
|
21
|
-
HeadMusic::Style::Guidelines::AllowedRhythmicValuesForFifthSpecies,
|
|
22
|
-
HeadMusic::Style::Guidelines::MixedRhythmicValues,
|
|
23
|
-
HeadMusic::Style::Guidelines::NoRestsAfterNote
|
|
18
|
+
HeadMusic::Style::Guidelines::StepUpToFinalNote
|
|
24
19
|
].freeze
|
|
25
20
|
end
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
# Rules for first species harmony
|
|
2
2
|
class HeadMusic::Style::Guides::FirstSpeciesHarmony < HeadMusic::Style::Guides::SpeciesHarmony
|
|
3
3
|
RULESET = [
|
|
4
|
-
|
|
5
|
-
HeadMusic::Style::Guidelines::AvoidCrossingVoices,
|
|
6
|
-
HeadMusic::Style::Guidelines::AvoidOverlappingVoices,
|
|
7
|
-
HeadMusic::Style::Guidelines::ConsonantDownbeats,
|
|
8
|
-
HeadMusic::Style::Guidelines::NoParallelPerfectOnDownbeats,
|
|
4
|
+
*HARMONIC_CORE,
|
|
9
5
|
HeadMusic::Style::Guidelines::NoUnisonsInMiddle,
|
|
10
|
-
HeadMusic::Style::Guidelines::OneToOne
|
|
11
|
-
HeadMusic::Style::Guidelines::PreferContraryMotion,
|
|
12
|
-
HeadMusic::Style::Guidelines::PreferImperfect
|
|
6
|
+
HeadMusic::Style::Guidelines::OneToOne
|
|
13
7
|
].freeze
|
|
14
8
|
end
|
|
15
9
|
|
|
@@ -4,18 +4,13 @@ module HeadMusic::Style::Guides; end
|
|
|
4
4
|
# Rules for first species melodies
|
|
5
5
|
class HeadMusic::Style::Guides::FirstSpeciesMelody < HeadMusic::Style::Guides::SpeciesMelody
|
|
6
6
|
RULESET = [
|
|
7
|
-
|
|
8
|
-
HeadMusic::Style::Guidelines::Diatonic,
|
|
7
|
+
*MELODIC_CORE,
|
|
9
8
|
HeadMusic::Style::Guidelines::EndOnTonic,
|
|
10
|
-
HeadMusic::Style::Guidelines::NoteFillsFinalBar,
|
|
11
9
|
HeadMusic::Style::Guidelines::FirstBarWholeNote,
|
|
12
10
|
HeadMusic::Style::Guidelines::FrequentDirectionChanges,
|
|
13
|
-
HeadMusic::Style::Guidelines::
|
|
14
|
-
HeadMusic::Style::Guidelines::MostlyConjunct,
|
|
11
|
+
HeadMusic::Style::Guidelines::NoteFillsFinalBar,
|
|
15
12
|
HeadMusic::Style::Guidelines::OnePerBar,
|
|
16
13
|
HeadMusic::Style::Guidelines::PrepareOctaveLeaps,
|
|
17
|
-
HeadMusic::Style::Guidelines::SingableIntervals,
|
|
18
|
-
HeadMusic::Style::Guidelines::SingableRange,
|
|
19
14
|
HeadMusic::Style::Guidelines::StartOnPerfectConsonance,
|
|
20
15
|
HeadMusic::Style::Guidelines::StepOutOfUnison,
|
|
21
16
|
HeadMusic::Style::Guidelines::StepUpToFinalNote
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
# Rules for fourth species harmony
|
|
2
2
|
class HeadMusic::Style::Guides::FourthSpeciesHarmony < HeadMusic::Style::Guides::SpeciesHarmony
|
|
3
3
|
RULESET = [
|
|
4
|
-
|
|
5
|
-
HeadMusic::Style::Guidelines::AvoidCrossingVoices,
|
|
6
|
-
HeadMusic::Style::Guidelines::AvoidOverlappingVoices,
|
|
7
|
-
HeadMusic::Style::Guidelines::ConsonantDownbeats,
|
|
8
|
-
HeadMusic::Style::Guidelines::NoParallelPerfectOnDownbeats,
|
|
4
|
+
*HARMONIC_CORE,
|
|
9
5
|
HeadMusic::Style::Guidelines::NoParallelPerfectWithSyncopation,
|
|
10
6
|
HeadMusic::Style::Guidelines::NoStrongBeatUnisons,
|
|
11
|
-
HeadMusic::Style::Guidelines::PreferContraryMotion,
|
|
12
|
-
HeadMusic::Style::Guidelines::PreferImperfect,
|
|
13
7
|
HeadMusic::Style::Guidelines::SecondSpeciesBreak,
|
|
14
8
|
HeadMusic::Style::Guidelines::SuspensionTreatment
|
|
15
9
|
].freeze
|
|
@@ -4,21 +4,16 @@ module HeadMusic::Style::Guides; end
|
|
|
4
4
|
# Rules for fourth species melodies
|
|
5
5
|
class HeadMusic::Style::Guides::FourthSpeciesMelody < HeadMusic::Style::Guides::SpeciesMelody
|
|
6
6
|
RULESET = [
|
|
7
|
+
*MELODIC_CORE,
|
|
7
8
|
HeadMusic::Style::Guidelines::AlwaysMove,
|
|
8
|
-
HeadMusic::Style::Guidelines::ConsonantClimax,
|
|
9
|
-
HeadMusic::Style::Guidelines::Diatonic,
|
|
10
9
|
HeadMusic::Style::Guidelines::EndOnTonic,
|
|
11
|
-
HeadMusic::Style::Guidelines::NoteFillsFinalBar,
|
|
12
10
|
HeadMusic::Style::Guidelines::FrequentDirectionChanges,
|
|
13
|
-
HeadMusic::Style::Guidelines::
|
|
14
|
-
HeadMusic::Style::Guidelines::
|
|
11
|
+
HeadMusic::Style::Guidelines::NoRestsAfterNote,
|
|
12
|
+
HeadMusic::Style::Guidelines::NoteFillsFinalBar,
|
|
15
13
|
HeadMusic::Style::Guidelines::OneToOneWithTies,
|
|
16
14
|
HeadMusic::Style::Guidelines::PrepareOctaveLeaps,
|
|
17
|
-
HeadMusic::Style::Guidelines::SingableIntervals,
|
|
18
|
-
HeadMusic::Style::Guidelines::SingableRange,
|
|
19
15
|
HeadMusic::Style::Guidelines::StartOnPerfectConsonance,
|
|
20
16
|
HeadMusic::Style::Guidelines::StepOutOfUnison,
|
|
21
|
-
HeadMusic::Style::Guidelines::StepUpToFinalNote
|
|
22
|
-
HeadMusic::Style::Guidelines::NoRestsAfterNote
|
|
17
|
+
HeadMusic::Style::Guidelines::StepUpToFinalNote
|
|
23
18
|
].freeze
|
|
24
19
|
end
|
|
@@ -4,19 +4,14 @@ module HeadMusic::Style::Guides; end
|
|
|
4
4
|
# Rules for the cantus firmus according to Fux.
|
|
5
5
|
class HeadMusic::Style::Guides::FuxCantusFirmus < HeadMusic::Style::Guides::SpeciesMelody
|
|
6
6
|
RULESET = [
|
|
7
|
+
*MELODIC_CORE,
|
|
7
8
|
HeadMusic::Style::Guidelines::AlwaysMove,
|
|
8
9
|
HeadMusic::Style::Guidelines::AtLeastEightNotes,
|
|
9
|
-
HeadMusic::Style::Guidelines::ConsonantClimax,
|
|
10
|
-
HeadMusic::Style::Guidelines::Diatonic,
|
|
11
10
|
HeadMusic::Style::Guidelines::EndOnTonic,
|
|
12
11
|
HeadMusic::Style::Guidelines::FrequentDirectionChanges,
|
|
13
|
-
HeadMusic::Style::Guidelines::LimitOctaveLeaps,
|
|
14
|
-
HeadMusic::Style::Guidelines::MostlyConjunct,
|
|
15
12
|
HeadMusic::Style::Guidelines::NoRests,
|
|
16
13
|
HeadMusic::Style::Guidelines::NotesSameLength,
|
|
17
14
|
HeadMusic::Style::Guidelines::RecoverLargeLeaps,
|
|
18
|
-
HeadMusic::Style::Guidelines::SingableIntervals,
|
|
19
|
-
HeadMusic::Style::Guidelines::SingableRange,
|
|
20
15
|
HeadMusic::Style::Guidelines::StartOnTonic,
|
|
21
16
|
HeadMusic::Style::Guidelines::StepDownToFinalNote,
|
|
22
17
|
HeadMusic::Style::Guidelines::UpToFourteenNotes
|
|
@@ -4,19 +4,14 @@ module HeadMusic::Style::Guides; end
|
|
|
4
4
|
# Modern rules for the cantus firmus
|
|
5
5
|
class HeadMusic::Style::Guides::ModernCantusFirmus < HeadMusic::Style::Guides::SpeciesMelody
|
|
6
6
|
RULESET = [
|
|
7
|
+
*MELODIC_CORE,
|
|
7
8
|
HeadMusic::Style::Guidelines::AlwaysMove,
|
|
8
9
|
HeadMusic::Style::Guidelines::AtLeastEightNotes,
|
|
9
|
-
HeadMusic::Style::Guidelines::ConsonantClimax,
|
|
10
|
-
HeadMusic::Style::Guidelines::Diatonic,
|
|
11
10
|
HeadMusic::Style::Guidelines::EndOnTonic,
|
|
12
|
-
HeadMusic::Style::Guidelines::LimitOctaveLeaps,
|
|
13
11
|
HeadMusic::Style::Guidelines::ModerateDirectionChanges,
|
|
14
|
-
HeadMusic::Style::Guidelines::MostlyConjunct,
|
|
15
12
|
HeadMusic::Style::Guidelines::NoRests,
|
|
16
13
|
HeadMusic::Style::Guidelines::NotesSameLength,
|
|
17
14
|
HeadMusic::Style::Guidelines::PrepareOctaveLeaps,
|
|
18
|
-
HeadMusic::Style::Guidelines::SingableIntervals,
|
|
19
|
-
HeadMusic::Style::Guidelines::SingableRange,
|
|
20
15
|
HeadMusic::Style::Guidelines::SingleLargeLeaps,
|
|
21
16
|
HeadMusic::Style::Guidelines::StartOnTonic,
|
|
22
17
|
HeadMusic::Style::Guidelines::StepToFinalNote,
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
# Rules for second species harmony
|
|
2
2
|
class HeadMusic::Style::Guides::SecondSpeciesHarmony < HeadMusic::Style::Guides::SpeciesHarmony
|
|
3
3
|
RULESET = [
|
|
4
|
-
|
|
5
|
-
HeadMusic::Style::Guidelines::AvoidCrossingVoices,
|
|
6
|
-
HeadMusic::Style::Guidelines::AvoidOverlappingVoices,
|
|
7
|
-
HeadMusic::Style::Guidelines::ConsonantDownbeats,
|
|
4
|
+
*HARMONIC_CORE,
|
|
8
5
|
HeadMusic::Style::Guidelines::NoParallelPerfectAcrossBarline,
|
|
9
|
-
HeadMusic::Style::Guidelines::NoParallelPerfectOnDownbeats,
|
|
10
6
|
HeadMusic::Style::Guidelines::NoStrongBeatUnisons,
|
|
11
|
-
HeadMusic::Style::Guidelines::PreferContraryMotion,
|
|
12
|
-
HeadMusic::Style::Guidelines::PreferImperfect,
|
|
13
7
|
HeadMusic::Style::Guidelines::WeakBeatDissonanceTreatment
|
|
14
8
|
].freeze
|
|
15
9
|
end
|
|
@@ -4,22 +4,17 @@ module HeadMusic::Style::Guides; end
|
|
|
4
4
|
# Rules for second species melodies
|
|
5
5
|
class HeadMusic::Style::Guides::SecondSpeciesMelody < HeadMusic::Style::Guides::SpeciesMelody
|
|
6
6
|
RULESET = [
|
|
7
|
+
*MELODIC_CORE,
|
|
7
8
|
HeadMusic::Style::Guidelines::AlwaysMove,
|
|
8
|
-
HeadMusic::Style::Guidelines::ConsonantClimax,
|
|
9
|
-
HeadMusic::Style::Guidelines::Diatonic,
|
|
10
9
|
HeadMusic::Style::Guidelines::EndOnTonic,
|
|
11
|
-
HeadMusic::Style::Guidelines::NoteFillsFinalBar,
|
|
12
10
|
HeadMusic::Style::Guidelines::FirstBarHalfNotes,
|
|
13
11
|
HeadMusic::Style::Guidelines::FrequentDirectionChanges,
|
|
14
|
-
HeadMusic::Style::Guidelines::
|
|
15
|
-
HeadMusic::Style::Guidelines::
|
|
12
|
+
HeadMusic::Style::Guidelines::NoRestsAfterNote,
|
|
13
|
+
HeadMusic::Style::Guidelines::NoteFillsFinalBar,
|
|
16
14
|
HeadMusic::Style::Guidelines::PrepareOctaveLeaps,
|
|
17
|
-
HeadMusic::Style::Guidelines::SingableIntervals,
|
|
18
|
-
HeadMusic::Style::Guidelines::SingableRange,
|
|
19
15
|
HeadMusic::Style::Guidelines::StartOnPerfectConsonance,
|
|
20
16
|
HeadMusic::Style::Guidelines::StepOutOfUnison,
|
|
21
17
|
HeadMusic::Style::Guidelines::StepUpToFinalNote,
|
|
22
|
-
HeadMusic::Style::Guidelines::TwoPerBar
|
|
23
|
-
HeadMusic::Style::Guidelines::NoRestsAfterNote
|
|
18
|
+
HeadMusic::Style::Guidelines::TwoPerBar
|
|
24
19
|
].freeze
|
|
25
20
|
end
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
# Module for guides
|
|
2
2
|
module HeadMusic::Style::Guides; end
|
|
3
3
|
|
|
4
|
-
# Base class for species harmony guides
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
# Base class for species harmony guides. Inherits analysis behavior from Base;
|
|
5
|
+
# exists as a semantic marker distinguishing harmony guides from melody guides.
|
|
6
|
+
class HeadMusic::Style::Guides::SpeciesHarmony < HeadMusic::Style::Guides::Base
|
|
7
|
+
# Guidelines shared by every harmonic guide. Subclasses splat this into their
|
|
8
|
+
# RULESET: RULESET = [*HARMONIC_CORE, ...species-specific rules].
|
|
9
|
+
HARMONIC_CORE = [
|
|
10
|
+
HeadMusic::Style::Guidelines::ApproachPerfectionContrarily,
|
|
11
|
+
HeadMusic::Style::Guidelines::AvoidCrossingVoices,
|
|
12
|
+
HeadMusic::Style::Guidelines::AvoidOverlappingVoices,
|
|
13
|
+
HeadMusic::Style::Guidelines::ConsonantDownbeats,
|
|
14
|
+
HeadMusic::Style::Guidelines::NoParallelPerfectOnDownbeats,
|
|
15
|
+
HeadMusic::Style::Guidelines::PreferContraryMotion,
|
|
16
|
+
HeadMusic::Style::Guidelines::PreferImperfect
|
|
17
|
+
].freeze
|
|
9
18
|
end
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
# Module for guides
|
|
2
2
|
module HeadMusic::Style::Guides; end
|
|
3
3
|
|
|
4
|
-
# Base class for species melody guides
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
# Base class for species melody guides. Inherits analysis behavior from Base;
|
|
5
|
+
# exists as a semantic marker distinguishing melody guides from harmony guides.
|
|
6
|
+
class HeadMusic::Style::Guides::SpeciesMelody < HeadMusic::Style::Guides::Base
|
|
7
|
+
# Guidelines shared by every melodic guide. Subclasses splat this into their
|
|
8
|
+
# RULESET: RULESET = [*MELODIC_CORE, ...species-specific rules].
|
|
9
|
+
MELODIC_CORE = [
|
|
10
|
+
HeadMusic::Style::Guidelines::ConsonantClimax,
|
|
11
|
+
HeadMusic::Style::Guidelines::Diatonic,
|
|
12
|
+
HeadMusic::Style::Guidelines::LimitOctaveLeaps,
|
|
13
|
+
HeadMusic::Style::Guidelines::MostlyConjunct,
|
|
14
|
+
HeadMusic::Style::Guidelines::SingableIntervals,
|
|
15
|
+
HeadMusic::Style::Guidelines::SingableRange
|
|
16
|
+
].freeze
|
|
9
17
|
end
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
# Rules for third species harmony
|
|
2
2
|
class HeadMusic::Style::Guides::ThirdSpeciesHarmony < HeadMusic::Style::Guides::SpeciesHarmony
|
|
3
3
|
RULESET = [
|
|
4
|
-
|
|
5
|
-
HeadMusic::Style::Guidelines::AvoidCrossingVoices,
|
|
6
|
-
HeadMusic::Style::Guidelines::AvoidOverlappingVoices,
|
|
7
|
-
HeadMusic::Style::Guidelines::ConsonantDownbeats,
|
|
4
|
+
*HARMONIC_CORE,
|
|
8
5
|
HeadMusic::Style::Guidelines::NoParallelPerfectAcrossBarline,
|
|
9
|
-
HeadMusic::Style::Guidelines::NoParallelPerfectOnDownbeats,
|
|
10
6
|
HeadMusic::Style::Guidelines::NoStrongBeatUnisons,
|
|
11
|
-
HeadMusic::Style::Guidelines::PreferContraryMotion,
|
|
12
|
-
HeadMusic::Style::Guidelines::PreferImperfect,
|
|
13
7
|
HeadMusic::Style::Guidelines::ThirdSpeciesDissonanceTreatment
|
|
14
8
|
].freeze
|
|
15
9
|
end
|
|
@@ -4,22 +4,17 @@ module HeadMusic::Style::Guides; end
|
|
|
4
4
|
# Rules for third species melodies
|
|
5
5
|
class HeadMusic::Style::Guides::ThirdSpeciesMelody < HeadMusic::Style::Guides::SpeciesMelody
|
|
6
6
|
RULESET = [
|
|
7
|
+
*MELODIC_CORE,
|
|
7
8
|
HeadMusic::Style::Guidelines::AlwaysMove,
|
|
8
|
-
HeadMusic::Style::Guidelines::ConsonantClimax,
|
|
9
|
-
HeadMusic::Style::Guidelines::Diatonic,
|
|
10
9
|
HeadMusic::Style::Guidelines::EndOnTonic,
|
|
11
|
-
HeadMusic::Style::Guidelines::NoteFillsFinalBar,
|
|
12
10
|
HeadMusic::Style::Guidelines::FirstBarQuarterNotes,
|
|
13
11
|
HeadMusic::Style::Guidelines::FourPerBar,
|
|
14
12
|
HeadMusic::Style::Guidelines::FrequentDirectionChanges,
|
|
15
|
-
HeadMusic::Style::Guidelines::
|
|
16
|
-
HeadMusic::Style::Guidelines::
|
|
13
|
+
HeadMusic::Style::Guidelines::NoRestsAfterNote,
|
|
14
|
+
HeadMusic::Style::Guidelines::NoteFillsFinalBar,
|
|
17
15
|
HeadMusic::Style::Guidelines::PrepareOctaveLeaps,
|
|
18
|
-
HeadMusic::Style::Guidelines::SingableIntervals,
|
|
19
|
-
HeadMusic::Style::Guidelines::SingableRange,
|
|
20
16
|
HeadMusic::Style::Guidelines::StartOnPerfectConsonance,
|
|
21
17
|
HeadMusic::Style::Guidelines::StepOutOfUnison,
|
|
22
|
-
HeadMusic::Style::Guidelines::StepUpToFinalNote
|
|
23
|
-
HeadMusic::Style::Guidelines::NoRestsAfterNote
|
|
18
|
+
HeadMusic::Style::Guidelines::StepUpToFinalNote
|
|
24
19
|
].freeze
|
|
25
20
|
end
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
# Rules for triple meter harmony
|
|
2
2
|
class HeadMusic::Style::Guides::ThirdSpeciesTripleMeterHarmony < HeadMusic::Style::Guides::SpeciesHarmony
|
|
3
3
|
RULESET = [
|
|
4
|
-
|
|
5
|
-
HeadMusic::Style::Guidelines::AvoidCrossingVoices,
|
|
6
|
-
HeadMusic::Style::Guidelines::AvoidOverlappingVoices,
|
|
7
|
-
HeadMusic::Style::Guidelines::ConsonantDownbeats,
|
|
4
|
+
*HARMONIC_CORE,
|
|
8
5
|
HeadMusic::Style::Guidelines::NoParallelPerfectAcrossBarline,
|
|
9
|
-
HeadMusic::Style::Guidelines::NoParallelPerfectOnDownbeats,
|
|
10
6
|
HeadMusic::Style::Guidelines::NoStrongBeatUnisons,
|
|
11
|
-
HeadMusic::Style::Guidelines::PreferContraryMotion,
|
|
12
|
-
HeadMusic::Style::Guidelines::PreferImperfect,
|
|
13
7
|
HeadMusic::Style::Guidelines::TripleMeterDissonanceTreatment
|
|
14
8
|
].freeze
|
|
15
9
|
end
|
|
@@ -4,22 +4,17 @@ module HeadMusic::Style::Guides; end
|
|
|
4
4
|
# Rules for triple meter melodies
|
|
5
5
|
class HeadMusic::Style::Guides::ThirdSpeciesTripleMeterMelody < HeadMusic::Style::Guides::SpeciesMelody
|
|
6
6
|
RULESET = [
|
|
7
|
+
*MELODIC_CORE,
|
|
7
8
|
HeadMusic::Style::Guidelines::AlwaysMove,
|
|
8
|
-
HeadMusic::Style::Guidelines::ConsonantClimax,
|
|
9
|
-
HeadMusic::Style::Guidelines::Diatonic,
|
|
10
9
|
HeadMusic::Style::Guidelines::EndOnTonic,
|
|
11
|
-
HeadMusic::Style::Guidelines::NoteFillsFinalBar,
|
|
12
10
|
HeadMusic::Style::Guidelines::FirstBarQuarterNotes,
|
|
13
11
|
HeadMusic::Style::Guidelines::FrequentDirectionChanges,
|
|
14
|
-
HeadMusic::Style::Guidelines::
|
|
15
|
-
HeadMusic::Style::Guidelines::
|
|
12
|
+
HeadMusic::Style::Guidelines::NoRestsAfterNote,
|
|
13
|
+
HeadMusic::Style::Guidelines::NoteFillsFinalBar,
|
|
16
14
|
HeadMusic::Style::Guidelines::PrepareOctaveLeaps,
|
|
17
|
-
HeadMusic::Style::Guidelines::SingableIntervals,
|
|
18
|
-
HeadMusic::Style::Guidelines::SingableRange,
|
|
19
15
|
HeadMusic::Style::Guidelines::StartOnPerfectConsonance,
|
|
20
16
|
HeadMusic::Style::Guidelines::StepOutOfUnison,
|
|
21
17
|
HeadMusic::Style::Guidelines::StepUpToFinalNote,
|
|
22
|
-
HeadMusic::Style::Guidelines::ThreePerBar
|
|
23
|
-
HeadMusic::Style::Guidelines::NoRestsAfterNote
|
|
18
|
+
HeadMusic::Style::Guidelines::ThreePerBar
|
|
24
19
|
].freeze
|
|
25
20
|
end
|
data/lib/head_music/version.rb
CHANGED
data/lib/head_music.rb
CHANGED
|
@@ -9,6 +9,7 @@ require "head_music/version"
|
|
|
9
9
|
|
|
10
10
|
require "active_support/core_ext/module/delegation"
|
|
11
11
|
require "active_support/core_ext/string/access"
|
|
12
|
+
require "active_support/core_ext/integer/inflections"
|
|
12
13
|
require "humanize"
|
|
13
14
|
require "i18n"
|
|
14
15
|
require "i18n/backend/fallbacks"
|
|
@@ -152,6 +153,7 @@ require "head_music/style/mark"
|
|
|
152
153
|
# style guidelines
|
|
153
154
|
require "head_music/style/guidelines/always_move"
|
|
154
155
|
require "head_music/style/guidelines/approach_perfection_contrarily"
|
|
156
|
+
require "head_music/style/guidelines/minimum_notes"
|
|
155
157
|
require "head_music/style/guidelines/at_least_eight_notes"
|
|
156
158
|
require "head_music/style/guidelines/avoid_crossing_voices"
|
|
157
159
|
require "head_music/style/guidelines/avoid_overlapping_voices"
|
|
@@ -200,6 +202,7 @@ require "head_music/style/guidelines/step_up_to_final_note"
|
|
|
200
202
|
require "head_music/style/guidelines/suspension_treatment"
|
|
201
203
|
require "head_music/style/guidelines/three_per_bar"
|
|
202
204
|
require "head_music/style/guidelines/two_per_bar"
|
|
205
|
+
require "head_music/style/guidelines/maximum_notes"
|
|
203
206
|
require "head_music/style/guidelines/up_to_fourteen_notes"
|
|
204
207
|
require "head_music/style/guidelines/weak_beat_dissonance_treatment"
|
|
205
208
|
require "head_music/style/guidelines/dissonance_figure_detection"
|
|
@@ -212,10 +215,12 @@ require "head_music/style/guidelines/florid_dissonance_treatment"
|
|
|
212
215
|
require "head_music/style/guidelines/mixed_rhythmic_values"
|
|
213
216
|
|
|
214
217
|
# style guides
|
|
218
|
+
require "head_music/style/guides/base"
|
|
215
219
|
require "head_music/style/guides/species_melody"
|
|
216
220
|
require "head_music/style/guides/fux_cantus_firmus"
|
|
217
221
|
require "head_music/style/guides/modern_cantus_firmus"
|
|
218
222
|
require "head_music/style/guides/first_species_melody"
|
|
223
|
+
require "head_music/style/guides/diatonic_melody"
|
|
219
224
|
require "head_music/style/guides/species_harmony"
|
|
220
225
|
require "head_music/style/guides/first_species_harmony"
|
|
221
226
|
require "head_music/style/guides/second_species_melody"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: head_music
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 12.
|
|
4
|
+
version: 12.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rob Head
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -291,6 +291,8 @@ files:
|
|
|
291
291
|
- lib/head_music/style/guidelines/four_per_bar.rb
|
|
292
292
|
- lib/head_music/style/guidelines/frequent_direction_changes.rb
|
|
293
293
|
- lib/head_music/style/guidelines/limit_octave_leaps.rb
|
|
294
|
+
- lib/head_music/style/guidelines/maximum_notes.rb
|
|
295
|
+
- lib/head_music/style/guidelines/minimum_notes.rb
|
|
294
296
|
- lib/head_music/style/guidelines/mixed_rhythmic_values.rb
|
|
295
297
|
- lib/head_music/style/guidelines/moderate_direction_changes.rb
|
|
296
298
|
- lib/head_music/style/guidelines/mostly_conjunct.rb
|
|
@@ -328,8 +330,10 @@ files:
|
|
|
328
330
|
- lib/head_music/style/guidelines/two_per_bar.rb
|
|
329
331
|
- lib/head_music/style/guidelines/up_to_fourteen_notes.rb
|
|
330
332
|
- lib/head_music/style/guidelines/weak_beat_dissonance_treatment.rb
|
|
333
|
+
- lib/head_music/style/guides/base.rb
|
|
331
334
|
- lib/head_music/style/guides/combined_first_second_third_species_harmony.rb
|
|
332
335
|
- lib/head_music/style/guides/combined_first_second_third_species_melody.rb
|
|
336
|
+
- lib/head_music/style/guides/diatonic_melody.rb
|
|
333
337
|
- lib/head_music/style/guides/fifth_species_harmony.rb
|
|
334
338
|
- lib/head_music/style/guides/fifth_species_melody.rb
|
|
335
339
|
- lib/head_music/style/guides/first_species_harmony.rb
|
|
@@ -417,7 +421,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
417
421
|
- !ruby/object:Gem::Version
|
|
418
422
|
version: '0'
|
|
419
423
|
requirements: []
|
|
420
|
-
rubygems_version: 3.5.
|
|
424
|
+
rubygems_version: 3.5.3
|
|
421
425
|
signing_key:
|
|
422
426
|
specification_version: 4
|
|
423
427
|
summary: The rudiments of western music theory and analysis.
|