deftones 0.1.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.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +5 -0
  3. data/CHANGELOG.md +12 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +197 -0
  6. data/Rakefile +8 -0
  7. data/examples/poly_chord.rb +14 -0
  8. data/examples/render_sampler.rb +16 -0
  9. data/examples/render_sequence.rb +13 -0
  10. data/examples/render_synth.rb +18 -0
  11. data/lib/deftones/analysis/analyser.rb +162 -0
  12. data/lib/deftones/analysis/dc_meter.rb +56 -0
  13. data/lib/deftones/analysis/fft.rb +128 -0
  14. data/lib/deftones/analysis/meter.rb +83 -0
  15. data/lib/deftones/analysis/waveform.rb +93 -0
  16. data/lib/deftones/component/amplitude_envelope.rb +8 -0
  17. data/lib/deftones/component/biquad_filter.rb +7 -0
  18. data/lib/deftones/component/channel.rb +109 -0
  19. data/lib/deftones/component/compressor.rb +64 -0
  20. data/lib/deftones/component/convolver.rb +99 -0
  21. data/lib/deftones/component/cross_fade.rb +67 -0
  22. data/lib/deftones/component/envelope.rb +160 -0
  23. data/lib/deftones/component/eq3.rb +73 -0
  24. data/lib/deftones/component/feedback_comb_filter.rb +75 -0
  25. data/lib/deftones/component/filter.rb +75 -0
  26. data/lib/deftones/component/follower.rb +55 -0
  27. data/lib/deftones/component/frequency_envelope.rb +24 -0
  28. data/lib/deftones/component/gate.rb +46 -0
  29. data/lib/deftones/component/lfo.rb +88 -0
  30. data/lib/deftones/component/limiter.rb +11 -0
  31. data/lib/deftones/component/lowpass_comb_filter.rb +43 -0
  32. data/lib/deftones/component/merge.rb +45 -0
  33. data/lib/deftones/component/mid_side_compressor.rb +43 -0
  34. data/lib/deftones/component/mid_side_merge.rb +53 -0
  35. data/lib/deftones/component/mid_side_split.rb +54 -0
  36. data/lib/deftones/component/mono.rb +8 -0
  37. data/lib/deftones/component/multiband_compressor.rb +70 -0
  38. data/lib/deftones/component/multiband_split.rb +133 -0
  39. data/lib/deftones/component/one_pole_filter.rb +71 -0
  40. data/lib/deftones/component/pan_vol.rb +26 -0
  41. data/lib/deftones/component/panner.rb +75 -0
  42. data/lib/deftones/component/panner3d.rb +322 -0
  43. data/lib/deftones/component/solo.rb +56 -0
  44. data/lib/deftones/component/split.rb +47 -0
  45. data/lib/deftones/component/volume.rb +31 -0
  46. data/lib/deftones/context.rb +213 -0
  47. data/lib/deftones/core/audio_block.rb +82 -0
  48. data/lib/deftones/core/audio_node.rb +262 -0
  49. data/lib/deftones/core/clock.rb +91 -0
  50. data/lib/deftones/core/computed_signal.rb +69 -0
  51. data/lib/deftones/core/delay.rb +44 -0
  52. data/lib/deftones/core/effect.rb +66 -0
  53. data/lib/deftones/core/emitter.rb +51 -0
  54. data/lib/deftones/core/gain.rb +39 -0
  55. data/lib/deftones/core/instrument.rb +109 -0
  56. data/lib/deftones/core/param.rb +31 -0
  57. data/lib/deftones/core/signal.rb +452 -0
  58. data/lib/deftones/core/signal_operator_methods.rb +73 -0
  59. data/lib/deftones/core/signal_operators.rb +138 -0
  60. data/lib/deftones/core/signal_shapers.rb +83 -0
  61. data/lib/deftones/core/source.rb +213 -0
  62. data/lib/deftones/core/synced_signal.rb +88 -0
  63. data/lib/deftones/destination.rb +132 -0
  64. data/lib/deftones/draw.rb +100 -0
  65. data/lib/deftones/dsp/biquad.rb +129 -0
  66. data/lib/deftones/dsp/delay_line.rb +41 -0
  67. data/lib/deftones/dsp/helpers.rb +25 -0
  68. data/lib/deftones/effect/auto_filter.rb +92 -0
  69. data/lib/deftones/effect/auto_panner.rb +57 -0
  70. data/lib/deftones/effect/auto_wah.rb +98 -0
  71. data/lib/deftones/effect/bit_crusher.rb +38 -0
  72. data/lib/deftones/effect/chebyshev.rb +36 -0
  73. data/lib/deftones/effect/chorus.rb +73 -0
  74. data/lib/deftones/effect/distortion.rb +22 -0
  75. data/lib/deftones/effect/feedback_delay.rb +38 -0
  76. data/lib/deftones/effect/freeverb.rb +11 -0
  77. data/lib/deftones/effect/frequency_shifter.rb +89 -0
  78. data/lib/deftones/effect/jc_reverb.rb +11 -0
  79. data/lib/deftones/effect/modulation_control.rb +159 -0
  80. data/lib/deftones/effect/phaser.rb +72 -0
  81. data/lib/deftones/effect/ping_pong_delay.rb +40 -0
  82. data/lib/deftones/effect/pitch_shift.rb +156 -0
  83. data/lib/deftones/effect/reverb.rb +71 -0
  84. data/lib/deftones/effect/stereo_widener.rb +34 -0
  85. data/lib/deftones/effect/tremolo.rb +52 -0
  86. data/lib/deftones/effect/vibrato.rb +47 -0
  87. data/lib/deftones/event/callback_behavior.rb +61 -0
  88. data/lib/deftones/event/loop.rb +53 -0
  89. data/lib/deftones/event/part.rb +51 -0
  90. data/lib/deftones/event/pattern.rb +94 -0
  91. data/lib/deftones/event/sequence.rb +87 -0
  92. data/lib/deftones/event/tone_event.rb +77 -0
  93. data/lib/deftones/event/transport.rb +276 -0
  94. data/lib/deftones/instrument/am_synth.rb +56 -0
  95. data/lib/deftones/instrument/duo_synth.rb +68 -0
  96. data/lib/deftones/instrument/fm_synth.rb +60 -0
  97. data/lib/deftones/instrument/membrane_synth.rb +60 -0
  98. data/lib/deftones/instrument/metal_synth.rb +61 -0
  99. data/lib/deftones/instrument/mono_synth.rb +88 -0
  100. data/lib/deftones/instrument/noise_synth.rb +56 -0
  101. data/lib/deftones/instrument/pluck_synth.rb +41 -0
  102. data/lib/deftones/instrument/poly_synth.rb +96 -0
  103. data/lib/deftones/instrument/sampler.rb +97 -0
  104. data/lib/deftones/instrument/synth.rb +60 -0
  105. data/lib/deftones/io/buffer.rb +352 -0
  106. data/lib/deftones/io/buffers.rb +77 -0
  107. data/lib/deftones/io/recorder.rb +89 -0
  108. data/lib/deftones/listener.rb +120 -0
  109. data/lib/deftones/music/frequency.rb +128 -0
  110. data/lib/deftones/music/midi.rb +206 -0
  111. data/lib/deftones/music/note.rb +58 -0
  112. data/lib/deftones/music/ticks.rb +106 -0
  113. data/lib/deftones/music/time.rb +209 -0
  114. data/lib/deftones/music/transport_time.rb +94 -0
  115. data/lib/deftones/music/unit_helpers.rb +30 -0
  116. data/lib/deftones/offline_context.rb +46 -0
  117. data/lib/deftones/portaudio_support.rb +112 -0
  118. data/lib/deftones/source/am_oscillator.rb +42 -0
  119. data/lib/deftones/source/fat_oscillator.rb +49 -0
  120. data/lib/deftones/source/fm_oscillator.rb +47 -0
  121. data/lib/deftones/source/grain_player.rb +198 -0
  122. data/lib/deftones/source/karplus_strong.rb +51 -0
  123. data/lib/deftones/source/noise.rb +99 -0
  124. data/lib/deftones/source/omni_oscillator.rb +175 -0
  125. data/lib/deftones/source/oscillator.rb +74 -0
  126. data/lib/deftones/source/player.rb +228 -0
  127. data/lib/deftones/source/players.rb +133 -0
  128. data/lib/deftones/source/pulse_oscillator.rb +38 -0
  129. data/lib/deftones/source/pwm_oscillator.rb +49 -0
  130. data/lib/deftones/source/tone_buffer_source.rb +136 -0
  131. data/lib/deftones/source/tone_oscillator_node.rb +65 -0
  132. data/lib/deftones/source/user_media.rb +519 -0
  133. data/lib/deftones/version.rb +5 -0
  134. data/lib/deftones.rb +542 -0
  135. metadata +221 -0
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Core
5
+ class AudioBlock
6
+ attr_reader :channel_data
7
+
8
+ def self.silent(num_frames, channels = 1)
9
+ from_channel_data(Array.new([channels.to_i, 1].max) { Array.new(num_frames.to_i, 0.0) })
10
+ end
11
+
12
+ def self.from_channel_data(channel_data)
13
+ normalized = channel_data.map { |channel| channel.map(&:to_f) }
14
+ new(normalized)
15
+ end
16
+
17
+ def self.from_mono(samples, channels: 1)
18
+ normalized = samples.map(&:to_f)
19
+ from_channel_data(Array.new([channels.to_i, 1].max) { normalized.dup })
20
+ end
21
+
22
+ def initialize(channel_data)
23
+ @channel_data = channel_data
24
+ end
25
+
26
+ def channels
27
+ @channel_data.length
28
+ end
29
+
30
+ def num_frames
31
+ @channel_data.first&.length || 0
32
+ end
33
+
34
+ def dup
35
+ self.class.from_channel_data(@channel_data)
36
+ end
37
+
38
+ def mono
39
+ return [] if @channel_data.empty?
40
+ return @channel_data.first.dup if channels == 1
41
+
42
+ Array.new(num_frames) do |frame_index|
43
+ @channel_data.sum { |channel| channel[frame_index] } / channels.to_f
44
+ end
45
+ end
46
+
47
+ def interleaved
48
+ Array.new(num_frames * channels) do |index|
49
+ frame_index = index / channels
50
+ channel_index = index % channels
51
+ @channel_data[channel_index][frame_index]
52
+ end
53
+ end
54
+
55
+ def channel(index)
56
+ @channel_data[index] || Array.new(num_frames, 0.0)
57
+ end
58
+
59
+ def fit_channels(target_channels)
60
+ target = [target_channels.to_i, 1].max
61
+ return dup if target == channels
62
+ return self.class.from_channel_data([mono]) if target == 1
63
+
64
+ if channels == 1
65
+ return self.class.from_channel_data(Array.new(target) { @channel_data.first.dup })
66
+ end
67
+
68
+ self.class.from_channel_data(Array.new(target) { |index| channel(index % channels).dup })
69
+ end
70
+
71
+ def mix!(other)
72
+ incoming = other.fit_channels(channels)
73
+ channels.times do |channel_index|
74
+ num_frames.times do |frame_index|
75
+ @channel_data[channel_index][frame_index] += incoming.channel_data[channel_index][frame_index]
76
+ end
77
+ end
78
+ self
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,262 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Core
5
+ class AudioNode
6
+ attr_reader :context, :input
7
+
8
+ def initialize(context: Deftones.context)
9
+ @context = context
10
+ @input = self
11
+ @sources = []
12
+ @destinations = []
13
+ @disposed = false
14
+ end
15
+
16
+ def output
17
+ self
18
+ end
19
+
20
+ def connect(destination, output_index: 0, input_index: 0)
21
+ _ = output_index
22
+ _ = input_index
23
+ raise ArgumentError, "destination is required" if destination.nil?
24
+
25
+ destination_node = destination.respond_to?(:input) ? destination.input : destination
26
+ output.attach_destination(destination_node)
27
+ self
28
+ end
29
+
30
+ def disconnect(destination = nil)
31
+ if destination
32
+ destination_node = destination.respond_to?(:input) ? destination.input : destination
33
+ output.detach_destination(destination_node)
34
+ else
35
+ output.detach_all_destinations
36
+ end
37
+ self
38
+ end
39
+
40
+ def >>(other)
41
+ connect(other)
42
+ other
43
+ end
44
+
45
+ def chain(*nodes)
46
+ [self, *nodes].each_cons(2) { |source, destination| source.connect(destination) }
47
+ nodes.last || self
48
+ end
49
+
50
+ def fan(*nodes)
51
+ nodes.each { |node| connect(node) }
52
+ self
53
+ end
54
+
55
+ def to_output
56
+ connect(context.output)
57
+ self
58
+ end
59
+
60
+ def to_destination
61
+ to_output
62
+ end
63
+
64
+ def to_master
65
+ to_destination
66
+ end
67
+
68
+ def now
69
+ context.current_time
70
+ end
71
+
72
+ def immediate
73
+ now
74
+ end
75
+
76
+ def to_seconds(time = nil)
77
+ return context.current_time if time.nil?
78
+
79
+ Deftones::Music::Time.parse(time)
80
+ end
81
+
82
+ def to_ticks(time = nil)
83
+ return Deftones.transport.ticks if time.nil?
84
+
85
+ Deftones.transport.seconds_to_ticks(to_seconds(time))
86
+ end
87
+
88
+ def to_frequency(value)
89
+ Deftones::Music::Frequency.parse(value)
90
+ end
91
+
92
+ def to_midi(value)
93
+ Deftones::Music::Midi.parse(value)
94
+ end
95
+
96
+ def sample_time
97
+ 1.0 / context.sample_rate
98
+ end
99
+
100
+ def block_time
101
+ context.buffer_size.to_f / context.sample_rate
102
+ end
103
+
104
+ def channel_count
105
+ context.channels
106
+ end
107
+
108
+ def channel_count_mode
109
+ "max"
110
+ end
111
+
112
+ def channel_interpretation
113
+ "speakers"
114
+ end
115
+
116
+ def number_of_inputs
117
+ 1
118
+ end
119
+
120
+ def number_of_outputs
121
+ 1
122
+ end
123
+
124
+ def set(**params)
125
+ params.each do |key, value|
126
+ writer = :"#{key}="
127
+ public_send(writer, value) if respond_to?(writer)
128
+ end
129
+ self
130
+ end
131
+
132
+ def get(*keys)
133
+ keys.flatten.each_with_object({}) do |key, values|
134
+ reader = key.to_sym
135
+ values[reader] = public_send(reader) if respond_to?(reader)
136
+ end
137
+ end
138
+
139
+ def name
140
+ self.class.name.split("::").last
141
+ end
142
+
143
+ def to_s
144
+ name
145
+ end
146
+
147
+ alias toDestination to_destination
148
+ alias toMaster to_master
149
+ alias toSeconds to_seconds
150
+ alias toTicks to_ticks
151
+ alias toFrequency to_frequency
152
+ alias toMidi to_midi
153
+ alias sampleTime sample_time
154
+ alias blockTime block_time
155
+ alias channelCount channel_count
156
+ alias channelCountMode channel_count_mode
157
+ alias channelInterpretation channel_interpretation
158
+ alias numberOfInputs number_of_inputs
159
+ alias numberOfOutputs number_of_outputs
160
+ alias toString to_s
161
+
162
+ def dispose
163
+ disconnect
164
+ @sources.dup.each { |source| source.detach_destination(self) }
165
+ @sources.clear
166
+ @disposed = true
167
+ self
168
+ end
169
+
170
+ def disposed?
171
+ @disposed
172
+ end
173
+
174
+ def render(num_frames, start_frame = 0, cache = {})
175
+ render_block(num_frames, start_frame, cache).mono
176
+ end
177
+
178
+ protected
179
+
180
+ def render_block(num_frames, start_frame = 0, cache = {})
181
+ cache_key = [object_id, :block, start_frame, num_frames]
182
+ return cache.fetch(cache_key).dup if cache.key?(cache_key)
183
+
184
+ output_block = if uses_legacy_render_for_block?
185
+ normalize_output_block(render(num_frames, start_frame, cache), num_frames, 1)
186
+ else
187
+ input_block = mix_source_blocks(num_frames, start_frame, cache)
188
+ if multichannel_process?
189
+ normalize_output_block(process(input_block, num_frames, start_frame, cache), num_frames, input_block.channels)
190
+ else
191
+ mono_output = process(input_block.mono, num_frames, start_frame, cache)
192
+ normalize_output_block(mono_output, num_frames, [input_block.channels, default_output_channels].max)
193
+ end
194
+ end
195
+
196
+ cache[cache_key] = output_block
197
+ output_block.dup
198
+ end
199
+
200
+ def attach_source(source)
201
+ return if @sources.include?(source)
202
+
203
+ @sources << source
204
+ end
205
+
206
+ def detach_source(source)
207
+ @sources.delete(source)
208
+ end
209
+
210
+ def attach_destination(destination)
211
+ return if @destinations.include?(destination)
212
+
213
+ @destinations << destination
214
+ destination.attach_source(self)
215
+ end
216
+
217
+ def detach_destination(destination)
218
+ return unless @destinations.delete(destination)
219
+
220
+ destination.detach_source(self)
221
+ end
222
+
223
+ def detach_all_destinations
224
+ @destinations.dup.each { |destination| detach_destination(destination) }
225
+ end
226
+
227
+ def mix_source_blocks(num_frames, start_frame, cache)
228
+ blocks = @sources.map { |source| source.send(:render_block, num_frames, start_frame, cache) }
229
+ output_channels = blocks.map(&:channels).max || default_input_channels
230
+ mixed = AudioBlock.silent(num_frames, output_channels)
231
+ blocks.each { |block| mixed.mix!(block) }
232
+ mixed
233
+ end
234
+
235
+ def normalize_output_block(output, num_frames, channels)
236
+ return output.dup if output.is_a?(AudioBlock)
237
+
238
+ AudioBlock.from_mono(output, channels: channels)
239
+ end
240
+
241
+ def process(input_buffer, _num_frames, _start_frame, _cache)
242
+ input_buffer
243
+ end
244
+
245
+ def uses_legacy_render_for_block?
246
+ self.class.instance_method(:render).owner != AudioNode
247
+ end
248
+
249
+ def multichannel_process?
250
+ false
251
+ end
252
+
253
+ def default_input_channels
254
+ 1
255
+ end
256
+
257
+ def default_output_channels
258
+ default_input_channels
259
+ end
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Core
5
+ class Clock < Emitter
6
+ attr_reader :context, :frequency, :state
7
+
8
+ def initialize(frequency: 1.0, context: Deftones.context, &block)
9
+ super()
10
+ @context = context
11
+ @frequency = Signal.new(value: frequency, units: :frequency, context: context)
12
+ @state = :stopped
13
+ @start_time = 0.0
14
+ @offset_ticks = 0.0
15
+ on(:tick, &block) if block
16
+ end
17
+
18
+ def start(time = nil, offset: nil)
19
+ @start_time = resolve_time(time)
20
+ @offset_ticks = offset.to_f if offset
21
+ @state = :started
22
+ self
23
+ end
24
+
25
+ def stop(time = nil)
26
+ @offset_ticks = ticks_at(resolve_time(time))
27
+ @start_time = resolve_time(time)
28
+ @state = :stopped
29
+ self
30
+ end
31
+
32
+ def pause(time = nil)
33
+ @offset_ticks = ticks_at(resolve_time(time))
34
+ @start_time = resolve_time(time)
35
+ @state = :paused
36
+ self
37
+ end
38
+
39
+ def ticks(time = context.current_time)
40
+ ticks_at(resolve_time(time))
41
+ end
42
+
43
+ def seconds(time = context.current_time)
44
+ ticks(time) / current_frequency
45
+ end
46
+
47
+ def next_tick_time(time = context.current_time)
48
+ tick_duration = 1.0 / current_frequency
49
+ current_ticks = ticks(time)
50
+ next_tick = current_ticks.floor + 1
51
+ resolve_time(time) + ((next_tick - current_ticks) * tick_duration)
52
+ end
53
+
54
+ def get_ticks_at_time(time)
55
+ ticks(time)
56
+ end
57
+
58
+ def emit_ticks_until(time)
59
+ return self unless state == :started
60
+
61
+ current_time = resolve_time(time)
62
+ emitted_ticks = (@last_emitted_tick || @offset_ticks.floor) + 1
63
+ while emitted_ticks <= ticks_at(current_time).floor
64
+ emit(:tick, emitted_ticks)
65
+ emitted_ticks += 1
66
+ end
67
+ @last_emitted_tick = emitted_ticks - 1
68
+ self
69
+ end
70
+
71
+ alias getTicksAtTime get_ticks_at_time
72
+ alias nextTickTime next_tick_time
73
+
74
+ private
75
+
76
+ def resolve_time(value)
77
+ value.nil? ? context.current_time : Deftones::Music::Time.parse(value)
78
+ end
79
+
80
+ def ticks_at(time)
81
+ return @offset_ticks unless state == :started
82
+
83
+ @offset_ticks + ([time - @start_time, 0.0].max * current_frequency)
84
+ end
85
+
86
+ def current_frequency
87
+ [frequency.value.to_f, 1.0e-6].max
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Core
5
+ class ComputedSignal < Signal
6
+ attr_reader :input
7
+
8
+ def initialize(input:, units: nil, context: nil)
9
+ resolved_context = resolve_context(input, fallback: context)
10
+ resolved_units = units || default_units(input)
11
+
12
+ super(value: 0.0, units: resolved_units, context: resolved_context)
13
+ @input = coerce_signal(input || 0.0, units: resolved_units)
14
+ end
15
+
16
+ def value
17
+ value_at(context.current_time)
18
+ end
19
+
20
+ def value=(_new_value)
21
+ raise Deftones::Error, "#{self.class.name} is derived and cannot be assigned"
22
+ end
23
+
24
+ def ramp_to(*)
25
+ raise Deftones::Error, "#{self.class.name} is derived and cannot be automated directly"
26
+ end
27
+
28
+ alias linear_ramp_to ramp_to
29
+ alias exponential_ramp_to ramp_to
30
+ alias set_value_at_time ramp_to
31
+ alias cancel_scheduled_values ramp_to
32
+
33
+ def process(num_frames, start_frame = 0)
34
+ Array.new(num_frames) do |offset|
35
+ value_at(sample_time(start_frame + offset))
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def default_units(candidate)
42
+ candidate.respond_to?(:units) ? candidate.units : :number
43
+ end
44
+
45
+ def resolve_context(candidate, fallback:)
46
+ return candidate.context if candidate.respond_to?(:context)
47
+ return fallback if fallback
48
+
49
+ Deftones.context
50
+ end
51
+
52
+ def coerce_signal(value, units:)
53
+ return value if value.respond_to?(:value_at)
54
+
55
+ Signal.new(value: value, units: units, context: context)
56
+ end
57
+
58
+ def exponentiate(value, exponent)
59
+ return value**exponent if value >= 0.0 || integer_like?(exponent)
60
+
61
+ -((-value)**exponent)
62
+ end
63
+
64
+ def integer_like?(value)
65
+ value.finite? && value.round == value
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Core
5
+ class Delay < AudioNode
6
+ attr_reader :delay_time, :max_delay
7
+
8
+ def initialize(delay_time: 0.0, max_delay: 1.0, context: Deftones.context)
9
+ super(context: context)
10
+ @delay_time = Signal.new(value: delay_time, units: :time, context: context)
11
+ @max_delay = [max_delay.to_f, @delay_time.value].max
12
+ @delay_lines = []
13
+ end
14
+
15
+ def multichannel_process?
16
+ true
17
+ end
18
+
19
+ def process(input_block, num_frames, start_frame, _cache)
20
+ delay_values = @delay_time.process(num_frames, start_frame)
21
+ AudioBlock.from_channel_data(
22
+ input_block.channel_data.each_with_index.map do |channel, channel_index|
23
+ delay_line = ensure_delay_line(channel_index)
24
+ Array.new(num_frames) do |index|
25
+ delay_seconds = [delay_values[index], 0.0].max
26
+ delay_samples = [delay_seconds * context.sample_rate, @max_delay * context.sample_rate].min
27
+ delay_line.tap(delay_samples, input_sample: channel[index], feedback: 0.0)
28
+ end
29
+ end
30
+ )
31
+ end
32
+
33
+ private
34
+
35
+ def ensure_delay_line(channel_index)
36
+ required = [channel_index.to_i, 0].max
37
+ while @delay_lines.length <= required
38
+ @delay_lines << DSP::DelayLine.new((@max_delay * context.sample_rate).ceil)
39
+ end
40
+ @delay_lines[required]
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Core
5
+ class Effect < AudioNode
6
+ attr_reader :wet
7
+
8
+ def initialize(wet: 1.0, context: Deftones.context)
9
+ super(context: context)
10
+ @wet = Signal.new(value: wet, units: :number, context: context)
11
+ end
12
+
13
+ def wet=(value)
14
+ @wet.value = value
15
+ end
16
+
17
+ def multichannel_process?
18
+ true
19
+ end
20
+
21
+ def process(input_block, num_frames, start_frame, cache)
22
+ wet_values = @wet.process(num_frames, start_frame)
23
+ wet_block = process_effect_block(input_block.dup, num_frames, start_frame, cache)
24
+ output_channels = [input_block.channels, wet_block.channels].max
25
+ dry_block = input_block.fit_channels(output_channels)
26
+ wet_block = wet_block.fit_channels(output_channels)
27
+
28
+ AudioBlock.from_channel_data(
29
+ Array.new(output_channels) do |channel_index|
30
+ Array.new(num_frames) do |frame_index|
31
+ DSP::Helpers.mix(
32
+ dry_block.channel_data[channel_index][frame_index],
33
+ wet_block.channel_data[channel_index][frame_index],
34
+ wet_values[frame_index].clamp(0.0, 1.0)
35
+ )
36
+ end
37
+ end
38
+ )
39
+ end
40
+
41
+ private
42
+
43
+ def process_effect_block(input_block, num_frames, start_frame, cache)
44
+ AudioBlock.from_channel_data(
45
+ input_block.channel_data.each_with_index.map do |channel, channel_index|
46
+ normalize_channel_output(
47
+ process_effect(channel, num_frames, start_frame, cache, channel_index: channel_index),
48
+ num_frames
49
+ )
50
+ end
51
+ )
52
+ end
53
+
54
+ def process_effect(input_buffer, _num_frames, _start_frame, _cache, channel_index: 0)
55
+ input_buffer
56
+ end
57
+
58
+ def normalize_channel_output(output, num_frames)
59
+ normalized = Array(output).map(&:to_f)
60
+ return normalized.first(num_frames) if normalized.length >= num_frames
61
+
62
+ normalized + Array.new(num_frames - normalized.length, 0.0)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Core
5
+ class Emitter
6
+ def initialize
7
+ @listeners = Hash.new { |hash, key| hash[key] = [] }
8
+ end
9
+
10
+ def on(event_name, &block)
11
+ raise ArgumentError, "block is required" unless block
12
+
13
+ @listeners[event_name.to_sym] << block
14
+ self
15
+ end
16
+
17
+ def once(event_name, &block)
18
+ raise ArgumentError, "block is required" unless block
19
+
20
+ wrapper = nil
21
+ wrapper = proc do |*arguments|
22
+ off(event_name, wrapper)
23
+ block.call(*arguments)
24
+ end
25
+ on(event_name, &wrapper)
26
+ end
27
+
28
+ def off(event_name, listener = nil)
29
+ key = event_name.to_sym
30
+ return @listeners.delete(key) unless listener
31
+
32
+ @listeners[key].delete(listener)
33
+ self
34
+ end
35
+
36
+ def emit(event_name, *arguments)
37
+ @listeners[event_name.to_sym].dup.each { |listener| listener.call(*arguments) }
38
+ self
39
+ end
40
+
41
+ def listeners(event_name)
42
+ @listeners[event_name.to_sym].dup
43
+ end
44
+
45
+ def dispose
46
+ @listeners.clear
47
+ self
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Core
5
+ class Gain < AudioNode
6
+ attr_reader :gain
7
+
8
+ def initialize(gain: 1.0, context: Deftones.context)
9
+ super(context: context)
10
+ @gain = Signal.new(value: gain, units: :number, context: context)
11
+ end
12
+
13
+ def gain=(value)
14
+ @gain.value = value
15
+ end
16
+
17
+ def process(input_buffer, num_frames, start_frame, _cache)
18
+ gain_values = @gain.process(num_frames, start_frame)
19
+
20
+ Array.new(num_frames) do |index|
21
+ input_buffer[index] * gain_values[index]
22
+ end
23
+ end
24
+
25
+ def multichannel_process?
26
+ true
27
+ end
28
+
29
+ def process(input_block, num_frames, start_frame, _cache)
30
+ gain_values = @gain.process(num_frames, start_frame)
31
+ AudioBlock.from_channel_data(
32
+ input_block.channel_data.map do |channel|
33
+ Array.new(num_frames) { |index| channel[index] * gain_values[index] }
34
+ end
35
+ )
36
+ end
37
+ end
38
+ end
39
+ end