head_music 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/head_music/functional_interval.rb +64 -15
- data/lib/head_music/letter.rb +4 -0
- data/lib/head_music/pitch.rb +3 -2
- data/lib/head_music/quality.rb +8 -0
- data/lib/head_music/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27bbe45d50118d4f5f4bcf02e3192da3ddd2ec70
|
4
|
+
data.tar.gz: 1900eb67572a4bfb79e0b91c05673bfadd1f7c2c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30f5b988d501ca3286bc41da70c3ca3672d9d30438d81a5740c1c8db4bd1d4e3e9af594302aa928afea446c2d6197f1b3aa0d69280c1e94fc986e03359712872
|
7
|
+
data.tar.gz: d5534e5c7dadf6b7339d29b4db89256cf2d853b5415add44032c15eb24f1e10a83bb0d185d4437ef319a29f7c003f0b90228e3cce19bcfe22d5d73646255f561
|
@@ -2,18 +2,63 @@ class HeadMusic::FunctionalInterval
|
|
2
2
|
NUMBER_NAMES = %w[unison second third fourth fifth sixth seventh octave ninth tenth eleventh twelfth thirteenth fourteenth fifteenth sixteenth seventeenth]
|
3
3
|
NAME_SUFFIXES = Hash.new('th').merge({ 1 => 'st', 2 => 'nd', 3 => 'rd' })
|
4
4
|
|
5
|
-
|
6
|
-
unison: {perfect: 0},
|
7
|
-
second: {major: 2},
|
8
|
-
third: {major: 4},
|
9
|
-
fourth: {perfect: 5},
|
10
|
-
fifth: {perfect: 7},
|
11
|
-
sixth: {major: 9},
|
12
|
-
seventh: {major: 11},
|
5
|
+
QUALITY_SEMITONES = {
|
6
|
+
unison: { perfect: 0 },
|
7
|
+
second: { major: 2 },
|
8
|
+
third: { major: 4 },
|
9
|
+
fourth: { perfect: 5 },
|
10
|
+
fifth: { perfect: 7 },
|
11
|
+
sixth: { major: 9 },
|
12
|
+
seventh: { major: 11 },
|
13
|
+
octave: { perfect: 12 },
|
14
|
+
ninth: { major: 14 },
|
15
|
+
tenth: { major: 16 },
|
16
|
+
eleventh: { perfect: 17 },
|
17
|
+
twelfth: { perfect: 19 },
|
18
|
+
thirteenth: { major: 21 },
|
19
|
+
fourteenth: { major: 23 },
|
20
|
+
fifteenth: { perfect: 24 },
|
21
|
+
sixteenth: { major: 26 },
|
22
|
+
seventeenth: { major: 28 }
|
13
23
|
}
|
14
24
|
|
15
25
|
attr_reader :lower_pitch, :higher_pitch
|
16
26
|
|
27
|
+
delegate :to_s, to: :name
|
28
|
+
delegate :==, to: :to_s
|
29
|
+
|
30
|
+
def self.get(name)
|
31
|
+
words = name.to_s.split(/[_ ]+/)
|
32
|
+
quality_name, degree_name = words[0..-2].join(' '), words.last
|
33
|
+
lower_pitch = HeadMusic::Pitch.get('C4')
|
34
|
+
steps = NUMBER_NAMES.index(degree_name)
|
35
|
+
higher_letter = lower_pitch.letter.steps(steps)
|
36
|
+
semitones = degree_quality_semitones.dig(degree_name.to_sym, quality_name.to_sym)
|
37
|
+
higher_pitch = HeadMusic::Pitch.from_number_and_letter(lower_pitch + semitones, higher_letter)
|
38
|
+
new(lower_pitch, higher_pitch)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.degree_quality_semitones
|
42
|
+
@degree_quality_semitones ||= begin
|
43
|
+
degree_quality_semitones = QUALITY_SEMITONES
|
44
|
+
QUALITY_SEMITONES.each do |degree_name, qualities|
|
45
|
+
default_quality = qualities.keys.first
|
46
|
+
if default_quality == :perfect
|
47
|
+
modification_hash = HeadMusic::Quality::PERFECT_INTERVAL_MODIFICATION.invert
|
48
|
+
else
|
49
|
+
modification_hash = HeadMusic::Quality::MAJOR_INTERVAL_MODIFICATION.invert
|
50
|
+
end
|
51
|
+
default_semitones = qualities[default_quality]
|
52
|
+
modification_hash.each do |quality_name, delta|
|
53
|
+
if quality_name != default_quality
|
54
|
+
degree_quality_semitones[degree_name][quality_name] = default_semitones + delta
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
degree_quality_semitones
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
17
62
|
def initialize(pitch1, pitch2)
|
18
63
|
@lower_pitch, @higher_pitch = [HeadMusic::Pitch.get(pitch1), HeadMusic::Pitch.get(pitch2)].sort
|
19
64
|
end
|
@@ -69,13 +114,9 @@ class HeadMusic::FunctionalInterval
|
|
69
114
|
end
|
70
115
|
|
71
116
|
def quality_name
|
72
|
-
starting_quality =
|
73
|
-
delta = simple_semitones -
|
74
|
-
|
75
|
-
HeadMusic::Quality::PERFECT_INTERVAL_MODIFICATION[delta]
|
76
|
-
elsif starting_quality == :major
|
77
|
-
HeadMusic::Quality::MAJOR_INTERVAL_MODIFICATION[delta]
|
78
|
-
end
|
117
|
+
starting_quality = QUALITY_SEMITONES[simple_number_name.to_sym].keys.first
|
118
|
+
delta = simple_semitones - QUALITY_SEMITONES[simple_number_name.to_sym][starting_quality]
|
119
|
+
HeadMusic::Quality::from(starting_quality, delta)
|
79
120
|
end
|
80
121
|
|
81
122
|
def simple_number_name
|
@@ -87,4 +128,12 @@ class HeadMusic::FunctionalInterval
|
|
87
128
|
number.to_s + NAME_SUFFIXES[number % 10]
|
88
129
|
end
|
89
130
|
end
|
131
|
+
|
132
|
+
def inversion
|
133
|
+
inverted_low_pitch = lower_pitch
|
134
|
+
while inverted_low_pitch < higher_pitch
|
135
|
+
inverted_low_pitch += 12
|
136
|
+
end
|
137
|
+
HeadMusic::FunctionalInterval.new(higher_pitch, inverted_low_pitch)
|
138
|
+
end
|
90
139
|
end
|
data/lib/head_music/letter.rb
CHANGED
data/lib/head_music/pitch.rb
CHANGED
@@ -7,6 +7,7 @@ class HeadMusic::Pitch
|
|
7
7
|
delegate :letter, :letter_cycle, to: :spelling
|
8
8
|
delegate :accidental, :sharp?, :flat?, to: :spelling
|
9
9
|
delegate :pitch_class, to: :spelling
|
10
|
+
delegate :semitones, to: :accidental, prefix: true, allow_nil: true
|
10
11
|
|
11
12
|
delegate :smallest_interval_to, to: :pitch_class
|
12
13
|
|
@@ -29,7 +30,7 @@ class HeadMusic::Pitch
|
|
29
30
|
def self.from_number_and_letter(number, letter)
|
30
31
|
letter = HeadMusic::Letter.get(letter)
|
31
32
|
natural_letter_pitch = get(HeadMusic::Letter.get(letter).pitch_class)
|
32
|
-
natural_letter_pitch += 12 while (number - natural_letter_pitch.to_i) >= 11
|
33
|
+
natural_letter_pitch += 12 while (number - natural_letter_pitch.to_i).to_i >= 11
|
33
34
|
natural_letter_pitch = get(natural_letter_pitch)
|
34
35
|
accidental_interval = natural_letter_pitch.smallest_interval_to(HeadMusic::PitchClass.get(number))
|
35
36
|
accidental = HeadMusic::Accidental.for_interval(accidental_interval)
|
@@ -55,7 +56,7 @@ class HeadMusic::Pitch
|
|
55
56
|
end
|
56
57
|
|
57
58
|
def midi_note_number
|
58
|
-
(octave + 1) * 12 + pitch_class.to_i
|
59
|
+
(octave + 1) * 12 + letter.pitch_class.to_i + accidental_semitones.to_i
|
59
60
|
end
|
60
61
|
|
61
62
|
alias_method :midi, :midi_note_number
|
data/lib/head_music/quality.rb
CHANGED
@@ -32,6 +32,14 @@ class HeadMusic::Quality
|
|
32
32
|
@qualities[identifier] ||= new(identifier) if NAMES.include?(identifier)
|
33
33
|
end
|
34
34
|
|
35
|
+
def self.from(starting_quality, delta)
|
36
|
+
if starting_quality == :perfect
|
37
|
+
PERFECT_INTERVAL_MODIFICATION[delta].to_s.gsub(/_+/, ' ')
|
38
|
+
elsif starting_quality == :major
|
39
|
+
MAJOR_INTERVAL_MODIFICATION[delta].to_s.gsub(/_+/, ' ')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
35
43
|
attr_reader :name
|
36
44
|
delegate :to_s, to: :name
|
37
45
|
|
data/lib/head_music/version.rb
CHANGED
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.
|
4
|
+
version: 0.5.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-
|
11
|
+
date: 2017-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|