Skip to content

Commit b7c1089

Browse files
committed
📦 Release 0.2.0 version
1 parent 3691496 commit b7c1089

File tree

2 files changed

+226
-9
lines changed

2 files changed

+226
-9
lines changed

README.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Description
22
**obs-libre-macros** is an Extension for OBS Studio built on top of its scripting facilities,
33
utilising built-in embedded LuaJIT interpreter, filter UI and function environment from Lua 5.2
4+
# Screenshot
5+
6+
![img](https://i.imgur.com/10IrnOu.png)
47

58
# Features
69
- Attach `Console` to **any** source in real-time.
@@ -183,10 +186,61 @@ print(t.mv2)
183186
until false
184187
```
185188

189+
Attach volmeter to source with sound(same as above, but without plugin):
190+
191+
```lua
192+
volume_level(return_source_name(t.source))
193+
repeat
194+
sleep(1)
195+
print(LVL)
196+
print(NOISE)
197+
until false
198+
```
199+
200+
Start virtual camera as a triggered named callback:
201+
202+
```lua
203+
local description = 'OBSBasic.StartVirtualCam'
204+
trigger_from_hotkey_callback(description)
205+
```
206+
207+
Send hotkey combination to OBS:
208+
```lua
209+
send_hotkey('OBS_KEY_2',{shift=true})
210+
```
211+
212+
Hook state of right and left mouse buttons:
213+
```lua
214+
hook_mouse_buttons()
215+
repeat
216+
sleep(0.1)
217+
print(tostring(LMB))
218+
print(tostring(RMB))
219+
until false
220+
```
221+
222+
Access sceneitem from scene:
223+
```lua
224+
local sceneitem = get_scene_sceneitem("Scene 2",sname(t.source))
225+
repeat
226+
sleep(0.01)
227+
if sceneitem then
228+
obs.obs_sceneitem_set_rot(sceneitem, math.sin(math.random() * 100))
229+
end
230+
until false
231+
```
232+
233+
Send keyboard key to browser :
234+
```lua
235+
send_hotkey_to_browser_source(t.source,"OBS_KEY_Q")
236+
```
237+
238+
# Contribute
239+
Contributions are welcome!
186240

187241
# License
188242
<a href="https://www.gnu.org/licenses/agpl-3.0.en.html">
189243
<img src="https://www.gnu.org/graphics/agplv3-with-text-162x68.png" align="right" />
190244
</a>
191245

192-
The **obs-libre-macros** is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. That means that if users interacting with it remotely through a network: If you **not** modified, then you can direct them [here](https://github.com/upgradeQ/obs-libre-macros), if you **modified** it, you simply have to publish your modifications. The easiest way to do this is to have a public Github repository of your fork or create a PR upstream. Otherwise, you will be in violation of the license. The relevant part of the license is under section 13 of the AGPLv3.
246+
The **obs-libre-macros** is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. That means that if users interacting with it remotely through a network then: If you **not** modified it, then you can direct them [here](https://github.com/upgradeQ/obs-libre-macros), if you **modified** it, you simply have to publish your modifications. The easiest way to do this is to have a public Github repository of your fork or create a PR upstream. Otherwise, you will be in violation of the license. The relevant part of the license is under section 13 of the AGPLv3.

console.lua

Lines changed: 171 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
copyright = [[
1+
copyleft = [[
22
obs-libre-macros - scripting and macros hotkeys in OBS Studio for Humans
33
Contact/URL https://www.github.com/upgradeQ/obs-libre-macros
44
Copyright (C) 2021 upgradeQ
@@ -16,18 +16,19 @@ GNU Affero General Public License for more details.
1616
You should have received a copy of the GNU Affero General Public License
1717
along with this program. If not, see <https://www.gnu.org/licenses/>.
1818
]]
19-
print(copyright)
20-
obs_libre_macros_version = "0.1.0"
19+
print(copyleft)
20+
obs_libre_macros_version = "0.2.0"
2121
obs = obslua -- needs to be global for use in repl
2222
ffi = require "ffi"
23+
jit = require "jit"
24+
bit = require "bit"
2325

2426
if ffi.os == "OSX" then
2527
obsffi = ffi.load("obs.0.dylib")
2628
else
2729
obsffi = ffi.load("obs")
2830
end
2931

30-
3132
run = coroutine.create
3233
gn = {}
3334

@@ -40,15 +41,15 @@ function Timer:init(o)
4041
end
4142

4243
function Timer:update(dt)
43-
self.current_time = self.current_time + dt
44-
if self.current_time >= self.delay then
44+
self.current_accumulated_time = self.current_accumulated_time + dt
45+
if self.current_accumulated_time >= self.duration then
4546
self.finished = true
4647
end
4748
end
4849

4950
function Timer:enter()
5051
self.finished = false
51-
self.current_time = 0
52+
self.current_accumulated_time = 0
5253
end
5354

5455
function Timer:launch()
@@ -60,7 +61,7 @@ function Timer:launch()
6061
end
6162

6263
function sleep(s)
63-
local action = Timer:init{delay=s}
64+
local action = Timer:init{duration=s}
6465
action:launch()
6566
end
6667

@@ -88,10 +89,172 @@ function viewer()
8889
error(">Script Log")
8990
end
9091

92+
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
93+
9194
function print_source_name(source)
9295
print(obs.obs_source_get_name(source))
9396
end
9497

98+
function sname(source)
99+
return obs.obs_source_get_name(source)
100+
end
101+
102+
function get_scene_sceneitem(scene_name,scene_item_name)
103+
local sceneitem;
104+
local scenes = obs.obs_frontend_get_scenes()
105+
for _,scene in pairs(scenes) do
106+
if sname(scene) == scene_name then
107+
scene = obs.obs_scene_from_source(scene)
108+
sceneitem = obs.obs_scene_find_source_recursive(scene,scene_item_name)
109+
end
110+
end
111+
obs.source_list_release(scenes)
112+
return sceneitem
113+
end
114+
115+
LMB,RMB,MOUSE_HOOKED = false,false,false
116+
function htk_1_cb(pressed) LMB = pressed end
117+
function htk_2_cb(pressed) RMB = pressed end
118+
function hook_mouse_buttons()
119+
if MOUSE_HOOKED then return error('already hooked mouse') end
120+
local key_1 = '{"htk_1_mouse": [ { "key": "OBS_KEY_MOUSE1" } ],'
121+
local key_2 = '"htk_2_mouse": [ { "key": "OBS_KEY_MOUSE2" } ]}'
122+
local json_s = key_1 .. key_2
123+
local default_hotkeys = {
124+
{id='htk_1_mouse',des='LMB state',callback=htk_1_cb},
125+
{id='htk_2_mouse',des='RMB state',callback=htk_2_cb},
126+
}
127+
local s = obs.obs_data_create_from_json(json_s)
128+
for _,v in pairs(default_hotkeys) do
129+
local a = obs.obs_data_get_array(s,v.id)
130+
h = obs.obs_hotkey_register_frontend(v.id,v.des,v.callback)
131+
obs.obs_hotkey_load(h,a)
132+
obs.obs_data_array_release(a)
133+
end
134+
obs.obs_data_release(s)
135+
MOUSE_HOOKED = true
136+
end
137+
138+
function send_hotkey(hotkey_id_name,key_modifiers)
139+
local key_modifiers = key_modifiers or {}
140+
local shift = key_modifiers.shift or false
141+
local control = key_modifiers.control or false
142+
local alt = key_modifiers.alt or false
143+
local command = key_modifiers.command or false
144+
local modifiers = 0
145+
146+
if shift then modifiers = bit.bor(modifiers,obs.INTERACT_SHIFT_KEY ) end
147+
if control then modifiers = bit.bor(modifiers,obs.INTERACT_CONTROL_KEY ) end
148+
if alt then modifiers = bit.bor(modifiers,obs.INTERACT_ALT_KEY ) end
149+
if command then modifiers = bit.bor(modifiers,obs.INTERACT_COMMAND_KEY ) end
150+
151+
local combo = obs.obs_key_combination()
152+
combo.modifiers = modifiers
153+
combo.key = obs.obs_key_from_name(hotkey_id_name)
154+
155+
if not modifiers and -- there is should be OBS_KEY_NONE, but it is missing in obslua
156+
(combo.key == 0 or combo.key >= obs.OBS_KEY_LAST_VALUE) then
157+
return error('invalid key-modifier combination')
158+
end
159+
160+
obs.obs_hotkey_inject_event(combo,false)
161+
obs.obs_hotkey_inject_event(combo,true)
162+
obs.obs_hotkey_inject_event(combo,false)
163+
end
164+
165+
function send_hotkey_to_browser_source(source,hotkey_id_name)
166+
local key = obs.obs_key_from_name(hotkey_id_name)
167+
local vk = obs.obs_key_to_virtual_key(key)
168+
local event = obs.obs_key_event()
169+
event.native_vkey = vk
170+
event.native_modifiers = 0
171+
event.native_scancode = 0
172+
event.modifiers = 0
173+
event.text = ""
174+
obs.obs_source_send_key_click(source,event,false)
175+
obs.obs_source_send_key_click(source,event,true)
176+
end
177+
178+
ffi.cdef[[
179+
typedef struct obs_hotkey obs_hotkey_t;
180+
typedef size_t obs_hotkey_id;
181+
182+
const char *obs_hotkey_get_name(const obs_hotkey_t *key);
183+
typedef bool (*obs_hotkey_enum_func)(void *data, obs_hotkey_id id, obs_hotkey_t *key);
184+
void obs_enum_hotkeys(obs_hotkey_enum_func func, void *data);
185+
]]
186+
187+
function trigger_from_hotkey_callback(description)
188+
local htk_id;
189+
function callback_htk(data,id,key)
190+
local name = obsffi.obs_hotkey_get_name(key)
191+
if ffi.string(name) == description then
192+
htk_id = tonumber(id)
193+
return false
194+
else
195+
return true
196+
end
197+
end
198+
local cb = ffi.cast("obs_hotkey_enum_func",callback_htk)
199+
obsffi.obs_enum_hotkeys(cb,nil)
200+
if htk_id then
201+
obs.obs_hotkey_trigger_routed_callback(htk_id,false)
202+
obs.obs_hotkey_trigger_routed_callback(htk_id,true)
203+
obs.obs_hotkey_trigger_routed_callback(htk_id,false)
204+
end
205+
end
206+
207+
ffi.cdef[[
208+
typedef struct obs_source obs_source_t;
209+
obs_source_t *obs_get_source_by_name(const char *name);
210+
void obs_source_release(obs_source_t *source);
211+
212+
enum obs_fader_type {
213+
OBS_FADER_CUBIC,
214+
OBS_FADER_IEC,
215+
OBS_FADER_LOG
216+
};
217+
218+
typedef struct obs_volmeter obs_volmeter_t;
219+
220+
bool obs_volmeter_attach_source(obs_volmeter_t *volmeter,
221+
obs_source_t *source);
222+
223+
int MAX_AUDIO_CHANNELS;
224+
225+
obs_volmeter_t *obs_volmeter_create(enum obs_fader_type type);
226+
227+
typedef void (*obs_volmeter_updated_t)(
228+
void *param, const float magnitude[MAX_AUDIO_CHANNELS],
229+
const float peak[MAX_AUDIO_CHANNELS],
230+
const float input_peak[MAX_AUDIO_CHANNELS]);
231+
232+
void obs_volmeter_add_callback(obs_volmeter_t *volmeter,
233+
obs_volmeter_updated_t callback,
234+
void *param);
235+
]]
236+
237+
LVL,NOISE,LOCK = "?",0,false
238+
function callback_meter(data,mag,peak,input)
239+
LVL = 'Volume lvl is :' .. tostring(tonumber(peak[0]))
240+
NOISE = tonumber(peak[0])
241+
end
242+
243+
jit.off(callback_meter)
244+
245+
function volume_level(source_name)
246+
if LOCK then return error("cannot attach to more than 1 source") end
247+
local source = obsffi.obs_get_source_by_name(source_name)
248+
local volmeter = obsffi.obs_volmeter_create(obsffi.OBS_FADER_LOG)
249+
-- https://github.com/WarmUpTill/SceneSwitcher/blob/214821b69f5ade803a4919dc9386f6351583faca/src/switch-audio.cpp#L194-L207
250+
local cb = ffi.cast("obs_volmeter_updated_t",callback_meter)
251+
obsffi.obs_volmeter_add_callback(volmeter,cb,nil)
252+
obsffi.obs_volmeter_attach_source(volmeter,source)
253+
obsffi.obs_source_release(source)
254+
LOCK = true
255+
end
256+
257+
95258
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
96259

97260
local SourceDef = {}

0 commit comments

Comments
 (0)