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.6-cp314-cp314-win_amd64.whl (963.2 kB view details)

Uploaded CPython 3.14Windows x86-64

minihost-0.1.6-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.6-cp314-cp314-macosx_11_0_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.14macOS 11.0+ x86-64

minihost-0.1.6-cp314-cp314-macosx_11_0_arm64.whl (1.2 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

minihost-0.1.6-cp313-cp313-win_amd64.whl (936.4 kB view details)

Uploaded CPython 3.13Windows x86-64

minihost-0.1.6-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.6-cp313-cp313-macosx_11_0_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.13macOS 11.0+ x86-64

minihost-0.1.6-cp313-cp313-macosx_11_0_arm64.whl (1.2 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

minihost-0.1.6-cp312-cp312-win_amd64.whl (936.4 kB view details)

Uploaded CPython 3.12Windows x86-64

minihost-0.1.6-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.6-cp312-cp312-macosx_11_0_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.12macOS 11.0+ x86-64

minihost-0.1.6-cp312-cp312-macosx_11_0_arm64.whl (1.2 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

minihost-0.1.6-cp311-cp311-win_amd64.whl (936.5 kB view details)

Uploaded CPython 3.11Windows x86-64

minihost-0.1.6-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.6-cp311-cp311-macosx_11_0_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.11macOS 11.0+ x86-64

minihost-0.1.6-cp311-cp311-macosx_11_0_arm64.whl (1.2 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

minihost-0.1.6-cp310-cp310-win_amd64.whl (936.7 kB view details)

Uploaded CPython 3.10Windows x86-64

minihost-0.1.6-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (1.9 MB view details)

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

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

Uploaded CPython 3.10macOS 11.0+ x86-64

minihost-0.1.6-cp310-cp310-macosx_11_0_arm64.whl (1.2 MB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

File details

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

File metadata

  • Download URL: minihost-0.1.6-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 963.2 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.6-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 0be4862a8c5881561d743a8141d5af644795a8724e07f9499926bfdd546fe64a
MD5 fdb8f226a42387ac6c3d6e69d5c1b0c3
BLAKE2b-256 5950c42e18ad3c3f426cdd4b5942a4477af533b7e138ab9d1076b86e621f1d1e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 eedb0abb2c056dace36a21a14834d590c328eed3fbef7f0d9d5a5839dce77d8b
MD5 d9422124a2128fb15c6ed48e6931bb0d
BLAKE2b-256 7709776bcbf64a7bddc675ed8bbf93b17d524fda0e1887236dc6f77a31da0a7b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp314-cp314-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 2875c382dcb0023af81ee58d71d881c60d66463b27c367cd88ac0a6d661491b1
MD5 6ae113b81f93794fe1791db1a3b9874a
BLAKE2b-256 398a9b5e0744e8bf518fcacaa20b311cd806c1a36c3672989f85f378d42783cd

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c9d5532c843777b67390a06011b08b0f80fd8acbdbe9a37fb266401c340b80dc
MD5 7c37d6018f674bd3d0e100dbc46bedba
BLAKE2b-256 e950d5434b8cd37c7f0112d37114808e1fe045274f221c97f2b5588c3467ebd1

See more details on using hashes here.

File details

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

File metadata

  • Download URL: minihost-0.1.6-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 936.4 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.6-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 4392a4a04904bbe8b0fcfee2c9b2bdbd215f762787b15f10eb3473d28615fe60
MD5 60537f47b2cddc7624fc70ab823700cf
BLAKE2b-256 4db4723660e433aa4256f01cde3d1b67fffe2f02f6c62c43bfc2a7d887f840a3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 4e045d247ac38be19aae3827b1f80b316c21dfa28a5ffd8d94816c546e3184e6
MD5 8ac78a150e5011bb4e2ea42bb6c57ade
BLAKE2b-256 ed3a5e4404f7687adbee627b0702508dd9deda25f88a5ecd1655d190abdc9084

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp313-cp313-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 0e56c151f5f3f7ae1beee5bfa5a48ec53ba3d39ef7145c8f79a5281132699baa
MD5 a6f0be02c11baf116279753a8d4973a1
BLAKE2b-256 1d03dd53112e8708071f818a1094b50742f488319696c9f1d1a7c451b30afa51

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 099d4b21f361f6dfe71dbdf5f3fd4cee517e5805ca1f0ce146fdc33e299a7725
MD5 a1a514b506e18549dc84cbe52b7ec782
BLAKE2b-256 78e525d6556d10593259b8d1a53828a09f36e829ff0877f38d71f067af9bd35f

See more details on using hashes here.

File details

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

File metadata

  • Download URL: minihost-0.1.6-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 936.4 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.6-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 92b8bb9e50bd1d8cc4d5cb5977af08d313bc71eb4966dddd0f09fa60b83d4411
MD5 207307192c7653401e70cf66a558a6ae
BLAKE2b-256 ec8a26882b44f552fb01ed07e9fc3dc5a22642e8020cd99b4aff609dd064c1ff

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 d10961d55793da060390649ddcf1209647b8447bcf05fff251dcc5f94296dd58
MD5 38df4ca2f75dc44f25062f3bd4ba5435
BLAKE2b-256 1a391fd5bf672e6c36526478d0422fa5ebb77b396eea46a0e239aefb2aaab0e2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp312-cp312-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 22c10bee147c2bf2f08b11b044140e41b5c9e932bdb46a183c47eee03bc9879e
MD5 05ecc3cd463a5af9ffe6fbec7146aa03
BLAKE2b-256 fa033b7ec52f0f4c041264a8be0d2b0347ba190e72faf41151db8b19d03654d2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 e803e18963e6e542895532d34661d0c77efce8b6e8e0b45b72b7eecbcb142b2e
MD5 a895ea17ea3a3c4506cfb0f5e764c274
BLAKE2b-256 d46304578c758b52b7b19fc6b57ac6bb9130e07c3d9e1227e51ac4f1ba4e630e

See more details on using hashes here.

File details

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

File metadata

  • Download URL: minihost-0.1.6-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 936.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.6-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 b327bd3daef0179db30eba8f820980c3c1ee340b40ff3a53527332618b4177b3
MD5 f276f21a163687bb216460202ce80a6d
BLAKE2b-256 95563eadb8107a1ec2305063888897f6b9c5ed1ceb69de6795b5a79da69efd33

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 2519bafb976b128f37748c555c27182a524f732c3139e42eff5ea9b4440cfcdb
MD5 3ea429a5de60f6fb2c183cc180d5f259
BLAKE2b-256 439677b2039b831bf2d666421b265650a80b2ec22b4ce37c78a600a867b9366f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp311-cp311-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 ebda28ab60d5954beb97b39bb1394145e0c93847c83c5eca51e793e281560cd9
MD5 164b24bfff822849fb7a196280e2ff85
BLAKE2b-256 6b6a4d19f4db6140a5c2a2af4d6dd3977f6df15c122254a9b5e65aa113203d3b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6de7e665aba1857007b7622c58a916b7710c434c831945282788984c33a8338f
MD5 ce938ce0417481ed7c57eac1ab897540
BLAKE2b-256 7143ff5488d75d6d63f3fa6ca5183037bea0f313d49839fa8040a5e8a0868188

See more details on using hashes here.

File details

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

File metadata

  • Download URL: minihost-0.1.6-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 936.7 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.6-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 b552c0bf4032fcfdd7bae0e4e08c4258ccfe69b3a14af37e5baf12d988d90f99
MD5 063b18c5256fa50028ed56acd634ae90
BLAKE2b-256 dc16cf776574b18035a3274dbb1baa360661ffb7c415f295e3ff91f0082f0a06

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b0287469c797d346336337d88ac2544aca4aa01f48d68d3dd29b9e4b54d7d216
MD5 0ec3b3bfa7d73cbfeb4095192940355c
BLAKE2b-256 67d9437742965fafc8fc238fa69d9da3f6452d9305389c7b317a95fcf92d167b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp310-cp310-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 f1266191edcf7b26f3a0fff349474655522734196f1d52ebad456b8fc9287cd6
MD5 636e93857d12d8274946d3c68d57a3ac
BLAKE2b-256 da812fba20a3fdb820dafb5b0f8abe012f45a46f20b21e99856d6c05208bb620

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for minihost-0.1.6-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f179c2161d033a5bb7bdeaa2736a9b8ea95474b52a8a2e8fd1023e91d04acd8a
MD5 1af4dd4e6ce7eab3ec41215ebcaa32ce
BLAKE2b-256 04a44896b7520e71f23d553c16499dfd832186166a55a90092669428c876a5a6

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