Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
This package offers a Python interface for the Voicemeeter Remote C API.
For an outline of past/future changes refer to: CHANGELOG
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):
self.vm.bus[3].gain = -6.3
self.vm.bus[4].eq.on = True
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.on}",
)
print("\n".join(info))
def main():
KIND_ID = "banana"
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, "eq": {"on": True}},
"button-0": {"state": True},
"vban-in-0": {"on": True},
"vban-out-1": {"name": "streamname"},
}
)
if __name__ == "__main__":
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
The following properties are available.
mono
: booleansolo
: booleanmute
: booleangain
: float, from -60.0 to 12.0audibility
: float, from 0.0 to 10.0limit
: int, from -40 to 12A1 - A5
, B1 - B3
: booleanlabel
: stringmc
: booleank
: int, from 0 to 4bass
: float, from -12.0 to 12.0mid
: float, from -12.0 to 12.0treble
: float, from -12.0 to 12.0reverb
: float, from 0.0 to 10.0delay
: float, from 0.0 to 10.0fx1
: float, from 0.0 to 10.0fx2
: float, from 0.0 to 10.0pan_x
: float, from -0.5 to 0.5pan_y
: float, from 0.0 to 1.0color_x
: float, from -0.5 to 0.5color_y
: float, from 0.0 to 1.0fx_x
: float, from -0.5 to 0.5fx_y
: float, from 0.0 to 1.0postreverb
: booleanpostdelay
: booleanpostfx1
: booleanpostfx2
: booleanexample:
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.0Set the gain in db by value for the app matching name.
appmute(name, value)
: string, boolSet mute state as value for the app matching name.
example:
vm.strip[5].appmute("Spotify", True)
vm.strip[5].appgain("Spotify", 0.5)
The following properties are available.
knob
: float, from 0.0 to 10.0gainin
: float, from -24.0 to 24.0ratio
: float, from 1.0 to 8.0threshold
: float, from -40.0 to -3.0attack
: float, from 0.0 to 200.0release
: float, from 0.0 to 5000.0knee
: float, from 0.0 to 1.0gainout
: float, from -24.0 to 24.0makeup
: booleanexample:
print(vm.strip[4].comp.knob)
Strip Comp parameters are defined for PhysicalStrips.
knob
defined for all versions, all other parameters potato only.
The following properties are available.
knob
: float, from 0.0 to 10.0threshold
: float, from -60.0 to -10.0damping
: float, from -60.0 to -10.0bpsidechain
: int, from 100 to 4000attack
: float, from 0.0 to 1000.0hold
: float, from 0.0 to 5000.0release
: float, from 0.0 to 5000.0example:
vm.strip[2].gate.attack = 300.8
Strip Gate parameters are defined for PhysicalStrips.
knob
defined for all versions, all other parameters potato only.
The following properties are available.
knob
: float, from 0.0 to 10.0example:
vm.strip[0].denoiser.knob = 0.5
Strip Denoiser parameters are defined for PhysicalStrips, potato version only.
The following properties are available.
on
: booleanab
: booleanexample:
vm.strip[0].eq.ab = True
Strip EQ parameters are defined for PhysicalStrips, potato version only.
gain
: float, from -60.0 to 12.0example:
vm.strip[3].gainlayer[3].gain = 3.7
Gainlayers are defined for potato version only.
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.
The following properties are available.
mono
: booleanmute
: booleansel
: booleangain
: float, from -60.0 to 12.0label
: stringreturnreverb
: float, from 0.0 to 10.0returndelay
: float, from 0.0 to 10.0returnfx1
: float, from 0.0 to 10.0returnfx2
: float, from 0.0 to 10.0monitor
: booleanexample:
vm.bus[3].gain = 3.7
print(vm.bus[0].label)
vm.bus[4].mono = True
The following properties are available.
on
: booleanab
: booleanexample:
vm.bus[3].eq.on = True
The following properties are available.
normal
: booleanamix
: booleanbmix
: booleancomposite
: booleantvmix
: booleanupmix21
: booleanupmix41
: booleanupmix61
: booleancenteronly
: booleanlfeonly
: booleanrearonly
: booleanThe following methods are available.
get()
: Returns the current bus modeexample:
vm.bus[4].mode.amix = True
print(vm.bus[2].mode.get())
The following properties are available.
all
example:
print(vm.bus[0].levels.all)
levels.all
will return -200.0 if no audio detected.
The following methods are available.
fadeto(amount, time)
: float, intfadeby(amount, time)
: float, intModify 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)
The following properties are available
name
: strsr
: intwdm
: strks
: strmme
: strasio
: strexample:
print(vm.strip[0].device.name)
vm.bus[0].device.asio = "Audient USB Audio ASIO Driver"
strip|bus device parameters are defined for physical channels only.
name, sr are read only. wdm, ks, mme, asio are write only.
The following properties are available.
state
: booleanstateonly
: booleantrigger
: booleanexample:
vm.button[37].state = True
vm.button[55].trigger = False
The following methods are available
play()
stop()
pause()
record()
ff()
rew()
load(filepath)
: raw stringgoto(time_string)
: time string in format hh:mm:ss
filetype(filetype)
: string, ("wav", "aiff", "bwf", "mp3")The following properties are available
A1 - A5
: booleanB1 - B3
: booleansamplerate
: int, (22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000)bitresolution
: int, (8, 16, 24, 32)channel
: int, from 1 to 8kbps
: int, (32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320)gain
: float, from -60.0 to 12.0example:
vm.recorder.play()
vm.recorder.stop()
# Disable recorder out channel B2
vm.recorder.B2 = False
# filepath as raw string
vm.recorder.load(r'C:\music\mytune.mp3')
# set the goto time to 1m 30s
vm.recorder.goto("00:01:30")
The following properties are available
recbus
: booleanplayonload
: booleanloop
: booleanmultitrack
: booleanexample:
# Enable loop play
vm.recorder.mode.loop = True
The following method is available
set(val)
: booleanexample:
# Arm strip 3
vm.recorder.armstrip[3].set(True)
# Arm bus 0
vm.recorder.armbus[0].set(True)
vm.vban.enable()
vm.vban.disable()
Turn VBAN on or offThe following properties are available.
on
: booleanname
: stringip
: stringport
: int, range from 1024 to 65535sr
: int, (11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000)channel
: int, from 1 to 8bit
: int, 16 or 24quality
: int, from 0 to 4route
: int, from 0 to 8SR
, channel
and bit
are defined as:
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
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 frontshutdown()
: Shuts down the GUIrestart()
: Restart the audio enginereset()
: 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
: booleanlock
: booleanexample:
vm.command.restart()
vm.command.showvbanchat = True
showvbanchat
and lock
are write only.
ins
outs
: Returns the number of input/output devicesinput(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))
The following properties are available:
reverb
: booleanreverb_ab
: booleandelay
: booleandelay_ab
: booleanexample:
vm.fx.reverb_ab = True
The following properties are available:
postfadercomposite
: booleanpostfxinsert
: booleanexample:
vm.patch.postfxinsert = False
get()
: intset(patch_in)
: int, valid range determined by connected device.example:
vm.patch.asio[3].set(4)
i, from 0 to 10
get()
: intset(patch_out)
: int, valid range determined by connected device.example:
vm.patch.A3[5].set(3)
i, from 0 to 8.
get()
: intset(channel)
: int, from 0 up to number of channels depending on version.example:
vm.patch.composite[7].set(4)
i, from 0 to 8.
on
: booleanexample:
vm.patch.insert[18].on = True
i, from 0 up to number of channels depending on version.
The following properties are available:
sr
: intasiosr
: booleanmonitoronsel
: booleanexample:
vm.option.sr = 48000
The following methods are available:
buffer(driver, buf)
: Set buffer size for particular audio driver.
example:
vm.option.buffer("wdm", 512)
get()
: intset(delay)
: int, from 0 to 500example:
vm.option.delay[4].set(30)
i, from 0 up to 4.
The following properties are available:
channel
: int, returns the midi channelcurrent
: int, returns the current (or most recently pressed) keyThe following methods are available:
get(key)
: int, returns most recent velocity value for a keyexample:
print(vm.midi.get(12))
get() may return None if no value for requested key in midi cache
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, "eq": {"on": 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})
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 load one you may do:
import voicemeeterlib
with voicemeeterlib.api('banana') as vm:
vm.apply_config('example')
Your configs may be located in one of the following paths:
If a config with the same name is located in multiple locations, only the first one found is loaded into memory, in the above order.
config extends
You may also load a config that extends another config with overrides or additional parameters.
You just need to define a key extends
in the config TOML, that names the config to be extended.
Three example 'extender' configs are included with the repo. You may load them with:
import voicemeeterlib
with voicemeeterlib.api('banana') as vm:
vm.apply_config('extender')
By default, NO events are listened for. Use events kwargs to enable specific event types.
example:
import voicemeeterlib
# Set event updates to occur every 50ms
# Listen for level updates only
with voicemeeterlib.api('banana', ratelimit=0.05, ldirty=True) as vm:
...
vm.observer
Use the Subject class to register an app as event observer.
The following methods are available:
add
: registers an app as an event observerremove
: deregisters an app as an event observerexample:
# register an app to receive updates
class App():
def __init__(self, vm):
vm.observer.add(self)
...
vm.event
Use the event class to toggle updates as necessary.
The following properties are available:
pdirty
: booleanmdirty
: booleanmidi
: booleanldirty
: booleanexample:
vm.event.ldirty = True
vm.event.pdirty = False
Or add, remove a list of events.
The following methods are available:
add()
remove()
get()
example:
vm.event.remove(["pdirty", "mdirty", "midi"])
# get a list of currently subscribed
print(vm.event.get())
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.pdirty
: boolean=False, parameter updatesmdirty
: boolean=False, macrobutton updatesmidi
: boolean=False, midi updatesldirty
: boolean=False, level updatestimeout
: float=2.0, maximum time to wait for a successful login in secondsbits
: int=64, (may be one of 32 or 64), overrides the type of Voicemeeter GUI {Remote}.run_voicemeeter() will launchAccess 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.example:
vm.get('Strip[2].Mute')
vm.set('Strip[4].Label', 'stripname')
vm.set('Strip[0].Gain', -3.6)
Access to lower level polling functions are provided with the following property objects:
vm.pdirty
True iff a parameter has been updated.
vm.mdirty
True iff a macrobutton has been updated.
vm.ldirty
True iff a level has been updated.
errors.VMError
: Base custom exception class.errors.InstallError
: Exception raised when installation errors occur.errors.CAPIError
: Exception raised when the C-API returns error values.
fn_name
: C-API function name.code
: error codeIt's possible to see the messages sent by the interface's setters and getters, may be useful for debugging.
example:
import voicemeeterlib
logging.basicConfig(level=logging.DEBUG)
with voicemeeterlib.api("banana") as vm:
...
To run all tests:
pytest -v
FAQs
A Python wrapper for the Voiceemeter API
We found that voicemeeter-api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.