Spielzeugformantvocoder (Sprachsynthese)

OP #736149
Lesenswert?

OK, eines vorweg. Der Code ist in Pascal. Ganz einfach deswegen, da das 
nicht nur meine Lieblingsprogrammiersprache ist, sondern auch noch 
leicht von jedem verstanden werden kann. Mir geht es hier nicht darum, 
einen perfekten Code abzuliefern, sondern darum, einfach mal zu zeigen, 
wie einfach das geht.

Das Programm macht einen einfachen Formant-Vocoder. Ein Vocoder 
simuliert den Stimmtrakt. Im Prinzip ist das eine Anregung welche aus 
einem Dirakpuls und Rauschen besteht (Verhältnis einstellbar) und diesen 
dann durch 2 Filter schickt welche eine Frequenzerhöhung bei einer 
bestimmten Frequenz (Formant) machen. 2 Formanten reichen für 
verständliche Sprache bereits aus.

Die Filter sind parallelgeschaltet und sind rekursive Filter 2. Ordnung. 
Vor rekursiven Filtern haben manche Leute Angst, wenn man die redoch in 
vernünftigen Rahmen betreibt sind die stabil.

Filterstruktur:

x---->+->------->y
      |\    |
      | \   T
      |  \b1|
       \    |
        \   T
         \b2|

Also grob gesagt kommt das Signal bei x rein, und dazu wird dann das 
einfach verzögerte, mit b1 multiplizierte Ausgangssignal addiert, sowie 
das zweifach verzögerte, mit b2 multiplizierte Ausgangssignal addiert.

Vereinfach gesagt bestimmt b2 die Güte des Filters und b1 die Frequenz.

Stabil ist der Filter in einem Dreieck mit der Spitze b1=0 und b2=1 
sowie der Basis b2=-1 und -2<=b1<=2.

Die Eingabe des Programmes ist
Dauer Grundfreq Stimmh. Rauschh.Formant1 Formant2
Beispiel:
1       100     1       0       1000    1400
1       100     1       0       500     2300
1       100     1       0       320     3200
1       100     1       0       500     1000
1       100     1       0       320     800
1       100     1       0       700     1800
1       100     1       0       500     1500
1       100     1       0       320     1650
1       100     0       1       3000    3500
1       100     0       1       2000    2500

Das sind mehrere Laute, jeweils eine Sekunde lang. Es beginnt mit A E I 
O U, Ä Ö Ü und dann kommen 2 experimentelle Frikale.

Die Ausgabe ist:
Zeit/s seit Dateianfang, Leerzeichen, Abtastwert
Das Programm sox kann dieses Format direkt als "dat" verarbeiten.

Wenn man mal genau nachsieht, in welchen Wertebereichen die einzelnen 
Variablen sind, und man die Cosinusse durch Tabellen ersetzt kann man 
das bestimmt auch mit Festkommaartithmetrik machen und somit problemlos 
auf einem AVR laufen lassen.
Angehängte Dateien:
Gast #742790
Lesenswert?

Hallo Christian!

Ich finde Deine Postings sehr interessant und überlege, sie auf einem 
AVR zu konvertieren. Allerdings woher bekommt man die Parameter für 
Phoneme? Selber ausprobieren? (Ich habe noch nicht wirklich selber 
gesucht :-)

Gruß, Michael
OP #742897
Lesenswert?

Micha wrote:
> Hallo Christian!
>
> Ich finde Deine Postings sehr interessant und überlege, sie auf einem
> AVR zu konvertieren.

Danke

> Allerdings woher bekommt man die Parameter für
> Phoneme? Selber ausprobieren? (Ich habe noch nicht wirklich selber
> gesucht :-)

In dem Fall des Musikstücks habe ich die einfach vom Spektrogramm 
abgelesen. Ansonsten ist die Wikipedia dein Freund. Zumindest bei 
Vokalen.
http://de.wikipedia.org/wiki/Formant

> Gruß, Michael
Gast #747682
Lesenswert?

Christian,

interessante sache, hatte mich noch nie damit beschäftigt! Ich hab mir 
mal den Code angesehen, da ist mir aufgefallen, das der implementierte 
Filter nicht zur textuellen Beschreibung passt:
Im code steht:
filter1_d1:=y1;

lt. Beschreibung würde ich hier ein:
filter1_d1:=x;

erwarten. Selbiges für den 2ten filter. Die Abbildung des Filters hilft 
mir da auch nicht weiter ...

Gruß
Mario
OP #747836
Lesenswert?

Mario wrote:
> Christian,
>
> interessante sache, hatte mich noch nie damit beschäftigt! Ich hab mir
> mal den Code angesehen, da ist mir aufgefallen, das der implementierte
> Filter nicht zur textuellen Beschreibung passt:
> Im code steht:
> filter1_d1:=y1;
>
> lt. Beschreibung würde ich hier ein:
> filter1_d1:=x;
>
> erwarten. Selbiges für den 2ten filter. Die Abbildung des Filters hilft
> mir da auch nicht weiter ...

Ahh, das ist ein Implementationsdetail. Würde ich den Wert von X nehmen, 
so müsste ich X verändern und beide Filter würden zusammenfallen.


Ich glaub so kann man das besser darstellen:


X--->Y1------>
    |
| |   V
|f1<-d1
|     |
|     V
f2<--d2


Die Summationsstelle ist somit Y1. Das macht den Code einfacher und ich 
brauche weniger Variablen.

> Gruß
> Mario

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren