Class: HeadMusic::Analysis::Sonority

Inherits:
Object
  • Object
show all
Defined in:
lib/head_music/analysis/sonority.rb

Overview

A Sonority describes a set of pitch class intervalic relationships. For example, a minor triad, or a major-minor seventh chord. The Sonority class is a factory for returning one of its subclasses.

Constant Summary collapse

SONORITIES =
{
  major_triad: %w[M3 P5],
  minor_triad: %w[m3 P5],
  diminished_triad: %w[m3 d5],
  augmented_triad: %w[M3 A5],
  major_minor_seventh_chord: %w[M3 P5 m7],
  major_major_seventh_chord: %w[M3 P5 M7],
  minor_minor_seventh_chord: %w[m3 P5 m7],
  minor_major_seventh_chord: %w[m3 P5 M7],
  half_diminished_seventh_chord: %w[m3 d5 m7],
  diminished_seventh_chord: %w[m3 d5 d7],
  dominant_ninth_chord: %w[M2 M3 P5 m7],
  dominant_minor_ninth_chord: %w[m2 M3 P5 m7],
  minor_ninth_chord: %w[M2 m3 P5 m7],
  major_ninth_chord: %w[M2 M3 P5 M7],
  six_nine_chord: %w[M2 M3 P5 M6],
  minor_six_nine_chord: %w[M2 m3 P5 M6],
  suspended_four_chord: %w[P4 P5],
  suspended_two_chord: %w[M2 P5],
  quartal_chord: %w[P4 m7]
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pitch_set) ⇒ Sonority

Returns a new instance of Sonority.



39
40
41
42
# File 'lib/head_music/analysis/sonority.rb', line 39

def initialize(pitch_set)
  @pitch_set = pitch_set
  identifier
end

Instance Attribute Details

#pitch_setObject (readonly)

Returns the value of attribute pitch_set.



30
31
32
# File 'lib/head_music/analysis/sonority.rb', line 30

def pitch_set
  @pitch_set
end

Instance Method Details

#==(other) ⇒ Object



119
120
121
122
123
# File 'lib/head_music/analysis/sonority.rb', line 119

def ==(other)
  other = HeadMusic::Analysis::PitchSet.new(other) if other.is_a?(Array)
  other = self.class.new(other) if other.is_a?(HeadMusic::Analysis::PitchSet)
  identifier == other.identifier
end

#consonant?Boolean

Returns:

  • (Boolean)


76
77
78
79
80
# File 'lib/head_music/analysis/sonority.rb', line 76

def consonant?
  @consonant ||=
    pitch_set.reduction_diatonic_intervals.all?(&:consonant?) &&
    root_position.diatonic_intervals_above_bass_pitch.all?(&:consonant?)
end

#diatonic_intervals_above_bass_pitchObject



112
113
114
115
116
117
# File 'lib/head_music/analysis/sonority.rb', line 112

def diatonic_intervals_above_bass_pitch
  return [] unless identifier

  @diatonic_intervals_above_bass_pitch ||=
    SONORITIES[identifier].map { |shorthand| HeadMusic::Analysis::DiatonicInterval.get(shorthand) }
end

#identifierObject



44
45
46
47
48
49
50
51
52
# File 'lib/head_music/analysis/sonority.rb', line 44

def identifier
  return @identifier if defined?(@identifier)

  @identifier = SONORITIES.keys.detect do |key|
    inversions.map do |inversion|
      inversion.diatonic_intervals_above_bass_pitch.map(&:shorthand)
    end.include?(SONORITIES[key])
  end
end

#inversionObject



54
55
56
57
58
# File 'lib/head_music/analysis/sonority.rb', line 54

def inversion
  @inversion ||= inversions.index do |inversion|
    SONORITIES[identifier] == inversion.diatonic_intervals_above_bass_pitch.map(&:shorthand)
  end
end

#inversionsObject



60
61
62
63
64
65
66
67
68
69
70
# File 'lib/head_music/analysis/sonority.rb', line 60

def inversions
  @inversions ||= begin
    inversion = reduction
    inversions = []
    inversion.pitches.length.times do |_i|
      inversions << inversion
      inversion = inversion.uninvert
    end
    inversions
  end
end

#quartal?Boolean Also known as: quintal?

Returns:

  • (Boolean)


103
104
105
106
107
108
109
# File 'lib/head_music/analysis/sonority.rb', line 103

def quartal?
  @quartal ||= inversions.detect do |inversion|
    inversion.diatonic_intervals.count do |interval|
      interval.fourth? || interval.fifth?
    end.to_f / inversion.diatonic_intervals.length > 0.5
  end
end

#root_positionObject



72
73
74
# File 'lib/head_music/analysis/sonority.rb', line 72

def root_position
  @root_position ||= inversions[inversion]
end

#secundal?Boolean

Returns:

  • (Boolean)


97
98
99
100
101
# File 'lib/head_music/analysis/sonority.rb', line 97

def secundal?
  @secundal ||= inversions.detect do |inversion|
    inversion.diatonic_intervals.count(&:second?).to_f / inversion.diatonic_intervals.length > 0.5
  end
end

#seventh_chord?Boolean

Returns:

  • (Boolean)


86
87
88
# File 'lib/head_music/analysis/sonority.rb', line 86

def seventh_chord?
  @seventh_chord ||= tetrachord? && tertian?
end

#tertian?Boolean

Returns:

  • (Boolean)


90
91
92
93
94
95
# File 'lib/head_music/analysis/sonority.rb', line 90

def tertian?
  @tertian ||= inversions.detect do |inversion|
    inversion.diatonic_intervals.count(&:third?).to_f / inversion.diatonic_intervals.length > 0.5 ||
      (scale_degrees_above_bass_pitch && [3, 5, 7]).length == 3
  end
end

#triad?Boolean

Returns:

  • (Boolean)


82
83
84
# File 'lib/head_music/analysis/sonority.rb', line 82

def triad?
  @triad ||= trichord? && tertian?
end