Class: Wavify::DSP::Effects::Reverb

Inherits:
EffectBase show all
Defined in:
lib/wavify/dsp/effects/reverb.rb,
sig/effects.rbs

Overview

Lightweight Schroeder-style reverb effect.

Constant Summary collapse

COMB_TAPS_44K =

:nodoc:

[1116, 1188, 1277, 1356].freeze
ALLPASS_TAPS_44K =

:nodoc:

[556, 441].freeze

Constants inherited from EffectBase

EffectBase::TAIL_CHUNK_FRAMES

Instance Method Summary collapse

Methods inherited from EffectBase

#apply, #build_runtime, #flush, #latency, #lookahead, #reset

Constructor Details

#initialize(room_size: 0.5, damping: 0.5, mix: 0.3, pre_delay: 0.0, width: 1.0) ⇒ Reverb

Returns a new instance of Reverb.

Parameters:

  • room_size: (Numeric) (defaults to: 0.5)
  • damping: (Numeric) (defaults to: 0.5)
  • mix: (Numeric) (defaults to: 0.3)
  • pre_delay: (Numeric) (defaults to: 0.0)
  • width: (Numeric) (defaults to: 1.0)


11
12
13
14
15
16
17
18
19
# File 'lib/wavify/dsp/effects/reverb.rb', line 11

def initialize(room_size: 0.5, damping: 0.5, mix: 0.3, pre_delay: 0.0, width: 1.0)
  super()
  @room_size = validate_unit!(room_size, :room_size)
  @damping = validate_unit!(damping, :damping)
  @mix = validate_unit!(mix, :mix)
  @pre_delay = validate_time!(pre_delay, :pre_delay)
  @width = validate_width!(width)
  reset
end

Instance Method Details

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

Processes a sample buffer.

Stereo buffers apply width: to the wet signal before mixing it with the dry input. Mono and multichannel buffers keep per-channel wet paths.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/wavify/dsp/effects/reverb.rb', line 28

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

  float_format = buffer.format.with(sample_format: :float, bit_depth: 32)
  float_buffer = buffer.convert(float_format)
  channels = float_buffer.format.channels
  prepare_runtime_if_needed!(sample_rate: float_format.sample_rate, channels: channels)

  output = Array.new(float_buffer.samples.length)
  float_buffer.samples.each_slice(channels).with_index do |frame, frame_index|
    wet_frame = frame.each_with_index.map do |sample, channel|
      wet_sample_for(@channels_state.fetch(channel), sample.to_f)
    end
    wet_frame = apply_stereo_width(wet_frame) if channels == 2

    base = frame_index * channels
    frame.each_with_index do |dry, channel|
      output[base + channel] = mix_dry_wet(dry.to_f, wet_frame.fetch(channel))
    end
  end

  Core::SampleBuffer.new(output, float_format).convert(buffer.format)
end

#process_sample(sample, channel:, sample_rate:) ⇒ Float

Processes a single sample for one channel.

Parameters:

  • sample (Numeric)
  • channel (Integer)
  • sample_rate (Integer)

Returns:

  • (Float)


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

def process_sample(sample, channel:, sample_rate:)
  dry = sample.to_f
  channel_state = @channels_state.fetch(channel)
  mix_dry_wet(dry, wet_sample_for(channel_state, dry))
end

#tail_durationFloat

Returns estimated reverb tail duration in seconds.

Returns:

  • (Float)

    estimated reverb tail duration in seconds



65
66
67
68
69
# File 'lib/wavify/dsp/effects/reverb.rb', line 65

def tail_duration
  return 0.0 if @mix.zero?

  @pre_delay + 0.25 + (@room_size * 2.5)
end