Class: Deftones::Component::Envelope
Constant Summary
collapse
- STATES =
%i[idle attack decay sustain release].freeze
Instance Attribute Summary collapse
#context, #input
Instance Method Summary
collapse
-
#active? ⇒ Boolean
-
#attack_value(time) ⇒ Object
private
-
#consume_events(time) ⇒ Object
private
-
#decay_value(time) ⇒ Object
private
-
#envelope_value_at(time) ⇒ Object
private
-
#idle? ⇒ Boolean
-
#initialize(attack: 0.01, decay: 0.1, sustain: 0.5, release: 1.0, context: Deftones.context) ⇒ Envelope
constructor
A new instance of Envelope.
-
#lerp(from, to, progress) ⇒ Object
private
-
#multichannel_process? ⇒ Boolean
-
#process(input_block, num_frames, start_frame, _cache) ⇒ Object
-
#release_value(time) ⇒ Object
private
-
#resolve_time(time) ⇒ Object
private
-
#sample_time(frame_index) ⇒ Object
private
-
#schedule_event(type, time, velocity) ⇒ Object
private
-
#transition_to(next_state, value, time) ⇒ Object
private
-
#trigger_attack(time = nil, velocity = 1.0) ⇒ Object
-
#trigger_attack_release(duration, time = nil, velocity = 1.0) ⇒ Object
-
#trigger_release(time = nil) ⇒ Object
#>>, #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, #name, #normalize_connection_index, #normalize_output_block, #now, #number_of_inputs, #number_of_outputs, #output, #output_for_connection, #output_for_index, #outputs, #raise_connection_index_error!, #reaches_node?, #render, #render_block, #set, #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(attack: 0.01, decay: 0.1, sustain: 0.5, release: 1.0, context: Deftones.context) ⇒ Envelope
Returns a new instance of Envelope.
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# File 'lib/deftones/component/envelope.rb', line 11
def initialize(attack: 0.01, decay: 0.1, sustain: 0.5, release: 1.0, context: Deftones.context)
super(context: context)
@attack = attack.to_f
@decay = decay.to_f
@sustain = sustain.to_f
@release = release.to_f
@state = :idle
@events = []
@current_value = 0.0
@velocity = 1.0
@stage_started_at = 0.0
@stage_from_value = 0.0
end
|
Instance Attribute Details
#attack ⇒ Object
Returns the value of attribute attack.
8
9
10
|
# File 'lib/deftones/component/envelope.rb', line 8
def attack
@attack
end
|
#decay ⇒ Object
Returns the value of attribute decay.
8
9
10
|
# File 'lib/deftones/component/envelope.rb', line 8
def decay
@decay
end
|
#release ⇒ Object
Returns the value of attribute release.
8
9
10
|
# File 'lib/deftones/component/envelope.rb', line 8
def release
@release
end
|
#state ⇒ Object
Returns the value of attribute state.
9
10
11
|
# File 'lib/deftones/component/envelope.rb', line 9
def state
@state
end
|
#sustain ⇒ Object
Returns the value of attribute sustain.
8
9
10
|
# File 'lib/deftones/component/envelope.rb', line 8
def sustain
@sustain
end
|
Instance Method Details
#active? ⇒ Boolean
39
40
41
|
# File 'lib/deftones/component/envelope.rb', line 39
def active?
@state != :idle || !@events.empty?
end
|
#attack_value(time) ⇒ Object
109
110
111
112
113
114
115
116
|
# File 'lib/deftones/component/envelope.rb', line 109
def attack_value(time)
return transition_to(:decay, @velocity, time) if @attack <= 0.0
progress = (time - @stage_started_at) / @attack
return transition_to(:decay, @velocity, @stage_started_at + @attack) if progress >= 1.0
lerp(@stage_from_value, @velocity, progress)
end
|
#consume_events(time) ⇒ Object
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
# File 'lib/deftones/component/envelope.rb', line 74
def consume_events(time)
while @events.any? && @events.first[:time] <= time
event = @events.shift
case event[:type]
when :attack
@state = :attack
@velocity = event[:velocity] || 1.0
@stage_started_at = event[:time]
@stage_from_value = @current_value
when :release
@state = :release
@stage_started_at = event[:time]
@stage_from_value = @current_value
end
end
end
|
#decay_value(time) ⇒ Object
118
119
120
121
122
123
124
125
126
|
# File 'lib/deftones/component/envelope.rb', line 118
def decay_value(time)
sustain_level = @velocity * @sustain
return transition_to(:sustain, sustain_level, time) if @decay <= 0.0
progress = (time - @stage_started_at) / @decay
return transition_to(:sustain, sustain_level, @stage_started_at + @decay) if progress >= 1.0
lerp(@velocity, sustain_level, progress)
end
|
#envelope_value_at(time) ⇒ Object
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
# File 'lib/deftones/component/envelope.rb', line 92
def envelope_value_at(time)
case @state
when :idle
0.0
when :attack
attack_value(time)
when :decay
decay_value(time)
when :sustain
@velocity * @sustain
when :release
release_value(time)
else
0.0
end
end
|
#idle? ⇒ Boolean
43
44
45
|
# File 'lib/deftones/component/envelope.rb', line 43
def idle?
!active?
end
|
#lerp(from, to, progress) ⇒ Object
145
146
147
|
# File 'lib/deftones/component/envelope.rb', line 145
def lerp(from, to, progress)
from + ((to - from) * progress.clamp(0.0, 1.0))
end
|
#multichannel_process? ⇒ Boolean
47
48
49
|
# File 'lib/deftones/component/envelope.rb', line 47
def multichannel_process?
true
end
|
#process(input_block, num_frames, start_frame, _cache) ⇒ Object
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
# File 'lib/deftones/component/envelope.rb', line 51
def process(input_block, num_frames, start_frame, _cache)
values = Array.new(num_frames) do |index|
time = sample_time(start_frame + index)
consume_events(time)
@current_value = envelope_value_at(time)
@current_value
end
Core::AudioBlock.from_channel_data(
input_block.channel_data.map do |channel|
Array.new(num_frames) { |index| channel[index] * values[index] }
end
)
end
|
#release_value(time) ⇒ Object
128
129
130
131
132
133
134
135
|
# File 'lib/deftones/component/envelope.rb', line 128
def release_value(time)
return transition_to(:idle, 0.0, time) if @release <= 0.0
progress = (time - @stage_started_at) / @release
return transition_to(:idle, 0.0, @stage_started_at + @release) if progress >= 1.0
lerp(@stage_from_value, 0.0, progress)
end
|
#resolve_time(time) ⇒ Object
149
150
151
152
153
|
# File 'lib/deftones/component/envelope.rb', line 149
def resolve_time(time)
return context.current_time if time.nil?
Deftones::Music::Time.parse(time)
end
|
#sample_time(frame_index) ⇒ Object
155
156
157
|
# File 'lib/deftones/component/envelope.rb', line 155
def sample_time(frame_index)
frame_index.to_f / context.sample_rate
end
|
#schedule_event(type, time, velocity) ⇒ Object
68
69
70
71
72
|
# File 'lib/deftones/component/envelope.rb', line 68
def schedule_event(type, time, velocity)
@events << { type: type, time: time, velocity: velocity }
@events.sort_by! { |event| event[:time] }
self
end
|
#transition_to(next_state, value, time) ⇒ Object
137
138
139
140
141
142
143
|
# File 'lib/deftones/component/envelope.rb', line 137
def transition_to(next_state, value, time)
@state = next_state
@stage_started_at = time
@stage_from_value = value
@current_value = value
value
end
|
#trigger_attack(time = nil, velocity = 1.0) ⇒ Object
25
26
27
|
# File 'lib/deftones/component/envelope.rb', line 25
def trigger_attack(time = nil, velocity = 1.0)
schedule_event(:attack, resolve_time(time), velocity.to_f)
end
|
#trigger_attack_release(duration, time = nil, velocity = 1.0) ⇒ Object
33
34
35
36
37
|
# File 'lib/deftones/component/envelope.rb', line 33
def trigger_attack_release(duration, time = nil, velocity = 1.0)
attack_time = resolve_time(time)
trigger_attack(attack_time, velocity)
trigger_release(attack_time + Deftones::Music::Time.parse(duration))
end
|
#trigger_release(time = nil) ⇒ Object
29
30
31
|
# File 'lib/deftones/component/envelope.rb', line 29
def trigger_release(time = nil)
schedule_event(:release, resolve_time(time), nil)
end
|