naja das was die daw und die plugins halt machen müssen
audio samples mit hilfe von algorithmen berechnen(z.b. synth,sampler) / verändern(z.b. input des interfaces, wav in der daw...) und das auf basis von mehr oder weniger großen buffern in verschiedenen bereichen der software
das sind viele buffer und die wollen alle so klein wie möglich bleiben (sonst ist die latenz groß), damit der interfacetreiber für die ausgabe der neu berechneten samples im ausgabebuffer noch rechtzeitig -vor abschicken an die hardware- übertragen kann, da es ansonsten audio aussetzer gibt (knachser, kleine loops)
im groben kann ich den signallauf an einem beispiel erklären wenn ich eine gitarre am interface einstecke und über ein VST plugin (z.b. amplitube) den sound machen will und das ganze wieder über die kopfhörer hören möchte:
input am interface -> preamp -> A/D wandler (kleine latenz, aber kein samplebuffer)
A/D wandler -> interface hardware (z.B. mit DSP für effektberechnung usw..) dort gibt es den ersten buffer, der die kommunikation zwischen interface und rechner bus buffern soll - falls es kein pci/pcie bus ist, kann noch ein weiterer hardware/softwarelayer dazu kommen, der protokollbedingt einen weiteren buffer dazwischenstellt (USB/Firewire..)
das ist bis jetzt nur hardware und hat eigentlich nichts mit der cpu auslastung zu tun
der buffer im interface ist höchstens dann zu klein, wenn der systembus derart belastet werden würde, daß die daten mit einer größeren verzögerung, als die buffergröße ausgelegt wurde, abgenommen oder geschrieben werden würden.
nun gibt es den ersten softwarebuffer im treiber (genau den, der am interfacetreiber in form von samples eingestellt werden kann) der die eingangsdaten und ausgangsdaten aller interface kanäle an die applikationen (z.b. in form von asio - was den betriebssystem audioteil umgeht) und betriebssystem (z.b. WDM) bereitstellt
da der treiber in einer höheren priorität läuft, als die DAW, wird der treiber selbst nur dann ausgebremst, wenn andere min gleichwertig eingestufte treiber die ausführung beeinträchtigen. dann kann dieser treiberbuffer seinserseits nicht mehr rechtzeitig an die hardware synchronisiert/übergeben werden. logischerweise wird der zeitpunkt des buffer-austausch von treiber zu interface (bufferswitch) vom interface aus getriggert, da es die clock für die samples beinhaltet.
bei jedem bufferswitch wird also das, was die daw über den asiotreiber auf den buffer geschrieben hat, an das interface weitergegeben und gleichzeitig die eingänge des interfaces auf die buffer der eingangskanäle - den bekommt dann die daw.
wenn nun also das input signal der gitarre im asio buffer des treibers nach einem bufferswitch anliegt, kann die daw ihn auslesen -> es wird hierbei der asiotreiber die bufferswitch funktion (callback) der daw aufrufen, die dann ihrerseits die eingangsbuffer und ausgangsbuffer ausliest/beschreibt
und genau hier ist der haken bei knachsern -> es muss der buffer vor dem nächsten bufferswitch, der von der interfaceclock angetriggert wird, von der daw beschrieben bzw ausgelesen werden.
ist die daw z.b. zu spät beim schreiben, wird der buffer einfach an das interface zum D/A wandeln abgegeben und zwar so wie er ist (es kann unterschiedlich implementiert sein, ob das nun ausgenullte buffer sind oder das drin bleibt, was beim letzten bufferswitch übertragen wurde)
bis hierhin war es im prinzip die kette hardware input -> A/D -> treiber -> asio bufferswitch -> treiber -> D/A
was nun die daw mit den buffern anfängt, liegt natürlich voll und ganz in ihrem ermessen
die einfachste bufferswitch funktion wäre: "lege inputbuffer auf outputbuffer"
damit wäre der kleinste minimalste aufwand getrieben, was eine audioengine mit hilfe des asiotreibers machen kann. im prinzip nur eingänge auf ausgänge routen.
beim alltagsbetrieb mit er daw ist das natürlich viel komplexer.. da gibt es evtl nochmal einen buffer, dann einen plugin-latenz ausgleich (in den meisten daws) - was im prinzip wieder in buffer pro routing darstellt - die aber alle unterschiedlich lang sind ( da sie von den pluginlatenzen abhängig sind)
es gibt also noch plugins mit latenzen -> also buffer, die allerdings weniger dazu da sind, um timings und datenübertragungen zu gewärleisten, sondern weil die internen algorithmen mehrere samples "sehen" müssen, um korrekt zu rechnen. beispiel: limiter mit lookahead -> es wird künstlich über einen kleinen samplebuffer die zeit verschoben, damit der limiter "vorher" reagieren kann, bevor es klippt und somit sanft reagiert.
um jetzt beim beispiel "amplitube als VST" zu bleiben sieht das je nach daw ungefär so aus:
hardware input -> A/D -> treiber -> asio bufferswitch -> mixer kanal routings -> insert effekte routing -> VST plugin eingangsbuffer(normal gleichgroß wie ASIO Buffer) -> eventueller VST plugin interner eingangsbuffer (=pluginlatenz) -> plugin algorithmus/logik (multithreading machbar) -> plugin interner ausgangsbuffer -> DAW mixer routing -> sonstige insert effekte, send routings usw -> summing -> asio bufferswich -> treiber -> D/A
der VST plugin buffer ist deshalb gleichgroß wie der asio buffer, weil die daten im prinzip in einem rutsch von Asio buffer durch das plugin durch, wieder zurück und wieder auf den asiobuffer geschrieben werden können - falls nirgends weitere pluginlatenzen oder pluginlatenz-ausgleich stattfindet, kann dies ohne weitere latenz innerhalb der daw [zwischen den bufferswitches] passieren
verkürzt gesagt, nimmt die daw also eingangs-samples über den asiobuffer entgegen (gesamte bufferlänge auf einmal), berechnet alles (schickt es durch plugins usw) und legt das ergebnis auf die ausgänge auf den asiobuffer - das passiert getriggert vom treiber, der wiederum vom interface getriggert wird.
genau diese kette kann nun daw intern über multithreading auf mehrere threads aufgeteilt werden - dadurch können wiederum die threads auf verschiedene kerne (sofern vorhanden) gelegt werden (bestimmt mitunter das OS, kann aber auch die DAW oder Plugins programmiertechnisch gesteuert werden)
in wie weit nun genau dieser signalpfad zwischen buffer übergabe parallelisiert werden kann, liegt ganz einfach an der struktur des routings
wenn ich nur einen kanal habe, der wie im beispiel von input - > vst -> output geroutet ist, kann ich ihn nicht parallelisierren, da ich nichts berechnen kann, was noch nicht da ist.
wenn ich aber zwei inputs habe und die auf getrennte kanäle verarbeite, wäre dies schon über zwei threads parallel abzuarbeiten.
das war aber nur grob beschrieben - in wirklichkeit gibt es ziemlich viel synchronisationspunkte, wo sich die daten der verschiedenen threads "treffen" - genau dort kann immer nur ein thread gleichzeitig drauf zugreifen und somit gibt es in der praxis einen overhead, durch multithreading
erst entsteht. dieser wird auch größer, umso mehr threads sich um "gemeinsam genutzte speicherbereiche" kümmern müssen - man muss nur mal überlegen, daß es nicht nur die audioengine gibt wovon ich die ganze zeit rede, sondern auch eine GUI, die mehr oder weniger in echtzeit diese daten anzeigen soll bzw beeinflussen. genau hier entstehen auch synchronisationspunkte, die wiederum die audioengine mehr oder weniger ausbremsen -> je nach implementierung und priorisierung. wenn man also träge "laggy" VU meter sieht, die dem audiosignal hinterhereilen, dann ist ganz einfach der thread für die gui niedriger priorisiert als der audiothread, der wichtiger ist.
sprich - die multithreading geschichte ist sozusagen eine wissenschaft für sich (selbst für entwickler) - da man es hocheffizient implementieren muss, damit es nicht zum flaschenhals durch sich selbst wird (overhead > nutzen multithreading)
um jetzt wieder auf die erde zurückzukommen (ich bin ja ziemlich ins detail gegangen und abgeschweift)
wenn der eine signalpfad, der zwingendermaßen über einen thread laufen MUSS, zuviel rechnzeit benötigt, bis er die asiobuffer wieder mit daten beschrieben hat, wird es aussetzer geben - und da kann kein anderer thread (und somit kern) helfen, die berechnung schneller durchzuführen.
wenn ich also grundsätzlich zu langsame kerne habe, aber viele, dann limitiert mir die singlethreadleistung die "länge/berechnungsdauer" meines (eines) signalpfades
sobald ich also nur einen einzigen kanal, der nicht parallelisierbar ist, in meinem routing habe, der für einen core zuviel ist, dann wird es zu einem buffer aussetzer kommen - egal ob der rest der kerne noch freiraum hätte.
anderstrum können mehrere kanäle parallel auf einem kern berechnet werden (wenn es zeitlich reicht) - das macht die daw sowieso und das betriebssystem unterstützt dies von natur aus schon. sonst könnte man ja nur soviel programme laufen lassen wie man kerne hat -> das nennt man multitasking -> das OS teilt im prinzip die threds selbstständig auf die kerne auf, und gibt ihnen immer wieder zeit zum rechnen und hält sie danach an -> es läuft also immer nur ein thread (oder 2 im falle HT) auf einem kern gleichzeitig
innerhalb der plugins kann wie geschrieben auch multithreading passieren -> skaliert aber auch nicht 100% pauschal.
auch hier gelten die limits "was nicht da ist - kann nicht berechnet werden"
und somit ist meiner meinung nach (für mich) ein potenter mehrkern proz mit großer singlethreadleistung besser als ein proz mit doppelt soviel kernen aber ein Ghz weniger, weil genau das eine felhende Ghz in dem einen nicht-parallelisierbaren-routing die buffer-underrun grenze nach unten verschiebt.
aber eigentlich anwendungsfall abhängig
hier noch ne kleine ältere lektüre von RME
http://www.rme-audio.de/techinfo/lola_lomo.htm