Forum: Digitale Signalverarbeitung / DSP / Machine Learning Stimm / Gesangsanalyse


von Paul (Gast)


Lesenswert?

Schönen guten Tag,

ich arbeite gerade aus Interesse an einem Programm welches später 
ähnlich wie Singstar oder Ultrastar in quasi realtime die Stimmlage 
eines Menschens über das Mikrofon analysieren soll.

Mein erster Ansatz ist über die Fourier Transformation das 
Frequenzspektrum abzufragen. Allerdings habe ich nun ein Problem mit der 
erkennung einer Tonhöhe. Über die Aufnahme durch ein Mikro wird 
natürlich keine saubere Frequenz aufgenommen, so das ich da nicht so 
recht weiß wie ich nun aus dem entwas unübersichtlichen Frequenzspektrum 
eine Tonlage interpretieren kann. Gibt es da irgendwelche Filter oder 
sonstige Ansätze die mir helfen könnten das zu verstehen?

/ Paul

von Kai G. (runtimeterror)


Lesenswert?

Eine einfache Möglichkeit:
- Wähle die unterste Oktave in der du noch sinnvollen Gesang vermutest.
- Berechne die Frequenzen aller 12 Halbtöne
- Erstelle für jeden der Halbtöne einen Puffer mit der zur Frequenz 
passenden Wellenlänge (sample rate / Frequenz)
- Schreibe das gesampelte Audio-Signal in den Puffer (einfach auf die 
bestehenden Werte aufaddieren und am Ende umbrechen -> Ringpuffer)
- Berechne den Energiegehalt (Quadratsumme für jeden Buffer / Länge?)
- Der Buffer, der den höchsten Energiegehalt liefert wurde von der 
Stimme am besten getroffen.

Das Verfahren ist recht simpel und erfüllt auf jeden Fall seinen Zweck. 
Ein wenig Feinschliff ist aber dennoch nötig/sinnvoll (Tiefpass, 
Downsampling, Gewichtungen).

Bildlich beschrieben versucht das Verfahren eine stehende Welle im 
Buffer aufzubauen, was nur dann funktioniert, wenn die gesungene 
Wellenlänge ein ganzzahliges Vielfaches der Bufferlänge ist. Auf diese 
Weise werden auch die Obertöne des Grundtons mit bewertet und die Oktave 
weitgehend ignoriert (macht Singstar ja auch).

Hoffe, das gibt dir schonmal ein paar Werkzeuge an die Hand.

von Paul (Gast)


Lesenswert?

Ich habe gelesen das Singstar ganz auf eine FT verzichtet, in Ultrastar 
NG (native Linux C++ version) allerdings verwendet wird, was zu einer 
genaueren Analyse und Darstellung führt. Verstehe ich das richtig das in 
deinem beschriebenen Verfahren garnicht die Fourier Transformation 
benötigt wird?

- Wähle die unterste Oktave in der du noch sinnvollen Gesang vermutest.
Gibt es da so etwas wie Richtwerte, oder ist die unterste Oktave vom 
referenz-lied abhängig?

Gibt es einen Namen zu diesem Verfahren oder hast du vielleicht Links zu 
Artikeln die das beschreiben?

von Kai G. (runtimeterror)


Lesenswert?

Ich sehe hier keinen Sinn in einer Fourier-Analyse. Die Fourier-Analyse 
ist geeignet, wenn man sich für das Obertonspektrum eines gegebenen 
Grundtons interessiert (z.B. Stimmerkennung). Für deinen Anwendungsfall 
ist aber nur die Ermittlung des Grundtons wichtig.

In welcher Oktave gesungen wird ist auch egal. Wenn du in einer unteren 
Oktave suchst, werden die höheren Oktaven (als Obertöne) mit erfasst - 
andersrum nicht.

>Gibt es da so etwas wie Richtwerte, oder ist die unterste Oktave vom
>referenz-lied abhängig?
Ich komme mit meiner Stimme bis 37 Hz runter wenn ich mich rechterinnere 
(mit dem o.g. Algorithmus gemessen) - verstehen tut man da aber nichts 
mehr ;)
Sing einfach mal ein paar Lieder vor dich hin und schau, in welchen 
Oktaven du dich normalerweise befindest. Ich denke, dass man hier 
mindestens so viel ausprobieren wie berechnen muss.

>Gibt es einen Namen zu diesem Verfahren oder hast du vielleicht Links zu
>Artikeln die das beschreiben?
Öhm... nenn es Grundtonermittlung nach Giebeler :) keine Ahnung, ob das 
einen Namen hat.

Das ganze ließe sich auch mit 12 FIR-Filtern erreichen, was mathematisch 
identisch, aber algorithmisch unnötig komplex wäre.

Du kannst auch mal nach BPM-Countern Ausschau halten, die müssen ein 
sehr ähnliches Problem lösen... nur halt in einem anderen 
Frequenzbereich.

Ich suche auch schon ein Weilchen nach einem schnellen Algorithmus um 
den Grundton unabhängig von den festen Noten zu ermitteln - bis jetzt 
habe ich das immer mit der Holzhammer-Methode gelöst.

von Paul (Gast)


Lesenswert?

Vielen Dank für Deine Ausführlichen Antworten!
Ich dachte eigentlich das ich das Prinzip verstanden habe, allerdings 
bekomme ich bei meinen Tests nicht immer das gewünschte Ergebnis.
Ich schreibe mal auf wie ich konkret vorgehe, falls du einen Fehler 
entdeckst wäre das super wenn du mir dabei helfen könntest :)

Zuerst generiere ich die Referenzbuffer. Dabei habe ich bei meinen Tests 
als Oktave 32.7hz und nachher 65.41hz genommen. die anderen halbtöne 
berechne ich mit der Formel
 Wobei x der gewünschte Halbton ist.

Als nächstes addiere ich in einer Schleife die Daten meines Samples auf 
die Referenzbuffer und errechne die Energie jedes einzelnen buffers:
1
  for(int j = 0; j< 12; j++) {
2
    double tmp = 0;
3
    double *tempData = (double*) malloc(sampleCount * sizeof(double));
4
    for(int i=0; i<sampleCount; i++) {
5
      tempData[i] = refBuffer[j][i] + pcmData[i];
6
      tmp += tempData[i] * tempData[i];
7
    }
8
    energy[j] = tmp / sampleCount;
9
  }
refBuffer ist ein zweidimensionales array welches alle 12 generierten 
referenzbuffer enthält.
pcmData beinhaltet einen Beispielframe meiner Testdateien
in tempData werden die ergebnise der Addition gespeichert
energy ist ein array welches die errechnete Energie für jeden 
referenzfall speichert.

Nach meinem Verständnis ist das genau die Vorgehensweise die du 
beschrieben hast, und es macht so auch Sinn denke ich ;) Allerdings 
bekomme ich bei meinen Versuchen nicht immer eine Korrekte Lösung. Als 
Eingabesignale benutze ich im Moment noch saubere generierte Frequenzen 
z.B. 164.81Hz (E) und 146.83Hz (D)

Fällt dir oder sonst jemandem ein Fehler auf??

von Kai G. (runtimeterror)


Lesenswert?

Ich verwende meist

f(i) = 440.0 * 2 ^ (i / 12)

was auch in etwa deiner Formel entspricht. i = 0 liefert damit den 
Kammerton A'. Verwende mal 55.0 Hz oder 110.0 als untere Grenze. Ist 
dann zwar ein A, aber sonst hat es nur Vorteile.

Ich hatte jetzt noch nicht allzu viel Zeit mir das anzusehen, aber ein 
paar Sachen kommen mir komisch vor:
- Wo wird refBuffer befüllt?
- Wofür befüllst du tempData?
Der Ansatz scheint aber mit meiner Beschreibung übereinzustimmen.

Finde wahrscheinlich erst am Donnerstag wieder Zeit hier nochmal 
reinzusehen, sorry.

Schöne Grüße

Kai

von Paul (Gast)


Lesenswert?

- Wo wird der refBuffer befüllt?
Den codeabschnitt habe ich vergessen:
1
// Funktion generiert Frequenzen und speichert sie in *dataBuffer
2
void generateFrequence(float freq, float amp, float phase, double *dataBuffer, int frameLength) {
3
  double cnt=0.0f;
4
  register float x=freq*3.1416f/(float)44100;
5
  for(int i = 0;cnt < frameLength; cnt+=1.0f, i++) {
6
    dataBuffer[i] = amp*sin(x*cnt)+127;
7
  }
8
}
9
10
....
11
// Init Buffer
12
for(int i=0; i<12; i++)
13
  refBuffer[i] = (double*)malloc(sampleCount*sizeof(double));
14
15
// Die Berechnung der Halbtöne
16
float oktave = 110.0f; // in hz Ton: A
17
float halbton[12];
18
float factor = pow(2.0f, 1.0f/12.0f);
19
for(int i= 0; i< 12; i++) {
20
  halbton[i] = oktave * pow(factor, i+1); // calculate reference frequencies in hz
21
  // füllt den refBuffer
22
  generateFrequence(halbton[i], 8000.0f, 0.0f, refBuffer[i], sampleCount);
23
}

Nach dieser Schleife habe ich ein array was dieser Tonfolge entsprechen 
sollte:
1
  TONE_B    =  0,  // 1. Halbton
2
  TONE_H    =  1,  // 2. Halbton
3
  TONE_C    =  2,  // 3. Halbton
4
  TONE_CIS  =  3,  // 4. Halbton
5
  TONE_D    =  4,  // 5. Halbton
6
  TONE_DIS  =  5,  // 6. Halbton
7
  TONE_E    =  6,  // 7. Halbton
8
  TONE_F    =  7,  // 8. Halbton
9
  TONE_FIS  =  8,  // 9. Halbton
10
  TONE_G    =  9,  // 10. Halbton
11
  TONE_GIS  =  10,  // 11. Halbton
12
  TONE_A    =  11  // 12. Halbton

- Wofür befüllst du tempData?
Da hast du allerdings recht, das war ziemlich sinnlos ;)
1
  for(int j = 0; j< 12; j++) {
2
    double tmp = 0;
3
    for(int i=0; i<sampleCount; i++) 
4
      tmp += (refBuffer[j][i] + pcmData[i]) * (refBuffer[j][i] + pcmData[i]); // Quadratsumme
5
6
    energy[j] = tmp / sampleCount;
7
  }
 so gehts auch.

Die Wahl des Kammertons als Oktave hat leider nichts an den Ergebnissen 
geändert.

Mir ist da eben noch was eingefallen was mich etwas stuzig gemacht hat..
Wie kann denn das verfahren eigentlich funktionieren wenn man ein 
Eingabesignal hat, was aber phasenverschoben ist? Also wenn wir 
Referenzsignale haben die nicht verschoben sind, aber das Eingangssignal 
ist um 1/2 frequenz verschoben. Wie kann dann das Verfahren trotzdem 
klappen?

von Paul (Gast)


Lesenswert?

Ich glaub meine generateFrequence funktion war fehlerhaft ;)

Ich habe sie jetzt so abgeändert:
1
void generateFrequence(float freq, float amp, float phase, double *dataBuffer, int frameLength) {
2
  double cnt=0.0f;
3
  register float x=freq*3.1416f/(float)44100;
4
  for(int i = 0;cnt < frameLength; cnt+=1.0f, i++) {
5
    dataBuffer[i] = sin(cnt /(44100.0f/freq) * 2.0f * 3.1415f) * amp;
6
  }
7
}

Dann habe ich ausführlich getestet indem ich verschiedene Frequenzen auf 
verschiedene Oktaven gegengetestet habe:
1
Testton                Oktave 55hz            Oktave 110hz            Oktave 220hz
2
--------------------------------------------------------------------------------------------------
3
- ton_e_clean_82.wav  - OK                   - Nein -> C             - Nein -> C
4
- ton_h_123.47.wav    - Nein -> g            - OK                    - Nein -> Cis
5
- ton_c_130.81.wav    - Nein -> gis          - OK                    - Nein -> H
6
- ton_d_146.83.wav    - Nein -> fis          - OK                    - Nein -> C
7
- ton_e_164.81.wav    - Nein -> fis          - OK                    - Nein -> B
8
- ton_f_174.61.wav    - Nein -> gis          - OK                    - Nein -> H
9
- ton_g_196.00.wav    - Nein -> gis          - OK                    - Nein -> H
10
- ton_a_220.00.wav    - Nein -> gis + e      - OK                    - Nein -> H
11
- ton_h_246.94.wav    - Nein -> cis und fis  - Nein - A              - OK
12
- 440hz.wav           - OK                   - Konflikt -> A und Dis - OK

Ich vermute die Ergebnise sind so wie sie sein sollen oder? Die 
Frequenzen zwischen den Oktaven werden richtig erkannt, die anderen 
nicht. Die frage ist dann allerdings, wie ich dann JEDEN denkbaren Ton 
herausfinden kann, den ein Mensch singen könnte, ohne zu wissen in 
welchem Frequenzbereich gesungen wird? Muss ich in dem Fall wirklich 
referenz Buffer für alle denkbaren Oktaven erstellen?

von Kai G. (runtimeterror)


Lesenswert?

>Muss ich in dem Fall wirklich
>referenz Buffer für alle denkbaren Oktaven erstellen?

Nein, die 55 Hz-Oktave müsste bei dir bessere Treffer erzielen. Sofern 
die Oktave korrekt gewählt ist und der Messintervall lang genug, 
solltest du nahezu eine 100%-Quote erzielen.

Bei obertonreichen Klängen (wie z.B. der menschlichen Stimme) müsste 
auch eine zu hoch gewählte Oktave noch brauchbare Ergebnisse liefern. 
Beim Sinus werden die Ergebnisse nicht so gut. Sägezahn oder Rechteck 
sollten als Testsignal besser geeignet sein, da sie ein Obertonspektrum 
besitzen.

Eine Fensterung (z.B. mit f(x) = (1 + cos(x)) * 0.5 mit x := [-PI;+PI]) 
dürfte die Messung zusätzlich verbessern.

Zur Not schau dich noch mal bei anderen Verfahren um - ich habe im 
Moment nicht so super viel Zeit und will dich damit nicht hängen lassen 
:)

von Kai G. (runtimeterror)


Lesenswert?

Ach ja, wenn's nicht wirklich genau sein muss: Tiefpassfiltern und 
Nulldurchgänge zählen. Danach Taste Auf der Klaviatur zuordnen und 
Ausreißer eliminieren.

von Paul (Gast)


Lesenswert?

Mh dann ist das in der Tat seltsam... bzw. ich müsste noch irgendwo 
einen Fehler haben den ich übersehen habe. Denn wenn ich die Oktave bei 
55hz wähle bekomme ich bei meinen Testfällen immer falsche Werte, es sei 
denn sie liegen zwischen 55hz und 110 hz. Auch eine Sawtooth funktion 
ändert daran nichts...

Ich will dich auch garnicht von deiner Arbeit abhalten, danke das du 
trotzdem hilfst sofern das zeitlich geht :)
Wenn du das schonmal so in der Art implementiert hast, wäre es möglich 
mir deinen source (bzw. relevanten teil) davon zur Verfügung zu stellen? 
Vielleicht finde ich meinen Fehler ja dann noch selber.

von Kai G. (runtimeterror)


Lesenswert?

>Mir ist da eben noch was eingefallen was mich etwas stuzig gemacht hat..
>Wie kann denn das verfahren eigentlich funktionieren wenn man ein
>Eingabesignal hat, was aber phasenverschoben ist? Also wenn wir
>Referenzsignale haben die nicht verschoben sind, aber das Eingangssignal
>ist um 1/2 frequenz verschoben. Wie kann dann das Verfahren trotzdem
>klappen?

Keine Sorge, das geht :)
Wie gesagt wird im Buffer eine stehende Welle erzeugt. Welche Phase die 
am Ende hat ist unbekannt, aber wir bestimmen ja eh nur den 
Energiegehalt.

>Wenn du das schonmal so in der Art implementiert hast, wäre es möglich
>mir deinen source (bzw. relevanten teil) davon zur Verfügung zu stellen?
>Vielleicht finde ich meinen Fehler ja dann noch selber.

Leider nein - ich entwickle meine Algorithmen gerne in QuickBasic 4.0 - 
kaum Overhead, einfach drauflostippen und immer noch recht fix. Leider 
hat die Version meinen Quelltext gefressen (QB speichert per default 
Binaries) :((

Ich schreib das nochmal in Java nach - die Visualisierung ist zwar 
aufwändiger, aber dafür muss ich das danach nicht nochmal schreiben. 
Reicht dir erstmal eine Implementierung mit float-Werten?

von Paul (Gast)


Lesenswert?

- Ich schreib das nochmal in Java nach - die Visualisierung ist zwar
- aufwändiger, aber dafür muss ich das danach nicht nochmal schreiben.
- Reicht dir erstmal eine Implementierung mit float-Werten?

Ja klar das reicht, es geht ja nur darum das ich dann hoffentlich 
rausfinde was ich falsch mache ;) In andere Datentypen umwandeln sollte 
dann das kleinste Problem sein.

Ist echt etwas deprimierend wenn man so nette Hilfe bekommt, die methode 
auch noch versteht, aber dann irgendwas nicht klappt weil ich vermutlich 
nen total banalen fehler gemacht habe ;) Naja... da muss man durch :)

Da fällt mir ein, ich könnte mich ja eigentlich auch mal hier 
registrieren ;)

von Paul R. (zerd)


Lesenswert?

So jetzt gibts mich auch offiziell...
Ich begeb mich dann mal weiter auf fehlersuche :-|

von Kai G. (runtimeterror)


Lesenswert?

Aus Wikipedia (http://de.wikipedia.org/wiki/Menschliche_Stimme):
>Die Tonhöhe des Grundtons der menschlichen Stimme liegt für die männliche >Stimme 
bei etwa 125 Hz, für die weibliche bei etwa 250 Hz. Kleine Kinder >haben eine 
Tonlage um 440 Hz. Ursache dieser Unterschiede ist die >unterschiedliche Größe des 
Kehlkopfes und damit der Länge der Stimmbänder. >Der Stimmumfang beträgt 1,3 - 2,5 
Oktaven. Der Frequenzbereich der >menschlichen Stimme mit den Obertönen beträgt 
etwa 80 Hz bis 12 kHz. In >diesem Frequenzgang befinden sich Frequenzabschnitte, 
die für die >Sprachverständlichkeit, die Betonung der Vokale und Konsonanten sowie 
>Brillanz und Wärme eine Rolle spielen.

110 Hz als Untergrenze wäre meiner Meinung nach ideal.
Bei einem Stimmumfang von 2,5 Oktaven erhalten wir 622 Hz als 
Obergrenze. Also würde ich alles über 1 kHz per Tiefpass wegschneiden. 
Um das Datenvolumen zu verringen kann man auch einfach downsamplen, aber 
dadurch werden auch die Buffer kürzer. Wenn die zu kurz werden entstehen 
erhebliche Fehler bei der Längenbestimmung und die Testfrequenzen werden 
nicht mehr sauber getroffen da die Buffer ja nur ganzzahlige Längen 
besitzen.

Ein Trick ist auch die Bufferlänge konstant zu wählen und das 
Originalsignal mit unterschiedlichen Sample-Raten einzulesen. Als 
Bufferlänge empfehlt sich ein Wert, bei dem möglichlichst viele Obertöne 
mit ganzzahligen Wellenlängen angegeben werden können: Um die Obertöne 
1, 2, 3, 4, 5, 6 darzustellen braucht man die Primfaktoren 2, 2, 3, 5 
und erhält eine Bufferlänge von
2*2*3*5*n = 60*n
(44100 besteht übrigens aus den Primfaktoren 2*2*3*3*5*5*7*7=210*210)

... ich denke mal laut weiter ...

Zu den unterschiedlich großen Buffern:
1
s // Sample rate
2
f1 = x // Testfrequenz
3
f2 = f1 * 2 ^ 1/12 // Testfrequenz um einen Halbton erhöht
4
L1 = s / f1 // Länge des Buffers für die Testfrequenz
5
L2 = s / f2 // Länge des Buffers für die erhöhte Testfrequenz
6
k = L1 - L2 = s / f2 - s / f1 // Längenunterschied zwischen zwei Buffern
7
s = k * f1 * f2 / (f2 - f1) = k * f1 / (1 - f1 / f2)
8
  = k * f1 / (1 - 2 ^ -1/12)
9
  = k * f1 * 17,817153745105767553490105576143 (ungefähr)
- Angenommen, die oberste zu scannende Frequenz ist 220 Hz
- Angenommen, die Bufferlänge zweier Halbtöne soll sich um mindestens 6 
Samples in der Länge unterscheiden
s = 6*220 Hz*17,82 = 23519 Hz
Das Originalsignal muss also mit mindestens 23519 Hz abgetastet werden - 
das ist mehr als ich dachte. Die 12 Buffer sind also zwischen 107 (220 
Hz) und 213 (110 Hz) Samples lang. Das wiederum sieht ok aus.

von Kai G. (runtimeterror)


Angehängte Dateien:

Lesenswert?

Habe dir mal auf die Schnelle mal was zusammengebastelt.

Screenshot und Erklärung nach der nächsten Maus... bzw. im nächsten Post 
;)

von Kai G. (runtimeterror)


Angehängte Dateien:

Lesenswert?

Das Programm analysiert ein Testsignal mit dem oben beschriebenen 
Verfahren.

Das Testsignal ist ein mit Obertönen angereicherter Sinus, dessen 
Frequenz 6 Halbtöne über der Basisfrequenz der Testoktave liegt. Nach 
0,5 Sekunden wird die Tonhöhe um 3 Halbtöne angehoben. Das Gesamtsignal 
ist 1 s lang.

Die gelben Graphen auf der linken Seite zeigen den Inhalt der Buffer am 
Ende der Analyse an. Zeile 10 zeigt korrekter Weise genau eine Periode 
des Testsignals an.

Die Grünen Diagramme daneben zeigen den Energiegehalt der Buffer nach 
jedem Bufferdurchlauf an. Der kürzeste Buffer wird in einer Sekunde 
natürlich öfters durchlaufen als der längste und liefert mehr Messwerte.

Interessant ist der Parameter STRENGTH. Mit dem kannst du festlegen,
wie dick das Originalsignal aufgetragen wird . 0.0 Bedeutet der Inhalt 
des Buffers wird nicht überschrieben; 1.0 überschreibt den Buffer 
komplett; 0.5 legt im Buffer das arithmetische Mittel vom alten und dem 
neuen Wert ab. Kleinere Werte verbessern die Genauigkeit und 
verschlechtern das Zeitverhalten und vice versa.

Schau mal, ob dir das schon weiterhilft... wenn ich Lust habe und es dir 
hilft kommentier ich den Code noch nach ;)

schöne Grüße
Kai

von Kai G. (runtimeterror)


Angehängte Dateien:

Lesenswert?

So, jetzt noch mal was näher an der Realität:
- Eingangssignal ist jetzt ein Monotones "a", 1 Sekunde, 44100 Hz, 8 bit 
mono
- Den Bufferinhalt habe ich für die Darstellung auf eine feste Breite 
skaliert. Der Oberste Buffer ist immer noch der längste und entspricht 
der Startnote der Oktave. Die Buffer darunter entsprechen den 
aufsteigenden Halbtönen. Der letzte Buffer ist genau eine Oktave Höher 
als der erste. Er dient mir nur zur Kontrolle und muss normaler Weise 
nicht berechnet werden.
- Die Energiepegel der Buffer werden jetzt zeitlich deutlich feiner 
aufgelöst (Es ist nun eine kontinuierliche Abfrage nach jedem Sample 
möglich). Werte, die untereinander dargestellt werden, wurden auch zum 
selben Zeitpunkt gemessen.

(Bild im nächsten Post)

Jetzt zeigen sich auch die Schwächen des Verfahrens: Ich habe den 
Einfluss der Obertöne unterschätzt. Insbesondere wenn man eine Oktave zu 
niedrig misst (stell das Programm mal auf BASE_FREQUENCY = 30 Hz ein) 
wird neben der korrekten Note auch die Note die 7 Halbtöne darunter 
liegt stark betont. Ich habe den Effekt ein wenig dadurch gemildert, 
dass die die eingelesene WAV-Datei durch einen starken Tiefpass läuft. 
Die Obertöne werden hierdurch stärker gedämpft als der Grundton.

Das mit den sieben Halbtönen ergibt sich aus dem Frequenzverhältnis von
2 ^ 7/12 = 1,498 ~= 1,5
Solange wir in der korrekten Oktave messen ist das kein Problem. Aus 
Sicht der Oktave darunter lässt sich aber auch ein Halbtonabstand von 7 
+ 12 = 19 interpretieren:
2 ^ 19/12 = 2,9966 ~= 3
Und bei einem ganzzahligen Verhältnis bildet sich dort auch eine 
stehende Welle :(

Vielleicht ist eine abgespeckte Fourier-Analyse doch sinnvoller...

von Kai G. (runtimeterror)


Angehängte Dateien:

Lesenswert?

Hier noch die zum Programm gehörige Ausgabe.

von Paul R. (zerd)


Lesenswert?

Wow, danke! Das hilft mir sicher weiter!! :) Ich werde es mir jetzt mal 
genauer anschauen. Kommentieren brauchst du denke ich nicht extra, das 
dürfte ich so nachvollziehen können, Java ist mir geläufig :)

Sorry das ich nicht eher antworten konnte, aber über Ostern habe ich den 
Rechner mal aus gelassen :)

Eine Basis Frequenz von 30hz ist nicht realistisch bei einem Spiel wie 
Singstar, deshalb denke ich kann man so einen Grenzfall durchaus außen 
vorlassen oder?

von Kai G. (runtimeterror)


Lesenswert?

>Sorry das ich nicht eher antworten konnte, aber über Ostern habe ich den
>Rechner mal aus gelassen :)

dzdzdz... ;)

>Eine Basis Frequenz von 30hz ist nicht realistisch bei einem Spiel wie
>Singstar, deshalb denke ich kann man so einen Grenzfall durchaus außen
>vorlassen oder?

Leider nein... das Problem besteht auch, wenn man zwei Oktaven höher 
singt und zwei Oktaven höher misst.

Spiel einfach mal mit rum... ich hoffe, du hast die nötige Java-Version 
da...

Siehe auch: Beitrag "Re: Frequenz über Mikrofon einlesen ATmega16 oder 32"

von Paul R. (zerd)


Angehängte Dateien:

Lesenswert?

Ich hab es jetzt nochmal mit dem (jetzt etwas überarbeiteten) FFT Ansatz 
versucht und erhalte bei reinen Tönen auch eine 100% richtige 
Trefferquote.

Ich suche nach der FFT die dominante Frequenz im real array des 
Ergebnisses. Allerdings komme ich z.B. bei einem von einem Metronom 
generierten Ton den ich über das Mikro aufgenommen habe nicht auf das 
erwartete Ergebnis... Hast du eine Idee woher das kommen kann? Wie 
gesagt, alle reinen Töne werden gut erkannt.

Im anhang ist der Ton der nicht erkannt wird.

von Kai G. (runtimeterror)


Lesenswert?

Ein Metronom? Kenne das nur als Taktgeber für's Musizieren :)

Habe mir den Ton mal angehört - der ist extrem Obertonreich und ich 
tippe, dass der Grundton verhältnismäßig leise ist... um zu wissen was 
da schief geht müsstest du mir sagen, was du unter einem "etwas 
überarbeitetem FFT-Ansatz" verstehst.

von Paul R. (zerd)


Lesenswert?

Na gut, ich korrigiere... ein Tongenerator der zusammen mit einem 
Metronom in einem gerät agiert :-D

Die Aussage hatte nichts mit der Funktionsweise des FFT zu tun, sondern 
nur mit meiner Implementierung ;). Ich führe eine ganz normale FFT 
analyse durch und betrachte dabei 8096 byte. Wenn ich die dominante 
frequenz daraus gefunden habe berechne ich daraus den Ton...  Vor der 
FFT wende ich die Hamming-Fensterfunktion an um das Signal ein wenig zu 
glätten, ich hatte gehofft das hilft etwas ;)

von Kai G. (runtimeterror)


Lesenswert?

Lass mich raten... die ermittelte Frequenz ist zu hoch :)

Das Problem bei dem Prüfton ist, dass die Obertöne eine weitaus höhere 
Amplitude besitzen als der Grundton. Du ermittelst mit deinem Verfahren 
nur die präsenteste Frequenz und nicht den Grundton. Du könntest 
versuchen den ggT auf den lautesten fünf Frequenzen bestimmen - das 
ergäbe bei entsprechender Fehlertoleranz ziemlich gut den Grundton... 
glaub mir, das macht keinen Spaß :)

von Paul R. (zerd)


Lesenswert?

> Das Problem bei dem Prüfton ist, dass die Obertöne eine weitaus höhere
> Amplitude besitzen als der Grundton. Du ermittelst mit deinem Verfahren
> nur die präsenteste Frequenz und nicht den Grundton. Du könntest
> versuchen den ggT auf den lautesten fünf Frequenzen bestimmen - das
> ergäbe bei entsprechender Fehlertoleranz ziemlich gut den Grundton...
> glaub mir, das macht keinen Spaß :)

Die Frage die sich mir dann natürlich als nächstes stellt (bevor ich 
noch den ggT berechne ;) ), ist ob so ein Ton (oder besser gesagt ein 
Ton mit so starken Obertönen das der Grundton verdeckt wird) überhaupt 
in einer menschlichen Stimme vorkommen kann? Ich habe bisher nur 
generierte Töne getestet, entweder die reinen Töne aus dem 
Frequenzgenerator, oder Töne aufgenommen aus dem Tongenerator.

von Kai G. (runtimeterror)


Lesenswert?

Ich würde behaupten, dass das schon vorkommt.

Aus http://www.obertoene.de/de/obertonmusik-1.pl
"Das Gehirn kann aus den hörbaren Obertönen den Grundton zurückrechnen"
Siehe auch "Residualton" und http://de.wikipedia.org/wiki/Obertongesang

Teste einfach mal deine Stimme durch, ob du das schaffst :)

von Paul R. (zerd)


Lesenswert?

Ich werde es mal testen, allerdings denke ich, wenn ich mal wieder zu 
dem eigentlichen Singstar-Gedanken zurück komme, das Obertongesang 
wahrscheinlich in den Gängigen Songs seltener zu hören ist ;)

von Kai G. (runtimeterror)


Lesenswert?

Hi, wollte mal fragen, ob du mit dem Problem weitergekommen bist.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.