diff --git a/clip-notify.lua b/clip-notify.lua deleted file mode 100644 index 5fe1662..0000000 --- a/clip-notify.lua +++ /dev/null @@ -1,189 +0,0 @@ ---[[ - clip-notify.lua v3 - ─────────────────────────────────────────────────────── - "Clip Saved" chime for OBS Studio. - Plays a sound + logs to OBS when the replay buffer saves. - - Install: - 1. Place this file + your .wav in the same folder. - 2. OBS → Tools → Scripts → "+" → select clip-notify.lua - 3. Set your chime file & volume, hit Test. - ─────────────────────────────────────────────────────── ---]] - -obs = obslua - -local cfg = { - play_sound = true, - sound_path = "", - chime_volume = 80, -- 0–100 - notify_on_record = false, -} - --- ── Platform ────────────────────────────────────────── -local is_windows = package.config:sub(1,1) == "\\" -local is_mac, is_linux = false, false -if not is_windows then - local f = io.popen("uname -s 2>/dev/null") - if f then - local u = f:read("*l"); f:close() - is_mac = (u == "Darwin") - is_linux = not is_mac - end -end - --- ── FFI (Windows only) ──────────────────────────────── -local ffi, winmm -local ffi_ok = false - -if is_windows then - local ok; ok, ffi = pcall(require, "ffi") - if ok then - ffi.cdef[[ - /* winmm */ - int __stdcall PlaySoundA(const char* pszSound, void* hmod, unsigned long fdwSound); - unsigned long __stdcall waveOutSetVolume(void* hwo, unsigned long dwVolume); - unsigned long __stdcall waveOutGetVolume(void* hwo, unsigned long* pdwVolume); - ]] - local ok2; ok2, winmm = pcall(ffi.load, "winmm") - ffi_ok = ok2 - if ffi_ok then - obs.blog(obs.LOG_INFO, "[clip-notify] winmm FFI ready") - else - obs.blog(obs.LOG_WARNING, "[clip-notify] winmm failed to load — sound disabled") - end - end -end - --- ── Volume helpers ──────────────────────────────────── --- waveOutSetVolume: low word = left, high word = right (each 0x0000–0xFFFF) -local function pct_to_dword(pct) - local v = math.floor((math.max(0, math.min(100, pct)) / 100) * 0xFFFF) - return v + v * 0x10000 -end - --- ── Sound playback ──────────────────────────────────── -local SND_FILENAME = 0x00020000 -local SND_ASYNC = 0x00000001 -local SND_NODEFAULT = 0x00000002 - -local function play_chime(path) - if not cfg.play_sound or path == "" then return end - - if is_windows then - if not ffi_ok then return end - - -- Save current wave-out volume - local prev = ffi.new("unsigned long[1]", 0) - winmm.waveOutGetVolume(nil, prev) - local saved = prev[0] - - -- Apply our volume - winmm.waveOutSetVolume(nil, pct_to_dword(cfg.chime_volume)) - - -- Fire async — returns immediately - winmm.PlaySoundA(path, nil, SND_FILENAME + SND_ASYNC + SND_NODEFAULT) - - -- Restore original volume after the chime has finished (1.5s headroom) - obs.timer_add(function() - winmm.waveOutSetVolume(nil, saved) - obs.remove_current_callback() - end, 1500) - - elseif is_mac then - -- afplay -v accepts 0.0–1.0 - local vol = string.format("%.2f", cfg.chime_volume / 100) - os.execute(string.format('afplay -v %s "%s" &', vol, path)) - - elseif is_linux then - -- paplay --volume: 0–65536 (100% = 65536) - local vol = math.floor((cfg.chime_volume / 100) * 65536) - os.execute(string.format( - 'paplay --volume=%d "%s" 2>/dev/null || aplay "%s" 2>/dev/null &', - vol, path, path)) - end -end - --- ── Handlers ───────────────────────────────────────── -local function on_clip_saved() - play_chime(cfg.sound_path) - local filename = "" - if obs.obs_frontend_get_last_replay ~= nil then - local raw = obs.obs_frontend_get_last_replay() - if raw and raw ~= "" then - filename = raw:match("([^/\\]+)$") or raw - end - end - obs.blog(obs.LOG_INFO, "[clip-notify] Clip saved → " .. (filename ~= "" and filename or "done")) -end - -local function on_recording_saved() - if not cfg.notify_on_record then return end - play_chime(cfg.sound_path) - obs.blog(obs.LOG_INFO, "[clip-notify] Recording saved.") -end - -local function on_event(event) - if event == obs.OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED then on_clip_saved() - elseif event == obs.OBS_FRONTEND_EVENT_RECORDING_STOPPED then on_recording_saved() - end -end - --- ── Script UI ───────────────────────────────────────── -function script_properties() - local p = obs.obs_properties_create() - - obs.obs_properties_add_bool(p, "play_sound", "Enable chime sound") - - obs.obs_properties_add_path(p, "sound_path", - "Chime sound file (.wav)", - obs.OBS_PATH_FILE, - "WAV Files (*.wav);;All Files (*.*)", - script_path()) - - obs.obs_properties_add_int_slider(p, "chime_volume", "Volume", 0, 100, 1) - - obs.obs_properties_add_bool(p, "notify_on_record", - "Also chime when a recording is saved") - - obs.obs_properties_add_button(p, "test_btn", "▶ Test Chime Now", - function() on_clip_saved(); return true end) - - return p -end - -function script_defaults(s) - obs.obs_data_set_default_bool (s, "play_sound", true) - obs.obs_data_set_default_string(s, "sound_path", "") - obs.obs_data_set_default_int (s, "chime_volume", 80) - obs.obs_data_set_default_bool (s, "notify_on_record", false) -end - -function script_update(s) - cfg.play_sound = obs.obs_data_get_bool (s, "play_sound") - cfg.sound_path = obs.obs_data_get_string(s, "sound_path") - cfg.chime_volume = obs.obs_data_get_int (s, "chime_volume") - cfg.notify_on_record = obs.obs_data_get_bool (s, "notify_on_record") - if cfg.sound_path == "" then - cfg.sound_path = script_path() .. "clip-saved.wav" - end -end - -function script_load(s) - script_update(s) - obs.obs_frontend_add_event_callback(on_event) - obs.blog(obs.LOG_INFO, "[clip-notify] v3 loaded.") -end - -function script_unload() - obs.blog(obs.LOG_INFO, "[clip-notify] Unloaded.") -end - -function script_description() - return [[

🎬 Clip Notify  v3

-

Plays a chime the moment your replay buffer clip is saved.

-

Windows: native winmm — no subprocess, instant.
-macOS: afplay  |  Linux: paplay / aplay

-
-Setup: pick your .wav, set volume, hit Test Chime Now.]] -end