Class: Wavify::DSP::Effects::EffectChain

Inherits:
Object
  • Object
show all
Defined in:
lib/wavify/dsp/effects/effect_chain.rb,
sig/effects.rbs

Overview

Processor that applies a fixed list of effects in sequence.

Direct Known Subclasses

MasteringChain, PodcastChain

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(effects) ⇒ EffectChain

Returns a new instance of EffectChain.

Parameters:

Raises:



11
12
13
14
15
# File 'lib/wavify/dsp/effects/effect_chain.rb', line 11

def initialize(effects)
  raise InvalidParameterError, "effects must be an Array" unless effects.is_a?(Array)

  @effects = effects.map { |effect| validate_effect!(effect) }.freeze
end

Instance Attribute Details

#effectsArray[untyped] (readonly)

Returns the value of attribute effects.

Returns:

  • (Array[untyped])


8
9
10
# File 'lib/wavify/dsp/effects/effect_chain.rb', line 8

def effects
  @effects
end

Instance Method Details

#apply(buffer) ⇒ Core::SampleBuffer

Applies every effect using its offline entrypoint when available.

Parameters:

Returns:

Raises:



29
30
31
32
33
# File 'lib/wavify/dsp/effects/effect_chain.rb', line 29

def apply(buffer)
  raise InvalidParameterError, "buffer must be Core::SampleBuffer" unless buffer.is_a?(Core::SampleBuffer)

  DSP::Processor.render(self, buffer)
end

#build_runtimeEffectChain

Builds a chain whose processors do not share runtime state.

Returns:



58
59
60
61
62
63
# File 'lib/wavify/dsp/effects/effect_chain.rb', line 58

def build_runtime
  runtime_effects = @effects.map { |effect| DSP::Processor.build_runtime(effect) }
  runtime = dup
  runtime.instance_variable_set(:@effects, runtime_effects.freeze)
  runtime.reset
end

#flush(format: nil) ⇒ Enumerator[Core::SampleBuffer, nil]

Flushes effect tails through every downstream processor.

Parameters:

Returns:



36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/wavify/dsp/effects/effect_chain.rb', line 36

def flush(format: nil)
  Enumerator.new do |yielder|
    @effects.each_with_index do |effect, index|
      DSP::Processor.flush(effect, format: format).each do |tail|
        next unless tail.sample_frame_count.positive?

        processed = @effects.drop(index + 1).reduce(tail) do |current, downstream|
          process_effect(downstream, current)
        end
        yielder << processed
      end
    end
  end
end

#latencyFloat

Returns:

  • (Float)


66
67
68
# File 'lib/wavify/dsp/effects/effect_chain.rb', line 66

def latency
  @effects.sum { |effect| DSP::Processor.duration(effect, :latency) }
end

#lookaheadFloat

Returns:

  • (Float)


71
72
73
# File 'lib/wavify/dsp/effects/effect_chain.rb', line 71

def lookahead
  @effects.sum { |effect| DSP::Processor.duration(effect, :lookahead) }
end

#process(buffer) ⇒ Wavify::Core::SampleBuffer



19
20
21
22
23
24
25
26
# File 'lib/wavify/dsp/effects/effect_chain.rb', line 19

def process(buffer)
  raise InvalidParameterError, "buffer must be Core::SampleBuffer" unless buffer.is_a?(Core::SampleBuffer)

  original_format = buffer.format
  float_format = original_format.with(sample_format: :float, bit_depth: 32)
  processed = @effects.reduce(buffer.convert(float_format)) { |current, effect| process_effect(effect, current) }
  processed.convert(original_format)
end

#resetEffectChain

Returns self.

Returns:



52
53
54
55
# File 'lib/wavify/dsp/effects/effect_chain.rb', line 52

def reset
  @effects.each { |effect| effect.reset if effect.respond_to?(:reset) }
  self
end

#tail_durationFloat

Returns:

  • (Float)


76
77
78
# File 'lib/wavify/dsp/effects/effect_chain.rb', line 76

def tail_duration
  @effects.sum { |effect| DSP::Processor.duration(effect, :tail_duration) }
end