Sha256: 9a78a5daba4b44c872a2ea2f8b25121db633d31ce342206f911d01866e9fbb55

Contents?: true

Size: 1.66 KB

Versions: 2

Compression:

Stored size: 1.66 KB

Contents

# frozen_string_literal: true

# Represents a key signature.
class HeadMusic::KeySignature
  attr_reader :tonic_spelling
  attr_reader :scale_type
  attr_reader :scale

  SHARPS = %w[F♯ C♯ G♯ D♯ A♯ E♯ B♯].freeze
  FLATS = %w[B♭ E♭ A♭ D♭ G♭ C♭ F♭].freeze

  def self.default
    @default ||= new('C', :major)
  end

  def self.get(identifier)
    return identifier if identifier.is_a?(HeadMusic::KeySignature)
    @key_signatures ||= {}
    tonic_spelling, scale_type_name = identifier.strip.split(/\s/)
    hash_key = HeadMusic::Utilities::HashKey.for(identifier.gsub(/#|♯/, 'sharp').gsub(/b|♭/, 'flat'))
    @key_signatures[hash_key] ||= new(tonic_spelling, scale_type_name)
  end

  delegate :pitch_class, to: :tonic_spelling, prefix: :tonic
  delegate :to_s, to: :name
  delegate :pitches, to: :scale

  def initialize(tonic_spelling, scale_type = nil)
    @tonic_spelling = HeadMusic::Spelling.get(tonic_spelling)
    @scale_type = HeadMusic::ScaleType.get(scale_type) if scale_type
    @scale_type ||= HeadMusic::ScaleType.default
    @scale_type = @scale_type.parent || @scale_type
    @scale = HeadMusic::Scale.get(@tonic_spelling, @scale_type)
  end

  def spellings
    pitches.map(&:spelling).uniq
  end

  def sharps
    spellings.select(&:sharp?).sort_by { |sharp| SHARPS.index(sharp.to_s) }
  end

  def flats
    spellings.select(&:flat?).sort_by { |flat| FLATS.index(flat.to_s) }
  end

  def num_sharps
    sharps.length
  end

  def num_flats
    flats.length
  end

  def signs
    flats.any? ? flats : sharps
  end

  def name
    [tonic_spelling, scale_type].join(' ')
  end

  def ==(other)
    signs == self.class.get(other).signs
  end
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
head_music-0.19.1 lib/head_music/key_signature.rb
head_music-0.19.0 lib/head_music/key_signature.rb