head_music 0.16.0 → 0.16.2

Sign up to get free protection for your applications and to get access to all the features.
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