Skip to main content

minihost

Minihost is a headless, JUCE-based audio plugin host that supports VST3, AudioUnit, and LV2 plugins. It provides a C/C++ API for integration and a Python API powered by nanobind.

At a glance

Process an input WAV through a chain of effect plugins and write the result:

import minihost

with (
    minihost.Plugin("/path/to/delay.vst3", sample_rate=48000) as delay,
    minihost.Plugin("/path/to/reverb.vst3", sample_rate=48000) as reverb,
    minihost.PluginChain([delay, reverb]) as chain,
):
    minihost.process_audio_to_file(
        chain, "in.wav", "out.wav",
        tail_seconds=4.0,           # capture reverb tail
    )

process_audio_to_file handles block iteration, latency compensation, sample-rate matching, channel layout, and tail rendering. See the Python API section for lower-level control.

Features

  • Load VST3 plugins (macOS, Windows, Linux)

  • Load AudioUnit plugins (macOS only)

  • Load LV2 plugins (macOS, Windows, Linux)

  • Headless mode (default) - no GUI dependencies, uses JUCE's juce_audio_processors_headless module

  • Plugin chaining - connect multiple plugins in series (synth -> reverb -> limiter)

  • AudioBuffer -- the canonical audio container. Planar float32, JUCE-backed, stdlib-only. Numpy-style 2-axis indexing (buf[ch, frame_slice]), JUCE DSP ops (clear, apply_gain, magnitude, copy), zero-copy channel-range views (buf.channel_view(start, count)), DLPack export so it's accepted directly by Plugin.process / numpy.asarray / PyTorch / etc.

  • numpy is optional. pip install minihost installs no Python runtime dependencies; the AudioBuffer API works without numpy. pip install minihost[numpy] enables numpy-typed APIs (AudioBuffer.as_ndarray(), read_audio(as_=numpy.ndarray), accepting numpy arrays as inputs).

  • High-level offline processing -- process_audio_to_file(plugin_or_chain, "in.wav", "out.wav") collapses block iteration, latency compensation, sample-rate matching, and tail rendering into one call.

  • Audio file I/O via miniaudio + tflac -- read WAV/FLAC/MP3/Vorbis, write WAV (16/24/32-bit) and FLAC (16/24-bit), optional Broadcast Wave (bext) metadata on WAV output (write_audio(..., bwf={...}))

  • Sample rate conversion via miniaudio resampler -- minihost.resample() API and minihost resample CLI subcommand

  • Real-time audio playback via miniaudio (cross-platform), with duplex capture mode for effect processing

  • Audio device selection -- enumerate and target specific playback/capture devices (minihost devices CLI, audio_get_playback_devices() / audio_get_capture_devices() API, --playback-device / --capture-device on minihost play)

  • Real-time audio input -- lock-free ring buffer API (write_input()) and duplex capture (capture=True) for routing system audio through effects

  • Real-time MIDI I/O via libremidi (cross-platform)

  • Control surface mapping -- minihost.MidiMapper translates incoming MIDI CCs from a USB control surface (Launch Control / MIDIMix / nanoKONTROL / X-Touch / etc.) onto plugin parameters with optional value-range and curve (linear/exp/log); CLI: minihost play --map "channel:cc:param[:lo:hi[:curve]]" (repeatable) or --map-file PATH for saved JSON mappings.

  • 14-bit MIDI CC -- map_cc14 pairs controller n (0-31) with n+32 for 16384 steps instead of 128, which matters on anything a 7-bit CC makes audibly stepped; CLI: minihost play --map14 "channel:msb_cc:param". Overlap with a plain CC is rejected at map time, because a stray mapping on the LSB otherwise shadows it silently.

  • OSC in and out -- OscServer / OscClient over UDP, built on JUCE's juce_osc (no new dependency). AudioDevice.connect_osc(port) parses /mh/param/<index> in C and drives parameters without taking a lock or the GIL; OscMapper adds name addressing, curves and ranges; OscFeedback sends values back so a surface tracks preset loads instead of lying. CLI: minihost play --osc-port 9000 --osc-feedback HOST:PORT.

  • Sample-accurate live parameter writes -- AudioDevice.send_param() queues a change on a lock-free ring the audio thread drains at the next block boundary, rather than writing the parameter underneath a running processBlock as set_param does. Coalesces per parameter per block, so a fader drag costs one write.

  • Host playhead for realtime -- AudioDevice.set_transport_enabled(True) plus transport_play() / transport_set_bpm() / loop points gives live plugins a tempo and a position. Tempo-synced delays, arpeggiators and LFOs previously saw no transport at all under minihost play.

  • Generated touch surfaces -- minihost touch synth.vst3 turns a plugin's parameters into a TouchOSC layout and a matching MIDI map, rendered from one table so the two cannot disagree. Widget choice follows the plugin's metadata (boolean -> button, stepped -> radio, else fader). Generation needs no dependency; compiling to .tosc uses the optional minihost[touch] extra (py2tosc).

  • Looped sources for live tweaking -- minihost play --loop-midi PATH loops a MIDI file through the plugin (with All Notes Off between iterations); --loop-audio PATH loops an audio file into the plugin's input ring buffer at real time. Useful for parameter exploration against a repeating pattern.

  • Virtual MIDI ports - create named ports that DAWs can connect to (macOS, Linux)

  • Standalone MIDI input - monitor raw MIDI messages without a plugin (MidiIn class)

  • Batch processing -- glob patterns and directory output for processing multiple files (minihost process -i "*.wav" -o output/)

  • Auto-tail detection -- tail_seconds="auto" monitors output amplitude and stops rendering when reverb/delay tails decay below threshold

  • Process audio with sample-accurate parameter automation

  • Single and double precision processing

  • MIDI input/output support

  • Transport info for tempo-synced plugins

  • State save/restore for presets and per-program state

  • Preset morphing -- minihost.morph interpolates between two parameter snapshots (A/B blend) for sound-design sweeps (capture / lerp / apply / morph)

  • Thread-safe by design -- construction, destruction, and thread-affine control operations are marshaled onto a dedicated native plugin thread, so a plugin can be built on one thread and used or closed from another (only the real-time process* path is single-thread/lock-free)

  • Change notifications (latency, parameter info, program, non-parameter state) with deferred dispatch via poll_callbacks()

  • Parameter gestures for automation bracketing

  • Bus layout validation and sidechain support

  • Track name/color metadata forwarding to plugins

  • Latency and tail time reporting

  • Parameter access by name -- plugin.find_param("Cutoff"), plugin.get_param_by_name("Cutoff"), plugin.set_param_by_name("Cutoff", 0.5) with case-insensitive lookup

  • Async plugin loading -- minihost.open_async() returns a concurrent.futures.Future that resolves to a ready-to-use Plugin, loaded off the calling thread (safe to use/close from any thread thanks to the dedicated plugin thread)

  • VST3 preset I/O -- read and write .vstpreset files from C (minihost_vstpreset.h), C++, and Python (minihost.vstpreset); minihost presets CLI subcommand exports the current plugin state, optionally after loading a program, state blob, or another .vstpreset

Library structure

minihost ships as two separate static libraries with a one-way dependency: libminihost_audio builds on libminihost, never the reverse.

  • libminihost -- the plugin host core (projects/libminihost/). Loads and runs VST3/AU/LV2 plugins and processes audio blocks you hand it: MIDI in/out, parameters, state save/restore, sample-accurate automation, sidechain, transport, bus layouts, and the routing abstractions (PluginChain, PluginBus, PluginGraph). Depends only on JUCE. C ABI prefix: mh_* (e.g. mh_open, mh_process, mh_chain_*, mh_bus_*, mh_graph_*). Header: minihost.h. Link this alone to load a plugin and feed it your own buffers -- the offline and embedded path, with no device or codec dependencies.

  • libminihost_audio -- the I/O layer around the core (projects/libminihost_audio/). It has no plugin-format knowledge; it gets audio and MIDI in and out of the machine and drives a plugin or chain through its real-time audio callback. Provides live audio device playback/capture (miniaudio), audio file read/write (read WAV/FLAC/MP3/Vorbis; write WAV/FLAC via miniaudio + tflac), MIDI ports (libremidi), and the lock-free ring buffers. Depends on libminihost plus the vendored miniaudio, tflac, and libremidi. C ABI prefix: mh_audio_*. Headers: minihost_audio.h, minihost_audiofile.h, minihost_midi.h. Link this in addition to libminihost when you want real-time devices, file I/O, or MIDI hardware.

In short: libminihost runs the plugin; libminihost_audio connects it to speakers, files, and MIDI hardware. The Python wheel links both.

Desktop application

minihost_desktop (projects/minihost_desktop/) is a developer-facing GUI host built on the same libraries. It loads VST3/AU/LV2 plugins, wires them into a node graph on a canvas, opens native plugin editor windows, renders the graph to disk offline, and drives a realtime audio device with live MIDI input and a transport (BPM / loop region). Project files are JSON, schema-versioned, and round-trip with the Python loader (minihost.load_project / render_project), so a graph built in the app renders identically from the command line.

Each plugin window carries the host-side controls a plugin's own editor usually leaves out: a factory-program selector, a bypass toggle (backed by the plugin's own bypass parameter where it publishes one), and .vstpreset load/save for interchange with other hosts. Offline renders put every plugin into non-realtime mode for the duration, so a bounce uses the plugin's offline code path rather than its realtime one.

Status: functional and pre-release. Both the offline renderer and the realtime engine are built and tested. Not yet done: packaging (code signing, notarization, installers). See docs/dev/desktop_app.md for the design and docs/dev/desktop_app_todo.md for per-feature status.

Plugins run in-process, the same trust model a DAW uses: a misbehaving plugin can crash the whole app and lose unsaved canvas edits. Two mitigations bound the harm. Plugin scanning is out-of-process, so a plugin that crashes while being catalogued takes down only a disposable child. And the working project is autosaved to a sidecar every few seconds; after an unclean exit the app offers to recover it on the next launch, so a crash costs at most a few seconds of unsaved editing. Save often regardless.

The app is opt-in and off by default (it requires a non-headless build, so it is excluded from the headless library, CLI, and Python wheel builds):

# Build the desktop app into its own build-desktop/ dir (keeps the
# headless library / CLI / wheel build in build/ untouched)
make desktop

# Or configure it by hand:
cmake -B build-desktop -DMINIHOST_BUILD_DESKTOP=ON
cmake --build build-desktop --config Release --target minihost_desktop

# Build (if needed) and launch it (macOS)
make run-desktop

Headless entry points for scripting and CI: minihost_desktop --render-project=<project.json> renders a project with no window, and minihost_desktop --save-roundtrip=<project.json> parses and re-saves a project (used as a build smoke test).

Requirements

  • CMake 3.20+

  • C++17 compiler

  • JUCE framework (automatically downloaded if not present)

  • Vendored C libraries: miniaudio, tflac, libremidi, midifile (see docs/vendored.md)

Platform-specific

  • macOS: Xcode command line tools

  • Windows: Visual Studio 2019+ or MinGW

  • Linux: Install the following development libraries:

    sudo apt install libasound2-dev libfreetype-dev libfontconfig1-dev \
        libwebkit2gtk-4.1-dev libgtk-3-dev libgl-dev libcurl4-openssl-dev
    

Building

macOS / Linux

# Clone the repository
git clone https://github.com/shakfu/minihost.git
cd minihost

# Build (JUCE will be downloaded automatically)
make

# Or with a custom JUCE path
cmake -B build -DJUCE_PATH=/path/to/JUCE
cmake --build build

# Also build the non-headless libminihost_gui.a (GUI support: plugin
# editor windows). The headless libminihost.a is still built alongside it.
cmake -B build -DMINIHOST_BUILD_GUI_LIB=ON
cmake --build build

Windows

# Clone the repository
git clone https://github.com/shakfu/minihost.git
cd minihost

# Download JUCE
python scripts/download_juce.py

# Configure and build
cmake -B build
cmake --build build --config Release

JUCE Setup

JUCE is downloaded automatically by make (macOS/Linux). You can also download it manually:

python scripts/download_juce.py

To use a different version or existing installation:

# Download specific version (macOS/Linux)
JUCE_VERSION=8.0.6 python scripts/download_juce.py

# Download specific version (Windows PowerShell)
$env:JUCE_VERSION="8.0.6"; python scripts/download_juce.py

# Or point to existing JUCE
cmake -B build -DJUCE_PATH=/path/to/your/JUCE

Command Line Interface

The minihost command provides a CLI for common plugin operations:

# Install (from source)
uv sync

# Available commands
minihost --help
usage: minihost [-h] [-r SAMPLE_RATE] [-b BLOCK_SIZE]
                {scan,info,params,midi,devices,presets,play,process,resample} ...

Audio plugin hosting CLI

positional arguments:
  {scan,info,params,midi,devices,presets,play,process,resample}
                        Commands
    scan                Scan directory for plugins
    info                Show plugin info
    params              List plugin parameters
    midi                List or monitor MIDI ports
    devices             List audio playback/capture devices
    presets             List factory presets or export .vstpreset files
    play                Play plugin with real-time audio/MIDI
    process             Process audio through plugin (offline)
    resample            Resample audio file to a different sample rate

options:
  -h, --help            show this help message and exit
  -r, --sample-rate SAMPLE_RATE
                        Sample rate in Hz (default: 48000)
  -b, --block-size BLOCK_SIZE
                        Block size in samples (default: 512)

Commands

minihost info - Show plugin info

minihost info /path/to/plugin.vst3          # full info (loads plugin)
minihost info /path/to/plugin.vst3 --probe  # lightweight metadata only
minihost info /path/to/plugin.vst3 --json   # JSON output

By default shows full runtime details (sample rate, channels, latency, buses, presets). Use --probe for fast metadata-only mode without fully loading the plugin.

minihost scan - Scan directory for plugins

minihost scan /Library/Audio/Plug-Ins/VST3/
minihost scan ~/Music/Plugins --json

minihost params - List plugin parameters

minihost params /path/to/plugin.vst3
minihost params /path/to/plugin.vst3 --json

minihost devices - List audio devices

minihost devices                    # list playback and capture devices
minihost devices --json             # JSON output

Use an index or case-insensitive device-name substring with minihost play --playback-device / --capture-device.

minihost presets - List or export factory presets

# List factory presets
minihost presets /path/to/synth.vst3
minihost presets /path/to/synth.vst3 --json

# Export factory preset N as a .vstpreset
minihost presets /path/to/synth.vst3 --program 5 --save preset5.vstpreset

# Round-trip: load a .vstpreset and re-save (preserves class_id)
minihost presets /path/to/synth.vst3 --load-vstpreset in.vstpreset --save out.vstpreset

# Convert a raw state blob to .vstpreset
minihost presets /path/to/synth.vst3 --state state.bin --save out.vstpreset

minihost midi - List or monitor MIDI ports

minihost midi                          # list all MIDI ports
minihost midi --json                   # list as JSON
minihost midi -m 0                     # monitor MIDI input port 0
minihost midi --virtual-midi "Monitor" # create virtual port and monitor

minihost play - Play plugin with real-time audio/MIDI

# Connect to MIDI input port 0
minihost play /path/to/synth.vst3 --midi 0

# Create a virtual MIDI port (macOS/Linux)
minihost play /path/to/synth.vst3 --virtual-midi "My Synth"

# Enable audio input for effect processing (duplex mode)
minihost play /path/to/reverb.vst3 --input
minihost play /path/to/amp-sim.vst3 --input --midi 0  # with MIDI too

# Select specific audio devices (index from `minihost devices` or name substring)
minihost play /path/to/synth.vst3 --playback-device "BlackHole"
minihost play /path/to/effect.vst3 --input --playback-device 0 --capture-device 1
Map a control surface to plugin parameters

--map wires incoming MIDI CCs from a USB control surface (Launch Control, MIDIMix, nanoKONTROL, X-Touch, etc.) onto plugin parameters. When set, MIDI is routed through Python via a MidiMapper; mapped CCs become parameter writes and unmapped events (notes, unmapped CCs) are forwarded to the plugin so notes still play. Format: channel:cc:param[:lo:hi[:curve]]. Curves: linear (default), exp (more resolution at low end), log (more resolution at high end).

# One mapping per --map flag, repeatable
minihost play /path/to/synth.vst3 --midi 0 \
  --map 0:7:Volume \
  --map 0:10:Pan:-1:1 \
  --map 0:74:Cutoff:0:1:exp

For a permanent setup, save the mappings to a JSON file once and load it with --map-file:

{
  "mappings": [
    {"channel": 0, "cc": 7,  "param": "Volume"},
    {"channel": 0, "cc": 10, "param": "Pan", "value_range": [-1.0, 1.0]},
    {"channel": 0, "cc": 74, "param": "Cutoff", "curve": "exp"}
  ]
}
minihost play /path/to/synth.vst3 --midi 0 \
  --map-file ~/.config/minihost/launch_control.json

--map and --map-file are combinable -- the file loads first, CLI args append. Required JSON fields per entry: channel, cc, param. Optional: value_range (default [0.0, 1.0]), curve (default "linear").

Loop a MIDI or audio file as the source

--loop-midi loops a MIDI file into a synth (or any plugin that accepts MIDI), useful for live-tweaking parameters against a repeating pattern. A Python thread schedules events at wall-clock-correct times; All Notes Off is sent on every channel between iterations to silence sustained notes.

# Loop a MIDI pattern through a synth while live-tweaking knobs
minihost play /path/to/synth.vst3 \
  --midi 0 \
  --map 0:74:Cutoff:0:1:exp \
  --loop-midi tests/_wav/test_pattern.mid

--loop-audio loops an audio file as the plugin's input, useful for testing effects against a known source without needing live audio. The ring buffer is auto-enabled; the file is resampled to the device rate if needed. Mutually exclusive with --input.

# Loop a guitar take into a reverb while turning the mix knob
minihost play /path/to/reverb.vst3 \
  --midi 0 \
  --map 0:7:Mix \
  --loop-audio guitar_dry.wav

Both loop flags can run alongside live MIDI input (the file's events and your live notes are merged into the plugin).

minihost process - Process audio/MIDI offline

# Process audio through effect
minihost process /path/to/effect.vst3 -i input.wav -o output.wav

# With parameter control
minihost process /path/to/effect.vst3 -i input.wav -o output.wav --param "Mix:0.5"

# Render MIDI through synth
minihost process /path/to/synth.vst3 -m song.mid -o output.wav --tail 3.0

# With preset and bit depth
minihost process /path/to/synth.vst3 -m song.mid -o output.wav --preset 5 --bit-depth 16

# Sidechain processing (second -i is sidechain)
minihost process /path/to/compressor.vst3 -i main.wav -i sidechain.wav -o output.wav

# Batch processing (glob input, directory output)
minihost process /path/to/reverb.vst3 -i "drums/*.wav" -o processed/
minihost process /path/to/effect.vst3 -i "*.wav" -o output/ -y  # overwrite existing

# Mixed sample rates are automatically resampled (use --no-resample to error instead)
minihost process /path/to/effect.vst3 -i 44100hz.wav -i 48000hz_sidechain.wav -o out.wav

minihost resample - Resample audio files

minihost resample input.wav -o output.wav -r 48000
minihost resample input.wav -o output.wav -r 44100 --bit-depth 16
minihost resample input.wav -o output.wav -r 96000 -y  # overwrite

Global Options

Option Description
-r, --sample-rate Sample rate in Hz (default: 48000)
-b, --block-size Block size in samples (default: 512)

Native CLI binaries

Alongside the Python minihost command, the project ships two native binaries -- minihost_c (pure C) and minihost_cpp (C++) -- built into build/projects/ and published in the cli release archive. They are independent implementations over the same C API and are meant to be interchangeable; a conformance test runs them against each other and fails if they diverge. Beyond the single-plugin commands they add the routing ones:

Plugins are named by path, or by name once they have been scanned -- matching ignores case and takes the whole name:

minihost_c scan                    # index this platform's plugin locations
minihost_c probe dexed             # by name (whole name, any case)
minihost_c --fuzzy probe "pro-q 3" # --fuzzy to match part of a name
minihost_c --format au probe "FabFilter Pro-Q 4"   # pin a format

A plugin installed in both AU and VST3 resolves to the VST3 unless --format says otherwise. Substring matching is opt-in because it is rarely decisive on a large collection: with 343 plugins installed here, reverb matches 5 and filter 31.

scan takes an optional directory to scan instead of the defaults. It probes each plugin, so a first pass over a large collection takes minutes; results are cached (shared with the Python CLI's cache), written as the scan proceeds, and only changed plugins are re-probed. Each plugin is probed in a child process the scan is willing to lose, so one that hangs or crashes on load costs one cache entry (timeout / crash) instead of the scan -- --in-process opts out. See the CLI reference.

# one plugin: audio in, or a MIDI file through an instrument
minihost_c process Plugin.vst3 -i input.wav -o output.wav --tail 3
minihost_c process Synth.vst3  -m song.mid  -o output.wav --tail 2

# plugins in series; MIDI effects come first and drive what follows
minihost_c chain EQ.vst3 Reverb.vst3 -i input.wav -o output.wav --mix 1:0.5 --tail 3
minihost_c chain Arpeggiator.component Synth.vst3 -m song.mid -o output.wav

# branches in parallel, summed -- one MIDI part layered across instruments.
# A branch may itself be a chain: commas run plugins in series.
minihost_c bus SynthA.vst3 SynthB.vst3 -m song.mid -o output.wav
minihost_c bus Synth.vst3 "Chorder.component,Synth.vst3" -m song.mid -o out.wav --gain 1:0.7

See the CLI reference for the full option list and MIDI Routing for why MIDI effects must precede the instrument they drive.

Python API

Install:

pip install minihost              # AudioBuffer-only API; no numpy required
pip install minihost[numpy]       # adds numpy-typed return values + numpy input acceptance

The default audio container is minihost.AudioBuffer (planar float32, JUCE-backed, stdlib-only). It supports DLPack so any C extension that takes a 2D float32 c-contiguous buffer (including all of minihost's process methods) accepts it directly. Numpy is fully supported when installed -- pass as_=numpy.ndarray to receive numpy arrays from read_audio / render_midi, or call .as_ndarray() on any AudioBuffer for a zero-copy numpy view.

Quick start: process a WAV file through a chain

import minihost

with (
    minihost.Plugin("/path/to/delay.vst3", sample_rate=48000) as delay,
    minihost.Plugin("/path/to/reverb.vst3", sample_rate=48000) as reverb,
    minihost.PluginChain([delay, reverb]) as chain,
):
    minihost.process_audio_to_file(
        chain, "in.wav", "out.wav",
        tail_seconds=4.0,           # capture reverb tail
    )

process_audio_to_file handles block iteration, latency compensation, sample-rate matching (input is auto-resampled to the plugin's rate), mono-to-stereo channel duplication, and tail rendering. For in-memory data use process_audio(plugin_or_chain, audio, tail_seconds=...), which returns an AudioBuffer.

Lower-level processing

import minihost

plugin = minihost.Plugin("/path/to/plugin.vst3", sample_rate=48000)

# AudioBuffer is the default container. process accepts it directly via DLPack.
input_audio = minihost.AudioBuffer(2, 512)
output_audio = minihost.AudioBuffer(2, 512)
plugin.process(input_audio, output_audio)

# Numpy users can mix and match -- both accepted as inputs:
import numpy as np                                       # requires minihost[numpy]
input_np = np.zeros((2, 512), dtype=np.float32)
plugin.process(input_np, output_audio)                   # numpy in -> AudioBuffer out
output_np = output_audio.as_ndarray()                    # zero-copy numpy view

Parameter Access by Name

import minihost

plugin = minihost.Plugin("/path/to/synth.vst3", sample_rate=48000)

# Find parameter index by name (case-insensitive)
idx = plugin.find_param("Cutoff")

# Get/set by name directly
value = plugin.get_param_by_name("Cutoff")
plugin.set_param_by_name("Cutoff", 0.7)
plugin.set_param_by_name("resonance", 0.4)  # case-insensitive

# Index-based API remains available for hot paths
plugin.set_param(idx, 0.5)

Preset Morphing

Interpolate between two parameter snapshots (an A/B blend), useful for sound-design sweeps. Morphing operates on normalized per-parameter values (not opaque VST/AU state blobs).

import minihost

plugin = minihost.Plugin("/path/to/synth.vst3", sample_rate=48000)

# Capture two states (e.g. after loading two presets)
a = minihost.capture_params(plugin)
# ... dial in a different sound ...
b = minihost.capture_params(plugin)

# Blend 30% of the way from A to B and apply to the plugin
minihost.morph_params(plugin, a, b, 0.3)

# Or compute a blend without applying; t can be a per-parameter sequence
blended = minihost.lerp_params(a, b, 0.5)
minihost.apply_params(plugin, blended)

Async Plugin Loading

import minihost

# Load a heavy plugin in the background (off the calling thread)
future = minihost.open_async("/path/to/heavy_sampler.vst3", sample_rate=48000)

# Do other work while plugin loads...

# Block until ready -- returns a normal Plugin
plugin = future.result()
print(f"Loaded: {plugin.num_params} params")

# The plugin is built on a loader thread but is safe to use and close from
# any thread: minihost marshals thread-affine operations onto a dedicated
# native plugin thread. Loads are serialized on that thread, so this is
# non-blocking (not parallel) loading.
plugin.close()

Shared session for multi-plugin loading

mh_open and its Python equivalent register the JUCE plugin formats on every call. A Session builds that format manager once and reuses it across loads, probes and scans, which is the difference between loading one plugin and loading a chain of them.

import minihost

session = minihost.Session()
eq     = session.open("/path/to/EQ.vst3", sample_rate=48000)
reverb = session.open("/path/to/Reverb.vst3", sample_rate=48000)

# AudioUnits are identified by an id rather than a path, so they load from a
# serialized PluginDescription -- through the session like anything else.
delay = session.open_desc(
    '<PLUGIN name="AUDelay" format="AudioUnit" file="AudioUnit:Effects/aufx,dely,appl"/>'
)

session.close()   # the plugins keep working; they do not depend on it

The native chain and bus commands load this way, which is where the saving shows: a four-plugin chain built four format managers before.

Audio Device Enumeration and Selection

import minihost

# List available audio devices
for dev in minihost.audio_get_playback_devices():
    print(f"[{dev['index']}] {dev['name']}{' *' if dev['is_default'] else ''}")

for dev in minihost.audio_get_capture_devices():
    print(f"[{dev['index']}] {dev['name']}{' *' if dev['is_default'] else ''}")

# Target a specific playback device (e.g., for routing to a loopback driver)
plugin = minihost.Plugin("/path/to/synth.vst3", sample_rate=48000)
with minihost.AudioDevice(plugin, playback_device_index=2) as audio:
    audio.send_midi(0x90, 60, 100)

# Duplex mode with explicit capture + playback devices
with minihost.AudioDevice(plugin, capture=True,
                          capture_device_index=1,
                          playback_device_index=0) as audio:
    pass

Pass -1 (the default) to use the system default device.

Real-time Audio Playback

import minihost
import time

plugin = minihost.Plugin("/path/to/synth.vst3", sample_rate=48000)

# Use as context manager for automatic start/stop
with minihost.AudioDevice(plugin) as audio:
    # Plugin is now producing audio through speakers
    # Send MIDI programmatically
    audio.send_midi(0x90, 60, 100)  # Note on: C4, velocity 100
    time.sleep(1)
    audio.send_midi(0x80, 60, 0)    # Note off
    time.sleep(0.5)

# Or manual control
audio = minihost.AudioDevice(plugin)
audio.start()
audio.send_midi(0x90, 64, 80)  # E4 note on
time.sleep(0.5)
audio.send_midi(0x80, 64, 0)   # E4 note off
audio.stop()

Real-time Audio Input (Effect Processing)

Route system audio through an effect plugin using duplex mode or the ring buffer API:

import minihost
import time

plugin = minihost.Plugin("/path/to/reverb.vst3", sample_rate=48000)

# Option 1: Duplex mode (system audio capture -> plugin -> speakers)
with minihost.AudioDevice(plugin, capture=True) as audio:
    print("Processing system audio through effect... Ctrl+C to stop")
    time.sleep(10)

# Option 2: Ring buffer (push audio from Python).
# AudioBuffer slicing returns a new AudioBuffer; write_input accepts it
# directly via DLPack -- no numpy required.
audio = minihost.AudioDevice(plugin)
audio.enable_input()  # ~0.5s ring buffer by default
audio.start()

data, sr = minihost.read_audio("guitar.wav")
block_size = 512
for i in range(0, data.frames, block_size):
    chunk = data[:, i:i+block_size]
    audio.write_input(chunk)
    time.sleep(block_size / sr * 0.9)  # pace to real time

audio.stop()
audio.disable_input()

Real-time MIDI I/O

import minihost

# Enumerate available MIDI ports
inputs = minihost.midi_get_input_ports()
outputs = minihost.midi_get_output_ports()
print(f"MIDI Inputs: {inputs}")
print(f"MIDI Outputs: {outputs}")

# Connect MIDI when creating AudioDevice
with minihost.AudioDevice(plugin, midi_input_port=0) as audio:
    # MIDI from port 0 is now routed to the plugin
    pass

# Or connect dynamically
audio = minihost.AudioDevice(plugin)
audio.connect_midi_input(0)
audio.start()
# ...
audio.disconnect_midi_input()
audio.stop()

# Create virtual MIDI ports (appear in system MIDI, DAWs can connect)
audio = minihost.AudioDevice(plugin)
audio.create_virtual_midi_input("minihost Input")
audio.create_virtual_midi_output("minihost Output")
audio.start()
# Other apps can now send MIDI to "minihost Input"
# and receive MIDI from "minihost Output"

Standalone MIDI Input

Monitor MIDI messages without loading a plugin:

import minihost

def on_midi(data: bytes):
    status = data[0]
    if status & 0xF0 == 0x90 and data[2] > 0:
        print(f"Note On: {data[1]} vel={data[2]}")

# Open hardware MIDI port
with minihost.MidiIn.open(0, on_midi) as midi_in:
    input("Press Enter to stop...\n")

# Or create a virtual MIDI port
with minihost.MidiIn.open_virtual("My Monitor", on_midi) as midi_in:
    input("Press Enter to stop...\n")

Audio File I/O

import minihost

# Read audio files (WAV, FLAC, MP3, Vorbis).
# Default container is AudioBuffer (planar float32, no numpy required).
data, sample_rate = minihost.read_audio("input.wav")
# data is an AudioBuffer of shape (channels, samples)

# Pass as_=numpy.ndarray to get a numpy array instead (requires minihost[numpy]).
import numpy as np
data_np, sample_rate = minihost.read_audio("input.wav", as_=np.ndarray)

# write_audio accepts AudioBuffer, numpy ndarray, or any DLPack/buffer-protocol producer.
minihost.write_audio("output.wav", data, sample_rate, bit_depth=24)   # WAV (16/24/32-bit)
minihost.write_audio("output.flac", data, sample_rate, bit_depth=24)  # FLAC (16/24-bit)

# Broadcast Wave (bext) metadata for film/broadcast workflows (WAV only)
minihost.write_audio("take.wav", data, sample_rate, bit_depth=24, bwf={
    "description": "Scene 12 take 3",
    "originator": "minihost",
    "originator_reference": "REF-0012",
    "origination_date": "2026-07-07",   # yyyy-mm-dd
    "origination_time": "12:34:56",     # hh:mm:ss
    "time_reference": 48000 * 3600,     # samples since midnight (timecode anchor)
})

# Get file info without decoding
info = minihost.get_audio_info("song.wav")
print(f"{info['channels']}ch, {info['sample_rate']}Hz, {info['duration']:.2f}s")

Sample Rate Conversion

import minihost

# Works on AudioBuffer (default), numpy ndarray, or any 2D float32
# c-contig buffer-protocol producer. Return type matches the input type
# (AudioBuffer in -> AudioBuffer out; numpy in -> numpy out).
data, sr = minihost.read_audio("input_44100.wav")  # AudioBuffer @ 44.1kHz
resampled = minihost.resample(data, 44100, 48000)   # -> 48kHz AudioBuffer
minihost.write_audio("output_48000.wav", resampled, 48000)

MIDI File Read/Write

import minihost

# Create a new MIDI file
mf = minihost.MidiFile()
mf.ticks_per_quarter = 480

# Add events
mf.add_tempo(0, 0, 120.0)  # 120 BPM at tick 0
mf.add_note_on(0, 0, 0, 60, 100)    # C4 note on at tick 0
mf.add_note_off(0, 480, 0, 60, 0)   # C4 note off at tick 480

# Save to file
mf.save("output.mid")

# Load existing MIDI file
mf2 = minihost.MidiFile()
mf2.load("input.mid")

# Read events
events = mf2.get_events(0)  # Get events from track 0
for event in events:
    if event['type'] == 'note_on':
        print(f"Note {event['pitch']} vel {event['velocity']} at {event['seconds']:.2f}s")

MIDI File Rendering

Render MIDI files through plugins to produce audio output. Returns AudioBuffer by default; pass as_=numpy.ndarray for numpy:

import minihost

plugin = minihost.Plugin("/path/to/synth.vst3", sample_rate=48000)

# Render to AudioBuffer (default)
audio = minihost.render_midi(plugin, "song.mid")
print(f"Rendered {audio.frames / 48000:.2f} seconds of audio")

# Numpy variant
import numpy as np
audio_np = minihost.render_midi(plugin, "song.mid", as_=np.ndarray)

# Render directly to WAV file (returns frame count)
samples = minihost.render_midi_to_file(plugin, "song.mid", "output.wav", bit_depth=24)

# Stream blocks for large files or real-time processing.
# Each yielded block is an AudioBuffer; pass as_=numpy.ndarray to yield numpy instead.
for block in minihost.render_midi_stream(plugin, "song.mid", block_size=512):
    # block.shape == (channels, n) where n <= block_size
    pass

# Auto-detect reverb/delay tail (stops when output decays below -80 dB)
audio = minihost.render_midi(plugin, "song.mid", tail_seconds="auto")

# Custom threshold (-40 dB) and max tail (10s safety cap)
audio = minihost.render_midi(plugin, "song.mid",
                             tail_seconds="auto", tail_threshold=1e-2, max_tail_seconds=10)

# Fine-grained control with MidiRenderer class
renderer = minihost.MidiRenderer(plugin, "song.mid")
print(f"Duration: {renderer.duration_seconds:.2f}s")

while not renderer.is_finished:
    block = renderer.render_block()   # returns AudioBuffer or None
    print(f"Progress: {renderer.progress:.1%}")

Plugin Chaining

Chain multiple plugins together for serial processing:

import minihost
import time

# Load plugins (all must have same sample rate)
synth = minihost.Plugin("/path/to/synth.vst3", sample_rate=48000)
reverb = minihost.Plugin("/path/to/reverb.vst3", sample_rate=48000)
limiter = minihost.Plugin("/path/to/limiter.vst3", sample_rate=48000)

# Create chain
chain = minihost.PluginChain([synth, reverb, limiter])
print(f"Total latency: {chain.latency_samples} samples")
print(f"Tail length: {chain.tail_seconds:.2f} seconds")

# Real-time playback through chain
with minihost.AudioDevice(chain) as audio:
    audio.send_midi(0x90, 60, 100)  # Note on to synth
    time.sleep(2)
    audio.send_midi(0x80, 60, 0)    # Note off
    time.sleep(1)  # Let reverb tail fade

# Offline processing -- AudioBuffer is the default container
input_audio = minihost.AudioBuffer(2, 512)
output_audio = minihost.AudioBuffer(2, 512)
chain.process(input_audio, output_audio)

# Process with MIDI (enters the first plugin that accepts it, then
# carried on by any plugin that produces MIDI -- e.g. arpeggiator -> synth)
midi_events = [(0, 0x90, 60, 100)]
chain.process_midi(input_audio, output_audio, midi_events)

# Sample-accurate automation across chain
# param_changes: (sample_offset, plugin_index, param_index, value)
param_changes = [
    (0, 1, 0, 0.3),    # Set reverb param 0 at sample 0
    (256, 1, 0, 0.6),  # Change reverb param 0 at sample 256
    (0, 2, 0, 0.8),    # Set limiter param 0 at sample 0
]
chain.process_auto(input_audio, output_audio, midi_events, param_changes)

# Render MIDI file through chain
audio = minihost.render_midi(chain, "song.mid")        # -> AudioBuffer
minihost.render_midi_to_file(chain, "song.mid", "output.wav")

# File-to-file processing through the chain (handles tail, latency, resample)
minihost.process_audio_to_file(chain, "input.wav", "output.wav", tail_seconds=4.0)

# Access individual plugins in chain
for i in range(chain.num_plugins):
    plugin = chain.get_plugin(i)
    print(f"Plugin {i}: {plugin.num_params} params")

Parallel routing (PluginBus)

PluginChain is series; PluginBus is parallel. A bus fans the same input to N branches (each a PluginChain) and sums their outputs with a per-branch gain -- parallel compression, dry-bus + reverb-send, multi-band processing. With process_midi, the same MIDI is delivered to every branch, which is the idiomatic way to layer one part across several instruments:

import minihost

# Three synths layered under one MIDI part, summed to stereo.
a = minihost.PluginChain([minihost.Plugin("/path/to/saw.vst3", sample_rate=48000)])
b = minihost.PluginChain([minihost.Plugin("/path/to/sub.vst3", sample_rate=48000)])
c = minihost.PluginChain([minihost.Plugin("/path/to/pad.vst3", sample_rate=48000)])

bus = minihost.PluginBus(2, 2, max_block_size=512, sample_rate=48000.0)
bus.add_branch(a, gain=1.0)
bus.add_branch(b, gain=0.7)
bus.add_branch(c, gain=0.5)

silence = minihost.AudioBuffer(2, 512)   # synths ignore audio input
out = minihost.AudioBuffer(2, 512)
note_on = [(0, 0x90, 60, 100)]           # C4 reaches ALL three synths
bus.process_midi(silence, out, note_on)

A complete, runnable version (block loop, chord, WAV output) is in examples/parallel_bus.py.

For arbitrary node-to-node topologies (multiple inputs/outputs, MIDI processors, channel pick/merge), use PluginGraph -- the general DAG executor that also backs project files (minihost.load_project). Branch MIDI output is not collected by the bus; reach for PluginGraph if you need that.

VST3 Presets

Read, load, and write Steinberg .vstpreset files:

import minihost
from minihost import vstpreset

plugin = minihost.Plugin("/path/to/synth.vst3")

# Read a .vstpreset into raw chunks
preset = vstpreset.read_vstpreset("patch.vstpreset")
print(preset.class_id, len(preset.component_state or b""))

# Load into a plugin (calls plugin.set_state under the hood)
vstpreset.load_vstpreset("patch.vstpreset", plugin)

# Save the plugin's current state to a .vstpreset.
# class_id defaults to the FUID auto-detected from the plugin bundle's
# moduleinfo.json (requires VST3 SDK 3.7.5+, which all modern plugins ship).
vstpreset.save_vstpreset("out.vstpreset", plugin)

# Or pass class_id explicitly (e.g., for legacy plugins without moduleinfo.json):
vstpreset.save_vstpreset("out.vstpreset", plugin,
                         class_id="ABCDEF0123456789ABCDEF0123456789")

# Read just the class ID from a bundle without instantiating the plugin
fuid = vstpreset.read_class_id_from_bundle("/path/to/synth.vst3")
print(fuid)  # e.g., "ABCDEF0123456789ABCDEF0123456789"

# Or write raw chunks you already have
vstpreset.write_vstpreset("out.vstpreset",
                          class_id=fuid,
                          component_state=plugin.get_state())

C API Usage

#include "minihost.h"

// Load a plugin
char err[256];
MH_Plugin* plugin = mh_open("/path/to/plugin.vst3",
                            48000.0,  // sample rate
                            512,      // max block size
                            2, 2,     // in/out channels
                            err, sizeof(err));

// Process audio
float* inputs[2] = { in_left, in_right };
float* outputs[2] = { out_left, out_right };
mh_process(plugin, inputs, outputs, 512);

// Process with MIDI
MH_MidiEvent midi[] = {
    { 0, 0x90, 60, 100 },   // Note on at sample 0
    { 256, 0x80, 60, 0 }    // Note off at sample 256
};
mh_process_midi(plugin, inputs, outputs, 512, midi, 2);

// Parameter control
int num_params = mh_get_num_params(plugin);
float value = mh_get_param(plugin, 0);
mh_set_param(plugin, 0, 0.5f);

// State save/restore
int size = mh_get_state_size(plugin);
void* state = malloc(size);
mh_get_state(plugin, state, size);
mh_set_state(plugin, state, size);

// Cleanup
mh_close(plugin);

Real-time Audio Playback

#include "minihost_audio.h"

// Enumerate and select a playback device (optional)
MH_AudioDeviceInfo devices[32];
int n = mh_audio_enumerate_playback_devices(devices, 32);
for (int i = 0; i < n; i++) {
    printf("[%d]%s %s\n", i, devices[i].is_default ? "*" : " ", devices[i].name);
}

// Open audio device for real-time playback
MH_AudioConfig config = {
    .sample_rate = 48000,
    .buffer_frames = 512,
    .playback_device_index = -1,  // -1 = system default
    .capture_device_index = -1,
};
MH_AudioDevice* audio = mh_audio_open(plugin, &config, err, sizeof(err));

// Start playback
mh_audio_start(audio);

// Plugin is now producing audio through speakers
// Send MIDI, adjust parameters, etc.

// Stop and cleanup
mh_audio_stop(audio);
mh_audio_close(audio);
mh_close(plugin);

Real-time MIDI I/O

#include "minihost_midi.h"

// Enumerate available MIDI ports
int num_inputs = mh_midi_get_num_inputs();
int num_outputs = mh_midi_get_num_outputs();

for (int i = 0; i < num_inputs; i++) {
    char name[256];
    mh_midi_get_input_name(i, name, sizeof(name));
    printf("MIDI Input %d: %s\n", i, name);
}

// Connect MIDI to audio device
MH_AudioConfig config = {
    .sample_rate = 48000,
    .midi_input_port = 0,   // Connect to first MIDI input
    .midi_output_port = -1  // No MIDI output
};
MH_AudioDevice* audio = mh_audio_open(plugin, &config, err, sizeof(err));

// Or connect/disconnect dynamically
mh_audio_connect_midi_input(audio, 1);
mh_audio_disconnect_midi_input(audio);

// Create virtual MIDI ports (appear in system MIDI, DAWs can connect)
mh_audio_create_virtual_midi_input(audio, "minihost Input");
mh_audio_create_virtual_midi_output(audio, "minihost Output");

Plugin Chaining

Chain multiple plugins together for processing (e.g., synth -> reverb -> limiter):

#include "minihost_chain.h"

// Load plugins
MH_Plugin* synth = mh_open("/path/to/synth.vst3", 48000, 512, 0, 2, err, sizeof(err));
MH_Plugin* reverb = mh_open("/path/to/reverb.vst3", 48000, 512, 2, 2, err, sizeof(err));
MH_Plugin* limiter = mh_open("/path/to/limiter.vst3", 48000, 512, 2, 2, err, sizeof(err));

// Create chain (all plugins must have same sample rate)
MH_Plugin* plugins[] = { synth, reverb, limiter };
MH_PluginChain* chain = mh_chain_create(plugins, 3, err, sizeof(err));

// Get combined latency
int latency = mh_chain_get_latency_samples(chain);

// Process audio through chain
float* inputs[2] = { in_left, in_right };
float* outputs[2] = { out_left, out_right };
mh_chain_process(chain, inputs, outputs, 512);

// Process with MIDI (carried onward by plugins that produce MIDI)
MH_MidiEvent midi[] = { { 0, 0x90, 60, 100 } };
mh_chain_process_midi_io(chain, inputs, outputs, 512, midi, 1, NULL, 0, NULL);

// Sample-accurate automation across chain
MH_ChainParamChange changes[] = {
    { .sample_offset = 0,   .plugin_index = 1, .param_index = 0, .value = 0.3f },
    { .sample_offset = 256, .plugin_index = 1, .param_index = 0, .value = 0.6f },
};
mh_chain_process_auto(chain, inputs, outputs, 512,
                       NULL, 0, NULL, 0, NULL, changes, 2);

// Real-time playback through chain
MH_AudioConfig config = { .sample_rate = 48000, .buffer_frames = 512 };
MH_AudioDevice* audio = mh_audio_open_chain(chain, &config, err, sizeof(err));
mh_audio_start(audio);
// ...
mh_audio_stop(audio);
mh_audio_close(audio);

// Cleanup
mh_chain_close(chain);  // Does not close individual plugins
mh_close(synth);
mh_close(reverb);
mh_close(limiter);

MIDI File Rendering

Read a standard MIDI file into the event form mh_process* consumes. Tracks are merged and the file's tempo map is applied; sample_offset is absolute, so rebase it per block:

MH_MidiEvent* events = NULL;
int count = 0;
double duration = 0.0;
char err[512] = {0};

if (!mh_midi_file_load("song.mid", 48000.0, &events, &count, &duration,
                       err, sizeof(err))) {
    fprintf(stderr, "%s\n", err);
    return 1;
}

int cursor = 0;
for (int start = 0; start < total_frames; start += block) {
    int end = start + block;
    MH_MidiEvent block_midi[256];
    int n = 0;
    while (cursor < count && events[cursor].sample_offset < end && n < 256) {
        block_midi[n] = events[cursor];
        block_midi[n].sample_offset -= start;   // rebase to this block
        n++;
        cursor++;
    }
    mh_process_midi(synth, inputs, outputs, block, block_midi, n);
}

mh_midi_file_free(events);

Audio File I/O

Read and write audio files without external dependencies:

#include "minihost_audiofile.h"

// Read any supported format (WAV, FLAC, MP3, Vorbis)
char err[1024];
MH_AudioData* audio = mh_audio_read("input.flac", err, sizeof(err));
if (audio) {
    printf("Channels: %u, Frames: %u, Rate: %u\n",
           audio->channels, audio->frames, audio->sample_rate);
    // audio->data is interleaved float32
    mh_audio_data_free(audio);
}

// Write audio file (format selected by extension)
mh_audio_write("output.wav", interleaved_data,
               2, num_frames, 48000, 24, err, sizeof(err));   // WAV
mh_audio_write("output.flac", interleaved_data,
               2, num_frames, 48000, 24, err, sizeof(err));   // FLAC

// Get file info without decoding
MH_AudioFileInfo info;
mh_audio_get_file_info("song.wav", &info, err, sizeof(err));
printf("Duration: %.2f seconds\n", info.duration);

// Resample audio (e.g., 44.1kHz -> 48kHz)
MH_AudioData* resampled = mh_audio_resample(
    audio->data, audio->channels, audio->frames,
    44100, 48000, err, sizeof(err));
if (resampled) {
    printf("Resampled: %u frames at %u Hz\n", resampled->frames, resampled->sample_rate);
    mh_audio_data_free(resampled);
}

VST3 Preset I/O

Portable .vstpreset reader/writer with no external dependencies:

#include "minihost_vstpreset.h"

char err[256];

// Read a .vstpreset
MH_VstPreset preset;
if (mh_vstpreset_read("in.vstpreset", &preset, err, sizeof(err))) {
    // Apply the processor chunk to a plugin
    mh_set_state(plugin, preset.component_state, preset.component_size);
    mh_vstpreset_free(&preset);
}

// Auto-detect the processor FUID from the plugin bundle's moduleinfo.json
// (requires VST3 SDK 3.7.5+, which all modern plugins ship).
char class_id[MH_VSTPRESET_CLASS_ID_LEN + 1];
if (!mh_vstpreset_read_class_id_from_bundle(
        "/path/to/synth.vst3", class_id, err, sizeof(err))) {
    fprintf(stderr, "Cannot determine class_id: %s\n", err);
    // For legacy plugins without moduleinfo.json, supply class_id another way
    // (e.g., copy it from an existing .vstpreset).
}

// Write current plugin state to a .vstpreset
int state_size = mh_get_state_size(plugin);
void* state = malloc(state_size);
mh_get_state(plugin, state, state_size);

mh_vstpreset_write("out.vstpreset",
                   class_id,
                   state, state_size,
                   NULL, 0,  // optional controller state
                   err, sizeof(err));
free(state);

Thread Safety

minihost runs a dedicated native plugin thread and marshals every thread-affine plugin operation onto it -- construction, destruction, and control-plane queries (state, parameter text, program names, reset, set_sample_rate, processing precision). This makes plugins safe to build on one thread and use or close from another (which is what makes open_async work), and hardens the whole library against cross-thread use.

  • process* functions (process, process_midi, process_auto, process_double, process_sidechain): the real-time path -- lock-free, call from a single thread (typically the audio thread). Not marshaled.

  • All other (control) functions: safe to call from any thread.

  • Reconfiguring calls (set_sample_rate, set_state, set_processing_precision, set_non_realtime, reset) must not overlap a process* call -- they reconfigure the audio pipeline while process runs unprotected. Stop processing before calling them.

  • Set the environment variable MINIHOST_MESSAGE_THREAD=0 to disable the plugin thread (operations then run inline on the caller's thread; cross- thread plugin use, including open_async, becomes unsafe).

API Reference

Detailed API documentation:

  • C API Reference -- minihost.h, minihost_audio.h, minihost_audiofile.h, minihost_chain.h, minihost_midi.h, minihost_vstpreset.h

  • Python API Reference -- Plugin, PluginChain, AudioDevice, MidiFile, MidiIn, audio I/O, MIDI rendering, automation, VST3 presets

  • Hosting Guide -- practical guide with extended examples

License

GPL3

Release files for minihost 0.8.2

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

Built distributions (wheels)

Table of built distributions (wheels) for minihost 0.8.2
File
minihost-0.8.2-cp314-cp314-win_amd64.whl CPython 3.14 CPython 3.14 Windows x86-64 Details
minihost-0.8.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.14 CPython 3.14 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details
minihost-0.8.2-cp314-cp314-macosx_11_0_x86_64.whl CPython 3.14 CPython 3.14 macOS 11.0+ x86-64 Details
minihost-0.8.2-cp314-cp314-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 macOS 11.0+ ARM64 Details
minihost-0.8.2-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details
minihost-0.8.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details
minihost-0.8.2-cp313-cp313-macosx_11_0_x86_64.whl CPython 3.13 CPython 3.13 macOS 11.0+ x86-64 Details
minihost-0.8.2-cp313-cp313-macosx_11_0_arm64.whl CPython 3.13 CPython 3.13 macOS 11.0+ ARM64 Details
minihost-0.8.2-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
minihost-0.8.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details
minihost-0.8.2-cp312-cp312-macosx_11_0_x86_64.whl CPython 3.12 CPython 3.12 macOS 11.0+ x86-64 Details
minihost-0.8.2-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details
minihost-0.8.2-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
minihost-0.8.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details
minihost-0.8.2-cp311-cp311-macosx_11_0_x86_64.whl CPython 3.11 CPython 3.11 macOS 11.0+ x86-64 Details
minihost-0.8.2-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details
minihost-0.8.2-cp310-cp310-win_amd64.whl CPython 3.10 CPython 3.10 Windows x86-64 Details
minihost-0.8.2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details
minihost-0.8.2-cp310-cp310-macosx_11_0_x86_64.whl CPython 3.10 CPython 3.10 macOS 11.0+ x86-64 Details
minihost-0.8.2-cp310-cp310-macosx_11_0_arm64.whl CPython 3.10 CPython 3.10 macOS 11.0+ ARM64 Details

Total release size: 33.5 MB

Release files / minihost-0.8.2-cp314-cp314-win_amd64.whl

Download URL minihost-0.8.2-cp314-cp314-win_amd64.whl
Size 1.4 MB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
ac73cea5e4b684692903726266a670cefe7e19d590e0a54c760821339fd9a7ad
BLAKE2b-256 checksum
How to use checksums
8bbc7d9e504661310ce64d28c676cb157ca432af81e5dcd3a5742bc70d95136b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL minihost-0.8.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 2.3 MB
Tags CPython 3.14 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
4bd5402df1daeed4d36829c9b46db4a88602fcd482d8b21be3a0baeb6b5a1bb5
BLAKE2b-256 checksum
How to use checksums
71a07f30c0c3577bdcd0d62ff1a1166fbd1f0af0da0f213f809285467a031176
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp314-cp314-macosx_11_0_x86_64.whl

Download URL minihost-0.8.2-cp314-cp314-macosx_11_0_x86_64.whl
Size 1.6 MB
Tags CPython 3.14 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
351678e6fcc07bbe0fd33a6952b5159704ba44adf3513094f1c05e42e0791a9b
BLAKE2b-256 checksum
How to use checksums
a00f07abd176eccf70cfe79f8c5fee80107bf2cd798d572df8ad04146db76fc9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp314-cp314-macosx_11_0_arm64.whl

Download URL minihost-0.8.2-cp314-cp314-macosx_11_0_arm64.whl
Size 1.5 MB
Tags CPython 3.14 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
d186b36f061a8fc6b1d48d4ec4b6d0cd6a4a14e637f5bee12cc52aedea71b645
BLAKE2b-256 checksum
How to use checksums
d384daa5ea54b7c0e98af32d2023365924e1bfba569c6c03f7a7e955cf90c8a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp313-cp313-win_amd64.whl

Download URL minihost-0.8.2-cp313-cp313-win_amd64.whl
Size 1.4 MB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
3a04842cd41ec85ad96e1463cdd36da2ddf0e395eb47922a3aacb31cb754e3e0
BLAKE2b-256 checksum
How to use checksums
4b3bba51678552793fd48d5036b49149deaac1721301c3c638f8c37df71f78f5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL minihost-0.8.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 2.3 MB
Tags CPython 3.13 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
7670f9a986a49d39ed86aef57767705327f87e79701a6f3c54f415a62dc4a4a5
BLAKE2b-256 checksum
How to use checksums
e7662b0b5e73b68935149787f71394a8009c2c5e2a9e9a2c20129a931133b25f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp313-cp313-macosx_11_0_x86_64.whl

Download URL minihost-0.8.2-cp313-cp313-macosx_11_0_x86_64.whl
Size 1.6 MB
Tags CPython 3.13 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
5112d4650ab314609e4b5952874960a26269ab45b8b957dd08d70680dc6cd4a7
BLAKE2b-256 checksum
How to use checksums
76cc54005cd8cfe0b574448be74bdae42144bb6ac8bbbb288d217cf699d4c117
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp313-cp313-macosx_11_0_arm64.whl

Download URL minihost-0.8.2-cp313-cp313-macosx_11_0_arm64.whl
Size 1.5 MB
Tags CPython 3.13 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
4e122c586f88dfe47fb7d74f0b37617b8bced4e53244cd45aac963f49a0043b2
BLAKE2b-256 checksum
How to use checksums
e9baaf6555546b269f4508aad1c28b09edcc98f87a86f040a2027c5a98df52e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp312-cp312-win_amd64.whl

Download URL minihost-0.8.2-cp312-cp312-win_amd64.whl
Size 1.4 MB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
fb3f28e808fc18517b55d7c77df59a4dc563c9174293b9a2d117d61b16f58fa4
BLAKE2b-256 checksum
How to use checksums
189937c3df107071cda67f9a55ed9e5f3c850b8eea7a6b4ca75c12fdb30b1358
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL minihost-0.8.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 2.3 MB
Tags CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
bc2511016d595d86c8ca0e8a734b7a57caebd00371debef0ec1108abd8da9c13
BLAKE2b-256 checksum
How to use checksums
59133e90f9d0fd68f82f47813b43d7814fdd5edc53cd69364726646ba6112321
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp312-cp312-macosx_11_0_x86_64.whl

Download URL minihost-0.8.2-cp312-cp312-macosx_11_0_x86_64.whl
Size 1.6 MB
Tags CPython 3.12 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
8aa5feedd5c328f7539cd5e28935ff4b62275fbd45924d23556a3cd5908ad1b3
BLAKE2b-256 checksum
How to use checksums
d46897cbc275daf27f7950e37c99c1137048078dfcc52876f8282f405257a44b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp312-cp312-macosx_11_0_arm64.whl

Download URL minihost-0.8.2-cp312-cp312-macosx_11_0_arm64.whl
Size 1.5 MB
Tags CPython 3.12 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
3012d65921ddb4645169e8752a7f279e320766df19c4c0d7de1afbb86b1fe989
BLAKE2b-256 checksum
How to use checksums
ecd3d4e406b8772a3b0651024c17c3ed64e27f7fdff80606b1f6a1a8169edbe2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp311-cp311-win_amd64.whl

Download URL minihost-0.8.2-cp311-cp311-win_amd64.whl
Size 1.4 MB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
58072b4370c4b8a79ab303b2a24c5c4df1ae7a6da6854a193256f54d5d96a414
BLAKE2b-256 checksum
How to use checksums
3cac608a844bc3c7a903c17db163a3dead7b81c1d654564b1d1d829c8ba2599e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL minihost-0.8.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 2.3 MB
Tags CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
f6adc27863528f392c16bc701aa8155881cc3989c21ad8699c6650102bee098c
BLAKE2b-256 checksum
How to use checksums
6192a35ee7624f3b8765037cfeb5d97dfd7dc4637f23bea6091d88ee81a6cc82
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp311-cp311-macosx_11_0_x86_64.whl

Download URL minihost-0.8.2-cp311-cp311-macosx_11_0_x86_64.whl
Size 1.6 MB
Tags CPython 3.11 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
d404aabca30c9dadc34a7f32a73da13b8bf0dc9995c24c757475b9b82052a881
BLAKE2b-256 checksum
How to use checksums
46999d60d932d0d25aa1cf2edea08cb3ca6694423dfcc655d63f466d1cf50684
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp311-cp311-macosx_11_0_arm64.whl

Download URL minihost-0.8.2-cp311-cp311-macosx_11_0_arm64.whl
Size 1.5 MB
Tags CPython 3.11 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
dd198ce25065427125b3e64ef4efadb919d12fad9bba130cd212c04ebf481638
BLAKE2b-256 checksum
How to use checksums
1115acaa04dc289ac5c573861ca6536007d1491d7ba793658b94629f12a32135
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp310-cp310-win_amd64.whl

Download URL minihost-0.8.2-cp310-cp310-win_amd64.whl
Size 1.4 MB
Tags CPython 3.10 Windows x86-64
SHA-256 checksum
How to use checksums
ec84e7a7b7b84a7d4b0af016d615131015afc469ea6fcdb74508d61067ddcced
BLAKE2b-256 checksum
How to use checksums
dc5adedaff23758a84f4273cf2a9b1bb6c944e4075cb21a2b74c9862b481757d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL minihost-0.8.2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 2.3 MB
Tags CPython 3.10 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
c60ebd1be78d99ca0b6a766b55c3697f99a6e9c2f909b1756936eef6b552fbe1
BLAKE2b-256 checksum
How to use checksums
a4d882cc5fd79992a6ae059d65b5b1196e87a46a8ced235a87d1fffcbf22f270
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp310-cp310-macosx_11_0_x86_64.whl

Download URL minihost-0.8.2-cp310-cp310-macosx_11_0_x86_64.whl
Size 1.6 MB
Tags CPython 3.10 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
4a538ea8a41b54c006e38bf1b48ef26f8f4f0d3f4c82673638e70a3bfbf8a889
BLAKE2b-256 checksum
How to use checksums
0f7cb4d6e39db44b077ba5211bd27e2d875180156eb74c504b82328a4f837a6d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / minihost-0.8.2-cp310-cp310-macosx_11_0_arm64.whl

Download URL minihost-0.8.2-cp310-cp310-macosx_11_0_arm64.whl
Size 1.5 MB
Tags CPython 3.10 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
3781010d6cd020cfb77060864fb7a8d229952b7b039b4c2cc7b654ad51339cde
BLAKE2b-256 checksum
How to use checksums
1e423d77d292464ec3915c1ada500154ea11f96357d0f08539c63fee8a6b2103
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release history Release notifications | RSS feed

0.9.0

20 release files

This release

0.8.2 This release

20 release files

0.8.1

20 release files

0.8.0

20 release files

0.7.2

20 release files

0.7.0

20 release files

0.6.0

20 release files

0.5.1

20 release files

0.4.2

20 release files

0.4.1

20 release files

0.2.1

20 release files

0.2.0

20 release files

0.1.7

20 release files

0.1.6

20 release files

0.1.5

20 release files

0.1.4

21 release files

0.1.3

21 release files

0.1.2

21 release files

0.1.1

21 release files

0.1.0

21 release files

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