Class: Deftones::Core::AudioNode

Inherits:
Object
  • Object
show all
Defined in:
lib/deftones/core/audio_node.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context: Deftones.context) ⇒ AudioNode

Returns a new instance of AudioNode.



8
9
10
11
12
13
14
# File 'lib/deftones/core/audio_node.rb', line 8

def initialize(context: Deftones.context)
  @context = context
  @input = self
  @sources = []
  @destinations = []
  @disposed = false
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



6
7
8
# File 'lib/deftones/core/audio_node.rb', line 6

def context
  @context
end

#inputObject (readonly)

Returns the value of attribute input.



6
7
8
# File 'lib/deftones/core/audio_node.rb', line 6

def input
  @input
end

Instance Method Details

#>>(other) ⇒ Object



42
43
44
45
# File 'lib/deftones/core/audio_node.rb', line 42

def >>(other)
  connect(other)
  other
end

#attach_destination(destination) ⇒ Object (protected)



253
254
255
256
257
258
# File 'lib/deftones/core/audio_node.rb', line 253

def attach_destination(destination)
  return if @destinations.include?(destination)

  @destinations << destination
  destination.attach_source(self)
end

#attach_source(source) ⇒ Object (protected)



243
244
245
246
247
# File 'lib/deftones/core/audio_node.rb', line 243

def attach_source(source)
  return if @sources.include?(source)

  @sources << source
end

#block_timeObject Also known as: blockTime



117
118
119
# File 'lib/deftones/core/audio_node.rb', line 117

def block_time
  context.buffer_size.to_f / context.sample_rate
end

#chain(*nodes) ⇒ Object



47
48
49
50
# File 'lib/deftones/core/audio_node.rb', line 47

def chain(*nodes)
  [self, *nodes].each_cons(2) { |source, destination| source.connect(destination) }
  nodes.last || self
end

#channel_countObject Also known as: channelCount



121
122
123
# File 'lib/deftones/core/audio_node.rb', line 121

def channel_count
  context.channels
end

#channel_count_modeObject Also known as: channelCountMode



125
126
127
# File 'lib/deftones/core/audio_node.rb', line 125

def channel_count_mode
  "max"
end

#channel_interpretationObject Also known as: channelInterpretation



129
130
131
# File 'lib/deftones/core/audio_node.rb', line 129

def channel_interpretation
  "speakers"
end

#connect(destination, output_index: 0, input_index: 0) ⇒ Object

Raises:

  • (ArgumentError)


20
21
22
23
24
25
26
27
28
29
30
# File 'lib/deftones/core/audio_node.rb', line 20

def connect(destination, output_index: 0, input_index: 0)
  raise ArgumentError, "destination is required" if destination.nil?

  source_node = output_for_connection(output_index)
  destination_node = destination_for_connection(destination, input_index)
  validate_connectable!(source_node, destination_node)
  raise ArgumentError, "connection would create a cycle" if destination_node.send(:reaches_node?, source_node)

  source_node.attach_destination(destination_node)
  self
end

#connected?(destination = nil) ⇒ Boolean Also known as: connected

Returns:

  • (Boolean)


65
66
67
68
69
70
# File 'lib/deftones/core/audio_node.rb', line 65

def connected?(destination = nil)
  return @destinations.any? if destination.nil?

  destination_node = destination.respond_to?(:input) ? destination.input : destination
  @destinations.include?(destination_node)
end

#default_input_channelsObject (protected)



296
297
298
# File 'lib/deftones/core/audio_node.rb', line 296

def default_input_channels
  1
end

#default_output_channelsObject (protected)



300
301
302
# File 'lib/deftones/core/audio_node.rb', line 300

def default_output_channels
  default_input_channels
end

#destination_for_connection(destination, index) ⇒ Object (private)



323
324
325
326
327
328
329
330
331
332
# File 'lib/deftones/core/audio_node.rb', line 323

def destination_for_connection(destination, index)
  normalized_index = normalize_connection_index(index, :input_index)
  if destination.respond_to?(:input_for_index)
    destination.input_for_index(normalized_index)
  else
    destination_node = destination.respond_to?(:input) ? destination.input : destination
    validate_connection_index!(normalized_index, destination_node.number_of_inputs, :input_index)
    destination_node
  end
end

#detach_all_destinationsObject (protected)



266
267
268
# File 'lib/deftones/core/audio_node.rb', line 266

def detach_all_destinations
  @destinations.dup.each { |destination| detach_destination(destination) }
end

#detach_destination(destination) ⇒ Object (protected)



260
261
262
263
264
# File 'lib/deftones/core/audio_node.rb', line 260

def detach_destination(destination)
  return unless @destinations.delete(destination)

  destination.detach_source(self)
end

#detach_source(source) ⇒ Object (protected)



249
250
251
# File 'lib/deftones/core/audio_node.rb', line 249

def detach_source(source)
  @sources.delete(source)
end

#disconnect(destination = nil) ⇒ Object



32
33
34
35
36
37
38
39
40
# File 'lib/deftones/core/audio_node.rb', line 32

def disconnect(destination = nil)
  if destination
    destination_node = destination.respond_to?(:input) ? destination.input : destination
    output.detach_destination(destination_node)
  else
    output.detach_all_destinations
  end
  self
end

#disposeObject



191
192
193
194
195
196
197
# File 'lib/deftones/core/audio_node.rb', line 191

def dispose
  disconnect
  @sources.dup.each { |source| source.detach_destination(self) }
  @sources.clear
  @disposed = true
  self
end

#disposed?Boolean

Returns:

  • (Boolean)


199
200
201
# File 'lib/deftones/core/audio_node.rb', line 199

def disposed?
  @disposed
end

#fan(*nodes) ⇒ Object



52
53
54
55
# File 'lib/deftones/core/audio_node.rb', line 52

def fan(*nodes)
  nodes.each { |node| connect(node) }
  self
end

#get(*keys, strict: false) ⇒ Object

Raises:

  • (ArgumentError)


152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/deftones/core/audio_node.rb', line 152

def get(*keys, strict: false)
  unknown = []
  values = keys.flatten.each_with_object({}) do |key, collected|
    reader = key.to_sym
    if respond_to?(reader)
      collected[reader] = public_send(reader)
    else
      unknown << reader
    end
  end
  raise ArgumentError, "Unknown parameter(s): #{unknown.join(', ')}" if strict && unknown.any?

  values
end

#immediateObject



89
90
91
# File 'lib/deftones/core/audio_node.rb', line 89

def immediate
  now
end

#input_for_index(index) ⇒ Object (protected)



215
216
217
218
219
# File 'lib/deftones/core/audio_node.rb', line 215

def input_for_index(index)
  raise_connection_index_error!(:input_index, index, number_of_inputs) unless index.zero?

  input
end

#inputsObject



57
58
59
# File 'lib/deftones/core/audio_node.rb', line 57

def inputs
  @sources.dup
end

#mix_source_blocks(num_frames, start_frame, cache) ⇒ Object (protected)



270
271
272
273
274
275
276
# File 'lib/deftones/core/audio_node.rb', line 270

def mix_source_blocks(num_frames, start_frame, cache)
  blocks = @sources.map { |source| source.send(:render_block, num_frames, start_frame, cache) }
  output_channels = blocks.map(&:channels).max || default_input_channels
  mixed = AudioBlock.silent(num_frames, output_channels)
  blocks.each { |block| mixed.mix!(block) }
  mixed
end

#multichannel_process?Boolean (protected)

Returns:

  • (Boolean)


292
293
294
# File 'lib/deftones/core/audio_node.rb', line 292

def multichannel_process?
  false
end

#nameObject



167
168
169
# File 'lib/deftones/core/audio_node.rb', line 167

def name
  self.class.name.split("::").last
end

#normalize_connection_index(index, name) ⇒ Object (private)



334
335
336
337
338
339
340
# File 'lib/deftones/core/audio_node.rb', line 334

def normalize_connection_index(index, name)
  Integer(index).tap do |normalized|
    raise ArgumentError, "#{name} must be greater than or equal to 0" if normalized.negative?
  end
rescue ArgumentError, TypeError
  raise ArgumentError, "#{name} must be an integer"
end

#normalize_output_block(output, num_frames, channels) ⇒ Object (protected)



278
279
280
281
282
# File 'lib/deftones/core/audio_node.rb', line 278

def normalize_output_block(output, num_frames, channels)
  return output.dup if output.is_a?(AudioBlock)

  AudioBlock.from_mono(output, channels: channels)
end

#nowObject



85
86
87
# File 'lib/deftones/core/audio_node.rb', line 85

def now
  context.current_time
end

#number_of_inputsObject Also known as: numberOfInputs



133
134
135
# File 'lib/deftones/core/audio_node.rb', line 133

def number_of_inputs
  1
end

#number_of_outputsObject Also known as: numberOfOutputs



137
138
139
# File 'lib/deftones/core/audio_node.rb', line 137

def number_of_outputs
  1
end

#outputObject



16
17
18
# File 'lib/deftones/core/audio_node.rb', line 16

def output
  self
end

#output_for_connection(index) ⇒ Object (private)



318
319
320
321
# File 'lib/deftones/core/audio_node.rb', line 318

def output_for_connection(index)
  normalized_index = normalize_connection_index(index, :output_index)
  output_for_index(normalized_index)
end

#output_for_index(index) ⇒ Object (protected)



209
210
211
212
213
# File 'lib/deftones/core/audio_node.rb', line 209

def output_for_index(index)
  raise_connection_index_error!(:output_index, index, number_of_outputs) unless index.zero?

  output
end

#outputsObject



61
62
63
# File 'lib/deftones/core/audio_node.rb', line 61

def outputs
  @destinations.dup
end

#process(input_buffer, _num_frames, _start_frame, _cache) ⇒ Object (protected)



284
285
286
# File 'lib/deftones/core/audio_node.rb', line 284

def process(input_buffer, _num_frames, _start_frame, _cache)
  input_buffer
end

#raise_connection_index_error!(name, index, count) ⇒ Object (protected)

Raises:

  • (ArgumentError)


312
313
314
# File 'lib/deftones/core/audio_node.rb', line 312

def raise_connection_index_error!(name, index, count)
  raise ArgumentError, "#{name} #{index} is out of range for #{count} #{count == 1 ? 'port' : 'ports'}"
end

#reaches_node?(target, visited = {}) ⇒ Boolean (protected)

Returns:

  • (Boolean)


304
305
306
307
308
309
310
# File 'lib/deftones/core/audio_node.rb', line 304

def reaches_node?(target, visited = {})
  return true if equal?(target)
  return false if visited[object_id]

  visited[object_id] = true
  @destinations.any? { |destination| destination.send(:reaches_node?, target, visited) }
end

#render(num_frames, start_frame = 0, cache = {}) ⇒ Object



203
204
205
# File 'lib/deftones/core/audio_node.rb', line 203

def render(num_frames, start_frame = 0, cache = {})
  render_block(num_frames, start_frame, cache).mono
end

#render_block(num_frames, start_frame = 0, cache = {}) ⇒ Object (protected)

Raises:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/deftones/core/audio_node.rb', line 221

def render_block(num_frames, start_frame = 0, cache = {})
  raise Deftones::Error, "cannot render disposed node: #{name}" if disposed?

  cache_key = [object_id, :block, start_frame, num_frames]
  return cache.fetch(cache_key).dup if cache.key?(cache_key)

  output_block = if uses_legacy_render_for_block?
                   normalize_output_block(render(num_frames, start_frame, cache), num_frames, 1)
                 else
                   input_block = mix_source_blocks(num_frames, start_frame, cache)
                   if multichannel_process?
                     normalize_output_block(process(input_block, num_frames, start_frame, cache), num_frames, input_block.channels)
                   else
                     mono_output = process(input_block.mono, num_frames, start_frame, cache)
                     normalize_output_block(mono_output, num_frames, [input_block.channels, default_output_channels].max)
                   end
                 end

  cache[cache_key] = output_block
  output_block.dup
end

#sample_timeObject Also known as: sampleTime



113
114
115
# File 'lib/deftones/core/audio_node.rb', line 113

def sample_time
  1.0 / context.sample_rate
end

#set(strict: false, **params) ⇒ Object

Raises:

  • (ArgumentError)


141
142
143
144
145
146
147
148
149
150
# File 'lib/deftones/core/audio_node.rb', line 141

def set(strict: false, **params)
  unknown = params.keys.reject { |key| respond_to?(:"#{key}=") }
  raise ArgumentError, "Unknown parameter(s): #{unknown.join(', ')}" if strict && unknown.any?

  params.each do |key, value|
    writer = :"#{key}="
    public_send(writer, value) if respond_to?(writer)
  end
  self
end

#to_destinationObject Also known as: toDestination



77
78
79
# File 'lib/deftones/core/audio_node.rb', line 77

def to_destination
  to_output
end

#to_frequency(value) ⇒ Object Also known as: toFrequency



105
106
107
# File 'lib/deftones/core/audio_node.rb', line 105

def to_frequency(value)
  Deftones::Music::Frequency.parse(value)
end

#to_masterObject Also known as: toMaster



81
82
83
# File 'lib/deftones/core/audio_node.rb', line 81

def to_master
  to_destination
end

#to_midi(value) ⇒ Object Also known as: toMidi



109
110
111
# File 'lib/deftones/core/audio_node.rb', line 109

def to_midi(value)
  Deftones::Music::Midi.parse(value)
end

#to_outputObject



72
73
74
75
# File 'lib/deftones/core/audio_node.rb', line 72

def to_output
  connect(context.output)
  self
end

#to_sObject Also known as: toString



171
172
173
# File 'lib/deftones/core/audio_node.rb', line 171

def to_s
  name
end

#to_seconds(time = nil) ⇒ Object Also known as: toSeconds



93
94
95
96
97
# File 'lib/deftones/core/audio_node.rb', line 93

def to_seconds(time = nil)
  return context.current_time if time.nil?

  Deftones::Music::Time.parse(time)
end

#to_ticks(time = nil) ⇒ Object Also known as: toTicks



99
100
101
102
103
# File 'lib/deftones/core/audio_node.rb', line 99

def to_ticks(time = nil)
  return Deftones.transport.ticks if time.nil?

  Deftones.transport.seconds_to_ticks(to_seconds(time))
end

#uses_legacy_render_for_block?Boolean (protected)

Returns:

  • (Boolean)


288
289
290
# File 'lib/deftones/core/audio_node.rb', line 288

def uses_legacy_render_for_block?
  self.class.instance_method(:render).owner != AudioNode
end

#validate_connectable!(source_node, destination_node) ⇒ Object (private)

Raises:



346
347
348
349
# File 'lib/deftones/core/audio_node.rb', line 346

def validate_connectable!(source_node, destination_node)
  raise Deftones::Error, "cannot connect disposed source node" if source_node.disposed?
  raise Deftones::Error, "cannot connect disposed destination node" if destination_node.disposed?
end

#validate_connection_index!(index, count, name) ⇒ Object (private)



342
343
344
# File 'lib/deftones/core/audio_node.rb', line 342

def validate_connection_index!(index, count, name)
  raise_connection_index_error!(name, index, count) if index >= count
end