Wie passe ich die Lautstärke automatisch an den Klang um mich herum an?

8

Ich wohne neben einer großen Straße. Nachts das Fenster offen zu haben ist wunderbar kühl und zeitweise sehr laut. Wie kann ich die Lautstärke basierend auf dem eingebauten Mikrofoneingang automatisch anpassen? Wenn ich die Lautstärke so einstelle, dass ich in einem Film Sprache hören kann, während ein Auto vorbeifährt, ist es zu anderen Zeiten sehr laut und es fühlt sich für die Menschen in der Nähe (draußen und Nachbarn) sehr unangenehm an.

Mein System ist Debian Buster, obwohl ich wahrscheinlich eine generische Lösung zum Laufen bringen kann. Wenn kein Paket verfügbar ist, das dies tut, wäre ein Befehl zum Extrahieren der Lautstärke aus dem Standardmikrofon bereits hilfreich, um dies zu skripten.

Luc
quelle
1
Sie können verwenden sox, um die durchschnittliche Lautstärke zu berechnen (IIRC gibt es andere Fragen zum Stapelaustausch) und pacmddie Lautstärke für Pulseaudio zu ändern.
Dirkt
1
@dirkt Danke für die Hinweise! Ich habe diese Frage gefunden, ich werde versuchen, sie morgen zu implementieren und zurückzumelden (vielleicht kann ich meine eigene Frage beantworten): superuser.com/questions/306701/…
Luc

Antworten:

2

Ich habe ein Python-Skript erstellt, um den Job zu erledigen. Ein verbleibendes Problem ist, dass das Mikrofon meines Laptops natürlich auch seine eigenen Lautsprecher aufnimmt. Ich denke, 'Echokompensation' könnte das sein, wonach ich suche, aber ich hätte keine Ahnung, wie ich das selbst implementieren soll. Die Verwendung eines externen Mikrofons könnte jedoch funktionieren.

Es ist Python 2 aufgrund der python-alsaaudioAbhängigkeit leider.

#!/usr/bin/env python

''' For noise cancellation:
$ pactl load-module module-echo-cancel
$ PULSE_PROP="filter.want=echo-cancel" ./this-script.py
'''

''' SETTINGS (you might want to keep presets for music and speech) '''
smoothing = 15 # Over how many samples should we compute?
step_size = 1 # maximum volume adjustment in percent points
# scale_xxx = (n, level) # At mic level n, scale to level% audio volume
scale_min = (4, 39)
scale_max = (19, 53)

''' CREDITS
https://stackoverflow.com/a/1937058
How get sound input from microphone in python, and process it on the fly?
Answer by jbochi

https://stackoverflow.com/a/10739764
How to programmatically change volume in Ubuntu
Answer by mata
'''

import alsaaudio, audioop, sys, os

bucket = [None for i in range(smoothing)]

inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE)

inp.setchannels(1)
inp.setrate(8000)
inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)

inp.setperiodsize(200)

print('Setting volume to minimum ({}%)'.format(scale_min[1]))
os.system('pactl set-sink-volume 0 {}%'.format(scale_min[1]))

i = 1
last_volume = scale_min[1]
while True:
    l, data = inp.read()
    if l:
        val = audioop.max(data, 2)
        bucket[i % smoothing] = val

        if i % smoothing == 0:
            m = min(bucket)
            miclvl = float(m) / 50.0

            if miclvl < scale_min[0]:
                scale = scale_min[1]
            elif miclvl > scale_max[0]:
                scale = scale_max[1]
            else:
                miclvl_range = scale_max[0] - scale_min[0]
                level_range = scale_max[1] - scale_min[1]
                scale = (miclvl - scale_min[0]) / miclvl_range * level_range + scale_min[1]

            scale = int(round(scale))
            step = max(min(scale - last_volume, step_size), -step_size)

            if step != 0:
                last_volume += step
                step = '+' + str(step) if step > 0 else str(step)
                os.system('pactl set-sink-volume 0 {}%'.format(step))

            miclvl = round(miclvl, 1)
            miclvlpacing = ' ' * (4 - len(str(miclvl)))
            stepspacing = ' ' * (2 - len(str(step)))
            sys.stdout.write('mic lvl {}{}  ideal scale {}%  adjust {}{}  now {}  '.format(
                miclvl, miclvlpacing, str(scale), step, stepspacing, last_volume))
            print(int(round(last_volume - scale_min[1])) * 'x')

        i += 1
Luc
quelle
1
Pulseaudio kann bis zu einem gewissen Grad eine Echokompensation durchführen. Weitere Informationen finden Sie beispielsweise hier und hier bei Google. Wenn Sie es selbst tun möchten, müssen Sie das Ausgangssignal zeitverzögert und mit der richtigen Amplitude vom Eingangssignal subtrahieren. Das automatische Finden dieser beiden Parameter macht Spaß. :-) (Google "Korrelation")
dirkt
@dirkt Nochmals vielen Dank! Pulseaudio scheint jedoch nicht sehr gut zu funktionieren; Besonders bei höheren Lautstärken (> 50%) bricht es einfach zusammen, erkennt sich selbst und steigt weiter an. Ich muss mir nur ein Mikrofon schnappen, es ist sowieso nicht so, als wären sie teuer :)
Luc