Class: Wavify::DSP::Effects::EQ
- Inherits:
-
Object
- Object
- Wavify::DSP::Effects::EQ
- Defined in:
- lib/wavify/dsp/effects/eq.rb,
sig/effects.rbs
Overview
Ordered chain of biquad filters for simple EQ curves.
Class Method Summary collapse
-
.simple(highpass: nil, lowpass: nil, presence: nil) ⇒ EQ
Convenience constructor for common tone-shaping bands.
Instance Method Summary collapse
- #apply(buffer) ⇒ Core::SampleBuffer
- #build_runtime ⇒ EQ
-
#flush(format: nil) ⇒ Object
Drains the filters' IIR state through the complete EQ chain.
-
#initialize(*filters) ⇒ EQ
constructor
A new instance of EQ.
- #latency ⇒ Float
- #lookahead ⇒ Float
-
#process(buffer) ⇒ Wavify::Core::SampleBuffer
Applies all filters in order.
-
#reset ⇒ EQ
Resets stateful filters in the chain.
- #tail_duration ⇒ Float
Constructor Details
#initialize(*filters) ⇒ EQ
Returns a new instance of EQ.
10 11 12 13 14 15 16 17 18 |
# File 'lib/wavify/dsp/effects/eq.rb', line 10 def initialize(*filters) @filters = filters.flatten raise InvalidParameterError, "at least one filter is required" if @filters.empty? @filters.each do |filter| raise InvalidParameterError, "filters must respond to :apply or :process" unless filter.respond_to?(:apply) || filter.respond_to?(:process) end @runtime_format = nil end |
Class Method Details
.simple(highpass: nil, lowpass: nil, presence: nil) ⇒ EQ
Convenience constructor for common tone-shaping bands.
26 27 28 29 30 31 32 |
# File 'lib/wavify/dsp/effects/eq.rb', line 26 def self.simple(highpass: nil, lowpass: nil, presence: nil) filters = [] filters << Wavify::DSP::Filter.highpass(cutoff: highpass) if highpass filters << Wavify::DSP::Filter.lowpass(cutoff: lowpass) if lowpass filters << Wavify::DSP::Filter.peaking(**presence) if presence new(filters) end |
Instance Method Details
#apply(buffer) ⇒ Core::SampleBuffer
50 51 52 |
# File 'lib/wavify/dsp/effects/eq.rb', line 50 def apply(buffer) DSP::Processor.render(self, buffer) end |
#build_runtime ⇒ EQ
63 64 65 |
# File 'lib/wavify/dsp/effects/eq.rb', line 63 def build_runtime self.class.new(@filters.map { |filter| DSP::Processor.build_runtime(filter) }) end |
#flush(format: nil) ⇒ Object
Drains the filters' IIR state through the complete EQ chain.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/wavify/dsp/effects/eq.rb', line 68 def flush(format: nil) return nil unless @runtime_format Enumerator.new do |yielder| @filters.each_with_index do |filter, index| DSP::Processor.flush(filter, format: format || @runtime_format).each do |tail| processed = @filters.drop(index + 1).reduce(tail) do |current, downstream| DSP::Processor.process(downstream, current) end yielder << processed end end ensure @runtime_format = nil end end |
#latency ⇒ Float
86 87 88 |
# File 'lib/wavify/dsp/effects/eq.rb', line 86 def latency @filters.sum { |filter| DSP::Processor.duration(filter, :latency) } end |
#lookahead ⇒ Float
91 92 93 |
# File 'lib/wavify/dsp/effects/eq.rb', line 91 def lookahead @filters.sum { |filter| DSP::Processor.duration(filter, :lookahead) } end |
#process(buffer) ⇒ Wavify::Core::SampleBuffer
Applies all filters in order.
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/wavify/dsp/effects/eq.rb', line 38 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 = @filters.reduce(buffer.convert(float_format)) do |current, filter| DSP::Processor.process(filter, current) end.convert(original_format) @runtime_format = buffer.format processed end |
#reset ⇒ EQ
Resets stateful filters in the chain.
57 58 59 60 61 |
# File 'lib/wavify/dsp/effects/eq.rb', line 57 def reset @filters.each { |filter| filter.reset if filter.respond_to?(:reset) } @runtime_format = nil self end |