Class: Wavify::DSP::Effects::Compressor

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

Overview

Peak compressor with threshold, ratio, attack, and release controls.

Constant Summary

Constants inherited from EffectBase

EffectBase::TAIL_CHUNK_FRAMES

Instance Method Summary collapse

Methods inherited from EffectBase

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

Constructor Details

#initialize(threshold: -10,, ratio: 4, attack: 0.01, release: 0.1, makeup_gain: 0.0, knee: 0.0, sidechain: nil, sidechain_end: :silence) ⇒ Compressor

Returns a new instance of Compressor.

Parameters:

  • threshold: (Numeric) (defaults to: -10,)
  • ratio: (Numeric) (defaults to: 4)
  • attack: (Numeric) (defaults to: 0.01)
  • release: (Numeric) (defaults to: 0.1)
  • makeup_gain: (Numeric) (defaults to: 0.0)
  • knee: (Numeric) (defaults to: 0.0)
  • sidechain: (Audio, Core::SampleBuffer, nil) (defaults to: nil)
  • sidechain_end: (Symbol) (defaults to: :silence)


8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/wavify/dsp/effects/compressor.rb', line 8

def initialize(threshold: -10, ratio: 4, attack: 0.01, release: 0.1, makeup_gain: 0.0, knee: 0.0,
               sidechain: nil, sidechain_end: :silence)
  super()
  @threshold_db = validate_numeric!(threshold, :threshold).to_f
  @ratio = validate_ratio!(ratio)
  @attack = validate_time!(attack, :attack)
  @release = validate_time!(release, :release)
  @makeup_gain_db = validate_numeric!(makeup_gain, :makeup_gain).to_f
  @knee_db = validate_knee!(knee)
  @sidechain = validate_sidechain!(sidechain)
  @sidechain_end = validate_sidechain_end!(sidechain_end)
  reset
end

Instance Method Details

#process(buffer) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/wavify/dsp/effects/compressor.rb', line 22

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)
  prepare_runtime_if_needed!(
    sample_rate: float_format.sample_rate,
    channels: float_buffer.format.channels
  )

  output = []
  float_buffer.samples.each_slice(@runtime_channels) do |frame|
    detector_level = @sidechain ? next_sidechain_level : frame.map(&:abs).max
    gain = gain_for_detector_level(detector_level)
    output.concat(frame.map { |sample| sample * gain })
  end

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

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

Compression requires a complete frame so the detector can remain stereo-linked. Use #process with a SampleBuffer.

Parameters:

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

Returns:

  • (Float)

Raises:

  • (NotImplementedError)


49
50
51
# File 'lib/wavify/dsp/effects/compressor.rb', line 49

def process_sample(sample, channel:, sample_rate:)
  raise NotImplementedError, "Compressor requires frame-aware #apply or #process"
end