Skip to main content

saythanks Latest Version Build Status

Python miniaudio

Multiplatform audio playback, recording, decoding and sample format conversion for Linux (including Raspberri Pi), Windows, Mac and probably other systems such as BSD.

This module provides:

  • playback, recording and sound conversion, handled by the embedded cross-platform miniaudio library
  • uses their decoders for wav, flac, vorbis and mp3
  • python bindings for most of the functions offered in those libraries:
    • reading and decoding audio files
    • getting audio file properties (such as duration, number of channels, sample rate)
    • converting sample formats and frequencies
    • streaming large audio files
    • audio playback
    • audio recording
  • Audio file and Icecast internet radio streaming
  • TODO: filters
  • TODO: waveform generators

This library aims to provide a Pythonic interface to the miniaudio C library. Some of the main aspects of this are:

  • Python enums instead of just some integers for special values,
  • several classes to represent the main functions of the library,
  • generators for the Audio playback and recording
  • sample data is usually in the form of a Python array with appropriately sized elements depending on the sample width (rather than a raw block of bytes)

Requires Python 3.6 or newer. Also works on pypy3 (because it uses cffi).

The library is primarily distributed in source form so you need a C compiler to build and install this (note: the setup script takes care of the actual compilation process, no need to worry about compiling things yourself). For Linux and Mac this shouldn't be a problem. For Windows users, if the correct binary install is not available on pypi, you'll have to get it to compile as well which may be a bit of a hassle on this platform. You have to make sure that the required tools that allow you to compile Python extension modules are installed (Visual Studio or the VC++ build tools).

Software license for these Python bindings, miniaudio and the decoders: MIT

Synthesizer, modplayer?

If you like this library you may also be interested in my software FM synthesizer or my mod player which uses libxmp.

Examples

Most basic audio file playback

import miniaudio
stream = miniaudio.stream_file("samples/music.mp3")
with miniaudio.PlaybackDevice() as device:
    device.start(stream)
    input("Audio file playing in the background. Enter to stop playback: ")

Playback of an unsupported file format

This example uses ffmpeg as an external tool to decode an audio file in a format that miniaudio itself can't decode (m4a/aac in this case):

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()

API

enum class Backend names: WASAPI DSOUND WINMM COREAUDIO SNDIO AUDIO4 OSS PULSEAUDIO ALSA JACK AAUDIO OPENSL WEBAUDIO CUSTOM NULL

Operating system audio backend to use (only a subset will be available)

enum class ChannelMixMode names: RECTANGULAR SIMPLE CUSTOMWEIGHTS

How to mix channels when converting

enum class DeviceType names: PLAYBACK CAPTURE DUPLEX

Type of audio device

enum class DitherMode names: NONE RECTANGLE TRIANGLE

How to dither when converting

enum class FileFormat names: UNKNOWN WAV FLAC VORBIS MP3

Audio file format

enum class SampleFormat names: UNKNOWN UNSIGNED8 SIGNED16 SIGNED24 SIGNED32 FLOAT32

Sample format in memory

enum class SeekOrigin names: START CURRENT

How to seek() in a source

enum class ThreadPriority names: IDLE LOWEST LOW NORMAL HIGH HIGHEST REALTIME

The priority of the worker thread (default=HIGHEST)

function convert_frames (from_fmt: miniaudio.SampleFormat, from_numchannels: int, from_samplerate: int, sourcedata: bytes, to_fmt: miniaudio.SampleFormat, to_numchannels: int, to_samplerate: int) -> bytearray

Convert audio frames in source sample format with a certain number of channels, to another sample format and possibly down/upmixing the number of channels as well.

function convert_sample_format (from_fmt: miniaudio.SampleFormat, sourcedata: bytes, to_fmt: miniaudio.SampleFormat, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> bytearray

Convert a raw buffer of pcm samples to another sample format. The result is returned as another raw pcm sample buffer

function decode (data: bytes, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> miniaudio.DecodedSoundFile

Convenience function to decode any supported audio file in memory to raw PCM samples in your chosen format.

function decode_file (filename: str, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> miniaudio.DecodedSoundFile

Convenience function to decode any supported audio file to raw PCM samples in your chosen format.

function flac_get_file_info (filename: str) -> miniaudio.SoundFileInfo

Fetch some information about the audio file (flac format).

function flac_get_info (data: bytes) -> miniaudio.SoundFileInfo

Fetch some information about the audio data (flac format).

function flac_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile

Reads and decodes the whole flac audio file. Resulting sample format is 32 bits float.

function flac_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile

Reads and decodes the whole flac audio file. Resulting sample format is 32 bits float.

function flac_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile

Reads and decodes the whole flac audio file. Resulting sample format is 16 bits signed integer.

function flac_read_file_s32 (filename: str) -> miniaudio.DecodedSoundFile

Reads and decodes the whole flac audio file. Resulting sample format is 32 bits signed integer.

function flac_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile

Reads and decodes the whole flac audio data. Resulting sample format is 16 bits signed integer.

function flac_read_s32 (data: bytes) -> miniaudio.DecodedSoundFile

Reads and decodes the whole flac audio data. Resulting sample format is 32 bits signed integer.

function flac_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]

Streams the flac audio file as interleaved 16 bit signed integer sample arrays segments. This uses a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using stream_file() instead.

function get_enabled_backends () -> Set[miniaudio.Backend]

Returns the set of available backends by the compilation environment for the underlying miniaudio C library

function get_file_info (filename: str) -> miniaudio.SoundFileInfo

Fetch some information about the audio file.

function is_backend_enabled (backend: miniaudio.Backend) -> bool

Determines whether or not the given backend is available by the compilation environment for the underlying miniaudio C library

function is_loopback_supported (backend: miniaudio.Backend) -> bool

Determines whether or not loopback mode is support by a backend.

function lib_version () -> str

Returns the version string of the underlying miniaudio C library

function mp3_get_file_info (filename: str) -> miniaudio.SoundFileInfo

Fetch some information about the audio file (mp3 format).

function mp3_get_info (data: bytes) -> miniaudio.SoundFileInfo

Fetch some information about the audio data (mp3 format).

function mp3_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile

Reads and decodes the whole mp3 audio data. Resulting sample format is 32 bits float.

function mp3_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile

Reads and decodes the whole mp3 audio file. Resulting sample format is 32 bits float.

function mp3_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile

Reads and decodes the whole mp3 audio file. Resulting sample format is 16 bits signed integer.

function mp3_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile

Reads and decodes the whole mp3 audio data. Resulting sample format is 16 bits signed integer.

function mp3_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]

Streams the mp3 audio file as interleaved 16 bit signed integer sample arrays segments. This uses a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using stream_file() instead.

function read_file (filename: str, convert_to_16bit: bool = False) -> miniaudio.DecodedSoundFile

Reads and decodes the whole audio file. Miniaudio will attempt to return the sound data in exactly the same format as in the file. Unless you set convert_convert_to_16bit to True, then the result is always a 16 bit sample format.

function stream_any (source: miniaudio.StreamableSource, source_format: miniaudio.FileFormat = <FileFormat.UNKNOWN: 0>, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>, seek_frame: int = 0) -> Generator[array.array, int, NoneType]

Convenience function that returns a generator to decode and stream any source of encoded audio data (such as a network stream). Stream result is chunks of raw PCM samples in the chosen format. If you send() a number into the generator rather than just using next() on it, you'll get that given number of frames, instead of the default configured amount. This is particularly useful to plug this stream into an audio device callback that wants a variable number of frames per call.

function stream_file (filename: str, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>, seek_frame: int = 0) -> Generator[array.array, int, NoneType]

Convenience generator function to decode and stream any supported audio file as chunks of raw PCM samples in the chosen format. If you send() a number into the generator rather than just using next() on it, you'll get that given number of frames, instead of the default configured amount. This is particularly useful to plug this stream into an audio device callback that wants a variable number of frames per call.

function stream_memory (data: bytes, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, frames_to_read: int = 1024, dither: miniaudio.DitherMode = <DitherMode.NONE: 0>) -> Generator[array.array, int, NoneType]

Convenience generator function to decode and stream any supported audio file in memory as chunks of raw PCM samples in the chosen format. If you send() a number into the generator rather than just using next() on it, you'll get that given number of frames, instead of the default configured amount. This is particularly useful to plug this stream into an audio device callback that wants a variable number of frames per call.

function vorbis_get_file_info (filename: str) -> miniaudio.SoundFileInfo

Fetch some information about the audio file (vorbis format).

function vorbis_get_info (data: bytes) -> miniaudio.SoundFileInfo

Fetch some information about the audio data (vorbis format).

function vorbis_read (data: bytes) -> miniaudio.DecodedSoundFile

Reads and decodes the whole vorbis audio data. Resulting sample format is 16 bits signed integer.

function vorbis_read_file (filename: str) -> miniaudio.DecodedSoundFile

Reads and decodes the whole vorbis audio file. Resulting sample format is 16 bits signed integer.

function vorbis_stream_file (filename: str, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]

Streams the ogg vorbis audio file as interleaved 16 bit signed integer sample arrays segments. This uses a variable unconfigurable chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using stream_file() instead.

function wav_get_file_info (filename: str) -> miniaudio.SoundFileInfo

Fetch some information about the audio file (wav format).

function wav_get_info (data: bytes) -> miniaudio.SoundFileInfo

Fetch some information about the audio data (wav format).

function wav_read_f32 (data: bytes) -> miniaudio.DecodedSoundFile

Reads and decodes the whole wav audio data. Resulting sample format is 32 bits float.

function wav_read_file_f32 (filename: str) -> miniaudio.DecodedSoundFile

Reads and decodes the whole wav audio file. Resulting sample format is 32 bits float.

function wav_read_file_s16 (filename: str) -> miniaudio.DecodedSoundFile

Reads and decodes the whole wav audio file. Resulting sample format is 16 bits signed integer.

function wav_read_file_s32 (filename: str) -> miniaudio.DecodedSoundFile

Reads and decodes the whole wav audio file. Resulting sample format is 32 bits signed integer.

function wav_read_s16 (data: bytes) -> miniaudio.DecodedSoundFile

Reads and decodes the whole wav audio data. Resulting sample format is 16 bits signed integer.

function wav_read_s32 (data: bytes) -> miniaudio.DecodedSoundFile

Reads and decodes the whole wav audio data. Resulting sample format is 32 bits signed integer.

function wav_stream_file (filename: str, frames_to_read: int = 1024, seek_frame: int = 0) -> Generator[array.array, NoneType, NoneType]

Streams the WAV audio file as interleaved 16 bit signed integer sample arrays segments. This uses a fixed chunk size and cannot be used as a generic miniaudio decoder input stream. Consider using stream_file() instead.

function wav_write_file (filename: str, sound: miniaudio.DecodedSoundFile)

Writes the pcm sound to a WAV file

class CaptureDevice

CaptureDevice (self, input_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, device_id: Union[_cffi_backend.CData, NoneType] = None, callback_periods: int = 0, backends: Union[List[miniaudio.Backend], NoneType] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '')

An audio device provided by miniaudio, for audio capture (recording).

method close (self)

Halt playback or capture and close down the device. If you use the device as a context manager, it will be closed automatically.

method start (self, callback_generator: Generator[NoneType, Union[bytes, array.array], NoneType], stop_callback: Union[Callable, NoneType] = None)

Start the audio device: capture (recording) begins. The recorded audio data is sent to the given callback generator as raw bytes. (it should already be started before)

method stop (self)

Halt playback or capture.

class DecodeError

DecodeError (self, /, *args, **kwargs)

When something went wrong during decoding an audio file.

class DecodedSoundFile

DecodedSoundFile (self, name: str, nchannels: int, sample_rate: int, sample_format: miniaudio.SampleFormat, samples: array.array)

Contains various properties and also the PCM frames of a fully decoded audio file.

class Devices

Devices (self, backends: Union[List[miniaudio.Backend], NoneType] = None)

Query the audio playback and record devices that miniaudio provides

method get_captures (self) -> List[Dict[str, Any]]

Get a list of capture devices and some details about them

method get_playbacks (self) -> List[Dict[str, Any]]

Get a list of playback devices and some details about them

class DuplexStream

DuplexStream (self, playback_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, playback_channels: int = 2, capture_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, capture_channels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, playback_device_id: Union[_cffi_backend.CData, NoneType] = None, capture_device_id: Union[_cffi_backend.CData, NoneType] = None, callback_periods: int = 0, backends: Union[List[miniaudio.Backend], NoneType] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '')

Joins a capture device and a playback device.

method close (self)

Halt playback or capture and close down the device. If you use the device as a context manager, it will be closed automatically.

method start (self, callback_generator: Generator[Union[bytes, array.array], Union[bytes, array.array], NoneType], stop_callback: Union[Callable, NoneType] = None)

Start the audio device: playback and capture begin. The audio data for playback is provided by the given callback generator, which is sent the recorded audio data at the same time. (it should already be started before passing it in)

method stop (self)

Halt playback or capture.

class IceCastClient

IceCastClient (self, url: str, update_stream_title: Callable[[ForwardRef('IceCastClient'), str], NoneType] = None)

A simple client for IceCast audio streams as miniaudio streamable source. If the stream has Icy Meta Data, the stream_title attribute will be updated with the actual title taken from the meta data. You can also provide a callback to be called when a new stream title is available. The downloading of the data from the internet is done in a background thread and it tries to keep a (small) buffer filled with available data to read.

method close (self)

Stop the stream, aborting the background downloading.

method read (self, num_bytes: int) -> bytes

Read a chunk of data from the stream.

method seek (self, offset: int, origin: miniaudio.SeekOrigin) -> bool

Override this if the stream supports seeking. Note: seek support is sometimes not needed if you give the file type to a decoder upfront. You can ignore this method then.

class MiniaudioError

MiniaudioError (self, /, *args, **kwargs)

When a miniaudio specific error occurs.

class PlaybackDevice

PlaybackDevice (self, output_format: miniaudio.SampleFormat = <SampleFormat.SIGNED16: 2>, nchannels: int = 2, sample_rate: int = 44100, buffersize_msec: int = 200, device_id: Union[_cffi_backend.CData, NoneType] = None, callback_periods: int = 0, backends: Union[List[miniaudio.Backend], NoneType] = None, thread_prio: miniaudio.ThreadPriority = <ThreadPriority.HIGHEST: 0>, app_name: str = '')

An audio device provided by miniaudio, for audio playback.

method close (self)

Halt playback or capture and close down the device. If you use the device as a context manager, it will be closed automatically.

method start (self, callback_generator: Generator[Union[bytes, array.array], int, NoneType], stop_callback: Union[Callable, NoneType] = None)

Start the audio device: playback begins. The audio data is provided by the given callback generator. The generator gets sent the required number of frames and should yield the sample data as raw bytes, a memoryview, an array.array, or as a numpy array with shape (numframes, numchannels). The generator should already be started before passing it in.

method stop (self)

Halt playback or capture.

class SoundFileInfo

SoundFileInfo (self, name: str, file_format: miniaudio.FileFormat, nchannels: int, sample_rate: int, sample_format: miniaudio.SampleFormat, duration: float, num_frames: int)

Contains various properties of an audio file.

class StreamableSource

StreamableSource (self, /, *args, **kwargs)

Base class for streams of audio data bytes. Can be used as a contextmanager, to properly call close().

method close (self)

Override this to properly close the stream and free resources.

method read (self, num_bytes: int) -> Union[bytes, memoryview]

override this to provide data bytes to the consumer of the stream

method seek (self, offset: int, origin: miniaudio.SeekOrigin) -> bool

Override this if the stream supports seeking. Note: seek support is sometimes not needed if you give the file type to a decoder upfront. You can ignore this method then.

class WavFileReadStream

WavFileReadStream (self, pcm_sample_gen: Generator[Union[bytes, array.array], int, NoneType], sample_rate: int, nchannels: int, output_format: miniaudio.SampleFormat, max_frames: int = 0)

An IO stream that reads as a .wav file, and which gets its pcm samples from the provided producer

method close (self)

Close the file

method read (self, amount: int = 9223372036854775807) -> Union[bytes, NoneType]

Read up to the given amount of bytes from the file.

Metadata

Release files for miniaudio 1.44

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for miniaudio 1.44
File Size Uploaded
miniaudio-1.44.tar.gz 524.1 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for miniaudio 1.44
File Interpreter ABI Platform
miniaudio-1.44-cp39-cp39-win_amd64.whl CPython 3.9 CPython 3.9 Windows x86-64 Details
miniaudio-1.44-cp38-cp38-win_amd64.whl CPython 3.8 CPython 3.8 Windows x86-64 Details
miniaudio-1.44-cp37-cp37m-win_amd64.whl CPython 3.7 CPython 3.7 pymalloc Windows x86-64 Details

Total release size: 1.4 MB

Release files / miniaudio-1.44.tar.gz

Download URL miniaudio-1.44.tar.gz
Size 524.1 kB
Tags Source
SHA-256 checksum
How to use checksums
4edd08a9b5a9ceb570a06cda9844f453cf3f0145bb4a19828df8f04ecfdf9993
BLAKE2b-256 checksum
How to use checksums
87e57d8fcaba04f8d7d851f0300a4269da03c084beb7e69bde87520b35069068
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.1 importlib_metadata/4.0.1 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.60.0 CPython/3.9.5

Release files / miniaudio-1.44-cp39-cp39-win_amd64.whl

Download URL miniaudio-1.44-cp39-cp39-win_amd64.whl
Size 285.8 kB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
9c9926eba1fc6d25965dc35ef9351fd7d14e27df27a25d0b2c1b4492de89bb03
BLAKE2b-256 checksum
How to use checksums
33e011a8e030f27d6fe6e7fe650260d51cff15326ca087d1a812f349d539543f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.1 CPython/3.7.3

Release files / miniaudio-1.44-cp38-cp38-win_amd64.whl

Download URL miniaudio-1.44-cp38-cp38-win_amd64.whl
Size 280.4 kB
Tags CPython 3.8 Windows x86-64
SHA-256 checksum
How to use checksums
18d1ea9e26aa154bfd79a1f579c513042b73d7f081d476b1b339c114142fe89c
BLAKE2b-256 checksum
How to use checksums
9a63cbc9bbe408a717b36936623e8836e9857dbebb53e511b671d2950d4e23c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.1 CPython/3.7.3

Release files / miniaudio-1.44-cp37-cp37m-win_amd64.whl

Download URL miniaudio-1.44-cp37-cp37m-win_amd64.whl
Size 280.4 kB
Tags CPython 3.7 CPython 3.7 pymalloc Windows x86-64
SHA-256 checksum
How to use checksums
b84b5892cd4c36085acfc535b59e08c0d141b8ac6d97b26cbea47e3cdb037383
BLAKE2b-256 checksum
How to use checksums
d7ee4d84b241aea4f2da87b07c7f85c4443de68730c703406f266b8cd85370cc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.1 CPython/3.7.3

Release history Release notifications | RSS feed

1.71

31 release files

1.70

33 release files

1.61

60 release files

1.60

60 release files

1.59

52 release files

1.58

47 release files

1.57

37 release files

1.56

37 release files

1.55

37 release files

1.54

37 release files

1.53

37 release files

1.52

37 release files

1.51

37 release files

1.50

37 release files

1.46

37 release files

1.45

6 release files

This release

1.44 This release

4 release files

1.43

5 release files

1.42

5 release files

1.41

6 release files

1.40

6 release files

1.39

6 release files

1.38

6 release files

1.37

6 release files

1.36

6 release files

1.35

6 release files

1.34

6 release files

1.33

6 release files

1.32

6 release files

1.31

6 release files

1.30

6 release files

1.23

6 release files

1.22

6 release files

1.21

6 release files

1.20

6 release files

1.10

6 release files

1.9

5 release files

1.8

5 release files

1.7

6 release files

1.6

4 release files

1.5

3 release files

1.4

3 release files

1.3

3 release files

1.2.2

3 release files

1.2

1 release file

1.1

1 release file

1.0.1

1 release file

1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page