head_music 0.16.0 → 0.16.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 445b3a56d6b47014d6baa3d5a194f2721aebd04d
4
- data.tar.gz: 5eade45431e7167069a5f669713dab209c70529c
3
+ metadata.gz: 3eff7c01e7dbb6e69538d9cdcbad34c55fc9f05e
4
+ data.tar.gz: e78e38ddd5ec3e8c77aae6a9dc371df7183ef29d
5
5
  SHA512:
6
- metadata.gz: dfaf16a40716354c6364ddcdc749046a8af9800d838f190e829a56a38e9a5ae110757dc2aab69154c0290a279bcd2a7db6a9b7d10f56afc7d99e54f5c3b8a3b7
7
- data.tar.gz: 8736a3fb3564809f62b64a5a7e502563ba08a484b15b1b80c8d4540c668b8ebbff1fa8ce077bb4f5be4b921ac53141d497e79bdaec25c0cbcbe170ea58b2cb94
6
+ metadata.gz: 98da361ccd151df8d8b8d31688a783cbf3586845e06bf5584e6131b0eb657f18f820f0111e86cdd6a38e65770a99a64588e5693d938aa364b317f590f01db330
7
+ data.tar.gz: 67bfc70343e9c9733671aea1e9d1d80291ee4233e70fe60899e22efe61f8f6132cff06e54804aa34e3b098080db22919ba38a695a615d42219ba04ee2a3f1c74
@@ -19,7 +19,7 @@ module HeadMusic
19
19
 
20
20
  def fitness
21
21
  return 1.0 if annotations.length == 0
22
- fitness_scores.inject(:+).to_f / fitness_scores.length
22
+ @fitness ||= fitness_scores.inject(:+).to_f / fitness_scores.length
23
23
  end
24
24
 
25
25
  def adherent?
@@ -29,7 +29,7 @@ module HeadMusic
29
29
  private
30
30
 
31
31
  def fitness_scores
32
- annotations.map(&:fitness)
32
+ @fitness_scores ||= annotations.map(&:fitness)
33
33
  end
34
34
  end
35
35
  end
@@ -2,7 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::AvoidCrossingVoices < HeadMusic::Style::Annotation
5
- MESSAGE = "Avoid crossing voices."
5
+ MESSAGE = "Avoid crossing voices. Maintain the high-low relationship between voices."
6
6
 
7
7
  def marks
8
8
  crossings.map do |crossing|
@@ -2,7 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::AvoidOverlappingVoices < HeadMusic::Style::Annotation
5
- MESSAGE = "Avoid overlapping voices."
5
+ MESSAGE = "Avoid overlapping voices. Maintain the high-low relationship between voices even for adjacent notes."
6
6
 
7
7
  def marks
8
8
  overlappings
@@ -2,7 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::ConsonantClimax < HeadMusic::Style::Annotation
5
- MESSAGE = "Peak on a consonant high note one time or twice with a step between."
5
+ MESSAGE = "Peak on a consonant high or low note one time or twice with a step between."
6
6
 
7
7
  def marks
8
8
  HeadMusic::Style::Mark.for_each(highest_notes) if !adherent_climax?
@@ -11,7 +11,7 @@ class HeadMusic::Style::Annotations::ConsonantClimax < HeadMusic::Style::Annotat
11
11
  private
12
12
 
13
13
  def adherent_climax?
14
- adherent_high_pitch? || adherent_low_pitch?
14
+ descending_melody? ? adherent_low_pitch? : adherent_high_pitch?
15
15
  end
16
16
 
17
17
  def adherent_high_pitch?
@@ -21,7 +21,6 @@ class HeadMusic::Style::Annotations::ConsonantClimax < HeadMusic::Style::Annotat
21
21
 
22
22
  def adherent_low_pitch?
23
23
  notes? &&
24
- only_goes_down? &&
25
24
  lowest_pitch_consonant_with_tonic? &&
26
25
  ( lowest_pitch_appears_once? || lowest_pitch_appears_twice_with_step_between? )
27
26
  end
@@ -101,7 +100,14 @@ class HeadMusic::Style::Annotations::ConsonantClimax < HeadMusic::Style::Annotat
101
100
  notes[(indexes.first + 1)..(indexes.last - 1)] || []
102
101
  end
103
102
 
104
- def only_goes_down?
105
- first_note && first_note.pitch == highest_pitch
103
+ def descending_melody?
104
+ # account for the possibility of opening with an octave leap
105
+ notes.length > 1 &&
106
+ [first_note.pitch, second_note.pitch].include?(highest_pitch) &&
107
+ highest_pitch.spelling == tonic_spelling
108
+ end
109
+
110
+ def second_note
111
+ notes && notes[1]
106
112
  end
107
113
  end
@@ -2,7 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::ConsonantDownbeats < HeadMusic::Style::Annotation
5
- MESSAGE = "Use consonant harmonic intervals."
5
+ MESSAGE = "Use consonant harmonic intervals on every downbeat."
6
6
 
7
7
  def marks
8
8
  dissonant_pairs.map do |dissonant_pair|
@@ -3,7 +3,7 @@ end
3
3
 
4
4
  # marks the voice if the first note is not the first or fifth scale degree of the key.
5
5
  class HeadMusic::Style::Annotations::EndOnPerfectConsonance < HeadMusic::Style::Annotation
6
- MESSAGE = 'End on the tonic or the fifth scale degree.'
6
+ MESSAGE = 'End on the first or the fifth scale degree.'
7
7
 
8
8
  def marks
9
9
  if last_note && !ends_on_perfect_consonance?
@@ -2,7 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::EndOnTonic < HeadMusic::Style::Annotation
5
- MESSAGE = 'End on the tonic.'
5
+ MESSAGE = 'End on the first scale degree.'
6
6
 
7
7
  def marks
8
8
  if !notes.empty? && !ends_on_tonic?
@@ -2,7 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::LimitOctaveLeaps < HeadMusic::Style::Annotation
5
- MESSAGE = "Use a maximum of one octave skip."
5
+ MESSAGE = "Use a maximum of one octave leap."
6
6
 
7
7
  def marks
8
8
  if octave_leaps.length > 1
@@ -2,7 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::NoRests < HeadMusic::Style::Annotation
5
- MESSAGE = "Use only notes."
5
+ MESSAGE = "Place a note in each measure."
6
6
 
7
7
  def marks
8
8
  HeadMusic::Style::Mark.for_each(rests)
@@ -2,7 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::PreferContraryMotion < HeadMusic::Style::Annotation
5
- MESSAGE = "Prefer contrary motion."
5
+ MESSAGE = "Prefer contrary motion. Move voices in different melodic directions."
6
6
 
7
7
  def marks
8
8
  return nil if notes.length < 2
@@ -14,7 +14,7 @@ class HeadMusic::Style::Annotations::PrepareOctaveLeaps < HeadMusic::Style::Anno
14
14
 
15
15
  def external_entries
16
16
  melodic_intervals.map.with_index do |melodic_interval, i|
17
- if melodic_interval.octave? && (i == 0 || !melodic_interval.spans?(notes[i-1].pitch))
17
+ if melodic_interval.octave? && i > 0 && !melodic_interval.spans?(notes[i-1].pitch)
18
18
  notes[[i-1, 0].max..(i+1)]
19
19
  end
20
20
  end.compact
@@ -6,7 +6,7 @@ end
6
6
  # unless another leap (in either direction) creates a consonant triad.
7
7
  # - Brian
8
8
  class HeadMusic::Style::Annotations::RecoverLargeLeaps < HeadMusic::Style::Annotation
9
- MESSAGE = "Recover leaps by step in the opposite direction."
9
+ MESSAGE = "Recover large leaps by step in the opposite direction."
10
10
 
11
11
  def marks
12
12
  melodic_intervals.drop(1).to_a.map.with_index do |interval, i|
@@ -2,7 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::StartOnTonic < HeadMusic::Style::Annotation
5
- MESSAGE = 'Start on the tonic.'
5
+ MESSAGE = 'Start on the first scale degree.'
6
6
 
7
7
  def marks
8
8
  if first_note && !starts_on_tonic?
@@ -2,7 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::StepDownToFinalNote < HeadMusic::Style::Annotation
5
- MESSAGE = 'Step down to final note.'
5
+ MESSAGE = 'Step down to the final note.'
6
6
 
7
7
  def marks
8
8
  if !last_melodic_interval.nil?
@@ -0,0 +1,20 @@
1
+ module HeadMusic::Style::Annotations
2
+ end
3
+
4
+ class HeadMusic::Style::Annotations::StepToFinalNote < HeadMusic::Style::Annotation
5
+ MESSAGE = 'Step to the final note.'
6
+
7
+ def marks
8
+ HeadMusic::Style::Mark.for_all(notes[-2..-1]) unless step_to_final_note?
9
+ end
10
+
11
+ private
12
+
13
+ def step_to_final_note?
14
+ last_melodic_interval && last_melodic_interval.step?
15
+ end
16
+
17
+ def last_melodic_interval
18
+ @last_melodic_interval ||= melodic_intervals.last
19
+ end
20
+ end
@@ -4,7 +4,7 @@ end
4
4
  class HeadMusic::Style::Annotations::UpToFourteenNotes < HeadMusic::Style::Annotation
5
5
  MAXIMUM_NOTES = 14
6
6
 
7
- MESSAGE = 'Write up to thirteen notes.'
7
+ MESSAGE = 'Write up to fourteen notes.'
8
8
 
9
9
  def marks
10
10
  if overage > 0
@@ -7,10 +7,10 @@ class HeadMusic::Style::Rulesets::FirstSpeciesHarmony
7
7
  HeadMusic::Style::Annotations::AvoidCrossingVoices,
8
8
  HeadMusic::Style::Annotations::AvoidOverlappingVoices,
9
9
  HeadMusic::Style::Annotations::ConsonantDownbeats,
10
- HeadMusic::Style::Annotations::PreferContraryMotion,
11
- HeadMusic::Style::Annotations::PreferImperfect,
12
10
  HeadMusic::Style::Annotations::NoUnisonsInMiddle,
13
11
  HeadMusic::Style::Annotations::OneToOne,
12
+ HeadMusic::Style::Annotations::PreferContraryMotion,
13
+ HeadMusic::Style::Annotations::PreferImperfect,
14
14
  ]
15
15
 
16
16
  def self.analyze(voice)
@@ -1,7 +1,7 @@
1
1
  module HeadMusic::Style::Rulesets
2
2
  end
3
3
 
4
- class HeadMusic::Style::Rulesets::DavisLybbertCantusFirmus
4
+ class HeadMusic::Style::Rulesets::ModernCantusFirmus
5
5
  RULESET = [
6
6
  HeadMusic::Style::Annotations::AlwaysMove,
7
7
  HeadMusic::Style::Annotations::AtLeastEightNotes,
@@ -18,7 +18,7 @@ class HeadMusic::Style::Rulesets::DavisLybbertCantusFirmus
18
18
  HeadMusic::Style::Annotations::SingableRange,
19
19
  HeadMusic::Style::Annotations::SingleLargeLeaps,
20
20
  HeadMusic::Style::Annotations::StartOnTonic,
21
- HeadMusic::Style::Annotations::StepDownToFinalNote,
21
+ HeadMusic::Style::Annotations::StepToFinalNote,
22
22
  HeadMusic::Style::Annotations::UpToFourteenNotes,
23
23
  ]
24
24
 
@@ -1,3 +1,3 @@
1
1
  module HeadMusic
2
- VERSION = "0.16.0"
2
+ VERSION = "0.16.2"
3
3
  end
@@ -54,9 +54,10 @@ class HeadMusic::Voice
54
54
  end
55
55
 
56
56
  def melodic_intervals
57
- notes.map.with_index do |note, i|
58
- HeadMusic::MelodicInterval.new(self, notes[i-1], note) if i > 0
59
- end.compact
57
+ @melodic_intervals ||=
58
+ notes.map.with_index do |note, i|
59
+ HeadMusic::MelodicInterval.new(self, notes[i-1], note) if i > 0
60
+ end.compact
60
61
  end
61
62
 
62
63
  def leaps
data/lib/head_music.rb CHANGED
@@ -65,9 +65,9 @@ require 'head_music/style/annotations/frequent_direction_changes'
65
65
  require 'head_music/style/annotations/limit_octave_leaps'
66
66
  require 'head_music/style/annotations/moderate_direction_changes'
67
67
  require 'head_music/style/annotations/mostly_conjunct'
68
+ require 'head_music/style/annotations/notes_same_length'
68
69
  require 'head_music/style/annotations/no_rests'
69
70
  require 'head_music/style/annotations/no_unisons_in_middle'
70
- require 'head_music/style/annotations/notes_same_length'
71
71
  require 'head_music/style/annotations/one_to_one'
72
72
  require 'head_music/style/annotations/prefer_contrary_motion'
73
73
  require 'head_music/style/annotations/prefer_imperfect'
@@ -80,11 +80,12 @@ require 'head_music/style/annotations/start_on_perfect_consonance'
80
80
  require 'head_music/style/annotations/start_on_tonic'
81
81
  require 'head_music/style/annotations/step_down_to_final_note'
82
82
  require 'head_music/style/annotations/step_out_of_unison'
83
+ require 'head_music/style/annotations/step_to_final_note'
83
84
  require 'head_music/style/annotations/step_up_to_final_note'
84
85
  require 'head_music/style/annotations/up_to_fourteen_notes'
85
86
 
86
87
  require 'head_music/style/rulesets/fux_cantus_firmus'
87
- require 'head_music/style/rulesets/davis_lybbert_cantus_firmus'
88
+ require 'head_music/style/rulesets/modern_cantus_firmus'
88
89
  require 'head_music/style/rulesets/first_species_melody'
89
90
  require 'head_music/style/rulesets/first_species_harmony'
90
91
 
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: 0.16.0
4
+ version: 0.16.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Head
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-06-15 00:00:00.000000000 Z
11
+ date: 2017-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -181,13 +181,14 @@ files:
181
181
  - lib/head_music/style/annotations/start_on_tonic.rb
182
182
  - lib/head_music/style/annotations/step_down_to_final_note.rb
183
183
  - lib/head_music/style/annotations/step_out_of_unison.rb
184
+ - lib/head_music/style/annotations/step_to_final_note.rb
184
185
  - lib/head_music/style/annotations/step_up_to_final_note.rb
185
186
  - lib/head_music/style/annotations/up_to_fourteen_notes.rb
186
187
  - lib/head_music/style/mark.rb
187
- - lib/head_music/style/rulesets/davis_lybbert_cantus_firmus.rb
188
188
  - lib/head_music/style/rulesets/first_species_harmony.rb
189
189
  - lib/head_music/style/rulesets/first_species_melody.rb
190
190
  - lib/head_music/style/rulesets/fux_cantus_firmus.rb
191
+ - lib/head_music/style/rulesets/modern_cantus_firmus.rb
191
192
  - lib/head_music/utilities/hash_key.rb
192
193
  - lib/head_music/version.rb
193
194
  - lib/head_music/voice.rb