Skip to content

Commit

Permalink
Generalize to #inversion method and make aliases for convenience
Browse files Browse the repository at this point in the history
  • Loading branch information
cheerfulstoic committed Nov 3, 2012
1 parent ac50b70 commit 87a89a3
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 12 deletions.
29 changes: 20 additions & 9 deletions lib/music/chord.rb
Expand Up @@ -65,20 +65,31 @@ def to_s
@notes.to_a.sort.collect(&:to_s).join(' / ')
end

# Give the first inversion of the chord which simply adjusts the lowest note up by one octive
# Give the Nth inversion of the chord which simply adjusts the lowest N notes up by one octive
#
# @returns [Chord] The first inversion of chord
def first_inversion
# @returns [Chord] The specified inversion of chord
def inversion(amount)
raise ArgumentError, "Inversion amount must be greater than or equal to 1" if amount < 1
raise ArgumentError, "Not enough notes in chord for inversion" if amount >= @notes.size

note_array = @notes.to_a.sort
note = note_array.shift
Chord.new([note.adjust_by_semitones(12)] + note_array)
notes = (0...amount).collect { note_array.shift.adjust_by_semitones(12) }
Chord.new(notes + note_array)
end

# Give the first inversion of the chord which simply adjusts the lowest two notes up by one octive
#
# @returns [Chord] The second inversion of chord
# Calls inversion(1)
def first_inversion
self.inversion(1)
end

# Calls inversion(2)
def second_inversion
self.first_inversion.first_inversion
self.inversion(2)
end

# Calls inversion(3)
def third_inversion
self.inversion(3)
end

class << self
Expand Down
33 changes: 30 additions & 3 deletions spec/classes/chord_spec.rb
Expand Up @@ -137,19 +137,46 @@
# TODO: Fill out other chords
end

describe '#inversion' do
it 'should adjust the lowest n notes up by an octive' do
@c_major.inversion(1).should == Chord.new(['E4', 'G4', 'C5'])
Chord.new(['Eb4', 'C4', 'Gb4']).inversion(1).should == Chord.new(['Eb4', 'C5', 'Gb4'])

@c_major.inversion(2).should == Chord.new(['E5', 'G4', 'C5'])
Chord.new(['Eb4', 'C4', 'Gb4']).inversion(2).should == Chord.new(['Eb5', 'C5', 'Gb4'])

@c_augmented_seventh.inversion(3).should == Chord.new(['E5', 'G#5', 'C5', 'Bb4'])
end

it 'should raise an error when the inversion amount is too great' do
lambda { @c_major.inversion(3) }.should raise_error(ArgumentError, 'Not enough notes in chord for inversion')
lambda { @c_major.inversion(4) }.should raise_error(ArgumentError, 'Not enough notes in chord for inversion')

lambda { @c_augmented_seventh.inversion(4) }.should raise_error(ArgumentError, 'Not enough notes in chord for inversion')
lambda { @c_augmented_seventh.inversion(5) }.should raise_error(ArgumentError, 'Not enough notes in chord for inversion')
end

it 'should raise an error when the inversion amount is too small' do
lambda { @c_major.inversion(0) }.should raise_error(ArgumentError, 'Inversion amount must be greater than or equal to 1')
lambda { @c_major.inversion(-1) }.should raise_error(ArgumentError, 'Inversion amount must be greater than or equal to 1')
end
end

describe '#first_inversion' do
it 'should adjust the lowest note up by an octive' do
@c_major.first_inversion.should == Chord.new(['E4', 'G4', 'C5'])

Chord.new(['Eb4', 'C4', 'Gb4']).first_inversion.should == Chord.new(['Eb4', 'C5', 'Gb4'])
end
end

describe '#second_inversion' do
it 'should adjust the lowest two notes up by an octive' do
@c_major.second_inversion.should == Chord.new(['E5', 'G4', 'C5'])
end
end

Chord.new(['Eb4', 'C4', 'Gb4']).second_inversion.should == Chord.new(['Eb5', 'C5', 'Gb4'])
describe '#third_inversion' do
it 'should adjust the lowest three notes up by an octive' do
@c_augmented_seventh.third_inversion.should == Chord.new(['E5', 'G#5', 'C5', 'Bb4'])
end
end
end

0 comments on commit 87a89a3

Please sign in to comment.