music 0.5.1 → 0.6.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.
data/.gitignore CHANGED
@@ -45,4 +45,6 @@ pkg
45
45
  #.redcar
46
46
 
47
47
  # For rubinius:
48
- #*.rbc
48
+ *.rbc
49
+ *.rbx
50
+
data/Gemfile CHANGED
@@ -1,2 +1,8 @@
1
1
  source "http://rubygems.org"
2
2
  gemspec
3
+
4
+ group :development do
5
+ gem 'guard-bundler'
6
+ gem 'guard-rspec'
7
+ gem 'rb-fsevent', '~> 0.9.1'
8
+ end
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- music (0.5.0)
4
+ music (0.5.1)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
@@ -13,10 +13,29 @@ GEM
13
13
  i18n (~> 0.6)
14
14
  multi_json (~> 1.0)
15
15
  builder (3.0.0)
16
+ coderay (1.0.8)
16
17
  diff-lcs (1.1.3)
18
+ guard (1.5.3)
19
+ listen (>= 0.4.2)
20
+ lumberjack (>= 1.0.2)
21
+ pry (>= 0.9.10)
22
+ thor (>= 0.14.6)
23
+ guard-bundler (1.0.0)
24
+ bundler (~> 1.0)
25
+ guard (~> 1.1)
26
+ guard-rspec (1.2.1)
27
+ guard (>= 1.1)
17
28
  i18n (0.6.0)
29
+ listen (0.5.3)
30
+ lumberjack (1.0.2)
31
+ method_source (0.8.1)
18
32
  multi_json (1.3.5)
33
+ pry (0.9.10)
34
+ coderay (~> 1.0.5)
35
+ method_source (~> 0.8)
36
+ slop (~> 3.3.1)
19
37
  rake (0.9.2.2)
38
+ rb-fsevent (0.9.2)
20
39
  rspec (2.10.0)
21
40
  rspec-core (~> 2.10.0)
22
41
  rspec-expectations (~> 2.10.0)
@@ -25,6 +44,8 @@ GEM
25
44
  rspec-expectations (2.10.0)
26
45
  diff-lcs (~> 1.1.3)
27
46
  rspec-mocks (2.10.1)
47
+ slop (3.3.3)
48
+ thor (0.16.0)
28
49
 
29
50
  PLATFORMS
30
51
  ruby
@@ -32,6 +53,9 @@ PLATFORMS
32
53
  DEPENDENCIES
33
54
  activemodel (>= 3.2.0)
34
55
  bundler (>= 1.1.3)
56
+ guard-bundler
57
+ guard-rspec
35
58
  music!
36
59
  rake (>= 0.9)
60
+ rb-fsevent (~> 0.9.1)
37
61
  rspec
@@ -0,0 +1,29 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'bundler' do
5
+ watch('Gemfile')
6
+ # Uncomment next line if Gemfile contain `gemspec' command
7
+ # watch(/^.+\.gemspec/)
8
+ end
9
+
10
+ guard 'rspec', :version => 2, :rvm => ['1.9.3', '1.8.7', 'rbx'] do
11
+ watch(%r{^spec/.+_spec\.rb$})
12
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
13
+ watch('spec/spec_helper.rb') { "spec" }
14
+
15
+ # Rails example
16
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
17
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
18
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
19
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
20
+ watch('config/routes.rb') { "spec/routing" }
21
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
22
+
23
+ # Capybara request specs
24
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
25
+
26
+ # Turnip features and steps
27
+ watch(%r{^spec/acceptance/(.+)\.feature$})
28
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
29
+ end
data/README.md CHANGED
@@ -3,6 +3,8 @@ music
3
3
 
4
4
  The *music* gem provides a means on calculating notes and chords.
5
5
 
6
+ [![Build Status](https://travis-ci.org/cheerfulstoic/music.png)](https://travis-ci.org/cheerfulstoic/music)
7
+
6
8
  Examples:
7
9
  ---------
8
10
 
@@ -39,7 +41,17 @@ Describe chords:
39
41
 
40
42
  Chord.new(['C4', 'Eb4', 'Gb4']) # => ['C', :diminished]
41
43
 
42
- *For further usage, see the examples in the spec files*
44
+ *For further usage:*
45
+ * Docs: http://rubydoc.info/github/cheerfulstoic/music/frames
46
+ * See the examples in the spec files
47
+
48
+ TODOs:
49
+ ======
50
+
51
+ * Use the term musical term 'interval' or 'semitones' instead of 'distance' in code
52
+ * 'C-' can be used to represent C minor
53
+ * There can be many versions of chords. See: http://giventowail.com/lessons/evan/the-basics-major-minor-and-power-chords?phpMyAdmin=97715a053dab6cd797cf01c69d7492a4
54
+ * Implement calculation of 'cents'
43
55
 
44
56
  Contributing to music
45
57
  =====================
@@ -1,22 +1,40 @@
1
1
  module Music
2
2
  class Chord
3
+
4
+ def eql?(other_chord)
5
+ @notes == other_chord.notes
6
+ end
7
+ def hash
8
+ @notes.hash
9
+ end
10
+ def ==(other_chord)
11
+ self.eql?(other_chord)
12
+ end
13
+
14
+ attr_reader :notes
15
+
3
16
  def initialize(notes)
4
- @notes = notes.collect do |note|
17
+ raise ArgumentError, 'Chords must have at least two notes' if notes.size < 2
18
+ @notes = Set.new(notes) do |note|
5
19
  if note.is_a?(Note)
6
20
  note
7
21
  else
8
22
  Note.new(note)
9
23
  end
10
- end.sort
24
+ end
11
25
  end
12
26
 
27
+ # Spec and implement
28
+ # def to_i
29
+
13
30
  def note_strings
14
- @notes.collect(&:note_string)
31
+ Set.new(@notes.collect(&:note_string))
15
32
  end
16
33
 
17
34
  def describe
18
- distances = (1...@notes.size).collect do |i|
19
- @notes[0].distance_to(@notes[i])
35
+ note_array = @notes.to_a.sort
36
+ distances = (1...note_array.size).collect do |i|
37
+ note_array[0].distance_to(note_array[i])
20
38
  end
21
39
 
22
40
  quality = case distances
@@ -40,7 +58,50 @@ module Music
40
58
  :augmented_7
41
59
  end
42
60
 
43
- [@notes.first.letter, quality]
61
+ [note_array.first.letter, quality]
62
+ end
63
+
64
+ def to_s
65
+ @notes.to_a.sort.collect(&:to_s).join(' / ')
66
+ end
67
+
68
+ # Give the Nth inversion of the chord which simply adjusts the lowest N notes up by one octive
69
+ #
70
+ # @returns [Chord] The specified inversion of chord
71
+ def inversion(amount)
72
+ raise ArgumentError, "Inversion amount must be greater than or equal to 1" if amount < 1
73
+ raise ArgumentError, "Not enough notes in chord for inversion" if amount >= @notes.size
74
+
75
+ note_array = @notes.to_a.sort
76
+ notes = (0...amount).collect { note_array.shift.adjust_by_semitones(12) }
77
+ Chord.new(notes + note_array)
78
+ end
79
+
80
+ # Calls inversion(1)
81
+ def first_inversion
82
+ self.inversion(1)
83
+ end
84
+
85
+ # Calls inversion(2)
86
+ def second_inversion
87
+ self.inversion(2)
88
+ end
89
+
90
+ # Calls inversion(3)
91
+ def third_inversion
92
+ self.inversion(3)
93
+ end
94
+
95
+ class << self
96
+ def parse_chord_string(chord_string, assumed_octave = nil)
97
+ if note_string_match = chord_string.match(/^([A-Ga-g])([#b]?)([^\d]*)(\d*)$/)
98
+ full_string, note, accidental, interval, octave = note_string_match.to_a
99
+
100
+ raise ArgumentError, 'No octave found and no octave assumed' if note.blank? && assumed_octave.nil?
101
+
102
+ Note.new(note + accidental + octave, assumed_octave).chord(interval)
103
+ end
104
+ end
44
105
  end
45
106
  end
46
107
  end
@@ -16,7 +16,22 @@ module Music
16
16
  def <=>(other_note)
17
17
  self.frequency <=> other_note.frequency
18
18
  end
19
+ def hash
20
+ self.frequency.hash
21
+ end
22
+ def eql?(other_note)
23
+ self.frequency == other_note.frequency
24
+ end
25
+
26
+ def to_s
27
+ self.note_string
28
+ end
19
29
 
30
+ # Creates a new note
31
+ #
32
+ # @param [String, Numeric] descriptor Either a string describing the note (e.g. 'C#4') or a number giving the note's frequency (e.g. 440)
33
+ # @param [Numeric, nil] assumed_octave If no octive is given in the descriptor, use this
34
+ # @returns [Note] Note specified
20
35
  def initialize(descriptor, assumed_octave = nil)
21
36
  self.frequency = if descriptor.is_a? Numeric
22
37
  Note.nearest_note_frequency(descriptor)
@@ -25,35 +40,214 @@ module Music
25
40
  end
26
41
  end
27
42
 
43
+ # Returns string representing note with letter, accidental, and octave number
44
+ # e.g. 'C#5'
45
+ #
46
+ # @param [boolean] give_flat Should the result give a flat? (defults to giving a sharp)
47
+ # @return [String] The resulting note string
28
48
  def note_string(give_flat = false)
29
49
  Note.calculate_note(self.frequency, give_flat).join
30
50
  end
31
51
 
52
+ # Returns the letter portion of the note
53
+ # e.g. 'C'
54
+ #
55
+ # @param [boolean] give_flat Should the result be based on giving a flat? (defaults to giving a sharp)
56
+ # @return [String] The resulting note letter
32
57
  def letter(give_flat = false)
33
58
  Note.calculate_note(self.frequency, give_flat)[0]
34
59
  end
35
60
 
61
+ # Returns the accidental portion of the note
62
+ # e.g. '#' or 'b'
63
+ #
64
+ # @param [boolean] give_flat Should the result give a flat? (defaults to giving a sharp)
65
+ # @return [String] The resulting accidental
36
66
  def accidental(give_flat = false)
37
67
  Note.calculate_note(self.frequency, give_flat)[1]
38
68
  end
39
69
 
70
+ # Returns the octive number of the note
71
+ # e.g. 4
72
+ #
73
+ # @return [Fixnum] The resulting octive number
40
74
  def octave
41
75
  Note.calculate_note(self.frequency)[2]
42
76
  end
43
77
 
44
- def pred
78
+ # Return the previous note (adjusted by one semitone down)
79
+ #
80
+ # @return [Note] The previous note
81
+ def prev
45
82
  Note.new(Note.frequency_adjustment(self.frequency, -1))
46
83
  end
47
84
 
85
+ # Return the next note (adjusted by one semitone up)
86
+ #
87
+ # @return [Note] The next note
48
88
  def succ
49
89
  Note.new(Note.frequency_adjustment(self.frequency, 1))
50
90
  end
51
91
  alias :next :succ
52
92
 
93
+ # Return the distance (in semitones) to a note
94
+ #
95
+ # @return [Fixnum] Number of semitones
53
96
  def distance_to(note)
54
97
  Note.note_distance(self.note_string, note.note_string)
55
98
  end
56
99
 
100
+ # Return another note adjusted by a given interval
101
+ #
102
+ # @param [Fixnum] interval Number of semitones to adjust by
103
+ # @return [Note] Resulting note after adjustment
104
+ def adjust_by_semitones(interval)
105
+ Note.new(Note.frequency_adjustment(self.frequency, interval))
106
+ end
107
+
108
+ {
109
+ :minor_second => 1,
110
+ :major_second => 2,
111
+
112
+ :minor_third => 3,
113
+ :major_third => 4,
114
+
115
+ :perfect_fourth => 5,
116
+
117
+ :tritone => 6, :diminished_fifth => 6, :flat_fifth => 6, :augmented_fourth => 6,
118
+ :perfect_fifth => 7,
119
+ :augmented_fifth => 8, :minor_sixth => 8,
120
+
121
+ :major_sixth => 9, :diminished_seventh => 9,
122
+ :minor_seventh => 10,
123
+ :major_seventh => 11
124
+ }.each do |interval, semitones_count|
125
+ define_method interval do
126
+ adjust_by_semitones(semitones_count)
127
+ end
128
+ end
129
+
130
+ # Uses note as key to give major scale
131
+ #
132
+ # @returns [Array<Note>] Notes in major scale
133
+ def major_scale
134
+ [self,
135
+ self.major_second,
136
+ self.major_third,
137
+ self.perfect_fourth,
138
+ self.perfect_fifth,
139
+ self.major_sixth,
140
+ self.major_seventh,
141
+ ]
142
+ end
143
+
144
+ # Uses note as key to give minor scale
145
+ #
146
+ # @returns [Array<Note>] Notes in minor scale
147
+ def minor_scale
148
+ [self,
149
+ self.major_second,
150
+ self.minor_third,
151
+ self.perfect_fourth,
152
+ self.perfect_fifth,
153
+ self.minor_sixth,
154
+ self.minor_seventh,
155
+ ]
156
+ end
157
+
158
+ CHORD_INTERVALS = {
159
+ :minor => [:minor_third, :perfect_fifth],
160
+ :major => [:major_third, :perfect_fifth],
161
+ :fifth => [:perfect_fifth],
162
+ :diminished => [:minor_third, :diminished_fifth],
163
+ :augmented => [:major_third, :augmented_fifth],
164
+ :major_seventh => [:major_third, :perfect_fifth, :major_seventh],
165
+ :minor_seventh => [:minor_third, :perfect_fifth, :minor_seventh],
166
+ :diminished_seventh => [:minor_third, :diminished_fifth, :diminished_seventh],
167
+ :augmented_seventh => [:major_third, :augmented_fifth, :minor_seventh],
168
+ :half_diminished_seventh => [:minor_third, :diminished_fifth, :minor_seventh]
169
+ }
170
+
171
+ CHORD_ALIASES = {
172
+ :min => :minor,
173
+ :m => :minor,
174
+ :maj => :major,
175
+ :M => :major,
176
+ :p => :fifth,
177
+ :pow => :fifth,
178
+ :power => :fifth,
179
+ :'5' => :fifth,
180
+ :'5th' => :fifth,
181
+ :dim => :diminished,
182
+ :aug => :augmented,
183
+ :'+' => :augmented,
184
+
185
+ :maj_seventh => :major_seventh,
186
+ :major_7 => :major_seventh,
187
+ :major_7th => :major_seventh,
188
+ :maj_7 => :major_seventh,
189
+ :maj_7th => :major_seventh,
190
+ :maj7 => :major_seventh,
191
+ :maj7th => :major_seventh,
192
+ :M7 => :major_seventh,
193
+
194
+ :min_seventh => :minor_seventh,
195
+ :minor_7 => :minor_seventh,
196
+ :minor_7th => :minor_seventh,
197
+ :min_7 => :minor_seventh,
198
+ :min_7th => :minor_seventh,
199
+ :min7 => :minor_seventh,
200
+ :min7th => :minor_seventh,
201
+ :m7 => :minor_seventh,
202
+
203
+ :dim_seventh => :diminished_seventh,
204
+ :diminished_7 => :diminished_seventh,
205
+ :diminished_7th => :diminished_seventh,
206
+ :dim_7 => :diminished_seventh,
207
+ :dim_7th => :diminished_seventh,
208
+ :dim7 => :diminished_seventh,
209
+ :dim7th => :diminished_seventh,
210
+ :d7 => :diminished_seventh,
211
+
212
+ :aug_seventh => :augmented_seventh,
213
+ :augmented_7 => :augmented_seventh,
214
+ :augmented_7th => :augmented_seventh,
215
+ :aug_7 => :augmented_seventh,
216
+ :aug_7th => :augmented_seventh,
217
+ :aug7 => :augmented_seventh,
218
+ :aug7th => :augmented_seventh,
219
+ :'+7' => :augmented_seventh,
220
+
221
+ :half_dim_seventh => :half_diminished_seventh,
222
+ :half_diminished_7 => :half_diminished_seventh,
223
+ :half_diminished_7th => :half_diminished_seventh,
224
+ :half_dim_7 => :half_diminished_seventh,
225
+ :half_dim_7th => :half_diminished_seventh,
226
+ :half_dim7 => :half_diminished_seventh,
227
+ :half_dim7th => :half_diminished_seventh,
228
+ }
229
+
230
+ def chord(description)
231
+ description = :major if description.blank?
232
+
233
+ description = description.to_s
234
+ description.downcase! unless ['M', 'M7'].include?(description)
235
+ description.gsub!(/[\s\-]+/, '_')
236
+ description = description.to_sym
237
+
238
+ intervals = CHORD_INTERVALS[description] || CHORD_INTERVALS[CHORD_ALIASES[description]]
239
+
240
+ if intervals
241
+ Chord.new([self] + intervals.collect {|interval| self.send(interval) })
242
+ end
243
+ end
244
+
245
+ (CHORD_INTERVALS.keys + CHORD_ALIASES.keys).each do |chord_description|
246
+ define_method "#{chord_description}_chord" do
247
+ self.chord(chord_description)
248
+ end
249
+ end
250
+
57
251
  class << self
58
252
  extend ActiveSupport::Memoizable
59
253
 
@@ -1,3 +1,3 @@
1
1
  module Music
2
- VERSION = '0.5.1'
2
+ VERSION = '0.6.1'
3
3
  end
@@ -3,6 +3,16 @@ require 'spec_helper'
3
3
  describe Music::Chord do
4
4
  before :all do
5
5
  @standard_tuning_notes = [Note.new('E2'), Note.new('A2'), Note.new('D3'), Note.new('G3'), Note.new('B3'), Note.new('E4')]
6
+
7
+ @c_minor = Chord.new(['C4', 'Eb4', 'G4'])
8
+ @c_major = Chord.new(['C4', 'E4', 'G4'])
9
+ @c_diminished = Chord.new(['C4', 'Eb4', 'Gb4'])
10
+ @c_augmented = Chord.new(['C4', 'E4', 'G#4'])
11
+ @c_major_seventh = Chord.new(['C4', 'E4', 'G4', 'B4'])
12
+ @c_minor_seventh = Chord.new(['C4', 'Eb4', 'G4', 'Bb4'])
13
+ @c_diminished_seventh = Chord.new(['C4', 'Eb4', 'Gb4', 'A4'])
14
+ @c_augmented_seventh = Chord.new(['C4', 'E4', 'G#4', 'Bb4'])
15
+ @c_half_diminished_seventh = Chord.new(['C4', 'Eb4', 'Gb4', 'Bb4'])
6
16
  end
7
17
 
8
18
  describe '#new(notes)' do
@@ -14,23 +24,36 @@ describe Music::Chord do
14
24
  Chord.new(@standard_tuning_notes.collect(&:note_string))
15
25
  end
16
26
 
17
- it 'should sort the notes by frequency' do
18
- Chord.new(['A2', 'E2']).note_strings.should == ['E2', 'A2']
27
+ it 'should validate that chords must have at least two notes' do
28
+ lambda { Chord.new(['C4']) }.should raise_error(ArgumentError, 'Chords must have at least two notes')
29
+ lambda { Chord.new([]) }.should raise_error(ArgumentError, 'Chords must have at least two notes')
30
+ end
31
+ end
32
+
33
+ describe '#==' do
34
+ it 'should recognize that the order of notes in the chord does not matter' do
35
+ Chord.new(['C4', 'Eb4', 'G4']).should == Chord.new(['G4', 'Eb4', 'C4'])
19
36
  end
20
37
  end
21
38
 
22
39
  describe '#note_strings' do
23
- it 'should return an array of note strings' do
40
+ it 'should return a set of note strings' do
24
41
  chord = Chord.new(@standard_tuning_notes)
25
42
 
26
- chord.note_strings.should == @standard_tuning_notes.collect(&:note_string)
43
+ chord.note_strings.should == Set.new(@standard_tuning_notes.collect(&:note_string))
44
+ end
45
+ end
46
+
47
+ describe '#to_s' do
48
+ it 'should output just the sorted note descriptions separated by slashes' do
49
+ @c_minor.to_s.should == 'C4 / D#4 / G4'
27
50
  end
28
51
  end
29
52
 
30
53
  describe '#describe' do
31
54
  describe "triads" do
32
55
  it 'should recognize C major' do
33
- Chord.new(['C4', 'E4', 'G4']).describe.should == ['C', :major]
56
+ @c_major.describe.should == ['C', :major]
34
57
  end
35
58
 
36
59
  it 'should recognize C minor' do
@@ -62,4 +85,98 @@ describe Music::Chord do
62
85
  end
63
86
  end
64
87
  end
88
+
89
+ describe '.parse_chord_string' do
90
+ it 'should recognize C major' do
91
+ Chord.parse_chord_string('Cmajor4').should == @c_major
92
+ Chord.parse_chord_string('CMajor4').should == @c_major
93
+ Chord.parse_chord_string('Cmaj4').should == @c_major
94
+ Chord.parse_chord_string('CMaj4').should == @c_major
95
+ Chord.parse_chord_string('CM4').should == @c_major
96
+ Chord.parse_chord_string('C4').should == @c_major
97
+
98
+ expect { Chord.parse_chord_string('C') }.to raise_error ArgumentError
99
+ Chord.parse_chord_string('C', 4).should == @c_major
100
+ end
101
+
102
+ it 'should recognize C minor' do
103
+ Chord.parse_chord_string('Cminor4').should == @c_minor
104
+ Chord.parse_chord_string('CMinor4').should == @c_minor
105
+ Chord.parse_chord_string('Cmin4').should == @c_minor
106
+ Chord.parse_chord_string('CMin4').should == @c_minor
107
+ Chord.parse_chord_string('Cm4').should == @c_minor
108
+
109
+ expect { Chord.parse_chord_string('Cm') }.to raise_error ArgumentError
110
+ Chord.parse_chord_string('Cm', 4).should == @c_minor
111
+
112
+ end
113
+
114
+ it 'should recognize C diminished' do
115
+ Chord.parse_chord_string('Cdiminished4').should == @c_diminished
116
+ Chord.parse_chord_string('CDiminished4').should == @c_diminished
117
+ Chord.parse_chord_string('Cdim4').should == @c_diminished
118
+ Chord.parse_chord_string('CDim4').should == @c_diminished
119
+ Chord.parse_chord_string('CDIM4').should == @c_diminished
120
+
121
+ expect { Chord.parse_chord_string('Cdim').should == @c_diminished }.to raise_error ArgumentError
122
+ Chord.parse_chord_string('Cdim', 4).should == @c_diminished
123
+ end
124
+
125
+ it 'should recognize C augmented' do
126
+ Chord.parse_chord_string('Caugmented4').should == @c_augmented
127
+ Chord.parse_chord_string('Caugmented4').should == @c_augmented
128
+ Chord.parse_chord_string('Caug4').should == @c_augmented
129
+ Chord.parse_chord_string('CAug4').should == @c_augmented
130
+ Chord.parse_chord_string('CAUG4').should == @c_augmented
131
+ Chord.parse_chord_string('C+4').should == @c_augmented
132
+
133
+ expect { Chord.parse_chord_string('Caug').should == @c_augmented }.to raise_error ArgumentError
134
+ Chord.parse_chord_string('Caug', 4).should == @c_augmented
135
+ end
136
+
137
+ # TODO: Fill out other chords
138
+ end
139
+
140
+ describe '#inversion' do
141
+ it 'should adjust the lowest n notes up by an octive' do
142
+ @c_major.inversion(1).should == Chord.new(['E4', 'G4', 'C5'])
143
+ Chord.new(['Eb4', 'C4', 'Gb4']).inversion(1).should == Chord.new(['Eb4', 'C5', 'Gb4'])
144
+
145
+ @c_major.inversion(2).should == Chord.new(['E5', 'G4', 'C5'])
146
+ Chord.new(['Eb4', 'C4', 'Gb4']).inversion(2).should == Chord.new(['Eb5', 'C5', 'Gb4'])
147
+
148
+ @c_augmented_seventh.inversion(3).should == Chord.new(['E5', 'G#5', 'C5', 'Bb4'])
149
+ end
150
+
151
+ it 'should raise an error when the inversion amount is too great' do
152
+ lambda { @c_major.inversion(3) }.should raise_error(ArgumentError, 'Not enough notes in chord for inversion')
153
+ lambda { @c_major.inversion(4) }.should raise_error(ArgumentError, 'Not enough notes in chord for inversion')
154
+
155
+ lambda { @c_augmented_seventh.inversion(4) }.should raise_error(ArgumentError, 'Not enough notes in chord for inversion')
156
+ lambda { @c_augmented_seventh.inversion(5) }.should raise_error(ArgumentError, 'Not enough notes in chord for inversion')
157
+ end
158
+
159
+ it 'should raise an error when the inversion amount is too small' do
160
+ lambda { @c_major.inversion(0) }.should raise_error(ArgumentError, 'Inversion amount must be greater than or equal to 1')
161
+ lambda { @c_major.inversion(-1) }.should raise_error(ArgumentError, 'Inversion amount must be greater than or equal to 1')
162
+ end
163
+ end
164
+
165
+ describe '#first_inversion' do
166
+ it 'should adjust the lowest note up by an octive' do
167
+ @c_major.first_inversion.should == Chord.new(['E4', 'G4', 'C5'])
168
+ end
169
+ end
170
+
171
+ describe '#second_inversion' do
172
+ it 'should adjust the lowest two notes up by an octive' do
173
+ @c_major.second_inversion.should == Chord.new(['E5', 'G4', 'C5'])
174
+ end
175
+ end
176
+
177
+ describe '#third_inversion' do
178
+ it 'should adjust the lowest three notes up by an octive' do
179
+ @c_augmented_seventh.third_inversion.should == Chord.new(['E5', 'G#5', 'C5', 'Bb4'])
180
+ end
181
+ end
65
182
  end
@@ -151,6 +151,330 @@ describe Music::Note do
151
151
  end
152
152
  end
153
153
 
154
+ describe 'interval calculations' do
155
+ let(:c4) { Note.new('C4') }
156
+ let(:b4) { Note.new('B4') }
157
+
158
+ it { c4.should have_an_interval :minor_second, 'C#4' }
159
+ it { b4.should have_an_interval :minor_second, 'C5' }
160
+
161
+ it { c4.should have_an_interval :major_second, 'D4' }
162
+ it { b4.should have_an_interval :major_second, 'C#5' }
163
+
164
+
165
+ it { c4.should have_an_interval :minor_third, 'D#4' }
166
+ it { b4.should have_an_interval :minor_third, 'D5' }
167
+
168
+ it { c4.should have_an_interval :major_third, 'E4' }
169
+ it { b4.should have_an_interval :major_third, 'D#5' }
170
+
171
+ it { c4.should have_an_interval :perfect_fourth, 'F4' }
172
+ it { b4.should have_an_interval :perfect_fourth, 'E5' }
173
+
174
+ # Enharmonic equivalents
175
+ it { c4.should have_an_interval :tritone, 'F#4' }
176
+ it { b4.should have_an_interval :tritone, 'F5' }
177
+ it { c4.should have_an_interval :diminished_fifth, 'F#4' }
178
+ it { b4.should have_an_interval :diminished_fifth, 'F5' }
179
+ it { c4.should have_an_interval :flat_fifth, 'F#4' }
180
+ it { b4.should have_an_interval :flat_fifth, 'F5' }
181
+ it { c4.should have_an_interval :augmented_fourth, 'F#4' }
182
+ it { b4.should have_an_interval :augmented_fourth, 'F5' }
183
+
184
+ it { c4.should have_an_interval :perfect_fifth, 'G4' }
185
+ it { b4.should have_an_interval :perfect_fifth, 'F#5' }
186
+
187
+ # Enharmonic equivalents
188
+ it { c4.should have_an_interval :augmented_fifth, 'G#4' }
189
+ it { b4.should have_an_interval :augmented_fifth, 'G5' }
190
+ it { c4.should have_an_interval :minor_sixth, 'G#4' }
191
+ it { b4.should have_an_interval :minor_sixth, 'G5' }
192
+
193
+ it { c4.should have_an_interval :major_sixth, 'A4' }
194
+ it { b4.should have_an_interval :major_sixth, 'G#5' }
195
+
196
+ it { c4.should have_an_interval :diminished_seventh, 'A4' }
197
+ it { b4.should have_an_interval :diminished_seventh, 'G#5' }
198
+
199
+ it { c4.should have_an_interval :minor_seventh, 'A#4' }
200
+ it { b4.should have_an_interval :minor_seventh, 'A5' }
201
+
202
+ it { c4.should have_an_interval :major_seventh, 'B4' }
203
+ it { b4.should have_an_interval :major_seventh, 'A#5' }
204
+ end
205
+
206
+
207
+ describe 'scales from notes (as scale key)' do
208
+ describe '#major_scale' do
209
+ Note.new('C4').major_scale.should == [
210
+ Note.new('C4'),
211
+ Note.new('D4'),
212
+ Note.new('E4'),
213
+ Note.new('F4'),
214
+ Note.new('G4'),
215
+ Note.new('A4'),
216
+ Note.new('B4')
217
+ ]
218
+
219
+ Note.new('G4').major_scale.should == [
220
+ Note.new('G4'),
221
+ Note.new('A4'),
222
+ Note.new('B4'),
223
+ Note.new('C5'),
224
+ Note.new('D5'),
225
+ Note.new('E5'),
226
+ Note.new('F#5')
227
+ ]
228
+ end
229
+
230
+ describe '#minor_scale' do
231
+ Note.new('C4').minor_scale.should == [
232
+ Note.new('C4'),
233
+ Note.new('D4'),
234
+ Note.new('D#4'),
235
+ Note.new('F4'),
236
+ Note.new('G4'),
237
+ Note.new('G#4'),
238
+ Note.new('A#4')
239
+ ]
240
+
241
+ Note.new('G4').minor_scale.should == [
242
+ Note.new('G4'),
243
+ Note.new('A4'),
244
+ Note.new('A#4'),
245
+ Note.new('C5'),
246
+ Note.new('D5'),
247
+ Note.new('D#5'),
248
+ Note.new('F5')
249
+ ]
250
+ end
251
+ end
252
+
253
+ describe '#to_s' do
254
+ it 'should output the note_string' do
255
+ Note.new('E4').to_s.should == 'E4'
256
+ end
257
+
258
+ it 'should use the sharp version' do
259
+ Note.new('D#5').to_s.should == 'D#5'
260
+ Note.new('Eb5').to_s.should == 'D#5'
261
+ end
262
+ end
263
+
264
+ describe 'chords from notes' do
265
+ c4 = Note.new('C4')
266
+
267
+ c_minor = Chord.new(['C4', 'Eb4', 'G4'])
268
+ c_major = Chord.new(['C4', 'E4', 'G4'])
269
+ c_fifth = Chord.new(['C4', 'G4'])
270
+ c_diminished = Chord.new(['C4', 'Eb4', 'Gb4'])
271
+ c_augmented = Chord.new(['C4', 'E4', 'G#4'])
272
+ c_major_seventh = Chord.new(['C4', 'E4', 'G4', 'B4'])
273
+ c_minor_seventh = Chord.new(['C4', 'Eb4', 'G4', 'Bb4'])
274
+ c_diminished_seventh = Chord.new(['C4', 'Eb4', 'Gb4', 'A4'])
275
+ c_augmented_seventh = Chord.new(['C4', 'E4', 'G#4', 'Bb4'])
276
+ c_half_diminished_seventh = Chord.new(['C4', 'Eb4', 'Gb4', 'Bb4'])
277
+
278
+ describe 'chords from notes' do
279
+ describe '#chord' do
280
+ it 'should recognize minor chords' do
281
+ c4.chord(:minor).should == c_minor
282
+ c4.chord('Minor').should == c_minor
283
+ c4.chord('minor').should == c_minor
284
+ c4.chord('min').should == c_minor
285
+ c4.chord('MIN').should == c_minor
286
+ c4.chord('m').should == c_minor
287
+ end
288
+
289
+ it 'should recognize major chords' do
290
+ c4.chord(:major).should == c_major
291
+ c4.chord('Major').should == c_major
292
+ c4.chord('major').should == c_major
293
+ c4.chord('maj').should == c_major
294
+ c4.chord('MAJ').should == c_major
295
+ c4.chord('M').should == c_major
296
+ c4.chord('').should == c_major
297
+ end
298
+
299
+ it 'should recognize power chords' do
300
+ c4.chord(:power).should == c_fifth
301
+ c4.chord(:fifth).should == c_fifth
302
+ c4.chord('Power').should == c_fifth
303
+ c4.chord('power').should == c_fifth
304
+ c4.chord('Fifth').should == c_fifth
305
+ c4.chord('fifth').should == c_fifth
306
+ c4.chord('pow').should == c_fifth
307
+ c4.chord('POW').should == c_fifth
308
+ c4.chord('5').should == c_fifth
309
+ end
310
+
311
+ it 'should recognize diminished chords' do
312
+ c4.chord(:diminished).should == c_diminished
313
+ c4.chord('Diminished').should == c_diminished
314
+ c4.chord('diminished').should == c_diminished
315
+ c4.chord('dim').should == c_diminished
316
+ c4.chord('DIM').should == c_diminished
317
+ end
318
+
319
+ it 'should recognize augmented chords' do
320
+ c4.chord(:augmented).should == c_augmented
321
+ c4.chord('Augmented').should == c_augmented
322
+ c4.chord('augmented').should == c_augmented
323
+ c4.chord('aug').should == c_augmented
324
+ c4.chord('AUG').should == c_augmented
325
+ c4.chord('+').should == c_augmented
326
+ end
327
+
328
+ it 'should recognize major seventh chords' do
329
+ c4.chord(:major_seventh).should == c_major_seventh
330
+ c4.chord('major_seventh').should == c_major_seventh
331
+ c4.chord('major seventh').should == c_major_seventh
332
+ c4.chord('Major seventh').should == c_major_seventh
333
+ c4.chord('maj seventh').should == c_major_seventh
334
+ c4.chord('maj 7').should == c_major_seventh
335
+ c4.chord('maj 7th').should == c_major_seventh
336
+ c4.chord('maj7').should == c_major_seventh
337
+ c4.chord('maj7th').should == c_major_seventh
338
+ c4.chord('MAJ7').should == c_major_seventh
339
+ c4.chord('M7').should == c_major_seventh
340
+ end
341
+
342
+ it 'should recognize minor seventh chords' do
343
+ c4.chord(:minor_seventh).should == c_minor_seventh
344
+ c4.chord('minor_seventh').should == c_minor_seventh
345
+ c4.chord('minor seventh').should == c_minor_seventh
346
+ c4.chord('minor seventh').should == c_minor_seventh
347
+ c4.chord('min seventh').should == c_minor_seventh
348
+ c4.chord('min 7').should == c_minor_seventh
349
+ c4.chord('min 7th').should == c_minor_seventh
350
+ c4.chord('min7').should == c_minor_seventh
351
+ c4.chord('min7th').should == c_minor_seventh
352
+ c4.chord('min7').should == c_minor_seventh
353
+ c4.chord('m7').should == c_minor_seventh
354
+ end
355
+
356
+ it 'should recognize diminished seventh chords' do
357
+ c4.chord(:diminished_seventh).should == c_diminished_seventh
358
+ c4.chord('diminished_seventh').should == c_diminished_seventh
359
+ c4.chord('diminished seventh').should == c_diminished_seventh
360
+ c4.chord('diminished seventh').should == c_diminished_seventh
361
+ c4.chord('dim seventh').should == c_diminished_seventh
362
+ c4.chord('dim 7').should == c_diminished_seventh
363
+ c4.chord('dim 7th').should == c_diminished_seventh
364
+ c4.chord('dim7').should == c_diminished_seventh
365
+ c4.chord('dim7th').should == c_diminished_seventh
366
+ c4.chord('dim7').should == c_diminished_seventh
367
+ c4.chord('d7').should == c_diminished_seventh
368
+ end
369
+
370
+ it 'should recognize augmented seventh chords' do
371
+ c4.chord(:augmented_seventh).should == c_augmented_seventh
372
+ c4.chord('augmented_seventh').should == c_augmented_seventh
373
+ c4.chord('augmented seventh').should == c_augmented_seventh
374
+ c4.chord('augmented seventh').should == c_augmented_seventh
375
+ c4.chord('aug seventh').should == c_augmented_seventh
376
+ c4.chord('aug 7').should == c_augmented_seventh
377
+ c4.chord('aug 7th').should == c_augmented_seventh
378
+ c4.chord('aug7').should == c_augmented_seventh
379
+ c4.chord('aug7th').should == c_augmented_seventh
380
+ c4.chord('aug7').should == c_augmented_seventh
381
+ c4.chord('+7').should == c_augmented_seventh
382
+ end
383
+
384
+ it 'should recognize half diminished seventh chords' do
385
+ c4.chord(:half_diminished_seventh).should == c_half_diminished_seventh
386
+ c4.chord('half_diminished_7').should == c_half_diminished_seventh
387
+ c4.chord('half_diminished_7th').should == c_half_diminished_seventh
388
+ c4.chord('half-diminished seventh').should == c_half_diminished_seventh
389
+ c4.chord('half-diminished 7').should == c_half_diminished_seventh
390
+ c4.chord('half-diminished 7th').should == c_half_diminished_seventh
391
+ c4.chord('half_dim seventh').should == c_half_diminished_seventh
392
+ c4.chord('half_dim 7').should == c_half_diminished_seventh
393
+ c4.chord('half_dim 7th').should == c_half_diminished_seventh
394
+ c4.chord('half_dim7').should == c_half_diminished_seventh
395
+ c4.chord('half_dim7th').should == c_half_diminished_seventh
396
+ c4.chord('half_dim7').should == c_half_diminished_seventh
397
+ end
398
+ end
399
+
400
+ describe 'chord methods' do
401
+ it 'should have minor methods' do
402
+ c4.minor_chord.should == c_minor
403
+ c4.min_chord.should == c_minor
404
+ c4.m_chord.should == c_minor
405
+ end
406
+
407
+ it 'should have major methods' do
408
+ c4.major_chord.should == c_major
409
+ c4.maj_chord.should == c_major
410
+ c4.M_chord.should == c_major
411
+ end
412
+
413
+ it 'should have diminished methods' do
414
+ c4.diminished_chord.should == c_diminished
415
+ c4.dim_chord.should == c_diminished
416
+ end
417
+
418
+ it 'should have augmented methods' do
419
+ c4.augmented_chord.should == c_augmented
420
+ c4.aug_chord.should == c_augmented
421
+ end
422
+
423
+ it 'should have major seventh methods' do
424
+ c4.major_seventh_chord.should == c_major_seventh
425
+ c4.maj_seventh_chord.should == c_major_seventh
426
+ c4.maj_7_chord.should == c_major_seventh
427
+ c4.maj_7th_chord.should == c_major_seventh
428
+ c4.maj7_chord.should == c_major_seventh
429
+ c4.maj7th_chord.should == c_major_seventh
430
+ c4.M7_chord.should == c_major_seventh
431
+ end
432
+
433
+ it 'should have minor seventh methods' do
434
+ c4.minor_seventh_chord.should == c_minor_seventh
435
+ c4.min_seventh_chord.should == c_minor_seventh
436
+ c4.min_7_chord.should == c_minor_seventh
437
+ c4.min_7th_chord.should == c_minor_seventh
438
+ c4.min7_chord.should == c_minor_seventh
439
+ c4.min7th_chord.should == c_minor_seventh
440
+ c4.m7_chord.should == c_minor_seventh
441
+ end
442
+
443
+ it 'should have diminished seventh methods' do
444
+ c4.diminished_seventh_chord.should == c_diminished_seventh
445
+ c4.dim_seventh_chord.should == c_diminished_seventh
446
+ c4.dim_7_chord.should == c_diminished_seventh
447
+ c4.dim_7th_chord.should == c_diminished_seventh
448
+ c4.dim7_chord.should == c_diminished_seventh
449
+ c4.dim7th_chord.should == c_diminished_seventh
450
+ c4.d7_chord.should == c_diminished_seventh
451
+ end
452
+
453
+ it 'should have augmented seventh methods' do
454
+ c4.augmented_seventh_chord.should == c_augmented_seventh
455
+ c4.aug_seventh_chord.should == c_augmented_seventh
456
+ c4.aug_7_chord.should == c_augmented_seventh
457
+ c4.aug_7th_chord.should == c_augmented_seventh
458
+ c4.aug7_chord.should == c_augmented_seventh
459
+ c4.aug7th_chord.should == c_augmented_seventh
460
+ c4.send('+7_chord').should == c_augmented_seventh
461
+ end
462
+
463
+ it 'should have half diminished seventh methods' do
464
+ c4.half_diminished_seventh_chord.should == c_half_diminished_seventh
465
+ c4.half_diminished_7_chord.should == c_half_diminished_seventh
466
+ c4.half_diminished_7th_chord.should == c_half_diminished_seventh
467
+ c4.half_dim_seventh_chord.should == c_half_diminished_seventh
468
+ c4.half_dim_7_chord.should == c_half_diminished_seventh
469
+ c4.half_dim_7th_chord.should == c_half_diminished_seventh
470
+ c4.half_dim7_chord.should == c_half_diminished_seventh
471
+ c4.half_dim7th_chord.should == c_half_diminished_seventh
472
+ end
473
+ end
474
+ end
475
+
476
+ end
477
+
154
478
  describe ".calculate_frequency(letter, accidental, octave)" do
155
479
  {
156
480
  ['C', nil, 0] => 16.35,
@@ -201,6 +525,8 @@ describe Music::Note do
201
525
  end
202
526
  end
203
527
 
528
+ # TODO: Should return accurracy
529
+ # Thought: ((frequency off) / (distance to next note's frequency)) * 2.0?
204
530
  describe ".calculate_note(frequency)" do
205
531
  test_frequencies = {
206
532
  [16.35] => ['C', nil, 0],
@@ -258,7 +584,7 @@ describe Music::Note do
258
584
  end
259
585
 
260
586
  it "should allow getting of previous note" do
261
- Note.new(739.99).pred.should == Note.new(698.46)
587
+ Note.new(739.99).prev.should == Note.new(698.46)
262
588
  end
263
589
  end
264
590
  end
@@ -1 +1,3 @@
1
1
  require 'music'
2
+
3
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
@@ -0,0 +1,13 @@
1
+ RSpec::Matchers.define :have_an_interval do |interval_description, expected_note_string|
2
+ match do |note|
3
+ note.send(interval_description).note_string == expected_note_string
4
+ end
5
+
6
+ failure_message_for_should do |note|
7
+ "Expected #{note.note_string}'s #{interval_description} interval to be #{expected_note_string}"
8
+ end
9
+
10
+ description do |note|
11
+ "have an #{interval_description} interval of #{expected_note_string} for #{note.note_string}"
12
+ end
13
+ end
metadata CHANGED
@@ -1,98 +1,94 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: music
3
- version: !ruby/object:Gem::Version
4
- hash: 9
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.1
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 5
9
- - 1
10
- version: 0.5.1
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Brian Underwood
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2012-05-15 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2012-11-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: rake
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
24
17
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 25
29
- segments:
30
- - 0
31
- - 9
32
- version: "0.9"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0.9'
33
22
  type: :development
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: bundler
37
23
  prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0.9'
30
+ - !ruby/object:Gem::Dependency
31
+ name: bundler
32
+ requirement: !ruby/object:Gem::Requirement
39
33
  none: false
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- hash: 21
44
- segments:
45
- - 1
46
- - 1
47
- - 3
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
48
37
  version: 1.1.3
49
38
  type: :development
50
- version_requirements: *id002
51
- - !ruby/object:Gem::Dependency
52
- name: rspec
53
39
  prerelease: false
54
- requirement: &id003 !ruby/object:Gem::Requirement
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.1.3
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
55
49
  none: false
56
- requirements:
57
- - - ">="
58
- - !ruby/object:Gem::Version
59
- hash: 3
60
- segments:
61
- - 0
62
- version: "0"
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
63
54
  type: :development
64
- version_requirements: *id003
65
- - !ruby/object:Gem::Dependency
66
- name: activemodel
67
55
  prerelease: false
68
- requirement: &id004 !ruby/object:Gem::Requirement
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: activemodel
64
+ requirement: !ruby/object:Gem::Requirement
69
65
  none: false
70
- requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- hash: 15
74
- segments:
75
- - 3
76
- - 2
77
- - 0
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
78
69
  version: 3.2.0
79
70
  type: :development
80
- version_requirements: *id004
81
- description: Library for classifying notes and chords and performing calculations on them. See README.md
82
- email:
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 3.2.0
78
+ description: Library for classifying notes and chords and performing calculations
79
+ on them. See README.md
80
+ email:
83
81
  - ml+musicgem@semi-sentient.com
84
82
  executables: []
85
-
86
83
  extensions: []
87
-
88
84
  extra_rdoc_files: []
89
-
90
- files:
85
+ files:
91
86
  - .document
92
87
  - .gitignore
93
88
  - .travis.yml
94
89
  - Gemfile
95
90
  - Gemfile.lock
91
+ - Guardfile
96
92
  - LICENSE.txt
97
93
  - README.md
98
94
  - Rakefile
@@ -106,43 +102,35 @@ files:
106
102
  - spec/classes/hash_spec.rb
107
103
  - spec/classes/note_spec.rb
108
104
  - spec/spec_helper.rb
105
+ - spec/support/matchers/have_an_interval.rb
109
106
  homepage: http://github.com/cheerfulstoic/music
110
- licenses:
107
+ licenses:
111
108
  - MIT
112
109
  post_install_message:
113
110
  rdoc_options: []
114
-
115
- require_paths:
111
+ require_paths:
116
112
  - lib
117
- required_ruby_version: !ruby/object:Gem::Requirement
113
+ required_ruby_version: !ruby/object:Gem::Requirement
118
114
  none: false
119
- requirements:
120
- - - ">="
121
- - !ruby/object:Gem::Version
122
- hash: 3
123
- segments:
124
- - 0
125
- version: "0"
126
- required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
120
  none: false
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- hash: 31
132
- segments:
133
- - 1
134
- - 8
135
- version: "1.8"
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '1.8'
136
125
  requirements: []
137
-
138
126
  rubyforge_project:
139
- rubygems_version: 1.8.17
127
+ rubygems_version: 1.8.23
140
128
  signing_key:
141
129
  specification_version: 3
142
130
  summary: Library for performing calculations on musical elements
143
- test_files:
131
+ test_files:
144
132
  - spec/classes/chord_spec.rb
145
133
  - spec/classes/hash_spec.rb
146
134
  - spec/classes/note_spec.rb
147
135
  - spec/spec_helper.rb
148
- has_rdoc:
136
+ - spec/support/matchers/have_an_interval.rb