Echtzeit-Stimmhöhen-Teiler
Aus einer hohen Stimme eine tiefere machen, das hat einen ganz praktischen Nutzen. Ich denke da besonders einen älteren Herrn, dessen Gehör in letzter Zeit nicht mehr so gut funktioniert wie früher, was dazu führt, dass er seine Frau nicht mehr richtig verstehen kann.
Aus einer hohen Stimme eine tiefere machen, das hat einen ganz praktischen Nutzen. Ich denke da besonders einen älteren Herrn, dessen Gehör in letzter Zeit nicht mehr so gut funktioniert wie früher, was dazu führt, dass er seine Frau nicht mehr richtig verstehen kann. Auf einer Familienfeier konnte ich kürzlich beobachten, dass er dagegen eine tiefe Männestimme ganz ohne Probleme verstehen konnte. Es ist also eine Frage der oberen Grenzfrequenz, die bei jedem Menschen im Alter absinkt. Irgendwann reicht es nicht mehr für eine hohe Frauenstimme. Das führt nicht nur zu dauernden Missverständnissen, sondern auch zu Streit und Ärger. „Wenn du endlich mal deutlich sprechen würdest, könnte ich dich auch verstehen!“ „Ich rede wie immer! Wenn du mal richtig zuhören würdest, könntest du mich auch verstehen!“ Und so weiter. Könnte man aber die hohe Stimme der Frau in eine tiefere umsetzen, wäre der Frieden gerettet. Und genau das ist mein Ziel.
Der erste Versuch geht von einem bestehenden VB6-Programm aus, das ich mal für den Einsatz als SSB-Demodulator in einem Software Defined Radio eingesetzt habe. Eine FFT rechnet das Signal in die einzelnen Frequenzen um, die dann passend verschoben oder umgerechnet werden. Danach erzeugt eine inverse FFT wieder ein Audiosignal. Für ein SSB-Signal muss man Frequenzen um einen konstanten Betrag verschieben. Für den Stimmhöhen-Teiler muss dagegen jede einzelne Frequenz eines Audiosignals um einen konstanten Faktor verändert werden. Im Kern sieht das so aus:
FourierTransform NFFT, Single1(), Single2(), Single3(), Single4()
For n = 0 To 4095
Single1(n) = Single3(n)
Single2(n) = Single4(n)
Next n
For n = 0 To 4095
Single3(n) = 0
Single4(n) = 0
Next n
j = 1 + (HScroll2.Value) / 100
For n = 2 To 1000 '
u = (j * n) - Int(j * n) 'upper bin
l = 1 - u 'lower bin
Single3(n) = l * Single1(Int(j * n)) + u * Single1(Int(j * n) + 1)
Single4(n) = l * Single2(Int(j * n)) + u * Single2(Int(j * n) + 1)
Next n
FourierTransform NFFT, Single3(), Single4(), Single1(), Single2(), True
Das Verfahren funktioniert zwar grundsätzlich, aber es gibt noch einige Schönheitsfehler. Insbesondere entstehen Knackgeräusche am Ende jedes Frames. Man kann aber schon mal ausprobieren, wie es sich anhört. Eine hohe Frauenstimme wird zu einer auffällig tiefen Männerstimme, wenn man jede Frequenz durch 1,5 dividiert. Das Programm kann das Spektrum zwar sogar halbieren, aber dabei leiden alle Konsonanten so stark, dass die Verständlichkeit gegen Null geht.
Das folgende Youtube-Video zeigt das Programm in Aktion. Das originale Audiosignal stammt aus dem Radio, und zwar aus der von mir hoch geschätzten „Spielart“ am Sonntagnachmittag im WDR5. Eine Sprecherin mit hoher Stimme liest eine Geschichte vor. Die Stimme wird bis zu einer tiefen Männerstimme verändert. Die Störgeräusche muss man sich erst mal wegdenken.
Video: http://youtu.be/a_4tlksCDfA
Das jetzige Programm ist nicht mehr als eine erste Machbarkeitsstudie. Damit so ein Gerät in der Praxis einsetzbar wird, muss es viel kleiner sein und über zwei echte Potis mit Drehknöpfen einstellbar sein. Ich stelle mir vor, dass man einen Kopfhörer verwendet und das Mikrofon in das kleine tragbare Gerät eingebaut ist.
Vermutlich gibt es mehrere mögliche Lösungsansätze, vielleicht mit einem DSP-Board, mit dem Raspberry Pi, dem Elektor-Linux-Board, einem Android-System oder vielleicht sogar mit einem ATmega oder dem Xmega? Ich vermute auch, dass es Leute gibt, die locker mit solchen Aufgaben der Signalverarbeitung umgehen. Deshalb habe ich die Aufgabe auf der Elektor-Project-Page vorgestellt, mit der Bitte an alle Fachleute, bei der Umsetzung zu helfen. Oder gibt es vielleicht sogar schon eine fertige Lösung? Wenn nicht, muss sie jedenfalls entwickelt werden. Allein schon als Beitrag zum Frieden in der Welt. Und außerdem sind wir alle in einigen Jahrzehnten vielleicht auch schon in der Situation, dass das Gehör nachlässt. Wenn man dann mal was genau hören will, ist das Gerät schon da, wenn man gerade lieber nichts verstehen will, dann schaltet man es einfach aus.
Mit der Bitte um Mitarbeit,
Burkhard Kainka
-----------------------------------------------------------
Version 0.2
Inzwischen bin ich einen Schritt weiter gekommen und konnte die Störgeräusche etwas verringern. Der Trick dabei: Ich merke mir jeweils den letzten Wert eines Frames und passe dann den Anfang des nächsten daran an. Dabei werden große Sprünge im Signal vermieden. Nicht allerdings Phasensprünge, weshalb immer noch ein geringes Knacken übrig bleibt.
For n = 0 To BLKSIZE - 1
Single1(n) = Single1(n) + Single2(n)
If n = 0 Then diff = Last - Single1(0)
Single1(n) = Single1(n) + diff
diff = diff * 0.98
If n = BLKSIZE - 1 Then Last = Single1(n)
Single1(n) = Single1(n) * Multiplier
If Single1(n) < -1 Then Single1(n) = -1
If Single1(n) > 1 Then Single1(n) = 1
outBuffer(n * 2) = Int(Single1(n) * 32000)
outBuffer(n * 2 + 1) = outBuffer(n * 2) 'interleave L and R
Next n
Hier gibt es ein Hörbeispiel. Eine Dame spricht im Kinderfunk über Kaffeebohnen und Elefantenkacke, natürlich in wechselnder Tonhöhe. http://youtu.be/YVhDQnprYUo
------------------------------------------------------------------
Lösung mit Mikrocontroller ATmega168
Dank xyphro habe ich nun neue Wege beschritten und die ganze Sache auf einem ATmega168 mit Bascom zum Laufen gebracht. Es ist noch nicht ganz perfekt, zeigt aber schon wo es mal hingehen könnte. Im Moment arbeite ich mit 8-Bit-Daten und 512 Byte Pufferlänge. Das Tiefpassfilter am Eingang sollte noch verbessert werden. Außerdem wäre eine höhere Auflösung gut. Vermutlich ist die MSP430-Lösung von xyphro besser in Bezug auf Klang und Störungsfreiheit.
Hier ein Video zum Gerät, das ich in ein Radiogehäuse eingebaut habe:
http://youtu.be/Lfpzolm6-PE
Discussion (4 comments)