deftones 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -6
- data/README.md +5 -0
- data/Rakefile +50 -1
- data/lib/deftones/analysis/meter.rb +22 -2
- data/lib/deftones/component/channel.rb +1 -1
- data/lib/deftones/component/compressor.rb +127 -22
- data/lib/deftones/component/filter.rb +29 -19
- data/lib/deftones/component/merge.rb +14 -0
- data/lib/deftones/component/multiband_compressor.rb +1 -1
- data/lib/deftones/component/one_pole_filter.rb +10 -3
- data/lib/deftones/component/panner.rb +25 -2
- data/lib/deftones/component/panner3d.rb +0 -10
- data/lib/deftones/component/split.rb +14 -0
- data/lib/deftones/context.rb +90 -9
- data/lib/deftones/core/audio_block.rb +64 -5
- data/lib/deftones/core/audio_node.rb +98 -8
- data/lib/deftones/core/gain.rb +0 -8
- data/lib/deftones/core/instrument.rb +52 -10
- data/lib/deftones/core/param.rb +51 -1
- data/lib/deftones/core/signal.rb +79 -28
- data/lib/deftones/core/source.rb +71 -11
- data/lib/deftones/destination.rb +41 -17
- data/lib/deftones/draw.rb +6 -10
- data/lib/deftones/dsp/biquad.rb +9 -4
- data/lib/deftones/dsp/delay_line.rb +2 -2
- data/lib/deftones/dsp/helpers.rb +7 -0
- data/lib/deftones/effect/bit_crusher.rb +10 -2
- data/lib/deftones/effect/chebyshev.rb +7 -3
- data/lib/deftones/effect/distortion.rb +5 -3
- data/lib/deftones/effect/feedback_delay.rb +2 -1
- data/lib/deftones/effect/oversampling.rb +43 -0
- data/lib/deftones/effect/phaser.rb +2 -1
- data/lib/deftones/effect/pitch_shift.rb +1 -2
- data/lib/deftones/effect/reverb.rb +73 -5
- data/lib/deftones/event/callback_behavior.rb +7 -3
- data/lib/deftones/event/loop.rb +7 -2
- data/lib/deftones/event/part.rb +18 -3
- data/lib/deftones/event/pattern.rb +51 -6
- data/lib/deftones/event/sequence.rb +19 -5
- data/lib/deftones/event/tone_event.rb +7 -2
- data/lib/deftones/event/transport.rb +243 -21
- data/lib/deftones/instrument/poly_synth.rb +81 -15
- data/lib/deftones/instrument/sampler.rb +53 -10
- data/lib/deftones/io/buffer.rb +376 -55
- data/lib/deftones/io/buffers.rb +28 -4
- data/lib/deftones/io/recorder.rb +2 -1
- data/lib/deftones/music/frequency.rb +13 -8
- data/lib/deftones/music/midi.rb +132 -9
- data/lib/deftones/music/note.rb +13 -3
- data/lib/deftones/music/time.rb +42 -4
- data/lib/deftones/offline_context.rb +194 -17
- data/lib/deftones/portaudio_support.rb +68 -9
- data/lib/deftones/source/fat_oscillator.rb +28 -9
- data/lib/deftones/source/grain_player.rb +49 -2
- data/lib/deftones/source/noise.rb +42 -10
- data/lib/deftones/source/omni_oscillator.rb +1 -2
- data/lib/deftones/source/oscillator.rb +83 -19
- data/lib/deftones/source/player.rb +24 -6
- data/lib/deftones/source/players.rb +39 -6
- data/lib/deftones/source/tone_buffer_source.rb +12 -6
- data/lib/deftones/source/tone_oscillator_node.rb +4 -3
- data/lib/deftones/source/user_media.rb +83 -10
- data/lib/deftones/version.rb +1 -1
- data/lib/deftones.rb +108 -31
- metadata +3 -44
data/lib/deftones/core/signal.rb
CHANGED
|
@@ -9,6 +9,7 @@ module Deftones
|
|
|
9
9
|
|
|
10
10
|
attr_reader :context, :units, :input, :output, :default_value
|
|
11
11
|
attr_accessor :min_value, :max_value, :convert_values
|
|
12
|
+
attr_reader :clamp_values
|
|
12
13
|
|
|
13
14
|
def initialize(value: 0.0, units: :number, context: Deftones.context)
|
|
14
15
|
@context = context
|
|
@@ -21,6 +22,8 @@ module Deftones
|
|
|
21
22
|
@min_value = -Float::INFINITY
|
|
22
23
|
@max_value = Float::INFINITY
|
|
23
24
|
@events = []
|
|
25
|
+
@next_event_order = 0
|
|
26
|
+
@clamp_values = false
|
|
24
27
|
@disposed = false
|
|
25
28
|
end
|
|
26
29
|
|
|
@@ -29,7 +32,7 @@ module Deftones
|
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
def value=(new_value)
|
|
32
|
-
@base_value = coerce_value(new_value)
|
|
35
|
+
@base_value = bounded_value(coerce_value(new_value))
|
|
33
36
|
@events.clear
|
|
34
37
|
end
|
|
35
38
|
|
|
@@ -50,7 +53,7 @@ module Deftones
|
|
|
50
53
|
resolved_end = context.current_time + Deftones::Music::Time.parse(duration)
|
|
51
54
|
schedule_automation(
|
|
52
55
|
:linear,
|
|
53
|
-
coerce_value(target_value),
|
|
56
|
+
bounded_value(coerce_value(target_value)),
|
|
54
57
|
start_time: resolve_automation_start_time(resolved_end),
|
|
55
58
|
end_time: resolved_end
|
|
56
59
|
)
|
|
@@ -60,7 +63,7 @@ module Deftones
|
|
|
60
63
|
resolved_end = resolve_time(end_time)
|
|
61
64
|
schedule_automation(
|
|
62
65
|
:linear,
|
|
63
|
-
coerce_value(target_value),
|
|
66
|
+
bounded_value(coerce_value(target_value)),
|
|
64
67
|
start_time: resolve_automation_start_time(resolved_end),
|
|
65
68
|
end_time: resolved_end
|
|
66
69
|
)
|
|
@@ -70,7 +73,7 @@ module Deftones
|
|
|
70
73
|
resolved_end = context.current_time + Deftones::Music::Time.parse(duration)
|
|
71
74
|
schedule_automation(
|
|
72
75
|
:exponential,
|
|
73
|
-
coerce_value(target_value),
|
|
76
|
+
bounded_value(coerce_value(target_value)),
|
|
74
77
|
start_time: resolve_automation_start_time(resolved_end),
|
|
75
78
|
end_time: resolved_end
|
|
76
79
|
)
|
|
@@ -80,45 +83,42 @@ module Deftones
|
|
|
80
83
|
resolved_end = resolve_time(end_time)
|
|
81
84
|
schedule_automation(
|
|
82
85
|
:exponential,
|
|
83
|
-
coerce_value(target_value),
|
|
86
|
+
bounded_value(coerce_value(target_value)),
|
|
84
87
|
start_time: resolve_automation_start_time(resolved_end),
|
|
85
88
|
end_time: resolved_end
|
|
86
89
|
)
|
|
87
90
|
end
|
|
88
91
|
|
|
89
92
|
def set_value_at_time(target_value, time)
|
|
90
|
-
|
|
91
|
-
sort_events!
|
|
93
|
+
add_event(type: :set, time: resolve_time(time), value: bounded_value(coerce_value(target_value)))
|
|
92
94
|
self
|
|
93
95
|
end
|
|
94
96
|
|
|
95
97
|
def set_value_curve_at_time(values, start_time, duration)
|
|
96
|
-
curve = Array(values).map { |value| coerce_value(value) }
|
|
98
|
+
curve = Array(values).map { |value| bounded_value(coerce_value(value)) }
|
|
97
99
|
resolved_start = resolve_time(start_time)
|
|
98
100
|
resolved_duration = Deftones::Music::Time.parse(duration)
|
|
99
|
-
|
|
101
|
+
add_event(
|
|
100
102
|
type: :curve,
|
|
101
103
|
time: resolved_start,
|
|
102
104
|
start_time: resolved_start,
|
|
103
105
|
end_time: resolved_start + resolved_duration,
|
|
104
106
|
duration: resolved_duration,
|
|
105
107
|
values: curve
|
|
106
|
-
|
|
107
|
-
sort_events!
|
|
108
|
+
)
|
|
108
109
|
self
|
|
109
110
|
end
|
|
110
111
|
|
|
111
112
|
def set_target_at_time(target_value, start_time, time_constant)
|
|
112
113
|
resolved_start = resolve_time(start_time)
|
|
113
|
-
|
|
114
|
+
add_event(
|
|
114
115
|
type: :target,
|
|
115
116
|
time: resolved_start,
|
|
116
117
|
start_time: resolved_start,
|
|
117
118
|
time_constant: [Deftones::Music::Time.parse(time_constant), 1.0e-6].max,
|
|
118
119
|
from: value_at(resolved_start),
|
|
119
|
-
to: coerce_value(target_value)
|
|
120
|
-
|
|
121
|
-
sort_events!
|
|
120
|
+
to: bounded_value(coerce_value(target_value))
|
|
121
|
+
)
|
|
122
122
|
self
|
|
123
123
|
end
|
|
124
124
|
|
|
@@ -152,6 +152,11 @@ module Deftones
|
|
|
152
152
|
value_at(resolve_time(time))
|
|
153
153
|
end
|
|
154
154
|
|
|
155
|
+
def clamp_values=(value)
|
|
156
|
+
@clamp_values = !!value
|
|
157
|
+
@base_value = bounded_value(@base_value)
|
|
158
|
+
end
|
|
159
|
+
|
|
155
160
|
def dispose
|
|
156
161
|
@events.clear
|
|
157
162
|
@disposed = true
|
|
@@ -174,9 +179,9 @@ module Deftones
|
|
|
174
179
|
alias getValueAtTime get_value_at_time
|
|
175
180
|
|
|
176
181
|
def connect(destination, output_index: 0, input_index: 0)
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
182
|
+
raise ArgumentError, "destination is required" if destination.nil?
|
|
183
|
+
raise ArgumentError, "output_index must be 0 for Signal connections" unless Integer(output_index).zero?
|
|
184
|
+
raise ArgumentError, "input_index must be 0 for Signal connections" unless Integer(input_index).zero?
|
|
180
185
|
|
|
181
186
|
if destination.respond_to?(:value=)
|
|
182
187
|
destination.value = value
|
|
@@ -190,7 +195,10 @@ module Deftones
|
|
|
190
195
|
self
|
|
191
196
|
end
|
|
192
197
|
|
|
193
|
-
def set(**params)
|
|
198
|
+
def set(strict: false, **params)
|
|
199
|
+
unknown = params.keys.reject { |key| respond_to?(:"#{key}=") }
|
|
200
|
+
raise ArgumentError, "Unknown parameter(s): #{unknown.join(', ')}" if strict && unknown.any?
|
|
201
|
+
|
|
194
202
|
params.each do |key, entry|
|
|
195
203
|
writer = :"#{key}="
|
|
196
204
|
public_send(writer, entry) if respond_to?(writer)
|
|
@@ -198,11 +206,19 @@ module Deftones
|
|
|
198
206
|
self
|
|
199
207
|
end
|
|
200
208
|
|
|
201
|
-
def get(*keys)
|
|
202
|
-
|
|
209
|
+
def get(*keys, strict: false)
|
|
210
|
+
unknown = []
|
|
211
|
+
values = keys.flatten.each_with_object({}) do |key, collected|
|
|
203
212
|
reader = key.to_sym
|
|
204
|
-
|
|
213
|
+
if respond_to?(reader)
|
|
214
|
+
collected[reader] = public_send(reader)
|
|
215
|
+
else
|
|
216
|
+
unknown << reader
|
|
217
|
+
end
|
|
205
218
|
end
|
|
219
|
+
raise ArgumentError, "Unknown parameter(s): #{unknown.join(', ')}" if strict && unknown.any?
|
|
220
|
+
|
|
221
|
+
values
|
|
206
222
|
end
|
|
207
223
|
|
|
208
224
|
def get_defaults
|
|
@@ -252,6 +268,8 @@ module Deftones
|
|
|
252
268
|
alias minValue= min_value=
|
|
253
269
|
alias maxValue max_value
|
|
254
270
|
alias maxValue= max_value=
|
|
271
|
+
alias clampValues clamp_values
|
|
272
|
+
alias clampValues= clamp_values=
|
|
255
273
|
alias defaultValue default_value
|
|
256
274
|
alias getDefaults get_defaults
|
|
257
275
|
alias toSeconds to_seconds
|
|
@@ -261,11 +279,24 @@ module Deftones
|
|
|
261
279
|
alias exponentialApproachValueAtTime exponential_approach_value_at_time
|
|
262
280
|
|
|
263
281
|
def process(num_frames, start_frame = 0)
|
|
282
|
+
return Array.new(num_frames, bounded_value(@base_value)) if @events.empty?
|
|
283
|
+
|
|
264
284
|
Array.new(num_frames) do |offset|
|
|
265
285
|
value_at(sample_time(start_frame + offset))
|
|
266
286
|
end
|
|
267
287
|
end
|
|
268
288
|
|
|
289
|
+
def automation_event_count
|
|
290
|
+
@events.length
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def automation_events?
|
|
294
|
+
@events.any?
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
alias automationEventCount automation_event_count
|
|
298
|
+
alias automationEvents? automation_events?
|
|
299
|
+
|
|
269
300
|
def value_at(time)
|
|
270
301
|
current_value = @base_value
|
|
271
302
|
|
|
@@ -300,14 +331,14 @@ module Deftones
|
|
|
300
331
|
end
|
|
301
332
|
end
|
|
302
333
|
|
|
303
|
-
current_value
|
|
334
|
+
bounded_value(current_value)
|
|
304
335
|
end
|
|
305
336
|
|
|
306
337
|
private
|
|
307
338
|
|
|
308
339
|
def schedule_automation(type, target_value, start_time:, end_time:)
|
|
309
340
|
duration_in_seconds = [end_time.to_f - start_time.to_f, 0.0].max
|
|
310
|
-
|
|
341
|
+
add_event(
|
|
311
342
|
type: type,
|
|
312
343
|
start_time: start_time,
|
|
313
344
|
end_time: end_time,
|
|
@@ -315,13 +346,26 @@ module Deftones
|
|
|
315
346
|
duration: duration_in_seconds,
|
|
316
347
|
from: value_at(start_time),
|
|
317
348
|
to: target_value
|
|
318
|
-
|
|
319
|
-
sort_events!
|
|
349
|
+
)
|
|
320
350
|
self
|
|
321
351
|
end
|
|
322
352
|
|
|
323
|
-
def
|
|
324
|
-
|
|
353
|
+
def add_event(event)
|
|
354
|
+
event[:order] = @next_event_order
|
|
355
|
+
@next_event_order += 1
|
|
356
|
+
insert_event(event)
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
def insert_event(event)
|
|
360
|
+
key = event_sort_key(event)
|
|
361
|
+
index = @events.bsearch_index { |existing| (event_sort_key(existing) <=> key).positive? }
|
|
362
|
+
return @events << event unless index
|
|
363
|
+
|
|
364
|
+
@events.insert(index, event)
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def event_sort_key(event)
|
|
368
|
+
[event.fetch(:time, event[:start_time]), event.fetch(:order, 0)]
|
|
325
369
|
end
|
|
326
370
|
|
|
327
371
|
def resolve_automation_start_time(end_time)
|
|
@@ -447,6 +491,13 @@ module Deftones
|
|
|
447
491
|
def db_to_gain(value)
|
|
448
492
|
10.0**(value / 20.0)
|
|
449
493
|
end
|
|
494
|
+
|
|
495
|
+
def bounded_value(value)
|
|
496
|
+
return value unless @clamp_values
|
|
497
|
+
return value unless value.is_a?(Numeric)
|
|
498
|
+
|
|
499
|
+
value.clamp(@min_value, @max_value)
|
|
500
|
+
end
|
|
450
501
|
end
|
|
451
502
|
end
|
|
452
503
|
end
|
data/lib/deftones/core/source.rb
CHANGED
|
@@ -5,30 +5,91 @@ module Deftones
|
|
|
5
5
|
class Source < AudioNode
|
|
6
6
|
class VolumeProxy
|
|
7
7
|
attr_reader :source
|
|
8
|
-
attr_accessor :value
|
|
9
8
|
|
|
10
9
|
def initialize(source, value: 0.0)
|
|
11
10
|
@source = source
|
|
12
11
|
@value = value.to_f
|
|
12
|
+
@automation = Signal.new(value: @value, units: :number, context: source.context)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def value
|
|
16
|
+
@value
|
|
13
17
|
end
|
|
14
18
|
|
|
15
19
|
def value=(new_value)
|
|
16
20
|
@value = new_value.to_f
|
|
21
|
+
@automation.value = @value
|
|
17
22
|
source.send(:apply_volume!)
|
|
18
23
|
end
|
|
19
24
|
|
|
20
|
-
def ramp_to(target_value,
|
|
21
|
-
|
|
25
|
+
def ramp_to(target_value, duration = nil)
|
|
26
|
+
return assign_immediately(target_value) if duration.nil?
|
|
27
|
+
|
|
28
|
+
resolved_duration = Deftones::Music::Time.parse(duration)
|
|
29
|
+
return assign_immediately(target_value) if resolved_duration <= 0.0
|
|
30
|
+
|
|
31
|
+
@value = target_value.to_f
|
|
32
|
+
@automation.linear_ramp_to_value_at_time(@value, source.context.current_time + resolved_duration)
|
|
33
|
+
source.send(:apply_volume!)
|
|
34
|
+
self
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def set_value_at_time(target_value, time)
|
|
38
|
+
@value = target_value.to_f
|
|
39
|
+
@automation.set_value_at_time(@value, time)
|
|
40
|
+
source.send(:apply_volume!)
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def gains(num_frames, start_frame)
|
|
45
|
+
return Array.new(num_frames, 0.0) if source.mute?
|
|
46
|
+
|
|
47
|
+
@automation.process(num_frames, start_frame).map { |db| Deftones.db_to_gain(db) }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def current_gain
|
|
51
|
+
return 0.0 if source.mute?
|
|
52
|
+
|
|
53
|
+
Deftones.db_to_gain(@automation.get_value_at_time(source.context.current_time))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def cancel_scheduled_values(after_time = 0)
|
|
57
|
+
@automation.cancel_scheduled_values(after_time)
|
|
22
58
|
self
|
|
23
59
|
end
|
|
24
60
|
|
|
25
|
-
|
|
26
|
-
|
|
61
|
+
def cancel_and_hold_at_time(time)
|
|
62
|
+
@automation.cancel_and_hold_at_time(time)
|
|
63
|
+
@value = @automation.get_value_at_time(time)
|
|
64
|
+
source.send(:apply_volume!)
|
|
65
|
+
self
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def linear_ramp_to(target_value, duration = nil)
|
|
69
|
+
ramp_to(target_value, duration)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def exponential_ramp_to(target_value, duration = nil)
|
|
73
|
+
ramp_to(target_value, duration)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
alias setValueAtTime set_value_at_time
|
|
77
|
+
alias cancelScheduledValues cancel_scheduled_values
|
|
78
|
+
alias cancelAndHoldAtTime cancel_and_hold_at_time
|
|
79
|
+
alias linearRampTo linear_ramp_to
|
|
80
|
+
alias exponentialRampTo exponential_ramp_to
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def assign_immediately(target_value)
|
|
85
|
+
self.value = target_value
|
|
86
|
+
self
|
|
87
|
+
end
|
|
27
88
|
end
|
|
28
89
|
|
|
29
90
|
attr_reader :volume
|
|
30
91
|
attr_accessor :onstop
|
|
31
|
-
|
|
92
|
+
attr_reader :mute
|
|
32
93
|
|
|
33
94
|
def initialize(context: Deftones.context)
|
|
34
95
|
super(context: context)
|
|
@@ -127,16 +188,15 @@ module Deftones
|
|
|
127
188
|
end
|
|
128
189
|
|
|
129
190
|
def render(num_frames, start_frame = 0, cache = {})
|
|
130
|
-
|
|
131
|
-
notify_stop_in_window(start_frame, num_frames)
|
|
132
|
-
output_buffer
|
|
191
|
+
super
|
|
133
192
|
end
|
|
134
193
|
|
|
135
194
|
def render_block(num_frames, start_frame = 0, cache = {})
|
|
136
195
|
output_block = super
|
|
196
|
+
volume_gains = @volume.gains(num_frames, start_frame)
|
|
137
197
|
scaled = AudioBlock.from_channel_data(
|
|
138
198
|
output_block.channel_data.map do |channel|
|
|
139
|
-
channel.map { |sample| sample *
|
|
199
|
+
channel.each_with_index.map { |sample, index| sample * volume_gains[index] }
|
|
140
200
|
end
|
|
141
201
|
)
|
|
142
202
|
notify_stop_in_window(start_frame, num_frames)
|
|
@@ -159,7 +219,7 @@ module Deftones
|
|
|
159
219
|
end
|
|
160
220
|
|
|
161
221
|
def apply_volume!
|
|
162
|
-
@output_gain =
|
|
222
|
+
@output_gain = @volume.current_gain
|
|
163
223
|
self
|
|
164
224
|
end
|
|
165
225
|
|
data/lib/deftones/destination.rb
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "forwardable"
|
|
4
|
+
|
|
3
5
|
module Deftones
|
|
4
6
|
class Destination
|
|
5
7
|
class VolumeProxy
|
|
6
8
|
attr_reader :destination
|
|
7
|
-
|
|
9
|
+
attr_reader :value
|
|
8
10
|
|
|
9
11
|
def initialize(destination, value: 0.0)
|
|
10
12
|
@destination = destination
|
|
@@ -16,24 +18,56 @@ module Deftones
|
|
|
16
18
|
destination.apply_volume!
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
def ramp_to(target_value,
|
|
20
|
-
|
|
21
|
+
def ramp_to(target_value, duration = nil)
|
|
22
|
+
return assign_immediately(target_value) if duration.nil?
|
|
23
|
+
|
|
24
|
+
resolved_duration = Deftones::Music::Time.parse(duration)
|
|
25
|
+
return assign_immediately(target_value) if resolved_duration <= 0.0
|
|
26
|
+
|
|
27
|
+
@value = target_value.to_f
|
|
28
|
+
destination.node.gain.linear_ramp_to_value_at_time(
|
|
29
|
+
destination.mute? ? 0.0 : Deftones.db_to_gain(@value),
|
|
30
|
+
destination.context.current_time + resolved_duration
|
|
31
|
+
)
|
|
21
32
|
self
|
|
22
33
|
end
|
|
23
34
|
|
|
24
|
-
|
|
25
|
-
|
|
35
|
+
def linear_ramp_to(target_value, duration = nil)
|
|
36
|
+
ramp_to(target_value, duration)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def exponential_ramp_to(target_value, duration = nil)
|
|
40
|
+
ramp_to(target_value, duration)
|
|
41
|
+
end
|
|
26
42
|
|
|
27
43
|
def set_value_at_time(target_value, _time)
|
|
44
|
+
@value = target_value.to_f
|
|
45
|
+
destination.node.gain.set_value_at_time(destination.mute? ? 0.0 : Deftones.db_to_gain(@value), _time)
|
|
46
|
+
self
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
alias linearRampTo linear_ramp_to
|
|
50
|
+
alias exponentialRampTo exponential_ramp_to
|
|
51
|
+
alias setValueAtTime set_value_at_time
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def assign_immediately(target_value)
|
|
28
56
|
self.value = target_value
|
|
29
57
|
self
|
|
30
58
|
end
|
|
31
59
|
end
|
|
32
60
|
|
|
33
|
-
attr_reader :context, :volume
|
|
34
|
-
attr_accessor :mute
|
|
61
|
+
attr_reader :context, :mute, :volume
|
|
35
62
|
|
|
36
63
|
class << self
|
|
64
|
+
extend Forwardable
|
|
65
|
+
|
|
66
|
+
def_delegators :node, :input, :output, :volume, :mute, :mute=, :mute?
|
|
67
|
+
def_delegators :node, :sample_time, :block_time, :max_channel_count
|
|
68
|
+
def_delegators :node, :connect, :disconnect, :chain, :fan, :apply_volume!
|
|
69
|
+
def_delegators :node, :sampleTime, :blockTime, :maxChannelCount
|
|
70
|
+
|
|
37
71
|
def node(context: Deftones.context)
|
|
38
72
|
registry[context.object_id] ||= new(context: context)
|
|
39
73
|
end
|
|
@@ -43,16 +77,6 @@ module Deftones
|
|
|
43
77
|
self
|
|
44
78
|
end
|
|
45
79
|
|
|
46
|
-
def method_missing(method_name, *arguments, &block)
|
|
47
|
-
return super unless node.respond_to?(method_name)
|
|
48
|
-
|
|
49
|
-
node.public_send(method_name, *arguments, &block)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def respond_to_missing?(method_name, include_private = false)
|
|
53
|
-
node.respond_to?(method_name, include_private) || super
|
|
54
|
-
end
|
|
55
|
-
|
|
56
80
|
private
|
|
57
81
|
|
|
58
82
|
def registry
|
data/lib/deftones/draw.rb
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "forwardable"
|
|
4
|
+
|
|
3
5
|
module Deftones
|
|
4
6
|
class Draw
|
|
5
7
|
class << self
|
|
8
|
+
extend Forwardable
|
|
9
|
+
|
|
10
|
+
def_delegators :instance, :schedule, :cancel, :dispose, :prepare_render, :advance_to
|
|
11
|
+
|
|
6
12
|
def instance
|
|
7
13
|
@instance ||= new
|
|
8
14
|
end
|
|
@@ -11,16 +17,6 @@ module Deftones
|
|
|
11
17
|
@instance = nil
|
|
12
18
|
self
|
|
13
19
|
end
|
|
14
|
-
|
|
15
|
-
def method_missing(method_name, *arguments, &block)
|
|
16
|
-
return super unless instance.respond_to?(method_name)
|
|
17
|
-
|
|
18
|
-
instance.public_send(method_name, *arguments, &block)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def respond_to_missing?(method_name, include_private = false)
|
|
22
|
-
instance.respond_to?(method_name, include_private) || super
|
|
23
|
-
end
|
|
24
20
|
end
|
|
25
21
|
|
|
26
22
|
def initialize
|
data/lib/deftones/dsp/biquad.rb
CHANGED
|
@@ -13,8 +13,12 @@ module Deftones
|
|
|
13
13
|
def update(type:, frequency:, q:, gain_db:, sample_rate:)
|
|
14
14
|
raise ArgumentError, "Unsupported filter type: #{type}" unless TYPES.include?(type)
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
normalized_sample_rate = [sample_rate.to_f, 1.0].max
|
|
17
|
+
nyquist = normalized_sample_rate / 2.0
|
|
18
|
+
lower_bound = [10.0, nyquist * 0.5].min
|
|
19
|
+
upper_bound = [nyquist - 1.0e-6, lower_bound].max
|
|
20
|
+
normalized_frequency = Helpers.clamp(frequency.to_f, lower_bound, upper_bound)
|
|
21
|
+
omega = (2.0 * Math::PI * normalized_frequency) / normalized_sample_rate
|
|
18
22
|
sin_omega = Math.sin(omega)
|
|
19
23
|
cos_omega = Math.cos(omega)
|
|
20
24
|
alpha = sin_omega / (2.0 * [q.to_f, 0.001].max)
|
|
@@ -45,9 +49,10 @@ module Deftones
|
|
|
45
49
|
|
|
46
50
|
def process_sample(sample)
|
|
47
51
|
b0, b1, b2, a1, a2 = @coefficients
|
|
48
|
-
|
|
52
|
+
input = Helpers.flush_denormal(sample)
|
|
53
|
+
output = Helpers.flush_denormal((b0 * input) + (b1 * @x1) + (b2 * @x2) - (a1 * @y1) - (a2 * @y2))
|
|
49
54
|
@x2 = @x1
|
|
50
|
-
@x1 =
|
|
55
|
+
@x1 = input
|
|
51
56
|
@y2 = @y1
|
|
52
57
|
@y1 = output
|
|
53
58
|
output
|
|
@@ -13,7 +13,7 @@ module Deftones
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def write(sample)
|
|
16
|
-
@buffer[@write_index] = sample
|
|
16
|
+
@buffer[@write_index] = Helpers.flush_denormal(sample)
|
|
17
17
|
@write_index = (@write_index + 1) % @buffer.length
|
|
18
18
|
sample
|
|
19
19
|
end
|
|
@@ -34,7 +34,7 @@ module Deftones
|
|
|
34
34
|
next_index = (base_index + 1) % @buffer.length
|
|
35
35
|
fraction = read_position - read_position.floor
|
|
36
36
|
|
|
37
|
-
Helpers.lerp(@buffer[base_index], @buffer[next_index], fraction)
|
|
37
|
+
Helpers.flush_denormal(Helpers.lerp(@buffer[base_index], @buffer[next_index], fraction))
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
end
|
data/lib/deftones/dsp/helpers.rb
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
module Deftones
|
|
4
4
|
module DSP
|
|
5
5
|
module Helpers
|
|
6
|
+
DENORMAL_THRESHOLD = 1.0e-300
|
|
7
|
+
|
|
6
8
|
module_function
|
|
7
9
|
|
|
8
10
|
def clamp(value, min_value, max_value)
|
|
@@ -20,6 +22,11 @@ module Deftones
|
|
|
20
22
|
def soft_clip(value, drive = 1.0)
|
|
21
23
|
Math.tanh(value * drive)
|
|
22
24
|
end
|
|
25
|
+
|
|
26
|
+
def flush_denormal(value)
|
|
27
|
+
sample = value.to_f
|
|
28
|
+
sample.abs < DENORMAL_THRESHOLD ? 0.0 : sample
|
|
29
|
+
end
|
|
23
30
|
end
|
|
24
31
|
end
|
|
25
32
|
end
|
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
module Deftones
|
|
4
4
|
module Effects
|
|
5
5
|
class BitCrusher < Core::Effect
|
|
6
|
+
include Oversampling
|
|
7
|
+
|
|
6
8
|
attr_accessor :bits, :downsample
|
|
7
9
|
|
|
8
|
-
def initialize(bits: 8, downsample: 2, **options)
|
|
10
|
+
def initialize(bits: 8, downsample: 2, oversample: 1, **options)
|
|
9
11
|
super(**options)
|
|
10
12
|
@bits = bits.to_i
|
|
11
13
|
@downsample = [downsample.to_i, 1].max
|
|
14
|
+
self.oversample = oversample
|
|
12
15
|
@hold_counters = []
|
|
13
16
|
@held_samples = []
|
|
14
17
|
end
|
|
@@ -21,13 +24,18 @@ module Deftones
|
|
|
21
24
|
|
|
22
25
|
input_buffer.map do |sample|
|
|
23
26
|
if (@hold_counters[channel_index] % @downsample).zero?
|
|
24
|
-
@held_samples[channel_index] =
|
|
27
|
+
@held_samples[channel_index] =
|
|
28
|
+
process_oversampled([sample], channel_index) { |candidate| quantize(candidate, step) }.first
|
|
25
29
|
end
|
|
26
30
|
@hold_counters[channel_index] += 1
|
|
27
31
|
@held_samples[channel_index]
|
|
28
32
|
end
|
|
29
33
|
end
|
|
30
34
|
|
|
35
|
+
def quantize(sample, step)
|
|
36
|
+
((sample / step).round * step).clamp(-1.0, 1.0)
|
|
37
|
+
end
|
|
38
|
+
|
|
31
39
|
def ensure_state(channel_index)
|
|
32
40
|
required = [channel_index.to_i, 0].max
|
|
33
41
|
@hold_counters.fill(0, @hold_counters.length..required)
|
|
@@ -3,18 +3,22 @@
|
|
|
3
3
|
module Deftones
|
|
4
4
|
module Effects
|
|
5
5
|
class Chebyshev < Core::Effect
|
|
6
|
+
include Oversampling
|
|
7
|
+
|
|
6
8
|
attr_accessor :order
|
|
7
9
|
|
|
8
|
-
def initialize(order: 3, **options)
|
|
10
|
+
def initialize(order: 3, oversample: 1, **options)
|
|
9
11
|
super(**options)
|
|
10
12
|
@order = [order.to_i, 1].max
|
|
13
|
+
self.oversample = oversample
|
|
11
14
|
end
|
|
12
15
|
|
|
13
16
|
private
|
|
14
17
|
|
|
15
18
|
def process_effect(input_buffer, _num_frames, _start_frame, _cache, channel_index: 0)
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
process_oversampled(input_buffer, channel_index) do |sample|
|
|
20
|
+
chebyshev(sample.clamp(-1.0, 1.0), @order)
|
|
21
|
+
end
|
|
18
22
|
end
|
|
19
23
|
|
|
20
24
|
def chebyshev(value, order)
|
|
@@ -3,19 +3,21 @@
|
|
|
3
3
|
module Deftones
|
|
4
4
|
module Effects
|
|
5
5
|
class Distortion < Core::Effect
|
|
6
|
+
include Oversampling
|
|
7
|
+
|
|
6
8
|
attr_accessor :amount
|
|
7
9
|
|
|
8
|
-
def initialize(amount: 0.5, **options)
|
|
10
|
+
def initialize(amount: 0.5, oversample: 1, **options)
|
|
9
11
|
super(**options)
|
|
10
12
|
@amount = amount.to_f
|
|
13
|
+
self.oversample = oversample
|
|
11
14
|
end
|
|
12
15
|
|
|
13
16
|
private
|
|
14
17
|
|
|
15
18
|
def process_effect(input_buffer, _num_frames, _start_frame, _cache, channel_index: 0)
|
|
16
|
-
_ = channel_index
|
|
17
19
|
drive = 1.0 + (@amount * 20.0)
|
|
18
|
-
input_buffer
|
|
20
|
+
process_oversampled(input_buffer, channel_index) { |sample| DSP::Helpers.soft_clip(sample, drive) }
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
23
|
end
|
|
@@ -22,7 +22,8 @@ module Deftones
|
|
|
22
22
|
|
|
23
23
|
Array.new(num_frames) do |index|
|
|
24
24
|
delay_samples = delays[index] * context.sample_rate
|
|
25
|
-
|
|
25
|
+
feedback = feedbacks[index].to_f.clamp(-0.999, 0.999)
|
|
26
|
+
delay_line.tap(delay_samples, input_sample: input_buffer[index], feedback: feedback)
|
|
26
27
|
end
|
|
27
28
|
end
|
|
28
29
|
|