Skip to content

Instantly share code, notes, and snippets.

@to
Last active April 2, 2026 00:51
Show Gist options
  • Select an option

  • Save to/a35f45e3fc2548c985435b72b35015e3 to your computer and use it in GitHub Desktop.

Select an option

Save to/a35f45e3fc2548c985435b72b35015e3 to your computer and use it in GitHub Desktop.
OBS: シーンが切り替わるタイミングでメディアをフェードアウト/フェードインする
local obs = obslua
local duration = 1200
local interval = 50
local steps = duration / interval
local current_scene_name
local debug = false
local fade_table = {}
local is_running = false
function on_source_show(calldata)
local source = obs.calldata_source(calldata, "source")
if source == nil then return end
local source_id = obs.obs_source_get_id(source)
if source_id ~= "scene" then return end
-- 初回の実行か?
local next_scene_name = obs.obs_source_get_name(source)
if current_scene_name == nil then
current_scene_name = next_scene_name
return
end
log("SCENE_SHOW:" .. next_scene_name);
-- 古いシーンのメディアを繰り返す
local source = obs.obs_get_source_by_name(current_scene_name)
for_each_scene_items(source, function(source, source_name)
log("FADE_OUT: " .. source_name)
-- フェード方向をフェードアウトにする
fade_table[source_name].direction = -1
end)
obs.obs_source_release(source)
-- 新しいシーンのメディアを繰り返す
local source = obs.obs_get_source_by_name(next_scene_name)
for_each_scene_items(source, function(source, source_name)
log("FADE_IN: " .. source_name)
-- フェードアウトの途中でなかったか?
-- (前後のシーンで同一のメディアがあった場合、フェードがスキップされる)
if fade_table[source_name].direction == nil then
-- 音量をゼロにする
obs.obs_source_set_volume(source, 0)
end
-- フェード方向をフェードインにする
fade_table[source_name].direction = 1
end)
obs.obs_source_release(source)
start_timer()
current_scene_name = next_scene_name
end
function for_each_scene_items(source, func)
local scene = obs.obs_scene_from_source(source)
local items = obs.obs_scene_enum_items(scene)
for _, item in ipairs(items) do
-- メディアソースか?
local source = obs.obs_sceneitem_get_source(item)
local source_id = obs.obs_source_get_id(source)
if source_id == "vlc_source" or source_id == "ffmpeg_source" then
local source_name = obs.obs_source_get_name(source)
local volume = obs.obs_source_get_volume(source)
if not obs.obs_source_muted(source) then
if fade_table[source_name] == nil then
fade_table[source_name] = {volume = volume}
end
func(source, source_name)
end
end
end
obs.sceneitem_list_release(items)
end
function start_timer()
if table.empty(fade_table) or is_running then return end
obs.timer_add(function()
for source_name, info in pairs(fade_table) do
-- フェードインか?
local source = obs.obs_get_source_by_name(source_name)
local volume = obs.obs_source_get_volume(source)
if info.direction > 0 then
volume = math.min(volume + (info.volume / steps), info.volume)
-- 最大音量に達しているか?
if volume == info.volume then
fade_table[source_name] = nil
end
else
volume = math.max(volume - (info.volume / steps), 0)
-- メディアの再生が終了しているか?
if not obs.obs_source_active(source) then
-- 音量を元に戻す
volume = info.volume
fade_table[source_name] = nil
end
end
obs.obs_source_set_volume(source, volume)
obs.obs_source_release(source)
end
-- 全てのフェードが終了したか?
if table.empty(fade_table) then
log("TIMER_END:")
obs.remove_current_callback()
is_running = false
end
end, interval)
log("TIMER_START:")
is_running = true
end
function log(msg)
if not debug then return end
print(msg)
end
function script_description()
return "auto fade in/out audios"
end
function script_load(settings)
log("LOAD:");
obs.signal_handler_connect(
obs.obs_get_signal_handler(), "source_show", on_source_show)
end
function table.empty(tbl)
if tbl == nil then return true end
return not next(tbl)
end
@GasOjisan
Copy link
Copy Markdown

便利なスクリプトで実装不可避なのですが問題が発生しております。

フェードアウト後音声設定が-inf dBになって固定される

具体的に記述すると、例えば

  1. ABのシーンがありそれぞれ音声ソースがあるとすると
  2. AからBにシーン転換
  3. Aの音声シーンの音声がフェードアウト後-inf dBになってBに切り替わる
  4. Bの音声はフェードインしている
  5. BからAにシーン転換
  6. Bの音声シーンの音声がフェードアウト後-inf dBになってAに切り替わる
  7. Aの音声ソースの音量が-inf dBのままになっている。
  8. Bの音声ソースの音量は問題なく元通りになっている。

この問題は致命的で、シーンを切り替えると音声が出力されなくなってしまい放送に支障出てしまいます。
修正できないでしょうか?

@to
Copy link
Copy Markdown
Author

to commented May 7, 2024

4年前のことで 私も 現在 利用していないので まったく わからなくなっちゃってます><

@GasOjisan
Copy link
Copy Markdown

どうにか修正できないかとChatGPTといろいろやりましたが、結果は芳しく無く……
このスクリプトは非常に便利でグレートなものなので、どうにか!どうにか!していただけないでしょうか!
ちなみにChatGPTとの知識皆無な私が行った恥ずかしいやり取りはこちらです(/////)
https://chat.openai.com/share/47f64417-5e7b-41a3-85b5-8ccb46f3e04b

@ray34g
Copy link
Copy Markdown

ray34g commented Aug 21, 2024

私のほうでOBS Studio 30.2.3でフェードアウト中にすぐにシーンを戻すと再現しました。
ログを差し込んでデバッグをしたところ再現時にsource_showのsignalイベントが発火していないように見受けられました。
コード的に、スタジオモードでの切替時も動作しなさそうです。

OBS自体初心者なのですが、意外に、プラグインなども含めて音声をうまくクロスフェードする手段って提供されていないのですかね?
「高機能シーンスイッチャー」のマクロだと設定しにくかったので、
もう少し探して見当たらなければ私のほうで本スクリプトを参考に書きなおそうかと思います。

@ray34g
Copy link
Copy Markdown

ray34g commented Aug 23, 2024

ざっと書き直しました。もう少し自分で使ってみてバグが取れたところで、近日中に共有したいと思います。

@ray34g
Copy link
Copy Markdown

ray34g commented Aug 27, 2024

デフォルトの機能でトランジションのフェード設定さえしていれば音声もフェードイン・フェードアウトしていることに気が付きました。
音声をモニターしているだけではわからないのですが、配信や録画ではフェードが効いているようですね。

一通り書き直していろいろテストしている間に気がつきました・・・!

せっかく作ったスクリプトですが無用ですね。。どこかで供養はしますが。

@GasOjisan
Copy link
Copy Markdown

つまり最新のOBSのトランジションのフェード設定さえしておけば、
今までバツンと音声が切り替わっていたのが、音もフェードして滑らかに切り替わってくれるようになったということですか?
……だとしたらOBS神アプデ!?
それにしてもray34g様スクリプトの見直しと現状の確認作業本当に助かりました。ありがとうございます。神と崇めます。

@NagaoSouma
Copy link
Copy Markdown

NagaoSouma commented Nov 1, 2024

https://github.com/NagaoSouma/OBS-fade-audio-when-transitioning

1000001901.mp4

OBSを最新にしているものの音声ごとフェードしていることが確認できなかったため、一応トランジション毎(フェード、カット、スティンガーなど)にフェード時間を設定できるスクリプトを公開しました。
スタジオモードでも使えます(スタジオモードの方がいいまである)

@tthonda
Copy link
Copy Markdown

tthonda commented Apr 2, 2026

OBS 32.1.0でauto_fade_audio.luaを利用したときに、なぜかシーンが完全に切り替わった後に音量が0になってしまっていたので、Geminiに聞いて修正案をこちらに記載しておきます。NagaoSoumaさんのスクリプトの方が良いかもしれませんがご参考まで。

local obs = obslua

-- 設定値
local duration = 1200 -- フェード時間(ms)
local interval = 50   -- タイマー間隔(ms)
local steps = duration / interval
local debug = true

local fade_table = {}
local is_running = false

-- ログ出力用
function log(msg)
    if not debug then return end
    print("[AutoFade] " .. msg)
end

-- フェード処理のメインループ
function fade_timer_callback()
    if fade_table == nil then return end

    local current_scene_source = obs.obs_frontend_get_current_scene()
    if current_scene_source == nil then return end
    
    local current_scene = obs.obs_scene_from_source(current_scene_source)
    
    for name, _ in pairs(fade_table) do
        local source = obs.obs_get_source_by_name(name)
        if source ~= nil then
            -- このソースが「現在のアクティブシーン」に含まれているか確認
            local scene_item = obs.obs_scene_find_source(current_scene, name)
            local is_in_active_scene = (scene_item ~= nil)
            
            local volume = obs.obs_source_get_volume(source)
            
            if is_in_active_scene then
                -- フェードイン
                if volume < 1.0 then
                    local new_vol = math.min(1.0, volume + (1.0 / steps))
                    obs.obs_source_set_volume(source, new_vol)
                else
                    fade_table[name] = nil
                end
            else
                -- フェードアウト
                if volume > 0.0 then
                    local new_vol = math.max(0.0, volume - (1.0 / steps))
                    obs.obs_source_set_volume(source, new_vol)
                else
                    fade_table[name] = nil
                end
            end
            obs.obs_source_release(source)
        else
            fade_table[name] = nil
        end
    end

    obs.obs_source_release(current_scene_source)

    -- 全てのフェードが完了したらタイマー停止
    if next(fade_table) == nil then
        obs.timer_remove(fade_timer_callback) -- 修正箇所
        is_running = false
        log("All fades complete. Timer stopped.")
    end
end

-- シーンが切り替わった時のイベント
function on_source_show(calldata)
    local source = obs.calldata_source(calldata, "source")
    if source == nil then return end
    
    local source_id = obs.obs_source_get_id(source)
    if source_id ~= "scene" then return end

    log("Scene switch detected: " .. obs.obs_source_get_name(source))

    local sources = obs.obs_enum_sources()
    if sources ~= nil then
        for _, s in ipairs(sources) do
            local flags = obs.obs_source_get_output_flags(s)
            if bit.band(flags, obs.OBS_SOURCE_AUDIO) ~= 0 then
                local s_name = obs.obs_source_get_name(s)
                fade_table[s_name] = true
            end
        end
        obs.source_list_release(sources)
    end

    if not is_running then
        obs.timer_add(fade_timer_callback, interval) -- 修正箇所
        is_running = true
        log("Fade timer started.")
    end
end

function script_description()
    return "シーン切り替え時に音声を自動フェードイン/アウトします (修正版v2)"
end

function script_load(settings)
    local sh = obs.obs_get_signal_handler()
    obs.signal_handler_connect(sh, "source_show", on_source_show)
    log("Script loaded and signal connected.")
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment