Ich habe die letzten Tage auf Linux/Alsa einen bare-bone Synthesizer
programmiert.
Mich interessierte eigentlich nur, was mit Alsa oder Jack an Low-Latency
möglich ist.
Ich war beruflich mit Audio-Entwicklung vor 15 Jahren beschäftigt,
allerdings mit DSP, insofern kenne ich mich mit der Theorie ganz gut
aus.
Mich erstaunte die Leistungsfähigkeit sehr, was mich überraschte, da ich
vorher LinuxSampler, ourorgan(Grandorgue) installierte und enttäuscht
war.
Im wesentlich habe ich 2 Worker-Threads. Der eine empfängt Midi-Daten
vom USB-Midi-Keyboard, der andere beschreibt die Audio-Buffer.
1
if((r=alsaPcmOpen((void**)&pcm_handle,sDevice,
2
sampleRate,channels,bufsize,2))<0){
3
printf("alsaPcmOpen error r=%d\n",r);
4
returnNULL;
5
}
6
data=(short*)malloc(p->bufsize);
7
while(1){
8
intpcmreturn;
9
10
//beschreiben von data[] mithilfe von Sinus-Tabellen
11
// im wesentlichen Sinuswellen mit Attack und Release
12
// (je nach dem welche Töne angeschlagen werden)
13
14
15
if((pcmreturn=snd_pcm_writei(pcm_handle,data,
16
buffSize))<0){
17
snd_pcm_prepare(pcm_handle);
18
fprintf(stderr,"<< Buffer Underrun >>\n");
19
usleep(1000);
20
//break;
21
}
22
}
Dabei sind beim normalen Linux-Netbook (Asus 2GB) Buffer bis zu 128
Samples (512 Byte) möglich und Latenz kaum spürbar.
Alle Berechnungen mache ich mit uint32_t, keine Floats/Doubles.
(die Sinustabelle schon vorher berechnet und die Werte im Bereich
[-0x7fff,0x7fff] abgespeichert.)
OK, da probierte ich den Raspberry-PI (512MB) mit dem neuesten Raspbian.
Die Performance war schon schlechter, die minimale Buffergröße ist 680
Samples (2720 Bytes).
Wenn man den Buffer kleiner macht, funktioniert schon eine Stimme nicht
mehr. Bei 2720 sind 10 stimmen zu je 3 Oszillatoren möglich.
Also durchaus ausbaufähig.
Und da wollte ich fragen, was man noch verbessern kann.
Gibt es eine bessere Distro für diesen Zweck.
Ich habe mal Emlid (Realtime Linux auf Raspbian-Grundlage) installiert,
ohne wesentlichen Verbesserungen.
Ist das Overclocken gefährlich, was zu Zerstörungen führen kann?
Bringt eine schnellere SD-Karte was (class 10 oder was)?
(mein Programm macht aber keine Datei-Zugriffe)
welche kernel hast du verglichen? 4.05 ist der aktuelle stable kernel.
Das kann ganz schön was ausmachen... vor allem bei ARM
Ggf. den kernel und dein Programm mit "-Ofast -march=native
-mtune=native" übersetzen und probieren.
Das sollte den Interrupt-Code gehörig beschleunigen und die sonst nicht
verwendeten Befehlssatzerweiterungen einschalten.
Wie beschreibst du deinen Buffer? memcpy aus der LibC sollte schneller
sein als einfach nur per for-Schleife (wobei hier -Ofast ... das
gehörig aufräumen sollte).
So ein ARM11 ist halt nicht das Speed-Wunder....Das sollte auf dem
Raspberry2 wesentlich besser laufen... (4 Cores die die Interrupts
bedienen können, SIMD erweiterung,...)
Deine SD-Karte spielt da keine Rolle...
73
Hans Wilhelm schrieb:> Wie beschreibst du deinen Buffer? memcpy aus der LibC sollte schneller> sein als einfach nur per for-Schleife
Da habe ich eine Hauptschleife. Pro angeschlagenen Ton und pro
Oszillator nehme ich die Phase und hole den Sinus-wert aus der Tabelle.
Die Werte werden addiert und ggf mit dem Envelop (Falls im Attack oder
Release) multipliziert.
Alle Phasen müssen dann mit dem jeweiligen Inkrement erhöht werden.
Schon einiges zum Rechnen, aber mit memcpy geht das natürlich nicht.
Aber wie schon geschrieben, bei etwas kleinerem Buffer habe ich schon
bei einer Taste Knacken (Buffer-Underruns) während bei der
Mindestbuffergröße 10 Töne (á 3 Oszillatoren) sauber und rund klingen.
> welche kernel hast du verglichen? 4.05 ist der aktuelle stable kernel.> Das kann ganz schön was ausmachen... vor allem bei ARM
Da habe ich den Standard Raspian-Kernel vom 5.5.2015.
Seit Kernel 2.4 habe ich keinen mehr kompiliert.
Macht man das als Cross-Compile am PC oder am Raspberry ?
> Das sollte auf dem Raspberry2 wesentlich besser laufen...
Tatsächlich ? Ich hätte gedacht, der Vorteil ist nur im größerem RAM.
Da könnte ich diesen ja bestellen ...
Gibt es andere solche MINI-PCs ?
Ein Realtime-Kernel hilft nur, wenn andere Software deiner in die Quere
kommt. Gegen schlechte Hardware oder Treiber hilft er nicht.
(Insbesondere Closed-Source-)WLAN-Treiber sind bekannt dafür, mit ihren
Interrupts die CPU auch mal länger lahm zu legen.
Probier mal, wie gut Jack läuft. Je nach Ergebnis musst du dir dann
davon etwas abschauen, oder kannst beruhigt sein.
Außer dem Rat, alles Unnötige aus dem Kernel rauszuschmeißen, sehe ich
da wenig Optionen. Und aus Sicht von Klangsynthese Unnötiges
rauszuschmeißen, heißt genau genommen, so ziemlich alles zu entfernen.
Immer dran denken: Das Multitasking ist der Echtzeit ihr Feind.
Wieviele Stimmequivalente kann der Synthie?
> Wieviele Stimmequivalente kann der Synthie?
Das ist ein bare-bone in ein paar Stunden zusammenprogrammiert.
Der gibt nur Sinus-Töne aus (pro Ton 3 unterschiedliche Oktavlagan)
und hat einen ganz einfachen ADSR-Envelop-Generator.
Ich wollte nur Latenz vergleichen zwischen Windows/ASIO und Linux/Alsa.
Raspberry war ursrünglich gar nicht geplant.
> Außer dem Rat, alles Unnötige aus dem Kernel rauszuschmeißen, sehe ich> da wenig Optionen.
Ja, das wird nicht einfach. menuconfig bietet bis zu 4000 Optionen?!
Ich habe das vor ein paar Jahren regelmäßig gemacht, um
Linux-Installationen zu haben, die ganz schnell hochfahren.
J. Wa. schrieb:> Das ist ein bare-bone in ein paar Stunden zusammenprogrammiert.
Ich dachte, das wird jetzt DER Linux-Synth überhaupt :-)
> Ja, das wird nicht einfach. menuconfig bietet bis zu 4000 Optionen?!
Als ich den letzten Linux-Kernel konfiguriert habe, was noch im letzten
Jahrtausend war!!! - gab es so 40 Optionen, glaube ich :-)
Ich habe irgendwie den Verdacht, dass Linux in all der Zeit nicht
wirklich schnell geworden sein könnte, eher schon, mächtig Fett
angesetzt hat. Liege ich richtig?
Mark Brandis schrieb:> J. Wa. schrieb:>> Ja, das wird nicht einfach. menuconfig bietet bis zu 4000 Optionen?!>> Ich habe das vor ein paar Jahren regelmäßig gemacht, um>> Linux-Installationen zu haben, die ganz schnell hochfahren.>> Vielleicht ein Fall für Tiny Core Linux?>> http://www.techrepublic.com/blog/diy-it-guy/diy-ti...
Gibt es für den Raspi auch schon zugeschnitten:
http://sourceforge.net/projects/minibian/
Wobei ich nicht glaube, dass mir das viel hilft. Die sind halt im
Footprint klein gehalten aber nicht in der Schnelligkeit
Ich habe nun meinen neuen Raspi (RPi 2) in Betrieb genommen.
(Ein sehr schönes Gerät mit 4 USB 2.0 Buchsen)
Das Verhalten ist aber unverändert.
Die geringste Buffergröße des normalen Betriebs liegt bei 2640 Bytes
(660 Samples), das entspricht 14,99 ms.
Ich vermute, dass der Scheduler die Tasks bei 15ms neu zuweist.
Wenn man bei sched.c irgendeine Konstante ändert, könnte es
funktionieren,
aber ich kenne mich an der Stelle nicht aus.
An mangelnder Rechenleistung liegt es nicht:
Bei 2640 kann ich noch 8-stimmig fehlerfrei spielen, beim nächst
kleinerem (2560 Bytes) geht 1 Stimme nicht.
Weiß jemand, wie man beim Scheduler die Task-Wechsel-Frequenz hochsetzt
?
Ich sollte noch sagen, dass das Öffnen des PCM-Devices auch bei
kleineren Buffergrößen funktioniert, wenn sie durch 80 teilbar sind,
2640, 2560, 2480 bis ca 1000.
Bei anderen meldet der Treiber einen Fehler (Error setting buffersize).
1120 funktioniert das Öffnen noch, aber snd_pcm_writei() meldet ständig
Buffer-Underruns, 960 und darunter öffnet das Device gar nicht mehr.
J. Wa. schrieb:> Ich habe mal Emlid (Realtime Linux auf Raspbian-Grundlage) installiert,> ohne wesentlichen Verbesserungen.
Hast du denn deinen Threads auch Realtime-Prioität gegeben und was sonst
noch so nötig ist, um die Realtime-Möglichkeiten auch zu nutzen?
"nice -20 ..." und so habe ich schon ausprobiert.
Mit sched_setscheduler(), /proc/sys/kernel/sched_rr_timeslice_ms usw
arbeite ich mich ein.
Wenn natürlich das Limit vom Treiber her kommt, dann hilft das
wahrscheinlich nichts.
Edit:
Realtime kenne ich nur von Embedded. Beruflich arbeite ich mit Osek-OS,
Free-RTOS usw.
Mit Linux habe ich in Sachen Realtime noch nichts gemacht.
J. Wa. schrieb:> "nice -20 ..." und so habe ich schon ausprobiert.
Stellt noch nicht auf Realtime-Priorität um, und der Scheduler wird
nicht angepaßt, aber solange nicht viel anderes läuft, sollte das auch
schon was bringen.
> Wenn natürlich das Limit vom Treiber her kommt, dann hilft das> wahrscheinlich nichts.
Allerdings. Ich hab noch nicht soviel mit dem Raspi gemacht, aber der
eingebaute Sound scheint da auch nicht so besonders gut zu sein. Mit
einem USB-Audio-Interface hab ich deutlich bessere Ergebnisse erzielt,
was die Latenzen betrifft.
Bisher habe ich mir um Nyquist-Limits keine Gedanken gemacht.
D.h. ich habe nur Sinus-Wellen ausgegeben.
Beim 61-Tasten Keyboard hat die höchste Note ca 2000Hz (Midi-Note 96),
bei 3 Oktaven drüber liege ich mit 16kHz noch unterhalb der Nyquist
Frequenz von 22050Hz.
Allerdings dachte ich mir schon, irgendwann andere Wellenformen zu
spielen, z.B. Dreieck, Sägezahn.
Rechnerisch ist ja das viel einfacher als sin().
Da lese ich in einem Buch, dass man das nicht darf. Alle Wellen müssen
als Überlagerung von Sinus-Oszillatoren erzeugt werden.
D.h. bei tiefen Tönen kann ein genaueres Rechteck erzeugt werden als bei
hohen Tönen, wo die Nyquist-Frequenz schon nach wenigen harmonischen
erreicht wird.
Ich kenne Nyquist nur von der Abtastung her (Tiefpassfilter
vorschalten), dass bei der synthestischen Wellenerzeugung es auch
beachtet werden muss, hätte ich nicht daran gedacht.
Wieso sollte man nicht auch nichtsinusförmige Wellen überlagern? Bei
meiner PLD Orgel mache ich das genau so. Das ergibt eben rechteckigere
Wellen.
J. Wa. schrieb:> D.h. bei tiefen Tönen kann ein genaueres Rechteck erzeugt werden als bei> hohen Tönen, wo die Nyquist-Frequenz schon nach wenigen harmonischen> erreicht wird.
Sagen wir mal so: Die Steilheit ist limitiert und dies für alle
Rechtecke gleichermaßen.
Du brauchts im Übrigen in der Software keine echten Sinusoszillatoren,
um die Oberwellen zu machen, sondern nur eine Multiplikation mit
Offsetkorrektur:
http://www.96khz.org/oldpages/soundsynthesiswithwavemul.htm
Nach einigen Wochen Verzug (Poststreik) habe ich mein
USB-Audio-Interface erhalten und es am Raspberry eingesteckt.
Jetzt sind Buffer von 512 Bytes (2.9ms @ 44.1kHz) möglich.
Kaum Buffer-Underruns.
Ich vermute, dass die Latenz doch etwas höher ist als beim PC bei der
gleichen Buffergröße, d.h. dass beim USB-Device noch zusätzliche
Verzögerungen dazukommen, aber das ist sehr gering.
Die Audio-Qualität ist erheblich besser als das eingebaute Sounddevice.