motion-music 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|