o
    ?eaN                     @   sV  d Z ddlZddlmZ ddlmZ ddlmZ ddlmZ ddlm	Z	 ddlm
Z
 dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ edejdejddfddZedejejdfddZedejdejdfddZdd ZedejejdddfddZedejejddfd d!ZdS )"z8Spectral operations (e.g. Short-time Fourier Transform).    N)constant_op)dtypes)ops)tensor_util)	array_ops)math_ops)dct_ops)fft_ops)reconstruction_ops)	shape_ops)
window_ops)dispatch)	tf_exportzsignal.stftFc           	      C   s   t |d| ||g^ t j| dd} | jd t j|dd}|jd t j|dd}|jd |du r;t|}nt j|d	d}tj| |||d
}|durZ|||j	d}||9 }t
||gW  d   S 1 skw   Y  dS )aC  Computes the [Short-time Fourier Transform][stft] of `signals`.

  Implemented with TPU/GPU-compatible ops and supports gradients.

  Args:
    signals: A `[..., samples]` `float32`/`float64` `Tensor` of real-valued
      signals.
    frame_length: An integer scalar `Tensor`. The window length in samples.
    frame_step: An integer scalar `Tensor`. The number of samples to step.
    fft_length: An integer scalar `Tensor`. The size of the FFT to apply.
      If not provided, uses the smallest power of 2 enclosing `frame_length`.
    window_fn: A callable that takes a window length and a `dtype` keyword
      argument and returns a `[window_length]` `Tensor` of samples in the
      provided datatype. If set to `None`, no windowing is used.
    pad_end: Whether to pad the end of `signals` with zeros when the provided
      frame length and step produces a frame that lies partially past its end.
    name: An optional name for the operation.

  Returns:
    A `[..., frames, fft_unique_bins]` `Tensor` of `complex64`/`complex128`
    STFT values where `fft_unique_bins` is `fft_length // 2 + 1` (the unique
    components of the FFT).

  Raises:
    ValueError: If `signals` is not at least rank 1, `frame_length` is
      not scalar, or `frame_step` is not scalar.

  [stft]: https://en.wikipedia.org/wiki/Short-time_Fourier_transform
  stftsignalsname   frame_lengthr   
frame_stepN
fft_lengthpad_enddtype)r   
name_scopeconvert_to_tensorshapewith_rank_at_leastassert_has_rank_enclosing_power_of_twor   framer   r	   Zrfft)	r   r   r   r   	window_fnr   r   framed_signalswindow r%   j/home/www/facesmatcher.com/pyenv/lib/python3.10/site-packages/tensorflow/python/ops/signal/spectral_ops.pyr   "   s(   "
$r   zsignal.inverse_stft_window_fnc                    s    fdd}|S )a4  Generates a window function that can be used in `inverse_stft`.

  Constructs a window that is equal to the forward window with a further
  pointwise amplitude correction.  `inverse_stft_window_fn` is equivalent to
  `forward_window_fn` in the case where it would produce an exact inverse.

  See examples in `inverse_stft` documentation for usage.

  Args:
    frame_step: An integer scalar `Tensor`. The number of samples to step.
    forward_window_fn: window_fn used in the forward transform, `stft`.
    name: An optional name for the operation.

  Returns:
    A callable that takes a window length and a `dtype` keyword argument and
      returns a `[window_length]` `Tensor` of samples in the provided datatype.
      The returned window is suitable for reconstructing original waveform in
      inverse_stft.
  c                    s   t d gi t jdd}|jd t j| dd} | jd  | |d}t|}|  |  }t|d|| |  fg}t	|||g}tj
|ddd}t||d	g}t	||| g}||d
|   W  d
   S 1 stw   Y  d
S )a`  Computes a window that can be used in `inverse_stft`.

    Args:
      frame_length: An integer scalar `Tensor`. The window length in samples.
      dtype: Data type of waveform passed to `stft`.

    Returns:
      A window suitable for reconstructing original waveform in `inverse_stft`.

    Raises:
      ValueError: If `frame_length` is not scalar, `forward_window_fn` is not a
      callable that takes a window length and a `dtype` keyword argument and
      returns a `[window_length]` `Tensor` of samples in the provided datatype
      `frame_step` is not scalar, or `frame_step` is not scalar.
    inverse_stft_window_fnr   r   r   r   r   T)Zkeepdimsr   N)r   r   r   r   r   r   Zsquarer   padZreshapeZ
reduce_sumZtile)r   r   Zframe_step_Zforward_windowdenomoverlapsforward_window_fnr   r   r%   r&   inverse_stft_window_fn_innerw   s   
$z<inverse_stft_window_fn.<locals>.inverse_stft_window_fn_innerr%   )r   r,   r   r-   r%   r+   r&   r'   _   s   !r'   zsignal.inverse_stftc                 C   s*  t |d| g t j| dd} | jd t j|dd}|jd t j|dd}|jd |du r:t|}nt j|d	d}|jd t| |g}t	
|}|du sf|jjdu sf|j d
 du r|dd|f }t|}t|}	ttj|d dg|jddtd||	d
  gggd}
t||
}n8|j d
 |kr|dd|f }n&|j d
 |k r||j d
  }t|ddgg|jjd  d|gg }|dur|jjdur|dg|jjd  |g  |dur||| jjd}||9 }t||W  d   S 1 sw   Y  dS )aF	  Computes the inverse [Short-time Fourier Transform][stft] of `stfts`.

  To reconstruct an original waveform, a complementary window function should
  be used with `inverse_stft`. Such a window function can be constructed with
  `tf.signal.inverse_stft_window_fn`.
  Example:

  ```python
  frame_length = 400
  frame_step = 160
  waveform = tf.random.normal(dtype=tf.float32, shape=[1000])
  stft = tf.signal.stft(waveform, frame_length, frame_step)
  inverse_stft = tf.signal.inverse_stft(
      stft, frame_length, frame_step,
      window_fn=tf.signal.inverse_stft_window_fn(frame_step))
  ```

  If a custom `window_fn` is used with `tf.signal.stft`, it must be passed to
  `tf.signal.inverse_stft_window_fn`:

  ```python
  frame_length = 400
  frame_step = 160
  window_fn = tf.signal.hamming_window
  waveform = tf.random.normal(dtype=tf.float32, shape=[1000])
  stft = tf.signal.stft(
      waveform, frame_length, frame_step, window_fn=window_fn)
  inverse_stft = tf.signal.inverse_stft(
      stft, frame_length, frame_step,
      window_fn=tf.signal.inverse_stft_window_fn(
         frame_step, forward_window_fn=window_fn))
  ```

  Implemented with TPU/GPU-compatible ops and supports gradients.

  Args:
    stfts: A `complex64`/`complex128` `[..., frames, fft_unique_bins]`
      `Tensor` of STFT bins representing a batch of `fft_length`-point STFTs
      where `fft_unique_bins` is `fft_length // 2 + 1`
    frame_length: An integer scalar `Tensor`. The window length in samples.
    frame_step: An integer scalar `Tensor`. The number of samples to step.
    fft_length: An integer scalar `Tensor`. The size of the FFT that produced
      `stfts`. If not provided, uses the smallest power of 2 enclosing
      `frame_length`.
    window_fn: A callable that takes a window length and a `dtype` keyword
      argument and returns a `[window_length]` `Tensor` of samples in the
      provided datatype. If set to `None`, no windowing is used.
    name: An optional name for the operation.

  Returns:
    A `[..., samples]` `Tensor` of `float32`/`float64` signals representing
    the inverse STFT for each input STFT in `stfts`.

  Raises:
    ValueError: If `stfts` is not at least rank 2, `frame_length` is not scalar,
      `frame_step` is not scalar, or `fft_length` is not scalar.

  [stft]: https://en.wikipedia.org/wiki/Short-time_Fourier_transform
  inverse_stftstftsr      r   r   r   Nr   .r   r   )r   r   r   r   r   r   r    r	   Zirfftr   constant_valueZndimsas_listr   ZrankconcatZzerosr   r   maximumr(   	set_shapeZ
real_dtyper
   overlap_and_add)r/   r   r   r   r"   r   real_framesframe_length_staticZreal_frames_rankZreal_frames_shapeZpaddingsZ
pad_amountr$   r%   r%   r&   r.      s\   C




&r.   c                 C   st   t | }|durttdtt|td  | jS t	
t	dt	t	t	
| tjt	d | jS )z2Return 2**N for integer N such that 2**N >= value.Nr0   g       @)r   r2   r   Zconstantintnpceillogr   r   castpowr   Zfloat32)valueZvalue_staticr%   r%   r&   r      s    
$r    zsignal.mdctc                 C   sZ  t |d| |g t j| dd} | jd t j|dd}|jd t|}|durB|d dkr7td	t j|d
 |j	d}n|d
 }t
j| |||d}|dur_|||j	d}	||	9 }n	|dtd
 9 }tj|ddd}
t|
d
 dg |
d  }|
d t|
d dg }tj||fdd}tj|d|dW  d   S 1 sw   Y  dS )a  Computes the [Modified Discrete Cosine Transform][mdct] of `signals`.

  Implemented with TPU/GPU-compatible ops and supports gradients.

  Args:
    signals: A `[..., samples]` `float32`/`float64` `Tensor` of real-valued
      signals.
    frame_length: An integer scalar `Tensor`. The window length in samples
      which must be divisible by 4.
    window_fn: A callable that takes a frame_length and a `dtype` keyword
      argument and returns a `[frame_length]` `Tensor` of samples in the
      provided datatype. If set to `None`, a rectangular window with a scale of
      1/sqrt(2) is used. For perfect reconstruction of a signal from `mdct`
      followed by `inverse_mdct`, please use `tf.signal.vorbis_window`,
      `tf.signal.kaiser_bessel_derived_window` or `None`. If using another
      window function, make sure that w[n]^2 + w[n + frame_length // 2]^2 = 1
      and w[n] = w[frame_length - n - 1] for n = 0,...,frame_length // 2 - 1 to
      achieve perfect reconstruction.
    pad_end: Whether to pad the end of `signals` with zeros when the provided
      frame length and step produces a frame that lies partially past its end.
    norm: If it is None, unnormalized dct4 is used, if it is "ortho"
      orthonormal dct4 is used.
    name: An optional name for the operation.

  Returns:
    A `[..., frames, frame_length // 2]` `Tensor` of `float32`/`float64`
    MDCT values where `frames` is roughly `samples // (frame_length // 2)`
    when `pad_end=False`.

  Raises:
    ValueError: If `signals` is not at least rank 1, `frame_length` is
      not scalar, or `frame_length` is not a multiple of `4`.

  [mdct]: https://en.wikipedia.org/wiki/Modified_discrete_cosine_transform
  mdctr   r   r   r   r   N   z)The frame length must be a multiple of 4.r0   r   r         ?r1   Zaxis   typenorm)r   r   r   r   r   r   r   r2   
ValueErrorr   r   r!   r;   sqrtr   splitreverser4   r   dct)r   r   r"   r   rH   r   r9   r   r#   r$   Zsplit_framesZframe_firsthalfZframe_secondhalfZframes_rearrangedr%   r%   r&   rA   #  sD   '




$rA   zsignal.inverse_mdctc           
      C   s>  t |d| g t j| dd} | jd tj| jd tjd}|du r9tj|| j	d}d| t
j| d	d
 }n|dkrEt
j| d	dd}tj|ddd}tj|d t|d dg t|d dg |d  fdd}|dur|d| | j	d}	||	9 }n	|dtd 9 }t||W  d   S 1 sw   Y  dS )aU	  Computes the inverse modified DCT of `mdcts`.

  To reconstruct an original waveform, the same window function should
  be used with `mdct` and `inverse_mdct`.

  Example usage:

  >>> @tf.function
  ... def compare_round_trip():
  ...   samples = 1000
  ...   frame_length = 400
  ...   halflen = frame_length // 2
  ...   waveform = tf.random.normal(dtype=tf.float32, shape=[samples])
  ...   waveform_pad = tf.pad(waveform, [[halflen, 0],])
  ...   mdct = tf.signal.mdct(waveform_pad, frame_length, pad_end=True,
  ...                         window_fn=tf.signal.vorbis_window)
  ...   inverse_mdct = tf.signal.inverse_mdct(mdct,
  ...                                         window_fn=tf.signal.vorbis_window)
  ...   inverse_mdct = inverse_mdct[halflen: halflen + samples]
  ...   return waveform, inverse_mdct
  >>> waveform, inverse_mdct = compare_round_trip()
  >>> np.allclose(waveform.numpy(), inverse_mdct.numpy(), rtol=1e-3, atol=1e-4)
  True

  Implemented with TPU/GPU-compatible ops and supports gradients.

  Args:
    mdcts: A `float32`/`float64` `[..., frames, frame_length // 2]`
      `Tensor` of MDCT bins representing a batch of `frame_length // 2`-point
      MDCTs.
    window_fn: A callable that takes a frame_length and a `dtype` keyword
      argument and returns a `[frame_length]` `Tensor` of samples in the
      provided datatype. If set to `None`, a rectangular window with a scale of
      1/sqrt(2) is used. For perfect reconstruction of a signal from `mdct`
      followed by `inverse_mdct`, please use `tf.signal.vorbis_window`,
      `tf.signal.kaiser_bessel_derived_window` or `None`. If using another
      window function, make sure that w[n]^2 + w[n + frame_length // 2]^2 = 1
      and w[n] = w[frame_length - n - 1] for n = 0,...,frame_length // 2 - 1 to
      achieve perfect reconstruction.
    norm: If "ortho", orthonormal inverse DCT4 is performed, if it is None,
      a regular dct4 followed by scaling of `1/frame_length` is performed.
    name: An optional name for the operation.

  Returns:
    A `[..., samples]` `Tensor` of `float32`/`float64` signals representing
    the inverse MDCT for each input MDCT in `mdcts` where `samples` is
    `(frames - 1) * (frame_length // 2) + frame_length`.

  Raises:
    ValueError: If `mdcts` is not at least rank 2.

  [mdct]: https://en.wikipedia.org/wiki/Modified_discrete_cosine_transform
  inverse_mdctmdctsr   r0   r1   r   Ng      ?rB   )rG   ZorthorF   rD   r   r   rC   )r   r   r   r   r   r   r>   r   Zint32r   r   rM   r   rK   r4   rL   r;   rJ   r
   r7   )
rO   r"   rH   r   Zhalf_lenZhalf_len_floatZresult_idct4Zsplit_resultr8   r$   r%   r%   r&   rN   o  s.   ;


$rN   )__doc__numpyr;   Ztensorflow.python.frameworkr   r   r   r   Ztensorflow.python.opsr   r   Ztensorflow.python.ops.signalr   r	   r
   r   r   Ztensorflow.python.utilr   Z tensorflow.python.util.tf_exportr   Zadd_dispatch_supportZhann_windowr   r'   r.   r    Zvorbis_windowrA   rN   r%   r%   r%   r&   <module>   sX   ;:xJ