
    xi_@                        d Z ddlZ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	m
Z
mZmZ ddlZddlZddlZddlmZ dde	ej&                  ej(                  f   dede	ej&                  ej(                  f   fd	Z G d
 d      ZdefdZdefdZdefdZ	 dde	ej&                  ej(                  f   de
e   defdZ ed      Z	 	 	 dde	ej&                  ej(                  f   de	eef   dede
e   dedefdZ y)z
Audio saving and transcoding utility module

Independent audio file operations outside of handler, supporting:
- Save audio tensor/numpy to files (default FLAC format, fast)
- Format conversion (FLAC/WAV/MP3)
- Batch processing
    N)Path)UnionOptionalListTuple)logger
audio_data	target_dbreturnc                 \   t        | t        j                        r| j                         }d}n| j	                         }d}|r)t        j
                  t        j                  |            }n(t        j
                  t        j                  |            }|dk  r| S d|dz  z  }||z  }||z  }|S )a  
    Apply peak normalization to audio data.
    
    Args:
        audio_data: Audio data as torch.Tensor or numpy.ndarray
        target_db: Target peak level in dB (default: -1.0)
        
    Returns:
        Normalized audio data in the same format as input
    TFgư>
   g      4@)
isinstancetorchTensorclonecopymaxabsnp)r	   r
   audio	is_tensorpeak
target_ampgains          2/mnt/workspace/ACE-Step-1.5/acestep/audio_utils.pynormalize_audior      s     *ell+  "	!	 yy5)*vvbffUm$ d{ 	D()J D DLEL    c                   8   e Zd ZdZddefdZ	 	 	 ddeej                  e	j                  f   deeef   dedee   d	ed
efdZ	 ddeeef   deeef   deded
ef
dZ	 	 	 	 ddeeej                     ej                  f   deeef   dededee   d	ed
ee   fdZy)
AudioSaverz*Audio saving and transcoding utility classdefault_formatc                     |j                         | _        | j                  dvr!t        j                  d| d       d| _        yy)z
        Initialize audio saver
        
        Args:
            default_format: Default save format ('flac', 'wav', 'mp3', 'wav32', 'opus', 'aac')
        flacwavmp3wav32opusaacUnsupported format z, using 'flac'r#   N)lowerr    r   warning)selfr    s     r   __init__zAudioSaver.__init__E   sI     -224&TTNN00@OP"(D Ur   Nr	   output_pathsample_rateformatchannels_firstr   c           
         |xs | j                   j                         }|dvr1t        j                  d| d| j                           | j                   }t	        |      }|dk(  rdnd| }|j
                  j                         dvr|j                  |      }nW|dk(  r/|j
                  j                         dk(  r|j                  d      }n#|d	k(  r|j
                  j                         d
k(  r	 t        |t        j                        r|r$t        j                  |      j                         }nt        j                  |      j                         }|j                         dk(  r|j                  d   |j                  d   kD  rk|j                  }n^|j!                         j                         }|s>|j                         dk(  r+|j                  d   |j                  d   kD  r|j                  }|j#                         }	 |dv r$t%        j&                  t)        |      ||dd       n|dv r|dk(  rk	 ddl}|j-                  dd      j/                         }	|j1                  t)        |      |	|dd       t        j2                  d| d| d       t)        |      S t%        j&                  t)        |      ||dd       n"t%        j&                  t)        |      ||d       t        j2                  d| d| d | d       t)        |      S # t4        $ r%}
t        j6                  d|
 d       d}Y d}
~
d}
~
ww xY w# t4        $ r}
	 ddl}|j-                  dd      j/                         }	|dk(  rd}d}n|j9                         }d}|j1                  t)        |      |	|||!       t        j2                  d"| d| d | d       t)        |      cY d}
~
S # t4        $ r!}t        j6                  d#|
 d$|         d}~ww xY wd}
~
ww xY w)%a  
        Save audio data to file
        
        Args:
            audio_data: Audio data, torch.Tensor [channels, samples] or numpy.ndarray
            output_path: Output file path (extension can be omitted)
            sample_rate: Sample rate
            format: Audio format ('flac', 'wav', 'mp3', 'wav32', 'opus', 'aac'), defaults to default_format
            channels_first: If True, tensor format is [channels, samples], else [samples, channels]
        
        Returns:
            Actual saved file path
        r"   r)   z, using r&   .wav.)z.flacr3   z.mp3z.opusz.aac.m4az.wav32r(   r5      r      )r%   r'   r(   Tffmpeg)r1   backend)r#   r$   r&   NFLOATWAV)subtyper0   z[AudioSaver] Saved audio to z	 (wav32, zHz)zFailed to save wav32: z, falling back to standard wavr$   	soundfile)r1   z (z, )r0   r<   z/[AudioSaver] Fallback soundfile Saved audio to z#[AudioSaver] Failed to save audio: z -> Fallback failed: )r    r*   r   r+   r   suffixwith_suffixr   r   ndarrayr   
from_numpyfloatdimshapeTcpu
contiguous
torchaudiosavestrr=   	transposenumpywritedebug	Exceptionerrorupper)r,   r	   r.   r/   r0   r1   extaudio_tensorsfaudio_npe	sf_formatr<   inner_es                 r   
save_audiozAudioSaver.save_audioQ   s   * /D//668GGNN0ATAT@UVW((F ;' ')f6(|##%-__%11#6Kw;#5#5#;#;#=#I&226:[u_!3!3!9!9!;v!E j"**-$//
;AAC  %//
;AAC##%*|/A/A!/D|GYGYZ[G\/\$0NN\ &>>+113L!l&6&6&8A&=%%a(<+=+=a+@@#/>>L $..0B	//$ #'$ 33 W$'. $0#9#9!Q#?#E#E#G [!18[RYbgh'CK=PYZeYffi%jk";// $ #'' $ #'	 LL7}BvhbQ\P]]`ab{##- % ''=aS@^%_`!&'0  	&'11!Q7==? W$ %I%G &I"G[)8[\cdN{m[]^d]eeghsgttwxy;'' B1#EZ[bZcde!	sc   1L> 3A)L A/L> 	L;L61L> 6L;;L> >	PBOP	P O;;P  PP
input_pathoutput_formatremove_inputc                 0   t        |      }t        |      }|j                         st        d|       t        j                  t        |            \  }}| j                  ||||d      }|r(|j                          t        j                  d|        |S )aa  
        Convert audio format
        
        Args:
            input_path: Input audio file path
            output_path: Output audio file path
            output_format: Target format ('flac', 'wav', 'mp3', 'wav32', 'opus', 'aac')
            remove_input: Whether to delete input file
        
        Returns:
            Output file path
        zInput file not found: Tr/   r0   r1   z![AudioSaver] Removed input file: )
r   existsFileNotFoundErrorrH   loadrJ   rY   unlinkr   rN   )r,   rZ   r.   r[   r\   rS   r/   s          r   convert_audiozAudioSaver.convert_audio   s    & *%
;'  "#&<ZL$IJJ %/OOC
O$D!k oo#  & 
 LL<ZLIJr   audio_batch
output_dirfile_prefixc                    t        |      }|j                  dd       t        |t        j                        r<|j                         dk(  r)t        |j                  d         D cg c]  }||   	 }}nt        |t              r|}n|g}g }	t        |      D ]7  \  }}
|| d|dz  }| j                  |
||||      }|	j                  |       9 |	S c c}w )a  
        Save audio batch
        
        Args:
            audio_batch: Audio batch, List[tensor] or tensor [batch, channels, samples]
            output_dir: Output directory
            file_prefix: File prefix
            sample_rate: Sample rate
            format: Audio format
            channels_first: Tensor format flag
        
        Returns:
            List of saved file paths
        T)parentsexist_ok   r   _04dr^   )r   mkdirr   r   r   rC   rangerD   list	enumeraterY   append)r,   rd   re   rf   r/   r0   r1   i
audio_listsaved_pathsr   r.   
saved_paths                r   
save_batchzAudioSaver.save_batch  s    . *%
5 k5<<0[__5F!5K278I8I!8L2MN2MQ+a.2MJNT*$J%J!*-HAu$+a#w'??K'- ) J z* . % Os   &C)r#   逻  NT)F)r   rx   NT)__name__
__module____qualname____doc__rJ   r-   r   r   r   r   r@   r   intr   boolrY   rc   r   rv    r   r   r   r   B   sN   4
)s 
)  ! $#B%,,

23B 39%B 	B
 B B 
BR #*#t)$* 39%* 	*
 * 
*` #  $#/4-u||;</ #t)$/ 	/
 / / / 
c/r   r   c                 x   t        | dd      syt        | dd      syt        | dd      }||j                  syt        j                         }d}t	        |j                  j                               D ]  }|j                  |   }|j                  d      }|s'g }t        j                  j                  |      r|j                  |       nwt        j                  j                  |      rXdD ]S  }t        j                  j                  ||      }	t        j                  j                  |	      sC|j                  |	       U |D ]B  }		 t        |	d	      5 }
	 |
j                  d      }|sn|j                  |       &	 ddd       d
}D  |r|j#                         S dS # 1 sw Y   $xY w# t         $ r Y sw xY w)a  Compute an MD5 hash identifying the currently loaded LoRA adapter weights.

    Iterates over the handler's LoRA service registry to find adapter weight
    file paths, then hashes each file to produce a combined fingerprint.

    Args:
        dit_handler: DiT handler instance with LoRA state attributes.

    Returns:
        Hex digest string uniquely identifying the loaded LoRA weights,
        or empty string if no LoRA is active.
    lora_loadedF use_lora_lora_serviceNpath)zadapter_model.safetensorszadapter_model.binzlokr_weights.safetensorsrbTi   )getattrregistryhashlibsha256sortedkeysgetosr   isfilerq   isdirjoinopenreadupdateOSError	hexdigest)dit_handlerlora_servicehash_obj	found_anyadapter_namemeta	lora_path
candidatesfnamefpathfchunks               r   get_lora_weights_hashr   3  s    ;u5;
E2;>L<#8#8~~HI|4499;<$$\2HHV$	 
77>>)$i(WW]]9%
 Y677>>%(%%e,  E	%&! !w$! .	  "	 ' !	  ) =@ $-84"4 '&  s*   	F-(F!>
F-!F*&F--	F98F9c                    | y	 t        | t              rt        j                  j	                  |       rGt        | d      5 }t        j                  |j                               j                         cddd       S t        j                  | j                  d            j                         S t        | d      rEt        j                  t        | j                        j                  d            j                         S t        j                  t        |       j                  d            j                         S # 1 sw Y   xY w# t        $ r> t        j                  t        |       j                  d            j                         cY S w xY w)z
    Get hash identifier for an audio file.
    
    Args:
        audio_file: Path to audio file (str) or file-like object
    
    Returns:
        Hash string or empty string
    Nr   r   utf-8name)r   rJ   r   r   r_   r   r   r   r   r   encodehasattrr   rO   )
audio_filer   s     r   get_audio_file_hashr   o  s    
Kj#&ww~~j)*d+q">>!&&(3==? ,+>>*"3"3G"<=GGIIZ(>>#joo"6"="=g"FGQQSS~~c*o44W=>HHJJ ,+  K~~c*o44W=>HHJJKs=   ;E  1D91	E ;1E -AE >:E 9E>E AFFc                     t        j                  | dd      }t        j                  |j	                  d            }|j                         }|dd  d|dd  d|dd	  d|d	d
  d|d
d  	}|S )z
    Generate deterministic UUID from generation parameters.
    Same parameters will always generate the same UUID.
    
    Args:
        params_dict: Dictionary of parameters
    
    Returns:
        UUID string
    TF)	sort_keysensure_asciir   r      -             )jsondumpsr   r   r   r   )params_dictparams_jsonr   hash_hexuuid_strs        r   generate_uuid_from_paramsr     s     **[DuMK~~k009:H!!#H1Q-(1R.!18Br?2C1XbQS_DUUVW_`bceWfVghHOr   seedc                 R   t        | t        j                        r| j                         j	                         }n| }t        j                  |j                               j                         }|8| d| }t        j                  |j                               j                         S |S )z
    Generate UUID from audio data (for caching/deduplication)
    
    Args:
        audio_data: Audio data
        seed: Optional seed value
    
    Returns:
        UUID string
    rk   )
r   r   r   rF   rL   r   r   tobytesr   r   )r	   r   rU   	data_hashcombineds        r   generate_uuid_from_audio_datar     s     *ell+>>#))+ x//12<<>I[$(~~hoo/0::<<r   r#   )r    r.   r/   r0   r1   c                 4    t         j                  | ||||      S )a3  
    Convenience function: save audio (using default configuration)
    
    Args:
        audio_data: Audio data
        output_path: Output path
        sample_rate: Sample rate
        format: Format (default flac)
        channels_first: Tensor format flag
    
    Returns:
        Saved file path
    )_default_saverrY   )r	   r.   r/   r0   r1   s        r   rY   rY     s"    ( $$Kfn r   )g      )Nrw   )!r|   ior   r   
subprocessr   pathlibr   typingr   r   r   r   r   rL   r   rH   logurur   r   r@   rB   r   r   rJ   r   r   r   r}   r   r   r~   rY   r   r   r   <module>r      sW   
  	    / /    &ellBJJ&> ? &E &]bchcocoqsq{q{c{]| &Tn nb95# 95xKs K4c * ellBJJ./
3- 	> 62  ellBJJ./sDy!  SM	
  	r   