Le script volume_regulator.py est un régulateur de volume intelligent qui :

  1. Mesure le niveau sonore actuel.
  2. Compare ce niveau avec une référence définie par l'utilisateur.
  3. Ajuste dynamiquement le volume système pour atteindre la référence.
import subprocess
import json
import sys
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
from comtypes import CLSCTX_ALL
import numpy as np
import sounddevice as sd
import time

# Initialisation des paramètres globaux
tolerance_db = 5  # Tolérance par défaut en dB
sampling_interval = 0.5  # Intervalle d'analyse par défaut en secondes
recent_levels = []
max_recent = 5  # Taille de la fenêtre pour la moyenne glissante

# Fonction : Exécuter l'installateur
def run_installer():
    try:
        installer_path = "C:\\\\chemin\\\\vers\\\\VolumeRegulatorSetup.exe"
        subprocess.run([installer_path], check=True)
        return {"status": "success"}
    except Exception as e:
        return {"status": "error", "message": str(e)}

# Fonction : Régler le volume système
def set_volume(level):
    try:
        devices = AudioUtilities.GetSpeakers()
        interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
        volume = interface.QueryInterface(IAudioEndpointVolume)
        volume.SetMasterVolumeLevelScalar(level / 100.0, None)
        return {"status": "success"}
    except Exception as e:
        return {"status": "error", "message": f"Erreur lors du réglage du volume : {e}"}

# Fonction : Mesurer le niveau sonore actuel en dB
def get_audio_level():
    try:
        duration = 0.1
        samplerate = 44100
        audio_data = sd.rec(int(duration * samplerate), samplerate=samplerate, channels=1, dtype='float64')
        sd.wait()
        rms = np.sqrt(np.mean(np.square(audio_data)))
        db = 20 * np.log10(rms) if rms > 0 else -np.inf
        return db
    except Exception as e:
        print(f"Erreur lors de la mesure du niveau sonore : {e}")
        return -np.inf

# Fonction : Calculer une moyenne glissante
def get_smoothed_audio_level():
    global recent_levels
    current_level = get_audio_level()
    recent_levels.append(current_level)
    if len(recent_levels) > max_recent:
        recent_levels.pop(0)
    return np.mean(recent_levels)

# Fonction : Vérifier si un ajustement de volume est nécessaire
def should_adjust_volume(current_db, target_db):
    return abs(current_db - target_db) > tolerance_db

# Fonction : Lire un message JSON depuis stdin
def read_message():
    try:
        input_length = sys.stdin.read(4)
        if not input_length:
            return None
        length = int.from_bytes(bytearray(input_length.encode()), 'little')
        return sys.stdin.read(length)
    except Exception as e:
        print(f"Erreur lors de la lecture du message : {e}")
        return None

# Fonction : Envoyer un message JSON à stdout
def send_message(message):
    try:
        response = json.dumps(message)
        sys.stdout.write(response + "\\n")
        sys.stdout.flush()
    except Exception as e:
        print(f"Erreur lors de l'envoi du message : {e}")

# Fonction : Mettre à jour les paramètres globaux
def update_settings(tolerance, frequency):
    global tolerance_db, sampling_interval
    if tolerance > 0 and frequency > 0:
        tolerance_db = tolerance
        sampling_interval = frequency
        print(f"Paramètres mis à jour : Tolérance = {tolerance_db} dB, Fréquence = {sampling_interval} s")
        return {"status": "success"}
    else:
        return {"status": "error", "message": "Paramètres invalides"}

# Boucle principale pour gérer les actions
while True:
    message = read_message()
    if not message:
        time.sleep(sampling_interval)
        continue

    try:
        data = json.loads(message)
        action = data.get("action")

        if action == "runInstaller":
            result = run_installer()
            send_message(result)

        elif action == "setVolume":
            volume = data.get("volume")
            if isinstance(volume, (int, float)) and 0 <= volume <= 100:
                result = set_volume(volume)
                send_message(result)
            else:
                send_message({"status": "error", "message": "Volume invalide"})

        elif action == "updateSettings":
            tolerance = data.get("tolerance")
            frequency = data.get("frequency")
            if isinstance(tolerance, (int, float)) and isinstance(frequency, (int, float)):
                result = update_settings(tolerance, frequency)
                send_message(result)
            else:
                send_message({"status": "error", "message": "Paramètres invalides"})

        elif action == "getCurrentVolume":
            current_db = get_smoothed_audio_level()
            current_volume = max(0, min(100, int((current_db + 20) * 2.5)))
            send_message({"currentVolume": current_volume})

        else:
            send_message({"status": "error", "message": f"Action inconnue : {action}"})

    except json.JSONDecodeError:
        print("Erreur : Message JSON mal formé.")
    except Exception as e:
        print(f"Erreur inattendue : {e}")

    time.sleep(sampling_interval)

Bibliothèques utilisées :

  1. Récupère l'appareil de sortie audio par défaut via AudioUtilities.GetSpeakers().
  2. Active l'interface IAudioEndpointVolume pour accéder aux fonctions de contrôle du volume.
  3. Définit le volume via SetMasterVolumeLevelScalar, où le niveau (level) est normalisé entre 0 (muet) et 1 (volume maximum).