motion-music 0.0.2
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 +7 -0
- data/.gitignore +6 -0
- data/Gemfile +8 -0
- data/Guardfile +6 -0
- data/LICENSE +23 -0
- data/README.md +53 -0
- data/doc/Gemfile.html +111 -0
- data/doc/Gemfile_lock.html +168 -0
- data/doc/Guardfile.html +111 -0
- data/doc/LICENSE.html +124 -0
- data/doc/Object.html +116 -0
- data/doc/RBMusic.html +164 -0
- data/doc/RBMusic/Interval.html +440 -0
- data/doc/RBMusic/Note.html +620 -0
- data/doc/RBMusic/NoteSet.html +277 -0
- data/doc/RBMusic/Scale.html +274 -0
- data/doc/README_md.html +163 -0
- data/doc/created.rid +8 -0
- data/doc/fonts.css +167 -0
- data/doc/fonts/Lato-Light.ttf +0 -0
- data/doc/fonts/Lato-LightItalic.ttf +0 -0
- data/doc/fonts/Lato-Regular.ttf +0 -0
- data/doc/fonts/Lato-RegularItalic.ttf +0 -0
- data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
- data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
- data/doc/images/add.png +0 -0
- data/doc/images/arrow_up.png +0 -0
- data/doc/images/brick.png +0 -0
- data/doc/images/brick_link.png +0 -0
- data/doc/images/bug.png +0 -0
- data/doc/images/bullet_black.png +0 -0
- data/doc/images/bullet_toggle_minus.png +0 -0
- data/doc/images/bullet_toggle_plus.png +0 -0
- data/doc/images/date.png +0 -0
- data/doc/images/delete.png +0 -0
- data/doc/images/find.png +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/doc/images/macFFBgHack.png +0 -0
- data/doc/images/package.png +0 -0
- data/doc/images/page_green.png +0 -0
- data/doc/images/page_white_text.png +0 -0
- data/doc/images/page_white_width.png +0 -0
- data/doc/images/plugin.png +0 -0
- data/doc/images/ruby.png +0 -0
- data/doc/images/tag_blue.png +0 -0
- data/doc/images/tag_green.png +0 -0
- data/doc/images/transparent.png +0 -0
- data/doc/images/wrench.png +0 -0
- data/doc/images/wrench_orange.png +0 -0
- data/doc/images/zoom.png +0 -0
- data/doc/index.html +93 -0
- data/doc/js/darkfish.js +140 -0
- data/doc/js/jquery.js +18 -0
- data/doc/js/navigation.js +142 -0
- data/doc/js/search.js +109 -0
- data/doc/js/search_index.js +1 -0
- data/doc/js/searcher.js +228 -0
- data/doc/projections_json.html +115 -0
- data/doc/rb-music_gemspec.html +132 -0
- data/doc/rdoc.css +580 -0
- data/doc/table_of_contents.html +192 -0
- data/lib/motion-music.rb +9 -0
- data/lib/motion-music/version.rb +3 -0
- data/lib/rb-music.rb +8 -0
- data/lib/rb-music/constants.rb +105 -0
- data/lib/rb-music/interval.rb +50 -0
- data/lib/rb-music/note.rb +107 -0
- data/lib/rb-music/note_set.rb +61 -0
- data/lib/rb-music/scale.rb +30 -0
- data/lib/rb-music/version.rb +3 -0
- data/motion-music.gemspec +20 -0
- data/projections.json +12 -0
- data/rb-music.gemspec +29 -0
- data/spec/rb-music/constants_spec.rb +27 -0
- data/spec/rb-music/interval_spec.rb +90 -0
- data/spec/rb-music/note_set_spec.rb +191 -0
- data/spec/rb-music/note_spec.rb +318 -0
- data/spec/rb-music/scale_spec.rb +88 -0
- data/spec/spec_helper.rb +14 -0
- metadata +124 -0
@@ -0,0 +1,192 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<meta charset="UTF-8">
|
6
|
+
|
7
|
+
<title>Table of Contents - RDoc Documentation</title>
|
8
|
+
|
9
|
+
<link href="./fonts.css" rel="stylesheet">
|
10
|
+
<link href="./rdoc.css" rel="stylesheet">
|
11
|
+
|
12
|
+
<script type="text/javascript">
|
13
|
+
var rdoc_rel_prefix = "./";
|
14
|
+
</script>
|
15
|
+
|
16
|
+
<script src="./js/jquery.js"></script>
|
17
|
+
<script src="./js/navigation.js"></script>
|
18
|
+
<script src="./js/search_index.js"></script>
|
19
|
+
<script src="./js/search.js"></script>
|
20
|
+
<script src="./js/searcher.js"></script>
|
21
|
+
<script src="./js/darkfish.js"></script>
|
22
|
+
|
23
|
+
|
24
|
+
<body id="top" class="table-of-contents">
|
25
|
+
<main role="main">
|
26
|
+
<h1 class="class">Table of Contents - RDoc Documentation</h1>
|
27
|
+
|
28
|
+
|
29
|
+
<h2 id="classes">Classes and Modules</h2>
|
30
|
+
<ul>
|
31
|
+
<li class="class">
|
32
|
+
<a href="Object.html">Object</a>
|
33
|
+
</li>
|
34
|
+
<li class="module">
|
35
|
+
<a href="RBMusic.html">RBMusic</a>
|
36
|
+
</li>
|
37
|
+
<li class="class">
|
38
|
+
<a href="RBMusic/Interval.html">RBMusic::Interval</a>
|
39
|
+
</li>
|
40
|
+
<li class="class">
|
41
|
+
<a href="RBMusic/Note.html">RBMusic::Note</a>
|
42
|
+
</li>
|
43
|
+
<li class="class">
|
44
|
+
<a href="RBMusic/NoteSet.html">RBMusic::NoteSet</a>
|
45
|
+
</li>
|
46
|
+
<li class="class">
|
47
|
+
<a href="RBMusic/Scale.html">RBMusic::Scale</a>
|
48
|
+
</li>
|
49
|
+
</ul>
|
50
|
+
|
51
|
+
<h2 id="methods">Methods</h2>
|
52
|
+
<ul>
|
53
|
+
|
54
|
+
<li class="method">
|
55
|
+
<a href="RBMusic/Note.html#method-c-from_latin">::from_latin</a>
|
56
|
+
—
|
57
|
+
<span class="container">RBMusic::Note</span>
|
58
|
+
|
59
|
+
<li class="method">
|
60
|
+
<a href="RBMusic/Interval.html#method-c-from_name">::from_name</a>
|
61
|
+
—
|
62
|
+
<span class="container">RBMusic::Interval</span>
|
63
|
+
|
64
|
+
<li class="method">
|
65
|
+
<a href="RBMusic/Interval.html#method-c-from_semitones">::from_semitones</a>
|
66
|
+
—
|
67
|
+
<span class="container">RBMusic::Interval</span>
|
68
|
+
|
69
|
+
<li class="method">
|
70
|
+
<a href="RBMusic/Interval.html#method-c-from_tones_semitones">::from_tones_semitones</a>
|
71
|
+
—
|
72
|
+
<span class="container">RBMusic::Interval</span>
|
73
|
+
|
74
|
+
<li class="method">
|
75
|
+
<a href="RBMusic/NoteSet.html#method-c-new">::new</a>
|
76
|
+
—
|
77
|
+
<span class="container">RBMusic::NoteSet</span>
|
78
|
+
|
79
|
+
<li class="method">
|
80
|
+
<a href="RBMusic/Scale.html#method-c-new">::new</a>
|
81
|
+
—
|
82
|
+
<span class="container">RBMusic::Scale</span>
|
83
|
+
|
84
|
+
<li class="method">
|
85
|
+
<a href="RBMusic/Interval.html#method-c-new">::new</a>
|
86
|
+
—
|
87
|
+
<span class="container">RBMusic::Interval</span>
|
88
|
+
|
89
|
+
<li class="method">
|
90
|
+
<a href="RBMusic/Note.html#method-c-new">::new</a>
|
91
|
+
—
|
92
|
+
<span class="container">RBMusic::Note</span>
|
93
|
+
|
94
|
+
<li class="method">
|
95
|
+
<a href="RBMusic/Note.html#method-i-3D-3D">#==</a>
|
96
|
+
—
|
97
|
+
<span class="container">RBMusic::Note</span>
|
98
|
+
|
99
|
+
<li class="method">
|
100
|
+
<a href="RBMusic/Note.html#method-i-accidental">#accidental</a>
|
101
|
+
—
|
102
|
+
<span class="container">RBMusic::Note</span>
|
103
|
+
|
104
|
+
<li class="method">
|
105
|
+
<a href="RBMusic/NoteSet.html#method-i-add">#add</a>
|
106
|
+
—
|
107
|
+
<span class="container">RBMusic::NoteSet</span>
|
108
|
+
|
109
|
+
<li class="method">
|
110
|
+
<a href="RBMusic/Interval.html#method-i-add">#add</a>
|
111
|
+
—
|
112
|
+
<span class="container">RBMusic::Interval</span>
|
113
|
+
|
114
|
+
<li class="method">
|
115
|
+
<a href="RBMusic/Note.html#method-i-add">#add</a>
|
116
|
+
—
|
117
|
+
<span class="container">RBMusic::Note</span>
|
118
|
+
|
119
|
+
<li class="method">
|
120
|
+
<a href="RBMusic/Scale.html#method-i-degree_count">#degree_count</a>
|
121
|
+
—
|
122
|
+
<span class="container">RBMusic::Scale</span>
|
123
|
+
|
124
|
+
<li class="method">
|
125
|
+
<a href="RBMusic/Note.html#method-i-enharmonic-3F">#enharmonic?</a>
|
126
|
+
—
|
127
|
+
<span class="container">RBMusic::Note</span>
|
128
|
+
|
129
|
+
<li class="method">
|
130
|
+
<a href="RBMusic/Note.html#method-i-enharmonically_equivalent_to-3F">#enharmonically_equivalent_to?</a>
|
131
|
+
—
|
132
|
+
<span class="container">RBMusic::Note</span>
|
133
|
+
|
134
|
+
<li class="method">
|
135
|
+
<a href="RBMusic/Note.html#method-i-frequency">#frequency</a>
|
136
|
+
—
|
137
|
+
<span class="container">RBMusic::Note</span>
|
138
|
+
|
139
|
+
<li class="method">
|
140
|
+
<a href="RBMusic/Note.html#method-i-latin">#latin</a>
|
141
|
+
—
|
142
|
+
<span class="container">RBMusic::Note</span>
|
143
|
+
|
144
|
+
<li class="method">
|
145
|
+
<a href="RBMusic/Scale.html#method-i-notes_in_range">#notes_in_range</a>
|
146
|
+
—
|
147
|
+
<span class="container">RBMusic::Scale</span>
|
148
|
+
|
149
|
+
<li class="method">
|
150
|
+
<a href="RBMusic/Note.html#method-i-octave">#octave</a>
|
151
|
+
—
|
152
|
+
<span class="container">RBMusic::Note</span>
|
153
|
+
|
154
|
+
<li class="method">
|
155
|
+
<a href="RBMusic/Note.html#method-i-scale">#scale</a>
|
156
|
+
—
|
157
|
+
<span class="container">RBMusic::Note</span>
|
158
|
+
|
159
|
+
<li class="method">
|
160
|
+
<a href="RBMusic/Interval.html#method-i-semitone">#semitone</a>
|
161
|
+
—
|
162
|
+
<span class="container">RBMusic::Interval</span>
|
163
|
+
|
164
|
+
<li class="method">
|
165
|
+
<a href="RBMusic/Interval.html#method-i-subtract">#subtract</a>
|
166
|
+
—
|
167
|
+
<span class="container">RBMusic::Interval</span>
|
168
|
+
|
169
|
+
<li class="method">
|
170
|
+
<a href="RBMusic/Note.html#method-i-subtract">#subtract</a>
|
171
|
+
—
|
172
|
+
<span class="container">RBMusic::Note</span>
|
173
|
+
|
174
|
+
<li class="method">
|
175
|
+
<a href="RBMusic/NoteSet.html#method-i-subtract">#subtract</a>
|
176
|
+
—
|
177
|
+
<span class="container">RBMusic::NoteSet</span>
|
178
|
+
|
179
|
+
<li class="method">
|
180
|
+
<a href="RBMusic/Interval.html#method-i-tone_semitone">#tone_semitone</a>
|
181
|
+
—
|
182
|
+
<span class="container">RBMusic::Interval</span>
|
183
|
+
</ul>
|
184
|
+
</main>
|
185
|
+
|
186
|
+
|
187
|
+
<footer id="validator-badges" role="contentinfo">
|
188
|
+
<p><a href="http://validator.w3.org/check/referer">Validate</a>
|
189
|
+
<p>Generated by <a href="http://rdoc.rubyforge.org">RDoc</a> 4.1.1.
|
190
|
+
<p>Based on <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>.
|
191
|
+
</footer>
|
192
|
+
|
data/lib/motion-music.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise "This file must be required within a RubyMotion project Rakefile."
|
3
|
+
end
|
4
|
+
|
5
|
+
Motion::Project::App.setup do |app|
|
6
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'rb-music/*.rb')).each do |file|
|
7
|
+
app.files.unshift(file)
|
8
|
+
end
|
9
|
+
end
|
data/lib/rb-music.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
module RBMusic
|
2
|
+
Error = Class.new(StandardError)
|
3
|
+
ArgumentError = Class.new(ArgumentError)
|
4
|
+
|
5
|
+
NOTE_NAMES = ["F", "C", "G", "D", "A", "E", "B"]
|
6
|
+
ACCIDENTALS = ["bb", "b", "", "#", "x"]
|
7
|
+
|
8
|
+
# notes - two dimensional [octave, fifth] - relative to the 'main' note
|
9
|
+
NOTES = {
|
10
|
+
"Fbb" => [10, -17],
|
11
|
+
"Cbb" => [10, -16],
|
12
|
+
"Gbb" => [9, -15],
|
13
|
+
"Dbb" => [8, -14],
|
14
|
+
"Abb" => [8, -13],
|
15
|
+
"Ebb" => [7, -12],
|
16
|
+
"Bbb" => [7, -11],
|
17
|
+
|
18
|
+
"Fb" => [6, -10],
|
19
|
+
"Cb" => [5, -9],
|
20
|
+
"Gb" => [5, -8],
|
21
|
+
"Db" => [4, -7],
|
22
|
+
"Ab" => [4, -6],
|
23
|
+
"Eb" => [3, -5],
|
24
|
+
"Bb" => [3, -4],
|
25
|
+
|
26
|
+
"F" => [2, -3],
|
27
|
+
"C" => [1, -2],
|
28
|
+
"G" => [1, -1],
|
29
|
+
"D" => [0, 0],
|
30
|
+
"A" => [0, 1],
|
31
|
+
"E" => [-1, 2],
|
32
|
+
"B" => [-1, 3],
|
33
|
+
|
34
|
+
"F#" => [-2, 4],
|
35
|
+
"C#" => [-3, 5],
|
36
|
+
"G#" => [-3, 6],
|
37
|
+
"D#" => [-4, 7],
|
38
|
+
"A#" => [-4, 8],
|
39
|
+
"E#" => [-5, 9],
|
40
|
+
"B#" => [-5, 10],
|
41
|
+
|
42
|
+
"Fx" => [-6, 11],
|
43
|
+
"Cx" => [-7, 12],
|
44
|
+
"Gx" => [-7, 13],
|
45
|
+
"Dx" => [-8, 14],
|
46
|
+
"Ax" => [-8, 15],
|
47
|
+
"Ex" => [-9, 16],
|
48
|
+
"Bx" => [-10, 17]
|
49
|
+
}
|
50
|
+
|
51
|
+
BASE_FREQ = 440 # A4 'main' note
|
52
|
+
BASE_OFFSET = [4, 1] # offset of base note from D0
|
53
|
+
|
54
|
+
# intervals - two dimensional [octave, fifth] - relative to the 'main' note
|
55
|
+
INTERVALS = {
|
56
|
+
unison: [0, 0],
|
57
|
+
minor_second: [3, -5],
|
58
|
+
major_second: [-1, 2],
|
59
|
+
minor_third: [2, -3],
|
60
|
+
major_third: [-2, 4],
|
61
|
+
fourth: [1, -1],
|
62
|
+
augmented_fourth: [-3, 6],
|
63
|
+
tritone: [-3, 6],
|
64
|
+
diminished_fifth: [4, -6],
|
65
|
+
fifth: [0, 1],
|
66
|
+
minor_sixth: [3, -4],
|
67
|
+
major_sixth: [-1, 3],
|
68
|
+
minor_seventh: [2, -2],
|
69
|
+
major_seventh: [-2, 5],
|
70
|
+
octave: [1, 0]
|
71
|
+
}
|
72
|
+
|
73
|
+
INTERVALS_SEMITONES = {
|
74
|
+
0 => [0, 0],
|
75
|
+
1 => [3, -5],
|
76
|
+
2 => [-1, 2],
|
77
|
+
3 => [2, -3],
|
78
|
+
4 => [-2, 4],
|
79
|
+
5 => [1, -1],
|
80
|
+
6 => [-3, 6],
|
81
|
+
7 => [0, 1],
|
82
|
+
8 => [3, -4],
|
83
|
+
9 => [-1, 3],
|
84
|
+
10 => [2, -2],
|
85
|
+
11 => [-2, 5],
|
86
|
+
12 => [1, 0]
|
87
|
+
}
|
88
|
+
|
89
|
+
SCALES = {
|
90
|
+
major: [:major_second, :major_third, :fourth, :fifth, :major_sixth, :major_seventh],
|
91
|
+
natural_minor: [:major_second, :minor_third, :fourth, :fifth, :minor_sixth, :minor_seventh],
|
92
|
+
harmonic_minor: [:major_second, :minor_third, :fourth, :fifth, :minor_sixth, :major_seventh],
|
93
|
+
major_pentatonic: [:major_second, :major_third, :fifth, :major_sixth],
|
94
|
+
minor_pentatonic: [:minor_third, :fourth, :fifth, :minor_seventh],
|
95
|
+
blues: [:minor_third, :fourth, :augmented_fourth, :fifth, :minor_seventh],
|
96
|
+
dorian: [:major_second, :minor_third, :fourth, :fifth, :major_sixth, :minor_seventh],
|
97
|
+
phrygian: [:minor_second, :minor_third, :fourth, :fifth, :major_sixth, :minor_seventh],
|
98
|
+
lydian: [:major_second, :major_third, :augmented_fourth, :fifth, :major_sixth, :major_seventh],
|
99
|
+
mixolydian: [:major_second, :major_third, :fourth, :fifth, :major_sixth, :minor_seventh],
|
100
|
+
locrian: [:minor_second, :minor_third, :fourth, :diminished_fifth, :minor_sixth, :minor_seventh],
|
101
|
+
}
|
102
|
+
SCALES[:ionian] = SCALES[:major]
|
103
|
+
SCALES[:aeolian] = SCALES[:natural_minor]
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module RBMusic
|
2
|
+
|
3
|
+
class Interval
|
4
|
+
attr_accessor :coord
|
5
|
+
|
6
|
+
def initialize(coord)
|
7
|
+
self.coord = coord
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.from_name(name)
|
11
|
+
Interval.new(INTERVALS[name.to_sym])
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.from_semitones(num)
|
15
|
+
Interval.new(INTERVALS_SEMITONES[num])
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.from_tones_semitones(tone_semitone)
|
19
|
+
# multiply [tones, semitones] vector with [-1 2;3 -5] to get coordinate from tones and semitones
|
20
|
+
Interval.new([tone_semitone[0] * -1 + tone_semitone[1] * 3, tone_semitone[0] * 2 + tone_semitone[1] * -5])
|
21
|
+
end
|
22
|
+
|
23
|
+
def tone_semitone
|
24
|
+
# multiply coord vector with [5 2;3 1] to get coordinate in tones and semitones
|
25
|
+
# [5 2;3 1] is the inverse of [-1 2;3 -5], which is the coordinates of [tone; semitone]
|
26
|
+
@tone_semitone ||= [coord[0] * 5 + coord[1] * 3, coord[0] * 2 + coord[1] * 1]
|
27
|
+
end
|
28
|
+
|
29
|
+
def semitone
|
30
|
+
# number of semitones of interval = tones * 2 + semitones
|
31
|
+
tone_semitone[0] * 2 + tone_semitone[1]
|
32
|
+
end
|
33
|
+
|
34
|
+
def add(interval)
|
35
|
+
if interval.is_a?(String)
|
36
|
+
interval = Interval.from_name(interval)
|
37
|
+
end
|
38
|
+
Interval.new([coord[0] + interval.coord[0], coord[1] + interval.coord[1]])
|
39
|
+
end
|
40
|
+
|
41
|
+
def subtract(interval)
|
42
|
+
if interval.is_a?(String)
|
43
|
+
interval = Interval.from_name(interval)
|
44
|
+
end
|
45
|
+
Interval.new([coord[0] - interval.coord[0], coord[1] - interval.coord[1]])
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module RBMusic
|
2
|
+
|
3
|
+
class Note
|
4
|
+
attr_accessor :coord
|
5
|
+
|
6
|
+
def initialize(coord)
|
7
|
+
self.coord = coord
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.from_latin(name)
|
11
|
+
raise ArgumentError unless name.is_a?(String)
|
12
|
+
|
13
|
+
note_parts = name.split(/(\d+)/)
|
14
|
+
note_name = note_parts.first
|
15
|
+
octave = note_parts.last.to_i
|
16
|
+
|
17
|
+
unless NOTES.has_key?(note_name) && note_parts.size < 3
|
18
|
+
raise ArgumentError
|
19
|
+
end
|
20
|
+
|
21
|
+
coordinate = [NOTES[note_name][0] + octave, NOTES[note_name][1]]
|
22
|
+
|
23
|
+
coordinate[0] -= BASE_OFFSET[0]
|
24
|
+
coordinate[1] -= BASE_OFFSET[1]
|
25
|
+
|
26
|
+
Note.new(coordinate)
|
27
|
+
end
|
28
|
+
|
29
|
+
def frequency
|
30
|
+
BASE_FREQ * (2.0 ** ((coord[0] * 1200 + coord[1] * 700.0) / 1200.0))
|
31
|
+
end
|
32
|
+
|
33
|
+
def accidental
|
34
|
+
@accidental ||= ((coord[1] + BASE_OFFSET[1]) / 7.0).round
|
35
|
+
end
|
36
|
+
|
37
|
+
def octave
|
38
|
+
# calculate octave of base note without accidentals
|
39
|
+
@octave ||= coord[0] + BASE_OFFSET[0] + 4 * accidental + ((coord[1] + BASE_OFFSET[1] - 7 * accidental) / 2).floor
|
40
|
+
end
|
41
|
+
|
42
|
+
def latin
|
43
|
+
return @latin if @latin
|
44
|
+
accidentalName = ACCIDENTALS[accidental + 2]
|
45
|
+
@latin ||= base_note_name + accidentalName
|
46
|
+
end
|
47
|
+
|
48
|
+
def ==(other)
|
49
|
+
other.is_a?(Note) && other.latin == latin && other.octave == octave
|
50
|
+
end
|
51
|
+
|
52
|
+
def enharmonic?(other)
|
53
|
+
raise ArgumentError unless other.is_a?(Note)
|
54
|
+
|
55
|
+
other.frequency == frequency
|
56
|
+
end
|
57
|
+
alias_method :enharmonically_equivalent_to?, :enharmonic?
|
58
|
+
|
59
|
+
def midi_note_number
|
60
|
+
# see http://www.phys.unsw.edu.au/jw/notes.html
|
61
|
+
12 * Math.log2(frequency / 440) + 69
|
62
|
+
end
|
63
|
+
|
64
|
+
def scale(name, octaves = 1)
|
65
|
+
NoteSet.from_scale(Scale.new(latin, name), octave, octaves)
|
66
|
+
end
|
67
|
+
|
68
|
+
def add(that)
|
69
|
+
# if input is an array return an array
|
70
|
+
if that.is_a?(Array)
|
71
|
+
notes = that.map { |thing| add(thing) }
|
72
|
+
return NoteSet.new(notes)
|
73
|
+
end
|
74
|
+
|
75
|
+
# if input is string/symbol try to parse it as interval
|
76
|
+
if that.is_a?(String) || that.is_a?(Symbol)
|
77
|
+
that = Interval.from_name(that)
|
78
|
+
end
|
79
|
+
|
80
|
+
Note.new([coord[0] + that.coord[0], coord[1] + that.coord[1]])
|
81
|
+
end
|
82
|
+
|
83
|
+
def subtract(that)
|
84
|
+
if that.is_a?(Array)
|
85
|
+
notes = that.map { |thing| subtract(thing) }
|
86
|
+
return NoteSet.new(notes)
|
87
|
+
end
|
88
|
+
|
89
|
+
# if input is string try to parse it as interval
|
90
|
+
if that.is_a?(String) || that.is_a?(Symbol)
|
91
|
+
that = Interval.from_name(that)
|
92
|
+
end
|
93
|
+
|
94
|
+
coordinate = [coord[0] - that.coord[0], coord[1] - that.coord[1]]
|
95
|
+
|
96
|
+
# if input is another note return the difference as an Interval
|
97
|
+
that.is_a?(Note) ? Interval.new(coordinate) : Note.new(coordinate)
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def base_note_name
|
103
|
+
@base_note_name ||= NOTE_NAMES[coord[1] + BASE_OFFSET[1] - accidental * 7 + 3]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|