music 0.5.1 → 0.6.1

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