Autor Beitrag
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Fr 13.01.12 19:14 
Hallo,

dann frag ich doch mal :roll:

Also: ein Progamm benutzt waveIn und waveOut. Dazu braucht man bekannterweise einen gewissen Buffer (hier: Ringpuffer), damit keine Aussetzer auftreten.

Bei meinen Testsystemen sind das unabhängig von der Samplingrate 42ms bei der Ausgabe und 23ms bei der Aufnahme. Das ist Zufall und natürlich Hardware- und Treiberabhängig.

Also: wie komm ich an das Minimum? Probiert hab ich von magic numbers, Statistik über Regler und Timing schon alles, eher durchwachsener Erfolg.
Wie könnte man das noch lösen? Mir gehen langsam die Ideen aus, und ich will eigentlich nicht was großes nehmen und dafür mit Latenz bezahlen.

Alternativ: wie bestimme ich, ob ein Buffer Underrun aufgetreten ist? Dnn könnte der sich auch selber kalibrieren.


Danke für alle Ideen,
Martok

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Fr 13.01.12 22:12 
user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
Hallo,

dann frag ich doch mal :roll:

?

Wie auch immer: Wieso musst du so dicht am Limit sein? Du kannst nur schwer im Voraus wissen, was der User mit dem System macht. Möglicherweise trinkt er 10 Minuten Kaffee und plötzlich öffnet er ein CPU-Intensives Programm. Wie willst du das im Voraus kalibrieren?

Im Notfall kannst du die Datendurchsatzrate messen - wenn ein Buffer verloren geht, sollte dieser zu tief sein. Wie man das direkt rausfindet, weiss ich leider nicht.
Martok Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Fr 13.01.12 22:59 
user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
dann frag ich doch mal :roll:

?
An dem Problem arbeite ich (mit monatelangen Lücken) seit ein paar Jahren und seit dieser Woche zusammen mit user profile iconFinnO. Und jetzt bin ich mit meinem Latein am Ende ;-)

user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
Du kannst nur schwer im Voraus wissen, was der User mit dem System macht. Möglicherweise trinkt er 10 Minuten Kaffee und plötzlich öffnet er ein CPU-Intensives Programm. Wie willst du das im Voraus kalibrieren?
Indem ich in die Readme schreibe, dass er das unterlassen soll. Und indem ich REALTIME_PRIORITY_CLASS verwende :P

user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
Wie auch immer: Wieso musst du so dicht am Limit sein?
Weil ich Latenzen minimieren muss. Und ja, ich weiß was Kernel Streaming ist, aber dazu gibt's nicht mal eine Header-Übersetzung und mir reichen 65ms (also 23+42) aus. Wenn ich sie denn bekomme ;)

user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
Im Notfall kannst du die Datendurchsatzrate messen - wenn ein Buffer verloren geht, sollte dieser zu tief sein. Wie man das direkt rausfindet, weiss ich leider nicht.
Ja, das Gleiche misst man auch direkt am Timing (Buffergröße/Rundenzeit=Durchsatzrate)- nur: das schwankt extrem. Wenn man für 42ms Buffer hat (101x20 Samples bei 48kS) schwankt die "Durchlaufzeit" einmal durch den Ring zwischen 40 und 43ms, und das ohne jeden Aussetzer. Und wenn dann mal ein Aussetzer kommt, liegt der nicht außerhalb dieses bereichs, und es gab auch keinen Trend vorher.


Was ich vergessen hab zu erwähnen: ich habe einen separaten Thread, der sich nur um das Device kümmert. Also keine Callbacks, einfach nur eine Endlosschleife, die guckt ob Platz ist und sofort Daten abliefert.

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Sa 14.01.12 14:16 
Kann dir wohl nicht helfen. Allenfalls ein Echtzeitsystem verwenden oder benutzerkonfigurierbar machen.
TomyN
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 32
Erhaltene Danke: 2

Win10
D5 Std., Turbo-Delphi (w32), Delphi 2010
BeitragVerfasst: Di 17.01.12 10:19 
Hi,

- warum nimmst du nicht ASIO?

- Wie viele Buffer hast du?

Verstehe ich das richtig, dass du einen Thread in RealTime laufen hast, der nur 'pollt' (in welchen Abständen?) und du hast bei 42ms Buffersize Aussetzer bei der Ausgabe?

Grüße

Tomy
Martok Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Di 17.01.12 16:21 
Hallo,
user profile iconTomyN hat folgendes geschrieben Zum zitierten Posting springen:
- warum nimmst du nicht ASIO?
Im Grunde einfach nur weil die waveOut-API einfacher zu bedienen ist. ASIO ist, selbst mit den Komponenten dazu die ich sogar schonmal getestet hab, irgendwie seltsam.

user profile iconTomyN hat folgendes geschrieben Zum zitierten Posting springen:
- Wie viele Buffer hast du?
Das ist genau die Frage ;)
Mit etwas experimentieren hab ich festgestellt, dass es bei gleicher Gesamtzeit stabiler ist, viele kleine als wenige große Buffer im Ring-Satz zu haben.
Aktuell sind das N * 20 Samples. N ist genau die gesuchte Größe.


user profile iconTomyN hat folgendes geschrieben Zum zitierten Posting springen:
Verstehe ich das richtig, dass du einen Thread in RealTime laufen hast, der nur 'pollt' (in welchen Abständen?) und du hast bei 42ms Buffersize Aussetzer bei der Ausgabe?

Im Grunde ja.

ausblenden Pseudocode
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
InitBuffers;
while true do begin
  Daten:= ReadFromPipe;
  Samples:= ConvertToFormat(Daten, OutputFormat);

  while (not Buffer.Fertig) do Sleep(1);  // [1]

  SchreibSamplesInBuffer;
  waveOutWrite(Buffer);
  Buffer:= Ringpuffer.Next;
end;

Realtime brauchts gar nicht zwingend, HIGH_PRIORITY_CLASS und THREAD_PRIORITY_HIGHEST reicht schon aus. Das dürfte IIRC eine BasePriority=15 ergeben, genauso wie auch die "andere Seite", also der Thread in wdmaud der das dann ausgibt (sagt der Process Explorer).

Dabei spielt es keine Rolle, ob ich ein CALLBACK_EVENT verwende und statt [1] zu nehme auf dieses WaitForSingleObject-e. Die Performance bzw. das Verhalten ist identisch.

Das funktioniert sehr flüssig, solange BUFFER_NUM * BUFFER_SAMPLES / SampleRate größer als 42ms ist. Drunter gibt's die typischen Buffer-Underrun-Aussetzer.

Bei 48kS sind das gut 2048 Samples insgesamt (103 * 20), aber die 42ms sind unabhängig von der Samplerate, gelten also sowohl für 48kS als auch z.B. für 22kS. Aber abhängig von der Hardware.


Für Recording hat sich das übrigens erledigt, wie ich festgestellt habe ist da die Latenz immer gleich, egal wie viel gebuffert wird (weil nämlich nur so viele Buffer gefüllt werden wie Daten kommen). Man kann also einfach "etwas großes" nehmen und nur sicherstellen dass keine Underruns auftreten.

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
TomyN
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 32
Erhaltene Danke: 2

Win10
D5 Std., Turbo-Delphi (w32), Delphi 2010
BeitragVerfasst: Di 17.01.12 16:35 
Hi,

ASIO ist eigentlich genauso schwierig, hat halt eine andere 'Denkweise'.
Ich bin auch immer auf der Suche nach gutem I/O Verhalten, da ich eine Audio-Messsoftware programmiere (www.take-sat.de).

Im Moment bin ich eigentlich mit ASIO sehr zufrieden, das einzige Problem ist, dass viele ASIO Treiber sich nicht ganz genau an die Spezifikation halten.

Ich bin gerade dabei, die ersten vorsichtigen Schritte in Richtung DirectKS Audio zu machen, dabei ist mir ein Dokument in die Hände gefallen, in dem microsoft sagt, dass man durch den KsMixer bei der Audioausgabe mit zusätzlich ca. 30 ms rechnen muss. Daher auch der Unterschied in der nötigen Puffergröße für die Aufnahme und die Wiedergabe.

Tomy
Martok Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Di 17.01.12 16:55 
Ja, das mit dem Mixer kann sein. Gelesen hatte ich das auch, aber an zwei verschiedenen Stellen die sich exakt widersprochen haben :P

Die Frage ist immer noch: wie kriege ich raus ob ein Underrun aufgetreten ist... es gibt kein Event, kein Callback, kein Flag, nix. Momentan hab ich das wirklich über Device Config Files gemacht, in denen der User manuell Werte einträgt, testet und irgendwann das passende hat. Aber schön ist was anderes...

Den Beispielcode in C++ im Abschnit "Kernel Streaming" kennst du dann ja vermutlich schon?


Audio auf Windows ist wirklich ein Krampf.

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
TomyN
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 32
Erhaltene Danke: 2

Win10
D5 Std., Turbo-Delphi (w32), Delphi 2010
BeitragVerfasst: Di 17.01.12 17:06 
Hi,

da bin ich grad dabei mich mit zu beschäftigen. Bei mir ist der Leidensdruck nicht so groß grad :-)
Das Problem ist, dass es ja kein 'klassischer' Buffer_Under_Run ist, denn das passiert ja auch, wenn definitiv genug Puffer da sind (man z.B. 10 Puffer zur Verfügung stellt).

Das Audiosystem von Windows ist für den normalen Desktopeinsatz gedacht, da hat es viele Vorteile (Integrierter Mischer, d.h. Systemsounds und Sounds der Anwendung werden gleichzeitig wiedergeben, das Datenformat wird angepasst etc). Man muss sich erstmal 'um nix scheissen', solange man mit großen Puffern arbeitet.

Wenn es in Richtung 'realtime audio' geht, dann ist meiner Meinung nach im Moment ASIO der beste Weg, gerade weil ja mit ASIO4ALL ein Weg zur Verfügung steht, (fast) alle Soundkarten mit einem ASIO Treiber 'nachzurüsten'.

Tomy

Für diesen Beitrag haben gedankt: Martok