Class: Deftones::DSP::Biquad

Inherits:
Object
  • Object
show all
Defined in:
lib/deftones/dsp/biquad.rb

Constant Summary collapse

TYPES =
%i[lowpass highpass bandpass notch allpass peaking lowshelf highshelf].freeze

Instance Method Summary collapse

Constructor Details

#initializeBiquad

Returns a new instance of Biquad.



8
9
10
11
# File 'lib/deftones/dsp/biquad.rb', line 8

def initialize
  reset!
  @coefficients = [1.0, 0.0, 0.0, 0.0, 0.0]
end

Instance Method Details

#highpass_coefficients(cos_omega, alpha) ⇒ Object (private)



81
82
83
84
85
86
87
88
89
90
# File 'lib/deftones/dsp/biquad.rb', line 81

def highpass_coefficients(cos_omega, alpha)
  [
    (1.0 + cos_omega) / 2.0,
    -(1.0 + cos_omega),
    (1.0 + cos_omega) / 2.0,
    1.0 + alpha,
    -2.0 * cos_omega,
    1.0 - alpha
  ]
end

#lowpass_coefficients(cos_omega, alpha) ⇒ Object (private)



70
71
72
73
74
75
76
77
78
79
# File 'lib/deftones/dsp/biquad.rb', line 70

def lowpass_coefficients(cos_omega, alpha)
  [
    (1.0 - cos_omega) / 2.0,
    1.0 - cos_omega,
    (1.0 - cos_omega) / 2.0,
    1.0 + alpha,
    -2.0 * cos_omega,
    1.0 - alpha
  ]
end

#normalize(b0, b1, b2, a0, a1, a2) ⇒ Object (private)



129
130
131
# File 'lib/deftones/dsp/biquad.rb', line 129

def normalize(b0, b1, b2, a0, a1, a2)
  [b0 / a0, b1 / a0, b2 / a0, a1 / a0, a2 / a0]
end

#peaking_coefficients(cos_omega, alpha, amplitude) ⇒ Object (private)



92
93
94
95
96
97
98
99
100
101
# File 'lib/deftones/dsp/biquad.rb', line 92

def peaking_coefficients(cos_omega, alpha, amplitude)
  [
    1.0 + (alpha * amplitude),
    -2.0 * cos_omega,
    1.0 - (alpha * amplitude),
    1.0 + (alpha / amplitude),
    -2.0 * cos_omega,
    1.0 - (alpha / amplitude)
  ]
end

#process_sample(sample) ⇒ Object



50
51
52
53
54
55
56
57
58
59
# File 'lib/deftones/dsp/biquad.rb', line 50

def process_sample(sample)
  b0, b1, b2, a1, a2 = @coefficients
  input = Helpers.flush_denormal(sample)
  output = Helpers.flush_denormal((b0 * input) + (b1 * @x1) + (b2 * @x2) - (a1 * @y1) - (a2 * @y2))
  @x2 = @x1
  @x1 = input
  @y2 = @y1
  @y1 = output
  output
end

#reset!Object



61
62
63
64
65
66
# File 'lib/deftones/dsp/biquad.rb', line 61

def reset!
  @x1 = 0.0
  @x2 = 0.0
  @y1 = 0.0
  @y2 = 0.0
end

#shelf_coefficients(kind, cos_omega, sin_omega, amplitude) ⇒ Object (private)



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/deftones/dsp/biquad.rb', line 103

def shelf_coefficients(kind, cos_omega, sin_omega, amplitude)
  sqrt_a = Math.sqrt(amplitude)
  alpha = sin_omega / Math.sqrt(2.0)
  common = 2.0 * sqrt_a * alpha

  if kind == :low
    [
      amplitude * ((amplitude + 1.0) - ((amplitude - 1.0) * cos_omega) + common),
      2.0 * amplitude * ((amplitude - 1.0) - ((amplitude + 1.0) * cos_omega)),
      amplitude * ((amplitude + 1.0) - ((amplitude - 1.0) * cos_omega) - common),
      (amplitude + 1.0) + ((amplitude - 1.0) * cos_omega) + common,
      -2.0 * ((amplitude - 1.0) + ((amplitude + 1.0) * cos_omega)),
      (amplitude + 1.0) + ((amplitude - 1.0) * cos_omega) - common
    ]
  else
    [
      amplitude * ((amplitude + 1.0) + ((amplitude - 1.0) * cos_omega) + common),
      -2.0 * amplitude * ((amplitude - 1.0) + ((amplitude + 1.0) * cos_omega)),
      amplitude * ((amplitude + 1.0) + ((amplitude - 1.0) * cos_omega) - common),
      (amplitude + 1.0) - ((amplitude - 1.0) * cos_omega) + common,
      2.0 * ((amplitude - 1.0) - ((amplitude + 1.0) * cos_omega)),
      (amplitude + 1.0) - ((amplitude - 1.0) * cos_omega) - common
    ]
  end
end

#update(type:, frequency:, q:, gain_db:, sample_rate:) ⇒ Object

Raises:

  • (ArgumentError)


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/deftones/dsp/biquad.rb', line 13

def update(type:, frequency:, q:, gain_db:, sample_rate:)
  raise ArgumentError, "Unsupported filter type: #{type}" unless TYPES.include?(type)

  normalized_sample_rate = [sample_rate.to_f, 1.0].max
  nyquist = normalized_sample_rate / 2.0
  lower_bound = [10.0, nyquist * 0.5].min
  upper_bound = [nyquist - 1.0e-6, lower_bound].max
  normalized_frequency = Helpers.clamp(frequency.to_f, lower_bound, upper_bound)
  omega = (2.0 * Math::PI * normalized_frequency) / normalized_sample_rate
  sin_omega = Math.sin(omega)
  cos_omega = Math.cos(omega)
  alpha = sin_omega / (2.0 * [q.to_f, 0.001].max)
  a = 10.0**(gain_db.to_f / 40.0)

  b0, b1, b2, a0, a1, a2 =
    case type
    when :lowpass
      lowpass_coefficients(cos_omega, alpha)
    when :highpass
      highpass_coefficients(cos_omega, alpha)
    when :bandpass
      [alpha, 0.0, -alpha, 1.0 + alpha, -2.0 * cos_omega, 1.0 - alpha]
    when :notch
      [1.0, -2.0 * cos_omega, 1.0, 1.0 + alpha, -2.0 * cos_omega, 1.0 - alpha]
    when :allpass
      [1.0 - alpha, -2.0 * cos_omega, 1.0 + alpha, 1.0 + alpha, -2.0 * cos_omega, 1.0 - alpha]
    when :peaking
      peaking_coefficients(cos_omega, alpha, a)
    when :lowshelf
      shelf_coefficients(:low, cos_omega, sin_omega, a)
    when :highshelf
      shelf_coefficients(:high, cos_omega, sin_omega, a)
    end

  @coefficients = normalize(b0, b1, b2, a0, a1, a2)
end