head_music 0.19.2 → 0.20.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2261f261fb02f64ef7142d521b9ac01c1cb1e2c8
4
- data.tar.gz: de8ced9611c0b4c4db2e7e4449341095eaa82986
3
+ metadata.gz: 84558801b5df822669de2d7be0b1316dc711511a
4
+ data.tar.gz: c246dbb35d11e8b7815d56a6535420e00096c791
5
5
  SHA512:
6
- metadata.gz: 5e8b3efc74e53e4a3ab83c56c16879c974111a5da9de8abe9c2b362ddea98c96ff43df38d06e6ec110ea00133fd5a208a4b41897b10a76ab01d3799173c1d508
7
- data.tar.gz: a9765c3240a4cca996d25532d9d513fa3f4a0d0984209cbba2599fd1b7f221a6159e0ac6729e503f65861fdd0f259b9ad8bedc4f66379bbc2cbb895f2a29a97e
6
+ metadata.gz: 851820181797720920c79212516349316722dac6a4cd7889f917d2659543dbba5a39f7fce51ac8e5ed08302a1d51d7daa820e93f121bc8d3c681f1321441230e
7
+ data.tar.gz: ec6881d59cd432e3c392eeafcba2a34edc1c9d51f3842bb0832641546a86c3656c381ac0226c9865152532696e36e16644e59d7b3e54554eec6e9978c25d8c64
data/.rubocop.yml CHANGED
@@ -8,7 +8,7 @@ Metrics/BlockLength:
8
8
  - 'spec/**/*.rb'
9
9
 
10
10
  Metrics/ClassLength:
11
- Max: 120
11
+ Max: 150
12
12
 
13
13
  Metrics/LineLength:
14
14
  Max: 120
@@ -7,7 +7,7 @@ class HeadMusic::Clef
7
7
  CLEFS = [
8
8
  { pitch: 'G4', line: 2, names: ['treble', 'G-clef'], modern: true },
9
9
  { pitch: 'G4', line: 1, names: ['French', 'French violin'] },
10
- { pitch: 'G3', line: 2, names: ['tenor'], modern: true },
10
+ { pitch: 'G3', line: 2, names: ['choral tenor', 'tenor'], modern: true },
11
11
 
12
12
  { pitch: 'F3', line: 3, names: ['baritone'] },
13
13
  { pitch: 'F3', line: 4, names: ['bass', 'F-clef'], modern: true },
@@ -15,7 +15,7 @@ class HeadMusic::Clef
15
15
 
16
16
  { pitch: 'C4', line: 1, names: ['soprano'] },
17
17
  { pitch: 'C4', line: 2, names: ['mezzo-soprano'] },
18
- { pitch: 'C4', line: 3, names: ['alto', 'viola', 'counter-tenor', 'countertenor'], modern: true },
18
+ { pitch: 'C4', line: 3, names: ['alto', 'viola', 'counter-tenor', 'countertenor', 'C-clef'], modern: true },
19
19
  { pitch: 'C4', line: 4, names: ['tenor'], modern: true },
20
20
  { pitch: 'C4', line: 5, names: ['baritone'] },
21
21
 
@@ -17,7 +17,7 @@ class HeadMusic::KeySignature
17
17
  return identifier if identifier.is_a?(HeadMusic::KeySignature)
18
18
  @key_signatures ||= {}
19
19
  tonic_spelling, scale_type_name = identifier.strip.split(/\s/)
20
- hash_key = HeadMusic::Utilities::HashKey.for(identifier.gsub(/#|♯/, 'sharp').gsub(/b|♭/, 'flat'))
20
+ hash_key = HeadMusic::Utilities::HashKey.for(identifier.gsub(/#|♯/, ' sharp').gsub(/(\w)[b♭]/, '\\1 flat'))
21
21
  @key_signatures[hash_key] ||= new(tonic_spelling, scale_type_name)
22
22
  end
23
23
 
@@ -67,4 +67,50 @@ class HeadMusic::KeySignature
67
67
  def ==(other)
68
68
  signs == self.class.get(other).signs
69
69
  end
70
+
71
+ def to_s
72
+ if sharps.any?
73
+ sharps.length == 1 ? '1 sharp' : "#{sharps.length} sharps"
74
+ elsif flats.any?
75
+ flats.length == 1 ? '1 flat' : "#{flats.length} flats"
76
+ else
77
+ 'no sharps or flats'
78
+ end
79
+ end
80
+
81
+ def enharmonic_equivalent?(other)
82
+ other = KeySignature.get(other)
83
+ enharmonic_equivalence.equivalent?(other)
84
+ end
85
+
86
+ private
87
+
88
+ def enharmonic_equivalence
89
+ @enharmonic_equivalence ||= EnharmonicEquivalence.get(self)
90
+ end
91
+
92
+ # Key signatures are enharmonic when all pitch classes in one are respellings of the pitch classes in the other.
93
+ class EnharmonicEquivalence
94
+ def self.get(key_signature)
95
+ key_signature = HeadMusic::KeySignature.get(key_signature)
96
+ @enharmonic_equivalences ||= {}
97
+ @enharmonic_equivalences[key_signature.to_s] ||= new(key_signature)
98
+ end
99
+
100
+ attr_reader :key_signature
101
+
102
+ def initialize(key_signature)
103
+ @key_signature = HeadMusic::KeySignature.get(key_signature)
104
+ end
105
+
106
+ def enharmonic_equivalent?(other)
107
+ other = HeadMusic::KeySignature.get(other)
108
+ (key_signature.signs | other.signs).map(&:to_s).uniq.length == 12
109
+ end
110
+
111
+ alias enharmonic? enharmonic_equivalent?
112
+ alias equivalent? enharmonic_equivalent?
113
+
114
+ private_class_method :new
115
+ end
70
116
  end
@@ -171,7 +171,7 @@ class HeadMusic::Pitch
171
171
  @target_letter_name[num_steps] ||= letter_name.steps(num_steps)
172
172
  end
173
173
 
174
- # Enharmonic equivalence occurs when two pitches are spelled differently but refer to the same frequency, such as D and E♭.
174
+ # An enharmonic equivalent pitch is the same frequency spelled differently, such as D# and Eb.
175
175
  class EnharmonicEquivalence
176
176
  def self.get(pitch)
177
177
  pitch = HeadMusic::Pitch.get(pitch)
@@ -64,7 +64,7 @@ class HeadMusic::PitchClass
64
64
  end
65
65
 
66
66
  def white_key?
67
- [0,2,4,5,7,9,11].include?(number)
67
+ [0, 2, 4, 5, 7, 9, 11].include?(number)
68
68
  end
69
69
 
70
70
  def black_key?
@@ -9,8 +9,9 @@ class HeadMusic::Scale
9
9
  root_pitch = HeadMusic::Pitch.get(root_pitch)
10
10
  scale_type = HeadMusic::ScaleType.get(scale_type || :major)
11
11
  @scales ||= {}
12
- name = [root_pitch, scale_type].join(' ')
13
- hash_key = HeadMusic::Utilities::HashKey.for(name)
12
+ hash_key = HeadMusic::Utilities::HashKey.for(
13
+ [root_pitch, scale_type].join(' ').gsub(/#|♯/, 'sharp').gsub(/(\w)[b♭]/, '\\1flat')
14
+ )
14
15
  @scales[hash_key] ||= new(root_pitch, scale_type)
15
16
  end
16
17
 
@@ -13,7 +13,7 @@ class HeadMusic::Spelling
13
13
  delegate :number, to: :pitch_class, prefix: true
14
14
  delegate :to_i, to: :pitch_class_number
15
15
  delegate :cycle, to: :letter_name, prefix: true
16
- delegate :enharmonic?, to: :pitch_class
16
+ delegate :enharmonic?, to: :enharmonic_equivalence
17
17
 
18
18
  def self.get(identifier)
19
19
  return identifier if identifier.is_a?(HeadMusic::Spelling)
@@ -88,7 +88,13 @@ class HeadMusic::Spelling
88
88
 
89
89
  private_class_method :new
90
90
 
91
- # Enharmonic equivalence occurs when two spellings refer to the same pitch class, such as D♯ and E♭.
91
+ private
92
+
93
+ def enharmonic_equivalence
94
+ @enharmonic_equivalence ||= EnharmonicEquivalence.get(self)
95
+ end
96
+
97
+ # Enharmonic equivalence occurs when two spellings refer to the same pitch class, such as D# and Eb.
92
98
  class EnharmonicEquivalence
93
99
  def self.get(spelling)
94
100
  spelling = HeadMusic::Spelling.get(spelling)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HeadMusic
4
- VERSION = '0.19.2'
4
+ VERSION = '0.20.0'
5
5
  end
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.19.2
4
+ version: 0.20.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-05-15 00:00:00.000000000 Z
11
+ date: 2018-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport