Class: Deftones::Instrument::PolySynth
Constant Summary
collapse
- VOICE_STEALING_POLICIES =
%i[oldest newest quietest released_first].freeze
- RETRIGGER_POLICIES =
%i[restart ignore].freeze
Instance Attribute Summary collapse
#mute, #output, #volume
#context, #input
Instance Method Summary
collapse
-
#active? ⇒ Boolean
-
#active_notes ⇒ Object
-
#active_voice_count ⇒ Object
-
#allocate_voice(note, time) ⇒ Object
private
-
#cleanup_inactive_voices! ⇒ Object
private
-
#initialize(voice_class = Synth, voices: 8, voice_stealing: :oldest, retrigger: :restart, context: Deftones.context, **voice_options) ⇒ PolySynth
constructor
A new instance of PolySynth.
-
#loaded? ⇒ Boolean
(also: #loaded)
-
#max_polyphony ⇒ Object
-
#normalize_retrigger(policy) ⇒ Object
private
-
#normalize_voice_stealing(policy) ⇒ Object
private
-
#play(notes, duration: "8n", at: nil, velocity: 1.0) ⇒ Object
-
#release_all(time = nil) ⇒ Object
(also: #releaseAll)
-
#resolve_time(time) ⇒ Object
private
-
#set(strict: false, **params) ⇒ Object
-
#steal_voice_entry(time) ⇒ Object
private
-
#trigger_attack(note, time = nil, velocity = 1.0) ⇒ Object
-
#trigger_release(note, time = nil) ⇒ Object
#apply_volume!, #dispose, #get, #input, #mute?, #render, #render_block, #triggerAttack, #triggerAttackRelease, #triggerRelease
#>>, #attach_destination, #attach_source, #block_time, #chain, #channel_count, #channel_count_mode, #channel_interpretation, #connect, #connected?, #default_input_channels, #default_output_channels, #destination_for_connection, #detach_all_destinations, #detach_destination, #detach_source, #disconnect, #dispose, #disposed?, #fan, #get, #immediate, #input_for_index, #inputs, #mix_source_blocks, #multichannel_process?, #name, #normalize_connection_index, #normalize_output_block, #now, #number_of_inputs, #number_of_outputs, #output, #output_for_connection, #output_for_index, #outputs, #process, #raise_connection_index_error!, #reaches_node?, #render, #render_block, #sample_time, #to_destination, #to_frequency, #to_master, #to_midi, #to_output, #to_s, #to_seconds, #to_ticks, #uses_legacy_render_for_block?, #validate_connectable!, #validate_connection_index!
Constructor Details
#initialize(voice_class = Synth, voices: 8, voice_stealing: :oldest, retrigger: :restart, context: Deftones.context, **voice_options) ⇒ PolySynth
Returns a new instance of PolySynth.
11
12
13
14
15
16
17
18
19
20
|
# File 'lib/deftones/instrument/poly_synth.rb', line 11
def initialize(voice_class = Synth, voices: 8, voice_stealing: :oldest, retrigger: :restart,
context: Deftones.context, **voice_options)
super(context: context)
@voice_class = voice_class
@voice_pool = Array.new(voices) { @voice_class.new(context: context, **voice_options) }
@voice_pool.each { |voice| voice >> @output }
@voice_stealing = normalize_voice_stealing(voice_stealing)
@retrigger = normalize_retrigger(retrigger)
@active_voices = {}
end
|
Instance Attribute Details
#retrigger ⇒ Object
Returns the value of attribute retrigger.
9
10
11
|
# File 'lib/deftones/instrument/poly_synth.rb', line 9
def retrigger
@retrigger
end
|
#voice_pool ⇒ Object
Returns the value of attribute voice_pool.
9
10
11
|
# File 'lib/deftones/instrument/poly_synth.rb', line 9
def voice_pool
@voice_pool
end
|
#voice_stealing ⇒ Object
Returns the value of attribute voice_stealing.
9
10
11
|
# File 'lib/deftones/instrument/poly_synth.rb', line 9
def voice_stealing
@voice_stealing
end
|
Instance Method Details
#active? ⇒ Boolean
94
95
96
|
# File 'lib/deftones/instrument/poly_synth.rb', line 94
def active?
@voice_pool.any?(&:active?)
end
|
#active_notes ⇒ Object
98
99
100
|
# File 'lib/deftones/instrument/poly_synth.rb', line 98
def active_notes
@active_voices.keys
end
|
#active_voice_count ⇒ Object
102
103
104
|
# File 'lib/deftones/instrument/poly_synth.rb', line 102
def active_voice_count
@active_voices.length
end
|
#allocate_voice(note, time) ⇒ Object
108
109
110
111
112
113
114
115
116
117
118
119
|
# File 'lib/deftones/instrument/poly_synth.rb', line 108
def allocate_voice(note, time)
cleanup_inactive_voices!
return @active_voices[note][:voice] if @active_voices.key?(note)
active_voice_ids = @active_voices.values.map { |entry| entry[:voice].object_id }
available_voice = @voice_pool.find { |voice| !active_voice_ids.include?(voice.object_id) }
return available_voice if available_voice
stolen_note, stolen_entry = steal_voice_entry(time)
@active_voices.delete(stolen_note)
stolen_entry[:voice]
end
|
#cleanup_inactive_voices! ⇒ Object
137
138
139
|
# File 'lib/deftones/instrument/poly_synth.rb', line 137
def cleanup_inactive_voices!
@active_voices.delete_if { |_, entry| entry[:released_at] && !entry[:voice].active? }
end
|
#loaded? ⇒ Boolean
Also known as:
loaded
87
88
89
|
# File 'lib/deftones/instrument/poly_synth.rb', line 87
def loaded?
!disposed?
end
|
#max_polyphony ⇒ Object
83
84
85
|
# File 'lib/deftones/instrument/poly_synth.rb', line 83
def max_polyphony
@voice_pool.length
end
|
#normalize_retrigger(policy) ⇒ Object
148
149
150
151
152
153
|
# File 'lib/deftones/instrument/poly_synth.rb', line 148
def normalize_retrigger(policy)
normalized = policy.to_sym
return normalized if RETRIGGER_POLICIES.include?(normalized)
raise ArgumentError, "Unsupported retrigger policy: #{policy}"
end
|
#normalize_voice_stealing(policy) ⇒ Object
141
142
143
144
145
146
|
# File 'lib/deftones/instrument/poly_synth.rb', line 141
def normalize_voice_stealing(policy)
normalized = policy.to_sym
return normalized if VOICE_STEALING_POLICIES.include?(normalized)
raise ArgumentError, "Unsupported voice stealing policy: #{policy}"
end
|
#play(notes, duration: "8n", at: nil, velocity: 1.0) ⇒ Object
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
# File 'lib/deftones/instrument/poly_synth.rb', line 22
def play(notes, duration: "8n", at: nil, velocity: 1.0)
scheduled_time = resolve_time(at)
Array(notes).compact.each do |note|
trigger_attack(note, scheduled_time, velocity)
end
release_time = scheduled_time + Deftones::Music::Time.parse(duration)
Array(notes).compact.each do |note|
trigger_release(note, release_time)
end
self
end
|
#release_all(time = nil) ⇒ Object
Also known as:
releaseAll
76
77
78
79
80
81
|
# File 'lib/deftones/instrument/poly_synth.rb', line 76
def release_all(time = nil)
scheduled_time = resolve_time(time)
@active_voices.each_value { |entry| entry[:voice].trigger_release(scheduled_time) }
@active_voices.clear
self
end
|
#resolve_time(time) ⇒ Object
155
156
157
158
159
|
# File 'lib/deftones/instrument/poly_synth.rb', line 155
def resolve_time(time)
return context.current_time if time.nil?
Deftones::Music::Time.parse(time)
end
|
#set(strict: false, **params) ⇒ Object
63
64
65
66
67
68
69
70
71
72
73
74
|
# File 'lib/deftones/instrument/poly_synth.rb', line 63
def set(strict: false, **params)
unknown = params.keys.reject { |key| @voice_pool.all? { |voice| voice.respond_to?(:"#{key}=") } }
raise ArgumentError, "Unknown parameter(s): #{unknown.join(', ')}" if strict && unknown.any?
@voice_pool.each do |voice|
params.each do |key, value|
writer = :"#{key}="
voice.public_send(writer, value) if voice.respond_to?(writer)
end
end
self
end
|
#steal_voice_entry(time) ⇒ Object
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
# File 'lib/deftones/instrument/poly_synth.rb', line 121
def steal_voice_entry(time)
case @voice_stealing
when :newest
@active_voices.max_by { |_, entry| entry[:attacked_at] }
when :quietest
@active_voices.min_by { |_, entry| entry[:velocity] }
when :released_first
released = @active_voices.select { |_, entry| entry[:released_at] && entry[:released_at] <= time }
return released.min_by { |_, entry| entry[:released_at] } if released.any?
@active_voices.min_by { |_, entry| entry[:attacked_at] }
else
@active_voices.min_by { |_, entry| entry[:attacked_at] }
end
end
|
#trigger_attack(note, time = nil, velocity = 1.0) ⇒ Object
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
# File 'lib/deftones/instrument/poly_synth.rb', line 37
def trigger_attack(note, time = nil, velocity = 1.0)
scheduled_time = resolve_time(time)
return self if @active_voices.key?(note) && @retrigger == :ignore
voice = allocate_voice(note, scheduled_time)
@active_voices.delete(note)
@active_voices[note] = {
voice: voice,
attacked_at: scheduled_time,
released_at: nil,
velocity: velocity.to_f
}
voice.trigger_attack(note, scheduled_time, velocity)
self
end
|
#trigger_release(note, time = nil) ⇒ Object
53
54
55
56
57
58
59
60
61
|
# File 'lib/deftones/instrument/poly_synth.rb', line 53
def trigger_release(note, time = nil)
entry = @active_voices[note]
return self unless entry
scheduled_time = resolve_time(time)
entry[:released_at] = scheduled_time
entry[:voice].trigger_release(scheduled_time)
self
end
|