Kivy Audiostream

repository·master·Indexed 42 days ago

https://github.com/kivy/audiostream

A low-level Python extension providing direct access to audio hardware for pushing bytes to speakers or retrieving bytes from a microphone. It features an AudioOutput mixer for managing AudioSample instances, a ThreadSource for custom audio generators, and platform-specific support for audio input on Android and iOS.

Tokens
2.4K
Snippets
9
Records
13
Agent score
51%

What's inside Audiostream

  1. Overview of Audiostream capabilities

    master

    Audiostream is a Python extension designed for handling real-time audio streams. It provides a high-level API for two primary tasks:

    1. Audio Output: Streaming raw bytes directly to the device's speakers.
    2. Audio Input: Reading audio data from an input stream (e.g., a microphone).

    Implementation Details:

    • Output: Uses SDL and SDL_Mixer for streaming audio out.
    • Input: Uses platform-specific APIs for reading audio input.
    • Platform Support: Works on desktop, as well as Android and iOS.
  2. How Audiostream works

    master

    Audiostream is designed to be a low-level interface for audio streams. It operates on a byte-oriented model:

    • Speaker Output: You push raw bytes to the speaker.
    • Microphone Input: You receive raw bytes from the microphone.
  3. Install Audiostream

    master

    Audiostream is a Python extension for direct access to speakers and microphones. To install it, you must have Cython installed for the compilation process. Note that running the provided examples requires Kivy to be installed in your environment.

    Use the following command to install the extension from the source directory:

    sudo python setup.py install
  4. Generate and stream a sine wave to a speaker

    master

    To play a generated waveform, use get_output to create an output stream and SineSource to generate the audio. You can dynamically update the frequency property of the SineSource instance while it is running to change the pitch in real-time.

    from time import sleep
    from audiostream import get_output
    from audiostream.sources.wave import SineSource
    
    # get a output stream where we can play samples
    stream = get_output(channels=2, rate=22050, buffersize=1024)
    
    # create one wave sin() at 440Hz, attach it to our speaker, and play
    sinsource = SineSource(stream, 440)
    sinsource.start()
    
    # you can change the frequency of the source during the playtime
    for x in xrange(10):
        sinsource.frequency = 440 + x
        sleep(.5)
    
    # ok we are done, stop everything.
    sinsource.stop()
  5. Read audio data from a microphone

    master

    To capture audio input, use get_input and provide a callback function. The callback function will be invoked whenever new audio data is received.

    Android Note: To record microphone audio on Android, your application must have the RECORD_AUDIO permission.

    from time import sleep
    from audiostream import get_input
    
    # declare a callback where we'll receive the data
    def callback_mic(data):
        print('i got', len(data))
    
    # get the microphone (or from another source if available)
    mic = get_input(callback=callback_mic)
    mic.start()
    sleep(5)
    mic.stop()
  6. Initialize audio output with get_output()

    master

    Use get_output() to initialize the audio engine and obtain an AudioOutput instance. This method should typically be called only once at the start of your application. It manages the mixing of multiple AudioSample instances.

    Parameters:

    • rate (int): Audio rate (e.g., 44100). Default is 44100.
    • channels (int): Number of channels (minimum 1). Default is 2.
    • encoding (int): Audio encoding, either 8 or 16. Default is 16.
    • buffersize (int): Size of the output buffer. Smaller buffers increase reactivity but consume more CPU.
    from audiostream import get_output
    stream = get_output(channels=2, rate=22050, buffersize=1024)
  7. Implement a custom generator with ThreadSource

    master

    To implement a custom audio generator that runs in its own thread, subclass audiostream.sources.thread.ThreadSource. This is the preferred way to provide continuous audio data to an AudioOutput.

    Requirements:

    • You must implement the get_bytes() method.
    • get_bytes() must return a bytes object containing the data to be stored in the ring buffer.
    from audiostream.sources.thread import ThreadSource
    
    class MyGenerator(ThreadSource):
        def __init__(self, stream):
            super().__init__(stream)
    
        def get_bytes(self) -> bytes:
            # Return your generated audio bytes here
            return b"\x00\x00" 
  8. Generate audio bytes with AudioSample

    master

    The AudioSample class is used to generate bytes that are consumed by an AudioOutput. Data is written to an internal RingBuffer.

    Behavior:

    • Underrun: If you don't write enough data, the library fills the gap with \x00.
    • Overrun: If you write too much, the .write() method will block until space is available.
    • Recommendation: For custom generators, use audiostream.sources.ThreadSource instead of raw AudioSample to avoid blocking issues.

    Methods:

    • write(chunk): Writes a bytes chunk into the ring buffer.
    • play(): Starts playback using the internal ring buffer.
    • stop(): Stops playback.
    from audiostream import get_output, AudioSample
    stream = get_output(channels=1, buffersize=1024, rate=22050)
    sample = AudioSample()
    stream.add_sample(sample)
    
    sample.play()
    while True:
        # Write raw bytes to the sample
        sample.write(b"\x00\x00\x00\x00\xff\xff\xff\xff")
  9. Capture audio input with get_input()

    master

    Use get_input() to obtain an AudioInput instance for recording audio.

    Important Lifecycle:

    1. Call get_input() to initialize.
    2. Call .start() to begin gathering data.
    3. Crucially, you must call .poll() regularly in your main loop. The callback function is only triggered when .poll() is called.
    4. Call .stop() to cease recording.

    Note: This function is currently only supported on Android and iOS.

    Parameters:

    • callback (callable): Function called when bytes are available. It receives one parameter (the data buffer).
    • source (str): The device to read from (e.g., 'default', 'mic'). Use get_input_sources() to see available options.
    • rate (int): Audio rate.
    • channels (int): Number of channels.
    • encoding (int): 8 or 16 bit encoding.
    • buffersize (int): Input buffer size. If <= 0, the system sizes it automatically.
    from audiostream import get_input
    
    def mic_callback(buf):
        print('got', len(buf))
    
    # get the default audio input (mic on most cases)
    mic = get_input(callback=mic_callback)
    mic.start()
    
    # In your application loop:
    while not quit:
        mic.poll()
    
    mic.stop()
  10. Use PureData patches with PatchSource

    master

    The PatchSource allows you to load a PureData patch and use its generated output as an audio source. This requires the pylibpd library.

    Usage:

    • Initialize with an AudioOutput instance and the path to your .pd patch file.
    from audiostream import get_output
    from audiostream.sources.puredata import PatchSource
    
    stream = get_output()
    patch = PatchSource(stream, patchfile="path/to/your/patch.pd")
    stream.add_sample(patch)
    patch.play()
  11. Generate a sine wave with SineSource

    master

    The SineSource is a built-in ThreadSource that generates a sine wave at a specific frequency.

    Usage:

    • Initialize with an AudioOutput instance and the desired frequency (e.g., 440 for A4).
    from audiostream import get_output
    from audiostream.sources.wave import SineSource
    
    stream = get_output()
    sine = SineSource(stream, frequency=440)
    stream.add_sample(sine)
    sine.play()
  12. List available audio input sources

    master

    Use get_input_sources() to retrieve a list of available input device strings. This is platform-dependent and currently only works on Android and iOS.

    Available sources by platform:

    • Android: 'camcorder', 'default', 'mic', 'voice_call', 'voice_communication', 'voice_downlink', 'voice_recognition', 'voice_uplink'
    • iOS: 'default'