Created
September 19, 2013 22:18
-
-
Save kevbuchanan/6630643 to your computer and use it in GitHub Desktop.
This Ruby Quiz: http://rubyquiz.strd6.com/quizzes/229-music-theory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Chord | |
| NOTE_POSITIONS = { | |
| 'C' => 0, | |
| 'B#' => 0, | |
| 'Db' => 1, | |
| 'C#' => 1, | |
| 'D' => 2, | |
| 'Eb' => 3, | |
| 'D#' => 3, | |
| 'Fb' => 4, | |
| 'E' => 4, | |
| 'F' => 5, | |
| 'E#' => 5, | |
| 'Gb' => 6, | |
| 'F#' => 6, | |
| 'G' => 7, | |
| 'Ab' => 8, | |
| 'G#' => 8, | |
| 'A' => 9, | |
| 'Bb' => 10, | |
| 'A#' => 10, | |
| 'Cb' => 11, | |
| 'B' => 11 | |
| } | |
| TRIADS = { | |
| major: [:major_third, :minor_third], | |
| minor: [:minor_third, :major_third], | |
| diminished: [:minor_third, :minor_third], | |
| augmented: [:major_third, :major_third] | |
| } | |
| attr_reader :notation, :root, :quality, :extended | |
| def initialize(notation) | |
| raise "Chord must be formatted like Cmaj, C#min, Dbdim, or Faug with an optional 7" unless notation.match(/^([A-G][#b]?)(min|maj|dim|aug)(7)?$/) | |
| @notation = notation | |
| @root = $1 | |
| @quality = get_quality($2) | |
| @extended = $3 | |
| end | |
| def get_quality(abbreviation) | |
| case abbreviation | |
| when 'maj' | |
| :major | |
| when 'min' | |
| :minor | |
| when 'dim' | |
| :diminished | |
| when 'aug' | |
| :augmented | |
| end | |
| end | |
| def notes | |
| base = TRIADS[@quality].each_with_object([@root]) do |third, notes| | |
| base = notes.last | |
| notes << self.send(third, base) | |
| end | |
| base << extended if @extended | |
| base | |
| end | |
| def major_third(root) | |
| keys = get_interval(root, 4) | |
| root[1] == 'b' ? keys.first : keys.last | |
| end | |
| def minor_third(root) | |
| keys = get_interval(root, 3) | |
| root[1] == '#' ? keys.last : keys.first | |
| end | |
| def extended | |
| if @quality == :minor | |
| keys = get_interval(@root, 10) | |
| @root[1] == '#' ? keys.last : keys.first | |
| else | |
| keys = get_interval(@root, 11) | |
| @root[1] == 'b' ? keys.first : keys.last | |
| end | |
| end | |
| def get_interval(root, interval) | |
| root_position = position_of(root) | |
| new_position = (root_position + interval) % 12 | |
| keys_of(new_position) | |
| end | |
| def position_of(note) | |
| NOTE_POSITIONS[note] | |
| end | |
| def keys_of(position) | |
| NOTE_POSITIONS.map{ |key, value| value == position ? key : nil }.compact | |
| end | |
| end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'rspec' | |
| require_relative 'music' | |
| describe Chord do | |
| let(:major_chord) { Chord.new('Cmaj') } | |
| let(:major_chord_notes) { ['C', 'E', 'G'] } | |
| let(:minor_chord) { Chord.new('Cmin') } | |
| let(:minor_chord_notes) { ['C', 'Eb', 'G'] } | |
| let(:diminished_chord) { Chord.new('Cdim') } | |
| let(:diminished_chord_notes) { ['C', 'Eb', 'Gb'] } | |
| let(:augmented_chord) { Chord.new('Caug') } | |
| let(:augmented_chord_notes) { ['C', 'E', 'G#'] } | |
| it "intializes with properly formatted notation" do | |
| expect{ major_chord }.to_not raise_error | |
| end | |
| it "raise an error with improperly formatted notation" do | |
| expect{ Chord.new('Cmajor7th') }.to raise_error | |
| end | |
| it "has a root" do | |
| expect(major_chord.root).to eq('C') | |
| end | |
| it "has a quality" do | |
| expect(major_chord.quality).to eq(:major) | |
| end | |
| describe "#notes" do | |
| it "returns an array of notes" do | |
| expect(major_chord.notes).to be_a(Array) | |
| end | |
| context "major chord" do | |
| it "returns the correct notes" do | |
| expect(major_chord.notes).to eq(major_chord_notes) | |
| end | |
| end | |
| context "minor chord" do | |
| it "returns the correct notes" do | |
| expect(minor_chord.notes).to eq(minor_chord_notes) | |
| end | |
| end | |
| context "diminished chord" do | |
| it "returns the correct notes" do | |
| expect(diminished_chord.notes).to eq(diminished_chord_notes) | |
| end | |
| end | |
| context "augmented chord" do | |
| it "returns the correct notes" do | |
| expect(augmented_chord.notes).to eq(augmented_chord_notes) | |
| end | |
| end | |
| it "returns the 7th" do | |
| expect( Chord.new('Cmaj7').notes.last ).to eq('B') | |
| end | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment