Class: HeadMusic::Analysis::Sonority
- Inherits:
-
Object
- Object
- HeadMusic::Analysis::Sonority
- 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
- DEFAULT_ROOT =
"C4"
Instance Attribute Summary collapse
-
#pitch_collection ⇒ Object
readonly
Returns the value of attribute pitch_collection.
Class Method Summary collapse
-
.get(identifier, root: DEFAULT_ROOT, inversion: 0) ⇒ Sonority?
Factory method to get a sonority by identifier Returns a Sonority with pitches starting at the default root (C4).
-
.identifiers ⇒ Array<Symbol>
Returns all available sonority identifiers.
Instance Method Summary collapse
-
#==(other) ⇒ Object
-
#consonant? ⇒ Boolean
-
#diatonic_intervals_above_bass_pitch ⇒ Object
-
#identifier ⇒ Object
-
#initialize(pitch_collection) ⇒ Sonority
constructor
A new instance of Sonority.
-
#interval_ratio(inversion, &predicate) ⇒ Object
private
Fraction of an inversion’s diatonic intervals that satisfy the given predicate.
-
#inversion ⇒ Object
-
#inversions ⇒ Object
-
#quartal? ⇒ Boolean
(also: #quintal?)
-
#root_position ⇒ Object
-
#secundal? ⇒ Boolean
Constructor Details
#initialize(pitch_collection) ⇒ Sonority
Returns a new instance of Sonority.
78 79 80 81 |
# File 'lib/head_music/analysis/sonority.rb', line 78 def initialize(pitch_collection) @pitch_collection = pitch_collection identifier end |
Instance Attribute Details
#pitch_collection ⇒ Object (readonly)
Returns the value of attribute pitch_collection.
68 69 70 |
# File 'lib/head_music/analysis/sonority.rb', line 68 def pitch_collection @pitch_collection end |
Class Method Details
.get(identifier, root: DEFAULT_ROOT, inversion: 0) ⇒ Sonority?
Factory method to get a sonority by identifier Returns a Sonority with pitches starting at the default root (C4)
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/head_music/analysis/sonority.rb', line 39 def self.get(identifier, root: DEFAULT_ROOT, inversion: 0) identifier = identifier.to_sym return nil unless SONORITIES.key?(identifier) root_pitch = HeadMusic::Rudiment::Pitch.get(root) interval_shorthands = SONORITIES[identifier] # Build pitches: root + intervals above root pitches = [root_pitch] + interval_shorthands.map do |shorthand| interval = HeadMusic::Analysis::DiatonicInterval.get(shorthand) interval.above(root_pitch) end pitch_collection = HeadMusic::Analysis::PitchCollection.new(pitches) # Apply inversions if requested inversion.times do pitch_collection = pitch_collection.invert end new(pitch_collection) end |
.identifiers ⇒ Array<Symbol>
Returns all available sonority identifiers
64 65 66 |
# File 'lib/head_music/analysis/sonority.rb', line 64 def self.identifiers SONORITIES.keys end |
Instance Method Details
#==(other) ⇒ Object
139 140 141 142 143 |
# File 'lib/head_music/analysis/sonority.rb', line 139 def ==(other) other = HeadMusic::Analysis::PitchCollection.new(other) if other.is_a?(Array) other = self.class.new(other) if other.is_a?(HeadMusic::Analysis::PitchCollection) identifier == other.identifier end |
#consonant? ⇒ Boolean
115 116 117 118 119 |
# File 'lib/head_music/analysis/sonority.rb', line 115 def consonant? @consonant ||= pitch_collection.reduction_diatonic_intervals.all?(&:consonant?) && root_position.diatonic_intervals_above_bass_pitch.all?(&:consonant?) end |
#diatonic_intervals_above_bass_pitch ⇒ Object
132 133 134 135 136 137 |
# File 'lib/head_music/analysis/sonority.rb', line 132 def diatonic_intervals_above_bass_pitch return [] unless identifier @diatonic_intervals_above_bass_pitch ||= SONORITIES[identifier].map { |shorthand| HeadMusic::Analysis::DiatonicInterval.get(shorthand) } end |
#identifier ⇒ Object
83 84 85 86 87 88 89 90 91 |
# File 'lib/head_music/analysis/sonority.rb', line 83 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 |
#interval_ratio(inversion, &predicate) ⇒ Object (private)
Fraction of an inversion’s diatonic intervals that satisfy the given predicate.
148 149 150 151 |
# File 'lib/head_music/analysis/sonority.rb', line 148 def interval_ratio(inversion, &predicate) intervals = inversion.diatonic_intervals intervals.count(&predicate).to_f / intervals.length end |
#inversion ⇒ Object
93 94 95 96 97 |
# File 'lib/head_music/analysis/sonority.rb', line 93 def inversion @inversion ||= inversions.index do |inversion| SONORITIES[identifier] == inversion.diatonic_intervals_above_bass_pitch.map(&:shorthand) end end |
#inversions ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/head_music/analysis/sonority.rb', line 99 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?
125 126 127 128 129 |
# File 'lib/head_music/analysis/sonority.rb', line 125 def quartal? @quartal ||= inversions.detect do |inversion| interval_ratio(inversion) { |interval| interval.fourth? || interval.fifth? } > 0.5 end end |
#root_position ⇒ Object
111 112 113 |
# File 'lib/head_music/analysis/sonority.rb', line 111 def root_position @root_position ||= inversions[inversion] end |
#secundal? ⇒ Boolean
121 122 123 |
# File 'lib/head_music/analysis/sonority.rb', line 121 def secundal? @secundal ||= inversions.detect { |inversion| interval_ratio(inversion, &:second?) > 0.5 } end |