o
    wiu                     @   s  d dl Z d dlZd dlmZmZ d dlmZ d dlmZm	Z	 d dl
Z
d dlmZ d dlmZmZ d dlmZmZ d dlmZmZ d d	lmZmZmZ d d
lmZmZmZmZmZm Z  d dl!m"Z" d dl#m$Z$ d dl%m&Z&m'Z' zd dl(Z(d dl)Z(d dl*Z(e+e(j,Z-e+dZ.dZ/W n e0y   dZ/Y nw g dZ1G dd deeZ2G dd de2eZ3G dd de2Z4G dd deZ5G dd deZ6G dd deZ7eG dd dZ8eG d d! d!Z9eG d"d# d#Z:eG d$d% d%Z;eG d&d' d'Z<dS )(    N)ABCabstractmethod)	dataclass)AnyOptional)version)SpecAugmentNumbaspec_augment_launch_heuristics)FilterbankFeaturesFilterbankFeaturesTA)SpecAugment
SpecCutout)
ExportableNeuralModule	typecheck)AudioSignalLengthsTypeMelSpectrogramTypeMFCCSpectrogramType
NeuralTypeSpectrogramType)numba_utils)__NUMBA_MINIMUM_VERSION__)logginglogging_modez0.5TF)!AudioToMelSpectrogramPreprocessorAudioToMFCCPreprocessorSpectrogramAugmentationMaskedPatchAugmentation CropOrPadSpectrogramAugmentationc                       sB   e Zd ZdZ fddZe e dd Ze	dd Z
  ZS )AudioPreprocessorzy
    An interface for Neural Modules that performs audio pre-processing,
    transforming the wav files to features.
    c                    sV   t    || _|| _tjtjtjtjtj	tj	d| _
| jdtjdtjddd d S )N)hannhammingblackmanbartlettonesNdtype_sentinel_tensor dtypeF)
persistent)super__init__
win_length
hop_lengthtorchhann_windowhamming_windowblackman_windowbartlett_windowr%   torch_windowsregister_buffertensorfloat32)selfr-   r.   	__class__r'   m/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/nemo/collections/asr/modules/audio_preprocessing.pyr,   C   s   
 zAudioPreprocessor.__init__c                 C   sT   |j tjkrtjd|j  dtjd | |tj|\}}|| j	j }||fS )Nz4AudioPreprocessor received an input signal of dtype a?  , rather than torch.float32. In sweeps across multiple datasets, we have found that the preprocessor is not robust to low precision  mathematics. As such, it runs in float32. Your input will be cast to float32, but this is not necessarily enough to recovery full accuracy. For example, simply casting input_signal from torch.float32 to torch.bfloat16, then back to torch.float32 before running AudioPreprocessor causes drops in absolute WER of up to 0.1%. torch.bfloat16 simply does not have enough mantissa bits to represent enough values in the range [-1.0,+1.0] correctly.)mode)
r)   r/   r7   r   warningr   ONCEget_featurestor&   )r8   input_signallengthprocessed_signalprocessed_lengthr'   r'   r;   forward]   s   zAudioPreprocessor.forwardc                 C      d S Nr'   r8   rA   rB   r'   r'   r;   r?   i   s   zAudioPreprocessor.get_features)__name__
__module____qualname____doc__r,   r   r/   no_gradrE   r   r?   __classcell__r'   r'   r9   r;   r    =   s    
r    c                       s   e Zd ZdZdefddZedefddZedd	 Z	ed
d Z
																												d/d ef fd!d"Zd0d&ed'ed(efd)d*Zd+d, Zed-d. Z  ZS )1r   a  Featurizer module that converts wavs to mel spectrograms.

    Args:
        sample_rate (int): Sample rate of the input audio data.
            Defaults to 16000
        window_size (float): Size of window for fft in seconds
            Defaults to 0.02
        window_stride (float): Stride of window for fft in seconds
            Defaults to 0.01
        n_window_size (int): Size of window for fft in samples
            Defaults to None. Use one of window_size or n_window_size.
        n_window_stride (int): Stride of window for fft in samples
            Defaults to None. Use one of window_stride or n_window_stride.
        window (str): Windowing function for fft. can be one of ['hann',
            'hamming', 'blackman', 'bartlett']
            Defaults to "hann"
        normalize (str): Can be one of ['per_feature', 'all_features']; all
            other options disable feature normalization. 'all_features'
            normalizes the entire spectrogram to be mean 0 with std 1.
            'pre_features' normalizes per channel / freq instead.
            Defaults to "per_feature"
        n_fft (int): Length of FT window. If None, it uses the smallest power
            of 2 that is larger than n_window_size.
            Defaults to None
        preemph (float): Amount of pre emphasis to add to audio. Can be
            disabled by passing None.
            Defaults to 0.97
        features (int): Number of mel spectrogram freq bins to output.
            Defaults to 64
        lowfreq (int): Lower bound on mel basis in Hz.
            Defaults to 0
        highfreq  (int): Lower bound on mel basis in Hz.
            Defaults to None
        log (bool): Log features.
            Defaults to True
        log_zero_guard_type(str): Need to avoid taking the log of zero. There
            are two options: "add" or "clamp".
            Defaults to "add".
        log_zero_guard_value(float, or str): Add or clamp requires the number
            to add with or clamp to. log_zero_guard_value can either be a float
            or "tiny" or "eps". torch.finfo is used if "tiny" or "eps" is
            passed.
            Defaults to 2**-24.
        dither (float): Amount of white-noise dithering.
            Defaults to 1e-5
        pad_to (int): Ensures that the output size of the time dimension is
            a multiple of pad_to.
            Defaults to 16
        frame_splicing (int): Defaults to 1
        exact_pad (bool): If True, sets stft center to False and adds padding, such that num_frames = audio_length
            // hop_length. Defaults to False.
        pad_value (float): The value that shorter mels are padded with.
            Defaults to 0
        mag_power (float): The power that the linear spectrogram is raised to
            prior to multiplication with mel basis.
            Defaults to 2 for a power spec
        rng : Random number generator
        nb_augmentation_prob (float) : Probability with which narrowband augmentation would be applied to
            samples in the batch.
            Defaults to 0.0
        nb_max_freq (int) : Frequency above which all frequencies will be masked for narrowband augmentation.
            Defaults to 4000
        use_torchaudio: Whether to use the `torchaudio` implementation.
        mel_norm: Normalization used for mel filterbank weights.
            Defaults to 'slaney' (area normalization)
        stft_exact_pad: Deprecated argument, kept for compatibility with older checkpoints.
        stft_conv: Deprecated argument, kept for compatibility with older checkpoints.
    	save_pathc                 C   rF   rG   r'   r8   rO   r'   r'   r;   save_to      z)AudioToMelSpectrogramPreprocessor.save_torestore_pathc                 C   rF   rG   r'   clsrS   r'   r'   r;   restore_from      z.AudioToMelSpectrogramPreprocessor.restore_fromc                 C   $   t dt| jdt tdt dS z*Returns definitions of module input ports.)BT)freqrZ   rA   rB   r   r   _sample_ratetupler   r8   r'   r'   r;   input_types   s
   
z-AudioToMelSpectrogramPreprocessor.input_typesc                 C      t dt t tdt dS )a  Returns definitions of module output ports.

        processed_signal:
            0: AxisType(BatchTag)
            1: AxisType(MelSpectrogramSignalTag)
            2: AxisType(ProcessedTimeTag)
        processed_length:
            0: AxisType(BatchTag)
        rZ   Dr[   rZ   rC   rD   )r   r   r`   r   ra   r'   r'   r;   output_types   s   
z.AudioToMelSpectrogramPreprocessor.output_types>  {Gz?{Gz?Nr!   per_feature
ףp=
?@   r   Tadd      p>h㈵>      F       @          slaneyuse_torchaudioc                    s  || _ |r|rt|  d|r|rt|  d|r"t|| j  }|r+t|| j  }t || |s7t}nt}|di d| j d|d|d|d|d|d	|	d
|
d|d|d|d|d|d|d|d|d|d|d|d|d|d|d|d|d|| _d S )NK received both window_size and n_window_size. Only one should be specified.O received both window_stride and n_window_stride. Only one should be specified.sample_raten_window_sizen_window_stridewindow	normalizen_fftpreemphnfiltlowfreqhighfreqloglog_zero_guard_typelog_zero_guard_valueditherpad_toframe_splicing	exact_pad	pad_value	mag_powerrngnb_augmentation_probnb_max_freqmel_normstft_exact_pad	stft_convr'   )r_   
ValueErrorintr+   r,   r
   r   
featurizer)r8   rz   window_sizewindow_strider{   r|   r}   r~   r   r   featuresr   r   r   r   r   r   r   r   r   r   r   r   r   r   rw   r   r   r   featurizer_classr9   r'   r;   r,      s   	

z*AudioToMelSpectrogramPreprocessor.__init__    }     	max_batchmax_dim
min_lengthc                 C   s>   | j j}tj||g|d}tj|||g|d}||d< ||fS )N)sizedevice)lowhighr   r   r   )filter_banksr   r/   randnrandint)r8   r   r   r   devsignalslengthsr'   r'   r;   input_example#  s
   z/AudioToMelSpectrogramPreprocessor.input_examplec                 C   s   |  ||S rG   )r   rH   r'   r'   r;   r?   +  s   z.AudioToMelSpectrogramPreprocessor.get_featuresc                 C   s   | j jS rG   )r   r   ra   r'   r'   r;   r   .  s   z.AudioToMelSpectrogramPreprocessor.filter_banks)rh   ri   rj   NNr!   rk   Nrl   rm   r   NTrn   ro   rp   rq   rr   Fr   rs   Nrt   ru   Frv   FF)r   r   r   )rI   rJ   rK   rL   strrQ   classmethodrV   propertyrb   rg   boolr,   r   r   r?   r   rN   r'   r'   r9   r;   r   o   sX    E
	
Mr   c                       s~   e Zd ZdZedd Zedd ZdefddZe	d	efd
dZ
														d fdd	Zdd Z  ZS )r   a!  Preprocessor that converts wavs to MFCCs.
    Uses torchaudio.transforms.MFCC.

    Args:
        sample_rate: The sample rate of the audio.
            Defaults to 16000.
        window_size: Size of window for fft in seconds. Used to calculate the
            win_length arg for mel spectrogram.
            Defaults to 0.02
        window_stride: Stride of window for fft in seconds. Used to caculate
            the hop_length arg for mel spect.
            Defaults to 0.01
        n_window_size: Size of window for fft in samples
            Defaults to None. Use one of window_size or n_window_size.
        n_window_stride: Stride of window for fft in samples
            Defaults to None. Use one of window_stride or n_window_stride.
        window: Windowing function for fft. can be one of ['hann',
            'hamming', 'blackman', 'bartlett', 'none', 'null'].
            Defaults to 'hann'
        n_fft: Length of FT window. If None, it uses the smallest power of 2
            that is larger than n_window_size.
            Defaults to None
        lowfreq (int): Lower bound on mel basis in Hz.
            Defaults to 0
        highfreq  (int): Lower bound on mel basis in Hz.
            Defaults to None
        n_mels: Number of mel filterbanks.
            Defaults to 64
        n_mfcc: Number of coefficients to retain
            Defaults to 64
        dct_type: Type of discrete cosine transform to use
        norm: Type of norm to use
        log: Whether to use log-mel spectrograms instead of db-scaled.
            Defaults to True.
    c                 C   rX   rY   r^   ra   r'   r'   r;   rb   X  s   z#AudioToMFCCPreprocessor.input_typesc                 C   rc   +Returns definitions of module output ports.rd   rZ   rf   )r   r   r`   r   ra   r'   r'   r;   rg   `     
z$AudioToMFCCPreprocessor.output_typesrO   c                 C   rF   rG   r'   rP   r'   r'   r;   rQ   h  rR   zAudioToMFCCPreprocessor.save_torS   c                 C   rF   rG   r'   rT   r'   r'   r;   rV   k  rW   z$AudioToMFCCPreprocessor.restore_fromrh   ri   rj   Nr!   rt   rm      orthoTc                    s  || _ tstd td|r|rt|  d|r$|r$t|  d|r-t|| j  }|r6t|| j  }t || i }||d< |	|d< |
|d< |pVdt	
t	| |d	< ||d
< ||d< | j|d }|d u rttd| d||d< tjj| j |||||d| _d S )Nz:Could not import torchaudio. Some features might not work.ztorchaudio is not installed but is necessary for AudioToMFCCPreprocessor. We recommend you try building it from source for the PyTorch version you have.rx   ry   f_minf_maxn_melsr   r   r-   r.   z/Window argument for AudioProcessor is invalid: z,.For no window function, use 'ones' or None.	window_fn)rz   n_mfccdct_typenormlog_mels	melkwargs)r_   HAVE_TORCHAUDIOr   errorModuleNotFoundErrorr   r   r+   r,   mathceillog2r4   get
torchaudio
transformsMFCCr   )r8   rz   r   r   r{   r|   r}   r   r   r   r   r   r   r   r   
mel_kwargsr   r9   r'   r;   r,   o  sL   

z AudioToMFCCPreprocessor.__init__c                 C   s4   |  |}t|tj| j jtjd}||fS )Nr(   )r   r/   r   r@   r7   r.   long)r8   rA   rB   r   seq_lenr'   r'   r;   r?     s   
"z$AudioToMFCCPreprocessor.get_features)rh   ri   rj   NNr!   Nrt   Nrm   rm   r   r   T)rI   rJ   rK   rL   r   rb   rg   r   rQ   r   rV   r,   r?   rN   r'   r'   r9   r;   r   3  s2    $

Fr   c                       sh   e Zd ZdZedd Zedd Z									
			ddedef fddZe	 dd Z
  ZS )r   a  
    Performs time and freq cuts in one of two ways.
    SpecAugment zeroes out vertical and horizontal sections as described in
    SpecAugment (https://arxiv.org/abs/1904.08779). Arguments for use with
    SpecAugment are `freq_masks`, `time_masks`, `freq_width`, and `time_width`.
    SpecCutout zeroes out rectangulars as described in Cutout
    (https://arxiv.org/abs/1708.04552). Arguments for use with Cutout are
    `rect_masks`, `rect_freq`, and `rect_time`.

    Args:
        freq_masks (int): how many frequency segments should be cut.
            Defaults to 0.
        time_masks (int): how many time segments should be cut
            Defaults to 0.
        freq_width (int): maximum number of frequencies to be cut in one
            segment.
            Defaults to 10.
        time_width (int): maximum number of time steps to be cut in one
            segment
            Defaults to 10.
        rect_masks (int): how many rectangular masks should be cut
            Defaults to 0.
        rect_freq (int): maximum size of cut rectangles along the frequency
            dimension
            Defaults to 5.
        rect_time (int): maximum size of cut rectangles along the time
            dimension
            Defaults to 25.
        use_numba_spec_augment: use numba code for Spectrogram augmentation
        use_vectorized_spec_augment: use vectorized code for Spectrogram augmentation

    c                 C   rc   z)Returns definitions of module input typesrd   rZ   
input_specrB   r   r   r`   r   ra   r'   r'   r;   rb     r   z#SpectrogramAugmentation.input_typesc                 C      dt dt iS z*Returns definitions of module output typesaugmented_specrd   r   r   ra   r'   r'   r;   rg        z$SpectrogramAugmentation.output_typesr   
         Nrt   TFuse_vectorized_spec_augmentuse_numba_spec_augmentc              	      s   t    |dkrt||||d| _ndd | _|| dkr+t||||||	|
d| _ndd | _|rIttrIt	
d t||||||	d| _d S d | _d S )	Nr   )
rect_masks	rect_time	rect_freqr   c                 S      | S rG   r'   r   r'   r'   r;   <lambda>      z2SpectrogramAugmentation.__init__.<locals>.<lambda>)
freq_masks
time_masks
freq_width
time_widthr   
mask_valueuse_vectorized_codec                 S   r   rG   r'   r   r'   r'   r;   r     r   z+Numba CUDA SpecAugment kernel is being used)r   r   r   r   r   r   )r+   r,   r   spec_cutoutr   spec_augmentr   numba_cuda_is_supportedr   r   infor   spec_augment_numba)r8   r   r   r   r   r   r   r   r   r   r   r   r9   r'   r;   r,     s>   







	z SpectrogramAugmentation.__init__c                 C   sD   | j |d}| jd urt||r| j||d}|S | j||d}|S )Nr   r   )r   r   r	   r   )r8   r   rB   r   r'   r'   r;   rE     s   zSpectrogramAugmentation.forward)r   r   r   r   r   r   r   Nrt   TF)rI   rJ   rK   rL   r   rb   rg   r   r,   r   rE   rN   r'   r'   r9   r;   r     s0    !

5r   c                	       sb   e Zd ZdZedd Zedd Z				dd	ed
ededef fddZ	e
 dd Z  ZS )r   aO  
    Zeroes out fixed size time patches of the spectrogram.
    All samples in batch are guaranteed to have the same amount of masked time steps.
    Optionally also performs frequency masking in the same way as SpecAugment.
    Args:
        patch_size (int): up to how many time steps does one patch consist of.
            Defaults to 48.
        mask_patches (float): how many patches should be masked in each sample.
            if >= 1., interpreted as number of patches (after converting to int)
            if <1.,   interpreted as fraction of total tokens to be masked (number of patches is rounded up)
            Defaults to 10.
        freq_masks (int): how many frequency segments should be cut.
            Defaults to 0.
        freq_width (int): maximum number of frequencies to be cut in a segment.
            Defaults to 0.
    c                 C   rc   r   r   ra   r'   r'   r;   rb   >  r   z#MaskedPatchAugmentation.input_typesc                 C   r   r   r   ra   r'   r'   r;   rg   F  r   z$MaskedPatchAugmentation.output_types0         $@r   
patch_sizemask_patchesr   r   c                    sj   t    || _|dkrt|| _n|dkr|| _d | _ntd|dkr0t|d|dd| _d S d | _d S )Nrr   r   zmask_patches cannot be negative)r   r   r   r   )	r+   r,   r   r   r   _mask_fractionr   r   r   )r8   r   r   r   r   r9   r'   r;   r,   K  s    

z MaskedPatchAugmentation.__init__c              	   C   s   |}t |}| jd u r"t|| j }|| j t|| j dk }n| j}|| j| k r1|| j }t|jd D ]+}|| }t|| j }	t	|	|}
|
D ]}d||d d || j |d | j f< qMq8| j
d urp| j
||d}|S )Nr   rt   rr   r   )r/   minr   r   r   r   rangeshaperandomsampler   )r8   r   rB   r   min_lenlen_fractionr   idxcur_lenpatchesmasked_patchesmpr'   r'   r;   rE   f  s$   


(
zMaskedPatchAugmentation.forward)r   r   r   r   )rI   rJ   rK   rL   r   rb   rg   r   floatr,   r   rE   rN   r'   r'   r9   r;   r   ,  s*    

r   c                       sn   e Zd ZdZ fddZe e dd Ze	dd Z
e	dd	 Zd
efddZedefddZ  ZS )r   z
    Pad or Crop the incoming Spectrogram to a certain shape.

    Args:
        audio_length (int): the final number of timesteps that is required.
            The signal will be either padded or cropped temporally to this
            size.
    c                    s*   t t|   || _| jdk rtdd S )Nr   zaudio_length must be non-negative. If using a dataclass with OmegaConf, please call OmegaConf.to_object(cfg) to call appropriate __post_init__ methods.)r+   r   r,   audio_lengthr   )r8   r   r9   r'   r;   r,     s   
z)CropOrPadSpectrogramAugmentation.__init__c              	   C   s   |}|j d }| j}|j d }||krHg }tjd|| d |gd}t|D ]\}	}|||	|	d d d ||| f  q&tj|dd}~n%|| d }
|| d }|| d dkr`|d7 }tjjj	||
|gddd}|d | }||fS )	Nr   rr   )r   r   r   )dimr   constant)r<   value)
r   r   r/   r   	enumerateappendcatnn
functionalpad)r8   rA   rB   image
num_imagesr   	image_lencutout_imagesoffsetr   pad_left	pad_rightr'   r'   r;   rE     s$   

*z(CropOrPadSpectrogramAugmentation.forwardc                 C   rc   )r   rd   rZ   r]   r   ra   r'   r'   r;   rb     r   z,CropOrPadSpectrogramAugmentation.input_typesc                 C   rc   r   r   ra   r'   r'   r;   rg     r   z-CropOrPadSpectrogramAugmentation.output_typesrO   c                 C   rF   rG   r'   rP   r'   r'   r;   rQ     rR   z(CropOrPadSpectrogramAugmentation.save_torS   c                 C   rF   rG   r'   rT   r'   r'   r;   rV     rW   z-CropOrPadSpectrogramAugmentation.restore_from)rI   rJ   rK   rL   r,   r   r/   rM   rE   r   rb   rg   r   rQ   r   rV   rN   r'   r'   r9   r;   r     s    	
 

r   c                   @   s~  e Zd ZU dZeed< dZeed< dZe	ed< dZ
e	ed< d	Zee ed
< d	Zee ed< dZeed< dZeed< d	Zee ed< dZe	ed< dZeed< dZeed< d	Zee ed< dZeed< dZeed< dZe	ed< dZe	ed< d Zeed!< d"Zeed#< d$Zeed%< dZeed&< d'Ze	ed(< d	Zee ed)< d*Z e	ed+< d,Z!eed-< d$Z"eed.< d/Z#eed0< d$Z$eed1< d$Z%eed2< d	S )3'AudioToMelSpectrogramPreprocessorConfigz>nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor_target_rh   rz   ri   r   rj   r   Nr{   r|   r!   r}   rk   r~   r   rl   r   rm   r   r   r   r   Tr   rn   r   ro   r   rp   r   rq   r   rr   r   Fr   r   rs   r   r   rt   r   ru   r   rw   rv   r   r   r   )&rI   rJ   rK   r  r   __annotations__rz   r   r   r   r   r{   r   r|   r}   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rw   r   r   r   r'   r'   r'   r;   r    s<   
 r  c                   @   s   e Zd ZU dZeed< dZeed< dZe	ed< dZ
e	ed< d	Zee ed
< d	Zee ed< dZeed< d	Zee ed< dZee	 ed< d	Zee	 ed< dZeed< dZeed< dZeed< dZeed< dZeed< d	S )AudioToMFCCPreprocessorConfigz4nemo.collections.asr.modules.AudioToMFCCPreprocessorr  rh   rz   ri   r   rj   r   Nr{   r|   r!   r}   r   rt   r   r   rm   r   r   r   r   r   r   Tr   )rI   rJ   rK   r  r   r  rz   r   r   r   r   r{   r   r|   r}   r   r   r   r   r   r   r   r   r   r'   r'   r'   r;   r    s    
 r  c                   @   s   e Zd ZU dZeed< dZeed< dZeed< dZ	eed< dZ
ee ed< dZeed< dZeed	< dZeed
< dZeed< dZee ed< dZeed< dZeed< dS )SpectrogramAugmentationConfigz4nemo.collections.asr.modules.SpectrogramAugmentationr  r   r   r   r   r   r   r   r   r   Nr   Fr   Tr   )rI   rJ   rK   r  r   r  r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r'   r'   r'   r;   r    s   
 r  c                   @   s"   e Zd ZU eed< dZeed< dS )&CropOrPadSpectrogramAugmentationConfigr   z=nemo.collections.asr.modules.CropOrPadSpectrogramAugmentationr  N)rI   rJ   rK   r   r  r  r   r'   r'   r'   r;   r    s   
 r  c                   @   sJ   e Zd ZU dZeed< dZeed< dZeed< dZ	eed< dZ
eed	< d
S )MaskedPatchAugmentationConfigr   r   r   r   r   r   r   z4nemo.collections.asr.modules.MaskedPatchAugmentationr  N)rI   rJ   rK   r   r   r  r   r   r   r   r  r   r'   r'   r'   r;   r    s   
 r  )=r   r   abcr   r   dataclassesr   typingr   r   r/   	packagingr   -nemo.collections.asr.parts.numba.spec_augmentr   r	   1nemo.collections.asr.parts.preprocessing.featuresr
   r   4nemo.collections.asr.parts.submodules.spectr_augmentr   r   nemo.core.classesr   r   r   nemo.core.neural_typesr   r   r   r   r   r   nemo.core.utilsr   nemo.core.utils.numba_utilsr   
nemo.utilsr   r   r   torchaudio.functionaltorchaudio.transformsparse__version__TORCHAUDIO_VERSIONTORCHAUDIO_VERSION_MINr   r   __all__r    r   r   r   r   r   r  r  r  r  r  r'   r'   r'   r;   <module>   sX    
	2 E 	qXN 