head_music 0.16.2 → 0.17.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 +4 -4
- data/lib/head_music/composition.rb +8 -0
- data/lib/head_music/key_signature.rb +4 -4
- data/lib/head_music/language.rb +54 -0
- data/lib/head_music/octave.rb +1 -3
- data/lib/head_music/pitch.rb +10 -9
- data/lib/head_music/scale.rb +1 -1
- data/lib/head_music/scale_degree.rb +8 -9
- data/lib/head_music/sign.rb +72 -0
- data/lib/head_music/spelling.rb +21 -19
- data/lib/head_music/style/annotations/diatonic.rb +1 -1
- data/lib/head_music/version.rb +1 -1
- data/lib/head_music.rb +11 -4
- metadata +4 -3
- data/lib/head_music/accidental.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ff78a490907bb272ceebc6b8d7b635ec7ddc629
|
4
|
+
data.tar.gz: a0dc85d1b1862519ea0ef6fb2469778180e86bab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bd80123c3cb687b3bdf9feae1bf82bbfbe71dcfd0a40714d5e698d4859e1578db55e2cf447f0c4515547053ac0d2f46379ab7593c038a221f84679f6c7bd263
|
7
|
+
data.tar.gz: 6fd59458857b94183c868f3c303f237bab322d455b9bb485a64282e6799ac188fd35bb30329ff903ae1a8bb5bf4bddcf9d1471290570085b44875ec854236c27
|
@@ -45,6 +45,14 @@ class HeadMusic::Composition
|
|
45
45
|
[voices.map(&:earliest_bar_number), 1].flatten.max
|
46
46
|
end
|
47
47
|
|
48
|
+
def cantus_firmus_voice
|
49
|
+
voices.detect(&:cantus_firmus?)
|
50
|
+
end
|
51
|
+
|
52
|
+
def counterpoint_voice
|
53
|
+
voices.reject(&:cantus_firmus?).first
|
54
|
+
end
|
55
|
+
|
48
56
|
private
|
49
57
|
|
50
58
|
def ensure_attributes(name, key_signature, meter)
|
@@ -3,8 +3,8 @@ class HeadMusic::KeySignature
|
|
3
3
|
attr_reader :scale_type
|
4
4
|
attr_reader :scale
|
5
5
|
|
6
|
-
SHARPS = %w{F
|
7
|
-
FLATS = %w{
|
6
|
+
SHARPS = %w{F♯ C♯ G♯ D♯ A♯ E♯ B♯}
|
7
|
+
FLATS = %w{B♭ E♭ A♭ D♭ G♭ C♭ F♭}
|
8
8
|
|
9
9
|
def self.default
|
10
10
|
@default ||= new('C', :major)
|
@@ -14,7 +14,7 @@ class HeadMusic::KeySignature
|
|
14
14
|
return identifier if identifier.is_a?(HeadMusic::KeySignature)
|
15
15
|
@key_signatures ||= {}
|
16
16
|
tonic_spelling, scale_type_name = identifier.strip.split(/\s/)
|
17
|
-
hash_key = HeadMusic::Utilities::HashKey.for(identifier.gsub(
|
17
|
+
hash_key = HeadMusic::Utilities::HashKey.for(identifier.gsub(/#|♯/, 'sharp').gsub(/b|♭/, 'flat'))
|
18
18
|
@key_signatures[hash_key] ||= new(tonic_spelling, scale_type_name)
|
19
19
|
end
|
20
20
|
|
@@ -55,7 +55,7 @@ class HeadMusic::KeySignature
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def name
|
58
|
-
[tonic_spelling
|
58
|
+
[tonic_spelling, scale_type].join(' ')
|
59
59
|
end
|
60
60
|
|
61
61
|
def ==(other)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class HeadMusic::Language
|
2
|
+
include Comparable
|
3
|
+
include HeadMusic::NamedRudiment
|
4
|
+
|
5
|
+
LANGUAGES = [
|
6
|
+
{ name: 'American English', short_name: 'English', abbreviation: 'en-US' },
|
7
|
+
{ name: 'British English', abbreviation: 'en-GB' },
|
8
|
+
{ name: 'French', native_name: 'Français', abbreviation: 'fr' },
|
9
|
+
{ name: 'German', native_name: 'Deutsche', abbreviation: 'de' },
|
10
|
+
{ name: 'Italian', native_name: 'Italiano', abbreviation: 'it' },
|
11
|
+
{ name: 'Spanish', native_name: 'Español', abbreviation: 'es' },
|
12
|
+
{ name: 'Russian', native_name: 'русский', abbreviation: 'ru' },
|
13
|
+
]
|
14
|
+
|
15
|
+
LANGUAGES.map { |language| ::HeadMusic::Utilities::HashKey.for(language[:name]) }.each do |language_key|
|
16
|
+
define_singleton_method(language_key) { HeadMusic::Language.get(language_key) }
|
17
|
+
end
|
18
|
+
|
19
|
+
LANGUAGES.map { |language| ::HeadMusic::Utilities::HashKey.for(language[:native_name]) }.reject(&:nil?).each do |language_key|
|
20
|
+
define_singleton_method(language_key) { HeadMusic::Language.get(language_key) }
|
21
|
+
end
|
22
|
+
|
23
|
+
LANGUAGES.map { |language| ::HeadMusic::Utilities::HashKey.for(language[:short_name]) }.reject(&:nil?).each do |language_key|
|
24
|
+
define_singleton_method(language_key) { HeadMusic::Language.get(language_key) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.default
|
28
|
+
self.english
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.get(name)
|
32
|
+
get_by_name(name) || default
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_accessor :name, :native_name, :short_name
|
36
|
+
|
37
|
+
def initialize(identifier)
|
38
|
+
identifier_key = HeadMusic::Utilities::HashKey.for(identifier)
|
39
|
+
language_data = LANGUAGES.detect { |data|
|
40
|
+
[:name, :native_name, :short_name].map { |key| HeadMusic::Utilities::HashKey.for(data[key]) }.include?(identifier_key)
|
41
|
+
}
|
42
|
+
@name = language_data[:name]
|
43
|
+
@native_name = language_data[:native_name]
|
44
|
+
@short_name = language_data[:short_name]
|
45
|
+
end
|
46
|
+
|
47
|
+
def <=>(other)
|
48
|
+
name.to_s <=> other.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
def inspect
|
52
|
+
[name, native_name, short_name].reject(&:nil?).join(' / ')
|
53
|
+
end
|
54
|
+
end
|
data/lib/head_music/octave.rb
CHANGED
@@ -3,8 +3,6 @@ class HeadMusic::Octave
|
|
3
3
|
|
4
4
|
DEFAULT = 4
|
5
5
|
|
6
|
-
MATCHER = /(-?\d+)$/
|
7
|
-
|
8
6
|
def self.get(identifier)
|
9
7
|
from_number(identifier) || from_name(identifier) || default
|
10
8
|
end
|
@@ -18,7 +16,7 @@ class HeadMusic::Octave
|
|
18
16
|
|
19
17
|
def self.from_name(string)
|
20
18
|
if string.to_s.match(HeadMusic::Spelling::MATCHER)
|
21
|
-
_letter,
|
19
|
+
_letter, _sign, octave_string = string.to_s.match(HeadMusic::Spelling::MATCHER).captures
|
22
20
|
@octaves ||= {}
|
23
21
|
@octaves[octave_string.to_i] ||= new(octave_string.to_i) if octave_string
|
24
22
|
end
|
data/lib/head_music/pitch.rb
CHANGED
@@ -5,9 +5,9 @@ class HeadMusic::Pitch
|
|
5
5
|
attr_reader :octave
|
6
6
|
|
7
7
|
delegate :letter_name, :letter_name_cycle, to: :spelling
|
8
|
-
delegate :
|
8
|
+
delegate :sign, :sharp?, :flat?, to: :spelling
|
9
9
|
delegate :pitch_class, to: :spelling
|
10
|
-
delegate :semitones, to: :
|
10
|
+
delegate :semitones, to: :sign, prefix: true, allow_nil: true
|
11
11
|
|
12
12
|
delegate :smallest_interval_to, to: :pitch_class
|
13
13
|
|
@@ -32,17 +32,17 @@ class HeadMusic::Pitch
|
|
32
32
|
natural_letter_pitch = get(HeadMusic::LetterName.get(letter_name).pitch_class)
|
33
33
|
natural_letter_pitch += 12 while (number - natural_letter_pitch.to_i).to_i >= 11
|
34
34
|
natural_letter_pitch = get(natural_letter_pitch)
|
35
|
-
|
36
|
-
|
37
|
-
spelling = HeadMusic::Spelling.fetch_or_create(letter_name,
|
35
|
+
sign_interval = natural_letter_pitch.smallest_interval_to(HeadMusic::PitchClass.get(number))
|
36
|
+
sign = HeadMusic::Sign.by(:semitones, sign_interval) if sign_interval != 0
|
37
|
+
spelling = HeadMusic::Spelling.fetch_or_create(letter_name, sign)
|
38
38
|
fetch_or_create(spelling, natural_letter_pitch.octave)
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.fetch_or_create(spelling, octave)
|
42
42
|
@pitches ||= {}
|
43
43
|
if spelling && (-1..9).include?(octave)
|
44
|
-
|
45
|
-
@pitches[
|
44
|
+
hash_key = [spelling, octave].join
|
45
|
+
@pitches[hash_key] ||= new(spelling, octave)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -56,7 +56,7 @@ class HeadMusic::Pitch
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def midi_note_number
|
59
|
-
(octave + 1) * 12 + letter_name.pitch_class.to_i +
|
59
|
+
(octave + 1) * 12 + letter_name.pitch_class.to_i + sign_semitones.to_i
|
60
60
|
end
|
61
61
|
|
62
62
|
alias_method :midi, :midi_note_number
|
@@ -93,7 +93,8 @@ class HeadMusic::Pitch
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def ==(value)
|
96
|
-
|
96
|
+
other = HeadMusic::Pitch.get(value)
|
97
|
+
to_s == other.to_s
|
97
98
|
end
|
98
99
|
|
99
100
|
def <=>(other)
|
data/lib/head_music/scale.rb
CHANGED
@@ -8,7 +8,7 @@ class HeadMusic::Scale
|
|
8
8
|
root_pitch = HeadMusic::Pitch.get(root_pitch)
|
9
9
|
scale_type = HeadMusic::ScaleType.get(scale_type || :major)
|
10
10
|
@scales ||= {}
|
11
|
-
name = [root_pitch
|
11
|
+
name = [root_pitch, scale_type].join(' ')
|
12
12
|
hash_key = HeadMusic::Utilities::HashKey.for(name)
|
13
13
|
@scales[hash_key] ||= new(root_pitch, scale_type)
|
14
14
|
end
|
@@ -16,21 +16,20 @@ class HeadMusic::ScaleDegree
|
|
16
16
|
scale.letter_name_cycle.index(spelling.letter_name.to_s) + 1
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
20
|
-
spelling.
|
21
|
-
scale_degree_usual_spelling.
|
22
|
-
|
23
|
-
|
24
|
-
HeadMusic::Accidental.for_interval(accidental_semitones - usual_accidental_semitones)
|
19
|
+
def sign
|
20
|
+
sign_semitones = spelling.sign && spelling.sign.semitones || 0
|
21
|
+
usual_sign_semitones = scale_degree_usual_spelling.sign && scale_degree_usual_spelling.sign.semitones || 0
|
22
|
+
delta = sign_semitones - usual_sign_semitones
|
23
|
+
HeadMusic::Sign.by(:semitones, delta) if delta != 0
|
25
24
|
end
|
26
25
|
|
27
26
|
def to_s
|
28
|
-
"#{
|
27
|
+
"#{sign}#{degree}"
|
29
28
|
end
|
30
29
|
|
31
30
|
def <=>(other)
|
32
31
|
if other.is_a?(HeadMusic::ScaleDegree)
|
33
|
-
[degree,
|
32
|
+
[degree, sign.semitones] <=> [other.degree, other.sign.semitones]
|
34
33
|
else
|
35
34
|
to_s <=> other.to_s
|
36
35
|
end
|
@@ -39,7 +38,7 @@ class HeadMusic::ScaleDegree
|
|
39
38
|
def name_for_degree
|
40
39
|
if scale_type.diatonic?
|
41
40
|
NAME_FOR_DIATONIC_DEGREE[degree] ||
|
42
|
-
(scale_type.intervals.last == 1 ||
|
41
|
+
(scale_type.intervals.last == 1 || sign == '#' ? 'leading tone' : 'subtonic')
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class HeadMusic::Sign
|
2
|
+
include Comparable
|
3
|
+
|
4
|
+
attr_reader :identifier, :name, :ascii, :unicode, :html_entity, :cents
|
5
|
+
|
6
|
+
def self.all
|
7
|
+
@all ||= [
|
8
|
+
new(identifier: :sharp, name: 'sharp', ascii: '#', unicode: '♯', html_entity: '♯', cents: 100),
|
9
|
+
new(identifier: :flat, name: 'flat', ascii: 'b', unicode: "♭", html_entity: '♭', cents: -100),
|
10
|
+
new(identifier: :natural, name: 'natural', ascii: '', unicode: '♮', html_entity: '♮', cents: 0),
|
11
|
+
new(identifier: :double_sharp, name: 'double sharp', ascii: '##', unicode: '𝄪', html_entity: '𝄪', cents: 200),
|
12
|
+
new(identifier: :double_flat, name: 'double flat', ascii: 'bb', unicode: '𝄫', html_entity: '𝄫', cents: -200),
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.symbols
|
17
|
+
@sign_symbols ||= all.map { |sign| [sign.ascii, sign.unicode] }.flatten.reject { |s| s.nil? || s.empty? }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.matcher
|
21
|
+
@matcher ||= Regexp.new symbols.join('|')
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.symbol?(candidate)
|
25
|
+
/^(#{matcher})$/.match?(candidate)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.get(identifier)
|
29
|
+
return identifier if identifier.is_a?(HeadMusic::Sign)
|
30
|
+
all.detect do |sign|
|
31
|
+
sign.representions.include?(identifier)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.by(key, value)
|
36
|
+
all.detect do |sign|
|
37
|
+
if %i[cents semitones].include?(key.to_sym)
|
38
|
+
sign.send(key) == value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def representions
|
44
|
+
[identifier, identifier.to_s, name, ascii, unicode, html_entity].reject { |representation| representation.to_s.strip == '' }
|
45
|
+
end
|
46
|
+
|
47
|
+
def semitones
|
48
|
+
cents / 100.0
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
unicode
|
53
|
+
end
|
54
|
+
|
55
|
+
def <=>(other)
|
56
|
+
other = HeadMusic::Sign.get(other)
|
57
|
+
self.cents <=> other.cents
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def initialize(attributes)
|
63
|
+
@identifier = attributes[:identifier]
|
64
|
+
@name = attributes[:name]
|
65
|
+
@ascii = attributes[:ascii]
|
66
|
+
@unicode = attributes[:unicode]
|
67
|
+
@html_entity = attributes[:html_entity]
|
68
|
+
@cents = attributes[:cents]
|
69
|
+
end
|
70
|
+
|
71
|
+
private_class_method :new
|
72
|
+
end
|
data/lib/head_music/spelling.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
class HeadMusic::Spelling
|
2
|
-
MATCHER = /^\s*([A-G])(
|
2
|
+
MATCHER = /^\s*([A-G])(#{HeadMusic::Sign.matcher}?)(\-?\d+)?\s*$/i
|
3
3
|
|
4
4
|
attr_reader :pitch_class
|
5
5
|
attr_reader :letter_name
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :sign
|
7
7
|
|
8
8
|
delegate :number, to: :pitch_class, prefix: true
|
9
9
|
delegate :to_i, to: :pitch_class_number
|
@@ -11,6 +11,7 @@ class HeadMusic::Spelling
|
|
11
11
|
delegate :enharmonic?, to: :pitch_class
|
12
12
|
|
13
13
|
def self.get(identifier)
|
14
|
+
return identifier if identifier.is_a?(HeadMusic::Spelling)
|
14
15
|
from_name(identifier) || from_number(identifier)
|
15
16
|
end
|
16
17
|
|
@@ -20,11 +21,11 @@ class HeadMusic::Spelling
|
|
20
21
|
|
21
22
|
def self.from_name(name)
|
22
23
|
if match(name)
|
23
|
-
letter_name,
|
24
|
+
letter_name, sign_string, _octave = match(name).captures
|
24
25
|
letter_name = HeadMusic::LetterName.get(letter_name)
|
25
26
|
return nil unless letter_name
|
26
|
-
|
27
|
-
fetch_or_create(letter_name,
|
27
|
+
sign = HeadMusic::Sign.get(sign_string)
|
28
|
+
fetch_or_create(letter_name, sign)
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
@@ -38,26 +39,26 @@ class HeadMusic::Spelling
|
|
38
39
|
def self.from_number_and_letter(number, letter_name)
|
39
40
|
letter_name = HeadMusic::LetterName.get(letter_name)
|
40
41
|
natural_letter_pitch_class = letter_name.pitch_class
|
41
|
-
|
42
|
-
|
43
|
-
fetch_or_create(letter_name,
|
42
|
+
sign_interval = natural_letter_pitch_class.smallest_interval_to(HeadMusic::PitchClass.get(number))
|
43
|
+
sign = HeadMusic::Sign.by(:semitones, sign_interval) if sign_interval != 0
|
44
|
+
fetch_or_create(letter_name, sign)
|
44
45
|
end
|
45
46
|
|
46
|
-
def self.fetch_or_create(letter_name,
|
47
|
+
def self.fetch_or_create(letter_name, sign)
|
47
48
|
@spellings ||= {}
|
48
|
-
|
49
|
-
@spellings[
|
49
|
+
hash_key = [letter_name, sign].join
|
50
|
+
@spellings[hash_key] ||= new(letter_name, sign)
|
50
51
|
end
|
51
52
|
|
52
|
-
def initialize(letter_name,
|
53
|
+
def initialize(letter_name, sign = nil)
|
53
54
|
@letter_name = HeadMusic::LetterName.get(letter_name.to_s)
|
54
|
-
@
|
55
|
-
|
56
|
-
@pitch_class = HeadMusic::PitchClass.get(letter_name.pitch_class +
|
55
|
+
@sign = HeadMusic::Sign.get(sign)
|
56
|
+
sign_semitones = @sign ? @sign.semitones : 0
|
57
|
+
@pitch_class = HeadMusic::PitchClass.get(letter_name.pitch_class + sign_semitones)
|
57
58
|
end
|
58
59
|
|
59
60
|
def name
|
60
|
-
[letter_name,
|
61
|
+
[letter_name, sign].join
|
61
62
|
end
|
62
63
|
|
63
64
|
def to_s
|
@@ -65,15 +66,16 @@ class HeadMusic::Spelling
|
|
65
66
|
end
|
66
67
|
|
67
68
|
def sharp?
|
68
|
-
|
69
|
+
sign && sign == '#'
|
69
70
|
end
|
70
71
|
|
71
72
|
def flat?
|
72
|
-
|
73
|
+
sign && sign == 'b'
|
73
74
|
end
|
74
75
|
|
75
76
|
def ==(value)
|
76
|
-
|
77
|
+
other = HeadMusic::Spelling.get(value)
|
78
|
+
to_s == other.to_s
|
77
79
|
end
|
78
80
|
|
79
81
|
def scale(scale_type_name = nil)
|
@@ -14,7 +14,7 @@ class HeadMusic::Style::Annotations::Diatonic < HeadMusic::Style::Annotation
|
|
14
14
|
notes_not_in_key.reject do |note|
|
15
15
|
penultimate_note &&
|
16
16
|
note == penultimate_note &&
|
17
|
-
HeadMusic::ScaleDegree.new(key_signature, note.pitch.spelling).
|
17
|
+
HeadMusic::ScaleDegree.new(key_signature, note.pitch.spelling).sign == '#'
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
data/lib/head_music/version.rb
CHANGED
data/lib/head_music.rb
CHANGED
@@ -11,9 +11,13 @@ require 'active_support/core_ext/module/delegation'
|
|
11
11
|
require 'active_support/core_ext/string/access'
|
12
12
|
require 'humanize'
|
13
13
|
|
14
|
+
# utilities
|
15
|
+
require 'head_music/utilities/hash_key'
|
16
|
+
|
17
|
+
# modules
|
14
18
|
require 'head_music/named_rudiment'
|
15
19
|
|
16
|
-
|
20
|
+
# rudiments
|
17
21
|
require 'head_music/bar'
|
18
22
|
require 'head_music/chord'
|
19
23
|
require 'head_music/circle'
|
@@ -26,6 +30,7 @@ require 'head_music/harmonic_interval'
|
|
26
30
|
require 'head_music/instrument'
|
27
31
|
require 'head_music/interval'
|
28
32
|
require 'head_music/key_signature'
|
33
|
+
require 'head_music/language'
|
29
34
|
require 'head_music/letter_name'
|
30
35
|
require 'head_music/melodic_interval'
|
31
36
|
require 'head_music/meter'
|
@@ -43,13 +48,17 @@ require 'head_music/rhythmic_value'
|
|
43
48
|
require 'head_music/scale'
|
44
49
|
require 'head_music/scale_degree'
|
45
50
|
require 'head_music/scale_type'
|
51
|
+
require 'head_music/sign'
|
46
52
|
require 'head_music/spelling'
|
47
53
|
require 'head_music/staff'
|
54
|
+
require 'head_music/voice'
|
48
55
|
|
56
|
+
# analysis
|
49
57
|
require 'head_music/style/analysis'
|
50
58
|
require 'head_music/style/annotation'
|
51
59
|
require 'head_music/style/mark'
|
52
60
|
|
61
|
+
# annotations
|
53
62
|
require 'head_music/style/annotations/always_move'
|
54
63
|
require 'head_music/style/annotations/approach_perfection_contrarily'
|
55
64
|
require 'head_music/style/annotations/at_least_eight_notes'
|
@@ -84,10 +93,8 @@ require 'head_music/style/annotations/step_to_final_note'
|
|
84
93
|
require 'head_music/style/annotations/step_up_to_final_note'
|
85
94
|
require 'head_music/style/annotations/up_to_fourteen_notes'
|
86
95
|
|
96
|
+
# rulesets
|
87
97
|
require 'head_music/style/rulesets/fux_cantus_firmus'
|
88
98
|
require 'head_music/style/rulesets/modern_cantus_firmus'
|
89
99
|
require 'head_music/style/rulesets/first_species_melody'
|
90
100
|
require 'head_music/style/rulesets/first_species_harmony'
|
91
|
-
|
92
|
-
require 'head_music/utilities/hash_key'
|
93
|
-
require 'head_music/voice'
|
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.
|
4
|
+
version: 0.17.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:
|
11
|
+
date: 2018-02-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -116,7 +116,6 @@ files:
|
|
116
116
|
- circle.yml
|
117
117
|
- head_music.gemspec
|
118
118
|
- lib/head_music.rb
|
119
|
-
- lib/head_music/accidental.rb
|
120
119
|
- lib/head_music/bar.rb
|
121
120
|
- lib/head_music/chord.rb
|
122
121
|
- lib/head_music/circle.rb
|
@@ -129,6 +128,7 @@ files:
|
|
129
128
|
- lib/head_music/instrument.rb
|
130
129
|
- lib/head_music/interval.rb
|
131
130
|
- lib/head_music/key_signature.rb
|
131
|
+
- lib/head_music/language.rb
|
132
132
|
- lib/head_music/letter_name.rb
|
133
133
|
- lib/head_music/melodic_interval.rb
|
134
134
|
- lib/head_music/meter.rb
|
@@ -147,6 +147,7 @@ files:
|
|
147
147
|
- lib/head_music/scale.rb
|
148
148
|
- lib/head_music/scale_degree.rb
|
149
149
|
- lib/head_music/scale_type.rb
|
150
|
+
- lib/head_music/sign.rb
|
150
151
|
- lib/head_music/spelling.rb
|
151
152
|
- lib/head_music/staff.rb
|
152
153
|
- lib/head_music/style/analysis.rb
|
@@ -1,42 +0,0 @@
|
|
1
|
-
class HeadMusic::Accidental
|
2
|
-
ACCIDENTAL_SEMITONES = {
|
3
|
-
'#' => 1,
|
4
|
-
'##' => 2,
|
5
|
-
'b' => -1,
|
6
|
-
'bb' => -2
|
7
|
-
}
|
8
|
-
|
9
|
-
attr_reader :string
|
10
|
-
|
11
|
-
def self.get(identifier)
|
12
|
-
for_symbol(identifier) || for_interval(identifier)
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.for_symbol(identifier)
|
16
|
-
@accidentals ||= {}
|
17
|
-
@accidentals[identifier.to_s] ||= new(identifier.to_s) if ACCIDENTAL_SEMITONES.keys.include?(identifier.to_s)
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.for_interval(semitones)
|
21
|
-
@accidentals ||= {}
|
22
|
-
@accidentals[semitones.to_i] ||= ACCIDENTAL_SEMITONES.key(semitones.to_i)
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize(string)
|
26
|
-
@string = string
|
27
|
-
end
|
28
|
-
|
29
|
-
def to_s
|
30
|
-
string
|
31
|
-
end
|
32
|
-
|
33
|
-
def ==(value)
|
34
|
-
to_s == value.to_s
|
35
|
-
end
|
36
|
-
|
37
|
-
def semitones
|
38
|
-
ACCIDENTAL_SEMITONES.fetch(string, 0)
|
39
|
-
end
|
40
|
-
|
41
|
-
private_class_method :new
|
42
|
-
end
|