motion-music 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/Gemfile +8 -0
  4. data/Guardfile +6 -0
  5. data/LICENSE +23 -0
  6. data/README.md +53 -0
  7. data/doc/Gemfile.html +111 -0
  8. data/doc/Gemfile_lock.html +168 -0
  9. data/doc/Guardfile.html +111 -0
  10. data/doc/LICENSE.html +124 -0
  11. data/doc/Object.html +116 -0
  12. data/doc/RBMusic.html +164 -0
  13. data/doc/RBMusic/Interval.html +440 -0
  14. data/doc/RBMusic/Note.html +620 -0
  15. data/doc/RBMusic/NoteSet.html +277 -0
  16. data/doc/RBMusic/Scale.html +274 -0
  17. data/doc/README_md.html +163 -0
  18. data/doc/created.rid +8 -0
  19. data/doc/fonts.css +167 -0
  20. data/doc/fonts/Lato-Light.ttf +0 -0
  21. data/doc/fonts/Lato-LightItalic.ttf +0 -0
  22. data/doc/fonts/Lato-Regular.ttf +0 -0
  23. data/doc/fonts/Lato-RegularItalic.ttf +0 -0
  24. data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
  25. data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
  26. data/doc/images/add.png +0 -0
  27. data/doc/images/arrow_up.png +0 -0
  28. data/doc/images/brick.png +0 -0
  29. data/doc/images/brick_link.png +0 -0
  30. data/doc/images/bug.png +0 -0
  31. data/doc/images/bullet_black.png +0 -0
  32. data/doc/images/bullet_toggle_minus.png +0 -0
  33. data/doc/images/bullet_toggle_plus.png +0 -0
  34. data/doc/images/date.png +0 -0
  35. data/doc/images/delete.png +0 -0
  36. data/doc/images/find.png +0 -0
  37. data/doc/images/loadingAnimation.gif +0 -0
  38. data/doc/images/macFFBgHack.png +0 -0
  39. data/doc/images/package.png +0 -0
  40. data/doc/images/page_green.png +0 -0
  41. data/doc/images/page_white_text.png +0 -0
  42. data/doc/images/page_white_width.png +0 -0
  43. data/doc/images/plugin.png +0 -0
  44. data/doc/images/ruby.png +0 -0
  45. data/doc/images/tag_blue.png +0 -0
  46. data/doc/images/tag_green.png +0 -0
  47. data/doc/images/transparent.png +0 -0
  48. data/doc/images/wrench.png +0 -0
  49. data/doc/images/wrench_orange.png +0 -0
  50. data/doc/images/zoom.png +0 -0
  51. data/doc/index.html +93 -0
  52. data/doc/js/darkfish.js +140 -0
  53. data/doc/js/jquery.js +18 -0
  54. data/doc/js/navigation.js +142 -0
  55. data/doc/js/search.js +109 -0
  56. data/doc/js/search_index.js +1 -0
  57. data/doc/js/searcher.js +228 -0
  58. data/doc/projections_json.html +115 -0
  59. data/doc/rb-music_gemspec.html +132 -0
  60. data/doc/rdoc.css +580 -0
  61. data/doc/table_of_contents.html +192 -0
  62. data/lib/motion-music.rb +9 -0
  63. data/lib/motion-music/version.rb +3 -0
  64. data/lib/rb-music.rb +8 -0
  65. data/lib/rb-music/constants.rb +105 -0
  66. data/lib/rb-music/interval.rb +50 -0
  67. data/lib/rb-music/note.rb +107 -0
  68. data/lib/rb-music/note_set.rb +61 -0
  69. data/lib/rb-music/scale.rb +30 -0
  70. data/lib/rb-music/version.rb +3 -0
  71. data/motion-music.gemspec +20 -0
  72. data/projections.json +12 -0
  73. data/rb-music.gemspec +29 -0
  74. data/spec/rb-music/constants_spec.rb +27 -0
  75. data/spec/rb-music/interval_spec.rb +90 -0
  76. data/spec/rb-music/note_set_spec.rb +191 -0
  77. data/spec/rb-music/note_spec.rb +318 -0
  78. data/spec/rb-music/scale_spec.rb +88 -0
  79. data/spec/spec_helper.rb +14 -0
  80. metadata +124 -0
@@ -0,0 +1,61 @@
1
+ module RBMusic
2
+
3
+ class NoteSet
4
+ include Enumerable
5
+
6
+ attr_accessor :notes
7
+
8
+ def initialize(notes = [])
9
+ @notes = notes
10
+ end
11
+
12
+ def self.from_scale(scale, octave=0, octaves=1)
13
+ raise ArgumentError unless scale.is_a?(Scale) && octaves > 0
14
+
15
+ root_note = Note.from_latin("#{scale.key}#{octave}")
16
+ notes = []
17
+ octaves.times do |i|
18
+ notes += scale.degrees.map do |interval_name|
19
+ note = root_note.add(interval_name)
20
+ i.times do |octave_offset|
21
+ note = note.add(:octave)
22
+ end
23
+ note
24
+ end
25
+ end
26
+
27
+ self.new(notes)
28
+ end
29
+
30
+ def each(&block)
31
+ @notes.each(&block)
32
+ end
33
+
34
+ def [](index)
35
+ @notes[index]
36
+ end
37
+
38
+ def <<(other)
39
+ @notes << other
40
+ end
41
+
42
+ def map(&block)
43
+ @notes.map(&block)
44
+ end
45
+
46
+ def ==(other)
47
+ @notes == other.notes
48
+ end
49
+ alias_method :eql?, :==
50
+
51
+ def add(that)
52
+ NoteSet.new(@notes.map { |note| note.add(that) })
53
+ end
54
+
55
+ def subtract(that)
56
+ NoteSet.new(@notes.map { |note| note.subtract(that) })
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,30 @@
1
+ module RBMusic
2
+
3
+ class Scale
4
+ attr_reader :key
5
+ attr_reader :degrees
6
+
7
+ def initialize(key, name)
8
+ @scale_name = name.to_sym
9
+ raise ArgumentError unless NOTES.has_key?(key)
10
+ raise ArgumentError unless SCALES.has_key?(@scale_name)
11
+ @key = key
12
+ @degrees = [:unison] + SCALES[@scale_name]
13
+ end
14
+
15
+ def degree_count
16
+ @degree_count ||= @degrees.size
17
+ end
18
+ alias_method :size, :degree_count
19
+
20
+ def name
21
+ @name ||= "#{key} #{human_scale_name}"
22
+ end
23
+
24
+ private
25
+ def human_scale_name
26
+ @scale_name.to_s.split("_").map { |word| word.capitalize }.join(" ")
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,3 @@
1
+ module RBMusic
2
+ VERSION = "0.0.1" unless defined? RBMusic::VERSION
3
+ end
@@ -0,0 +1,20 @@
1
+ $LOAD_PATH.push File.expand_path("../lib", __FILE__)
2
+ require "motion-music/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "motion-music"
6
+ s.version = MotionMusic::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.license = "MIT"
9
+ s.summary = "Music theory library for RubyMotion"
10
+ s.description = "This gem wraps the rb-music gem to provide RubyMotion classes for working with musical notes, scales and intervals."
11
+ s.author = "Mark Wise"
12
+ s.authors = ["Mark Wise"]
13
+ s.email = ["markmediadude@mgail.comm"]
14
+ s.files = `git ls-files`.split($\)
15
+ s.homepage = "https://rubygems.org/mwise/motion-music"
16
+
17
+ s.require_paths = ["lib"]
18
+
19
+ s.extra_rdoc_files = ['README.md']
20
+ end
data/projections.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "lib/rb-music/*.rb": {
3
+ "command": "sources",
4
+ "alternate": "./spec/rb-music/%s_spec.rb",
5
+ "reverse_layout": false
6
+ },
7
+ "spec/rb-music/*_spec.rb": {
8
+ "command": "specs",
9
+ "alternate": "./lib/rb-music/%s.rb",
10
+ "reverse_layout": true
11
+ }
12
+ }
data/rb-music.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ $LOAD_PATH.push File.expand_path("../lib", __FILE__)
2
+ require "rb-music/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "rb-music"
6
+ s.version = RBMusic::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.license = "MIT"
9
+ s.summary = "Music theory library for Ruby"
10
+ s.description = "This gem provides Ruby classes for working with musical notes, scales and intervals."
11
+ s.author = "Mark Wise"
12
+ s.authors = ["Mark Wise"]
13
+ s.email = ["markmediadude@mgail.comm"]
14
+ s.files = ["lib/rb-music.rb"]
15
+ s.homepage = "https://rubygems.org/mwise/rb-music"
16
+
17
+ s.require_paths = ["lib"]
18
+ s.required_ruby_version = ">= 1.8.6"
19
+ s.files = `git ls-files -- lib/*`.split("\n")
20
+ s.files += %w[README.md LICENSE]
21
+ s.test_files = `git ls-files -- spec/*`.split("\n")
22
+
23
+ s.extra_rdoc_files = ['README.md']
24
+
25
+ s.add_development_dependency("guard-rspec")
26
+ s.add_development_dependency("rake")
27
+ s.add_development_dependency("rspec")
28
+ s.add_development_dependency("simplecov")
29
+ end
@@ -0,0 +1,27 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe "RBMusic Constants" do
4
+
5
+ describe RBMusic::NOTE_NAMES do
6
+ it "is correct" do
7
+ subject.should == ["F", "C", "G", "D", "A", "E", "B"]
8
+ end
9
+ end
10
+
11
+ describe RBMusic::ACCIDENTALS do
12
+ it "is correct" do
13
+ subject.should == ["bb", "b", "", "#", "x"]
14
+ end
15
+ end
16
+
17
+ describe RBMusic::NOTES do
18
+ it "contains a key for each note/accidental combination" do
19
+ RBMusic::NOTE_NAMES.each do |note_name|
20
+ ACCIDENTALS.each do |accidental|
21
+ NOTES.should have_key("#{note_name}#{accidental}")
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,90 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe RBMusic::Interval do
4
+
5
+ context "after initialization" do
6
+ let(:subject) { described_class.new("some coord") }
7
+
8
+ it "assigns the coord argument" do
9
+ subject.coord.should == "some coord"
10
+ end
11
+ end
12
+
13
+ describe "class methods" do
14
+ describe "#from_name" do
15
+ it "looks up the correct coordinates" do
16
+ subject = described_class.from_name("major_second")
17
+
18
+ subject.coord.should == described_class::INTERVALS[:major_second]
19
+ end
20
+ end
21
+
22
+ describe "#from_semitones" do
23
+ it "looks up the correct coordinates" do
24
+ subject = described_class.from_semitones(3)
25
+
26
+ subject.coord.should == described_class::INTERVALS_SEMITONES[3]
27
+ end
28
+ end
29
+
30
+ describe "#from_tones_semitones" do
31
+ it "looks up the correct coordinates" do
32
+ subject = described_class.from_tones_semitones([0, 3])
33
+
34
+ subject.coord.should == [9, -15]
35
+ end
36
+ end
37
+ end
38
+
39
+ describe "instance methods" do
40
+ let(:subject) { described_class.from_name("major_second") }
41
+
42
+ describe "#tone_semitone" do
43
+ it "returns the tone / semitone vector" do
44
+ subject.tone_semitone.should == [1, 0]
45
+ end
46
+ end
47
+
48
+ describe "#semitone" do
49
+ it "returns number of semitones" do
50
+ subject.semitone.should == 2
51
+ end
52
+ end
53
+
54
+ describe "#add" do
55
+ context "when given a string" do
56
+ it "adds the string as an Interval" do
57
+ result = subject.add("major_second")
58
+ result.coord.should == Interval.from_name("major_third").coord
59
+ end
60
+ end
61
+
62
+ context "when given an Interval" do
63
+ it "adds the given Interval's coordinates and returns a new Interval" do
64
+ result = subject.add(described_class.from_name("minor_second"))
65
+ result.coord.should == Interval.from_name("minor_third").coord
66
+ end
67
+ end
68
+ end
69
+
70
+ describe "#subtract" do
71
+ context "when given a string" do
72
+ it "returns a Interval with the given string as Interval subtracted" do
73
+ result = subject.subtract("major_second")
74
+ result.coord.should == Interval.from_name("unison").coord
75
+ end
76
+ end
77
+
78
+ context "when given an Interval" do
79
+ it "subtracts the coordinates of the given Interval and returns a new Interval" do
80
+ subject = described_class.from_name("major_third")
81
+ result = subject.subtract(described_class.from_name("major_second"))
82
+
83
+ result.coord.should == Interval.from_name("major_second").coord
84
+ end
85
+ end
86
+ end
87
+
88
+ end
89
+
90
+ end
@@ -0,0 +1,191 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe RBMusic::NoteSet do
4
+
5
+ describe "class methods" do
6
+ describe "#from_scale" do
7
+ let(:scale) { RBMusic::Scale.new("C", "major") }
8
+
9
+ context "without any arguments" do
10
+ it "raises an ArgumentError" do
11
+ lambda {
12
+ described_class.from_scale
13
+ }.should raise_error(ArgumentError)
14
+ end
15
+ end
16
+
17
+ context "without a valid RBMusic::Scale" do
18
+ it "raises an ArgumentError" do
19
+ lambda {
20
+ described_class.from_scale("foo")
21
+ }.should raise_error(RBMusic::ArgumentError)
22
+ end
23
+ end
24
+
25
+ context "with a RBMusic::Scale only" do
26
+ let(:subject) { described_class.from_scale(scale) }
27
+
28
+ it "returns a #{described_class}" do
29
+ subject.should be_a(described_class)
30
+ end
31
+
32
+ it "builds a note for each scale degree in the default octave ranage (1)" do
33
+ subject.notes.length.should == scale.degree_count
34
+ end
35
+
36
+ it "builds notes from the default octave (0)" do
37
+ subject.notes[0].should == Note.from_latin("#{scale.key}0")
38
+ end
39
+ end
40
+
41
+ context "with a RBMusic::Scale and an octave" do
42
+ let(:octave) { 3 }
43
+ let(:subject) { described_class.from_scale(scale, octave) }
44
+
45
+ it "builds notes for the scale from the given octave" do
46
+ subject.notes[0].should == Note.from_latin("#{scale.key}#{octave}")
47
+ subject.notes.length.should == scale.degree_count
48
+ end
49
+ end
50
+
51
+ context "with a RBMusic::Scale, octave and octave range" do
52
+ let(:octave) { 3 }
53
+ let(:octaves) { 2 }
54
+ let(:subject) { described_class.from_scale(scale, octave, octaves) }
55
+
56
+ it "builds notes for the given octave range" do
57
+ degrees = scale.degree_count
58
+
59
+ subject.notes[0].should == Note.from_latin("#{scale.key}#{octave}")
60
+ subject.notes[degrees].should == Note.from_latin("#{scale.key}#{octave + 1}")
61
+ subject.notes.length.should == scale.degree_count * octaves
62
+ end
63
+ end
64
+
65
+ context "with an invalid octave range" do
66
+ it "raises an ArgumentError" do
67
+ lambda {
68
+ described_class.from_scale(scale, 3, -1)
69
+ }.should raise_exception(RBMusic::ArgumentError)
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ describe "instance methods" do
76
+
77
+ describe "#initialize" do
78
+ let(:notes_array) { ["foo", "bar"] }
79
+
80
+ it "assigns the notes array" do
81
+ subject = described_class.new(notes_array)
82
+
83
+ subject.notes.should == notes_array
84
+ end
85
+ end
86
+
87
+ describe "#==" do
88
+ let(:notes) { ["foo", "bar"] }
89
+
90
+ context "when all the notes are equal" do
91
+ it "is true" do
92
+ described_class.new(notes).should == described_class.new(notes)
93
+ end
94
+ end
95
+
96
+ context "when note all the notes are equal" do
97
+ it "is false" do
98
+ described_class.new(notes).should_not == described_class.new([1, 2])
99
+ end
100
+ end
101
+ end
102
+
103
+ describe "#add" do
104
+ let(:f4) { Note.from_latin("F4") }
105
+ let(:g4) { Note.from_latin("G4") }
106
+ let(:subject) { NoteSet.new([f4, g4]) }
107
+
108
+ context "when adding an interval string" do
109
+ let(:operand) { "major_second" }
110
+
111
+ it "retuns a new NoteSet with the operand added to each element of the original" do
112
+ result = subject.add(operand)
113
+
114
+ result.should be_a(NoteSet)
115
+ result[0].frequency.should == subject[0].add(operand).frequency
116
+ result[1].frequency.should == subject[1].add(operand).frequency
117
+ end
118
+ end
119
+
120
+ context "when adding an interval symbol" do
121
+ let(:operand) { :major_second }
122
+
123
+ it "retuns a new NoteSet with the operand added to each element of the original" do
124
+ result = subject.add(operand)
125
+
126
+ result.should be_a(NoteSet)
127
+ result[0].frequency.should == subject[0].add(operand).frequency
128
+ result[1].frequency.should == subject[1].add(operand).frequency
129
+ end
130
+ end
131
+
132
+ context "when adding an note" do
133
+ let(:operand) { Note.from_latin("C4") }
134
+
135
+ it "retuns a new NoteSet with the operand added to each element of the original" do
136
+ result = subject.add(operand)
137
+
138
+ result.should be_a(NoteSet)
139
+ result[0].frequency.should == subject[0].add(operand).frequency
140
+ result[1].frequency.should == subject[1].add(operand).frequency
141
+ end
142
+ end
143
+
144
+ end
145
+
146
+ describe "#subtract" do
147
+ let(:f4) { Note.from_latin("F4") }
148
+ let(:g4) { Note.from_latin("G4") }
149
+ let(:subject) { NoteSet.new([f4, g4]) }
150
+
151
+ context "when subtracting an interval string" do
152
+ let(:operand) { "major_second" }
153
+
154
+ it "retuns a new NoteSet with the operand subtracted to each element of the original" do
155
+ result = subject.subtract(operand)
156
+
157
+ result.should be_a(NoteSet)
158
+ result[0].frequency.should == subject[0].subtract(operand).frequency
159
+ result[1].frequency.should == subject[1].subtract(operand).frequency
160
+ end
161
+ end
162
+
163
+ context "when subtracting an interval symbol" do
164
+ let(:operand) { :major_second }
165
+
166
+ it "retuns a new NoteSet with the operand subtracted to each element of the original" do
167
+ result = subject.subtract(operand)
168
+
169
+ result.should be_a(NoteSet)
170
+ result[0].frequency.should == subject[0].subtract(operand).frequency
171
+ result[1].frequency.should == subject[1].subtract(operand).frequency
172
+ end
173
+ end
174
+
175
+ context "when subtracting an note" do
176
+ let(:operand) { Note.from_latin("C4") }
177
+
178
+ it "retuns a new NoteSet with the operand subtracted to each element of the original" do
179
+ result = subject.subtract(operand)
180
+
181
+ result.should be_a(NoteSet)
182
+ result[0].coord.should == subject[0].subtract(operand).coord
183
+ result[1].coord.should == subject[1].subtract(operand).coord
184
+ end
185
+ end
186
+
187
+ end
188
+
189
+ end
190
+
191
+ end