
    iQ@                     D   d dl Z d dlZd dlZd dlZd dlmZ d dlmZ d dlZ	d dl
Z
d dlmZ d dl
mZ d dlmZmZmZ d dlmZmZ d dlmZ d dlmZmZ erer	d dlZd dlZnd	\  ZZd
ddgiZdZdededefdZede ejB                  e"e#ef   f   fd       Z$d-dZ% G d dejB                        Z& G d dejB                        Z' G d dejB                        Z( G d dejB                        Z) G d dejB                        Z* G d dejB                        Z+ G d  d!ejB                        Z, G d" d#e
j                  jB                        Z-d$e	j\                  d%ed&e"e#ef   de	j\                  fd'Z/d(ed&e"e#ef   de eef   fd)Z0d*ejB                  d+edejb                  fd,Z2y).    N)	lru_cache)Any)Tensor)adaptive_max_pool2drelusoftmax)pack_padded_sequencepad_packed_sequence)rank_zero_info)_LIBROSA_AVAILABLE_REQUESTS_AVAILABLE)NN)'non_intrusive_speech_quality_assessmentlibrosarequestsz~/.torchmetrics/NISQApredsfsreturnc                 f   t         rt        st        d      t               \  }}t	        |t
              r|dk  rt        d|       |j                          | j                  d| j                  d         }t        |j                         j                         ||      }t        t        j                  |      |      \  }}t        j                          5   |||j#                  |j                  d               }ddd       |j                  g | j                  dd d      S # 1 sw Y   ,xY w)u6  `Non-Intrusive Speech Quality Assessment`_ (NISQA v2.0) [1], [2].

    .. hint::
        Usingsing this metric requires you to have ``librosa`` and ``requests`` installed. Install as
        ``pip install librosa requests``.

    Args:
        preds: float tensor with shape ``(...,time)``
        fs: sampling frequency of input

    Returns:
        Float tensor with shape ``(...,5)`` corresponding to overall MOS, noisiness, discontinuity, coloration and
        loudness in that order

    Raises:
        ModuleNotFoundError:
            If ``librosa`` or ``requests`` are not installed
        RuntimeError:
            If the input is too short, causing the number of mel spectrogram windows to be zero
        RuntimeError:
            If the input is too long, causing the number of mel spectrogram windows to exceed the maximum allowed

    Example:
        >>> import torch
        >>> from torchmetrics.functional.audio.nisqa import non_intrusive_speech_quality_assessment
        >>> _ = torch.manual_seed(42)
        >>> preds = torch.randn(16000)
        >>> non_intrusive_speech_quality_assessment(preds, 16000)
        tensor([1.0433, 1.9545, 2.6087, 1.3460, 1.7117])

    References:
        - [1] G. Mittag and S. Möller, "Non-intrusive speech quality assessment for super-wideband speech communication
          networks", in Proc. ICASSP, 2019.
        - [2] G. Mittag, B. Naderi, A. Chehadi and S. Möller, "NISQA: A deep CNN-self-attention model for
          multidimensional speech quality prediction with crowdsourced datasets", in Proc. INTERSPEECH, 2021.

    ziNISQA metric requires that librosa and requests are installed. Install as `pip install librosa requests`.r   z9Argument `fs` expected to be a positive integer, but got N   )r   r   ModuleNotFoundError_load_nisqa_model
isinstanceint
ValueErrorevalreshapeshape_get_librosa_melspeccpunumpy_segment_specstorch
from_numpyno_gradexpand)r   r   modelargsxn_winss         x/Volumes/fast/ai/experiments/voice-extract-mac/.venv/lib/python3.12/site-packages/torchmetrics/functional/audio/nisqa.pyr   r   B   s    L %8!w
 	
 $%KE4b#"'TUWTXYZZ	JJLb%++b/*AQUUW]]_b$7Au//2D9IAv	!V]]1771:./ 

 99+u{{3B'++,, 
s   &D''D0c                  Z   t         j                  j                  t         j                  j                  t        d            } t         j                  j                  |       s
t                t        j                  | dd      }|d   }t        |      }|j                  |d   d       ||fS )zLoad NISQA model and its parameters.

    Returns:
        Tuple ``(model,args)`` where ``model`` is the NISQA model and ``args`` is a dictionary with all its parameters

    	nisqa.tarr    T)map_locationweights_onlyr(   model_state_dict)strict)ospath
expanduserjoin	NISQA_DIRexists_download_weightsr#   load	_NISQADIMload_state_dict)
model_path
checkpointr(   r'   s       r+   r   r   {   s     ##BGGLLK$HIJ77>>*%JUNJfDdOE	*%78F$;    c                     d} t         j                  j                  t              }t        j                  |d       t         j                  j                  |d      }t         j                  j                  |      ryt        d|  d|        t        j                  |       }t        |d      5 }|j                  |j                         ddd       y# 1 sw Y   yxY w)	zDownload NISQA model weights.zNhttps://github.com/gabrielmittag/NISQA/raw/refs/heads/master/weights/nisqa.tarT)exist_okr-   Nzdownloading z to wb)r2   r3   r4   r6   makedirsr5   r7   r   r   getopenwritecontent)url	nisqa_dirsavetomyfilefs        r+   r8   r8      s    
ZC""9-IKK	D)WW\\)[1F	ww~~f\#d6(34\\#F	fd	q	 
		s   /CCc                   F     e Zd Zdeeef   ddf fdZdededefdZ xZ	S )r:   r(   r   Nc                     t         |           t        |      | _        t	        |      | _        t        |      }t        |d      | _        y )Nr   )	super__init__
_Framewisecnn_TimeDependencytime_dependency_Pooling_get_clonespool_layers)selfr(   pool	__class__s      r+   rO   z_NISQADIM.__init__   s?    d#.t4~&tQ/r>   r)   r*   c                     | j                  ||      }| j                  ||      \  }}| j                  D cg c]  } |||       }}t        j                  |d      S c c}w )N   dim)rQ   rS   rV   r#   cat)rW   r)   r*   modouts        r+   forwardz_NISQADIM.forward   s`    HHQ((F3	6)-)9)9:)9#s1f~)9:yy!$$ ;s   A
__name__
__module____qualname__dictstrr   rO   r   ra   __classcell__rY   s   @r+   r:   r:      s8    
0T#s(^ 0 0% % %F %r>   r:   c                   F     e Zd Zdeeef   ddf fdZdededefdZ xZ	S )rP   r(   r   Nc                 B    t         |           t        |      | _        y N)rN   rO   	_AdaptCNNr'   rW   r(   rY   s     r+   rO   z_Framewise.__init__   s    t_
r>   r)   r*   c           	          t        ||dd      }| j                  |j                  j                  d            }|j	                  |      }t        |ddt        |j                                     \  }}|S )NTF)batch_firstenforce_sortedr[   )data        )rp   padding_valuetotal_length)r	   r'   rr   	unsqueeze_replacer
   r   max)rW   r)   r*   x_packed_s        r+   ra   z_Framewise.forward   sl    '6tTYZJJx}}..q121%"1$cX[\b\f\f\hXij1r>   rb   ri   s   @r+   rP   rP      s8    %T#s(^ % %  F r>   rP   c                   B     e Zd Zdeeef   ddf fdZdedefdZ xZ	S )rm   r(   r   Nc                 n   t         |           |d   | _        |d   | _        |d   | _        t        j                  |d         | _        |d   d   dk(  rd	nd
}t        j                  d|d   |d   |      | _	        t        j                  | j                  j                        | _        t        j                  | j                  j                  |d   |d   |      | _        t        j                  | j                  j                        | _        t        j                  | j                  j                  |d   |d   |      | _        t        j                  | j                  j                        | _        t        j                  | j                  j                  |d   |d   |      | _        t        j                  | j"                  j                        | _        t        j                  | j"                  j                  |d   |d   |      | _        t        j                  | j&                  j                        | _        t        j                  | j&                  j                  |d   |d   d   |d   d   fd	      | _        t        j                  | j*                  j                        | _        y )N
cnn_pool_1
cnn_pool_2
cnn_pool_3cnn_dropout)pcnn_kernel_sizer   r[   )r[   r   )r[   r[   cnn_c_out_1)paddingcnn_c_out_2cnn_c_out_3)rN   rO   pool_1pool_2pool_3nn	Dropout2ddropoutConv2dconv1BatchNorm2dout_channelsbn1conv2bn2conv3bn3conv4bn4conv5bn5conv6bn6)rW   r(   cnn_padrY   s      r+   rO   z_AdaptCNN.__init__   s   <(<(<(||d=&9: !23A6!;&YYq$}"5t<M7NX_`
>>$**"9"9:YYtzz66]8KTRcMdnuv
>>$**"9"9:YYtzz66]8KTRcMdnuv
>>$**"9"9:YYtzz66]8KTRcMdnuv
>>$**"9"9:YYtzz66]8KTRcMdnuv
>>$**"9"9:YYJJ###$Q'l);A)>?	

 >>$**"9"9:r>   r)   c                 l   t        | j                  | j                  |                  }t        || j                        }t        | j                  | j                  |                  }t        || j                        }| j                  |      }t        | j                  | j                  |                  }| j                  |      }t        | j                  | j                  |                  }t        || j                        }| j                  |      }t        | j                  | j                  |                  }| j                  |      }t        | j!                  | j#                  |                  }|j%                  d| j"                  j&                  | j                  d   z        S )N)output_sizer   r   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   viewr   )rW   r)   s     r+   ra   z_AdaptCNN.forward   s0   $**Q-()=$**Q-()=LLO$**Q-()LLO$**Q-()=LLO$**Q-()LLO$**Q-()vvb$**11DKKNBCCr>   rb   ri   s   @r+   rm   rm      s4    ;T#s(^ ; ;2D DF Dr>   rm   c                   F     e Zd Zdeeef   ddf fdZdededefdZ xZ	S )rR   r(   r   Nc                 B    t         |           t        |      | _        y rl   )rN   rO   _SelfAttentionr'   rn   s     r+   rO   z_TimeDependency.__init__   s    #D)
r>   r)   r*   c                 &    | j                  ||      S rl   r'   rW   r)   r*   s      r+   ra   z_TimeDependency.forward       zz!V$$r>   rb   ri   s   @r+   rR   rR      s8    *T#s(^ * *% % %F %r>   rR   c                   X     e Zd Zdeeef   ddf fdZd	dZdedede	eef   fdZ
 xZS )
r   r(   r   Nc                    t         |           t        |      }t        j                  |d         | _        t        j                  |d   |d   d   z  |d         | _        t        ||d         | _	        | j                          y )Ntd_sa_d_modelr   r   r   td_sa_num_layers)rN   rO   _SelfAttentionLayerr   	LayerNormnorm1LinearlinearrU   layers_reset_parameters)rW   r(   encoder_layerrY   s      r+   rO   z_SelfAttention.__init__   sy    +D1\\$"78
ii] 3d<6H6K KTRaMbc!-6H1IJ r>   c                     | j                         D ]5  }|j                         dkD  st        j                  j	                  |       7 y )Nr[   )
parametersr]   r   initxavier_uniform_)rW   r   s     r+   r   z _SelfAttention._reset_parameters   s2    "Auuw{''* #r>   srcr*   c                     | j                  |      }|j                  dd      }| j                  |      }| j                  D ]  } |||      \  }} |j                  dd      |fS )Nr[   r   )r   	transposer   r   )rW   r   r*   outputr_   s        r+   ra   z_SelfAttention.forward  sd    kk#q!$F#;;C 0NFF 1%v--r>   r   N)rc   rd   re   rf   rg   r   rO   r   r   tuplera   rh   ri   s   @r+   r   r      sF    !T#s(^ ! !+
.6 .6 .eFFN6K .r>   r   c                   P     e Zd Zdeeef   ddf fdZdededeeef   fdZ	 xZ
S )r   r(   r   Nc                 (   t         |           t        j                  |d   |d   |d         | _        t        j
                  |d   |d         | _        t        j                  |d         | _        t        j
                  |d   |d         | _	        t        j                  |d         | _        t        j                  |d         | _        t        j                  |d         | _        t        j                  |d         | _        t        | _        y )Nr   td_sa_nheadtd_sa_dropouttd_sa_h)rN   rO   r   MultiheadAttention	self_attnr   linear1Dropoutr   linear2r   r   norm2dropout1dropout2r   
activationrn   s     r+   rO   z_SelfAttentionLayer.__init__  s    ..tO/Dd=FY[_`o[pqyyo!6YHzz$"78yyi$2GH\\$"78
\\$"78


4#89

4#89r>   r   r*   c           	         t        j                  |j                  d         d d d f   |d d d f   k  }| j                  ||||       d   }|| j	                  |      z   }| j                  |      }| j                  | j                  | j                  | j                  |                        }|| j                  |      z   }| j                  |      }||fS )Nr   )key_padding_mask)r#   aranger   r   r   r   r   r   r   r   r   r   )rW   r   r*   masksrc2s        r+   ra   z_SelfAttentionLayer.forward  s    ||CIIaL)$'2VAtG_D~~c3te~DQGDMM$''jjo||DLLc9J)KLMDMM$''jjoF{r>   )rc   rd   re   rf   rg   r   rO   r   r   ra   rh   ri   s   @r+   r   r   
  sA    
T#s(^ 
 
6 6 eFFN6K r>   r   c                   F     e Zd Zdeeef   ddf fdZdededefdZ xZ	S )rT   r(   r   Nc                 B    t         |           t        |      | _        y rl   )rN   rO   
_PoolAttFFr'   rn   s     r+   rO   z_Pooling.__init__%  s    %
r>   r)   r*   c                 &    | j                  ||      S rl   r   r   s      r+   ra   z_Pooling.forward)  r   r>   rb   ri   s   @r+   rT   rT   #  s8    &T#s(^ & &% % %F %r>   rT   c                   F     e Zd Zdeeef   ddf fdZdededefdZ xZ	S )r   r(   r   Nc                 ,   t         |           t        j                  |d   |d         | _        t        j                  |d   d      | _        t        j                  |d   d      | _        t        | _        t        j                  |d         | _
        y )Nr   
pool_att_hr[   pool_att_dropout)rN   rO   r   r   r   r   linear3r   r   r   r   rn   s     r+   rO   z_PoolAttFF.__init__/  su    yyo!6\8JKyyl!3Q7yyo!6:zz$'9":;r>   r)   r*   c           	         | j                  | j                  | j                  | j                  |                        }|j	                  dd      }t        j                  |j                  d         d d d f   |d d d f   k  }t        d      ||j                  d       <   t        |d      }t        j                  ||      }|j                  d      }| j                  |      S )N   r[   z-infr\   )r   r   r   r   r   r#   r   r   floatrv   r   bmmsqueezer   )rW   r)   r*   attr   s        r+   ra   z_PoolAttFF.forward7  s    ll4<<Q(HIJmmAq!||CIIaL)$'2VAtG_D"'-T^^Acq!IIc1IIaL||Ar>   rb   ri   s   @r+   r   r   -  s8    <T#s(^ < <  F r>   r   ysrr(   c                    t        ||d   z        }t        ||d   z        }t        j                         5  t        j                  dd       t        j
                  j                  | |d|d   ||dd	d
d|d   d|d   dd      }ddd       t        j                  D cg c]  }t	        j                  |ddd       c}      S # 1 sw Y   CxY wc c}w )a  Compute mel spectrogram from waveform using librosa.

    Args:
        y: waveform with shape ``(batch_size,time)``
        sr: sampling rate
        args: dictionary with all NISQA parameters

    Returns:
        Mel spectrogram with shape ``(batch_size,n_mels,n_frames)``

    ms_hop_lengthms_win_lengthignorez-Empty filters detected in mel frequency basis)messageNms_n_ffthannTreflectg      ?	ms_n_melsrs   ms_fmaxFslaney)r   r   Sn_fft
hop_length
win_lengthwindowcenterpad_modepowern_melsfminfmaxhtknormg-C6?g      T@)refamintop_db)
r   warningscatch_warningsfilterwarningsr   featuremelspectrogramnpstackamplitude_to_db)r   r   r(   r   r   melspecms          r+   r   r   B  s     R$//0JR$//0J		 	 	" 	2ab//00z"!!$i 1 
	 
#0 88ZabZaUVW,,QCd4PZabcc1 
#	"0 cs   AC! CCr)   c                    |d   }|d   }|d   }| j                   d   |dz
  z
  }|dk  rt        d      t        j                  |      }t        j                  |      }|j	                  d      |j	                  d      z   }| j                  dd      dd|ddf   j                  d	d      } | dddd|f   } t        j                  ||z        }||k  rt        d
      t        j                  | j                   d   || j                   d   | j                   d	   f      }	| |	ddd|f<   |	t        j                  |      fS )a   Segment mel spectrogram into overlapping windows.

    Args:
        x: mel spectrogram with shape ``(batch_size,n_mels,n_frames)``
        args: dictionary with all NISQA parameters

    Returns:
        Tuple ``(x_padded,n_wins)```, where ``x_padded`` is the segmented mel spectrogram with shape
        ``(batch_size,max_length,n_mels,seg_length)`` where the second dimension is the number of windows and was
        padded to ``max_length``, and ``n_wins`` is the number of windows and is 0-dimensional

    ms_seg_lengthms_seg_hop_lengthms_max_segmentsr   r[   zInput signal is too short.r   N   zFMaximum number of mel spectrogram windows exceeded. Use shorter audio.)
r   RuntimeErrorr#   r   rv   r   mathceilzerostensor)
r)   r(   
seg_lengthseg_hop
max_lengthr*   idx1idx2idx3x_paddeds
             r+   r"   r"   k  s:    o&J&'G'(JWWQZ:>*Fz788<<
#D<<D>>!t~~a00D	Aq!T1*%//15A	!YwY,AYYv'(FFcdd{{AGGAJ
AGGAJ
KLHHQZU\\&)))r>   modulenc                     t        j                  t        |      D cg c]  }t        j                  |        c}      S c c}w )z Create ``n`` copies of a module.)r   
ModuleListrangecopydeepcopy)r  r  is      r+   rU   rU     s0    ==qBA$--/BCCBs   A r   )3r  r  r2   r   	functoolsr   typingr   r!   r  r#   torch.nnr   r   torch.nn.functionalr   r   r   torch.nn.utils.rnnr	   r
   torchmetrics.utilitiesr   torchmetrics.utilities.importsr   r   r   r   __doctest_requires__r6   r   r   r   Modulerf   rg   r   r8   r:   rP   rm   rR   r   r   rT   r   ndarrayr   r"   r  rU    r>   r+   <module>r*     s  L   	        B B H 1 R-"GXDyR\F]^ #	6-6 6-s 6-v 6-r 5DcN!:;  " %		 %& )D		 )DX%bii %.RYY .0")) 2%ryy % *&dBJJ &dC &dtCH~ &d"** &dR*f *DcN *uVV^7L *@D		 Dc Dbmm Dr>   