Class: Deftones::Component::Convolver

Inherits:
Deftones::Core::Effect show all
Defined in:
lib/deftones/component/convolver.rb

Instance Attribute Summary collapse

Attributes inherited from Deftones::Core::Effect

#wet

Instance Method Summary collapse

Methods inherited from Deftones::Core::Effect

#multichannel_process?, #normalize_channel_output, #process, #process_effect

Constructor Details

#initialize(source = nil, wet: 1.0, normalize: false, context: Deftones.context, &onload) ⇒ Convolver

Returns a new instance of Convolver.



9
10
11
12
13
14
15
16
# File 'lib/deftones/component/convolver.rb', line 9

def initialize(source = nil, wet: 1.0, normalize: false, context: Deftones.context, &onload)
  super(wet: wet, context: context)
  @normalize = normalize
  @buffer = nil
  @kernels = [[1.0]]
  @histories = []
  load(source, &onload) if source
end

Instance Attribute Details

#bufferObject

Returns the value of attribute buffer.



6
7
8
# File 'lib/deftones/component/convolver.rb', line 6

def buffer
  @buffer
end

#normalizeObject

Returns the value of attribute normalize.



7
8
9
# File 'lib/deftones/component/convolver.rb', line 7

def normalize
  @normalize
end

Instance Method Details

#coerce_buffer(source) ⇒ Object (private)



70
71
72
73
74
# File 'lib/deftones/component/convolver.rb', line 70

def coerce_buffer(source)
  return source if source.is_a?(IO::Buffer)

  IO::Buffer.load(source)
end

#convolve(history, kernel) ⇒ Object (private)



61
62
63
64
65
66
67
68
# File 'lib/deftones/component/convolver.rb', line 61

def convolve(history, kernel)
  kernel.each_with_index.sum do |coefficient, offset|
    history_index = history.length - 1 - offset
    next 0.0 if history_index.negative?

    coefficient * history[history_index]
  end
end

#ensure_history(channel_index, kernel_length) ⇒ Object (private)



87
88
89
90
91
92
93
94
95
96
# File 'lib/deftones/component/convolver.rb', line 87

def ensure_history(channel_index, kernel_length)
  required = [channel_index.to_i, 0].max
  while @histories.length <= required
    @histories << Array.new([kernel_length - 1, 0].max, 0.0)
  end
  if @histories[required].length != [kernel_length - 1, 0].max
    @histories[required] = Array.new([kernel_length - 1, 0].max, 0.0)
  end
  @histories[required]
end

#load(source) {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:



22
23
24
25
26
27
28
# File 'lib/deftones/component/convolver.rb', line 22

def load(source)
  @buffer = coerce_buffer(source)
  @kernels = normalize_kernels(@buffer.to_array)
  @histories = []
  yield self if block_given?
  self
end

#normalize_kernels(channel_arrays) ⇒ Object (private)



76
77
78
79
80
81
82
83
84
85
# File 'lib/deftones/component/convolver.rb', line 76

def normalize_kernels(channel_arrays)
  kernels = channel_arrays.map { |channel| channel.map(&:to_f) }.reject(&:empty?)
  return [[1.0]] if kernels.empty?
  return kernels unless @normalize

  peak = kernels.flatten.map(&:abs).max || 0.0
  return kernels if peak.zero?

  kernels.map { |kernel| kernel.map { |sample| sample / peak } }
end

#passthrough?Boolean (private)

Returns:

  • (Boolean)


57
58
59
# File 'lib/deftones/component/convolver.rb', line 57

def passthrough?
  @buffer.nil? || (@kernels.length == 1 && @kernels.first.length == 1 && @kernels.first.first == 1.0)
end

#process_effect_block(input_block, num_frames, _start_frame, _cache) ⇒ Object (private)



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/deftones/component/convolver.rb', line 32

def process_effect_block(input_block, num_frames, _start_frame, _cache)
  return input_block if passthrough?

  output_channels = [input_block.channels, @kernels.length].max
  source = input_block.fit_channels([input_block.channels, 1].max)
  output = Array.new(output_channels) { Array.new(num_frames, 0.0) }

  output_channels.times do |channel_index|
    kernel = @kernels[channel_index % @kernels.length]
    history = ensure_history(channel_index, kernel.length).dup
    input_channel = source.channel_data[[channel_index, source.channels - 1].min]

    output[channel_index] = Array.new(num_frames) do |frame_index|
      history << input_channel[frame_index]
      sample = convolve(history, kernel)
      history.shift while history.length > kernel.length
      sample
    end

    @histories[channel_index] = history
  end

  Core::AudioBlock.from_channel_data(output)
end