More pep8 fixes. A tiny bit of refactoring.

This commit is contained in:
Storm Dragon
2025-07-07 00:42:23 -04:00
parent d28c18faed
commit 3390c25dfe
343 changed files with 11092 additions and 7582 deletions

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.soundDriver import sound_driver
@@ -15,55 +15,53 @@ class driver(sound_driver):
def initialize(self, environment):
self.env = environment
self._initialized = True
print('Sound Debug Driver: Initialized')
print("Sound Debug Driver: Initialized")
def shutdown(self):
if not self._initialized:
return
self.cancel()
self._initialized = False
print('Sound Debug Driver: Shutdown')
print("Sound Debug Driver: Shutdown")
def play_frequence(
self,
frequence,
duration,
adjust_volume=0.0,
interrupt=True):
self, frequence, duration, adjust_volume=0.0, interrupt=True
):
if not self._initialized:
return
if interrupt:
self.cancel()
print(
'Sound Debug Driver: play_frequence:' +
' freq:' +
str(frequence) +
' duration:' +
str(duration) +
' adjust_volume:' +
str(adjust_volume))
print('Sound Debug Driver: -----------------------------------')
"Sound Debug Driver: play_frequence:"
+ " freq:"
+ str(frequence)
+ " duration:"
+ str(duration)
+ " adjust_volume:"
+ str(adjust_volume)
)
print("Sound Debug Driver: -----------------------------------")
def play_sound_file(self, file_path, interrupt=True):
if not self._initialized:
return
if interrupt:
self.cancel()
print('Sound Debug Driver: play_sound_file:' + str(file_path))
print('Sound Debug Driver: -----------------------------------')
print("Sound Debug Driver: play_sound_file:" + str(file_path))
print("Sound Debug Driver: -----------------------------------")
def cancel(self):
if not self._initialized:
return
print('Sound Debug Driver: Cancel')
print("Sound Debug Driver: Cancel")
def set_callback(self, callback):
if not self._initialized:
return
print('Sound Debug Driver: set_callback')
print("Sound Debug Driver: set_callback")
def set_volume(self, volume):
if not self._initialized:
return
self.volume = volume
print('Sound Debug Driver: set_volume:' + str(self.volume))
print("Sound Debug Driver: set_volume:" + str(self.volume))

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.soundDriver import sound_driver

View File

@@ -2,40 +2,73 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
import shlex
import subprocess
from fenrirscreenreader.core import debug
import subprocess
import shlex
from fenrirscreenreader.core.soundDriver import sound_driver
class driver(sound_driver):
"""Generic sound driver for Fenrir screen reader.
This driver provides sound playback through external command-line tools
like sox, aplay, or other audio utilities. It supports both sound file
playback and frequency/tone generation.
Features:
- Configurable external command execution
- Sound file playback (WAV, OGG, etc.)
- Frequency/tone generation
- Process management and cancellation
Attributes:
proc: Currently running subprocess for sound playback
soundFileCommand (str): Command template for playing sound files
frequenceCommand (str): Command template for generating frequencies
"""
def __init__(self):
sound_driver.__init__(self)
self.proc = None
self.soundType = ''
self.soundFileCommand = ''
self.frequenceCommand = ''
self.soundType = ""
self.soundFileCommand = ""
self.frequenceCommand = ""
def initialize(self, environment):
"""Initialize the generic sound driver.
Loads command templates from configuration for sound file playback
and frequency generation.
Args:
environment: Fenrir environment dictionary with settings
"""
self.env = environment
self.soundFileCommand = self.env['runtime']['SettingsManager'].get_setting(
'sound', 'genericPlayFileCommand')
self.frequenceCommand = self.env['runtime']['SettingsManager'].get_setting(
'sound', 'genericFrequencyCommand')
if self.soundFileCommand == '':
self.soundFileCommand = 'play -q -v fenrirVolume fenrirSoundFile'
if self.frequenceCommand == '':
self.frequenceCommand = 'play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence'
self.soundFileCommand = self.env["runtime"][
"SettingsManager"
].get_setting("sound", "genericPlayFileCommand")
self.frequenceCommand = self.env["runtime"][
"SettingsManager"
].get_setting("sound", "genericFrequencyCommand")
if self.soundFileCommand == "":
self.soundFileCommand = "play -q -v fenrirVolume fenrirSoundFile"
if self.frequenceCommand == "":
self.frequenceCommand = "play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence"
self._initialized = True
def play_frequence(
self,
frequence,
duration,
adjust_volume=0.0,
interrupt=True):
self, frequence, duration, adjust_volume=0.0, interrupt=True
):
"""Play a tone at the specified frequency.
Args:
frequence (float): Frequency in Hz
duration (float): Duration in seconds
adjust_volume (float): Volume adjustment
interrupt (bool): Whether to interrupt current sound
"""
if not self._initialized:
return
if interrupt:
@@ -43,42 +76,54 @@ class driver(sound_driver):
popen_frequence_command = shlex.split(self.frequenceCommand)
for idx, word in enumerate(popen_frequence_command):
word = word.replace(
'fenrirVolume', str(
self.volume * adjust_volume))
word = word.replace('fenrirDuration', str(duration))
word = word.replace('fenrirFrequence', str(frequence))
"fenrirVolume", str(self.volume * adjust_volume)
)
word = word.replace("fenrirDuration", str(duration))
word = word.replace("fenrirFrequence", str(frequence))
popen_frequence_command[idx] = word
self.proc = subprocess.Popen(
popen_frequence_command,
stdin=None,
stdout=None,
stderr=None,
shell=False)
self.soundType = 'frequence'
shell=False,
)
self.soundType = "frequence"
def play_sound_file(self, file_path, interrupt=True):
"""Play a sound file.
Args:
file_path (str): Path to the sound file to play
interrupt (bool): Whether to interrupt current sound
"""
if not self._initialized:
return
if interrupt:
self.cancel()
# Validate file path to prevent injection
import os
if not os.path.isfile(file_path) or '..' in file_path:
if not os.path.isfile(file_path) or ".." in file_path:
return
popen_sound_file_command = shlex.split(self.soundFileCommand)
for idx, word in enumerate(popen_sound_file_command):
word = word.replace('fenrirVolume', str(self.volume))
word = word.replace('fenrirSoundFile', shlex.quote(str(file_path)))
word = word.replace("fenrirVolume", str(self.volume))
word = word.replace("fenrirSoundFile", shlex.quote(str(file_path)))
popen_sound_file_command[idx] = word
self.proc = subprocess.Popen(popen_sound_file_command, shell=False)
self.soundType = 'file'
self.soundType = "file"
def cancel(self):
"""Cancel currently playing sound.
Terminates the subprocess playing sound and cleans up resources.
"""
if not self._initialized:
return
if self.soundType == '':
if self.soundType == "":
return
if self.soundType == 'file':
if self.soundType == "file":
self.proc.kill()
try:
# Wait for process to finish to prevent zombies
@@ -87,7 +132,7 @@ class driver(sound_driver):
pass # Process already terminated
except Exception as e:
pass # Handle any other wait errors
if self.soundType == 'frequence':
if self.soundType == "frequence":
self.proc.kill()
try:
# Wait for process to finish to prevent zombies
@@ -96,4 +141,4 @@ class driver(sound_driver):
pass # Process already terminated
except Exception as e:
pass # Handle any other wait errors
self.soundType = ''
self.soundType = ""

View File

@@ -2,19 +2,22 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
import threading
import time
from fenrirscreenreader.core import debug
import time
import threading
from fenrirscreenreader.core.soundDriver import sound_driver
_gstreamerAvailable = False
try:
import gi
from gi.repository import GLib
gi.require_version('Gst', '1.0')
gi.require_version("Gst", "1.0")
from gi.repository import Gst
_gstreamerAvailable, args = Gst.init_check(None)
except Exception as e:
_gstreamerAvailable = False
@@ -33,21 +36,23 @@ class driver(sound_driver):
self._initialized = _gstreamerAvailable
if not self._initialized:
global _availableError
self.environment['runtime']['DebugManager'].write_debug_out(
'Gstreamer not available ' + _availableError, debug.DebugLevel.ERROR)
self.environment["runtime"]["DebugManager"].write_debug_out(
"Gstreamer not available " + _availableError,
debug.DebugLevel.ERROR,
)
return
self._player = Gst.ElementFactory.make('playbin', 'player')
self._player = Gst.ElementFactory.make("playbin", "player")
bus = self._player.get_bus()
bus.add_signal_watch()
bus.connect("message", self._on_player_message)
self._pipeline = Gst.Pipeline(name='fenrir-pipeline')
self._pipeline = Gst.Pipeline(name="fenrir-pipeline")
bus = self._pipeline.get_bus()
bus.add_signal_watch()
bus.connect("message", self._on_pipeline_message)
self._source = Gst.ElementFactory.make('audiotestsrc', 'src')
self._sink = Gst.ElementFactory.make('autoaudiosink', 'output')
self._source = Gst.ElementFactory.make("audiotestsrc", "src")
self._sink = Gst.ElementFactory.make("autoaudiosink", "output")
self._pipeline.add(self._source)
self._pipeline.add(self._sink)
self._source.link(self._sink)
@@ -61,7 +66,7 @@ class driver(sound_driver):
self.cancel()
self.mainloop.quit()
# Wait for the GLib MainLoop thread to finish to prevent shutdown races
if hasattr(self, 'thread') and self.thread.is_alive():
if hasattr(self, "thread") and self.thread.is_alive():
# 2 second timeout to prevent hanging
self.thread.join(timeout=2.0)
@@ -73,9 +78,10 @@ class driver(sound_driver):
elif message.type == Gst.MessageType.ERROR:
self._player.set_state(Gst.State.NULL)
error, info = message.parse_error()
self.env['runtime']['DebugManager'].write_debug_out(
'GSTREAMER: _on_player_message' + str(error) + str(info),
debug.DebugLevel.WARNING)
self.env["runtime"]["DebugManager"].write_debug_out(
"GSTREAMER: _on_player_message" + str(error) + str(info),
debug.DebugLevel.WARNING,
)
def _on_pipeline_message(self, bus, message):
if not self._initialized:
@@ -85,9 +91,10 @@ class driver(sound_driver):
elif message.type == Gst.MessageType.ERROR:
self._pipeline.set_state(Gst.State.NULL)
error, info = message.parse_error()
self.env['runtime']['DebugManager'].write_debug_out(
'GSTREAMER: _on_pipeline_message' + str(error) + str(info),
debug.DebugLevel.WARNING)
self.env["runtime"]["DebugManager"].write_debug_out(
"GSTREAMER: _on_pipeline_message" + str(error) + str(info),
debug.DebugLevel.WARNING,
)
def _on_timeout(self, element):
if not self._initialized:
@@ -99,23 +106,20 @@ class driver(sound_driver):
return
if interrupt:
self.cancel()
self._player.set_property('volume', self.volume)
self._player.set_property('uri', 'file://%s' % file_name)
self._player.set_property("volume", self.volume)
self._player.set_property("uri", "file://%s" % file_name)
self._player.set_state(Gst.State.PLAYING)
def play_frequence(
self,
frequence,
duration,
adjust_volume=0.0,
interrupt=True):
self, frequence, duration, adjust_volume=0.0, interrupt=True
):
if not self._initialized:
return
if interrupt:
self.cancel()
duration = duration * 1000
self._source.set_property('volume', self.volume * adjust_volume)
self._source.set_property('freq', frequence)
self._source.set_property("volume", self.volume * adjust_volume)
self._source.set_property("freq", frequence)
self._pipeline.set_state(Gst.State.PLAYING)
GLib.timeout_add(duration, self._on_timeout, self._pipeline)