pyminiaudio

repository·master·Indexed 41 days ago

https://github.com/irmen/pyminiaudio

Python bindings for the miniaudio C library (version 1.72), providing multiplatform audio playback, recording, decoding, and sample format conversion. It supports native decoders for MP3, FLAC, Ogg Vorbis, and WAV, and allows streaming from files or memory via PlaybackDevice and CaptureDevice.

Tokens
2.8K
Snippets
9
Records
13
Agent score
2%

What's inside pyminiaudio

  1. Install pyminiaudio

    master

    Install miniaudio via PyPI for most platforms. For Raspberry Pi, use PiWheels to obtain pre-built binaries.

    Requirements:

    • Python 3.10 or newer
    • Works on pypy3 (via cffi)

    Supported Decoders:

    • wav, flac, vorbis, and mp3
    pip install miniaudio
  2. Play unsupported formats using external decoders (e.g., ffmpeg)

    master

    If a format is not natively supported by miniaudio, you can pipe raw PCM data from an external tool like ffmpeg into a miniaudio.PlaybackDevice. This is achieved by creating a Python generator that yields chunks of bytes from the external process's stdout.

    import subprocess
    import miniaudio
    
    channels = 2
    sample_rate = 44100
    sample_width = 2  # 16 bit pcm
    filename = "samples/music.m4a"  # AAC encoded audio file
    
    def stream_pcm(source):
        required_frames = yield b""  # generator initialization
        while True:
            required_bytes = required_frames * channels * sample_width
            sample_data = source.read(required_bytes)
            if not sample_data:
                break
            print(".", end="", flush=True)
            required_frames = yield sample_data
    
    with miniaudio.PlaybackDevice(output_format=miniaudio.SampleFormat.SIGNED16,
                                  nchannels=channels, sample_rate=sample_rate) as device:
        ffmpeg = subprocess.Popen(["ffmpeg", "-v", "fatal", "-hide_banner", "-nostdin",
                                   "-i", filename, "-f", "s16le", "-acodec", "pcm_s16le",
                                   "-ac", str(channels), "-ar", str(sample_rate), "-"],
                                  stdin=None, stdout=subprocess.PIPE)
        stream = stream_pcm(ffmpeg.stdout)
        next(stream)  # start the generator
        device.start(stream)
        input("Audio file playing in the background. Enter to stop playback: ")
        ffmpeg.terminate()
  3. Basic audio file playback with info

    master

    To play an audio file, first retrieve its properties using miniaudio.get_file_info(). Then, create a stream using miniaudio.stream_file() and pass it to a miniaudio.PlaybackDevice instance. Using the PlaybackDevice as a context manager ensures the device is properly closed.

    import miniaudio
    
    # Get file info
    info = miniaudio.get_file_info("samples/music.mp3")
    print(f"Playing: {info.nchannels} channels, {info.sample_rate} Hz, {info.duration:.1f}s")
    
    # Stream and play
    stream = miniaudio.stream_file("samples/music.mp3")
    with miniaudio.PlaybackDevice() as device:
        device.start(stream)
        input("Playing... press Enter to stop")
  4. Decode and convert audio files

    master

    You can decode audio files into specific sample formats (like miniaudio.SampleFormat.FLOAT32) using miniaudio.decode_file(). To change the format or sample rate, use miniaudio.convert_frames(). Finally, you can write the result to a WAV file using miniaudio.wav_write_file().

    import miniaudio
    
    # Decode audio file to float32
    sound = miniaudio.decode_file("music.mp3", miniaudio.SampleFormat.FLOAT32)
    print(f"Decoded: {sound.nchannels} ch, {sound.sample_rate} Hz, {sound.num_frames} frames")
    
    # Convert to different format and sample rate
    converted = miniaudio.convert_frames(
        sound.sample_format, sound.nchannels, sound.sample_rate,
        sound.samples.tobytes(),
        miniaudio.SampleFormat.SIGNED16, sound.nchannels, 22050
    )
    
    # Write to WAV file
    miniaudio.wav_write_file("output.wav", miniaudio.DecodedSoundFile(
        "output.wav", sound.nchannels, 22050, miniaudio.SampleFormat.SIGNED16,
        converted
    ))
    print("Written to output.wav")
  5. Play audio using PlaybackDevice

    master

    The PlaybackDevice class handles audio output. To play audio, you must provide a callback generator to the .start() method. This generator is responsible for yielding the raw sample data (as bytes, memoryview, array.array, or a numpy array) required for playback.

    Note: The generator should be started before passing it to .start().

    import miniaudio
    
    def audio_generator():
        # This could be a stream_file generator
        yield from miniaudio.stream_file('test.wav')
    
    device = miniaudio.PlaybackDevice()
    gen = audio_generator()
    # The generator must be started before passing it
    next(gen) 
    device.start(gen)
    
    # To stop playback
    device.stop()
  6. Decode audio files to raw PCM

    master

    Use decode() or decode_file() to convert any supported audio file (MP3, WAV, FLAC, Vorbis, etc.) into raw PCM samples in memory. You can specify the desired output_format (e.g., SampleFormat.FLOAT32 or SampleFormat.SIGNED16), number of channels, and sample rate.

    Returns a DecodedSoundFile object which contains the raw PCM data in a .samples attribute (an array.array).

    import miniaudio
    
    # Decode a file to 32-bit float PCM
    decoded = miniaudio.decode_file('audio.mp3', 
        output_format=miniaudio.SampleFormat.FLOAT32, 
        nchannels=2, 
        sample_rate=44100
    )
    
    # Access the raw samples
    pcm_data = decoded.samples
  7. Stream audio from files or memory

    master

    To avoid loading entire files into memory, use generator functions to stream audio in chunks.

    • stream_file(filename, ...): Streams a supported audio file from disk.
    • stream_memory(data, ...): Streams encoded audio data from a bytes-like object in memory.
    • stream_any(source, ...): Streams from any StreamableSource (like a network stream).
    • stream_raw_pcm_memory(pcmdata, ...): Streams already decoded raw PCM data.

    All these functions return a generator. You can use next(generator) to get the default chunk size, or generator.send(num_frames) to request a specific number of frames. This is ideal for feeding audio device callbacks.

    import miniaudio
    
    # Stream a file in chunks
    stream = miniaudio.stream_file('music.flac', output_format=miniaudio.SampleFormat.SIGNED16)
    
    for chunk in stream:
        # Process or play chunk
        pass
    
    # Request a specific number of frames (e.g., 512)
    chunk = stream.send(512)
  8. Record audio using CaptureDevice

    master

    The CaptureDevice class handles audio input (recording). Use the .start(callback_generator) method to begin recording. The provided generator receives the recorded audio data as an array.array matching the chosen input_format (e.g., array('h') for SIGNED16, array('f') for FLOAT32). For SIGNED24, data is sent as raw bytes.

    import miniaudio
    import array
    
    def recording_callback():
        while True:
            # Receive recorded data
            data = yield
            # data is an array.array or bytes
            print(f"Captured {len(data)} bytes")
    
    device = miniaudio.CaptureDevice(input_format=miniaudio.SampleFormat.SIGNED16)
    # Start the generator logic
    callback = recording_callback()
    next(callback)
    
    device.start(callback)
  9. Query available audio devices

    master

    Use the Devices class to list available playback and capture hardware on the system.

    • get_playbacks(): Returns a list of dictionaries containing details about playback devices.
    • get_captures(): Returns a list of dictionaries containing details about capture devices.
    import miniaudio
    
    devices = miniaudio.Devices()
    playbacks = devices.get_playbacks()
    for dev in playbacks:
        print(f"Device: {dev['name']}")