--- Auto Audio Source Mute
--
-- Mutes selected audio source (if unmuted)
obs = obslua
bit = require("bit")
source_def = {}
source_def.id = "Auto_Mute_Source"
source_def.type = OBS_SOURCE_TYPE_INPUT
source_def.output_flags = bit.bor(obs.OBS_SOURCE_CUSTOM_DRAW)
muted = false
changed = true
volume = 0
source_ptr = nil
incallback = false
duck = false
muteActive = 0
duckVolume = 0
audio_source_name = ""
fade_direction = true
fade2Volume = 0
fade_speed = 1
source_def.get_name = function()
return "Auto Mute/Duck Audio"
end
source_def.create = function(settings, source)
data = {}
sh = obs.obs_source_get_signal_handler(source)
obs.signal_handler_connect(sh,"activate",active) --Set Active Callback
obs.signal_handler_connect(sh,"deactivate",deactive) --Set Preview Callback
source_ptr = source
return data
end
function rename_callback()
obs.timer_remove(rename_callback)
local sources = obs.obs_enum_sources()
if (sources ~= nil) then
local t = 0
for _, source in ipairs(sources) do
local source_id = obs.obs_source_get_id(source)
if source_id == "Auto_Mute_Source" then
t = t + 1
end
end
if t>0 then
for _, source in ipairs(sources) do
local source_id = obs.obs_source_get_id(source)
if source_id == "Auto_Mute_Source" then
local settings = obs.obs_source_get_settings(source)
local audio_source_name = obs.obs_data_get_string(settings, "audio_prop")
local direction = obs.obs_data_get_bool(settings,"dir")
local duck = obs.obs_data_get_bool(settings,"duck")
local duckVolume = 60+obs.obs_data_get_int(settings,"duckVolume")
local value = duckVolume
if (direction) then
value = volume
end
local color = "50FF00"
if (value > 40) then color = "FADB2C" end
if (value > 51) then color = "FF4319" end
local newname = ""
if direction then
if duck then
newname = "(" .. t .. ") " .. audio_source_name .. " Vol set to " .. 60-duckVolume .. string.format(" (%.1f db)",color,per_to_db(duckVolume))
else
newname = "(" .. t .. ") UnMute: " .. audio_source_name .. ""
end
else
if duck then
newname = "(" .. t .. ") " .. audio_source_name .. " Vol set to " .. 60-duckVolume .. string.format(" (%.1f db)",color,per_to_db(duckVolume))
else
newname = "(" .. t .. ") Mute: " .. audio_source_name .. ""
end
end
t = t - 1
obs.obs_source_set_name(source, newname)
obs.obs_data_release(settings) -- release memory
end
end
end
end
obs.source_list_release(sources)
end
function start_fade_timer()
obs.timer_add(fade_callback, 50)
end
function fade_callback()
local audio_source = obs.obs_get_source_by_name(audio_source_name)
if audio_source ~= nil then
local volume = mul_to_db(obs.obs_source_get_volume(audio_source))
local nextVol = volume
if volume ~= fade2Volume then
if (fade2Volume > volume) then
nextVol = volume+fade_speed
if (nextVol > fade2Volume) then
nextVol = fade2Volume
obs.remove_current_callback()
end
else
nextVol = volume-fade_speed
if (nextVol < fade2Volume) then
nextVol = fade2Volume
obs.remove_current_callback()
end
end
obs.obs_source_set_volume(audio_source,db_to_mul(nextVol))
end
obs.obs_source_release(audio_source)
end
end
source_def.save = function (data, settings)
if changed then
obs.timer_add(rename_callback, 3000) -- wait long enough for save to complete so callback is only once
end
changed = false
end
function change_duck_property(props, prop, settings)
obs.obs_property_set_visible(obs.obs_properties_get(props, "duckVolume"), obs.obs_data_get_bool(settings, "duck"))
obs.obs_property_set_visible(obs.obs_properties_get(props, "fadeOutSpeed"), obs.obs_data_get_bool(settings, "duck"))
obs.obs_property_set_visible(obs.obs_properties_get(props, "fadeInSpeed"), obs.obs_data_get_bool(settings, "duck"))
return true
end
source_def.get_properties = function (data)
changed = true
props = obs.obs_properties_create()
local source_prop = obs.obs_properties_add_list(props, "audio_prop", "Set Audio Source", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
local sources = obs.obs_enum_sources()
if sources ~= nil then
local n = {}
local source_id = nil
for _, source in ipairs(sources) do
if bit.band(obs.obs_source_get_output_flags(source),obs.OBS_SOURCE_AUDIO) > 0 then
n[#n+1] = obs.obs_source_get_name(source)
end
end
table.sort(n)
for _, name in ipairs(n) do
obs.obs_property_list_add_string(source_prop, name, name)
end
end
obs.source_list_release(sources)
obs.obs_properties_add_button(props, "show_help_button", "SHOW HELP", show_help_button)
obs.obs_properties_add_bool(props,"dir","Unmute if Muted (Default is Mute if Unmuted): ")
obs.obs_properties_add_bool(props,"restore","Restore Mute State/Volume Level on Exit: ")
local duck_prop = obs.obs_properties_add_bool(props,"duck","Duck Volume instead of Mute: ")
obs.obs_property_set_modified_callback(duck_prop, change_duck_property)
local dv = obs.obs_properties_add_int_slider(props,"duckVolume","Ducking Volume:",-60,0,1)
local dv = obs.obs_properties_add_int_slider(props,"fadeOutSpeed","Fade Speed Activating Source (1-10):",1,10,1)
local dv = obs.obs_properties_add_int_slider(props,"fadeInSpeed", "Fade Speed Deactivating Source (1-10):",1,10,1)
return props
end
help =
"▪▪▪▪▪ USAGE HELP ▪▪▪▪▪▲- CLICK TO CLOSE -▲▪▪▪▪▪\n\n" ..
"Settings for Auto Mute/Duck Source \n" ..
"==============================\n" ..
"Normal operation is to mute selected source when then scene loads\n" ..
"Check 'Unmute if Muted:' to unmute a selected source when the scene loads\n" ..
"Check 'Restore Mute State/Volume level on Exit:' to restore original volume setting on scene close\n" ..
"Check 'Duck Volume instead of Mute:' to set volume level for the selected source for this scene\n" ..
"Ducking sets source volume to the selected Ducking Volume\n\n" ..
"Note: OBS opens the next scene BEFORE it closes the prior scene!\n" ..
" For this reason, Restore option is ignored if next scene sets the same source.\n"
-----------------------------------------------------------------------------------------------------------------------
-- Show/Hide the Help Button Text
-----------------------------------------------------------------------------------------------------------------------
function show_help_button(props, prop, settings)
local hb = obs.obs_properties_get(props, "show_help_button")
showhelp = not showhelp
if showhelp then
obs.obs_property_set_description(hb, help)
else
obs.obs_property_set_description(hb, "SHOW HELP")
end
return true
end
function script_description()
return [[AUTO MUTE-DUCK AUDIO SOURCE
Ver 1.3 by DCStrato
Mutes/Unmutes or sets Audio level for a Selected Audio
Source during the Current Scene with optional Restore.
Property options are in the Source when added to a Scene]]
end
function per_to_db(level)
local def = level / 60.0
local db = 0
if (def >= 1.0) then
db = 0.0
elseif (def <= 0.0) then
db = -100;
else
db = 6 - (102 * (1/(17 ^ def)))
end
return db
end
function db_to_mul(db)
if ( db == 0) then
return 0
else
return 10 ^ (db / 20.0)
end
end
function mul_to_db(mul)
if (mul == 0) then
return 1;
else
return 20 * math.log10(mul)
end
end
function update(cd)
changed = true
end
function active(cd)
muteActive = muteActive + 1
local source = obs.calldata_source(cd,"source")
local settings = obs.obs_source_get_settings(source)
audio_source_name = obs.obs_data_get_string(settings, "audio_prop")
fade_direction = obs.obs_data_get_bool(settings,"dir")
duck = obs.obs_data_get_bool(settings,"duck")
duckVolume = per_to_db(60+obs.obs_data_get_int(settings,"duckVolume"))
fade_speed = obs.obs_data_get_int(settings,"fadeInSpeed")
obs.obs_data_release(settings)
local audio_source = obs.obs_get_source_by_name(audio_source_name)
if audio_source ~= nil then
muted = obs.obs_source_muted(audio_source)
volume = mul_to_db(obs.obs_source_get_volume(audio_source))
if duck then
if volume ~= duckVolume then
fade2Volume = duckVolume
start_fade_timer()
end
else
if not fade_direction then
if not muted then
obs.obs_source_set_muted(audio_source,true) -- mute if unmuted
end
else
if muted then
obs.obs_source_set_muted(audio_source,false) -- unmute if muted
end
end
end
obs.obs_source_release(audio_source)
end
end
function deactive(cd)
local source = obs.calldata_source(cd,"source")
local settings = obs.obs_source_get_settings(source)
local audio_source_name = obs.obs_data_get_string(settings, "audio_prop")
local direction = obs.obs_data_get_bool(settings,"dir")
local force = obs.obs_data_get_bool(settings,"force")
local restore = obs.obs_data_get_bool(settings,"restore")
local duck = obs.obs_data_get_bool(settings,"duck")
local duckVolume = per_to_db(60+obs.obs_data_get_int(settings,"duckVolume"))
fade_speed = obs.obs_data_get_int(settings,"fadeOutSpeed")
obs.obs_data_release(settings)
local audio_source = obs.obs_get_source_by_name(audio_source_name)
if audio_source ~= nil and restore and (muteActive == 1 or (audio_source_name ~= loaded_source_name)) then
if duck then
fade2Volume = volume -- restore prior volume
start_fade_timer()
else
obs.obs_source_set_muted(audio_source,muted) -- restore prior mute state
end
obs.obs_source_release(audio_source)
end
muteActive = muteActive - 1
end
obs.obs_register_source(source_def)