Sha256: a50b8ad2cf335142bbcdd8885de408d562f82d6e3b3fe8bb4ad0f17c35e821bd

Contents?: true

Size: 1.97 KB

Versions: 32

Compression:

Stored size: 1.97 KB

Contents

# frozen_string_literal: true

# Motion defines the relative pitch direction of the upper and lower voices of subsequence intervals.
class HeadMusic::Motion
  attr_reader :first_harmonic_interval, :second_harmonic_interval

  def initialize(first_harmonic_interval, second_harmonic_interval)
    @first_harmonic_interval = first_harmonic_interval
    @second_harmonic_interval = second_harmonic_interval
  end

  def repetition?
    upper_melodic_interval.repetition? && lower_melodic_interval.repetition?
  end

  def oblique?
    upper_melodic_interval.repetition? && lower_melodic_interval.moving? ||
      lower_melodic_interval.repetition? && upper_melodic_interval.moving?
  end

  def direct?
    parallel? || similar?
  end

  def parallel?
    upper_melodic_interval.moving? &&
      upper_melodic_interval.direction == lower_melodic_interval.direction &&
      upper_melodic_interval.steps == lower_melodic_interval.steps
  end

  def similar?
    upper_melodic_interval.direction == lower_melodic_interval.direction &&
      upper_melodic_interval.steps != lower_melodic_interval.steps
  end

  def contrary?
    upper_melodic_interval.moving? &&
      lower_melodic_interval.moving? &&
      upper_melodic_interval.direction != lower_melodic_interval.direction
  end

  def notes
    upper_notes + lower_notes
  end

  def contrapuntal_motion
    %i[parallel similar oblique contrary repetition].detect do |motion_type|
      send("#{motion_type}?")
    end
  end

  def to_s
    "#{contrapuntal_motion} motion from #{first_harmonic_interval} to #{second_harmonic_interval}"
  end

  private

  def upper_melodic_interval
    HeadMusic::MelodicInterval.new(upper_notes.first, upper_notes.last)
  end

  def lower_melodic_interval
    HeadMusic::MelodicInterval.new(lower_notes.first, lower_notes.last)
  end

  def upper_notes
    [first_harmonic_interval, second_harmonic_interval].map(&:upper_note)
  end

  def lower_notes
    [first_harmonic_interval, second_harmonic_interval].map(&:lower_note)
  end
end

Version data entries

32 entries across 32 versions & 1 rubygems

Version Path
head_music-4.0.1 lib/head_music/motion.rb
head_music-4.0.0 lib/head_music/motion.rb
head_music-3.0.1 lib/head_music/motion.rb
head_music-3.0.0 lib/head_music/motion.rb
head_music-2.0.1 lib/head_music/motion.rb
head_music-2.0.0 lib/head_music/motion.rb
head_music-1.0.0 lib/head_music/motion.rb
head_music-0.29.0 lib/head_music/motion.rb
head_music-0.28.0 lib/head_music/motion.rb
head_music-0.27.0 lib/head_music/motion.rb
head_music-0.26.3 lib/head_music/motion.rb
head_music-0.26.2 lib/head_music/motion.rb
head_music-0.26.1 lib/head_music/motion.rb
head_music-0.26.0 lib/head_music/motion.rb
head_music-0.25.0 lib/head_music/motion.rb
head_music-0.24.5 lib/head_music/motion.rb
head_music-0.24.4 lib/head_music/motion.rb
head_music-0.24.3 lib/head_music/motion.rb
head_music-0.24.2 lib/head_music/motion.rb
head_music-0.24.1 lib/head_music/motion.rb