Ë
    îÿæi	A  ã                   ó�  — 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
œ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)'aB  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 format support.
- Writing: Uses miniaudio for WAV and ffmpeg for MP3, FLAC, OGG, Opus, and Vorbis encoding.
é    N)ÚPath)ÚOptionalÚTupleÚUnionÚwavÚmp3ÚflacÚvorbisÚm4a)r   r   r	   Úoggr
   r   ÚaacÚ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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   z(Unable to detect audio format from bytes)Ú
ValueError)r   s    úg/Volumes/fast/ai/experiments/voice-extract-mac/.venv/lib/python3.12/site-packages/mlx_audio/audio_io.pyÚ_detect_format_from_bytesr    $   sŠ   € àˆBˆQ€x�7Ò˜t A b˜z¨WÒ4ØØ	ˆbˆqˆ�VÒ	  Q q 	¨[Ò 8¸DÀÀ1¸IÈÒ<TØØ	ˆbˆqˆ�WÒ	ØØ	ˆbˆqˆ�WÒ	ØØ	ˆa�ˆ�gÒ	àäÐ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 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Ústreamr.   Ú	nchannelsÚ
decode_cmdÚdecode_resultÚsampless                r   Ú_decode_ffmpegrS   5   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Ó9€JØ�>‰>˜)Ô$ÜÐ;Ó<Ð<à˜	Ñ" 1Ñ%€FÜ�f—j‘j °Ó6Ó7€KÜ�F—J‘J˜z¨1Ó-Ó.€Iô �*œeÔ$àØØØØØØØÜ�ÓØÜ�	‹NØð
ˆ
ô #Ÿ™ØØØô
‰ð ØÜ�
‹OØØØØØÜ�ÓØÜ�	‹NØð
ˆ
ô #Ÿ™ zÀ$ÔGˆà×Ñ 1Ò$ÜÐ5°m×6JÑ6J×6QÑ6QÓ6SÐ5TÐUÓVÐVô �m‰m˜M×0Ñ0¼¿¹ÔA€Gà�K Ð*Ð*r!   ÚfileÚ	always_2dr7   c                 ó$  — d}t        | t        t        f«      r9t        | «      j                  j	                  d«      j                  «       }|dv rbd}n_t        | t        j                  «      rE| j                  d«       | j                  d«      }| j                  d«       |dd d	k(  s|d
d dk(  rd}|rOt        | t        j                  «      r"| j                  d«       | j                  «       }n| }t        |«      \  }}}	�n�dd
l}
t        | t        t        f«      rL|
j                  t        | «      «      }|
j                  t        | «      |j                  |j                  ¬«      }nðt        | 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).

    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   ÚopusTr   r   r   r   r   Nr   )rO   r.   r   r   r	   r
   zUnsupported format: zUnsupported file type: r6   é   éÿÿÿÿ)r   Úfloat64g      à@r   )!r;   r?   r   ÚsuffixÚlstripÚlowerÚioÚBytesIOÚseekÚreadrS   Ú	miniaudioÚget_file_infoÚdecode_filerO   r.   r    Úwav_get_infoÚmp3_get_infoÚflac_get_infoÚvorbis_get_infor   rB   Ú	TypeErrorÚtyperG   ÚarrayrR   r   ÚreshapeÚastypeÚndimÚnewaxis)rT   rU   r7   Ú
use_ffmpegÚextÚheaderr"   rR   r.   rO   rc   ÚinfoÚdecodedr   Úfmts                  r   rb   rb   ´   s¶  € ð" €JÜ�$œœd˜Ô$Ü�4‹j×Ñ×&Ñ& sÓ+×1Ñ1Ó3ˆØÐ/Ñ/Ø‰JÜ	�Dœ"Ÿ*™*Ô	%Ø�	‰	�!ŒØ—‘˜2“ˆØ�	‰	�!ŒØ�!�Aˆ;˜'Ò! V¨B¨Q Z°7Ò%:ØˆJáä�dœBŸJ™JÔ'Ø�I‰I�aŒLØŸ™›‰JàˆJÜ*8¸Ó*DÑ'ˆ�šió 	ä�dœS¤$˜KÔ(à×*Ñ*¬3¨t«9Ó5ˆDØ×+Ñ+Ü�D“	ØŸ.™.Ø ×,Ñ,ð ,ó ‰Gô
 ˜œbŸj™jÔ)Ø�I‰I�aŒLØ—9‘9“;ˆDä+¨DÓ1ˆCØ�eŠ|Ø ×-Ñ-¨dÓ3‘Ø˜’Ø ×-Ñ-¨dÓ3‘Ø˜’Ø ×.Ñ.¨tÓ4‘Ø˜’Ø ×0Ñ0°Ó6‘ä Ð#7¸°uÐ!=Ó>Ð>Ø×&Ñ&ØØŸ.™.Ø ×,Ñ,ð 'ó ‰Gô Ð5´d¸4³j°\ÐBÓCÐCà×)Ñ)ˆØ×%Ñ%ˆ	ô —(‘(˜7Ÿ?™?´"·(±(Ô;ˆð �1‚}Ø—/‘/ " iÓ0ˆð Ð&Ñ&Ø—.‘. Ó'¨'Ñ1‰Ø	�'Ò	Øà—.‘. Ó'ˆñ �W—\‘\ QÒ&Øš!œRŸZ™Z˜-Ñ(ˆà�KÐÐr!   c                  ó0   — t        j                  d«      duS )z+Check if ffmpeg is available on the system.r$   N)r8   r9   © r!   r   Ú_check_ffmpeg_availablery     s   € ä�<‰<˜Ó!¨Ð-Ð-r!   c                  óJ   — t        j                  d«      } | €t        d«      ‚| S )z“Get the path to ffmpeg executable.

    Returns:
        Path to ffmpeg executable.

    Raises:
        RuntimeError: If ffmpeg is not found.
    r$   a5  
========================================
  ffmpeg not found!
========================================

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

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

Alternatively, use WAV format which doesn't require ffmpeg.
)r8   r9   r:   )rI   s    r   Ú_get_ffmpeg_pathr{     s3   € ô —,‘,˜xÓ(€KØÐÜðLó
ð 	
ð Ðr!   Ú
sampleraterO   Ú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«       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)
    rY   z-yr0   r1   r3   r4   r(   r)   r   z-b:arX   z-c:aÚlibopus)r   r
   r	   r
   r   r5   Tr*   r   zffmpeg failed: N)r{   ro   ÚtobytesÚflattenr?   Úextendr;   r_   r`   Úappendr=   r>   r@   r:   rA   rB   ÚwriterD   ra   )
r   r|   rO   r}   r~   r   rI   Ú	pcm_bytesÚcmdÚresults
             r   Ú_encode_ffmpegrŠ   7  s±  € ô$ #Ó$€Kð ‡y�y�A‚~Ø—L‘L“N‰	à—L‘L“N×*Ñ*Ó,ˆ	ð 	ØØØØÜˆJ‹ØÜˆI‹ØØð€Cð �‚Ø�
‰
�F˜GÐ$Õ%Ø	�6Ò	Ø�
‰
�F˜I v¨wÐ7Õ8Ø	Ð$Ñ	$ð 	�
‰
�F˜FÐ#Ô$ð �ÒØˆà‡J�J��fˆ~Ôä�&œ"Ÿ*™*Ô%Ø�
‰
�8ÔÜ—‘ØØØô
ˆð
 ×Ñ Ò!Ü °·±×1EÑ1EÓ1GÐ0HÐIÓJÐJØ�‰�V—]‘]Ô#Ø�‰�A�à�
‰
”3�v“;ÔÜ—‘ØØØô
ˆð
 ×Ñ Ò!Ü °·±×1EÑ1EÓ1GÐ0HÐ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                  «      ršd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'.
                If None, inferred from file extension.

    Note:
        WAV uses miniaudio for encoding.
        MP3, FLAC, OGG, Opus, and Vorbis use ffmpeg (must be installed: brew install ffmpeg).
    r   NrW   r   ÚtolistÚ	__array__g      ð¿g      ð?iÿ  rY   ÚpcmÚrawÚwbÚhr}   )ÚnamerO   r.   Úsample_formatrR   z.wavF)r\   ÚdeleteÚrb)r	   r   r   rX   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: )-rc   r;   r?   r   r\   r]   r^   rG   ÚndarrayÚhasattrrl   rŒ   Úasarrayr7   r   r[   Úcliprn   r   ro   Úshaperƒ   r‚   r_   r`   r†   ra   ÚopenÚDecodedSoundFileÚSampleFormatr   ÚtempfileÚNamedTemporaryFiler’   Úwav_write_filerb   ÚosÚunlinkry   ÚwarningsÚwarnÚupperÚRuntimeWarningrŠ   r   )rT   r   r|   r~   rc   rO   Úsamples_flatr‡   Úfrl   Úsamples_arrayÚsoundr    ÚtmpÚtmp_pathr£   r¥   s                    r   r†   r†   †  s0  € ó( ð €~Ü�dœS¤$˜KÔ(Ü˜$“Z×&Ñ&×-Ñ-¨cÓ2×8Ñ8Ó:‰FàˆFà�\‰\‹^€Fô �dœBŸJ™JÔ'ä�4˜Ô"¬7°4¸Ô+EÜ—8‘8˜DŸK™K›MÓ*‰DÜ�T˜;Ô'Ü—:‘:˜dÓ#‰Dä—8‘8˜D“>ˆDð ‡z�z”b—j‘j¤"§*¡*Ð-Ñ-ä�w‰w�t˜T 3Ó'ˆØ�u‘×$Ñ$¤R§X¡XÓ.‰Ø	�‰”r—x‘xÒ	Ø�{‰{œ2Ÿ8™8Ó$ˆð ‡y�y�A‚~Øˆ	Ø‰à—J‘J˜q‘Mˆ	Ø—|‘|“~ˆà�‚˜& Eš/à ×(Ñ(Ó*ˆ	ä�dœBŸJ™JÔ'Ø�J‰J�yÔ!Ø�I‰I�a�Lä�d˜DÔ! QØ—‘˜	Ô"÷ "Ð!ð 
�5‹Ûð Ÿ™ C¨×)<Ñ)<Ó)>Ó?ˆð ×*Ñ*ØØØ"Ø#×0Ñ0×9Ñ9Ø!ð +ó 
ˆô �dœBŸJ™JÔ'ãà×,Ñ,°FÀ5Ð,ÔIÈSØŸ8™8�÷ Jð$Ø×(Ñ(¨°5Ô9Ü˜( DÔ)¨QØ—J‘J˜qŸv™v›xÔ(÷ *à—	‘	˜!”ãà—	‘	˜(Õ#à×$Ñ$¤S¨£Y°Õ6à	Ð;Ñ	;ä&Ô(Ûà�M‰MØ)¨&¯,©,«.Ð)9ð :Nð Nô Øð ô ô 	�t˜Z¨°DÀÖHäÐ6°v°hÐ?Ó@Ð@÷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[   )rU   r7   )rb   )rT   rU   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†   )rT   r   r|   r~   s       r   Úsf_writer²     s   € ô  
ˆ$��j¨Ö0r!   )Fr[   )r   Ú128k)N)F)Ú__doc__r_   r8   r=   Úpathlibr   Útypingr   r   r   ÚnumpyrG   Ú_FORMAT_MAPÚ_SAMPLE_FORMAT_MAPr<   r?   r    r˜   rF   rS   r`   Úboolrb   ry   r{   rŠ   r†   r°   r²   rx   r!   r   Ú<module>r»      sl  ðñó 
Û Û Ý ß )Ñ )ã ð ØØØØØØñ€ð ØØñÐ ðE Eð E¨có Eð"|+Ø�c˜4 Ð&Ñ'ð|+à
ˆ2�:‰:�s˜CÐÑ ó|+ðB Øñ_ Ø
��T˜2Ÿ:™:Ð%Ñ
&ð_ àð_ ð ð_ ð ˆ2�:‰:�sˆ?Ñó	_ ðD. ó .ð
˜#ó ðB ØñLKØ
�*‰*ðLKàðLKð ðLKð �#�t˜RŸZ™ZÐ'Ñ(ð	LKð
 ðLKð ðLKð 
óLKðf !ñ	sAØ
��T˜2Ÿ:™:Ð%Ñ
&ðsAà
�*‰*ðsAð ðsAð �S‰Mð	sAð
 
ósAðr ñ<Ø
��T˜2Ÿ:™:Ð%Ñ
&ð<àð<ð ˆ2�:‰:�sˆ?Ñó<ð, !ñ	1Ø
��T˜2Ÿ:™:Ð%Ñ
&ð1à
�*‰*ð1ð ð1ð �S‰Mð	1ð
 
ô1r!   