head_music 0.18.0 → 0.19.0

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: 349efa7dc5c27c7c22b46c5d21b4e6fe9a407fc7
4
- data.tar.gz: d435a40658a1b0c5479479e1ac4877845cfd56e0
3
+ metadata.gz: 17a6cfc4f189a661c7f095056b429e32ce17468a
4
+ data.tar.gz: d3a3cc4b18e87fa0f7af9ba584b5f28946329784
5
5
  SHA512:
6
- metadata.gz: 7e689e373db60d8991b72cb6699e16ac174ee830d641b327cad7cc5ae128700f4822fc95e2926103074b281b0bf73f743e58541a1550234f1f3faf1aa6a7e9b2
7
- data.tar.gz: a6aa35cdf0166b4a9a7dcb12364c4daab304a7724d6b9d64e5133276e2c4a3975ca301dff7e5a1a90c789852420dc1728c8c71386c3ac702f0a56289f36e3914
6
+ metadata.gz: 2e9b674c4bde48f3ce71ef0768b60461f3af1ebfcfc501ab9500af24b9b61cbc071f176a43d064fba5e5d9e83f0bc53ee80ffd8d34551ea2bd2777926437f1dc
7
+ data.tar.gz: 04fb64922f6c47d6df0f0cb637ad68b188fffe448dbefe02992aa85169c6ae8993b83383bdf59118391e94c3651ea76ddb7c52c9dd7b93d266d9a0aa8a9d28f0
@@ -34,8 +34,8 @@ class HeadMusic::Chord
34
34
  end
35
35
 
36
36
  def intervals
37
- pitches.drop(1).map.with_index do |pitch, i|
38
- HeadMusic::FunctionalInterval.new(pitches[i], pitch)
37
+ pitches.each_cons(2).map do |pitch_pair|
38
+ HeadMusic::FunctionalInterval.new(*pitch_pair)
39
39
  end
40
40
  end
41
41
 
File without changes
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # A composition is a portion of music.
3
+ # A composition is musical content.
4
4
  class HeadMusic::Composition
5
5
  attr_reader :name, :key_signature, :meter, :voices
6
6
 
@@ -56,6 +56,10 @@ class HeadMusic::Composition
56
56
  voices.reject(&:cantus_firmus?).first
57
57
  end
58
58
 
59
+ def to_s
60
+ "#{name} — #{voices.count} voice(s)"
61
+ end
62
+
59
63
  private
60
64
 
61
65
  def ensure_attributes(name, key_signature, meter)
File without changes
@@ -29,25 +29,25 @@ class HeadMusic::Placement
29
29
  end
30
30
 
31
31
  def during?(other_placement)
32
- starts_during?(other_placement) || ends_during?(other_placement) || within?(other_placement)
32
+ starts_during?(other_placement) || ends_during?(other_placement) || wraps?(other_placement)
33
33
  end
34
34
 
35
35
  def to_s
36
- "#{pitch ? pitch : 'rest'} at #{position}"
36
+ "#{rhythmic_value} #{pitch ? pitch : 'rest'} at #{position}"
37
37
  end
38
38
 
39
39
  private
40
40
 
41
41
  def starts_during?(other_placement)
42
- (other_placement.next_position > position && other_placement.next_position <= next_position)
42
+ position >= other_placement.position && position < other_placement.next_position
43
43
  end
44
44
 
45
45
  def ends_during?(other_placement)
46
- (other_placement.position >= position && other_placement.position < next_position)
46
+ next_position > other_placement.position && next_position <= other_placement.next_position
47
47
  end
48
48
 
49
- def within?(other_placement)
50
- (other_placement.position <= position && other_placement.next_position >= next_position)
49
+ def wraps?(other_placement)
50
+ position <= other_placement.position && next_position >= other_placement.next_position
51
51
  end
52
52
 
53
53
  def ensure_attributes(voice, position, rhythmic_value, pitch)
@@ -95,7 +95,7 @@ end
95
95
 
96
96
  # In Logic Pro X, the 'beat' is determined by the denominator, even if compound.
97
97
  # Logic then divides the beat into 'divisions' that are a sixteenth in length.
98
- # Each division is then divided into 240 ticks (960 PPQN / 4 sixteenths-per-quarter)
98
+ # Each division is then divided into 240 ticks (960 PPQN / 4 sixteenths-per-quarter = 240 ticks per sixteenth note)
99
99
 
100
100
  # Tempo specifies the beat unit, usually the traditional beat unit in the case of compound meters,
101
101
  # so 6/8 would specify [dotted-quarter] = 132 (or whatever).
@@ -96,4 +96,8 @@ class HeadMusic::RhythmicValue
96
96
  def ==(other)
97
97
  to_s == other.to_s
98
98
  end
99
+
100
+ def to_s
101
+ name.tr('_', '-')
102
+ end
99
103
  end
@@ -59,9 +59,7 @@ class HeadMusic::Voice
59
59
 
60
60
  def melodic_intervals
61
61
  @melodic_intervals ||=
62
- notes.map.with_index do |note, i|
63
- HeadMusic::MelodicInterval.new(notes[i - 1], note) if i.positive?
64
- end.compact
62
+ notes.each_cons(2).map { |note_pair| HeadMusic::MelodicInterval.new(*note_pair) }
65
63
  end
66
64
 
67
65
  def leaps
@@ -102,6 +100,10 @@ class HeadMusic::Voice
102
100
  placements.last.position.bar_number
103
101
  end
104
102
 
103
+ def to_s
104
+ "#{role}: #{pitches.first(10).map(&:to_s)}"
105
+ end
106
+
105
107
  private
106
108
 
107
109
  def insert_into_placements(placement)
@@ -54,7 +54,7 @@ class HeadMusic::KeySignature
54
54
  end
55
55
 
56
56
  def signs
57
- !flats.empty? ? flats : sharps
57
+ flats.any? ? flats : sharps
58
58
  end
59
59
 
60
60
  def name
@@ -61,9 +61,9 @@ class HeadMusic::Scale
61
61
  end
62
62
 
63
63
  def octave_scale_pitches(direction, semitones_from_root)
64
- direction_intervals(direction).map.with_index do |semitones, i|
64
+ direction_intervals(direction).map.with_index(1) do |semitones, i|
65
65
  semitones_from_root += semitones * direction_sign(direction)
66
- pitch_for_step(i + 1, semitones_from_root, direction)
66
+ pitch_for_step(i, semitones_from_root, direction)
67
67
  end
68
68
  end
69
69
 
@@ -101,10 +101,9 @@ class HeadMusic::Style::Annotation
101
101
  end
102
102
 
103
103
  def motions
104
- downbeat_harmonic_intervals.map.with_index do |harmonic_interval, i|
105
- next_harmonic_interval = downbeat_harmonic_intervals[i + 1]
106
- HeadMusic::Motion.new(harmonic_interval, next_harmonic_interval) if next_harmonic_interval
107
- end.compact
104
+ downbeat_harmonic_intervals.each_cons(2).map do |harmonic_interval_pair|
105
+ HeadMusic::Motion.new(*harmonic_interval_pair)
106
+ end
108
107
  end
109
108
 
110
109
  def downbeat_harmonic_intervals
@@ -8,8 +8,8 @@ class HeadMusic::Style::Annotations::AlwaysMove < HeadMusic::Style::Annotation
8
8
  MESSAGE = 'Always move to a different note.'
9
9
 
10
10
  def marks
11
- melodic_intervals.map.with_index do |interval, i|
12
- HeadMusic::Style::Mark.for_all(notes[i..i + 1]) if interval.shorthand == 'PU'
13
- end.compact
11
+ melodic_intervals.
12
+ select { |interval| interval.perfect? && interval.unison? }.
13
+ map { |interval| HeadMusic::Style::Mark.for_all(interval.notes) }
14
14
  end
15
15
  end
@@ -23,9 +23,8 @@ class HeadMusic::Style::Annotations::DirectionChanges < HeadMusic::Style::Annota
23
23
  end
24
24
 
25
25
  def melodic_intervals_changing_direction
26
- melodic_intervals.drop(1).select.with_index do |interval, i|
27
- previous_direction = melodic_intervals[i].direction
28
- interval.direction != previous_direction
26
+ melodic_intervals.each_cons(2).reject do |interval_pair|
27
+ interval_pair[0].direction == interval_pair[1].direction
29
28
  end
30
29
  end
31
30
  end
@@ -8,7 +8,7 @@ class HeadMusic::Style::Annotations::EndOnTonic < HeadMusic::Style::Annotation
8
8
  MESSAGE = 'End on the first scale degree.'
9
9
 
10
10
  def marks
11
- HeadMusic::Style::Mark.for(notes.last) if !notes.empty? && !ends_on_tonic?
11
+ HeadMusic::Style::Mark.for(notes.last) if notes.any? && !ends_on_tonic?
12
12
  end
13
13
 
14
14
  private
@@ -18,9 +18,9 @@ class HeadMusic::Style::Annotations::MostlyConjunct < HeadMusic::Style::Annotati
18
18
  private
19
19
 
20
20
  def marks_for_skips_and_leaps
21
- melodic_intervals.map.with_index do |interval, i|
22
- HeadMusic::Style::Mark.for_all(notes[i..i + 1], fitness: HeadMusic::SMALL_PENALTY_FACTOR) unless interval.step?
23
- end.compact
21
+ melodic_intervals.
22
+ reject(&:step?).
23
+ map { |interval| HeadMusic::Style::Mark.for_all(interval.notes, fitness: HeadMusic::SMALL_PENALTY_FACTOR) }
24
24
  end
25
25
 
26
26
  def conjunct_ratio
@@ -16,7 +16,7 @@ class HeadMusic::Style::Annotations::SingableRange < HeadMusic::Style::Annotatio
16
16
  private
17
17
 
18
18
  def overage
19
- !notes.empty? ? [range.number - MAXIMUM_RANGE, 0].max : 0
19
+ notes.any? ? [range.number - MAXIMUM_RANGE, 0].max : 0
20
20
  end
21
21
 
22
22
  def extremes
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HeadMusic
4
- VERSION = '0.18.0'
4
+ VERSION = '0.19.0'
5
5
  end
data/lib/head_music.rb CHANGED
@@ -20,11 +20,9 @@ require 'head_music/utilities/hash_key'
20
20
  require 'head_music/named_rudiment'
21
21
 
22
22
  # rudiments
23
- require 'head_music/bar'
24
23
  require 'head_music/chord'
25
24
  require 'head_music/circle'
26
25
  require 'head_music/clef'
27
- require 'head_music/composition'
28
26
  require 'head_music/consonance'
29
27
  require 'head_music/functional_interval'
30
28
  require 'head_music/grand_staff'
@@ -32,28 +30,31 @@ require 'head_music/harmonic_interval'
32
30
  require 'head_music/instrument'
33
31
  require 'head_music/interval'
34
32
  require 'head_music/key_signature'
35
- require 'head_music/language'
36
33
  require 'head_music/letter_name'
37
34
  require 'head_music/melodic_interval'
38
35
  require 'head_music/meter'
39
36
  require 'head_music/motion'
40
- require 'head_music/note'
41
37
  require 'head_music/octave'
42
38
  require 'head_music/pitch'
43
39
  require 'head_music/pitch_class'
44
- require 'head_music/placement'
45
- require 'head_music/position'
46
40
  require 'head_music/quality'
47
41
  require 'head_music/rhythm'
48
42
  require 'head_music/rhythmic_unit'
49
- require 'head_music/rhythmic_value'
50
43
  require 'head_music/scale'
51
44
  require 'head_music/scale_degree'
52
45
  require 'head_music/scale_type'
53
46
  require 'head_music/sign'
54
47
  require 'head_music/spelling'
55
48
  require 'head_music/staff'
56
- require 'head_music/voice'
49
+
50
+ # content
51
+ require 'head_music/content/bar'
52
+ require 'head_music/content/composition'
53
+ require 'head_music/content/note'
54
+ require 'head_music/content/placement'
55
+ require 'head_music/content/position'
56
+ require 'head_music/content/rhythmic_value'
57
+ require 'head_music/content/voice'
57
58
 
58
59
  # analysis
59
60
  require 'head_music/style/analysis'
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.18.0
4
+ version: 0.19.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: 2018-02-24 00:00:00.000000000 Z
11
+ date: 2018-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -116,34 +116,34 @@ files:
116
116
  - circle.yml
117
117
  - head_music.gemspec
118
118
  - lib/head_music.rb
119
- - lib/head_music/bar.rb
120
119
  - lib/head_music/chord.rb
121
120
  - lib/head_music/circle.rb
122
121
  - lib/head_music/clef.rb
123
- - lib/head_music/composition.rb
124
122
  - lib/head_music/consonance.rb
123
+ - lib/head_music/content/bar.rb
124
+ - lib/head_music/content/composition.rb
125
+ - lib/head_music/content/note.rb
126
+ - lib/head_music/content/placement.rb
127
+ - lib/head_music/content/position.rb
128
+ - lib/head_music/content/rhythmic_value.rb
129
+ - lib/head_music/content/voice.rb
125
130
  - lib/head_music/functional_interval.rb
126
131
  - lib/head_music/grand_staff.rb
127
132
  - lib/head_music/harmonic_interval.rb
128
133
  - lib/head_music/instrument.rb
129
134
  - lib/head_music/interval.rb
130
135
  - lib/head_music/key_signature.rb
131
- - lib/head_music/language.rb
132
136
  - lib/head_music/letter_name.rb
133
137
  - lib/head_music/melodic_interval.rb
134
138
  - lib/head_music/meter.rb
135
139
  - lib/head_music/motion.rb
136
140
  - lib/head_music/named_rudiment.rb
137
- - lib/head_music/note.rb
138
141
  - lib/head_music/octave.rb
139
142
  - lib/head_music/pitch.rb
140
143
  - lib/head_music/pitch_class.rb
141
- - lib/head_music/placement.rb
142
- - lib/head_music/position.rb
143
144
  - lib/head_music/quality.rb
144
145
  - lib/head_music/rhythm.rb
145
146
  - lib/head_music/rhythmic_unit.rb
146
- - lib/head_music/rhythmic_value.rb
147
147
  - lib/head_music/scale.rb
148
148
  - lib/head_music/scale_degree.rb
149
149
  - lib/head_music/scale_type.rb
@@ -192,7 +192,6 @@ files:
192
192
  - lib/head_music/style/rulesets/modern_cantus_firmus.rb
193
193
  - lib/head_music/utilities/hash_key.rb
194
194
  - lib/head_music/version.rb
195
- - lib/head_music/voice.rb
196
195
  homepage: https://github.com/roberthead/head_music
197
196
  licenses:
198
197
  - MIT
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # A language.
4
- class HeadMusic::Language
5
- include Comparable
6
- include HeadMusic::NamedRudiment
7
-
8
- LANGUAGES = [
9
- { name: 'American English', short_name: 'English', abbreviation: 'en-US' },
10
- { name: 'British English', abbreviation: 'en-GB' },
11
- { name: 'French', native_name: 'Français', abbreviation: 'fr' },
12
- { name: 'German', native_name: 'Deutsche', abbreviation: 'de' },
13
- { name: 'Italian', native_name: 'Italiano', abbreviation: 'it' },
14
- { name: 'Spanish', native_name: 'Español', abbreviation: 'es' },
15
- { name: 'Russian', native_name: 'русский', abbreviation: 'ru' },
16
- ].freeze
17
-
18
- LANGUAGES.
19
- map { |language| ::HeadMusic::Utilities::HashKey.for(language[:name]) }.
20
- each { |language_key| define_singleton_method(language_key) { HeadMusic::Language.get(language_key) } }
21
-
22
- LANGUAGES.
23
- map { |language| ::HeadMusic::Utilities::HashKey.for(language[:native_name]) }.
24
- reject(&:nil?).
25
- each { |language_key| define_singleton_method(language_key) { HeadMusic::Language.get(language_key) } }
26
-
27
- LANGUAGES.
28
- map { |language| ::HeadMusic::Utilities::HashKey.for(language[:short_name]) }.
29
- reject(&:nil?).
30
- each { |language_key| define_singleton_method(language_key) { HeadMusic::Language.get(language_key) } }
31
-
32
- def self.default
33
- english
34
- end
35
-
36
- def self.get(name)
37
- get_by_name(name) || default
38
- end
39
-
40
- attr_accessor :name, :native_name, :short_name
41
-
42
- def initialize(identifier)
43
- identifier_key = HeadMusic::Utilities::HashKey.for(identifier)
44
- language_data = LANGUAGES.detect do |data|
45
- %i[name native_name short_name].
46
- map { |key| HeadMusic::Utilities::HashKey.for(data[key]) }.
47
- include?(identifier_key)
48
- end
49
- @name = language_data[:name]
50
- @native_name = language_data[:native_name]
51
- @short_name = language_data[:short_name]
52
- end
53
-
54
- def <=>(other)
55
- name.to_s <=> other.to_s
56
- end
57
-
58
- def inspect
59
- [name, native_name, short_name].reject(&:nil?).join(' / ')
60
- end
61
- end