o
    MeZ                     @   s   d dl mZ d dlZddlmZmZ ddlmZmZm	Z	 ddl
mZ ddlmZ ddlmZ d d	lmZmZ d d
lmZmZ ddgZdddZdddZ								dddZ									dddZdS )    )OptionalN   )
is_complexis_floating_point)fft_r2cfft_c2rfft_c2c)check_variable_and_dtype)_non_static_mode)LayerHelper)_C_ops_legacy_C_ops)in_dygraph_mode_in_legacy_dygraphstftistftc                 C   s<  |dvrt d| dt|tr|dkrt d| dt|tr&|dkr.t d| dt rF|| j| krFt d| d	| j|  d
d}t rSt| |||S t rmd|d|d|f}t	t
|}|| g|R  }|S t| dg d| t|fi t }	|	jdd}
|	j|
d}|	j|d| i|||dd|id |S )am	  
    Slice the N-dimensional (where N >= 1) input into (overlapping) frames.

    Args:
        x (Tensor): The input data which is a N-dimensional (where N >= 1) Tensor
            with shape `[..., seq_length]` or `[seq_length, ...]`.
        frame_length (int): Length of the frame and `0 < frame_length <= x.shape[axis]`.
        hop_length (int): Number of steps to advance between adjacent frames
            and `0 < hop_length`. 
        axis (int, optional): Specify the axis to operate on the input Tensors. Its
            value should be 0(the first dimension) or -1(the last dimension). If not
            specified, the last axis is used by default. 

    Returns:
        The output frames tensor with shape `[..., frame_length, num_frames]` if `axis==-1`,
            otherwise `[num_frames, frame_length, ...]` where
        
            `num_framse = 1 + (x.shape[axis] - frame_length) // hop_length`

    Examples:

    .. code-block:: python

        import paddle
        from paddle.signal import frame
        
        # 1D
        x = paddle.arange(8)
        y0 = frame(x, frame_length=4, hop_length=2, axis=-1)  # [4, 3]
        # [[0, 2, 4],
        #  [1, 3, 5],
        #  [2, 4, 6],
        #  [3, 5, 7]]

        y1 = frame(x, frame_length=4, hop_length=2, axis=0)   # [3, 4]
        # [[0, 1, 2, 3],
        #  [2, 3, 4, 5],
        #  [4, 5, 6, 7]]

        # 2D
        x0 = paddle.arange(16).reshape([2, 8])
        y0 = frame(x0, frame_length=4, hop_length=2, axis=-1)  # [2, 4, 3]
        # [[[0, 2, 4],
        #   [1, 3, 5],
        #   [2, 4, 6],
        #   [3, 5, 7]],
        #
        #  [[8 , 10, 12],
        #   [9 , 11, 13],
        #   [10, 12, 14],
        #   [11, 13, 15]]]

        x1 = paddle.arange(16).reshape([8, 2])
        y1 = frame(x1, frame_length=4, hop_length=2, axis=0)   # [3, 4, 2]
        # [[[0 , 1 ],
        #   [2 , 3 ],
        #   [4 , 5 ],
        #   [6 , 7 ]],
        #
        #   [4 , 5 ],
        #   [6 , 7 ],
        #   [8 , 9 ],
        #   [10, 11]],
        #
        #   [8 , 9 ],
        #   [10, 11],
        #   [12, 13],
        #   [14, 15]]]

        # > 2D
        x0 = paddle.arange(32).reshape([2, 2, 8])
        y0 = frame(x0, frame_length=4, hop_length=2, axis=-1)  # [2, 2, 4, 3]

        x1 = paddle.arange(32).reshape([8, 2, 2])
        y1 = frame(x1, frame_length=4, hop_length=2, axis=0)   # [3, 4, 2, 2]
    r   r   Unexpected axis: . It should be 0 or -1.r   zUnexpected frame_length: #. It should be an positive integer.Unexpected hop_length: zKAttribute frame_length should be less equal than sequence length, but got (z) > (z).frameframe_length
hop_lengthaxisxZint32Zint64Zfloat16float32float64Zinput_param_namedtypeX)r   r   r   OuttypeZinputsattrsZoutputs)
ValueError
isinstanceintr
   shaper   r   r   r   getattrr   r	   r   localsinput_dtype"create_variable_for_type_inference	append_op)r   r   r   r   nameop_typer'   opouthelperr"    r6   =D:\Projects\ConvertPro\env\Lib\site-packages\paddle/signal.pyr   !   sZ   M




r   c           
      C   s   |dvrt d| dt|tr|dkrt d| dd}t r+t| ||}|S t rDd|d	|f}tt	|}|| g|R  }|S t
| d
g d| t|fi t }|jd
d}	|j|	d}|j|d| i||dd|id |S )a  
    Reconstructs a tensor consisted of overlap added sequences from input frames.

    Args:
        x (Tensor): The input data which is a N-dimensional (where N >= 2) Tensor
            with shape `[..., frame_length, num_frames]` or
            `[num_frames, frame_length ...]`.
        hop_length (int): Number of steps to advance between adjacent frames and
            `0 < hop_length <= frame_length`. 
        axis (int, optional): Specify the axis to operate on the input Tensors. Its
            value should be 0(the first dimension) or -1(the last dimension). If not
            specified, the last axis is used by default. 

    Returns:
        The output frames tensor with shape `[..., seq_length]` if `axis==-1`,
            otherwise `[seq_length, ...]` where

            `seq_length = (n_frames - 1) * hop_length + frame_length`

    Examples:

    .. code-block:: python

        import paddle
        from paddle.signal import overlap_add
        
        # 2D
        x0 = paddle.arange(16).reshape([8, 2])
        # [[0 , 1 ],
        #  [2 , 3 ],
        #  [4 , 5 ],
        #  [6 , 7 ],
        #  [8 , 9 ],
        #  [10, 11],
        #  [12, 13],
        #  [14, 15]]
        y0 = overlap_add(x0, hop_length=2, axis=-1)  # [10]
        # [0 , 2 , 5 , 9 , 13, 17, 21, 25, 13, 15]

        x1 = paddle.arange(16).reshape([2, 8])
        # [[0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ],
        #  [8 , 9 , 10, 11, 12, 13, 14, 15]]
        y1 = overlap_add(x1, hop_length=2, axis=0)   # [10]
        # [0 , 1 , 10, 12, 14, 16, 18, 20, 14, 15]

        # > 2D
        x0 = paddle.arange(32).reshape([2, 1, 8, 2])
        y0 = overlap_add(x0, hop_length=2, axis=-1)  # [2, 1, 10]

        x1 = paddle.arange(32).reshape([2, 8, 1, 2])
        y1 = overlap_add(x1, hop_length=2, axis=0)   # [10, 1, 2] 
    r   r   r   r   r   r   overlap_addr   r   r   r   r    r!   r#   )r   r   r$   r%   )r(   r)   r*   r   r   r8   paddleZin_dynamic_moder,   r   r	   r   r-   r.   r/   r0   )
r   r   r   r1   r2   r4   r'   r3   r5   r"   r6   r6   r7   r8      s<   5


r8   TreflectFc
              	   C   sb  t | dg dd t| j}
|
dv sJ d|
 |
dkr"| d} |du r,t|d	 }|dks8J d
| d|du r>|}t r]d|  k rN| jd ks]n J d| jd  d| dd|  k rg|kssn J d| d| d|durt|jdkrt||ksJ d| d|j dn	tj|f| jd}||k r|| d }|| | }tj	j
j|||gdd}|r|dv sJ d||d }tj	j
j| d||g|ddd} t| ||dd}|jg dd}t||}|rdnd}t|r|rJ dt| st|dd|d ||	d!}n
t|dd|d |	d"}|jg dd}|
dkr/|d |S )#a  
    Short-time Fourier transform (STFT).

    The STFT computes the discrete Fourier transforms (DFT) of short overlapping
    windows of the input using this formula:
    
    .. math::
        X_t[\omega] = \sum_{n = 0}^{N-1}%
                      \text{window}[n]\ x[t \times H + n]\ %
                      e^{-{2 \pi j \omega n}/{N}}
    
    Where:
    - :math:`t`: The :math:`t`-th input window.
    - :math:`\omega`: Frequency :math:`0 \leq \omega < \text{n\_fft}` for `onesided=False`,
        or :math:`0 \leq \omega < \lfloor \text{n\_fft} / 2 \rfloor + 1` for `onesided=True`. 
    - :math:`N`: Value of `n_fft`.
    - :math:`H`: Value of `hop_length`.  
    
    Args:
        x (Tensor): The input data which is a 1-dimensional or 2-dimensional Tensor with
            shape `[..., seq_length]`. It can be a real-valued or a complex Tensor.
        n_fft (int): The number of input samples to perform Fourier transform.
        hop_length (int, optional): Number of steps to advance between adjacent windows
            and `0 < hop_length`. Default: `None`(treated as equal to `n_fft//4`)
        win_length (int, optional): The size of window. Default: `None`(treated as equal
            to `n_fft`)
        window (Tensor, optional): A 1-dimensional tensor of size `win_length`. It will
            be center padded to length `n_fft` if `win_length < n_fft`. Default: `None`(
            treated as a rectangle window with value equal to 1 of size `win_length`).
        center (bool, optional): Whether to pad `x` to make that the
            :math:`t \times hop\_length` at the center of :math:`t`-th frame. Default: `True`.
        pad_mode (str, optional): Choose padding pattern when `center` is `True`. See
            `paddle.nn.functional.pad` for all padding options. Default: `"reflect"`
        normalized (bool, optional): Control whether to scale the output by `1/sqrt(n_fft)`.
            Default: `False`
        onesided (bool, optional): Control whether to return half of the Fourier transform
            output that satisfies the conjugate symmetry condition when input is a real-valued
            tensor. It can not be `True` if input is a complex tensor. Default: `True`
        name (str, optional): The default value is None. Normally there is no need for user
            to set this property. For more information, please refer to :ref:`api_guide_Name`.
    
    Returns:
        The complex STFT output tensor with shape `[..., n_fft//2 + 1, num_frames]`(
            real-valued input and `onesided` is `True`) or `[..., n_fft, num_frames]`(
            `onesided` is `False`)
    
    Examples:
        .. code-block:: python
    
            import paddle
            from paddle.signal import stft
    
            # real-valued input
            x = paddle.randn([8, 48000], dtype=paddle.float64)
            y1 = stft(x, n_fft=512)  # [8, 257, 376]
            y2 = stft(x, n_fft=512, onesided=False)  # [8, 512, 376]
    
            # complex input
            x = paddle.randn([8, 48000], dtype=paddle.float64) + \
                    paddle.randn([8, 48000], dtype=paddle.float64)*1j  # [8, 48000] complex128
            y1 = stft(x, n_fft=512, center=False, onesided=False)  # [8, 512, 372]
    r   )r   r   	complex64
complex128r   )r      z9x should be a 1D or 2D real tensor, but got rank of x is r   r   N   z"hop_length should be > 0, but got .r   z"n_fft should be in (0, seq_length(z)], but got z"win_length should be in (0, n_fft(z8expected a 1D window tensor of size equal to win_length(z), but got window with shape r+   r"   r=   constantpadmode)rA   r:   z9pad_mode should be "reflect" or "constant", but got "{}".ZNLC)rC   rD   Zdata_format)r   r   r   r   r   r=   r   permorthobackwardzBonesided should be False when input or window is a complex Tensor.T)r   nr   normforwardonesidedr1   r   rJ   r   rK   rL   r1   )r	   lenr+   	unsqueezer*   r
   r9   onesr"   nn
functionalrC   formatZsqueezer   	transposemultiplyr   r   r   squeeze_)r   n_fftr   
win_lengthwindowcenterZpad_mode
normalizedrM   r1   x_rankpad_left	pad_rightZ
pad_lengthZx_framesrK   r4   r6   r6   r7   r      s   H










c                 C   sb  t | dddgd t| j}|dv sJ d||dkr"| d} |d	u r,t|d
 }|d	u r2|}d|  k r<|ksEn J d||d|  k rO|ksXn J d||| jd }| jd }t r|r|||d d ks{J d|d d |n||ksJ d|||d	urt|jdkrt||ksJ d||jn| jtj	tj
fv rtj	ntj}tj|f|d}||k r|| d }|| | }tjjj|||gdd}| jg dd} |rdnd}|	r|rJ dt| d	d|dd	d}n(t|rJ d|du r| d	d	d	d	d	|d d f } t| d	d|dd	d}t||jg dd}t||dd}ttjt||d|dgdjddgd|dd}|d	u rp|ro|d	d	|d |d  f }||d |d   }n|rx|d }nd}|d	d	||| f }||||  }t r|   d k rtd!|| }|dkr|d |S )"ax  
    Inverse short-time Fourier transform (ISTFT).

    Reconstruct time-domain signal from the giving complex input and window tensor when
        nonzero overlap-add (NOLA) condition is met: 

    .. math::
        \sum_{t = -\infty}^{\infty}%
            \text{window}^2[n - t \times H]\ \neq \ 0, \ \text{for } all \ n

    Where:
    - :math:`t`: The :math:`t`-th input window.
    - :math:`N`: Value of `n_fft`.
    - :math:`H`: Value of `hop_length`.

    Result of `istft` expected to be the inverse of `paddle.signal.stft`, but it is
        not guaranteed to reconstruct a exactly realizible time-domain signal from a STFT
        complex tensor which has been modified (via masking or otherwise). Therefore, `istft`
        gives the [Griffin-Lim optimal estimate](https://ieeexplore.ieee.org/document/1164317)
        (optimal in a least-squares sense) for the corresponding signal.

    Args:
        x (Tensor): The input data which is a 2-dimensional or 3-dimensional **complesx**
            Tensor with shape `[..., n_fft, num_frames]`. 
        n_fft (int): The size of Fourier transform.
        hop_length (int, optional): Number of steps to advance between adjacent windows
            from time-domain signal and `0 < hop_length < win_length`. Default: `None`(
            treated as equal to `n_fft//4`)
        win_length (int, optional): The size of window. Default: `None`(treated as equal
            to `n_fft`)
        window (Tensor, optional): A 1-dimensional tensor of size `win_length`. It will
            be center padded to length `n_fft` if `win_length < n_fft`. It should be a
            real-valued tensor if `return_complex` is False. Default: `None`(treated as
            a rectangle window with value equal to 1 of size `win_length`).
        center (bool, optional): It means that whether the time-domain signal has been
            center padded. Default: `True`.
        normalized (bool, optional): Control whether to scale the output by `1/sqrt(n_fft)`.
            Default: `False`
        onesided (bool, optional): It means that whether the input STFT tensor is a half
            of the conjugate symmetry STFT tensor transformed from a real-valued signal
            and `istft` will return a real-valued tensor when it is set to `True`.
            Default: `True`.
        length (int, optional): Specify the length of time-domain signal. Default: `None`(
            treated as the whole length of signal). 
        return_complex (bool, optional): It means that whether the time-domain signal is
            real-valued. If `return_complex` is set to `True`, `onesided` should be set to
            `False` cause the output is complex. 
        name (str, optional): The default value is None. Normally there is no need for user
            to set this property. For more information, please refer to :ref:`api_guide_Name`.

    Returns:
        A tensor of least squares estimation of the reconstructed signal(s) with shape
            `[..., seq_length]`

    Examples:
        .. code-block:: python

            import numpy as np
            import paddle
            from paddle.signal import stft, istft

            paddle.seed(0)

            # STFT
            x = paddle.randn([8, 48000], dtype=paddle.float64)
            y = stft(x, n_fft=512)  # [8, 257, 376]

            # ISTFT
            x_ = istft(y, n_fft=512)  # [8, 48000]

            np.allclose(x, x_)  # True
    r   r;   r<   r   )r=      z>x should be a 2D or 3D complex tensor, but got rank of x is {}r=   r   Nr>   z8hop_length should be in (0, win_length({})], but got {}.z3win_length should be in (0, n_fft({})], but got {}.r   r   zQfft_size should be equal to n_fft // 2 + 1({}) when onesided is True, but got {}.zIfft_size should be equal to n_fft({}) when onesided is False, but got {}.zZexpected a 1D window tensor of size equal to win_length({}), but got window with shape {}.r@   rA   rB   rE   rF   rH   rI   zSonesided should be False when input(output of istft) or window is a complex Tensor.FrN   zGData type of window should not be complex when return_complex is False.)r   r   r   )r   Zrepeat_timesgdy=zAbort istft because Nonzero Overlap Add (NOLA) condition failed. For more information about NOLA constraint please see `scipy.signal.check_NOLA`(https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.check_NOLA.html).)r	   rO   r+   rT   rP   r*   r
   r"   r9   r   r;   r   rQ   rR   rS   rC   rU   r   r   r   rV   r8   Ztileabsminitemr(   rW   )r   rX   r   rY   rZ   r[   r\   rM   lengthZreturn_complexr1   r]   Zn_framesZfft_sizeZwindow_dtyper^   r_   rK   r4   Zwindow_envelopstartr6   r6   r7   r     s   S











"



)r   N)NNNTr:   FTN)	NNNTFTNFN)typingr   r9   Ztensor.attributer   r   Zfftr   r   r   Zfluid.data_feederr	   Zfluid.frameworkr
   Zfluid.layer_helperr   r   r   Zpaddle.fluid.frameworkr   r   __all__r   r8   r   r   r6   r6   r6   r7   <module>   sD   

|X
 !