Class: HeadMusic::Content::Voice

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/head_music/content/voice.rb

Overview

A Voice is a stream of music with some indepedence that is conceptually one part or for one performer. The melodic lines in counterpoint are each a voice.

Defined Under Namespace

Classes: MelodicNotePair

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(composition: nil, role: nil) ⇒ Voice

Returns a new instance of Voice.



13
14
15
16
17
# File 'lib/head_music/content/voice.rb', line 13

def initialize(composition: nil, role: nil)
  @composition = composition || HeadMusic::Content::Composition.new
  @role = role
  @placements = []
end

Instance Attribute Details

#compositionObject (readonly)

Returns the value of attribute composition.



9
10
11
# File 'lib/head_music/content/voice.rb', line 9

def composition
  @composition
end

#placementsObject (readonly)

Returns the value of attribute placements.



9
10
11
# File 'lib/head_music/content/voice.rb', line 9

def placements
  @placements
end

#roleObject (readonly)

Returns the value of attribute role.



9
10
11
# File 'lib/head_music/content/voice.rb', line 9

def role
  @role
end

Instance Method Details

#cantus_firmus?Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/head_music/content/voice.rb', line 81

def cantus_firmus?
  role.to_s =~ /cantus.?firmus/i
end

#earliest_bar_numberObject



101
102
103
104
105
# File 'lib/head_music/content/voice.rb', line 101

def earliest_bar_number
  return 1 if notes.empty?

  placements.first.position.bar_number
end

#highest_notesObject



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

def highest_notes
  notes.select { |note| note.pitch == highest_pitch }
end

#highest_pitchObject



42
43
44
# File 'lib/head_music/content/voice.rb', line 42

def highest_pitch
  pitches.max
end

#insert_into_placements(placement) ⇒ Object (private)



129
130
131
132
# File 'lib/head_music/content/voice.rb', line 129

def insert_into_placements(placement)
  @placements << placement
  @placements = @placements.sort
end

#large_leapsObject



77
78
79
# File 'lib/head_music/content/voice.rb', line 77

def large_leaps
  melodic_note_pairs.select(&:large_leap?)
end

#last_placementObject



113
114
115
# File 'lib/head_music/content/voice.rb', line 113

def last_placement
  placements.last
end

#latest_bar_numberObject



107
108
109
110
111
# File 'lib/head_music/content/voice.rb', line 107

def latest_bar_number
  return 1 if notes.empty?

  placements.last.position.bar_number
end

#leapsObject



73
74
75
# File 'lib/head_music/content/voice.rb', line 73

def leaps
  melodic_note_pairs.select(&:leap?)
end

#lowest_notesObject



54
55
56
# File 'lib/head_music/content/voice.rb', line 54

def lowest_notes
  notes.select { |note| note.pitch == lowest_pitch }
end

#lowest_pitchObject



46
47
48
# File 'lib/head_music/content/voice.rb', line 46

def lowest_pitch
  pitches.min
end

#melodic_intervalsObject



68
69
70
71
# File 'lib/head_music/content/voice.rb', line 68

def melodic_intervals
  @melodic_intervals ||=
    melodic_note_pairs.map { |note_pair| HeadMusic::Analysis::MelodicInterval.new(*note_pair.notes) }
end

#melodic_note_pairsObject



62
63
64
65
66
# File 'lib/head_music/content/voice.rb', line 62

def melodic_note_pairs
  @melodic_note_pairs ||= notes.each_cons(2).map do |note1, note2|
    HeadMusic::Content::Voice::MelodicNotePair.new(note1, note2)
  end
end

#next_positionObject



117
118
119
# File 'lib/head_music/content/voice.rb', line 117

def next_position
  last_placement ? last_placement.next_position : HeadMusic::Content::Position.new(composition, 1, 1, 0)
end

#note_at(position) ⇒ Object



85
86
87
# File 'lib/head_music/content/voice.rb', line 85

def note_at(position)
  notes.detect { |note| position.within_placement?(note) }
end

#note_following(position) ⇒ Object



97
98
99
# File 'lib/head_music/content/voice.rb', line 97

def note_following(position)
  notes.detect { |note| note.position > position }
end

#note_preceding(position) ⇒ Object



93
94
95
# File 'lib/head_music/content/voice.rb', line 93

def note_preceding(position)
  notes.reverse.find { |note| note.position < position }
end

#notesObject



25
26
27
# File 'lib/head_music/content/voice.rb', line 25

def notes
  @placements.select(&:note?).sort_by(&:position)
end

#notes_during(placement) ⇒ Object



89
90
91
# File 'lib/head_music/content/voice.rb', line 89

def notes_during(placement)
  notes.select { |note| note.during?(placement) }
end

#notes_not_in_keyObject



29
30
31
32
# File 'lib/head_music/content/voice.rb', line 29

def notes_not_in_key
  key_spellings = key_signature.pitches.map(&:spelling).uniq
  notes.reject { |note| key_spellings.include? note.pitch.spelling }
end

#pitchesObject



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

def pitches
  notes.map(&:pitch)
end

#pitches_stringObject (private)



134
135
136
# File 'lib/head_music/content/voice.rb', line 134

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

#place(position, rhythmic_value, pitch = nil) ⇒ Object



19
20
21
22
23
# File 'lib/head_music/content/voice.rb', line 19

def place(position, rhythmic_value, pitch = nil)
  HeadMusic::Content::Placement.new(self, position, rhythmic_value, pitch).tap do |placement|
    insert_into_placements(placement)
  end
end

#rangeObject



58
59
60
# File 'lib/head_music/content/voice.rb', line 58

def range
  HeadMusic::Analysis::DiatonicInterval.new(lowest_pitch, highest_pitch)
end

#restsObject



38
39
40
# File 'lib/head_music/content/voice.rb', line 38

def rests
  @placements.select(&:rest?)
end

#to_sObject



121
122
123
124
125
# File 'lib/head_music/content/voice.rb', line 121

def to_s
  return pitches_string if role.to_s.strip == ""

  [role, pitches_string].join(": ")
end