1- copyright = [[
1+ copyleft = [[
22obs-libre-macros - scripting and macros hotkeys in OBS Studio for Humans
33Contact/URL https://www.github.com/upgradeQ/obs-libre-macros
44Copyright (C) 2021 upgradeQ
@@ -16,18 +16,19 @@ GNU Affero General Public License for more details.
1616You should have received a copy of the GNU Affero General Public License
1717along 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"
2121obs = obslua -- needs to be global for use in repl
2222ffi = require " ffi"
23+ jit = require " jit"
24+ bit = require " bit"
2325
2426if ffi .os == " OSX" then
2527 obsffi = ffi .load (" obs.0.dylib" )
2628else
2729 obsffi = ffi .load (" obs" )
2830end
2931
30-
3132run = coroutine.create
3233gn = {}
3334
@@ -40,15 +41,15 @@ function Timer:init(o)
4041end
4142
4243function 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
4748end
4849
4950function Timer :enter ()
5051 self .finished = false
51- self .current_time = 0
52+ self .current_accumulated_time = 0
5253end
5354
5455function Timer :launch ()
@@ -60,7 +61,7 @@ function Timer:launch()
6061end
6162
6263function sleep (s )
63- local action = Timer :init {delay = s }
64+ local action = Timer :init {duration = s }
6465 action :launch ()
6566end
6667
@@ -88,10 +89,172 @@ function viewer()
8889 error (" >Script Log" )
8990end
9091
92+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
93+
9194function print_source_name (source )
9295 print (obs .obs_source_get_name (source ))
9396end
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
97260local SourceDef = {}
0 commit comments