A Python wrapper for the Voiceemeter API
Go to file
onyx-and-iris bd686ef67d use time.time() to steady rate of updates.
reduce loop time if waiting for new event
2022-09-29 10:20:05 +01:00
configs added support for setting bus mode through dict 2022-07-16 21:19:10 +01:00
examples loglevel INFO set for examples 2022-09-29 10:01:18 +01:00
tests add patch, option unit tests. 2022-07-21 23:17:42 +01:00
voicemeeterlib use time.time() to steady rate of updates. 2022-09-29 10:20:05 +01:00
__main__.py fix str in readme, __main__. 2022-08-06 10:49:56 +01:00
.gitignore obs example updated for websocket v5 2022-07-29 20:06:26 +01:00
CHANGELOG.md fix ver bump in changelog 2022-09-03 16:33:01 +01:00
LICENSE Initial commit 2022-06-16 13:49:32 +01:00
poetry.lock tomli/tomllib compatibility layer added. 2022-09-03 16:28:19 +01:00
pyproject.toml fix import... oops. 2022-09-24 12:08:43 +01:00
README.md tomli/tomllib compatibility layer added. 2022-09-03 16:28:19 +01:00

PyPI version License: MIT Code style: black Imports: isort Tests Status Tests Status Tests Status

Python Wrapper for Voicemeeter API

This package offers a Python interface for the Voicemeeter Remote C API.

For an outline of past/future changes refer to: CHANGELOG

Tested against

  • Basic 1.0.8.4
  • Banana 2.0.6.4
  • Potato 3.0.2.4

Requirements

Installation

Pip

Install voicemeeter-api package from your console

pip install voicemeeter-api

Use

Simplest use case, use a context manager to request a Remote class of a kind.

Login and logout are handled for you in this scenario.

__main__.py

import voicemeeterlib


class ManyThings:
    def __init__(self, vm):
        self.vm = vm

    def things(self):
        self.vm.strip[0].label = "podmic"
        self.vm.strip[0].mute = True
        print(
            f"strip 0 ({self.vm.strip[0].label}) mute has been set to {self.vm.strip[0].mute}"
        )

    def other_things(self):
        info = (
            f"bus 3 gain has been set to {self.vm.bus[3].gain}",
            f"bus 4 eq has been set to {self.vm.bus[4].eq}",
        )
        self.vm.bus[3].gain = -6.3
        self.vm.bus[4].eq = True
        print("\n".join(info))


def main():
    with voicemeeterlib.api(kind_id) as vm:
        do = ManyThings(vm)
        do.things()
        do.other_things()

        # set many parameters at once
        vm.apply(
            {
                "strip-2": {"A1": True, "B1": True, "gain": -6.0},
                "bus-2": {"mute": True},
                "button-0": {"state": True},
                "vban-in-0": {"on": True},
                "vban-out-1": {"name": "streamname"},
            }
        )


if __name__ == "__main__":
    kind_id = "banana"

    main()

Otherwise you must remember to call vm.login(), vm.logout() at the start/end of your code.

kind_id

Pass the kind of Voicemeeter as an argument. kind_id may be:

  • basic
  • banana
  • potato

Available commands

Strip

The following properties are available.

  • mono: boolean
  • solo: boolean
  • mute: boolean
  • gain: float, from -60.0 to 12.0
  • comp: float, from 0.0 to 10.0
  • gate: float, from 0.0 to 10.0
  • audibility: float, from 0.0 to 10.0
  • limit: int, from -40 to 12
  • A1 - A5, B1 - B3: boolean
  • label: string
  • device: string
  • sr: int
  • mc: boolean
  • k: int, from 0 to 4
  • bass: float, from -12.0 to 12.0
  • mid: float, from -12.0 to 12.0
  • treble: float, from -12.0 to 12.0
  • reverb: float, from 0.0 to 10.0
  • delay: float, from 0.0 to 10.0
  • fx1: float, from 0.0 to 10.0
  • fx2: float, from 0.0 to 10.0
  • pan_x: float, from -0.5 to 0.5
  • pan_y: float, from 0.0 to 1.0
  • color_x: float, from -0.5 to 0.5
  • color_y: float, from 0.0 to 1.0
  • fx_x: float, from -0.5 to 0.5
  • fx_y: float, from 0.0 to 1.0
  • postreverb: boolean
  • postdelay: boolean
  • postfx1: boolean
  • postfx2: boolean

example:

vm.strip[3].gain = 3.7
print(vm.strip[0].label)

The following methods are Available.

  • appgain(name, value): string, float, from 0.0 to 1.0

Set the gain in db by value for the app matching name.

  • appmute(name, value): string, bool

Set mute state as value for the app matching name.

example:

vm.strip[5].appmute("Spotify", True)
vm.strip[5].appgain("Spotify", 0.5)
Gainlayers
  • gain: float, from -60.0 to 12.0

example:

vm.strip[3].gainlayer[3].gain = 3.7

Gainlayers are defined for potato version only.

Levels

The following properties are available.

  • prefader
  • postfader
  • postmute

example:

print(vm.strip[3].levels.prefader)

Level properties will return -200.0 if no audio detected.

Bus

The following properties are available.

  • mono: boolean
  • eq: boolean
  • eq_ab: boolean
  • mute: boolean
  • sel: boolean
  • gain: float, from -60.0 to 12.0
  • label: string
  • device: string
  • sr: int
  • returnreverb: float, from 0.0 to 10.0
  • returndelay: float, from 0.0 to 10.0
  • returnfx1: float, from 0.0 to 10.0
  • returnfx2: float, from 0.0 to 10.0
  • monitor: boolean

example:

vm.bus[3].gain = 3.7
print(vm.bus[0].label)

vm.bus[4].mono = True
Modes

The following properties are available.

  • normal: boolean
  • amix: boolean
  • bmix: boolean
  • composite: boolean
  • tvmix: boolean
  • upmix21: boolean
  • upmix41: boolean
  • upmix61: boolean
  • centeronly: boolean
  • lfeonly: boolean
  • rearonly: boolean

The following methods are available.

  • get(): Returns the current bus mode

example:

vm.bus[4].mode.amix = True

print(vm.bus[2].mode.get())
Levels

The following properties are available.

  • all

example:

print(vm.bus[0].levels.all)

levels.all will return -200.0 if no audio detected.

Strip | Bus

The following methods are available.

  • fadeto(amount, time): float, int
  • fadeby(amount, time): float, int

Modify gain to or by the selected amount in db over a time interval in ms.

example:

vm.strip[0].fadeto(-10.3, 1000)
vm.bus[3].fadeby(-5.6, 500)

Macrobuttons

The following properties are available.

  • state: boolean
  • stateonly: boolean
  • trigger: boolean

example:

vm.button[37].state = True
vm.button[55].trigger = False

Recorder

The following methods are available

  • play()
  • stop()
  • pause()
  • record()
  • ff()
  • rew()
  • load(<filepath>): string

The following properties are available

  • loop: boolean
  • A1 - A5: boolean
  • B1 - A3: boolean

example:

vm.recorder.play()
vm.recorder.stop()

# Enable loop play
vm.recorder.loop = True

# Disable recorder out channel B2
vm.recorder.B2 = False

# filepath as raw string
vm.recorder.load(r'C:\music\mytune.mp3')

Recorder properties are defined as write only.

VBAN

  • vm.vban.enable() vm.vban.disable() Turn VBAN on or off
Instream | Outstream

The following properties are available.

  • on: boolean
  • name: string
  • ip: string
  • port: int, range from 1024 to 65535
  • sr: int, (11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000)
  • channel: int, from 1 to 8
  • bit: int, 16 or 24
  • quality: int, from 0 to 4
  • route: int, from 0 to 8

SR, channel and bit are defined as:

  • readonly for instreams.
  • read and write for outstreams.

example:

# turn VBAN on
vm.vban.enable()

# turn on vban instream 0
vm.vban.instream[0].on = True

# set bit property for outstream 3 to 24
vm.vban.outstream[3].bit = 24

Command

Certain 'special' commands are defined by the API as performing actions rather than setting values.

The following methods are available:

  • show() : Bring Voiceemeter GUI to the front
  • shutdown() : Shuts down the GUI
  • restart() : Restart the audio engine
  • reset(): Applies the reset config. (phys strip B1, virt strip A1, gains, comp, gate 0.0, mute, mono, solo, eq false)

The following properties are available.

  • showvbanchat: boolean
  • lock: boolean

example:

vm.command.restart()
vm.command.showvbanchat = True

showvbanchat and lock are write only.

Device

  • ins outs : Returns the number of input/output devices
  • input(i) output(i) : Returns a dict of device properties for device[i]

example:

import voicemeeterlib
with voicemeeterlib.api(kind_id) as vm:
    for i in range(vm.device.ins):
        print(vm.device.input(i))

FX

The following properties are available:

  • reverb: boolean
  • reverb_ab: boolean
  • delay: boolean
  • delay_ab: boolean

example:

vm.fx.reverb_ab = True

Patch

The following properties are available:

  • postfadercomposite: boolean
  • postfxinsert: boolean

example:

vm.patch.postfxinsert = False
asio[i]
  • get(): int
  • set(patch_in): int, valid range determined by connected device.

example:

vm.patch.asio[3].set(4)

i, from 0 to 10

A2[i] - A5[i]
  • get(): int
  • set(patch_out): int, valid range determined by connected device.

example:

vm.patch.A3[5].set(3)

i, from 0 to 8.

composite[i]
  • get(): int
  • set(channel): int, from 0 up to number of channels depending on version.

example:

vm.patch.composite[7].set(4)

i, from 0 to 8.

insert[i]
  • on: boolean

example:

vm.patch.insert[18].on = True

i, from 0 up to number of channels depending on version.

Option

The following properties are available:

  • sr: int
  • asiosr: boolean
  • monitoronsel: boolean

example:

vm.option.sr = 48000

The following methods are available:

  • buffer(driver, buffer) : Set buffer size for particular audio driver.

example:

vm.option.buffer("wdm", 512)

driver defined as one of ("mme", "wdm", "ks", "asio")

buffer, from 128 to 2048

delay[i]
  • get(): int
  • set(delay): int, from 0 to 500

example:

vm.option.delay[4].set(30)

i, from 0 up to 4.

Midi

The following properties are available:

  • channel: int, returns the midi channel
  • current: int, returns the current (or most recently pressed) key

The following methods are available:

  • get(key): int, returns most recent velocity value for a key

example:

print(vm.midi.get(12))

get() may return None if no value for requested key in midi cache

Multiple parameters

  • apply Set many strip/bus/macrobutton/vban parameters at once, for example:
vm.apply(
    {
        "strip-2": {"A1": True, "B1": True, "gain": -6.0},
        "bus-2": {"mute": True},
        "button-0": {"state": True},
        "vban-in-0": {"on": True},
        "vban-out-1": {"name": "streamname"},
    }
)

Or for each class you may do:

vm.strip[0].apply(mute: True, gain: 3.2, A1: True)
vm.vban.outstream[0].apply(on: True, name: 'streamname', bit: 24)

Config Files

vm.apply_config(<configname>)

You may load config files in TOML format. Three example configs have been included with the package. Remember to save current settings before loading a user config. To set one you may do:

import voicemeeterlib
with voicemeeterlib.api('banana') as vm:
    vm.apply_config('example')

will load a user config file at configs/banana/example.toml for Voicemeeter Banana.

Base Module

Remote class

voicemeeterlib.api(kind_id: str)

You may pass the following optional keyword arguments:

  • sync: boolean=False, force the getters to wait for dirty parameters to clear. For most cases leave this as False.
  • ratelimit: float=0.033, how often to check for updates in ms.
  • subs: dict={"pdirty": True, "mdirty": True, "midi": True, "ldirty": False}, initialize which event updates to listen for.
    • pdirty: parameter updates
    • mdirty: macrobutton updates
    • midi: midi updates
    • ldirty: level updates

Event updates

To receive event updates you should do the following:

  • register your app to receive updates using the vm.subject.add(observer) method, where observer is your app.
  • define an on_update(subject) callback function in your app. The value of subject may be checked for the type of event.

See examples/observer for a demonstration.

Level updates are considered high volume, by default they are NOT listened for. However, polling them with strip.levels and bus.levels methods will still work.

So if you don't wish to receive level updates, or you prefer to handle them yourself simply leave ldirty as default (False).

Each of the update types may be enabled/disabled separately. Don't use a midi controller? You have the option to disable midi updates.

example:

import voicemeeterlib
# Set updates to occur every 50ms
# Listen for level updates but disable midi updates
with voicemeeterlib.api('banana', ratelimit=0.05, subs={"ldirty": True, "midi": False}) as vm:
    ...

vm.event

You may also add/remove event subscriptions as necessary with the Event class.

example:

vm.event.add("ldirty")

vm.event.remove("pdirty")

# get a list of currently subscribed
print(vm.event.get())

Access to lower level Getters and Setters are provided with these functions:

  • vm.get(param, is_string=False): For getting the value of any parameter. Set string to True if getting a property value expected to return a string.
  • vm.set(param, value): For setting the value of any parameter.

Access to lower level polling functions are provided with these functions:

  • vm.pdirty(): Returns True if a parameter has been updated.
  • vm.mdirty(): Returns True if a macrobutton has been updated.
  • vm.ldirty(): Returns True if a level has been updated.

example:

vm.get('Strip[2].Mute')
vm.set('Strip[4].Label', 'stripname')
vm.set('Strip[0].Gain', -3.6)

Run tests

To run all tests:

pytest -v

Official Documentation