Class: Vizcore::Analysis::FFTProcessor

Inherits:
Object
  • Object
show all
Defined in:
lib/vizcore/analysis/fft_processor.rb

Overview

Performs FFT analysis with optional FFTW acceleration and Ruby fallback.

Defined Under Namespace

Classes: FFTWBackend, RubyBackend

Constant Summary collapse

SUPPORTED_WINDOWS =

Supported windowing functions applied before FFT.

%i[hamming hann blackman none].freeze
SUPPORTED_BACKENDS =

Supported transform backends.

%i[auto ruby fftw].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sample_rate: 44_100, fft_size: 1024, window: :hamming, backend: :auto) ⇒ FFTProcessor

Returns a new instance of FFTProcessor.

Parameters:

  • sample_rate (Integer) (defaults to: 44_100)

    input sample rate

  • fft_size (Integer) (defaults to: 1024)

    FFT frame size (power of two)

  • window (Symbol) (defaults to: :hamming)
  • backend (Symbol) (defaults to: :auto)

Raises:

  • (ArgumentError)


25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/vizcore/analysis/fft_processor.rb', line 25

def initialize(sample_rate: 44_100, fft_size: 1024, window: :hamming, backend: :auto)
  @sample_rate = Integer(sample_rate)
  @fft_size = Integer(fft_size)
  @window = window.to_sym
  @backend_requested = backend.to_sym

  raise ArgumentError, "fft_size must be power of two" unless power_of_two?(@fft_size)
  raise ArgumentError, "unsupported window: #{@window}" unless SUPPORTED_WINDOWS.include?(@window)
  raise ArgumentError, "unsupported backend: #{@backend_requested}" unless SUPPORTED_BACKENDS.include?(@backend_requested)

  @backend = resolve_backend(@backend_requested)
end

Instance Attribute Details

#backend_nameObject (readonly)

Returns the value of attribute backend_name.



14
15
16
# File 'lib/vizcore/analysis/fft_processor.rb', line 14

def backend_name
  @backend_name
end

#fft_sizeObject (readonly)

Returns the value of attribute fft_size.



14
15
16
# File 'lib/vizcore/analysis/fft_processor.rb', line 14

def fft_size
  @fft_size
end

#sample_rateObject (readonly)

Returns the value of attribute sample_rate.



14
15
16
# File 'lib/vizcore/analysis/fft_processor.rb', line 14

def sample_rate
  @sample_rate
end

#windowObject (readonly)

Returns the value of attribute window.



14
15
16
# File 'lib/vizcore/analysis/fft_processor.rb', line 14

def window
  @window
end

Class Method Details

.fftw_available?Boolean

Returns true when FFTW3 is available.

Returns:

  • (Boolean)

    true when FFTW3 is available.



17
18
19
# File 'lib/vizcore/analysis/fft_processor.rb', line 17

def self.fftw_available?
  FFTWFFI.available?
end

Instance Method Details

#bin_frequency(bin_index) ⇒ Float

Returns frequency in Hz corresponding to the FFT bin.

Parameters:

  • bin_index (Integer)

Returns:

  • (Float)

    frequency in Hz corresponding to the FFT bin



58
59
60
# File 'lib/vizcore/analysis/fft_processor.rb', line 58

def bin_frequency(bin_index)
  Integer(bin_index) * sample_rate.to_f / fft_size.to_f
end

#call(samples) ⇒ Hash

Returns FFT result with magnitudes, complex spectrum, and peak info.

Parameters:

  • samples (Array<Numeric>)

    PCM frame samples

Returns:

  • (Hash)

    FFT result with magnitudes, complex spectrum, and peak info



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/vizcore/analysis/fft_processor.rb', line 40

def call(samples)
  frame = prepare_frame(samples)
  windowed = apply_window(frame)
  spectrum = execute_transform(windowed)
  half_spectrum = spectrum.first(@fft_size / 2)
  magnitudes = half_spectrum.map(&:abs)
  peak_bin = peak_index(magnitudes)

  {
    magnitudes: magnitudes,
    spectrum: half_spectrum,
    peak_bin: peak_bin,
    peak_frequency: bin_frequency(peak_bin)
  }
end