head_music 0.5.0 → 0.5.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 +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
|