+
    qvj0                        R t ^ RIt^ RIt^ RIt^ RIHt ^ RItRtR^ut	t
R^^utttRRuttRR ltR	 tR
 t]! 4       t]P(                  ! ]P*                  ],          ]P,                  ! ]4      R,           R,          ,          ]P,                  ! ^]^,           4      R,          ,          4      tR tRR ltR tR tRR lt ! R R4      tR tR tR t] R8X  d
   ]! 4        R# R# )uX  H3 DoD 3 2단 — 산출물 발화 구간이 **어느 레퍼런스 음색**에 붙었는지 관측한다.

1단(오디오 ref 없이)이 못 닫은 것은 "여성 2인이 갈렸나" 였다. 그때 막은 것은 두 가지다:
정답 앵커가 없었고(누가 어떤 목소리여야 하는지 모름), 지표가 f0 자기상관 하나였다.
여기선 앵커가 생겼다 — **합성 ref 3개가 곧 정답**이다. 지표도 아래처럼 캘리브레이션해서 쓴다.

지표
  ⓐ **MFCC(13) 평균 벡터의 코사인** — 단 도메인(녹음 채널)별 CMVN 을 먼저 뺀다.
     TTS ref(24kHz 합성)와 H3 산출물(32kHz 생성)은 채널이 달라 CMVN 없이 비교하면
     채널 차가 화자 차를 덮는다. **화자별이 아니라 도메인별**로 빼는 것이 핵심 —
     화자별로 빼면 화자 정보 자체가 0 이 된다.
  ⓑ **중앙 f0**(자기상관·옥타브 보정) — 채널에 둔감한 보조 앵커. 1단이 쓴 그 지표다.
  ⓒ **스펙트럼 기울기**(저역/고역 에너지 비) — 밝음/허스키 축의 대리지표.

캘리브레이션 (지표를 믿어도 되는지 먼저 본다)
  각 ref 를 반으로 갈라 **동일 화자쌍**의 코사인을, 서로 다른 ref 끼리 **이종 화자쌍**의 코사인을
  낸다. 두 분포가 마진을 두고 갈리지 않으면 이 지표로는 아무 판정도 하지 않는다.

판정 순서
  1. 산출물 내부 — 발화 구간끼리 갈리나 (같은 채널이라 비교가 깨끗하다)
  2. 산출물 ↔ ref — 각 구간이 어느 ref 에 가장 가깝나, 2등과의 마진은 얼마나 되나
N)Pathi>  i     g      N@g      y@c           
     j   . ROpVe   VRVR .,          pVe   VRVR .,          pVR\        V 4      RRR\        \        4      RR	R
.	,          p\        P                  ! VRRR7      P                  p\
        P                  ! V\
        P                  R7      P                  \
        P                  4      # )uO   ffmpeg 로 16kHz mono float32 로 통일해 읽는다 (wav·mp4 공통 경로).z-ssz.3fz-tz-iz-ac1z-arz-ff32le-T)capture_outputcheckdtype)ffmpegz-verror)
strSR
subprocessrunstdoutnp
frombufferfloat32astypefloat64)pathstartdurcmdraws   &&&  ;/Users/inhohur/ai/experiments/h3-r2v-dod3/analyze_voices.pyloadr   &   s    
#C%&&
S	##D#d)UCBwLLC
..T
>
E
EC==BJJ/66rzzBB    c                 ^   ^\        ^ \        V 4      \        ,
          \        ,          4      ,           p\        P
                  ! \        4      R,          \        \        P
                  ! V4      R,          ,          ,           pW,          \        P                  ! \        4      R,          ,          # )   NNNNr#   N)maxlenFRAMEHOPr   arangehamming)xnidxs   &  r   framesr.   4   se    	CCFUNs*++A
))E
7
#cBIIaL,A&A
AC6BJJu%g...r   c                     R  p R pV ! R4      V ! \         ^,          4      r2V! \        P                  ! W#\        ^,           4      4      p\        P                  ! \
        ^,           V,          \         ,          4      P                  \        4      p\        P                  ! \        \
        ^,          ^,           34      p\        \        4       F  pWW,          WW^,           ,          WW^,           ,          rpW8X  d
   V^,           p	W8X  d
   V	^,           p
\        P                  ! W4      V,
          W,
          ,          WgW13&   V
\        P                  ! W4      ,
          W,
          ,          WgW13&   K  	  V# )c                 X    R \         P                  ! RV R,          ,           4      ,          # )     F@      ?     @)r   log10)fs   &r   hz2mel_mel_fb.<locals>.hz2mel;   s    q5y111r   c                 >    R RV R,          ,          R,
          ,          # )r3         $@r1   r2    )ms   &r   mel2hz_mel_fb.<locals>.mel2hz>   s    V,s233r   g      I@)r   r   linspaceN_MELfloorN_FFTr   intzerosranger)   )r6   r<   lohiptsbinsfbr;   lcrs              r   _mel_fbrM   :   s   24 D\6"q&>
RUQY/
0C88UQY#%*+2237D	5%1*q.)	*B5\'4A;Ua6AA6AAiio)ae4ac6
"))A/)ae4ac6
  Ir         ?c           
     |   \        \        P                  ! V ^ ,          V R,          RV RR ,          ,
          4      4      p\        V4      ^ 8X  d3   \        P                  ! ^ \
        34      \        P                  ! ^ 4      3# \        P                  ! \        P                  P                  V\        4      4      ^,          p\        P                  ! \        VP                  ,          R,           4      p\        V,          P                  R\        P                  ! VP                  ^R7      R,           4      ,          3# )uN   프레임별 MFCC(13) + 프레임 에너지(dB). c0 는 버린다 (음량축).:r!   NNg
ףp=
?Ng|=r9   axis)r.   r   appendr&   rC   N_MFCCabsfftrfftrA   logMEL_FBTDCTr4   sum)r+   r5   specmels   &   r   mfcc_framesr_   T   s    ryy1qutaf}456A
1v{xxF$bhhqk1166"&&++a'(A-D
&&$&&5(
)C#I==$$(((*:U*B!CCCCr   c                    \        V 4      ^ 8X  d   \        P                  ! ^ \        R7      # V \        P                  ! V ^_4      V,
          8  # )um   상위 에너지 대비 -25dB 이상을 유성으로 본다 (무음 프레임이 평균을 흐리지 않게).r
   )r&   r   rC   bool
percentile)	energy_dbfloor_offsets   &&r   voiced_maskre   ^   s:    
9~xx&&i4|CDDr   c           	        . p\        ^ \        ^ \        V 4      R,
          4      R4       EF  pWVR,            p\        P                  ! V^,          P                  4       4      R8  d   KA  W3P                  4       ,
          p\        P                  ! W3R4      \        V4      ^,
          R p\        \        \        ,          4      \        \        \        ,          4      reV\        V4      8  d   K  WEV pVP                  4       ^ 8:  g   V^ ,          ^ 8:  d   K  V\        VP                  4       4      ,           pWH,          V^ ,          ,          R8  d   EK-  \        V,          p	V^,          p
W8  dD   WJ,          V^ ,          ,          RWH,          ,          V^ ,          ,          8  d   \        V
,          p	VP                  V	4       EK  	  V'       d    \        \        P                  ! V4      4      # \        R4      # )	u;   자기상관 f0 (옥타브 보정) — 유성 프레임만.i   r   gMbP?fullN333333?g?nan)rD   r%   r&   r   sqrtmean	correlaterB   r   F0_MAXF0_MINargmaxrS   floatmedian)r+   valsiwacrE   rF   seglagr5   halfs   &          r   	f0_medianry   e   s`   D1c!SVd]+S1DM77AF==?#d*L\\!'A
4R&[!3rF{#3BR=Bi779>RUaZ3szz|$$7RU?S Hax:"(RU*S27]RU-BBT	AA' 2( &*54!;uU|;r   c                *   \        V 4      p\        V4      ^ 8X  d   \        R4      # \        P                  ! \        P
                  P                  V\        4      4      ^,          p\        P
                  P                  \        ^\        ,          4      pVRV^ 8  VR8*  ,          3,          P                  4       pVRVR8  VR8*  ,          3,          P                  4       p\        \        P                  ! VR,           VR,           ,          4      4      # )uL   스펙트럼 기울기 = log10(고역 2~8kHz / 저역 0~1kHz) 에너지 비.ri   r#   i  i  i@  -q=)r.   r&   rp   r   rU   rV   rW   rA   rfftfreqr   r\   r4   )r+   r5   r]   freqrE   rF   s   &     r   tiltr~      s    q	A
1v{U|66"&&++a'(A-D66??5!b&)D	a$(tt|,,	-	1	1	3B	a$$,44<00	1	5	5	7B2:"u*5677r   c                t   \        V 4      w  r4\        VRR7      p. Rrv\        V\        ,          \        ,          4      p^ p	\        V4       FI  w  rV'       d   Vf   T
p^ p	K  Vf   K  V	^,          p	W8  g   K.  VP                  WzV	,
          34       RpKK  	  Ve   VP                  V\        V4      34       . pV Fw  w  rV\        ,          \        ,          V\        ,          \        ,           \        ,          ppVV,
          V8  g   KP  VP                  \        V^4      \        V^4      34       Ky  	  V# )u\   에너지 VAD → 발화 덩이. 3인이 차례로 말하므로 덩이 ≈ 화자 턴이다.g      6@)rd   N)
r_   re   rB   r   r(   	enumeraterS   r&   r'   round)r+   min_durgap_evsegsr   
gap_framessilencers   onoutse_t0t1s   &&&              r   speech_segmentsr      s    q>DAAD)AD#S2X^$JG1{G_qLG$Sg+./  S#a&M"
CS2S5 0B6B7gJJb!eBl34  Jr   c                   0   a  ] tR t^t o RtR tR tRtV tR# )Domainu_   한 녹음 채널(도메인)의 CMVN 통계. 도메인 안에서만 화자 차이를 남긴다.c                |   . pV FD  p\        V4      w  rE\        V4      '       g   K#  VP                  V\        V4      ,          4       KF  	  V'       d   \        P
                  ! V4      M\        P                  ! ^\        34      pVP                  ^ R7      V n	        VP                  ^ R7      R,           V n        R# )r!   rP   g&.>N)r_   r&   rS   re   r   concatenaterC   rT   rk   mustdsd)selfwavesaccrt   r;   r   allfs   &&     r   __init__Domain.__init__   s    Aq>DA1vv

1[^,-  '*r~~c"rxxF/D)))#((("T)r   c                    \        V4      w  r#\        V4      pVP                  4       ^8  d   R# W$,          V P                  ,
          V P                  ,          pVP                  ^ R7      # )   NrP   )r_   re   r\   r   r   rk   )r   rt   r;   r   r   zs   &&    r   vec
Domain.vec   sN    1~N557Q;TDGG^tww&vv1v~r   )r   r   N)	__name__
__module____qualname____firstlineno____doc__r   r   __static_attributes____classdictcell__)__classdict__s   @r   r   r      s     i* r   r   c                     \        \        P                  ! W4      \        P                  P	                  V 4      \        P                  P	                  V4      ,          R ,           ,          4      # )r{   )rp   r   dotlinalgnorm)abs   &&r   cosr      s>    !2RYY^^A5F!F!NOPPr   c                   \        \        V 4      \        V4      4      pV\        ^,          8  d   \        R4      # V RV V RV P	                  4       ,
          V RV P                  4       R,           ,          p VRV VRV P	                  4       ,
          VRV P                  4       R,           ,          p\        P                  ! WR4      V,          p\        \        \        P                  ! V4      P                  4       4      ^4      # )uo   정규화 상호상관 최대값 — 산출물이 ref 파형을 그대로 통과시켰는지(§5.6 ⓑ) 본다.ri   Nr{   rg   )minr&   r   rp   rk   r   r   rl   r   rU   r%   )r   r   r,   rK   s   &&  r   	xcorr_maxr      s    CFCFA27{U|	
2A2A	!BQ%))+"56A	
2A2A	!BQ%))+"56A
Q6"Q&Arvvay}}'++r   c                  ,   \        \        \        P                  4      ^8  d   \        P                  ^,          MR4      p RV R,          RV R,          RV R,          /pR/ R	/ R
/ /pVP	                  4        UUu/ uF  w  r4V\        V4      bK  	  ppp\        \        VP                  4       4      4      pVP	                  4        UUu/ uF  w  r7W6P                  V4      bK  	  pppVP	                  4        F[  w  r7R\        \        V4      \        ,          ^4      R\        \        V4      ^4      R\        \        V4      ^4      /VR,          V&   K]  	  / p	VP	                  4        F@  w  r7\        V4      ^,          p
VP                  VRV
 4      VP                  WzR 4      .W&   KB  	  V	P	                  4        UUUu/ uF  w  pw  rV\        \        W4      ^4      bK   	  pppp/ p\        V4      p\        \        V4      4       Fk  p\        V^,           \        V4      4       FH  p\        \        WV,          ,          WV,          ,          4      ^4      WV,           RVV,           2&   KJ  	  Km  	  RVRVR\        \!        VP                  4       4      \#        VP                  4       4      ,
          ^4      R\%        \!        VP                  4       4      \#        VP                  4       4      ,
          R8  4      /VR	&   \        P                  R,           Uu. uF  qP'                  R^4      NK  	  up EF  w  pp\        V4      p\)        V4      p\        V.4      p. pV EF  w  ppV\+        V\        ,          4      \+        V\        ,          4       pVP                  V4      pVP                  V4      pVe   Vf   K`  V Uu/ uF  q3\        \        VW,          4      ^4      bK!  	  pp\-        VP	                  4       R R7      p\        V4      ^,          p
VP                  VRV
 4      VP                  VV
R 4      p pTP/                  RVV.R\        VV,
          ^4      R\        \        V4      ^4      R\        \        V4      ^4      RVe   V e   \        \        VV 4      ^4      MRRTRV^ ,          ^ ,          R\        V^ ,          ^,          V^,          ^,          ,
          ^4      RV Uu/ uF  q3\1        VWS,          4      bK  	  upRVP3                  4       /
4       EK  	  / p!\        \        V4      4       F  p\        V^,           \        V4      4       Fe  p\        \        \4        P6                  ! VV,          R,          4      \4        P6                  ! VV,          R,          4      4      ^4      V!V RV 2&   Kg  	  K  	  V F  p"V"R K  	  R R!p$p#. p%R"p&V&V#,           \        V4      \        ,          8:  Ed@   V\+        V&\        ,          4      \+        V&V#,           \        ,          4       pVP                  V4      p'V'e   \4        P8                  ! V^,          P;                  4       4      R#8  d   V Uu/ uF  q3\        \        V'W,          4      ^4      bK!  	  pp\-        VP	                  4       R$ R7      pV%P/                  R\        V&^4      R%\        \        V4      ^4      R&VRV^ ,          ^ ,          R\        V^ ,          ^,          V^,          ^,          ,
          ^4      /4       V&V$,          p&EKb  V U"u. uF  p"V"R,          f   K  V"R,          NK  	  p(p"R\        \        V4      \        ,          ^4      R'TR(T!R)T%R*V('       d   \        \!        V(4      ^4      MR/VR
,          V&   EK  	  \=        \>        P@                  ! VR+^R,7      4       R# u uppi u uppi u upppi u upi u upi u upi u upi u up"i )-r!   .F1_hanna_brightzrefs/v1-hanna-female-bright.wavF2_yumin_midzrefs/v2-yumin-female-mid.wavM1_jiho_deepzrefs/v3-jiho-male-deep.wavrefscalibrationclipsdur_s	f0_med_hzr~   N~same_speaker_halvescross_speakermarginusableg333333?:   NN=c                     V ^,          ) # r!   r:   kvs   &r   <lambda>main.<locals>.<lambda>   s
    1vr   )keytr   self_halves_cos
sim_to_refbestxcorr_to_ref_v_selfg333333?g?g        g{Gz?c                     V ^,          ) # r   r:   r   s   &r   r   r     s
    BqE6r   f0simsegmentsinner_pairwise_costracksame_speaker_floorF)ensure_asciiindent)!r   r&   sysargvitemsr   r   listvaluesr   r   r   ry   r~   r   rD   r   r%   ra   splitr   rB   sortedrS   r   tolistr   arrayrj   rk   printjsondumps))baser   r   kpref_wavref_domrt   ref_vechalveshr   r   samediffkeysrs   jlabelr   wavr   clip_domrowsr   r   rv   v_selfv_refsimsrankvavbinnerrL   winhop_sr   r   r   floorss)                                            r   mainr     s   s388}q0c:D4"CC==;;D
 2}b'2
6C&*jjl3ldaq$q'zlG3T'..*+,G-4]]_=_TQq++a. _G=!5Q"a#8+uYWX\[\G] %Q"35FA  
 FFaK[[2A'QrU);<	   5;LLNCNyq&1AuSY""NDCD:D3t9q1uc$i(A+0W!W5EwTUwGW1XZ[+\DG9Ad1gY'( )  	t_d%DKKM*S-??C$s4;;=)C,>>EFC 25">AQ>t4js#3%=HRc"r'l3rBw<0C\\#&FKK$E~AEFAuS
3Q77DF$**,,=>D CAA\\#bq'*HLLQR,ABKKb"XueBGQ&7U9S>15vuT#YPQ?R!BNr~5Ra#8cgdFDGAJ%QPQ
UYZ[U\]^U_H_abBc M1Ic7:$>!> M6==?  * s4y!A1q5#d),$)#bhhtAwy7I.JBHHUYZ[U\]fUgLh*ikl$m1QCj! - " A) 
 #U#gSB&c!b&k#q3w"n"56CC A}#():!;d!BAEFA5Q
!3Q77Fdjjl0ABc5A;eIcNA6N#T6471:&d1gaj471:.Eq(IK L JA04Y1:K8L&!%&&YU3s8b=!,j$ %% 6%FQ"7t	
GUe ?r 
$**SuQ
78e 4= D ? G !N( G Zs6   9_*_0 $_6_=%`;`.	%``!`__main__)NNr"   r$   )g      9@)rN   rh   )!r   r   r   r   pathlibr   numpyr   r   r'   r(   rA   r?   rT   rn   rm   r   r.   rM   rY   r   pir)   r[   r_   re   ry   r~   r   r   r   r  r   r:   r   r   <module>r     s   ,   
  
#
sB ufu
	C/, 
ffRUUU]bii.4g>>1fWXjAYZaAbbcDE<4	8: ,Q,[9| zF r   