
    iD              5          d dl Z d dlZd dlZd dlmZmZmZ d dlm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 ddlmZ ddlmZ 	 	 	 d4d	ej2                  d
ededededeeef   fdZ	 	 d5d	ej2                  d
edededej2                  f
dZdedefdZdede d
ededdf
dZ!	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d6dedeeeejD                  f      dededee   dee   deded ee   d!ee   d"ee   d#ee   d$ee   d%eeeejD                  f      d&ee   d'eded(e#d)e#d*e#d+ed,e#d-ed.e#d/e#ddf4d0Z$d1 Z%d2 Z&e'd3k(  r e&        yy)7    N)OptionalTupleUnion)sliding_window_view)write)
load_audio   )AudioPlayer)
load_modelwavsample_ratewindow_durationenergy_thresholdmargin_factorreturnc           
         t        ||z        }||z  }|dz  }t        | |      dd|   }t        j                  t        j                  |dz  d            }	|	|k\  }
t        j
                  |
      st        d      t        dt        j                  |
      |z  |z
        }t        t        |       t        |
      dz
  t        j                  |
ddd         z
  |z  |z         }||fS )	a,  Detect the start and end points of speech in an audio signal using RMS energy.

    Args:
        wav: Input audio signal array with values in [-1, 1]
        sample_rate: Audio sample rate in Hz
        window_duration: Duration of detection window in seconds
        energy_threshold: RMS energy threshold for speech detection
        margin_factor: Factor to determine extra margin around detected boundaries

    Returns:
        tuple: (start_index, end_index) of speech segment

    Raises:
        ValueError: If the audio contains only silence
    
   N   r	   axisz*No speech detected in audio (only silence)r   )intr   npsqrtmeanany
ValueErrormaxargmaxminlen)r   r   r   r   r   window_sizemargin	step_sizewindowsenergyspeech_maskstartends                k/Volumes/fast/ai/experiments/voice-extract-mac/.venv/lib/python3.12/site-packages/mlx_audio/tts/generate.pydetect_speech_boundariesr+      s    , o34K[(Fr!I "#{3KiK@G WWRWWWaZa01F,,K66+EFF299[)I5>?E
C	[	A			+dd*; <	<	IFRC
 #:    volume_thresholdc                 .    t        | |||      \  }}| || S )a  Remove silence from both ends of an audio signal.

    Args:
        wav: Input audio signal array
        sample_rate: Audio sample rate in Hz
        window_duration: Duration of detection window in seconds
        volume_threshold: Amplitude threshold for silence detection

    Returns:
        np.ndarray: Audio signal with silence removed from both ends

    Raises:
        ValueError: If the audio contains only silence
    )r+   )r   r   r   r-   r(   r)   s         r*   remove_silence_on_both_endsr/   ?   s*    ( *[/+;JE3 uS>r,   pitchc                 B    dt        j                  d| dz  z         z  }|S )z
    Converts a frequency from the Hertz scale to the Mel scale.

    Parameters:
    - pitch: float or ndarray
        Frequency in Hertz.

    Returns:
    - mel: float or ndarray
        Frequency in Mel scale.
    i#
  r	   i  )r   log10)r0   mels     r*   hertz_to_melr4   Y   s$     !eck/*
*CJr,   	file_nameaudio_chunksaudio_formatc                 |    |sy t        |      dkD  rt        j                  |d      n|d   }t        | |||       y )Nr	   r   r   format)r!   mxconcatenateaudio_write)r5   r6   r   r7   audios        r*   write_joined_audior?   i   sE      |q  	|!,!_ 

 	5+lCr,   textmodel
max_tokensvoicepromptinstructspeed	lang_code	cfg_scale
ddpm_stepssigma	ref_audioref_text	stt_modeloutput_pathfile_prefix
join_audioplayverbosetemperaturestreamstreaming_intervalsaveuse_zero_spk_embc                 
   	 |xs |}|t        d      ||r|t        d      t        |t              rt        |      }|rt        j
                  j                  |      st        d|       d}t        |d      r|j                  dk(  rd	}t        ||j                  |
      }|sddl}d|j                  |j                        j                  v rgt!        d       ddlm} t        |t              r ||      }|j                  |      j&                  }~t)        j*                          t!        d|        |rt-        |j                        nd}|r7t	        j.                  |d	       t        j
                  j1                  ||      }|t!        d|        t!        d|  d| d| d|        t3        d:| |||||||	|||||||d|}|||d<   |
|
|d<    |j                  d:i |}|xr |} g }!g }"i }#i }$| d| }%t5        |      D ]  \  }&}'|r|j7                  |'j8                         | ra|r|"j;                  |'j8                         n|'j<                  }(|(|#vrg |#|(<   |'j                  |$|(<   |#|(   j;                  |'j8                         nq|r|s|!j;                  |'j8                         nQ|sO| d|&dd| }%t?        |%tA        jB                  |'j8                        |'j                  |       t!        d|%        |st!        d       t!        d |'jD                          t!        d!|'jF                  d"   d#       t!        d$|'jH                   d%|'jJ                  d&   d#d'       t!        d(|'jF                  d)    d*|'jF                  d"   d#d+       t!        d,|'jL                  d-d.       t!        d/|'jN                  d-d0       t!        d1|'jP                  d-d2        | rE|rC|"rA|rt!        d3tS        |"       d4       tU        |%|"|j                  |       t!        d|%        n| r`|#r^tW        |#      D ]O  }(| d|(dd| }%|#|(   })|$|(   }*|rt!        d3tS        |)       d5|(        tU        |%|)|*|       t!        d|%        Q nH|rF|sD|!rB|rt!        d3tS        |!       d6       tU        |%|!|j                  |       |rt!        d|%        |r!|jY                          |j[                          yy# t\        $ r#}+t!        d7|+        t!        d8       Y d}+~+yd}+~+wt^        $ r,}+t!        d9|+        ddl0},|,jc                          Y d}+~+yd}+~+ww xY w);a  
    Generates audio from text using a specified TTS model.

    Parameters:
    - text (str): The input text to be converted to speech.
    - model (str): The TTS model to use.
    - voice (str): The voice style to use (also used as speaker for Qwen3-TTS models).
    - instruct (str): Instruction for emotion/style (CustomVoice) or voice description (VoiceDesign).
    - temperature (float): The temperature for the model.
    - speed (float): Playback speed multiplier.
    - lang_code (str): The language code.
    - ref_audio (mx.array): Reference audio you would like to clone the voice from.
    - ref_text (str): Caption for reference audio.
    - stt_model_path (str): A mlx whisper model to use to transcribe.
    - output_path (str): Directory path where audio files will be saved.
    - file_prefix (str): The output file path without extension.
    - audio_format (str): Output audio format (e.g., "wav", "flac").
    - join_audio (bool): Whether to join multiple audio files into one.
    - play (bool): Whether to play the generated audio.
    - verbose (bool): Whether to print status messages.
    - save (bool): Whether to save streamed audio to a file when using stream mode.
    - model (object): A already loaded model.
    - stt_model (object): A already loaded stt model.
    Returns:
    - None: The function writes the generated audio to a file when not streaming, or when streaming with saving enabled.
    Nz.Model path or model instance must be provided.zKSTT model path or model instance must be provided when ref_text is missing.)
model_pathz Reference audio file not found: F
model_typesparkT)r   volume_normalizer   rL   z-Ref_text not found. Transcribing ref_audio...)loadz[94mRef_text:[0m )r   )exist_okz[94mInstruct:[0m z[94mText:[0m z
[94mVoice:[0m z
[94mSpeed:[0m zx
[94mLanguage:[0m )r@   rC   rF   rG   rK   rL   rH   rI   rS   rB   rR   rT   rU   rE   rW   rD   rJ   ._03dr9   u0   ✅ Audio successfully generated and saving as: z
==========zDuration:              zSamples/sec:           zsamples-per-secz.1fzPrompt:                z	 tokens, ztokens-per-secz tokens-per-seczAudio:                 samplesz
 samples, z samples-per-seczReal-time factor:      z.2fxzProcessing time:       szPeak memory usage:     GBzJoining z streamed audio chunksz# streamed audio chunks for segment z audio fileszImport error: zIThis might be due to incorrect Python path. Check your project structure.zError loading model:  )2r   
isinstancestrr   ospathexistsFileNotFoundErrorhasattrrZ   r   r   inspect	signaturegenerate
parametersprintmlx_audio.sttr]   r@   r;   clear_cacher
   makedirsjoindict	enumeratequeue_audior>   appendsegment_idxr=   r   arrayaudio_durationaudio_samplestoken_countrD   real_time_factorprocessing_time_secondspeak_memory_usager!   r?   sortedwait_for_drainstopImportError	Exception	traceback	print_exc)-r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rO   r7   rP   rQ   rR   rS   rT   rU   rV   rW   kwargs	normalizern   load_stt_modelplayer
gen_kwargsresultssave_streamed_audio
audio_liststreamed_audio_chunksstreamed_segment_audiostreamed_segment_sample_ratesr5   iresultr{   r6   r   er   s-                                                r*   generate_audior   z   s   pz~v=MNN)0@]  eS!%0E 77>>),'*J9+(VWWIul+0@0@G0K 	"u'8'89I !2!25>>!B!M!MMIJD!)S1$29$=	(11)<AAH!NN$5hZ@A @D):):; KKd3'',,{K@K-hZ89#D6 *%%*G ,%%*G ,((1{4	
  
!#!1-
  !

$ #)Jx "'Jw %...:.$o
 "!#(*%"m1\N3	"7+IAv""6<<0")00>"("4"4K"*@@>@.{;EKEWEW5kB*;7>>v||LF!!&,,/*m1QsG1\NC	HHV\\*&&'	 HTUl#/0E0E/FGH-f.B.BCT.UVY-Z[ -f.@.@-A6==YiKjknJoo~ -f.B.B9.M-NjY_YmYmn  ZA  BE  YF  FV  W /0G0G/LANO/0N0Ns/SSTUV/0H0H/MRPQQ ,T :2G%:!; <<RST%!!	 DYKPQ %;%&<=*m1[,=Q|nM	5kB;KH"|,--P&-)
 #  	 HTU!  >" :Z 1>?!!	 HTU!!#KKM   
qc"#W	
 	
  %aS)*	s+   L	T G:T 	U'T//U';"U""U'c                     t        j                  d      } | j                  dt        dd       | j                  dt        dd	
       | j                  dt        d d
       | j                  dt        d d
       | j                  dt        d d
       | j                  dt        d d
       | j                  dt
        dd
       | j                  dt
        dd
       | j                  dt        d d
       | j                  dt
        dd
       | j                  dt        dd 
       | j                  d!t
        dd"
       | j                  d#t        d$d%
       | j                  d&t        d d'
       | j                  d(t        d)d*
       | j                  d+d,d-.       | j                  d/d,d0.       | j                  d1d,d2.       | j                  d3t        d4d5
       | j                  d6t        d d7
       | j                  d8t        d d9
       | j                  d:t        d;d<
       | j                  d=t
        d>d?
       | j                  d@t
        d dA
       | j                  dBd,dC.       | j                  dDt
        dEdF
       | j                  dGt        dHdI
       | j                  dJt
        dKdL
       | j                  dMd,dN.       | j                  dOt
        dPdQ
       | j                  dRd,dS.       | j                         }|j                  r|j                  s| j                  dT       |j                  zt        j                  j                         s3t        j                  j                         j                         |_
        |S t!        dU       t#        dV      j                         |_
        |S )WNz#Generate audio from text using TTS.)descriptionz--modelTzPath or repo id of the model)typerequiredhelpz--max_tokens  z$Maximum number of tokens to generate)r   defaultr   z--textz1Text to generate (leave blank to input via stdin)z--voicez?Voice/speaker name (e.g., Chelsie, Ethan, Vivian for Qwen3-TTS)z--promptz&Optional model-specific prompt prefix.z
--instructzNInstruction for CustomVoice (emotion/style) or VoiceDesign (voice description)z--exaggerationg      ?z!Exaggeration factor for the voicez--cfg_scaleg      ?uH   Classifier-free guidance scale. Lower (≈1.0-1.5) is often more stable.z--ddpm_stepszFOverride diffusion steps. Higher = better quality, slower (try 30-50).z--speed      ?zSpeed of the audioz--gendermalez"Gender of the voice [male, female]z--pitchzPitch of the voicez--lang_codeenzLanguage codez--output_pathzDirectory path for output filesz--file_prefixr>   zOutput file name prefixz	--verbose
store_truezPrint verbose output)actionr   z--join_audiozJoin all audio files into onez--playzPlay the output audioz--audio_formatr   zOutput audio formatz--ref_audiozPath to reference audioz
--ref_textzCaption for reference audioz--stt_model-mlx-community/whisper-large-v3-turbo-asr-fp16z.STT model to use to transcribe reference audioz--temperatureffffff?zTemperature for the modelz--sigmaz6Optional model-specific sigma value (e.g., Ming Omni).z--use_zero_spk_embzFOptional model-specific zero speaker embedding mode (e.g., Ming Omni).z--top_pg?zTop-p for the modelz--top_k2   zTop-k for the modelz--repetition_penaltyg?z Repetition penalty for the modelz--streamz.Stream the audio as segments during generationz--streaming_interval       @z3The time interval in seconds for streaming segmentsz--savez1Save streamed audio to a file. Requires --stream.z--save requires --streamz"Please enter the text to generate:z> )argparseArgumentParseradd_argumentrh   r   float
parse_argsrV   rT   errorr@   sysstdinisattyreadstriprr   input)parserargss     r*   r   r   o  s;   $$1VWF
+	   3	   @	   N	   5	   ]	   0	   W	   U	   	sAUV
f3W   	sAUV
COT
c46W   c79R   L?UV
|2Q   <ST
sE8M   C4M   33P   ?=	   eS7R   E	   U  
 	sAVW
	R>ST
/	   =  
 B	   @   Dyy/0yyyy!		(..0DI
 K 67d))+DIKr,   c                  @    t               } t        di t        |        y )Nrf   )r   r   vars)r   s    r*   mainr     s    <D T$Z r,   __main__)皙?{Gz?r   )r   r   )Nr   af_heartNNr   r   NNNNNr   Nr>   r   FFTr   Fr   FF)(r   ri   r   typingr   r   r   mlx.corecorer;   mlx.nnnnnumpyr   numpy.lib.stride_tricksr   mlx_audio.audio_ior   r=   mlx_audio.utilsr   audio_playerr
   utilsr   ndarrayr   r   r+   r/   r4   rh   listr?   Moduleboolr   r   r   __name__rf   r,   r*   <module>r      s    	 
 ) )    7 3 & %  !"*	** * 	*
 * 38_*` !"		  	
 ZZ4 %  DDD D 	D
 
D& .2 "!% $!#" 	8!% #"7r
rE#ryy.)*r r 	r
 SMr smr r r r r E?r }r smr c299nr" ##r$ %r& 'r( )r* +r, -r. /r0 1r2 3r4 5r6 7r: 
;rjM`!
 zF r,   