class_docstr: Apply a Lowpass-like filterbank with variable octave attenuation that simulates attenuation of
  higher frequencies due to air absorption. This transform is parametrized by temperature,
  humidity, and the distance between audio source and microphone.
  
  This is not a scientifically accurate transform but basically applies a uniform
  filterbank with attenuations given by:
  
  att = exp(- distance * absorption_coefficient)
  
  where distance is the microphone-source assumed distance in meters and `absorption_coefficient`
  is adapted from a lookup table by pyroomacoustics [1]. It can also be seen as a lowpass filter
  with variable octave attenuation.
  
  Note: This only "simulates" the dampening of high frequencies, and does not
  attenuate according to the distance law. Gain augmentation needs to be done separately.
  
  [1] https://github.com/LCAV/pyroomacoustics
code: def apply(
      self, samples: NDArray[np.float32], sample_rate: int
  ) -> NDArray[np.float32]:
      assert samples.dtype == np.float32
  
      humidity = self.parameters["humidity"]
      distance = self.parameters["distance"]
  
      # Choose correct absorption coefficients
      key = str(int(self.parameters["temperature"])) + "C"
      bounds = [30, 50, 70, 90]
      for n in range(1, len(bounds)):
          if bounds[n - 1] <= humidity or humidity <= bounds[n]:
              key += f"_{bounds[n-1]}-{bounds[n]}%"
              break
  
      # Convert to attenuations
      attenuation_values = np.exp(
          -distance * np.array(self.air_absorption_table[key])
      )
  
      # Calculate n_fft so that the lowest band can be stored in a single
      # fft bin.
      first_band_bw = self.air_absorption_table["center_freqs"][0] / (
          2**0.5
      )
      n_fft = next_power_of_2(int(sample_rate / 2 / first_band_bw))
  
      # Frequencies to calculate the attenuations caused by air absorption
      frequencies = librosa.fft_frequencies(sr=sample_rate, n_fft=n_fft)
  
      # Interpolate to the desired frequencies (we have to do this in dB)
      db_target_attenuations = np.interp(
          frequencies,
          self.air_absorption_table["center_freqs"],
          20 * np.log10(attenuation_values),
      )
  
      linear_target_attenuations = 10 ** (db_target_attenuations / 20)
  
      # Apply using STFT
      if len(samples.shape) == 1:
          stft = librosa.stft(samples, n_fft=n_fft)
  
          # Compute mask
          mask = np.tile(
              linear_target_attenuations, (stft.shape[1], 1)
          ).T
  
          # Compute target degraded audio
          result = librosa.istft(
              stft * mask, length=len(samples), dtype=np.float32
          )
  
      else:
          result = np.zeros_like(samples, dtype=np.float32)
  
          for chn_idx, channel in enumerate(samples):
              stft = librosa.stft(channel, n_fft=n_fft)
  
              # Compute mask
              mask = np.tile(
                  linear_target_attenuations, (stft.shape[1], 1)
              ).T
  
              # Compute target degraded audio
              result[chn_idx, :] = librosa.istft(
                  stft * mask, length=result.shape[1]
              )
  
      return result
  
file_path: audiomentations/audiomentations/augmentations/air_absorption.py
imports: import librosa
  import numpy
  from numpy.typing import NDArray
  from audiomentations.core.transforms_interface import BaseWaveformTransform
label_desc: Use image node_id 3 for calling the AirAbsorption obj's underlying member method code with example usage: obj.apply(samples, sample_rate) and returns: result