head_music 0.19.2 → 0.20.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: 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