head_music 0.1.0 → 0.1.1

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: 180ffc27218ca1ef9eacf64c6d93aff2ab81fc49
4
- data.tar.gz: 76e58d1d8ed78ca58ebe899bedfed0756d7104fc
3
+ metadata.gz: 161df8f1795f4e70adcdc8d7298cdbf1dd2af984
4
+ data.tar.gz: 621aac81ec102840a879186df55eb9aeed040b8b
5
5
  SHA512:
6
- metadata.gz: 730ecdb5ebfadc4cc18c2776b3413a74c31629249e20376ad27928a762347b89ec32392fa4dc441bcd84724e41208915874cfbdacd3b75119c2910638339ba47
7
- data.tar.gz: 1f5ed8080b5584f26702fe7f257459975923ddff48be3239050e721837f65abe3e3f8863dd865e39b2161900b1fd924eec03d2c6337860d7d27bbde69f10537e
6
+ metadata.gz: 947631876b0c2c74a807515783a22783836838d75d2a21eab2f66e8863a5b25d5849e92874885007a99dd0596acacb5c795ad0ffc153d47cac616322ec566fef
7
+ data.tar.gz: 9ff5a2e01209ccd7f515d9d152f49159a0f18518f7bfb17e289609cb519395b96e7ae4399dd321346b3b971f05ae970d2095fb4556ca1bb666b36d268f46fe2c
@@ -8,9 +8,13 @@ class HeadMusic::Accidental
8
8
 
9
9
  attr_reader :string
10
10
 
11
- def self.get(string)
11
+ def self.get(identifier)
12
12
  @accidentals ||= {}
13
- @accidentals[string] ||= new(string)
13
+ @accidentals[identifier] ||= for_symbol(identifier) || for_interval(identifier)
14
+ end
15
+
16
+ def self.for_symbol(identifier)
17
+ new(identifier) if ACCIDENTAL_SEMITONES.keys.include?(identifier)
14
18
  end
15
19
 
16
20
  def self.for_interval(semitones)
@@ -19,6 +19,10 @@ class HeadMusic::Circle
19
19
  @pitch_classes = pitch_classes_by_interval(interval)
20
20
  end
21
21
 
22
+ def index(pitch_class)
23
+ @pitch_classes.index(HeadMusic::Spelling.get(pitch_class).pitch_class)
24
+ end
25
+
22
26
  private_class_method :new
23
27
 
24
28
  private
@@ -21,11 +21,17 @@ class HeadMusic::KeySignature
21
21
  end
22
22
 
23
23
  def num_sharps
24
- (HeadMusic::Circle.of_fifths.pitch_classes.index(tonic_pitch_class) - scale_type_adjustment) % 12
24
+ (HeadMusic::Circle.of_fifths.index(tonic_pitch_class) - scale_type_adjustment) % 12
25
25
  end
26
26
 
27
27
  def num_flats
28
- (HeadMusic::Circle.of_fourths.pitch_classes.index(tonic_pitch_class) + scale_type_adjustment) % 12
28
+ (HeadMusic::Circle.of_fourths.index(tonic_pitch_class) + scale_type_adjustment) % 12
29
+ end
30
+
31
+ def sharps_or_flats
32
+ return sharps if @tonic_spelling.to_s =~ /#/
33
+ return flats if @tonic_spelling.to_s =~ /b/
34
+ num_sharps <= num_flats ? sharps : flats
29
35
  end
30
36
 
31
37
  private
@@ -33,4 +39,17 @@ class HeadMusic::KeySignature
33
39
  def scale_type_adjustment
34
40
  scale_type == :minor ? 3 : 0
35
41
  end
42
+
43
+ def major?
44
+ @scale_type.to_sym == :major
45
+ end
46
+
47
+ def minor?
48
+ @scale_type.to_sym == :minor
49
+ end
50
+
51
+ def relative_major_pitch_class
52
+ return tonic_pitch_class if major?
53
+ return (tonic_pitch_class.to_i + 3) % 12 if minor?
54
+ end
36
55
  end
@@ -17,23 +17,23 @@ class HeadMusic::Letter
17
17
  NAMES.map { |letter_name| get(letter_name)}
18
18
  end
19
19
 
20
- def self.get(name)
20
+ def self.get(identifier)
21
21
  @letters ||= {}
22
+ @letters[identifier] ||= from_name(identifier) || from_pitch_class(identifier)
23
+ end
24
+
25
+ def self.from_name(name)
22
26
  name = name.to_s.first.upcase
23
- if NAMES.include?(name)
24
- @letters[name] ||= new(name)
25
- end
27
+ new(name) if NAMES.include?(name)
26
28
  end
27
29
 
28
30
  def self.from_pitch_class(pitch_class)
29
31
  @letters ||= {}
32
+ return nil if pitch_class.to_s == pitch_class
30
33
  pitch_class = pitch_class.to_i % 12
31
- name =
32
- NAMES.detect { |name| pitch_class == NATURAL_PITCH_CLASS_NUMBERS[name] } ||
33
- NAMES.detect { |name| pitch_class == NATURAL_PITCH_CLASS_NUMBERS[name]+1 }
34
- if NAMES.include?(name)
35
- @letters[name] ||= new(name)
36
- end
34
+ name = NAMES.detect { |name| pitch_class == NATURAL_PITCH_CLASS_NUMBERS[name] }
35
+ name ||= HeadMusic::PitchClass::PREFERRED_SPELLINGS[pitch_class].first
36
+ return new(name) if NAMES.include?(name)
37
37
  end
38
38
 
39
39
  attr_reader :name
@@ -1,6 +1,8 @@
1
1
  class HeadMusic::PitchClass
2
2
  attr_reader :number
3
3
 
4
+ PREFERRED_SPELLINGS = %w[C C# D Eb E F F# G Ab A Bb B]
5
+
4
6
  def self.get(number)
5
7
  @pitch_classes ||= {}
6
8
  number = number.to_i % 12
@@ -5,7 +5,7 @@ class HeadMusic::Spelling
5
5
  attr_reader :accidental
6
6
  attr_reader :pitch_class
7
7
 
8
- SPELLING_MATCHER = /([A-G])([b#]*)(\-?\d+)?/
8
+ SPELLING_MATCHER = /^\s*([A-G])([b#]*)(\-?\d+)?\s*$/
9
9
 
10
10
  def self.get(identifier)
11
11
  @spellings ||= {}
@@ -14,19 +14,17 @@ class HeadMusic::Spelling
14
14
 
15
15
  def self.from_name(name)
16
16
  return nil unless name == name.to_s
17
- match = name.match(SPELLING_MATCHER)
17
+ match = name.to_s.match(SPELLING_MATCHER)
18
18
  if match
19
19
  letter_name, accidental_string, _octave = match.captures
20
20
  letter = HeadMusic::Letter.get(letter_name)
21
- if letter
22
- return new(letter, HeadMusic::Accidental.get(accidental_string))
23
- end
21
+ new(letter, HeadMusic::Accidental.get(accidental_string)) if letter
24
22
  end
25
23
  end
26
24
 
27
25
  def self.from_number(number)
28
26
  return nil unless number == number.to_i
29
- pitch_class_number = number % 12
27
+ pitch_class_number = number.to_i % 12
30
28
  letter = HeadMusic::Letter.from_pitch_class(pitch_class_number)
31
29
  if letter.pitch_class != pitch_class_number
32
30
  accidental = HeadMusic::Accidental.for_interval(pitch_class_number - letter.pitch_class.to_i)
@@ -1,3 +1,3 @@
1
1
  module HeadMusic
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  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.1.0
4
+ version: 0.1.1
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-02-13 00:00:00.000000000 Z
11
+ date: 2017-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport