head_music 0.5.2 → 0.5.3

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: 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