head_music 0.11.9 → 0.13.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/head_music/bar.rb +9 -7
  4. data/lib/head_music/clef.rb +4 -6
  5. data/lib/head_music/composition.rb +40 -9
  6. data/lib/head_music/functional_interval.rb +34 -40
  7. data/lib/head_music/harmonic_interval.rb +49 -0
  8. data/lib/head_music/instrument.rb +3 -10
  9. data/lib/head_music/melodic_interval.rb +36 -1
  10. data/lib/head_music/meter.rb +33 -17
  11. data/lib/head_music/motion.rb +70 -0
  12. data/lib/head_music/named_rudiment.rb +27 -0
  13. data/lib/head_music/placement.rb +7 -1
  14. data/lib/head_music/position.rb +10 -5
  15. data/lib/head_music/rhythmic_unit.rb +21 -10
  16. data/lib/head_music/spelling.rb +1 -1
  17. data/lib/head_music/style/analysis.rb +12 -1
  18. data/lib/head_music/style/annotation.rb +72 -1
  19. data/lib/head_music/style/annotations/always_move.rb +1 -3
  20. data/lib/head_music/style/annotations/approach_perfection_contrarily.rb +24 -0
  21. data/lib/head_music/style/annotations/at_least_eight_notes.rb +5 -8
  22. data/lib/head_music/style/annotations/avoid_crossing_voices.rb +40 -0
  23. data/lib/head_music/style/annotations/avoid_overlapping_voices.rb +42 -0
  24. data/lib/head_music/style/annotations/consonant_climax.rb +3 -5
  25. data/lib/head_music/style/annotations/consonant_downbeats.rb +22 -0
  26. data/lib/head_music/style/annotations/diatonic.rb +1 -3
  27. data/lib/head_music/style/annotations/direction_changes.rb +1 -3
  28. data/lib/head_music/style/annotations/end_on_perfect_consonance.rb +2 -12
  29. data/lib/head_music/style/annotations/end_on_tonic.rb +6 -8
  30. data/lib/head_music/style/annotations/limit_octave_leaps.rb +20 -0
  31. data/lib/head_music/style/annotations/mostly_conjunct.rb +1 -3
  32. data/lib/head_music/style/annotations/no_rests.rb +2 -4
  33. data/lib/head_music/style/annotations/no_unisons_in_middle.rb +39 -0
  34. data/lib/head_music/style/annotations/notes_same_length.rb +1 -3
  35. data/lib/head_music/style/annotations/one_to_one.rb +3 -13
  36. data/lib/head_music/style/annotations/prefer_contrary_motion.rb +23 -0
  37. data/lib/head_music/style/annotations/prefer_imperfect.rb +23 -0
  38. data/lib/head_music/style/annotations/recover_large_leaps.rb +2 -4
  39. data/lib/head_music/style/annotations/singable_intervals.rb +1 -3
  40. data/lib/head_music/style/annotations/{limit_range.rb → singable_range.rb} +2 -4
  41. data/lib/head_music/style/annotations/start_on_perfect_consonance.rb +3 -13
  42. data/lib/head_music/style/annotations/start_on_tonic.rb +1 -11
  43. data/lib/head_music/style/annotations/step_down_to_final_note.rb +1 -3
  44. data/lib/head_music/style/annotations/step_out_of_unison.rb +38 -0
  45. data/lib/head_music/style/annotations/step_up_to_final_note.rb +1 -3
  46. data/lib/head_music/style/annotations/up_to_thirteen_notes.rb +2 -4
  47. data/lib/head_music/style/rulesets/cantus_firmus.rb +2 -2
  48. data/lib/head_music/style/rulesets/first_species_harmony.rb +8 -1
  49. data/lib/head_music/style/rulesets/first_species_melody.rb +10 -2
  50. data/lib/head_music/version.rb +1 -1
  51. data/lib/head_music/voice.rb +31 -1
  52. data/lib/head_music.rb +14 -1
  53. metadata +15 -3
@@ -2,21 +2,11 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::StartOnTonic < HeadMusic::Style::Annotation
5
- def message
6
- 'Start on the tonic.'
7
- end
5
+ MESSAGE = 'Start on the tonic.'
8
6
 
9
7
  def marks
10
8
  if first_note && !starts_on_tonic?
11
9
  HeadMusic::Style::Mark.for(first_note)
12
10
  end
13
11
  end
14
-
15
- def starts_on_tonic?
16
- composition.key_signature.tonic_spelling == first_note.spelling
17
- end
18
-
19
- def first_note
20
- notes.first
21
- end
22
12
  end
@@ -2,9 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::StepDownToFinalNote < HeadMusic::Style::Annotation
5
- def message
6
- 'Step down to final note.'
7
- end
5
+ MESSAGE = 'Step down to final note.'
8
6
 
9
7
  def marks
10
8
  if !last_melodic_interval.nil?
@@ -0,0 +1,38 @@
1
+ module HeadMusic::Style::Annotations
2
+ end
3
+
4
+ class HeadMusic::Style::Annotations::StepOutOfUnison < HeadMusic::Style::Annotation
5
+ MESSAGE = "Exit a unison by step."
6
+
7
+ def marks
8
+ skips_following_unisons.map do |skip|
9
+ HeadMusic::Style::Mark.for_all(skip.notes)
10
+ end.flatten
11
+ end
12
+
13
+ private
14
+
15
+ def skips_following_unisons
16
+ melodic_intervals_following_unisons.select(&:skip?)
17
+ end
18
+
19
+ def melodic_intervals_following_unisons
20
+ unisons.map do |unison|
21
+ note1 = voice.note_at(unison.position)
22
+ note2 = voice.note_following(unison.position)
23
+ MelodicInterval.new(voice, note1, note2) if note2
24
+ end.reject(&:nil?)
25
+ end
26
+
27
+ def unisons
28
+ harmonic_intervals.select { |interval| interval.perfect_consonance? && interval.unison? }
29
+ end
30
+
31
+ def harmonic_intervals
32
+ positions.map { |position| HarmonicInterval.new(cantus_firmus, voice, position) }
33
+ end
34
+
35
+ def positions
36
+ voices.map(&:notes).flatten.map(&:position).sort.uniq(&:to_s)
37
+ end
38
+ end
@@ -2,9 +2,7 @@ module HeadMusic::Style::Annotations
2
2
  end
3
3
 
4
4
  class HeadMusic::Style::Annotations::StepUpToFinalNote < HeadMusic::Style::Annotation
5
- def message
6
- 'Step up to final note.'
7
- end
5
+ MESSAGE = 'Step up to final note.'
8
6
 
9
7
  def marks
10
8
  if !last_melodic_interval.nil?
@@ -4,13 +4,11 @@ end
4
4
  class HeadMusic::Style::Annotations::UpToThirteenNotes < HeadMusic::Style::Annotation
5
5
  MAXIMUM_NOTES = 13
6
6
 
7
- def message
8
- 'Write up to thirteen notes.'
9
- end
7
+ MESSAGE = 'Write up to thirteen notes.'
10
8
 
11
9
  def marks
12
10
  if overage > 0
13
- HeadMusic::Style::Mark.for_all(notes[13..-1])
11
+ HeadMusic::Style::Mark.for_each(notes[13..-1])
14
12
  end
15
13
  end
16
14
 
@@ -9,12 +9,12 @@ class HeadMusic::Style::Rulesets::CantusFirmus
9
9
  HeadMusic::Style::Annotations::Diatonic,
10
10
  HeadMusic::Style::Annotations::DirectionChanges,
11
11
  HeadMusic::Style::Annotations::EndOnTonic,
12
- HeadMusic::Style::Annotations::LimitRange,
13
12
  HeadMusic::Style::Annotations::MostlyConjunct,
14
13
  HeadMusic::Style::Annotations::NoRests,
15
14
  HeadMusic::Style::Annotations::NotesSameLength,
16
- HeadMusic::Style::Annotations::SingableIntervals,
17
15
  HeadMusic::Style::Annotations::RecoverLargeLeaps,
16
+ HeadMusic::Style::Annotations::SingableIntervals,
17
+ HeadMusic::Style::Annotations::SingableRange,
18
18
  HeadMusic::Style::Annotations::StartOnTonic,
19
19
  HeadMusic::Style::Annotations::StepDownToFinalNote,
20
20
  HeadMusic::Style::Annotations::UpToThirteenNotes,
@@ -3,7 +3,14 @@ end
3
3
 
4
4
  class HeadMusic::Style::Rulesets::FirstSpeciesHarmony
5
5
  RULESET = [
6
- # HeadMusic::Style::Annotations::ConsonantOnStrongBeats,
6
+ HeadMusic::Style::Annotations::ApproachPerfectionContrarily,
7
+ HeadMusic::Style::Annotations::AvoidCrossingVoices,
8
+ HeadMusic::Style::Annotations::AvoidOverlappingVoices,
9
+ HeadMusic::Style::Annotations::ConsonantDownbeats,
10
+ HeadMusic::Style::Annotations::PreferContraryMotion,
11
+ HeadMusic::Style::Annotations::PreferImperfect,
12
+ HeadMusic::Style::Annotations::NoUnisonsInMiddle,
13
+ HeadMusic::Style::Annotations::OneToOne,
7
14
  ]
8
15
 
9
16
  def self.analyze(voice)
@@ -3,11 +3,19 @@ end
3
3
 
4
4
  class HeadMusic::Style::Rulesets::FirstSpeciesMelody
5
5
  RULESET = [
6
- HeadMusic::Style::Annotations::OneToOne,
6
+ HeadMusic::Style::Annotations::AlwaysMove,
7
+ HeadMusic::Style::Annotations::Diatonic,
8
+ HeadMusic::Style::Annotations::DirectionChanges,
9
+ HeadMusic::Style::Annotations::EndOnTonic,
10
+ HeadMusic::Style::Annotations::LimitOctaveLeaps,
11
+ HeadMusic::Style::Annotations::MostlyConjunct,
12
+ HeadMusic::Style::Annotations::NoRests,
7
13
  HeadMusic::Style::Annotations::NotesSameLength,
14
+ HeadMusic::Style::Annotations::RecoverLargeLeaps,
8
15
  HeadMusic::Style::Annotations::SingableIntervals,
16
+ HeadMusic::Style::Annotations::SingableRange,
9
17
  HeadMusic::Style::Annotations::StartOnPerfectConsonance,
10
- HeadMusic::Style::Annotations::EndOnPerfectConsonance,
18
+ HeadMusic::Style::Annotations::StepOutOfUnison,
11
19
  HeadMusic::Style::Annotations::StepUpToFinalNote,
12
20
  ]
13
21
 
@@ -1,3 +1,3 @@
1
1
  module HeadMusic
2
- VERSION = "0.11.9"
2
+ VERSION = "0.13.2"
3
3
  end
@@ -63,8 +63,38 @@ class HeadMusic::Voice
63
63
  melodic_intervals.select(&:leap?)
64
64
  end
65
65
 
66
+ def large_leaps
67
+ melodic_intervals.select(&:large_leap?)
68
+ end
69
+
66
70
  def cantus_firmus?
67
- role && role =~ /cantus.?firmus/i
71
+ role.to_s =~ /cantus.?firmus/i
72
+ end
73
+
74
+ def note_at(position)
75
+ notes.detect { |note| position.within_placement?(note) }
76
+ end
77
+
78
+ def notes_during(placement)
79
+ notes.select { |note| note.during?(placement) }
80
+ end
81
+
82
+ def note_preceding(position)
83
+ notes.select { |note| note.position < position }.last
84
+ end
85
+
86
+ def note_following(position)
87
+ notes.detect { |note| note.position > position }
88
+ end
89
+
90
+ def earliest_bar_number
91
+ return 1 if notes.empty?
92
+ placements.first.position.bar_number
93
+ end
94
+
95
+ def latest_bar_number
96
+ return 1 if notes.empty?
97
+ placements.last.position.bar_number
68
98
  end
69
99
 
70
100
  private
data/lib/head_music.rb CHANGED
@@ -4,6 +4,8 @@ require 'active_support/core_ext/module/delegation'
4
4
  require 'active_support/core_ext/string/access'
5
5
  require 'humanize'
6
6
 
7
+ require 'head_music/named_rudiment'
8
+
7
9
  require 'head_music/accidental'
8
10
  require 'head_music/bar'
9
11
  require 'head_music/chord'
@@ -13,12 +15,14 @@ require 'head_music/composition'
13
15
  require 'head_music/consonance'
14
16
  require 'head_music/functional_interval'
15
17
  require 'head_music/grand_staff'
18
+ require 'head_music/harmonic_interval'
16
19
  require 'head_music/instrument'
17
20
  require 'head_music/interval'
18
21
  require 'head_music/key_signature'
19
22
  require 'head_music/letter_name'
20
23
  require 'head_music/melodic_interval'
21
24
  require 'head_music/meter'
25
+ require 'head_music/motion'
22
26
  require 'head_music/note'
23
27
  require 'head_music/octave'
24
28
  require 'head_music/pitch'
@@ -39,22 +43,31 @@ require 'head_music/style/annotation'
39
43
  require 'head_music/style/mark'
40
44
 
41
45
  require 'head_music/style/annotations/always_move'
46
+ require 'head_music/style/annotations/approach_perfection_contrarily'
42
47
  require 'head_music/style/annotations/at_least_eight_notes'
48
+ require 'head_music/style/annotations/avoid_crossing_voices'
49
+ require 'head_music/style/annotations/avoid_overlapping_voices'
43
50
  require 'head_music/style/annotations/consonant_climax'
51
+ require 'head_music/style/annotations/consonant_downbeats'
44
52
  require 'head_music/style/annotations/diatonic'
45
53
  require 'head_music/style/annotations/direction_changes'
46
54
  require 'head_music/style/annotations/end_on_perfect_consonance'
47
55
  require 'head_music/style/annotations/end_on_tonic'
48
- require 'head_music/style/annotations/limit_range'
56
+ require 'head_music/style/annotations/limit_octave_leaps'
49
57
  require 'head_music/style/annotations/mostly_conjunct'
50
58
  require 'head_music/style/annotations/no_rests'
59
+ require 'head_music/style/annotations/no_unisons_in_middle'
51
60
  require 'head_music/style/annotations/notes_same_length'
52
61
  require 'head_music/style/annotations/one_to_one'
62
+ require 'head_music/style/annotations/prefer_contrary_motion'
63
+ require 'head_music/style/annotations/prefer_imperfect'
53
64
  require 'head_music/style/annotations/recover_large_leaps'
54
65
  require 'head_music/style/annotations/singable_intervals'
66
+ require 'head_music/style/annotations/singable_range'
55
67
  require 'head_music/style/annotations/start_on_perfect_consonance'
56
68
  require 'head_music/style/annotations/start_on_tonic'
57
69
  require 'head_music/style/annotations/step_down_to_final_note'
70
+ require 'head_music/style/annotations/step_out_of_unison'
58
71
  require 'head_music/style/annotations/step_up_to_final_note'
59
72
  require 'head_music/style/annotations/up_to_thirteen_notes'
60
73
 
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.11.9
4
+ version: 0.13.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-03 00:00:00.000000000 Z
11
+ date: 2017-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -125,12 +125,15 @@ files:
125
125
  - lib/head_music/consonance.rb
126
126
  - lib/head_music/functional_interval.rb
127
127
  - lib/head_music/grand_staff.rb
128
+ - lib/head_music/harmonic_interval.rb
128
129
  - lib/head_music/instrument.rb
129
130
  - lib/head_music/interval.rb
130
131
  - lib/head_music/key_signature.rb
131
132
  - lib/head_music/letter_name.rb
132
133
  - lib/head_music/melodic_interval.rb
133
134
  - lib/head_music/meter.rb
135
+ - lib/head_music/motion.rb
136
+ - lib/head_music/named_rudiment.rb
134
137
  - lib/head_music/note.rb
135
138
  - lib/head_music/octave.rb
136
139
  - lib/head_music/pitch.rb
@@ -148,22 +151,31 @@ files:
148
151
  - lib/head_music/style/analysis.rb
149
152
  - lib/head_music/style/annotation.rb
150
153
  - lib/head_music/style/annotations/always_move.rb
154
+ - lib/head_music/style/annotations/approach_perfection_contrarily.rb
151
155
  - lib/head_music/style/annotations/at_least_eight_notes.rb
156
+ - lib/head_music/style/annotations/avoid_crossing_voices.rb
157
+ - lib/head_music/style/annotations/avoid_overlapping_voices.rb
152
158
  - lib/head_music/style/annotations/consonant_climax.rb
159
+ - lib/head_music/style/annotations/consonant_downbeats.rb
153
160
  - lib/head_music/style/annotations/diatonic.rb
154
161
  - lib/head_music/style/annotations/direction_changes.rb
155
162
  - lib/head_music/style/annotations/end_on_perfect_consonance.rb
156
163
  - lib/head_music/style/annotations/end_on_tonic.rb
157
- - lib/head_music/style/annotations/limit_range.rb
164
+ - lib/head_music/style/annotations/limit_octave_leaps.rb
158
165
  - lib/head_music/style/annotations/mostly_conjunct.rb
159
166
  - lib/head_music/style/annotations/no_rests.rb
167
+ - lib/head_music/style/annotations/no_unisons_in_middle.rb
160
168
  - lib/head_music/style/annotations/notes_same_length.rb
161
169
  - lib/head_music/style/annotations/one_to_one.rb
170
+ - lib/head_music/style/annotations/prefer_contrary_motion.rb
171
+ - lib/head_music/style/annotations/prefer_imperfect.rb
162
172
  - lib/head_music/style/annotations/recover_large_leaps.rb
163
173
  - lib/head_music/style/annotations/singable_intervals.rb
174
+ - lib/head_music/style/annotations/singable_range.rb
164
175
  - lib/head_music/style/annotations/start_on_perfect_consonance.rb
165
176
  - lib/head_music/style/annotations/start_on_tonic.rb
166
177
  - lib/head_music/style/annotations/step_down_to_final_note.rb
178
+ - lib/head_music/style/annotations/step_out_of_unison.rb
167
179
  - lib/head_music/style/annotations/step_up_to_final_note.rb
168
180
  - lib/head_music/style/annotations/up_to_thirteen_notes.rb
169
181
  - lib/head_music/style/mark.rb