head_music 0.5.2 → 0.5.3

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: 208eb249d8215ed60a1047fa2ce44d615da37cf3
4
- data.tar.gz: 9e02bbfcd8df9e1ca07dc737b594063831caf7f3
3
+ metadata.gz: 326a9d839392519ee341ca47ec34eb63ea461bd1
4
+ data.tar.gz: 95dbb21634187c2ba6764829ce37e16759347d39
5
5
  SHA512:
6
- metadata.gz: a76df5d52cfc41df45d538da2fb0b4443d64bd65f4713e412e611082853906495881c26631799bad5c1fd160eea7355baa6c3c8911ad4151f8c719f61866900a
7
- data.tar.gz: 3153be5ac2b260d3ef0c9035d2e2772ba35d0871f831878eba88313365a843a08e24a4bb6ce59d1bc2fc661c388e317efdb7a2fc3ff92c76eed6db45b5165a3b
6
+ metadata.gz: d7b40960fcf36045cfd9d512e27d41024fc2a1a37c10cbcffa1c89c125ac2fd3fba06108b457f6ae99c612bc956c23763636999239c05250c0842314be75fb11
7
+ data.tar.gz: 6a7971653dad527be88f1321e9e3cab80b4855e8a460a82f885fd17d96a78fe1bb98e0b3fd21bfe2b6f49529bda891fadce86979dcf9669da5657ad82c51d5eb
@@ -11,6 +11,7 @@ class HeadMusic::Accidental
11
11
  def self.get(identifier)
12
12
  for_symbol(identifier) || for_interval(identifier)
13
13
  end
14
+ singleton_class.send(:alias_method, :[], :get)
14
15
 
15
16
  def self.for_symbol(identifier)
16
17
  @accidentals ||= {}
@@ -1,16 +1,17 @@
1
1
  class HeadMusic::Circle
2
2
  def self.of_fifths
3
- by_interval(HeadMusic::Interval.named(:perfect_fifth))
3
+ get(7)
4
4
  end
5
5
 
6
6
  def self.of_fourths
7
- by_interval(HeadMusic::Interval.named(:perfect_fourth))
7
+ get(5)
8
8
  end
9
9
 
10
- def self.by_interval(interval)
10
+ def self.get(interval = 7)
11
11
  @circles ||= {}
12
12
  @circles[interval.to_i] ||= new(interval)
13
13
  end
14
+ singleton_class.send(:alias_method, :[], :get)
14
15
 
15
16
  attr_reader :interval, :pitch_classes
16
17
 
@@ -5,6 +5,7 @@ class HeadMusic::Consonance
5
5
  @consonances ||= {}
6
6
  @consonances[name.to_sym] ||= new(name) if LEVELS.include?(name.to_s)
7
7
  end
8
+ singleton_class.send(:alias_method, :[], :get)
8
9
 
9
10
  attr_reader :name
10
11
 
@@ -38,6 +38,7 @@ class HeadMusic::FunctionalInterval
38
38
  higher_pitch = HeadMusic::Pitch.from_number_and_letter(lower_pitch + semitones, higher_letter)
39
39
  new(lower_pitch, higher_pitch)
40
40
  end
41
+ singleton_class.send(:alias_method, :[], :get)
41
42
 
42
43
  def self.degree_quality_semitones
43
44
  @degree_quality_semitones ||= begin
@@ -11,6 +11,7 @@ class HeadMusic::Interval
11
11
  @intervals ||= {}
12
12
  @intervals[semitones.to_i] ||= new(semitones.to_i)
13
13
  end
14
+ singleton_class.send(:alias_method, :[], :get)
14
15
 
15
16
  def self.named(name)
16
17
  name = name.to_s
@@ -1,4 +1,4 @@
1
- class HeadMusic::Letter
1
+ class HeadMusic::LetterName
2
2
  # Defines the natural relationship between the natural letter-named notes
3
3
 
4
4
  NAMES = ('A'..'G').to_a
@@ -20,6 +20,7 @@ class HeadMusic::Letter
20
20
  def self.get(identifier)
21
21
  from_name(identifier) || from_pitch_class(identifier)
22
22
  end
23
+ singleton_class.send(:alias_method, :[], :get)
23
24
 
24
25
  def self.from_name(name)
25
26
  @letters ||= {}
@@ -63,7 +64,7 @@ class HeadMusic::Letter
63
64
  end
64
65
 
65
66
  def steps_to(other, direction = :ascending)
66
- other = Letter.get(other)
67
+ other = LetterName.get(other)
67
68
  other_position = other.position
68
69
  if direction == :descending
69
70
  other_position -= NAMES.length if other_position > position
@@ -0,0 +1,50 @@
1
+ class HeadMusic::Meter
2
+ attr_reader :top_number, :bottom_number
3
+
4
+ NAMED = {
5
+ common_time: '4/4',
6
+ cut_time: '2/2'
7
+ }
8
+
9
+ def self.get(identifier)
10
+ identifer = identifer.to_s
11
+ identifier = NAMED[identifier.to_sym] || identifier
12
+ new(*identifier.split('/').map(&:to_i))
13
+ end
14
+
15
+ def initialize(top_number, bottom_number)
16
+ @top_number, @bottom_number = top_number, bottom_number
17
+ end
18
+
19
+ def simple?
20
+ !compound?
21
+ end
22
+
23
+ def compound?
24
+ top_number > 3 && top_number / 3 == top_number / 3.0
25
+ end
26
+
27
+ def duple?
28
+ top_number == 2
29
+ end
30
+
31
+ def triple?
32
+ top_number % 3 == 0
33
+ end
34
+
35
+ def quadruple?
36
+ top_number == 4
37
+ end
38
+
39
+ def beats_per_measure
40
+ compound? ? top_number / 3 : top_number
41
+ end
42
+
43
+ def to_s
44
+ [top_number, bottom_number].join('/')
45
+ end
46
+
47
+ def ==(other)
48
+ to_s == other.to_s
49
+ end
50
+ end
@@ -8,6 +8,7 @@ class HeadMusic::Octave
8
8
  def self.get(identifier)
9
9
  from_number(identifier) || from_name(identifier) || default
10
10
  end
11
+ singleton_class.send(:alias_method, :[], :get)
11
12
 
12
13
  def self.from_number(identifier)
13
14
  return nil unless identifier.to_s == identifier.to_i.to_s
@@ -14,6 +14,7 @@ class HeadMusic::Pitch
14
14
  def self.get(value)
15
15
  from_name(value) || from_number(value)
16
16
  end
17
+ singleton_class.send(:alias_method, :[], :get)
17
18
 
18
19
  def self.from_name(name)
19
20
  return nil unless name == name.to_s
@@ -28,8 +29,8 @@ class HeadMusic::Pitch
28
29
  end
29
30
 
30
31
  def self.from_number_and_letter(number, letter)
31
- letter = HeadMusic::Letter.get(letter)
32
- natural_letter_pitch = get(HeadMusic::Letter.get(letter).pitch_class)
32
+ letter = HeadMusic::LetterName.get(letter)
33
+ natural_letter_pitch = get(HeadMusic::LetterName.get(letter).pitch_class)
33
34
  natural_letter_pitch += 12 while (number - natural_letter_pitch.to_i).to_i >= 11
34
35
  natural_letter_pitch = get(natural_letter_pitch)
35
36
  accidental_interval = natural_letter_pitch.smallest_interval_to(HeadMusic::PitchClass.get(number))
@@ -11,6 +11,7 @@ class HeadMusic::PitchClass
11
11
  number ||= identifier.to_i % 12
12
12
  @pitch_classes[number] ||= new(number)
13
13
  end
14
+ singleton_class.send(:alias_method, :[], :get)
14
15
 
15
16
  class << self
16
17
  alias_method :[], :get
@@ -35,6 +36,7 @@ class HeadMusic::PitchClass
35
36
  def ==(value)
36
37
  to_i == value.to_i
37
38
  end
39
+ alias_method :enharmonic?, :==
38
40
 
39
41
  def intervals_to(other)
40
42
  delta = other.to_i - to_i
@@ -31,6 +31,7 @@ class HeadMusic::Quality
31
31
  identifier = identifier.to_s.to_sym
32
32
  @qualities[identifier] ||= new(identifier) if NAMES.include?(identifier)
33
33
  end
34
+ singleton_class.send(:alias_method, :[], :get)
34
35
 
35
36
  def self.from(starting_quality, delta)
36
37
  if starting_quality == :perfect
@@ -0,0 +1,63 @@
1
+ class HeadMusic::RhythmicValue
2
+ MULTIPLES = ['whole', 'double whole', 'longa', 'maxima']
3
+ DIVISIONS = ['whole', 'half', 'quarter', 'eighth', 'sixteenth', 'thirty-second', 'sixty-fourth', 'hundred twenty-eighth note', 'two hundred fifty-sixth note']
4
+
5
+ BRITISH_MULTIPLE_NAMES = %w[semibreve breve longa maxima]
6
+ BRITISH_DIVISION_NAMES = %w[semibreve minim crotchet quaver semiquaver demisemiquaver hemidemisemiquaver semihemidemisemiquaver demisemihemidemisemiquaver]
7
+
8
+ def self.get(name)
9
+ @rhythmic_values ||= {}
10
+ @rhythmic_values[name.to_s] ||= new(name.to_s)
11
+ end
12
+ singleton_class.send(:alias_method, :[], :get)
13
+
14
+ attr_reader :name
15
+ delegate :to_s, to: :name
16
+ delegate :to_i, to: :relative_value
17
+
18
+ def initialize(canonical_name)
19
+ @name ||= canonical_name
20
+ end
21
+
22
+ def relative_value
23
+ @relative_value ||=
24
+ if MULTIPLES.include?(name)
25
+ 1.0 * 2**MULTIPLES.index(name)
26
+ elsif DIVISIONS.include?(name)
27
+ 1.0 / 2**DIVISIONS.index(name)
28
+ end
29
+ end
30
+
31
+ def per_whole
32
+ @per_whole ||=
33
+ if MULTIPLES.include?(name)
34
+ 1.0 / 2**MULTIPLES.index(name)
35
+ elsif DIVISIONS.include?(name)
36
+ 1.0 * 2**DIVISIONS.index(name)
37
+ end
38
+ end
39
+
40
+ def note_head
41
+ return :breve if relative_value == 2
42
+ return :open if relative_value >= 0.5
43
+ :closed
44
+ end
45
+
46
+ def flags
47
+ DIVISIONS.include?(name) ? [DIVISIONS.index(name) - 2, 0].max : 0
48
+ end
49
+
50
+ def has_stem?
51
+ relative_value < 1
52
+ end
53
+
54
+ def british_name
55
+ if MULTIPLES.include?(name)
56
+ BRITISH_MULTIPLE_NAMES[MULTIPLES.index(name)]
57
+ elsif DIVISIONS.include?(name)
58
+ BRITISH_DIVISION_NAMES[DIVISIONS.index(name)]
59
+ end
60
+ end
61
+
62
+ private_class_method :new
63
+ end
@@ -64,6 +64,7 @@ class HeadMusic::ScaleType
64
64
  attributes = SCALE_TYPES[name]
65
65
  @scale_types[name] ||= new(name, attributes)
66
66
  end
67
+ singleton_class.send(:alias_method, :[], :get)
67
68
 
68
69
  attr_reader :name, :ascending_intervals, :descending_intervals, :parent_name
69
70
  alias_method :intervals, :ascending_intervals
@@ -1,5 +1,4 @@
1
- # A Spelling is a pitch class with a letter and possibly an accidental
2
-
1
+ # A Spelling is a pitch class with a letter name and possibly an accidental
3
2
  class HeadMusic::Spelling
4
3
  MATCHER = /^\s*([A-G])([b#]*)(\-?\d+)?\s*$/
5
4
 
@@ -10,10 +9,12 @@ class HeadMusic::Spelling
10
9
  delegate :number, to: :pitch_class, prefix: true
11
10
  delegate :to_i, to: :pitch_class_number
12
11
  delegate :cycle, to: :letter, prefix: true
12
+ delegate :enharmonic?, to: :pitch_class
13
13
 
14
14
  def self.get(identifier)
15
15
  from_name(identifier) || from_number(identifier)
16
16
  end
17
+ singleton_class.send(:alias_method, :[], :get)
17
18
 
18
19
  def self.match(string)
19
20
  string.to_s.match(MATCHER)
@@ -22,7 +23,7 @@ class HeadMusic::Spelling
22
23
  def self.from_name(name)
23
24
  if match(name)
24
25
  letter_name, accidental_string, _octave = match(name).captures
25
- letter = HeadMusic::Letter.get(letter_name)
26
+ letter = HeadMusic::LetterName.get(letter_name)
26
27
  return nil unless letter
27
28
  accidental = HeadMusic::Accidental.get(accidental_string)
28
29
  fetch_or_create(letter, accidental)
@@ -32,13 +33,13 @@ class HeadMusic::Spelling
32
33
  def self.from_number(number)
33
34
  return nil unless number == number.to_i
34
35
  pitch_class_number = number.to_i % 12
35
- letter = HeadMusic::Letter.from_pitch_class(pitch_class_number)
36
+ letter = HeadMusic::LetterName.from_pitch_class(pitch_class_number)
36
37
  from_number_and_letter(number, letter)
37
38
  end
38
39
 
39
40
  def self.from_number_and_letter(number, letter)
40
- letter = HeadMusic::Letter.get(letter)
41
- natural_letter_pitch_class = HeadMusic::Letter.get(letter).pitch_class
41
+ letter = HeadMusic::LetterName.get(letter)
42
+ natural_letter_pitch_class = HeadMusic::LetterName.get(letter).pitch_class
42
43
  accidental_interval = letter.pitch_class.smallest_interval_to(HeadMusic::PitchClass.get(number))
43
44
  accidental = HeadMusic::Accidental.for_interval(accidental_interval)
44
45
  fetch_or_create(letter, accidental)
@@ -51,7 +52,7 @@ class HeadMusic::Spelling
51
52
  end
52
53
 
53
54
  def initialize(letter, accidental = nil)
54
- @letter = HeadMusic::Letter.get(letter.to_s)
55
+ @letter = HeadMusic::LetterName.get(letter.to_s)
55
56
  @accidental = HeadMusic::Accidental.get(accidental.to_s)
56
57
  accidental_semitones = @accidental ? @accidental.semitones : 0
57
58
  @pitch_class = HeadMusic::PitchClass.get(letter.pitch_class + accidental_semitones)
@@ -1,3 +1,3 @@
1
1
  module HeadMusic
2
- VERSION = "0.5.2"
2
+ VERSION = "0.5.3"
3
3
  end
data/lib/head_music.rb CHANGED
@@ -1,23 +1,25 @@
1
- require "head_music/version"
1
+ require 'head_music/version'
2
2
 
3
- require "active_support/core_ext/module/delegation"
4
- require "active_support/core_ext/string/access"
5
- require "humanize"
3
+ require 'active_support/core_ext/module/delegation'
4
+ require 'active_support/core_ext/string/access'
5
+ require 'humanize'
6
6
 
7
- require "head_music/accidental"
8
- require "head_music/circle"
9
- require "head_music/consonance"
10
- require "head_music/functional_interval"
11
- require "head_music/interval"
12
- require "head_music/key_signature"
13
- require "head_music/letter"
14
- require "head_music/octave"
15
- require "head_music/pitch_class"
16
- require "head_music/pitch"
17
- require "head_music/quality"
18
- require "head_music/scale"
19
- require "head_music/scale_type"
20
- require "head_music/spelling"
7
+ require 'head_music/accidental'
8
+ require 'head_music/circle'
9
+ require 'head_music/consonance'
10
+ require 'head_music/functional_interval'
11
+ require 'head_music/interval'
12
+ require 'head_music/key_signature'
13
+ require 'head_music/letter_name'
14
+ require 'head_music/meter'
15
+ require 'head_music/octave'
16
+ require 'head_music/pitch_class'
17
+ require 'head_music/pitch'
18
+ require 'head_music/quality'
19
+ require 'head_music/rhythmic_value'
20
+ require 'head_music/scale'
21
+ require 'head_music/scale_type'
22
+ require 'head_music/spelling'
21
23
 
22
24
  module HeadMusic
23
25
  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.5.2
4
+ version: 0.5.3
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-22 00:00:00.000000000 Z
11
+ date: 2017-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -120,11 +120,13 @@ files:
120
120
  - lib/head_music/functional_interval.rb
121
121
  - lib/head_music/interval.rb
122
122
  - lib/head_music/key_signature.rb
123
- - lib/head_music/letter.rb
123
+ - lib/head_music/letter_name.rb
124
+ - lib/head_music/meter.rb
124
125
  - lib/head_music/octave.rb
125
126
  - lib/head_music/pitch.rb
126
127
  - lib/head_music/pitch_class.rb
127
128
  - lib/head_music/quality.rb
129
+ - lib/head_music/rhythmic_value.rb
128
130
  - lib/head_music/scale.rb
129
131
  - lib/head_music/scale_type.rb
130
132
  - lib/head_music/spelling.rb