pedrozath/coltrane

View on GitHub
lib/coltrane/theory/circle_of_fifths.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
# frozen_string_literal: true

module Coltrane
  module Theory
    class CircleOfFifths
      attr_reader :notes

      LETTER_SEQUENCE = %w[C G D A E B F].freeze

      def initialize(start_note = Note['C'], size = Float::INFINITY)
        index  = letters.index(start_note.name[0])
        @notes = fifths(note: start_note - Interval.perfect_fifth,
                        size: size,
                        index: (index - 1) % LETTER_SEQUENCE.size)
      end

      private

      def fifths(note:, index: nil, notes: [], size:)
        return notes if size == 0
        return notes if notes.any? && note.as(letters(index)).name == notes.first.name
        fifths note: note + Interval.perfect_fifth,
               notes: notes + [note.as(letters(index))],
               index: index + 1,
               size:  size - 1
      end

      def letters(i = nil)
        i.nil? ? LETTER_SEQUENCE : LETTER_SEQUENCE[i % LETTER_SEQUENCE.size]
      end
    end
  end
end