Files
I38/scripts/sound.py

114 lines
5.3 KiB
Python
Executable File

#!/usr/bin/env python3
# This file is part of I38.
# I38 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
# I38 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with I38. If not, see <https://www.gnu.org/licenses/>.
import i3ipc
from i3ipc import Event
import subprocess
import shlex
#This script allows for sounds in i3
i3 = i3ipc.Connection()
# Track the current mode so we know what we're exiting from
currentMode = 'default'
def play_sound_async(command):
"""Play a sound asynchronously without blocking i3's event loop"""
try:
subprocess.Popen(
command,
shell=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True
)
except Exception:
# Silently ignore sound playback errors to avoid blocking i3
pass
def on_new_window(self,i3):
try:
windowName = getattr(i3.container, 'name', None)
windowClass = getattr(i3.container, 'window_class', None)
# Special notification sound for notification daemon (it has its own sound)
if windowName == 'xfce4-notifyd' or windowClass == 'xfce4-notifyd':
play_sound_async('play -nqV0 synth .05 sq 1800 tri 2400 delay 0 .03 remix - repeat 2 echo .55 0.7 20 1 norm -12')
else:
play_sound_async('play -nqV0 synth .25 sin 440:880 sin 480:920 remix - norm -3 pitch -500')
except Exception:
# Silently ignore errors to prevent blocking i3
pass
def on_close_window(self,i3):
try:
windowName = getattr(i3.container, 'name', None)
windowClass = getattr(i3.container, 'window_class', None)
# Skip sound only for notification daemon (it has its own sound)
if windowName != 'xfce4-notifyd' and windowClass != 'xfce4-notifyd':
play_sound_async('play -nqV0 synth .25 sin 880:440 sin 920:480 remix - norm -3 pitch -500')
except Exception:
# Silently ignore errors to prevent blocking i3
pass
def on_mode(self,event):
global currentMode
mode = event.change
if mode == 'ratpoison':
play_sound_async('play -qV0 "|sox -np synth .07 sq 400" "|sox -np synth .5 sq 800" fade h 0 .5 .5 norm -20')
elif mode == 'bypass':
play_sound_async('play -nqV0 synth .1 saw 700 saw 1200 delay 0 .04 remix - norm -6')
elif mode == 'default':
# Play different sounds based on which mode we're exiting
if currentMode == 'ratpoison':
play_sound_async('play -qV0 "|sox -np synth .07 sq 400" "|sox -np synth .5 sq 800" fade h 0 .5 .5 norm -20 reverse')
elif currentMode == 'panel':
play_sound_async('play -nqV0 synth 0.05 pluck C5 norm -8 : synth 0.05 pluck F4 norm -8 : synth 0.05 pluck C4 norm -8 : synth 0.05 pluck F3 norm -8')
elif currentMode == 'bypass':
play_sound_async('play -nqV0 synth .1 saw 1200 saw 700 delay 0 .04 remix - norm -6')
else:
# Generic exit sound for any other mode
play_sound_async('play -qV0 "|sox -np synth .07 sq 400" "|sox -np synth .5 sq 800" fade h 0 .5 .5 norm -20 reverse')
else:
# Entering panel or any other mode
play_sound_async('play -nqV0 synth 0.05 pluck F3 norm -8 : synth 0.05 pluck C4 norm -8 : synth 0.05 pluck F4 norm -8 : synth 0.05 pluck C5 norm -8')
# Update current mode tracker
currentMode = mode
def on_workspace_focus(self,i3):
#system('play -qnV0 synth pi fade 0 .25 .15 pad 0 1 reverb overdrive riaa norm -8 speed 1 &')
pass
def on_workspace_move(self,i3):
play_sound_async('play -qnV0 synth pi fade 0 .25 .15 pad 0 1 reverb overdrive riaa norm -8 speed 1 reverse')
def on_restart(self,i3):
play_sound_async('play -qnV0 synth .25 saw 500:1200 fade .1 .25 .1 norm -8')
def on_exit(self,i3):
play_sound_async('play -qnV0 synth .3 sin 700:200 fade 0 .3 0')
def on_fullscreen(self,i3):
play_sound_async('play -qnV0 synth br flanger fade h .3 .3 0')
i3 = i3ipc.Connection()
i3.on('window::new', on_new_window)
i3.on('window::close', on_close_window)
i3.on(Event.MODE, on_mode)
i3.on('workspace::focus', on_workspace_focus)
i3.on('window::move', on_workspace_move)
i3.on('window::fullscreen_mode', on_fullscreen)
i3.on('shutdown::restart', on_restart)
i3.on('shutdown::exit', on_exit)
i3.main()