class_docstr: The Audio_Analyzer class provides access to continuously recorded
  (and mathematically processed) audio data.
  
  Arguments:
  
      device: int or None:      Select which audio stream to read .
      rate: float or None:      Sample rate to use. Defaults to something supported.
      FFT_window_size_ms: int:  Time window size (in ms) to use for the FFT transform
      updatesPerSecond: int:    How often to record new data.
class_docstr_tok: ["The","Audio_Analyzer","class","provides","access","to","continuously","recorded","(","and","mathematically","processed",")","audio","data",".","Arguments",":","device",":","int","or","None",":","Select","which","audio","stream","to","read",".","rate",":","float","or","None",":","Sample","rate","to","use",".","Defaults","to","something","supported",".","FFT_window_size_ms",":","int",":","Time","window","size","(","in","ms",")","to","use","for","the","FFT","transform","updatesPerSecond",":","int",":","How","often","to","record","new","data","."]
code: def get_audio_features(self):
      if (
          self.stream_reader.new_data
      ):  # Check if the stream_reader has new audio data we need to process
          if self.verbose:
              start = time.time()
  
          self.update_features()
          self.update_rolling_stats()
          self.stream_reader.new_data = False
  
          self.frequency_bin_energies = np.nan_to_num(
              self.frequency_bin_energies, copy=True
          )
          if self.apply_frequency_smoothing:
              if self.filter_width > 3:
                  self.frequency_bin_energies = savgol_filter(
                      self.frequency_bin_energies, self.filter_width, 3
                  )
          self.frequency_bin_energies[
              self.frequency_bin_energies < 0
          ] = 0
  
          if self.verbose:
              self.delays.append(time.time() - start)
              avg_fft_delay = 1000.0 * np.mean(np.array(self.delays))
              avg_data_capture_delay = 1000.0 * np.mean(
                  np.array(self.stream_reader.data_capture_delays)
              )
              data_fps = self.stream_reader.num_data_captures / (
                  time.time() - self.stream_reader.stream_start_time
              )
              print(
                  "\nAvg fft  delay: %.2fms  -- avg data delay: %.2fms"
                  % (avg_fft_delay, avg_data_capture_delay)
              )
              print(
                  "Num data captures: %d (%.2ffps)-- num fft computations: %d (%.2ffps)"
                  % (
                      self.stream_reader.num_data_captures,
                      data_fps,
                      self.num_ffts,
                      self.fft_fps,
                  )
              )
  
          if self.visualize and self.visualizer._is_running:
              self.visualizer.update()
  
      return (
          self.fftx,
          self.fft,
          self.frequency_bin_centres,
          self.frequency_bin_energies,
      )
  
file_path: rt-audio-fft/src/stream_analyzer.py
imports: import numpy
  import time, math, scipy
  from collections import deque
  from scipy.signal import savgol_filter
  from src.fft import getFFT
  from src.utils import *
label_desc: Use image node_id 4 for calling the Stream_Analyzer obj's underlying member method code with example usage: obj.get_audio_features() and returns: self,  self,  self,  self