text: """
  Modified version of librosa's mel function and supporting functions to not require hard install on pi (we dont need numba here)
  https://github.com/librosa/librosa
  """
  
  import numpy as np
  import time
  
  def fft_frequencies(sr=22050, n_fft=2048):
      return np.linspace(0, float(sr) / 2, int(1 + n_fft // 2), endpoint=True)
  
  def mel_to_hz(mels, htk=False):
      mels = np.asanyarray(mels)
  
      if htk:
          return 700.0 * (10.0 ** (mels / 2595.0) - 1.0)
  
      # Fill in the linear scale
      f_min = 0.0
      f_sp = 200.0 / 3
      freqs = f_min + f_sp * mels
  
      # And now the nonlinear scale
      min_log_hz = 1000.0  # beginning of log region (Hz)
      min_log_mel = (min_log_hz - f_min) / f_sp  # same (Mels)
      logstep = np.log(6.4) / 27.0  # step size for log region
  
      if mels.ndim:
          # If we have vector data, vectorize
          log_t = mels >= min_log_mel
          freqs[log_t] = min_log_hz * np.exp(logstep * (mels[log_t] - min_log_mel))
      elif mels >= min_log_mel:
          # If we have scalar data, check directly
          freqs = min_log_hz * np.exp(logstep * (mels - min_log_mel))
  
      return freqs
  
  def hz_to_mel(frequencies, htk=False):
      frequencies = np.asanyarray(frequencies)
  
      if htk:
          return 2595.0 * np.log10(1.0 + frequencies / 700.0)
  
      # Fill in the linear part
      f_min = 0.0
      f_sp = 200.0 / 3
  
      mels = (frequencies - f_min) / f_sp
  
      # Fill in the log-scale part
  
      min_log_hz = 1000.0  # beginning of log region (Hz)
      min_log_mel = (min_log_hz - f_min) / f_sp  # same (Mels)
      logstep = np.log(6.4) / 27.0  # step size for log region
  
      if frequencies.ndim:
          # If we have array data, vectorize
          log_t = frequencies >= min_log_hz
          mels[log_t] = min_log_mel + np.log(frequencies[log_t] / min_log_hz) / logstep
      elif frequencies >= min_log_hz:
          # If we have scalar data, heck directly
          mels = min_log_mel + np.log(frequencies / min_log_hz) / logstep
  
      return mels
  
  def mel_frequencies(n_mels=128, fmin=0.0, fmax=11025.0, htk=False):
  
      # 'Center freqs' of mel bands - uniformly spaced between limits
      min_mel = hz_to_mel(fmin, htk=htk)
      max_mel = hz_to_mel(fmax, htk=htk)
  
      mels = np.linspace(min_mel, max_mel, n_mels)
  
      return mel_to_hz(mels, htk=htk)
  
  
  def mel(
      sr,
      n_fft,
      n_mels=128,
      fmin=0.0,
      fmax=None,
      htk=False,
      dtype=np.float32,
  ):
  
      if fmax is None:
          fmax = float(sr) / 2
  
      # Initialize the weights
      n_mels = int(n_mels)
      weights = np.zeros((n_mels, int(1 + n_fft // 2)), dtype=dtype)
  
      # Center freqs of each FFT bin
      fftfreqs = fft_frequencies(sr=sr, n_fft=n_fft)
  
      # 'Center freqs' of mel bands - uniformly spaced between limits
      mel_f = mel_frequencies(n_mels + 2, fmin=fmin, fmax=fmax, htk=htk)
      fdiff = np.diff(mel_f)
      ramps = np.subtract.outer(mel_f, fftfreqs)
  
      for i in range(n_mels):
          # lower and upper slopes for all bins
          lower = -ramps[i] / fdiff[i]
          upper = ramps[i + 2] / fdiff[i + 1]
  
          # .. then intersect them with each other and zero
          weights[i] = np.maximum(0, np.minimum(lower, upper))
  
      for i in range(n_mels):
          # lower and upper slopes for all bins
          lower = -ramps[i] / fdiff[i]
          upper = ramps[i + 2] / fdiff[i + 1]
  
          # .. then intersect them with each other and zero
          weights[i] = np.maximum(0, np.minimum(lower, upper))
  
      # Slaney-style mel is scaled to be approx constant energy per channel
      enorm = 2.0 / (mel_f[2 : n_mels + 2] - mel_f[:n_mels])
      weights *= enorm[:, np.newaxis]
  
      return weights
  