
    (HJjB                        d 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	 ddl
Zdddddd	d	d
dZddddZdedefdZde	eeef   deej"                  eef   fdZ	 	 d$de	eeej(                  f   dededeej"                  ef   fdZdefdZdefdZ	 	 d%dej"                  dedede	eeej(                  f   dededdfd Z	 d&de	eeej(                  f   dej"                  dedee   ddf
d!Z	 d'de	eeej(                  f   dedeej"                  ef   fd"Z	 d&de	eeej(                  f   dej"                  dedee   ddf
d#Zy)(a]  Audio I/O utilities using miniaudio.

This module provides functions for reading and writing audio files.
- Reading: Uses miniaudio to support WAV, MP3, FLAC, and Vorbis formats.
           Uses ffmpeg for M4A/AAC, OGG, Opus, and WebM format support.
- Writing: Uses miniaudio for WAV and ffmpeg for MP3, FLAC, OGG, Opus, Vorbis, and WebM encoding.
    N)Path)OptionalTupleUnionwavmp3flacvorbism4awebm)r   r   r	   oggr
   r   aacr   SIGNED16SIGNED32FLOAT32)int16int32float32datareturnc                     | dd dk(  r	| dd dk(  ry| dd d	k(  s| d
d dk(  s| d
d dk(  ry| dd dk(  ry| dd dk(  ry| dd dk(  ry| dd dk(  ryt        d      )z6Detect audio format from bytes data using magic bytes.N   s   RIFF      s   WAVEr      s   ID3r      s   s   r   s   fLaCr	      OggSr
      ftypr      Eߣr   z(Unable to detect audio format from bytes)
ValueError)r   s    \/Users/ahmed/devFolder/claude-voice/.venv/lib/python3.12/site-packages/mlx_audio/audio_io.py_detect_format_from_bytesr"   %   s    BQx7tAbzW4	bqV	Qq	[ 8D1I<T	bqW		bqW		ag		bq(	(CDD    
input_datac                    t        j                  d      }|t        d      t        j                  d      }|t        d      t        | t              r%|dddd	d
ddddg
}t        j                  || d      }n+|dddd	d
ddt        |       g	}t        j                  |d      }|j                  dk7  r&t        d|j                  j                                ddl}|j                  |j                  j                               }|j                  d      st        d      |d   d   }t        |j                  dd            }t        |j                  dd            }	t        | t              r9|dddddddt        |      dt        |	      d g}
t        j                  |
| d      }n@|dt        |       dddddt        |      dt        |	      d g}
t        j                  |
d      }|j                  dk7  r&t        d!|j                  j                                t!        j"                  |j                  t         j$                  "      }|||	fS )#a>  Decode audio using ffmpeg (for formats not supported by miniaudio like M4A).

    Args:
        input_data: Path to the audio file or raw bytes data.

    Returns:
        Tuple of (samples as int16 numpy array, sample_rate, nchannels).

    Raises:
        RuntimeError: If ffmpeg is not found or decoding fails.
    ffmpegNz
========================================
  ffmpeg not found!
========================================

ffmpeg is required for M4A/AAC/WebM audio decoding.

Install ffmpeg:
  macOS:  brew install ffmpeg
  Ubuntu: sudo apt install ffmpeg
ffprobez1ffprobe not found (usually installed with ffmpeg)z-vquietz-print_formatjsonz-show_streamsz-select_streamsza:0-ipipe:0Tinputcapture_output)r.   r   zffprobe failed: streamszNo audio streams found in filesample_rateiD  channelsr   -fs16lez-acodec	pcm_s16le-ar-acpipe:1zffmpeg decoding failed: dtype)shutilwhichRuntimeError
isinstancebytes
subprocessrunstr
returncodestderrdecoder)   loadsstdoutgetintnp
frombufferr   )r$   ffmpeg_pathffprobe_path	probe_cmdprobe_resultr)   
probe_infostreamr0   	nchannels
decode_cmddecode_resultsampless                r!   _decode_ffmpegrU   9   sq    ,,x(K	2
 	
 <<	*LNOO*e$ 
	 "~~
 
O

	 "~~iE!#-l.A.A.H.H.J-KLMML//6689J>>)$;<<	"1%Ffjj67KFJJz1-.I *e$	N

 #
 
O	N

 #z$G1$5m6J6J6Q6Q6S5TUVV mmM00AGK**r#   file	always_2dr9   c                 4   d}t        | t        t        f      r9t        |       j                  j	                  d      j                         }|dv rjd}ngt        | t        j                        rM| j                  d       | j                  d      }| j                  d       |dd d	k(  s|d
d dk(  s|d
d dk(  rd}|rOt        | t        j                        r"| j                  d       | j                         }n| }t        |      \  }}}	ndd
l}
t        | t        t        f      rL|
j                  t        |             }|
j                  t        |       |j                  |j                        }nt        | t        j                        r| j                  d       | j                         }t!        |      }|dk(  r|
j#                  |      }nS|dk(  r|
j%                  |      }n<|dk(  r|
j'                  |      }n%|dk(  r|
j)                  |      }nt+        d|       |
j-                  ||j                  |j                        }nt/        dt1        |              |j                  }|j                  }	t3        j4                  |j6                  t2        j8                        }|	dkD  r|j;                  d|	      }|dv r|j=                  |      dz  }n|dk(  rn|j=                  |      }|r&|j>                  dk(  r|d
d
t2        j@                  f   }||fS )a  Read an audio file using miniaudio (or ffmpeg for M4A/AAC/OGG/Opus/WebM).

    Args:
        file: Path to the audio file or a BytesIO object.
        always_2d: If True, always return a 2D array (samples, channels).
        dtype: Data type for the output array. Supports 'float32', 'float64', 'int16'.

    Returns:
        Tuple of (audio_data, sample_rate).
        audio_data is a numpy array with shape (samples,) for mono or (samples, channels) for multi-channel.
    F.)r   r   r   opusr   Tr   r   r   r   r   Nr   r   )rQ   r0   r   r   r	   r
   zUnsupported format: zUnsupported file type: r8      )r   float64g      @r   )!r=   rA   r   suffixlstriplowerioBytesIOseekreadrU   	miniaudioget_file_infodecode_filerQ   r0   r"   wav_get_infomp3_get_infoflac_get_infovorbis_get_infor    rD   	TypeErrortyperI   arrayrT   r   reshapeastypendimnewaxis)rV   rW   r9   
use_ffmpegextheaderr$   rT   r0   rQ   re   infodecodedr   fmts                  r!   rd   rd      s   " J$d$4j&&s+11377J	D"**	%		!2		!1QK7"bqzW$bqz00JdBJJ'IIaLJJ*8*D'i 	dS$K(**3t95D++D	.. ,, , G
 bjj)IIaL99;D+D1Ce| --d3 --d3 ..t4 006 #7u!=>>&&.. ,, ' G 5d4j\BCC))%%	 ((7??"((; 1}//"i0 &&..''1	'	..' W\\Q&!RZZ-(Kr#   c                  0    t        j                  d      duS )z+Check if ffmpeg is available on the system.r&   N)r:   r;    r#   r!   _check_ffmpeg_availabler{     s    <<!--r#   c                  J    t        j                  d      } | t        d      | S )zGet the path to ffmpeg executable.

    Returns:
        Path to ffmpeg executable.

    Raises:
        RuntimeError: If ffmpeg is not found.
    r&   a?  
========================================
  ffmpeg not found!
========================================

ffmpeg is required for MP3/FLAC/WebM encoding and M4A/AAC/WebM decoding.

Install ffmpeg:
  macOS:  brew install ffmpeg
  Ubuntu: sudo apt install ffmpeg

Alternatively, use WAV format which doesn't require ffmpeg.
)r:   r;   r<   )rK   s    r!   _get_ffmpeg_pathr}   #  s3     ,,x(KL
 	
 r#   
sampleraterQ   outputformatbitratec           
         t               }| j                  dk(  r| j                         }n| j                         j                         }|ddddt	        |      dt	        |      ddg
}|d	k(  r|j                  d
|g       nM|dk(  r|j                  ddd
|g       n2|dk(  r|j                  ddd
|g       n|dv r|j                  ddg       |dk(  rd}|j                  d|g       t        |t        j                        r|j                  d       t        j                  ||d      }	|	j                  dk7  r&t        d|	j                  j                                |j!                  |	j"                         |j%                  d       y|j                  t	        |             t        j                  ||d      }	|	j                  dk7  r&t        d|	j                  j                                y)a}  Encode audio using ffmpeg.

    Args:
        data: Audio data as int16 numpy array (samples,) or (samples, channels)
        samplerate: Sample rate in Hz
        nchannels: Number of channels
        output: Output file path or BytesIO object
        format: Output format (mp3, flac, ogg, opus, vorbis, etc.)
        bitrate: Audio bitrate for lossy formats (default: 128k)
    r[   z-yr2   r3   r5   r6   r*   r+   r   z-b:arZ   z-c:alibopusr   )r   r
   r	   r
   r   r7   Tr,   r   zffmpeg failed: N)r}   rq   tobytesflattenrA   extendr=   ra   rb   appendr?   r@   rB   r<   rC   rD   writerF   rc   )
r   r~   rQ   r   r   r   rK   	pcm_bytescmdresults
             r!   _encode_ffmpegr   ?  s   $ #$K yyA~LLN	LLN**,	 	JIC 

FG$%	6	

FIvw78	6	

FIvw78	$	$ 	

FF#$ JJf~&"**%

8

 !1E1E1G0HIJJV]]#A

3v;

 !1E1E1G0HIJJ "r#   c                    ddl }|Kt        | t        t        f      r3t        |       j                  j                  d      j                         }nd}|j                         }t        |t        j                        sst        |d      r0t        |d      s$t        j                  |j                               }n7t        |d      rt        j                  |      }nt        j                  |      }|j                  t        j                  t        j                  fv r:t        j                   |dd      }|d	z  j#                  t        j$                        }n<|j                  t        j$                  k7  r|j#                  t        j$                        }|j&                  d
k(  rd
}|}n|j(                  d
   }|j+                         }|dk(  s|dk(  rt|j-                         }t        | t.        j0                        r#| j3                  |       | j5                  d       yt7        | d      5 }|j3                  |       ddd       y|dk(  rddl
}	|	j                  d|j                               }
|j9                  d|||j:                  j<                  |
      }t        | t.        j0                        rddl}|jA                  dd      5 }|jB                  }ddd       	 |jE                  |       t7        |d      5 }| j3                  |jG                                ddd       | j5                  d       ddl$}|jK                  |       y|jE                  t        |       |       y|dv rItM               s.ddl'}|jQ                  d|jS                          dtT        d       tW        |||| |       ytY        d|       # 1 sw Y   yxY w# 1 sw Y   xY w# 1 sw Y   xY w# ddl$}|jK                         w xY w)a=  Write audio data to a file.

    Args:
        file: Path to the output file or a BytesIO object.
        data: Audio data as numpy array. Shape can be (samples,) for mono
              or (samples, channels) for multi-channel.
        samplerate: Sample rate in Hz.
        format: Output format. Supports 'wav', 'flac', 'mp3', 'ogg', 'opus', 'vorbis', 'webm'.
                If None, inferred from file extension.

    Note:
        WAV uses miniaudio for encoding.
        MP3, FLAC, OGG, Opus, Vorbis, and WebM use ffmpeg (must be installed: brew install ffmpeg).
    r   NrY   r   tolist	__array__g      g      ?i  r[   pcmrawwbhr   )namerQ   r0   sample_formatrT   z.wavF)r^   deleterb)r	   r   r   rZ   r
   r   zffmpeg is required for z encoding but was not found. Install with: brew install ffmpeg (macOS) or sudo apt install ffmpeg (Ubuntu). Falling back will fail - consider using WAV format instead.r   )
stacklevelr   zUnsupported output format: )-re   r=   rA   r   r^   r_   r`   rI   ndarrayhasattrrn   r   asarrayr9   r   r]   cliprp   r   rq   shaper   r   ra   rb   r   rc   openDecodedSoundFileSampleFormatr   tempfileNamedTemporaryFiler   wav_write_filerd   osunlinkr{   warningswarnupperRuntimeWarningr   r    )rV   r   r~   r   re   rQ   samples_flatr   frn   samples_arraysoundr   tmptmp_pathr   r   s                    r!   r   r     s0   (  ~dS$K($Z&&--c288:FF\\^F dBJJ'4"74+E88DKKM*DT;'::d#D88D>D zzbjj"**--wwtT3'u$$RXX.	rxx	{{288$ yyA~	JJqM	||~&E/ ((*	dBJJ'JJy!IIaLdD!Q	" "! 
5 C)<)<)>? **"#0099! + 
 dBJJ',,F5,IS88 J$((59(D)QJJqvvx( *		!		(#$$SY6	C	C&(MM)&,,.)9 :N N    	tZDH6vh?@@e "!, JI *) 		(#s<   'OOO% ; OO% O
OO"O% %O<c                     t        | |d      S )a  Read audio file (soundfile-compatible API).

    This is a drop-in replacement for soundfile.read().

    Args:
        file: Path to audio file or BytesIO object.
        always_2d: If True, always return 2D array.

    Returns:
        Tuple of (data, samplerate).
    r]   )rW   r9   )rd   )rV   rW   s     r!   sf_readr     s     	;;r#   c                 "    t        | |||       y)a+  Write audio file (soundfile-compatible API).

    This is a drop-in replacement for soundfile.write().

    Args:
        file: Path to output file or BytesIO object.
        data: Audio data as numpy array.
        samplerate: Sample rate in Hz.
        format: Output format (wav, flac, mp3).
    r   N)r   )rV   r   r~   r   s       r!   sf_writer     s      
$j0r#   )Fr]   )r   128k)N)F)__doc__ra   r:   r?   pathlibr   typingr   r   r   numpyrI   _FORMAT_MAP_SAMPLE_FORMAT_MAPr>   rA   r"   r   rH   rU   rb   boolrd   r{   r}   r   r   r   r   rz   r#   r!   <module>r      so   
    ) )  	  EE Ec E(|+c4&'|+
2::sC |+B c 
T2::%
&c c  c  2::s?	c L. .
# B NK
**NKNK NK #tRZZ'(	NK
 NK NK 
NKj !	sA
T2::%
&sA
**sA sA SM	sA
 
sAr <
T2::%
&<< 2::s?<, !	1
T2::%
&1
**1 1 SM	1
 
1r#   