Résolu detecter l'utilisation de la carte son

stefmo

Habitué
bonjour,

je souhaiterais savoir comment détecter quand ma carte son (M-Audio Delta 1010LT) est utilisée, autrement dit quand un son est joué. (sous windows seven)

ce que je cherche a faire :
un HTPC qui via EventGhost mettrait mon ampli (piloté par le port serie) en veille après un certain temps de silence, et le sortirait de veille qd je joue un film, de la musique... le truc c'est que les sources de son sur un pc sont vraiment trop multiples pour passer par la reconnaissance des processus (foobar, mediaportal, vlc, internet...)

des idées?

merci d'avance

steph
 

KyrO_82

Grand Maître
Bonjour,

C'est pas trop compliqué de faire ça...
Regarde dans les API de capture du son: tu captures le son à intervalles régulières, puis tu regardes si tu as des données dans le buffer de capture (une simple boucle pour voir si valeur != 0).

Pour les API Windows, il y a par exemple winmm.dll, mais suivant le langage que tu utilises il y a surement des bibliothèques de plus haut niveau.

Bonne prog ;)


PS. Pour .NET, je crois qu'il y a la bibliothèque qui pourrait faire l'affaire. Spécialement les projets (en bas de page) "WPF Sound Visualization Library" ou "TuneBlade" qui semblent capturer les sons Windows.
 

stefmo

Habitué
merci pour la réponse.

je vois bien l'idée, le seul hic (me concernant), c'est ma connaissance très limitée en programmation en général. Je saurais même pas expliquer ce qu'est une API, c'est pour dire...

Eventghost semble fonctionner et accepter des scripts en python, je vais me pencher vers ce langage.
mais ça risque d'être un sacré chantier bien disproportionné si je dois apprendre un langage pour ça !
je veux pas une solution clé en main, mais si il existe moins lourd en investissement, je prends !

ou alors je revois mes ambitions à la baisse et utilise ma télécommande pour éteindre mon ampli et basta...
 

KyrO_82

Grand Maître
Meilleure réponse
;)

Clair que si tu connais rien en prog, ça va pas être facile, mais Python s'apprend assez vite.
Si j'ai rien à faire un de ces jours, peut être que j'essaierai de développer un petit VU-mètre en python ^^
 

stefmo

Habitué
merci pour le tuyau

je fouille un peu pyaudio, et le seul truc pertinent que j'arrive a comprendre c'est:
"
import pyaudio
import wave

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100

p = pyaudio.PyAudio()

stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
"
ensuite stream.read(CHUNK) semble se remplir de blancs ou de ÿÿ si y a rien qui joue et tout un tas de caractères incompréhensibles en grand nb si qqch joue.

problème (outre le fait que j'y connaisse rien et que je tâtonne comme un gosse) : j'ai pas trouvé comment utiliser ces 2 données pourtant bien différentes.

voila voila ou j'en suis... et c'est pas glorieux
 

stefmo

Habitué
ça y est j'ai enfin trouvé autre chose de clairement utilisable:

import pyaudio, audioop

p = pyaudio.PyAudio()

stream = p.open(format=pyaudio.paInt16,
channels=1,
rate=44100,
input=True,
frames_per_buffer=32)

data = stream.read(32)
pwr = audioop.rms(data,2)

-> et ce pwr est à 0 qd rien ne joue et > 0 qd qqch joue.

merci pour les pistes, je savais pas du tout comment commencer
 

KyrO_82

Grand Maître
Super :)

Après encore 2 choses:

- Je pensais que par défaut, lorsque le paramètre "input_device_index" n'est pas spécifié lors de l'appel de PyAudio.open(), l'entrée microphone était capturé.
Apparemment tu peux connaitre le nombre de périphériques avec la fonction PyAudio.get_device_count() et la description de chaque périphérique avec la fonction PyAudio.get_device_info_by_index(device_index).
A tester pour ne pas avoir de mauvaise surprise peut-être.

- Essaie d'utiliser le moins de ressources CPU possible en baissant la qualité d'enregistrement au maximum: "format" et "rate" le plus petit possible (paInt16 et 44100 c'est qualité CD, pas utile).
"frames_per_buffer" définis donc la longueur de chaque capture je pense, si tu y met la même valeur que "rate" ça te fera donc probablement des captures de 1 secondes. Essaies donc de mettre "rate" et "frames_per_buffer" à 1 pour voir (en théorie, je pense que ça te mesurera 1 valeur par seconde, mais je sais pas si c'est géré au niveau matériel).
Tu peux aussi faire des pauses entre chaque mesure (par exemple capturer 1 seconde toutes les 10 secondes) avec un time.sleep() dans la boucle principale ou alors plutôt gérer ça à partir de Eventghost, à toi de voir ;)


Bon boulot jusqu'à là, reste à intégrer ça dans Eventghost (ou gérer ton ampli à partir de Python) :)
 

stefmo

Habitué
merci pour tes conseils :)

je vois pas trop quoi faire de ton premier point. j'ai énuméré et obtiens les différents "device" par index et toutes leurs info, et après...? vu que je sais pas vraiment lequel il utilise qd je m'occupe pas de ça.

pour le deuxième point, j'ai essayé de tout baissé au max comme tu m'as dit, mais curieusement, le resultat mets beaucoup moins de temps a sortir qd je laisse format à paInt16 et rate à 44100 ou 48000, et rien de mieux en mettant frame_per_buffer et rate à la même valeur...

par contre j'ai un comportement embêtant: une fois que je lance le script, l'échantillonnage de la carte son semble ne plus pouvoir se modifier.
par exemple : j'écoute un morceau à 44100, derrière j'obtiens un message d'erreur de foobar (ASIO) dès que je veux lire un morceau en 48000 (Unrecoverable playback error: Sample rate of 48000 Hz not supported by this device). De même dans le pilote de ma carte je peux plus modifier le sample rate qui reste coincé à 44100.
Et ce indépendamment de la valeur de rate que je renseigne dans mon script, l'inverse étant vrai (44100 vers 48000 et vice-versa).
D'autres lecteurs tels que vlc ou le lecteur de mediaportal (même en ASIO) ne me posent pas ce soucis de refus de lecture.

Pour régler l'affaire, il faut que je ferme complétement Eventghost (qui "héberge" python), et là je peux changer mon rate et écouter autre chose.
J'imagine qu'il faudrait que je "libère" dans python les fonctions audio ou qqch comme ça (je le dis avec mes mots, hein ;) ). J'ai essayé pyaudio.terminate() mais ça donne rien.

Par contre pour ce qui est de l'intégration dans EventGhost, ça m'a pas posé (trop) de problèmes. mais je reste à un test par seconde pour pouvoir relancer l'ampli qd un son se joue, et 10 secondes de latence c'est trop.

Merci encore
 

KyrO_82

Grand Maître

Je pense que les différents "devices" sont par exemple: Wave_Out, Digital_Out, HDMI_Out, Mic_In, Line_In...
Actuellement ça prend le device par défaut, chez toi ça tombe sur ta sortie son que tu utilises. Mais est-ce que ça sera toujours le cas sur d'autres systèmes? Je ne sais pas, je pense simplement qu'il serait bien de pouvoir configurer ça facilement quelque-part.
Peut-être qu'il y a un device "wave_out_loop", qui permettrait d’arranger ce problème de fréquence...


Normal que ce soit plus long.
- rate = nombre de captures par seconde
- frame_per_buffer = nombre de captures à faire
donc temps = frame_per_buffer / rate [secondes]
-> 32 / 44100 = 0.725 ms
Si tu met un plus petit rate sans changer frame_per_buffer, par exemple 100:
-> 32 / 100 = 320 ms
Et si tu met tout à 1 comme je te l'ai dis avant:
-> 1 / 1 = 1 seconde
Ce qui fait 1 mesure par seconde. Mais donc évidemment, ça bloque ton thread pendant 1 seconde si tu fais ça en synchrone.

Mais le PaInt16 ou PaInt8 ne va rien changer à cela, si? La capture en 8 bit serait amplement suffisante et prend moins de ressources.


Hummm... Con ça...
Je comprend pas trop le problème des 48000 Hz... donc même si tu mets un rate d'enregistrement de 48 kHz?
Comme ça je vois pas, faudrait que j'essaie moi-même... (et voir ce que disent les infos au sujet des devices aussi).


PyAudio.close(stream) ;)


Ouais, clair que 10 secondes c'est long :D
 

stefmo

Habitué
le coup du rate sample bloqué, vu que ça a l'air de déranger que foobar, je lui mets le dsp resampler à 44100, du coup plus de soucis de ce côté, même si je sais toujours pas pourquoi ça fait ça...

ce soir en rentrant (ça a tourné toute la journée), en ayant mis frame_per_buffer à 32, rate à 44100 et paInt8 au lieu de paInt16, le résultat de mon pwr = audioop.rms(data,2) n'était pas 0... pourtant rien ne jouait... je remets à paInt16 pour voir

c'est chiant, j'y connais rien, et je tâtonne tout le long sans savoir ce que je fais. Ce serait un peu comme si j'étais un pigeon qui essaierait de faire tomber les graines d'un mangeoire en plastique en essayant différentes tonalités de roucoulement...
 

stefmo

Habitué
Voilà ça à l'air de marcher :

import pyaudio, audioop, time
p = pyaudio.PyAudio()

stream = p.open(format=pyaudio.paInt16,
channels=1,
rate=44100,
input=True,
frames_per_buffer=32)
stream.stop_stream() #nécessaire pour éviter une erreur d'overflow qqch

et en boucle toutes les secondes:
stream.start_stream()
data = stream.read(32)
pwr = audioop.rms(data,2)
stream.stop_stream()

if pwr == 0: #si muet, incrémente count
count = count+1

if count > 600 and eg.globals.denon_on == True: #si 10 minutes et l'ampli est en route
eg.plugins.DenonSerial.PowerOff() #eteint l'ampli (= plugin dans eventghost via port serie)

if pwr != 0: # si y a du son, on repart de zéro et si l'ampli est éteint, on l'allume
count = 0
if eg.globals.denon_on == False:
eg.plugins.DenonSerial.PowerOn()

les constantes eg.qqch c'est dans eventghost
 
Vous devez vous inscrire ou vous connecter pour répondre ici.
Derniers messages publiés
Statistiques globales
Discussions
730 098
Messages
6 717 064
Membres
1 586 286
Dernier membre
petitangebleu1977
Partager cette page
Haut