Skip to main content

A minimal juce-based plugin host using nanobind

Project description

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), 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)
  • 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.
  • 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
  • Thread-safe parameter access
  • 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 for background loading of large sample-library plugins
  • 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

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

# Disable headless mode (enables GUI support)
cmake -B build -DMINIHOST_HEADLESS=OFF
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:

# Cross-platform (recommended) - works on Windows, macOS, Linux
python scripts/download_juce.py

# Unix only (bash)
./scripts/download_juce.sh

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)

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)

Async Plugin Loading

import minihost

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

# Do other work while plugin loads...

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

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)

# 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 (MIDI goes to first plugin)
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")

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 (MIDI goes to first plugin only)
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);

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

  • mh_process, mh_process_midi, mh_process_midi_io, mh_process_auto: Call from audio thread only (no locking)
  • All other functions are thread-safe with internal locking
  • Do not call mh_close while another thread is using the plugin

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

minihost-0.1.7-cp314-cp314-win_amd64.whl (984.8 kB view details)

Uploaded CPython 3.14Windows x86-64

minihost-0.1.7-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

minihost-0.1.7-cp314-cp314-macosx_11_0_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.14macOS 11.0+ x86-64

minihost-0.1.7-cp314-cp314-macosx_11_0_arm64.whl (1.3 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

minihost-0.1.7-cp313-cp313-win_amd64.whl (957.1 kB view details)

Uploaded CPython 3.13Windows x86-64

minihost-0.1.7-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

minihost-0.1.7-cp313-cp313-macosx_11_0_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.13macOS 11.0+ x86-64

minihost-0.1.7-cp313-cp313-macosx_11_0_arm64.whl (1.3 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

minihost-0.1.7-cp312-cp312-win_amd64.whl (957.0 kB view details)

Uploaded CPython 3.12Windows x86-64

minihost-0.1.7-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

minihost-0.1.7-cp312-cp312-macosx_11_0_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.12macOS 11.0+ x86-64

minihost-0.1.7-cp312-cp312-macosx_11_0_arm64.whl (1.3 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

minihost-0.1.7-cp311-cp311-win_amd64.whl (957.5 kB view details)

Uploaded CPython 3.11Windows x86-64

minihost-0.1.7-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

minihost-0.1.7-cp311-cp311-macosx_11_0_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.11macOS 11.0+ x86-64

minihost-0.1.7-cp311-cp311-macosx_11_0_arm64.whl (1.3 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

minihost-0.1.7-cp310-cp310-win_amd64.whl (957.8 kB view details)

Uploaded CPython 3.10Windows x86-64

minihost-0.1.7-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

minihost-0.1.7-cp310-cp310-macosx_11_0_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.10macOS 11.0+ x86-64

minihost-0.1.7-cp310-cp310-macosx_11_0_arm64.whl (1.3 MB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

File details

Details for the file minihost-0.1.7-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: minihost-0.1.7-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 984.8 kB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for minihost-0.1.7-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 53dde5c52e922a363134f6fb809c2acef14202519f94e6bd8f69e33be3c59732
MD5 6a59cf91d6e55fd18d8c0177b1d46606
BLAKE2b-256 6436ca8d05622cf0fbd9ddb383a837c688435ebc39e5b400fdbe54b35c43fd7e

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 9b16003cbac16a028c7c732d3111c2ec1634670fbe50c2a9290c2151f88b65a9
MD5 8acb107ff1f7b0510b4144e42c695239
BLAKE2b-256 7412f0303b6ce4f5f8f42694c75c560ee7d3f0ec3672c7d0e4da577154b478d5

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp314-cp314-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp314-cp314-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 83454d1c9a3c9edafcd4e931c8a1b8d058fe51046183f75f98bc98e83714511f
MD5 fa9eedb4cace39113815b6e561d39cc7
BLAKE2b-256 e0a9228cf154e5f766706340a3a04274fa4c45e096f7385e4c064d6a80d49048

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ae2df6d0cf9fababea8d42765827d6308cba7b95821ed7a54f60ede2a3062489
MD5 bff926993587a669010e0c6d24f85f59
BLAKE2b-256 a5d14351040780ba8e7d08272e2bcb00371f3e099ebeeb3b006d8e8066a546f4

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: minihost-0.1.7-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 957.1 kB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for minihost-0.1.7-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 15eefdd63df5331fa93ef43b1875f7011713e202af9c8fe079df973f7a2d3267
MD5 cf80bfe3adb13dce1110fd6517226fcd
BLAKE2b-256 dec201931f3cab8285678665a1ec84c684f5190e7aa7720f1d9f4939f9e41d1f

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 50ed35f6a5c51054f22cbd54ba7c35f39f758a73c8ee81c0e6a014676009c8ac
MD5 938eef1da773ff6c07de48350606a6f4
BLAKE2b-256 72b56bfba373c5e357eaf99adbb542b3dd1f6a010cdd8f018d042e58542aea31

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp313-cp313-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp313-cp313-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 7a8d3a5e1ba447ec69f25ec688eb2d4c1c761fe4677d78b6ae0bb1a594b20818
MD5 c84456dcb5e4b1a9ba36e2e78ffc7516
BLAKE2b-256 54596b380baa360c10b1c68be185241e32cf4e83c45d80a38ff4791ad32701d4

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 d5baca9508b53570ea4f3ed973b0c79544b2462b5e90ecd52ed1fca1db5dddae
MD5 39f3932576bdda681e6cbbc213caae7c
BLAKE2b-256 bfecdec95790efc0800641926cfcdfa7d40432bcef6fb2e15f558e54adcaf8c2

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: minihost-0.1.7-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 957.0 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for minihost-0.1.7-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 283e5f5419d935eb017dde229cb1d341f8b7a554a116f03fb7485b0dec6c7619
MD5 8695a35b1f434efe466f14b5f91808a8
BLAKE2b-256 71ff0ef34b4aea2fdbd2d4415adf3ebb6bb67c32b36c04235f22807d4972fe84

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 f7ba66cabb7b0b2cd2106c9f8c96da0cfbdebc1f16d3acb789108dc8555f9420
MD5 b08c7a6b83fe800a3376b25cce5f5e18
BLAKE2b-256 c4c37c5f085f9781e9799788971e211e35c5894fad49cc4cdfa4af38642acc8d

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp312-cp312-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp312-cp312-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 5a032916665e0799e819e35a665ef7e5042219318b5ab4d5e101f9a140c4af90
MD5 222a565a447aceee39bd1802aae6394b
BLAKE2b-256 531dc44fda879c48f3aaa9b9574ad8d2315c9d0309a36282bfb08c01de13389d

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a108c801794aacab3330be1e7adcedb260f2be5bba1a080ade4a1e5ad78c25ee
MD5 158ad90d0fbc13004bf610b8f4f4b39e
BLAKE2b-256 9300bf774b394765a128ade68cdb7f1e71bd129b57365be14843f67ed32edc5b

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: minihost-0.1.7-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 957.5 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for minihost-0.1.7-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 46e8c75a8e5d952c11a9d39d8727ddf03844a0d76f6dc4c95eb9a6596e18d8fb
MD5 a6e4698cf4db7df776ae74c42250078f
BLAKE2b-256 8b213a8c1e905d6c9c284f612865be720ec962f3af3f98a72a1c41ae9500ce8e

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b47214fb2a2029a60b160ce353ba8df00dd0e604491dbfccd995e9cc19a7d9ba
MD5 439b391162db3dc801a09a828a6e356f
BLAKE2b-256 2b213eaac2342e4f15653f2c69be0cf8fb9142c92b8f047759a55bed8cf5e48f

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp311-cp311-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp311-cp311-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 07aa69d942ce4aeb741e7929f7d76507db4e280c29f8d8243458f81f03957d7b
MD5 6fd676e3b729c175243c15d2d32a8d7c
BLAKE2b-256 7d3e79130a79f56dfb1e451435ceb283d424729a2ad635cef9a51a7cf048ee8f

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4ffa6265df539da095108b0e193715ebb45b4a43596118f2852aeaa46ff60163
MD5 5c2b41d2046105860ffc2a219f6e2cfc
BLAKE2b-256 3bda2965f7b245be06a90ff7e70654ecd6dbb892064f4c02dfad0a5b2f38da92

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: minihost-0.1.7-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 957.8 kB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for minihost-0.1.7-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 63b893188f72472fb24dae23cd9df81c6f16e40cadd209e3c4c07addb3f28c3e
MD5 5c1f9e181850e8d610d1e2bd0fa30b24
BLAKE2b-256 8ca885a99a324cf84f664f3d49a0dbe6d739a51a24571a6d54b1b3e3d6c71a5b

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 e54ede8315f6f9edeedbd28b201809831d5a4f4603e6bc7bce5b14a410d5f6af
MD5 9a94bb79ad8f52bf001580fc0a99dc18
BLAKE2b-256 8cbbf2fe9ca8213824bcefb2d087e1050553e8755d8431eb7b6102323858bb6d

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp310-cp310-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp310-cp310-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 ce4a6cee44fbbc3eca4b8925a8bb156369c40b3993e781617842bf69963ae678
MD5 51089f237ebf3ebf2ad864c8c7ba2b5c
BLAKE2b-256 ce2415c852602525006e8d301f44933f2d06bdd246051e5db8532b36e010e55e

See more details on using hashes here.

File details

Details for the file minihost-0.1.7-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for minihost-0.1.7-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 952e8c27222ba622e3c80c545af2bfc57642ef9f9a0fd44bd476779acb0ede60
MD5 0eb593e9dc144722f985a699e4cae4cf
BLAKE2b-256 a5f236e24879b32c4b1111d94d97104ba2f919290664b19c21a467ef9d053132

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page