o
    2wi%                     @   s   d Z ddlZddlmZ ddlZddlmZ ddlm	Z	 ddl
mZ G dd	 d	ejjZ		ddejdededededee defddZdd ZdddZdddZdS )a  
Differentiable, Pytorch based resampling.
Implementation of Julius O. Smith algorithm for resampling.
See https://ccrma.stanford.edu/~jos/resample/ for details.
This implementation is specially optimized for when new_sr / old_sr is a fraction
with a small numerator and denominator when removing the gcd (e.g. new_sr = 700, old_sr = 500).

Very similar to [bmcfee/resampy](https://github.com/bmcfee/resampy) except this implementation
is optimized for the case mentioned before, while resampy is slower but more general.

    N)Optional)
functional   )sincsimple_reprc                	       sb   e Zd ZdZddedededef fdd	Zd
d Zddej	de
e defddZdd Z  ZS )ResampleFracz?
    Resampling from the sample rate `old_sr` to `new_sr`.
       =
ףp=?old_srnew_srzerosrolloffc                    s^   t    t|trt|tstdt||}|| | _|| | _|| _	|| _
|   dS )a  
        Args:
            old_sr (int): sample rate of the input signal x.
            new_sr (int): sample rate of the output.
            zeros (int): number of zero crossing to keep in the sinc filter.
            rolloff (float): use a lowpass filter that is `rolloff * new_sr / 2`,
                to ensure sufficient margin due to the imperfection of the FIR filter used.
                Lowering this value will reduce anti-aliasing, but will reduce some of the
                highest frequencies.

        Shape:

            - Input: `[*, T]`
            - Output: `[*, T']` with `T' = int(new_sr * T / old_sr)


        .. caution::
            After dividing `old_sr` and `new_sr` by their GCD, both should be small
            for this implementation to be fast.

        >>> import torch
        >>> resample = ResampleFrac(4, 5)
        >>> x = torch.randn(1000)
        >>> print(len(resample(x)))
        1250
        z$old_sr and new_sr should be integersN)super__init__
isinstanceint
ValueErrormathgcdr   r   r   r   _init_kernels)selfr   r   r   r   r   	__class__ L/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/julius/resample.pyr      s   


zResampleFrac.__init__c                 C   s  | j | jkrd S g }t| j| j }|| j9 }t| j| j  | | _t	| j | j| j  
 }t| jD ];}| | j || j   | }|| j | j}|tj9 }t|| j d d }t|| }||  || q5| dt|| jdd d S )N   kernelr   )r   r   minr   r   ceilr   _widthtorcharangefloatrangeclamp_picosr   div_sumappendregister_bufferstackview)r   kernelssridxitwindowr   r   r   r   r   C   s    

"zResampleFrac._init_kernelsNFxoutput_lengthfullc                 C   s  | j | jkr|S |j}|jd }|d|}tj|dddf | j| j| j  fdd}tj|| j| j d}|	ddt
|dd dg }t| j| | j  }t| }	t| }
|du rk|rh|	n|
}n|dk ss||	krztd	|	 t|}|rtd
|dd|f S )a  
        Resample x.
        Args:
            x (Tensor): signal to resample, time should be the last dimension
            output_length (None or int): This can be set to the desired output length
                (last dimension). Allowed values are between 0 and
                ceil(length * new_sr / old_sr). When None (default) is specified, the
                floored output length will be used. In order to select the largest possible
                size, use the `full` argument.
            full (bool): return the longest possible output from the input. This can be useful
                if you chain resampling operations, and want to give the `output_length` only
                for the last one, while passing `full=True` to all the other ones.
        r   N	replicate)mode)strider   r   r   z$output_length must be between 0 and z0You cannot pass both full=True and output_length.)r   r   shapereshapeFpadr!   conv1dr   	transposelistr"   	as_tensorr    longfloorr   tensor)r   r5   r6   r7   r;   lengthysyfloat_output_lengthmax_output_lengthdefault_output_lengthapplied_output_lengthr   r   r   forwardr   s&   
*$
zResampleFrac.forwardc                 C   s   t | S )Nr   )r   r   r   r   __repr__   s   zResampleFrac.__repr__)r	   r
   )NF)__name__
__module____qualname____doc__r   r$   r   r   r"   Tensorr   boolrM   rN   __classcell__r   r   r   r   r      s     &/%r   r	   r
   Fr5   r   r   r   r   r6   r7   c                 C   s   t ||||| | ||S )aR  
    Functional version of `ResampleFrac`, refer to its documentation for more information.

    ..warning::
        If you call repeatidly this functions with the same sample rates, then the
        resampling kernel will be recomputed everytime. For best performance, you should use
        and cache an instance of `ResampleFrac`.
    )r   to)r5   r   r   r   r   r6   r7   r   r   r   resample_frac   s   rW   c                 C   sd   t jd|  d dd}|dd d }t |  d | d d|  }|tj9 }t|| ddd}|S )N   r   F)periodicr         ?r   )r"   hann_windowlinspacer   r'   r   r.   )r   winwinoddr3   r   r   r   r   _kernel_upsample2_downsample2   s   
r_   c                 C   sv   | j ^ }}t|| }tj| dd|||ddddf jg ||R  }tj| |gdd}|jg |dR  S )a  
    Upsample x by a factor of two. The output will be exactly twice as long as the input.
    Args:
        x (Tensor): signal to upsample, time should be the last dimension
        zeros (int): number of zero crossing to keep in the sinc filter.

    This function is kept only for reference, you should use the more generic `resample_frac`
    one. This function does not perform anti-aliasing filtering.
    r   r   padding.N)dim)r;   r_   rV   r=   r?   r.   r"   r-   )r5   r   othertimer   outrH   r   r   r   
_upsample2   s
   
6rf   c                 C   s   | j d d dkrt| d} | ddddf }| ddddf }|j ^ }}t|| }|tj|dd|||ddddf jg ||R   }|jg |dR  d	S )
a  
    Downsample x by a factor of two. The output length is half of the input, ceiled.
    Args:
        x (Tensor): signal to downsample, time should be the last dimension
        zeros (int): number of zero crossing to keep in the sinc filter.

    This function is kept only for reference, you should use the more generic `resample_frac`
    one. This function does not perform anti-aliasing filtering.
    r   r   r   )r   r   .Nr   r`   rZ   )r;   r=   r>   r_   rV   r?   r.   mul)r5   r   xevenxoddrc   rd   r   re   r   r   r   _downsample2   s   
*
rj   )r	   r
   NF)r	   )rR   r   typingr   r"   torch.nnr   r=   corer   utilsr   nnModuler   rS   r   r$   rT   rW   r_   rf   rj   r   r   r   r   <module>   s.    

