Class: HeadMusic::Analysis::Dyad

Inherits:
Object
  • Object
show all
Defined in:
lib/head_music/analysis/dyad.rb,
lib/head_music/analysis/dyad/chord_implication.rb

Overview

A Dyad is a two-pitch combination that can imply various chords. It analyzes the harmonic implications of two pitches sounding together.

Defined Under Namespace

Classes: ChordImplication

Constant Summary collapse

ALTERATION_SIGNS =
{-2 => "bb", -1 => "b", 0 => "", 1 => "#", 2 => "##"}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pitch1, pitch2, key: nil) ⇒ Dyad

Returns a new instance of Dyad.



9
10
11
12
13
14
15
# File 'lib/head_music/analysis/dyad.rb', line 9

def initialize(pitch1, pitch2, key: nil)
  @pitch1, @pitch2 = [
    HeadMusic::Rudiment::Pitch.get(pitch1),
    HeadMusic::Rudiment::Pitch.get(pitch2)
  ].sort
  @key = key ? HeadMusic::Rudiment::Key.get(key) : nil
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object



53
54
55
# File 'lib/head_music/analysis/dyad.rb', line 53

def method_missing(method_name, *args, &block)
  respond_to_missing?(method_name) ? interval.send(method_name, *args, &block) : super
end

Instance Attribute Details

#keyObject (readonly)

Returns the value of attribute key.



7
8
9
# File 'lib/head_music/analysis/dyad.rb', line 7

def key
  @key
end

#pitch1Object (readonly)

Returns the value of attribute pitch1.



7
8
9
# File 'lib/head_music/analysis/dyad.rb', line 7

def pitch1
  @pitch1
end

#pitch2Object (readonly)

Returns the value of attribute pitch2.



7
8
9
# File 'lib/head_music/analysis/dyad.rb', line 7

def pitch2
  @pitch2
end

Instance Method Details

#all_spellingsObject (private)



93
94
95
96
97
# File 'lib/head_music/analysis/dyad.rb', line 93

def all_spellings
  HeadMusic::Rudiment::LetterName.all.flat_map do |letter_name|
    ALTERATION_SIGNS.each_value.map { |sign| HeadMusic::Rudiment::Spelling.get("#{letter_name}#{sign}") }
  end.compact
end

#chord_implicationObject (private)



63
64
65
# File 'lib/head_music/analysis/dyad.rb', line 63

def chord_implication
  @chord_implication ||= ChordImplication.new([lower_pitch.pitch_class, upper_pitch.pitch_class], key)
end

#enharmonic_equivalents_for(pitch) ⇒ Object (private)



82
83
84
85
86
87
# File 'lib/head_music/analysis/dyad.rb', line 82

def enharmonic_equivalents_for(pitch)
  equivalent_pitches = enharmonic_spellings_for(pitch.pitch_class).map do |spelling|
    HeadMusic::Rudiment::Pitch.fetch_or_create(spelling, pitch.register)
  end
  [pitch, *equivalent_pitches].uniq(&:spelling)
end

#enharmonic_respellingsObject



45
46
47
# File 'lib/head_music/analysis/dyad.rb', line 45

def enharmonic_respellings
  @enharmonic_respellings ||= generate_enharmonic_respellings
end

#enharmonic_spellings_for(target_pitch_class) ⇒ Object (private)



89
90
91
# File 'lib/head_music/analysis/dyad.rb', line 89

def enharmonic_spellings_for(target_pitch_class)
  all_spellings.select { |spelling| spelling.pitch_class == target_pitch_class }
end

#generate_enharmonic_respellingsObject (private)



67
68
69
70
71
72
73
74
# File 'lib/head_music/analysis/dyad.rb', line 67

def generate_enharmonic_respellings
  lower_equivalents = enharmonic_equivalents_for(pitch1)
  upper_equivalents = enharmonic_equivalents_for(pitch2)

  lower_equivalents.product(upper_equivalents)
    .reject { |lower, upper| original_spelling?(lower, upper) }
    .map { |lower, upper| self.class.new(lower, upper, key: key) }
end

#intervalObject



17
18
19
# File 'lib/head_music/analysis/dyad.rb', line 17

def interval
  @interval ||= HeadMusic::Analysis::DiatonicInterval.new(lower_pitch, upper_pitch)
end

#lower_pitchObject



25
26
27
# File 'lib/head_music/analysis/dyad.rb', line 25

def lower_pitch
  @lower_pitch ||= [pitch1, pitch2].min
end

#original_spelling?(lower, upper) ⇒ Boolean (private)

Returns:

  • (Boolean)


76
77
78
# File 'lib/head_music/analysis/dyad.rb', line 76

def original_spelling?(lower, upper)
  lower.spelling == pitch1.spelling && upper.spelling == pitch2.spelling
end

#pitchesObject



21
22
23
# File 'lib/head_music/analysis/dyad.rb', line 21

def pitches
  [pitch1, pitch2]
end

#possible_seventh_chordsObject



41
42
43
# File 'lib/head_music/analysis/dyad.rb', line 41

def possible_seventh_chords
  chord_implication.seventh_chords
end

#possible_triadsObject



37
38
39
# File 'lib/head_music/analysis/dyad.rb', line 37

def possible_triads
  @possible_triads ||= possible_trichords.select(&:triad?)
end

#possible_trichordsObject



33
34
35
# File 'lib/head_music/analysis/dyad.rb', line 33

def possible_trichords
  chord_implication.trichords
end

#respond_to_missing?(method_name, *_args) ⇒ Boolean

Returns:

  • (Boolean)


57
58
59
# File 'lib/head_music/analysis/dyad.rb', line 57

def respond_to_missing?(method_name, *_args)
  interval.respond_to?(method_name)
end

#to_sObject



49
50
51
# File 'lib/head_music/analysis/dyad.rb', line 49

def to_s
  "#{pitch1} - #{pitch2}"
end

#upper_pitchObject



29
30
31
# File 'lib/head_music/analysis/dyad.rb', line 29

def upper_pitch
  @upper_pitch ||= [pitch1, pitch2].max
end