
    i'                    <   d Z ddlmZ ddlmZ ddZddZej                  dd       Z	ddZ
ej                  dd       Zej                  dd	       Zej                  	 	 	 	 	 	 	 	 	 	 dd
       Z	 	 	 d	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZy)z
 Pure MLX implementation of Wiener filtering for multichannel audio separation.
 Optimized to use native mx.complex64 types and JIT compilation.
    )annotationsNc                z    | j                   d   dk7  rt        d      t        j                  | d   | d   dz        S )z6Convert (..., 2) real/imag tensor to native complex64.   z3Last dimension must be 2 for conversion to complex.).r   ).                 ?)shape
ValueErrormxaddxs    j/Volumes/fast/ai/experiments/voice-extract-mac/.venv/lib/python3.12/site-packages/demucs_mlx/wiener_mlx.py_to_complexr   
   s;    wwr{aNOO66!F)QvY^,,    c                \    t        j                  | j                  | j                  gd      S )z6Convert native complex64 tensor to (..., 2) real/imag.r   axis)r   stackrealimagr   s    r   _from_complexr      s     88QVVQVV$2..r   c                   | d   | d   z  | d   | d   z  z
  }d|z  }| d   |z  }| d    |z  }| d    |z  }| d   |z  }t        j                  ||gd      }t        j                  ||gd      }t        j                  ||gd      S )	zb
    Invert 2x2 complex matrices using analytical formula.
    M shape: (..., 2, 2) complex64
    ).r   r   ).r   r   ).r   r   ).r   r         ?r   r   )r   r   )	Mdetinv_detout_00out_01out_10out_11row0row1s	            r   _invert_2x2_complexr%      s     I,9
%)q|(C
CC CiG y\G#F	l]W$F	l]W$Fy\G#F 88VV$2.D88VV$2.D88T4Lr**r   c                r    | j                   d   }|dk(  rd| z  S |dk(  rt        |       S t        d| d      )z~
    Invert covariance matrices for nb_channels in {1, 2}.
    Cxx: (Batch, Bins, C, C) complex64
    Returns: same shape
    r   r   r   r   z6Wiener inversion currently supports C=1 or C=2 (got C=z).)r	   r%   NotImplementedError)Cxxnb_channelss     r   _invert_covariancer*   /   sO     ))B-KaSya"3''

@RP r   c                    | j                  dddd      }|d   }|j                         ddddf   }||z  }t        j                  |d      j                  dddd      S )	z
    Compute covariance for a batch of frames.
    y_batch: (Batch, Bins, Channels, Sources) complex64
    Returns: (Sources, Bins, Channels, Channels) complex64 (Summed over batch)
    r   r      r   .N.Nr   )	transposeconjr   sum)y_batchy_transy_expy_conjR_batchs        r   _compute_covariance_batchr6   @   sk     1a+G IE\\^CqL)F fnG 66'",,Q1a88r   c                \    t        j                  t        j                  |       dz  d      S )z
    Compute PSD for a batch.
    y_batch: (Batch, Bins, Channels, Sources) complex64
    Returns: (Batch, Bins, Sources) real
    r   r   )r   meanabs)r1   s    r   _compute_power_batchr:   ]   s"     77266'?a'a00r   c                   | j                   \  }}}|d   }|ddddf   j                  ddddd      }||z  }	t        j                  |	d	      }
t        j                  ||
j
                  
      }|
||z  z   }
t        |
      }|dddddddddf   }||z  }||z  }| ddddddddf   }||z  }|j                  d      }|j                  dddd      S )z
    Apply Wiener filter to a batch.
    x_batch: (Batch, Bins, Channels) complex mixture
    v_batch: (Batch, Bins, Sources) power estimate
    R: (Sources, Bins, Channels, Channels) spatial covariance
    eps: regularization
    .NNN.r   r   r   r,      r   dtyper   )r	   r.   r   r0   eyer?   r*   squeeze)x_batchv_batchReps
batch_sizenb_binsr)   v_expR_expweighted_covsr(   r@   inv_Cxxinv_Cxx_expGainx_expy_hats                    r   _apply_wiener_batchrP   g   s    (/}}$J O$E aslO%%aAq!4E EMM &&Q
'C &&CII
.C
c	/C !%G !Qa*+K
 ;D %<D Aq$4'(E 5LE MM"E ??1aA&&r   c                   |j                   \  }}}| j                   d   }t        j                  |||ft        j                        }	t        j                  ||||ft        j                        }
t        |      D ]A  }t        j                  t        j                  |       dz  d      }	t        j                  |
      }t        j                  ||ft        j                        }t        d||      D ]E  }t        |||z         }| || }|	|| }t        |      }||z   }|t        j                  |d      z   }G |j                  dd      d   }|||z   z  }
g }t        d||      D ]:  }t        |||z         }||| }|	|| }t        |||
|      }|j                  |       < t        j                  |d      } D | |	|
fS )z
    Optimized EM algorithm using native complex numbers.
    y: (Frames, Bins, Channels, Sources) complex64
    x: (Frames, Bins, Channels) complex64
    r   r>   r   r   r   r   r<   )r	   r   zerosfloat32	complex64ranger8   r9   
zeros_likeminr6   r0   r.   rP   appendconcatenate)yr   
iterationsrE   rF   	nb_framesrG   r)   
nb_sourcesvrD   itR_accumweight_accumposend_posy_slicev_slicer5   weight_norm
y_new_listx_slicer1   s                          r   expectation_maximizationri      s    '(gg#IwJ 	)Wj1DA 	*g{K@UAJ
 GGBFF1IN+ --"xx* 5RZZHIz2C)S:%56GGnGGnG 08G'G ("&&q*AAL 3" #,,Q2?C{S() 
Iz2C)S:%56GGnGGnG *'7AsCGg& 3 NN:A.[  ^ a7Nr   c                   t        |      }|r)t        j                  | dd      }| ||z   z  }	|d   |	z  }
nPt        j                  |      d   }| j	                  t        j
                        t        j                  d|z        z  }
|r7|d   t        j                  |
dd      z
  }t        j                  |
|gd      }
|dk(  rt        |
      S t        j                  t        j                  d|j                  	      t        j                  t        j                  |            |z        }||z  }|
|z  }t        ||||
      \  }}}||z  }t        |      S )z
    Wiener-based separation.
    
    Args:
        targets_spectrograms: (Frames, Bins, Channels, Sources) - Magnitude
        mix_stft: (Frames, Bins, Channels, 2) - Complex as Real/Imag
    r   T)r   keepdimsr-   r   r   r   r   r>   )r[   rE   )r   r   r0   angleastyperT   exprY   r   maximumarrayr?   maxr9   ri   )targets_spectrogramsmix_stftr[   softmaskresidualscale_factorrE   mix_complex	sum_specsratiorZ   rl   
res_targetmax_val
mix_scaledy_scaled	y_refined_y_finals                      r   wienerr      sO   " h'K FF/b4H	$i8	"U* %i0 !''5rEz8JJ !+bffQR$.OO
NNAz?4QQ jj
K--.
rvvk"#l2G
 w&J7{H /	OIq! '!G!!r   )r   mx.arrayreturnr   )r   r   r   r   )r(   r   r   r   )r1   r   r   r   )
rB   r   rC   r   rD   r   rE   floatr   r   )r   绽|=   )rZ   r   r   r   r[   intrE   r   rF   r   r   z#tuple[mx.array, mx.array, mx.array])r   FFg      $@r   )rr   r   rs   r   r[   r   rt   boolru   r   rv   r   rE   r   r   r   )__doc__
__future__r   mlx.corecorer   r   r   compiler%   r*   r6   r:   rP   ri   r    r   r   <module>r      si   # -/ + +2" 9 98 1 1 D'D'D' D' 
	D'
 D' D'R EEE E 
	E
 E )ET ?""?"?" ?" 	?"
 ?" ?" 
?" ?"r   