Class: HeadMusic::PitchSet

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

Overview

A PitchSet is a collection of one or more pitches. See also: PitchClassSet

Constant Summary collapse

TERTIAN_SONORITIES =
{
  implied_triad: [3],
  triad: [3, 5],
  seventh_chord: [3, 5, 7],
  ninth_chord: [2, 3, 5, 7],
  eleventh_chord: [2, 3, 4, 5, 7],
  thirteenth_chord: [2, 3, 4, 5, 6, 7] # a.k.a. diatonic scale
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pitches) ⇒ PitchSet

Returns a new instance of PitchSet.



22
23
24
# File 'lib/head_music/pitch_set.rb', line 22

def initialize(pitches)
  @pitches = pitches.map { |pitch| HeadMusic::Pitch.get(pitch) }.sort.uniq
end

Instance Attribute Details

#pitchesObject (readonly)

Returns the value of attribute pitches.



13
14
15
# File 'lib/head_music/pitch_set.rb', line 13

def pitches
  @pitches
end

Instance Method Details

#==(other) ⇒ Object



88
89
90
# File 'lib/head_music/pitch_set.rb', line 88

def ==(other)
  pitches.sort == other.pitches.sort
end

#augmented_triad?Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/head_music/pitch_set.rb', line 120

def augmented_triad?
  [%w[M3 M3], %w[M3 d4], %w[d4 M3]].include? reduction_diatonic_intervals.map(&:shorthand)
end

#bass_pitchObject



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

def bass_pitch
  @bass_pitch ||= pitches.first
end

#consonant_triad?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/head_music/pitch_set.rb', line 104

def consonant_triad?
  major_triad? || minor_triad?
end

#diatonic_intervalsObject



38
39
40
41
42
# File 'lib/head_music/pitch_set.rb', line 38

def diatonic_intervals
  @diatonic_intervals ||= pitches.each_cons(2).map do |pitch_pair|
    HeadMusic::DiatonicInterval.new(*pitch_pair)
  end
end

#diatonic_intervals_above_bass_pitchObject



44
45
46
47
48
# File 'lib/head_music/pitch_set.rb', line 44

def diatonic_intervals_above_bass_pitch
  @diatonic_intervals_above_bass_pitch ||= pitches_above_bass_pitch.map do |pitch|
    HeadMusic::DiatonicInterval.new(bass_pitch, pitch)
  end
end

#diminished_triad?Boolean

Returns:

  • (Boolean)


116
117
118
# File 'lib/head_music/pitch_set.rb', line 116

def diminished_triad?
  [%w[m3 m3], %w[m3 A4], %w[A4 m3]].include? reduction_diatonic_intervals.map(&:shorthand)
end

#eleventh_chord?Boolean

Returns:

  • (Boolean)


160
161
162
# File 'lib/head_music/pitch_set.rb', line 160

def eleventh_chord?
  hexachord? && tertian?
end

#equivalent?(other) ⇒ Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/head_music/pitch_set.rb', line 92

def equivalent?(other)
  pitch_classes.sort == other.pitch_classes.sort
end

#first_inversion_seventh_chord?Boolean

Returns:

  • (Boolean)


144
145
146
# File 'lib/head_music/pitch_set.rb', line 144

def first_inversion_seventh_chord?
  tetrachord? && reduction.uninvert.diatonic_intervals.all?(&:third?)
end

#first_inversion_triad?Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/head_music/pitch_set.rb', line 128

def first_inversion_triad?
  trichord? && reduction.uninvert.diatonic_intervals.all?(&:third?)
end

#inspectObject



80
81
82
# File 'lib/head_music/pitch_set.rb', line 80

def inspect
  pitches.map(&:to_s).join(" ")
end

#integer_notationObject



54
55
56
57
58
59
60
61
62
# File 'lib/head_music/pitch_set.rb', line 54

def integer_notation
  # questions:
  # - should this be absolute? 0 = C?
  # - should there be both absolute and relative versions?
  @integer_notation ||= begin
    return [] if pitches.empty?
    diatonic_intervals_above_bass_pitch.map { |interval| interval.semitones % 12 }.flatten.sort.unshift(0).uniq
  end
end

#invertObject



64
65
66
67
68
# File 'lib/head_music/pitch_set.rb', line 64

def invert
  inverted_pitch = pitches[0] + HeadMusic::DiatonicInterval.get("perfect octave")
  new_pitches = pitches.drop(1) + [inverted_pitch]
  HeadMusic::PitchSet.new(new_pitches)
end

#major_triad?Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/head_music/pitch_set.rb', line 108

def major_triad?
  [%w[M3 m3], %w[m3 P4], %w[P4 M3]].include? reduction_diatonic_intervals.map(&:shorthand)
end

#minor_triad?Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/head_music/pitch_set.rb', line 112

def minor_triad?
  [%w[m3 M3], %w[M3 P4], %w[P4 m3]].include? reduction_diatonic_intervals.map(&:shorthand)
end

#ninth_chord?Boolean

Returns:

  • (Boolean)


156
157
158
# File 'lib/head_music/pitch_set.rb', line 156

def ninth_chord?
  pentachord? && tertian?
end

#pitch_class_setObject



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

def pitch_class_set
  @pitch_class_set ||= HeadMusic::PitchClassSet.new(pitch_classes)
end

#pitch_classesObject



26
27
28
# File 'lib/head_music/pitch_set.rb', line 26

def pitch_classes
  @pitch_classes ||= reduction_pitches.map(&:pitch_class).uniq
end

#pitches_above_bass_pitchObject



50
51
52
# File 'lib/head_music/pitch_set.rb', line 50

def pitches_above_bass_pitch
  @pitches_above_bass_pitch ||= pitches.drop(1)
end

#reductionObject



34
35
36
# File 'lib/head_music/pitch_set.rb', line 34

def reduction
  @reduction ||= HeadMusic::PitchSet.new(reduction_pitches)
end

#root_position_seventh_chord?Boolean

Returns:

  • (Boolean)


140
141
142
# File 'lib/head_music/pitch_set.rb', line 140

def root_position_seventh_chord?
  tetrachord? && reduction_diatonic_intervals.all?(&:third?)
end

#root_position_triad?Boolean

Returns:

  • (Boolean)


124
125
126
# File 'lib/head_music/pitch_set.rb', line 124

def root_position_triad?
  trichord? && reduction_diatonic_intervals.all?(&:third?)
end

#scale_degreesObject



179
180
181
# File 'lib/head_music/pitch_set.rb', line 179

def scale_degrees
  @scale_degrees ||= pitches.empty? ? [] : scale_degrees_above_bass_pitch.unshift(1)
end

#scale_degrees_above_bass_pitchObject



183
184
185
# File 'lib/head_music/pitch_set.rb', line 183

def scale_degrees_above_bass_pitch
  @scale_degrees_above_bass_pitch ||= diatonic_intervals_above_bass_pitch.map(&:simple_number).sort - [8]
end

#second_inversion_seventh_chord?Boolean

Returns:

  • (Boolean)


148
149
150
# File 'lib/head_music/pitch_set.rb', line 148

def second_inversion_seventh_chord?
  tetrachord? && reduction.uninvert.uninvert.diatonic_intervals.all?(&:third?)
end

#second_inversion_triad?Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/head_music/pitch_set.rb', line 132

def second_inversion_triad?
  trichord? && reduction.invert.diatonic_intervals.all?(&:third?)
end

#seventh_chord?Boolean

Returns:

  • (Boolean)


136
137
138
# File 'lib/head_music/pitch_set.rb', line 136

def seventh_chord?
  tetrachord? && tertian?
end

#sizeObject



96
97
98
# File 'lib/head_music/pitch_set.rb', line 96

def size
  pitches.length
end

#tertian?Boolean

Returns:

  • (Boolean)


168
169
170
171
172
173
174
175
176
177
# File 'lib/head_music/pitch_set.rb', line 168

def tertian?
  return false unless diatonic_intervals.any?

  inversion = reduction
  pitches.length.times do
    return true if TERTIAN_SONORITIES.value?(inversion.scale_degrees_above_bass_pitch)
    inversion = inversion.invert
  end
  false
end

#third_inversion_seventh_chord?Boolean

Returns:

  • (Boolean)


152
153
154
# File 'lib/head_music/pitch_set.rb', line 152

def third_inversion_seventh_chord?
  tetrachord? && reduction.invert.diatonic_intervals.all?(&:third?)
end

#thirteenth_chord?Boolean

Returns:

  • (Boolean)


164
165
166
# File 'lib/head_music/pitch_set.rb', line 164

def thirteenth_chord?
  heptachord? && tertian?
end

#to_sObject



84
85
86
# File 'lib/head_music/pitch_set.rb', line 84

def to_s
  pitches.map(&:to_s).join(" ")
end

#triad?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/head_music/pitch_set.rb', line 100

def triad?
  trichord? && tertian?
end

#uninvertObject



70
71
72
73
74
# File 'lib/head_music/pitch_set.rb', line 70

def uninvert
  inverted_pitch = pitches[-1] - HeadMusic::DiatonicInterval.get("perfect octave")
  new_pitches = [inverted_pitch] + pitches[0..-2]
  HeadMusic::PitchSet.new(new_pitches)
end