voicemeeter-connector
Version:
A Connector to use the Voicemeeter API
3 lines (2 loc) • 14.2 kB
JavaScript
import e from"koffi";import t from"winreg";var a,r,o;!function(e){e.Mono="Mono",e.Mute="Mute",e.Solo="Solo",e.MC="MC",e.Gain="Gain",e.Pan_x="Pan_x",e.Pan_y="Pan_y",e.Color_x="Color_x",e.Color_y="Color_y",e.fx_x="fx_x",e.fx_y="fx_y",e.Audibility="Audibility",e.Comp="Comp",e.Gate="Gate",e.EqGain1="EqGain1",e.EqGain2="EqGain2",e.EqGain3="EqGain3",e.Label="Label",e.A1="A1",e.A2="A2",e.A3="A3",e.A4="A4",e.A5="A5",e.B1="B1",e.B2="B2",e.B3="B3",e.FadeTo="FadeTo"}(a||(a={})),function(e){e.Mono="Mono",e.Mute="Mute",e.EQ="EQ.on",e.Gain="Gain",e.NormalMode="mode.normal",e.AmixMode="mode.Amix",e.BmixMode="mode.Bmix",e.RepeatMode="mode.Repeat",e.CompositeMode="mode.Composite",e.FadeTo="FadeTo",e.Label="Label"}(r||(r={})),function(e){e[e.DEFAULT=0]="DEFAULT",e[e.STATEONLY=2]="STATEONLY",e[e.TRIGGER=3]="TRIGGER",e[e.COLOR=4]="COLOR"}(o||(o={}));const i={pointer:null,awaitUnregister:[],ended:!0};var n,s;!function(e){e[e.INPUT=1]="INPUT",e[e.OUTPUT=2]="OUTPUT",e[e.MAIN=4]="MAIN"}(n||(n={})),function(e){e[e.STARTING=1]="STARTING",e[e.ENDING=2]="ENDING",e[e.CHANGE=3]="CHANGE",e[e.BUFFER_IN=10]="BUFFER_IN",e[e.BUFFER_OUT=11]="BUFFER_OUT",e[e.BUFFER_MAIN=20]="BUFFER_MAIN"}(s||(s={}));const l=e.struct("VBVMR_T_AUDIOINFO",{samplerate:"long",nbSamplePerFrame:"long"}),c=e.struct("VBVMR_T_AUDIOBUFFER",{audiobuffer_sr:"long",audiobuffer_nbs:"long",audiobuffer_nbi:"long",audiobuffer_nbo:"long",audiobuffer_r:e.array("float*",128),audiobuffer_w:e.array("float*",128)});var u={__proto__:null,InterfaceTypes:{strip:0,bus:1},get StripProperties(){return a},get BusProperties(){return r},get MacroButtonModes(){return o},InitialAudioCallbackState:i,get AudioCallbackModes(){return n},get AudioCallbackCommands(){return s},AudioInfoStruct:l,AudioBufferStruct:c};function d(){return d=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var r in a)({}).hasOwnProperty.call(a,r)&&(e[r]=a[r])}return e},d.apply(null,arguments)}let h,_=e=>e;var f;let p,V,g;class b{constructor(){this.isInitialised=!1,this.isConnected=!1,this.outputDevices=[],this.inputDevices=[],this.version="",this.type=void 0,this.eventPool=[],this.stringParameters=["Label","FadeTo","FadeBy","AppGain","AppMute","name","ip"],this.timerInterval=void 0,this.audioCallbackStates={[n.MAIN]:d({},i),[n.INPUT]:d({},i),[n.OUTPUT]:d({},i)},this.awaitAudioCallbackEvents={start:[],stop:[]},this.connect=()=>{if(!this.isInitialised)throw new Error("Await the initialisation before connect");if(this.isConnected)return{success:!0,message:"Already connected.",code:0};const e=p.VBVMR_Login();switch(e){case 0:return this.isConnected=!0,this.type=this.getVoicemeeterType(),this.version=this.getVoicemeeterVersion(),this.timerInterval=setInterval(this.checkPropertyChange,10),{success:!0,message:"Successfully connected to VoiceMeeter (VM Running).",code:0};case 1:return this.isConnected=!0,this.type=void 0,this.version="Unknown",this.timerInterval=setInterval(this.checkPropertyChange,10),{success:!0,message:"Connected to VoiceMeeter API (VM App Not Running).",code:1};case-1:throw this.isConnected=!1,new Error("VoiceMeeter connection failed: Unable to get client (Unexpected error -1).");case-2:throw this.isConnected=!1,new Error("VoiceMeeter connection failed: Unexpected login (Expected logout first -2).");default:throw this.isConnected=!1,new Error(`VoiceMeeter connection failed with unknown error code: ${e}.`)}},this.disconnect=()=>{if(!this.isConnected)throw new Error("Not connected ");try{if(this.unregisterAllAudioCallbacks().catch(()=>{}),0===p.VBVMR_Logout())return clearInterval(this.timerInterval),void(this.isConnected=!1);throw new Error("Disconnect failed")}catch(e){throw new Error("Disconnect failed")}},this.updateDeviceList=()=>{if(!this.isConnected)throw new Error("Not connected ");this.outputDevices=[],this.inputDevices=[];const e=p.VBVMR_Output_GetDeviceNumber();for(let t=0;t<e;t++){const e=Buffer.alloc(256),a=Buffer.alloc(256),r=[0];p.VBVMR_Output_GetDeviceDescA(t,r,a,e),this.outputDevices.push({name:a.toString().replaceAll(/\u0000+$/g,""),hardwareId:e.toString().replaceAll(/\u0000+$/g,""),type:r[0]})}const t=p.VBVMR_Input_GetDeviceNumber();for(let e=0;e<t;e++){const t=Buffer.alloc(256),a=Buffer.alloc(256),r=[0];p.VBVMR_Input_GetDeviceDescA(e,r,a,t),this.inputDevices.push({name:a.toString().replaceAll(/\u0000+$/g,""),hardwareId:t.toString().replaceAll(/\u0000+$/g,""),type:r[0]})}},this.isParametersDirty=()=>p.VBVMR_IsParametersDirty(),this.getBusParameter=(e,t)=>this.getParameter("Bus",e,t),this.getStripParameter=(e,t)=>this.getParameter("Strip",e,t),this.setStripParameter=(e,t,a)=>this.setParameter("Strip",e,t,a),this.setBusParameter=(e,t,a)=>this.setParameter("Bus",e,t,a),this.attachChangeEvent=e=>{this.eventPool.push(e)},this.getOption=e=>{if(!this.isConnected)throw new Error("Not correct connected ");if(this.stringParameters.some(t=>e.includes(t))){const t=Buffer.alloc(512);return p.VBVMR_GetParameterStringA(e,t),[...String.fromCharCode.apply(null,t)].filter(e=>"\0"!==e).join("")}const t=[0];return p.VBVMR_GetParameterFloat(e,t),t[0]},this.setOption=e=>{const t=Buffer.alloc(e.length+1);return t.fill(0).write(e),p.VBVMR_SetParameters(t),new Promise(e=>{setTimeout(e,200)})},this.isMacroButtonDirty=()=>p.VBVMR_MacroButton_IsDirty(),this.getMacroButtonStatus=(e,t=o.DEFAULT)=>{const a=[0];if(0===p.VBVMR_MacroButton_GetStatus(e,a,t))return a[0];throw new Error(`Failed to get macro button ${e} status`)},this.setMacroButtonStatus=(e,t,a=o.DEFAULT)=>{if(0!==p.VBVMR_MacroButton_SetStatus(e,t,a))throw new Error(`Failed to set macro button ${e} status`)},this.registerAudioCallback=(t,a,r,o)=>{var i;if(null!==this.audioCallbackStates[t].pointer)throw new Error(`Audio callback for "${t}" is already registered.`);this.audioCallbackStates[t].pointer=e.register((a,i,n,l)=>{let c;try{switch(i){case s.STARTING:this.audioCallbackStates[t].ended=!1,c={lpUser:a,nnn:l,command:i,data:this.convertToAudioCallbackInfo(n)},this.resolveAudioCallbackEvent("start");break;case s.ENDING:this.audioCallbackStates[t].ended=!0,c={lpUser:a,nnn:l,command:i,data:this.convertToAudioCallbackInfo(n)},this.resolveAudioCallbackEvent("stop");break;case s.CHANGE:var u;c={lpUser:a,nnn:l,command:i,data:this.convertToAudioCallbackInfo(n)},(null==(u=null==o?void 0:o.restartOnChangedStream)||u)&&setTimeout(()=>{this.startAudioCallback().catch(e=>{const t=this.convertToErrorObject(e);t.message="Failed to restart callback after changed stream: "+t.message,r(t,c)})},50);break;case s.BUFFER_IN:case s.BUFFER_OUT:case s.BUFFER_MAIN:c={lpUser:a,nnn:l,command:i,data:this.convertToAudioCallbackBuffer(n)};break;default:return 0}if(i===s.ENDING&&this.audioCallbackStates[t].awaitUnregister.length>0&&null!==this.audioCallbackStates[t].pointer)for(e.unregister(this.audioCallbackStates[t].pointer),this.audioCallbackStates[t].pointer=null;this.audioCallbackStates[t].awaitUnregister.length>0;){const e=this.audioCallbackStates[t].awaitUnregister.shift();void 0!==e&&e()}}catch(e){const t=this.convertToErrorObject(e);return r(t,c),0}return r(null,c),0},V);const n=Buffer.alloc(64);n.write(a);const l=p.VBVMR_AudioCallbackRegister(t,this.audioCallbackStates[t].pointer,null!=(i=null==o?void 0:o.lpUser)?i:null,n);switch(l){case 0:return;case-1:throw new Error("Failed to register audio callback");case-2:{const e=n.toString().replace("/\0+$/g","");throw new Error(`Audio callback already registered by: ${e}`)}default:throw new Error(`Unexpected result registering audio callback: ${l}`)}},this.startAudioCallback=()=>new Promise((e,t)=>{const a=p.VBVMR_AudioCallbackStart();if(0===a)return void this.awaitAudioCallbackEvents.start.push(()=>e());let r;switch(a){case-1:r="Failed to start audio callback";break;case-2:r="No audio callback registered";break;default:r=`Unexpected result starting audio callback ${a}`}t(new Error(r))}),this.stopAudioCallback=()=>new Promise((e,t)=>{const a=p.VBVMR_AudioCallbackStop();if(0===a)return void this.awaitAudioCallbackEvents.stop.push(()=>e());let r;switch(a){case-1:r="Failed to stop audio callback";break;case-2:r="No audio callback registered";break;default:r=`Unexpected result stopping audio callback: ${a}`}t(r)}),this.unregisterAudioCallback=t=>new Promise((a,r)=>{if(null===this.audioCallbackStates[t].pointer)return void r(new Error(`No audio callback registered for "${t}"`));const o=p.VBVMR_AudioCallbackUnregister(this.audioCallbackStates[t].pointer);switch(o){case 0:return void(this.audioCallbackStates[t].ended?(e.unregister(this.audioCallbackStates[t].pointer),this.audioCallbackStates[t].pointer=null,a()):this.audioCallbackStates[t].awaitUnregister.push(()=>a()));case-1:r(new Error("Failed to unregister audio callback"));break;case-2:this.audioCallbackStates[t].pointer=null,a();break;default:r(new Error(`Unexpected result unregistering audio callback ${o}`))}}),this.unregisterAllAudioCallbacks=()=>{const e=[];for(const[t,a]of Object.entries(this.audioCallbackStates))null!==a.pointer&&e.push(this.unregisterAudioCallback(t));return Promise.all(e)},this.convertToAudioCallbackInfo=t=>{const a=e.decode(t,l);return{sampleRate:a.samplerate,samplesPerFrame:a.nbSamplePerFrame}},this.convertToAudioCallbackBuffer=t=>{const a=e.decode(t,c),r={sampleRate:a.audiobuffer_sr,samplesPerFrame:a.audiobuffer_nbs,inputChannelCount:a.audiobuffer_nbi,outputChannelCount:a.audiobuffer_nbo,inputChannels:[],outputChannels:[]};for(let t=0;t<a.audiobuffer_nbi;t++)r.inputChannels.push(new Float32Array(e.view(a.audiobuffer_r[t],4*a.audiobuffer_nbs)));for(let t=0;t<a.audiobuffer_nbo;t++)r.outputChannels.push(new Float32Array(e.view(a.audiobuffer_w[t],4*a.audiobuffer_nbs)));return r},this.convertToErrorObject=e=>e instanceof Error?e:"string"==typeof e?new Error(e):new Error(`Unknown error: ${String(e)}`),this.checkPropertyChange=()=>{let e=!1;if(1===this.isParametersDirty()&&(e=!0),1===this.isMacroButtonDirty()&&(e=!0),e)for(const e of this.eventPool)e()},this.getVoicemeeterType=()=>{const e=[0];if(0!==p.VBVMR_GetVoicemeeterType(e))throw new Error("running failed");switch(e[0]){case 1:return"voicemeeter";case 2:return"voicemeeterBanana";case 3:return"voicemeeterPotato";default:throw new Error("Voicemeeter seems not to be installed")}},this.getVoicemeeterVersion=()=>{const e=[0];if(0!==p.VBVMR_GetVoicemeeterVersion(e))throw new Error("running failed");return((4278190080&e[0])>>24)+"."+((16711680&e[0])>>16)+"."+((65280&e[0])>>8)+"."+(255&e[0])},this.getParameter=(e,t,a)=>this.getOption(`${e}[${t}].${a}`),this.setParameter=(e,t,a,r)=>{if(!this.isConnected)throw new Error("Not connected ");return this.setOption(`${e}[${t}].${a}=${r};`)},this.getLevel=(e,t)=>{const a=[0];return p.VBVMR_GetLevel(e,t,a),a[0]}}get $outputDevices(){return this.outputDevices}get $inputDevices(){return this.inputDevices}get $version(){return this.version}get $type(){return this.type}resolveAudioCallbackEvent(e){for(;this.awaitAudioCallbackEvents[e].length>0;){const t=this.awaitAudioCallbackEvents[e].shift();void 0!==t&&t()}}}f=b,b.init=async()=>{const a=await(async()=>{const e=new t({hive:t.HKLM,key:String.raw(h||(h=_`\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\VB:Voicemeeter {17359A74-1236-5467}`))});return new Promise(t=>{e.values((e,a)=>{if(e)throw new Error(e);const r=a.find(e=>"UninstallString"===e.name).value,o=r.lastIndexOf("\\");t(r.slice(0,o))})})})();return new Promise(t=>{g||(g=new f);const r=e.load(`${a}/VoicemeeterRemote64.dll`);p={VBVMR_Login:r.func("long __stdcall VBVMR_Login(void)"),VBVMR_Logout:r.func("long __stdcall VBVMR_Logout(void)"),VBVMR_RunVoicemeeter:r.func("long __stdcall VBVMR_RunVoicemeeter(long mode)"),VBVMR_IsParametersDirty:r.func("long __stdcall VBVMR_IsParametersDirty(void)"),VBVMR_GetLevel:r.func("long __stdcall VBVMR_GetLevel(long type, long channel, _Out_ float* value)"),VBVMR_GetParameterFloat:r.func("long __stdcall VBVMR_GetParameterFloat(const char* param, _Out_ float* value)"),VBVMR_GetParameterStringA:r.func("long __stdcall VBVMR_GetParameterStringA(const char* param, _Out_ char* value)"),VBVMR_SetParameters:r.func("long __stdcall VBVMR_SetParameters(const char* param)"),VBVMR_Output_GetDeviceNumber:r.func("long __stdcall VBVMR_Output_GetDeviceNumber(void)"),VBVMR_Output_GetDeviceDescA:r.func("long __stdcall VBVMR_Output_GetDeviceDescA(long index, _Out_ long* type, _Out_ char* name, _Out_ char* hardwareId)"),VBVMR_Input_GetDeviceNumber:r.func("long __stdcall VBVMR_Input_GetDeviceNumber(void)"),VBVMR_Input_GetDeviceDescA:r.func("long __stdcall VBVMR_Input_GetDeviceDescA(long index, long* type, char* name, char* hardwareId)"),VBVMR_GetVoicemeeterType:r.func("long __stdcall VBVMR_GetVoicemeeterType(_Out_ long* type)"),VBVMR_GetVoicemeeterVersion:r.func("long __stdcall VBVMR_GetVoicemeeterVersion(_Out_ long* version)"),VBVMR_MacroButton_IsDirty:r.func("long __stdcall VBVMR_MacroButton_IsDirty(void)"),VBVMR_MacroButton_GetStatus:r.func("long __stdcall VBVMR_MacroButton_GetStatus(long nuLogicalButton, _Out_ float* pValue, long bitmode)"),VBVMR_MacroButton_SetStatus:r.func("long __stdcall VBVMR_MacroButton_SetStatus(long nuLogicalButton, float fValue, long bitmode)"),VBVMR_AudioCallbackRegister:r.func("long __stdcall VBVMR_AudioCallbackRegister(long mode, void* audioCallback, void* lpUser, char* szClientName)"),VBVMR_AudioCallbackStart:r.func("long __stdcall VBVMR_AudioCallbackStart(void)"),VBVMR_AudioCallbackStop:r.func("long __stdcall VBVMR_AudioCallbackStop(void)"),VBVMR_AudioCallbackUnregister:r.func("long __stdcall VBVMR_AudioCallbackUnregister(void* audioCallback)")},V=e.pointer(e.proto("long __stdcall AudioCallback(void* lpUser, long nCommand, void* lpData, long nnn)")),g.isInitialised=!0,t(g)})},b.inputChannelCountMap={voicemeeter:12,voicemeeterBanana:22,voicemeeterPotato:34},b.outputChannelCountMap={voicemeeter:16,voicemeeterBanana:40,voicemeeterPotato:64};var m={__proto__:null};const{BusProperties:B,InterfaceTypes:v,StripProperties:M,MacroButtonModes:C,AudioCallbackModes:A,AudioCallbackCommands:R}=u;export{R as AudioCallbackCommands,A as AudioCallbackModes,B as BusProperties,v as InterfaceTypes,C as MacroButtonModes,M as StripProperties,b as Voicemeeter,m as types};
//# sourceMappingURL=index.modern.mjs.map