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.
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