Giter Site home page Giter Site logo

saifaqqad / vmr.ahk Goto Github PK

View Code? Open in Web Editor NEW
39.0 5.0 3.0 876 KB

AutoHotkey wrapper class for Voicemeeter's Remote API

Home Page: https://saifaqqad.github.io/VMR.ahk/

AutoHotkey 100.00%
voicemeeter-api voicemeeter-remote voicemeeter ahk autohotkey ahkpm-package

vmr.ahk's People

Contributors

onerandomusername avatar onyx-and-iris avatar saifaqqad avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

vmr.ahk's Issues

VMR.ahk for ahk v2

Hello, could you please convert the vmr.ahk code to be compatible with ahkv2? Thanks

Voicemeeter goes down

Thanks so much for writing this! I've found it very useful.

Modified the following that allows user to restart Voicemeeter if it goes down while script is running.

/* Original
IsParametersDirty(){
return DllCall(VBVMR.VM_DLL . "\VBVMR_IsParametersDirty")
}
*/
; Modified 2020-10-02
IsParametersDirty(){
a:= DllCall(VBVMR.VM_DLL . "\VBVMR_IsParametersDirty")
if ( a < 0 )
{
msgbox Voicemeeter is down, please restart then then press OK
return 1
}
return a
}

Using Gain Layer

I noticed that a few new Parameters were added to the Voicemeeter Remote API as of November 2022 with the new Version 3. One of them being the GainLayer Input Strip Parameter.
Is there any Way of making use of this Parameter in the current state of vmr.ahk?
The setParameter function does not work as far as I can tell because the GainLayer itself needs the Parameter of the desired Bus AND the desired gain which cannot be accomplished.

I would much appreciate any solution to using GainLayer in vmr.ahk
Thanks in Advance

From the Documentation of the Remote API:
image

Release version 1.1.0 with ahkpm support?

Hi @SaifAqqad. Thanks so much for adding ahkpm support to this library!

I was just playing around with generating an ahkpm demo using the VMR.ahk package and noticed that while there is a version 1.0.0 tagged, there hasn't been a new version released since you added ahkpm support.

That means that when users install via ahkpm, they'll get 1.0.0, but when they try to use ahkpm include, they'll get an error about VMR.ahk not having an ahkpm.json file.

voicemeeter.show() ?

6-MacroButton: New command Show(0/1) to Hide/Show the MacroButtons Application.

Show(0); Wait(1000); Show(1);

I think that this is not available in the Voicemeeter API, and that it is not planned, but I am curious to have an answer that status this.

Gui freezes (solved)

Hi,` the GUI app (buses and strips) is working fine; changing volume or output device with a hotkey within the main GUI script works too, but if I change volume (bus or strip) or any output device (e.g., A1 to A2) from another AHK script, the GUI freezes. After reloading, it starts working again.
I think parameter updating stops working while making any changes from another ahk script. I like this GUI script. Any help is appreciated.
Thanks

edit:

hi,
I made two GUIs, one for the buses and the other for the strips.
You can show or hide any of the GUIs with a button on the GUI.
Now, if I make any changes to the volume or to the output devices from another script, the GUI does not freeze.
Thanks for the help.
regards

#Include, %A_ScriptDir%\..\dist\VMR.ahk
SetBatchLines, 20ms

Global vm, GUI_hwnd, is_win_pos_changing:=0
vm := new VMR().login()

showUI()
vm.onUpdateLevels:= Func("syncLevel") ; register level callback func
vm.onUpdateParameters:= Func("syncParameters") ; register params callback func
OnMessage(0x46, Func("onPosChanging"))

showUI(){
 global

;gui1, buses
    Gui, 1: +HwndGUI_hwnd
    xPos := 45
    Loop % vm.bus.Length() { ; add UI controls for each bus
        yPos:=42, funcObj:=""
        yPos+= 40
        Gui,1: Add, Progress, x%xPos% y%yPos% w10 h100 Range-72-20 c0x70C399 Background0x2C3D4D vertical Hwndbus_%A_Index%_level

        ;bus gain
        yPos+= 110
        Gui,1: Add, Edit, w48 h20 x%xPos% y%yPos% ReadOnly
        Gui,1: Add, UpDown,Hwndbus_%A_Index%_gain Range-60-12 x0
        funcObj:= Func("updateParam").bind("bus", "gain", A_Index)
        GuiControl +g, % bus_%A_Index%_gain, % FuncObj

        ;bus mute
        yPos+= 32
	Gui, 1: Font, cC3C3C3 s11 norm, Calibri
        Gui, 1:Add, CheckBox, x%xPos% y%yPos% c7e7de5 Hwndbus_%A_Index%_mute, Mute
        funcObj:= Func("updateParam").bind("bus", "mute", A_Index)
        GuiControl +g, % bus_%A_Index%_mute, % FuncObj

        xPos+=52
	}

;gui2 strips
    Gui, 2: +HwndGUI_hwnd
    xPos:= 20
    Loop % vm.strip.Length() { ; add UI controls for each strip
        yPos:=42 funcObj:=""
        yPos+= 40
        Gui, 2: Add, Progress, x%xPos% y%yPos% w10 h100 Range-72-20 c0x70C399 Background0x2C3D4D vertical Hwndstrip_%A_Index%_level

        ;strip gain
        yPos+= 110
	Gui, 2: Font, cC3C3C3 s12 bold, Calibri
        Gui, 2:Add, Edit, w48 h20 x%xPos% y%yPos% ReadOnly
        Gui, 2:Add, UpDown,Hwndstrip_%A_Index%_gain Range-60-12 x0
        funcObj:= Func("updateParam").bind("strip", "gain", A_Index)
        GuiControl +g, % strip_%A_Index%_gain, % FuncObj

	;strip mute
        yPos+= 32
	Gui, 2:Font, cC3C3C3 s11 norm, Calibri
        Gui, 2: Add, CheckBox, x%xPos% y%yPos% c7e7de5 Hwndstrip_%A_Index%_mute, Mute
        funcObj:= Func("updateParam").bind("strip", "mute", A_Index)
        GuiControl +g, % strip_%A_Index%_mute, % FuncObj

	xPos+=52
	}
	syncParameters() ; get initial values for gui controls

;gui1 show
	Gui, 1:+ToolWindow -Caption +LastFound
	Gui, 1: Add, Text, cYellow x150 y248, vmBuses
	Gui, 1:Color, 224e70
	WinSet,Transparent, 150
	Gui,1: Show, x1496 y678 W340 H272, buses

;gui2 show
	Gui, 2: +ToolWindow -Caption +LastFound
	Gui, 2:Add, Text, cYellow x150 y248, vmStrips
	Gui, 2: Color, 224e70
	WinSet,Transparent, 150
	Gui,2: Show, x1134 y678 W290 H272, strips
}
return

; update voicemeeter bus parameters when they change on the AHK UI
updateParam(type, param, index){
    GuiControlGet, val,,% %type%_%index%_%param%
    if(param == "device"){
        RegExMatch(val, "iO)(?<driver>\w+): (?<name>.+)", match)
        if(match)
            vm[type][index].device[match.driver]:= match.name
        else
            vm[type][index].device:= ""
    }else{
        vm[type][index][param]:= val
    }
    SetTimer, syncParameters, -500 ; make sure params are in sync
}

; sync AHK UI controls with voicemeeter bus parameters
syncParameters(){
    Loop % vm.bus.Length() {
        GuiControl,1:, % bus_%A_Index%_gain, % vm.bus[A_Index].gain
        GuiControl,1:, % bus_%A_Index%_mute, % Format("{:i}", vm.bus[A_Index].mute) ; convert 0.0/1.0 to 0/1
    }

    Loop % vm.strip.Length() {
        GuiControl,2:, % strip_%A_Index%_gain, % vm.strip[A_Index].gain
        GuiControl,2:, % strip_%A_Index%_mute, % Format("{:i}", vm.strip[A_Index].mute) ; convert 0.0/1.0 to 0/1
	}
}
; sync level meters with vm bus levels
syncLevel(){
    if(is_win_pos_changing) ;dont update levels if the window is changing its position
        return
    Loop % vm.bus.Length() {
        GuiControl,1:, % bus_%A_Index%_level, % Max(vm.bus[A_Index].level*) ; get peak level for the bus
    }
    Loop % vm.strip.Length() {
        GuiControl,2:, % strip_%A_Index%_level, % Max(vm.strip[A_Index].level*) ; get peak level for the bus
    }
}

onPosChanging(){
    is_win_pos_changing:=1
    SetTimer, onPosChanged, -50
}

onPosChanged(){
    is_win_pos_changing:=0
}

Random error, VBVMR_GetParameterFloat returned -6

I have this error in a completely random way, I also put you the related autohotkey code to try to reproduce it

image

#if WinExist("ahk_exe VALORANT-Win64-Shipping.exe")
	~*u::
	~*v::
		if (vmr.strip[1].B1 == false && WinActive("ahk_exe VALORANT-Win64-Shipping.exe"))
			vmr.strip[1].B1 := !vmr.strip[1].B1
	return

	~*u Up::
	~*v Up::
		if (vmr.strip[1].B1 == true && WinActive("ahk_exe VALORANT-Win64-Shipping.exe"))
			vmr.strip[1].B1 := !vmr.strip[1].B1
	return
#if

Recorder Loading issues

Hi, I am trying to load an mp3 file, but it gives me this error. I don't really know if I did something wrong but maybe it's a bug. I figured out that the same error occurs when I don't put in anything at all, so this could just be me fucking up but I am certain that the file is in that location and I've checked it multiple times, but yea it still could be lol

Error:

image

This is the file i want to load

image

The part of my code that crashes

voicemeeter := new VMR()
voicemeeter.login()

voicemeeter.recorder["mode.PlayOnLoad"]:= true

voicemeeter.recorder.load:= "D:\Music\Trance-Music-for-Racing-Game.mp3"

This is where the error occurs

SetParameterString(p_prefix, p_parameter, p_value){
        this.IsParametersDirty()
        errLevel := DllCall(VBVMR.FUNC_ADDR["SetParameterString" . VBVMR.STR_TYPE], "AStr", p_prefix . "." . p_parameter , VBVMR.STR_TYPE . "Str" , p_value , "Int")
        if (errLevel<0)
            Throw, Format("`nVBVMR_SetParameterString returned {}`nDllCall returned {}", errLevel, ErrorLevel)
        return p_value
}

GetParameterFloat(p_prefix, p_parameter){
        local value
        this.IsParametersDirty()
        VarSetCapacity(value, 4)
        errLevel := DllCall(VBVMR.FUNC_ADDR.GetParameterFloat, "AStr" , p_prefix . "." . p_parameter , "Ptr" , &value, "Int")
        if (errLevel<0)
            Throw, Format("`nVBVMR_GetParameterFloat returned {}`nDllCall returned {}", errLevel, ErrorLevel)
        value := NumGet(&value, 0, "Float")
        return value
    }

Strips UI

May i make a request? Can you make the Strips UI in ahk v1 the way you made the buses(UI)?
I tried (Voicemeeter Compact) by Onyx and Iris in Python, but it takes almost 10% of CPU whereas ahk takes only 1 or 1.5%.
I'm also using Cantabile to run the vst plugins along with Voicemeeter that also takes some percentage of the CPU.
look forward to hearing from you.
edit:
I tried and made it. (Strip UI), ### Thanks
regards

The value of voicemeeter.recorder.goto isn't a string

First of all, thank you for providing this code, but when I was trying to use voicemeeter.recorder.goto, it set the position in the song always to 0. When searching for the reason, I saw that in "class recorder_base"(line 496ff.) "goto" is defined like "load" to require a string as its value, but "goto" only works if its value type is a float.

Original code:

   class recorder_base {
        __Set(p_name,p_value){
            local type:= "Float"
            if p_name contains goto,load
                type:= "String"
            return (VBVMR)["SetParameter" type]("Recorder", p_name, p_value)
        }

        __Get(p_name){
            local type:= "Float"
            if p_name contains goto,load
                type:= "String"
            return (VBVMR)["GetParameter" type]("Recorder", p_name)
        }

Adjusted code (that appears to work):

   class recorder_base {
        
        __Set(p_name,p_value){
            local type:= "Float"
            if p_name contains goto
            {
                type:= "Float"
            }
            else if p_name contains load
            {
                type:= "String"
            }
            return (VBVMR)["SetParameter" type]("Recorder", p_name, p_value)
        }

        __Get(p_name){
            local type:= "Float"
            if p_name contains goto
            {
                type:= "Float"
            }
            else if p_name contains load
            {
                type:= "String"
            }
            return (VBVMR)["GetParameter" type]("Recorder", p_name)
        }

only hotkeys working with voicemeeter focus are volume up and down and mute

#Requires AutoHotkey v2
#include VMR.ahk
voicemeeter := VMR().Login()
/*
voicemeeter controls
*/
Volume_Mute::{
    voicemeeter.Strip[6].mute := -1
    voicemeeter.Strip[7].mute := -1
    voicemeeter.Strip[8].mute := -1
    if is_muted := voicemeeter.Strip[6].mute
        DisplayOsd("UnMuted", 1000)
    else
        DisplayOsd("Muted", 1000)
}
F23::{
    if (voicemeeter.Strip[6].A1 == 1) {
        DisplayOsd("Headphones", 1000)
        voicemeeter.Strip[6].A2 := true
        voicemeeter.Strip[7].A2 := true
        voicemeeter.Strip[8].A2 := true
        voicemeeter.Strip[6].A1 := false
        voicemeeter.Strip[7].A1 := false
        voicemeeter.Strip[8].A1 := false
    } else {
        DisplayOsd("Speakers", 1000)
        voicemeeter.Strip[6].A2 := false
        voicemeeter.Strip[7].A2 := false
        voicemeeter.Strip[8].A2 := false
        voicemeeter.Strip[6].A1 := true
        voicemeeter.Strip[7].A1 := true
        voicemeeter.Strip[8].A1 := true
    }
}
F24::{
    if (voicemeeter.Strip[6].A3 == 1) {
        DisplayOsd("TV off", 1000)
        voicemeeter.Strip[6].A3 := false
        voicemeeter.Strip[7].A3 := false
        voicemeeter.Strip[8].A3 := false
    } else {
        DisplayOsd("TV on", 1000)
        voicemeeter.Strip[6].A3 := true
        voicemeeter.Strip[7].A3 := true
        voicemeeter.Strip[8].A3 := true
    }
}
F16 & Volume_Up::{
    voicemeeter.Bus[1].Increment("gain", 1).Then(gain => DisplayBusVol(1, gain))
    voicemeeter.Bus[2].Increment("gain", 1).Then(gain => DisplayBusVol(2, gain))
    voicemeeter.Bus[3].Increment("gain", 1).Then(gain => DisplayBusVol(3, gain))
}
F16 & Volume_Down::{
    voicemeeter.Bus[1].Increment("gain", -1).Then(gain => DisplayBusVol(1, gain))
    voicemeeter.Bus[2].Increment("gain", -1).Then(gain => DisplayBusVol(2, gain))
    voicemeeter.Bus[3].Increment("gain", -1).Then(gain => DisplayBusVol(3, gain))
}
DisplayBusVol(*) {
    SetTimer () => DisplayOsd(
        "Gain: " voicemeeter.Bus[1].gain
        "," voicemeeter.Bus[2].gain
        "," voicemeeter.Bus[3].gain,
        500
    ), -100
}
Volume_Down::{
    voicemeeter.Strip[6].Increment("gain", -1).Then(gain => DisplayVol(6, gain))
    voicemeeter.Strip[7].Increment("gain", -1).Then(gain => DisplayVol(7, gain))
    voicemeeter.Strip[8].Increment("gain", -1).Then(gain => DisplayVol(8, gain))
}
Volume_Up::{
    voicemeeter.Strip[6].Increment("gain", 1).Then(gain => DisplayVol(6, gain))
    voicemeeter.Strip[7].Increment("gain", 1).Then(gain => DisplayVol(7, gain))
    voicemeeter.Strip[8].Increment("gain", 1).Then(gain => DisplayVol(8, gain))
}
DisplayVol(*) {
    SetTimer () => DisplayOsd(
        "Gain: " voicemeeter.Strip[6].gain
        "," voicemeeter.Strip[7].gain
        "," voicemeeter.Strip[8].gain,
        500
    ), -100
}
DisplayOsd(text, timeout) {
        textColor := "d400cd"
        bgColor := "000000"
        g := Gui("+AlwaysOnTop +ToolWindow +E0x20 -Caption -SysMenu -Owner", "OSD")
        g.BackColor := bgColor
        g.SetFont "s16", "fixedsys"
        g.AddText "x10 y10 h40 c" textColor, text
        g.Show "NoActivate x10 y10 h35"
        SetTimer () => g.Destroy(), -Abs(timeout)
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.