Neu

Interessiert an einem Austausch zum Thema DSP-Entwicklung?

Interessiert an einem Austausch zum Thema DSP-Entwicklung?

  • Gar kein Interesse, ich mach lieber Musik

    Stimmen: 3 13,6%
  • Interesse schon, aber kein interesse an einem Austausch

    Stimmen: 2 9,1%
  • Spannendes Thema, auf jeden Fall

    Stimmen: 17 77,3%

  • Umfrageteilnehmer
    22
  • Diese Umfrage wird geschlossen: .
  • #31
Aktuell fade ich bei einer problematischen Änderung den Output kurz aus, führe die Änderung durch und fade dann wieder ein. Aber so wirklich zufriedenstellend ist das auch nicht, da man in diesem Zeitraum natürlich auch nichts mehr hört.

Aber jedes Audiosignal hat ja ohne Ende Nulldurchgänge. Anstatt also selbst einen mit Fade-In und -Out zu erzwingen, könntest du auch einfach einen solchen abwarten.
 
  • #32
Eine Frage ist ja, wie oder worüber man sich überhaupt sinnvoll austauschen kann.
Ich hatte ja mal an einem Softsynth gearbeitet:
Der basierte auf spektraler Synthese einschließlich Spectrum Squash/Stretch und bot verschiedene Verfahren zur Erzeugung von Unisono-Effekten/Texturen.
Dafür war zwar die MPE-Implementierung von JUCE die Basis, aber ich habe eine Menge eigenen Code implementiert wie z.B. spektrale Oszillatoren, diverse Verfahren zur Textur-Generierung, dazu Basis-Funktionalität wie kubische Spline-Interpolation, einen counter-basierten Pseudozufallszahlen-Generator uvm.
Wegen der mir eigenen Sprunghaftigkeit ruht das Ganze allerdings im Moment.
Frustriert hatten mich bei der Entwicklung letztlich die folgenden Punkte:
  • Ich wollte als Erweiterung der bestehenden Funktionalität auch noch spektrale Transformationen in Realtime einbauen, diese waren dann aber so rechenaufwendig, dass am Ende nur noch eine Stimme gleichzeitig gerendert werden konnte - also leider nicht praktisch einsetzbar.
  • Es sollte zur Ergänzung noch ein normales subtraktives Filter dazu, wofür ich das Ladder-Filter von JUCE genommen habe. Mit dieser Entscheidung war ich dann aber unglücklich, weil mich die Qualität des Filters nicht überzeugt hat.
  • Ich wollte bei der FFT auf double precision gehen, habe es aber bisher nicht geschafft.
    Dazu wollte ich den double precision PFFFT-Fork nehmen, habe ihn aber mit der LLVM/MSVC Toolchain nicht compilieren können.
    Mir fehlte dann leider die Kraft für den Versuch, komplett auf die MingGW-Toolchain zu gehen (also mit PFFFT, JUCE und meinem eigenen Projekt) und auch für CMake alles entsprechend anzupassen, oder aber den PFFFT-Fork mit LLVM/MSVC compilierbar zu machen.
  • Ich hatte es versäumt, frühzeitig ein Modulationssystem einzubauen, und nachdem ich dann schon zig Parameter hatte, wurde es schwierig, das nachträglich noch hinzuzufügen.
  • Trotz der in JUCE schon vorhandenen Widgets ist es mir nicht gelungen, eine vernünftige GUI aufzubauen.
Falls ich noch einmal in dem Vorhaben einsteige, würde ich von null anfangen und alles aus dem alten Projekt schrittweise übernehmen.
Zuerst müsste ich aber das Problem mit dem Umstieg auf double precision FFT lösen (davon verspreche ich mir viel, weil sehr viel durch FFT vorberechnet und bzw. aus den FFT-Koeffizienten abgeleitet und neu synthetisiert wird, und weil durch Oversampling die benötigten FFT-Frames noch einmal größer werden).
Diesmal würde ich auch von Anfang an das Modulationssystem anlegen und diesen Punkt nicht aufschieben.
Außerdem würde ich das JUCE Ladder Filter durch ein selbst implementiertes Zero-Delay Feedback-Filter ersetzen, müsste mich dafür aber erst in die Materie einlesen.
Bedenkenswert wäre auch, sich von der Idee zu lösen, ein komplettes Plugin zu realisieren, und stattdessen nur einen Oszillator für VCV Rack zu schaffen, wie schon mal jemand angeregt hatte, das würde die Aufgabe deutlich vereinfachen. Allerdings hat allein die Kombi aus Oszillator und Texturgenerator bereits zig Parameter, das lässt sich in einem herkömmlichen Modul kaum unterbringen.

Sollte jemand hier ähnliche Interessen haben oder mit ähnlichen Problemen kämpfen, dann wäre ich an einem Austausch sehr interessiert.
Das betrifft vor allem die Nutzung des PFFFT Double-Precision-Forks mit LLVM/MSVC und evtl. auch die anderen genannten Themen.
 
Zuletzt bearbeitet:
  • #33
Das könnte für manche Fälle tatsächlich ausreichen. Bei Puffern hast du allerdings die Gefahr einer Diskontinuität.

Beispiel Ringpuffer (Delay):
1767104450413.webp
Du stellt die Zeit von 2 auf 3 Sekunden ein. Die zwei Sekunden wurden bisher kontinuierlich beschrieben und wiedergegeben. Je nachdem, wo sich Write- und Read-Head gerade befinden, kann es zu Knacksern an Anfang und Ende des neuen roten Bereichs kommen. Nämlich dann, wenn der Read-Head sich vor dem Write-Head befinden. Welche Werte sich im roten Bereich befinden weiß man nicht. Extrem gesprochen, hast du im letzen Sample Vollausschlag und im ersten Sample des roten Bereichs eine 0, weil der Write-Head dort noch nicht war um das kontinuierliche Signal dort hineinzuschreiben. Das führt unweigerlich zu einem Knackser. Genau so am Ende.

Ich denke, dass es in diesem Fall Eingangs auf einen Fade-out auf 0 und am Ende auf den Wert des ersten Samples im Puffer hinauslaufen wird. Änderungen von wenigen Millisekunden sind aber trotzdem kritisch, weil man dann zu wenige Sample fürs Fade-in/-out hat. Für den Fall interpoliert man wohl am besten das letzte bekannte Sample auf das erste Sample im Puffer und schreibt das dann in den roten Bereich.

Oder man bewegt den Read-Head erst weiter, wenn der Write-Head vor dem Read-Head ist und stellt den Output mit Kurve auf 0. Das ist wahrscheinlich die einfachste Lösung.
 
  • #34
Aber jedes Audiosignal hat ja ohne Ende Nulldurchgänge. Anstatt also selbst einen mit Fade-In und -Out zu erzwingen, könntest du auch einfach einen solchen abwarten.
Das Probem bei diesem "Trick" ist, dass das Knacken nur scheinbar weg ist: Das Signal der neuen Parameter könnte z.B. im Umfeld dieser Stelle Werte weit vom Nulldurchgang entfernt haben.

Nicht nur ein Sprung im Zeitsignal wird zu einem Knack, sondern auch eine Diskontinuität in der 1. Ableitung (z.B. wenn ein Sinus stufenartig seine Frequenz ändert).

Diese scheinbar beiläufige "Problemchen" macht bei vielen PlugIns einen der großen Unterschiede zwischen analogem Vorbild und digitaler Simulation.

Nicht dass ich jetzt dafür eine gute Lösung anbieten könnte ...
(Cross-fading über z.B. 5ms ist weitgehend unhörbar, aber benötigt über 5ms das Berechnen von beiden Signalen gleichzeitig, also doppelten Rechenaufwand)
 
Zuletzt bearbeitet:
  • #35
Wofür ich allerdings noch keine elegante Lösung habe ist die Verzögerung von Parameter-Änderungen durch den Nutzer (also das Drehen am Poti). Gerade wenn es um Puffer geht (Größenänderung z. B.) kann man davon ausgehen, dass unerwünschtes Knistern gibt. Aktuell fade ich bei einer problematischen Änderung den Output kurz aus, führe die Änderung durch und fade dann wieder ein. Aber so wirklich zufriedenstellend ist das auch nicht, da man in diesem Zeitraum natürlich auch nichts mehr hört.
Kannst Du nicht in einem solchen Fall für eine gewisse Zeit vom alten Wert auf den neuen Zielwert des Parameters linear überblenden?
Und, solange dieses Überblenden läuft, evtl. nicht auf neue Parameter-Änderungen des Nutzers reagieren, sondern erst, wenn der letzte Zielwert erreicht ist.
(Kontinuierliches Nachführen mit Smoothing geht natürlich auch).
 
  • #36
Mir fehlte dann leider die Kraft für den Versuch, komplett auf die MingGW-Toolchain zu gehen
Ich vermute mal, dass du auf Windows arbeitest. UCRT64 ist eigentlich eine ziemlich einfache Umgebung.


Darauf baue ich auch für Windows. Ansonsten verstehe ich das. Architekturfehler rächen sich früher oder später immer. Und je später man anfängt, desto schwieriger wird's. Deswegen war meine erste Zeit auch geprägt von Nächten, in denen ich immer wieder alles gerade gezogen habe. Das Repo dazu willst du nicht sehen. Dafür bin ich jetzt allerdings wirklich sehr zufrieden.
 
  • hilfreich
M.i.a.u.: Turing
  • #37
Zielwert des Parameters linear überblenden
Das ist in der Parameter-Klasse sogar implementiert. Sowohl Werte- als auch Puffer-basiert. Aber das funktioniert halt nicht für alles. Zumal das auch noch maximal ineffizient ist. Was aber so lange keine Rolle spielt, wie man ausreichend CPU-Ressourcen hat. Bei meinem Supersaw-Synth für den Raspi3 kam es am Schluss allerdings wirklich auf jeden CPU-Zyklus an, so am Anschlag war der Raspi.

Aber vielleicht muss man das einfach auch akzeptieren. Ist halt so. Dann fallen halt Zyklen für Feature weg. Fällt mir aber häufig schwer.
 
  • #39
Oder man bewegt den Read-Head erst weiter, wenn der Write-Head vor dem Read-Head ist und stellt den Output mit Kurve auf 0. Das ist wahrscheinlich die einfachste Lösung.

Hm, spricht etwas gegen double buffering? Dann musst du dich nur um das richtige Timing beim Umschalten zwischen den beiden Puffern kümmern. Und gegebenenfalls Hysterese implementieren, um Parameter-Dauerfeuer durch Usereingaben abzufangen.
 
  • #40
Fies knacksende Boxenkiller sind es dagegen nicht
Diskontinuität kann halt bei allem auftreten, was in den Ausgabepuffer schreibt. So lange es nur ein Sample ist, ist es zwar unschön, aber nicht so gefährlich, denke ich.

Ich frage mich immer, was das in den 80/90ern bei der verfügbaren Hardware für krasse Hacker gewesen sein müssen, um dermaßen sauber zu implementieren.
Hm, spricht etwas gegen double buffering?
Du hast exakt dasselbe Problem. Mögliche Diskontinuität beim Switchen auf den anderen Puffer mit anderem Inhalt. Kannst du drehen und wenden wie du magst. ;-) Oder du erklärst das mit dem Timing etwas genauer. Vielleicht täusche ich mich ja.

Hysterese ist ja im Grunde nichts anderes als ein Filter. Da hast du unter Umständen dann zwar kleinere Sprünge, aber immer noch Sprünge. Kann gut gehen, muss es aber nicht. Was noch machbar wäre ist, dass der Parameterwechsel tatsächlich erst nach einer definierten Zeit durchgeführt wird. Z. B., wenn 100ms lang keine Werteänderung mehr stattgefunden hat. Für die Zeitmessung muss man sich aber wieder in den DSP-Prozess hängen. Alles andere ist ziemlich umständlich. Das wird wahrscheinlich auch der Weg sein, den ich wählen werden.

Kleine, lästige, aber leider wichtige Details bei Plugins. Eigentlich ja unwichtig, da ich niemals Geld damit verdienen will und werde.
 
  • #42
Oh, wir sind jetzt in der Nerdzone, also offiziell damit wohl Nerds. ;-)
Ich begnüge mich mit VS Codium auf Ubuntu. Claude nutze ich sehr viel als Dokumentationsgenerator, als mit Vorsicht zu genießenden Erklärbär und hauptsächlich für die Fehlersuche. Claude erkennt die Standardfehler sofort. Das ist ganz cool und hat mir schon viel Zeit und Mühe gespart. Erst vorhin wieder mit meinem Zufallszahlen-Generator, der leider aufgrund einer fehlerhaften Initialisierung statistisch zu Negativität tendierte.
 
  • #43
Du hast exakt dasselbe Problem. Mögliche Diskontinuität beim Switchen auf den anderen Puffer mit anderem Inhalt. Kannst du drehen und wenden wie du magst. ;-) Oder du erklärst das mit dem Timing etwas genauer. Vielleicht täusche ich mich ja.

Mir fallen da ein paar Sachen ein, aber die Universalstrategie gibt es nicht. Ist immer vom Kontext abhängig.

Ich geh mal davon aus, dass dein Ringpuffer von maximal 10 Sekunden irgendeinen tatsächlich nutzbaren Inhalt/Bereich mit Offset(Anfang) und Länge(Ende) per Zeiger kleinergleich 10 Sekunden beschreibt.

Da fiele mir dann ein, die zehn Sekunden grundsätzlich während einer Initialisierung bereits komplett voll zu schreiben und hinterher nur noch die beiden Zeiger zu ändern. Die neuen Zeigerpositionen (ein extra Array vielleicht?) müssen dann immer auf Nulldurchgänge zeigen. Damit kann man dann schon mal die Länge des (Teil-)Buffers sehr schnell ändern, ohne in den Puffer schreiben zu müssen. So könnte man quasi eine Wavetable erzeugen und dann durchmorphen, indem einfach nur die Zeiger geändert werden.

Will man nun den Inhalt des Ringpuffers ändern, zum Beispiel mit einem identischen Signal anderer Frequenz, dann holt man einen zweiten Ringpuffer dazu, füllt den komplett mit dem neuen Signal, sucht die Nulldurchgänge* und setzt die Pointer auf Offset(Anfang) und Länge(Ende) und schaltet dann um, sobald der alte Puffer sein Ende erreicht hat.

*Wenn die Frequenz des neuen Signals bekannt ist, kann man die Nulldurchgänge auch algorithmisch bestimmen, ohne den Pufferinhalt analysieren zu müssen.

Die Hysterese müsste dann halt der Leistungsfähigkeit der CPU entsprechend gewählt werden. Je schneller der Puffer im Hintergrund gefüllt werden kann, umso eher kann wieder getauscht werden und umso eher wird ne Usereingabe nicht mehr verworfen.
 
Zuletzt bearbeitet:
  • Daumen hoch
M.i.a.u.: Dagalos und _thomas_
  • #44
Hört sich verdammt kompliziert an, @2bit ;-)

Hier mal der Schwarm. Zusätzlich ist die Wolkengröße noch durch einen LFO moduliert. Ist teils etwas schwierig wahrnehmbar. Was wiederum mit der Verteilung der Grains im Stereofeld zu tun hat. Ein Haufen ist natürlich lauter (Summe vieler Grains) als ein hinterherlaufender Grain. Das spare ich mir dann für die Optimierung auf: Je weiter ein Grain vom Wolkenzentrum entfernt ist, desto lauter soll es werden. Aber erstmal kümmere ich mich um meinen Pufferknacksen. Nervt mich unsäglich...

Hier mal ein Beispiel (am besten natürlich mit Kopfhörern). Leider habe ich vergessen, das fortlaufende Mikro-Detunig zu aktivieren wie auch den Highpass etwas zu erhöhen. Das erhöht die Wahrnehmbarkeit des einzelnen Grains massiv. Aber ich denke, man kann es trotzdem erahnen. Ist Raw aufgenommen. Könnte leise sein.

Anhang anzeigen recording_0.wav

Hier mal das PD UI:

1767175531402.webp
Da geht schon was...
 
Zuletzt bearbeitet:
  • Daumen hoch
  • wunderbar
M.i.a.u.: Dagalos, Rolo, oli und 3 andere
  • #45
Ich arbeite viel mit variablen Delays. Hier sind ein paar meiner Erfahrungen:
Es gibt zwei Möglichkeiten, die Delayzeit durch Überblenden störungsfrei zu ändern. Entweder man macht zwei Lesevorgänge pro Sample, oder man macht zwei Schreibvorgänge pro Sample. Bei der ersten Variante werden gelesenen Werte von 2 Adressen (alt/neu) anteilig kombiniert, bei der zweiten ein zu schreibender Wert auf zwei Adressen (alt/neu) anteilig verteilt (wobei der nachlaufende Schreibvorgang ein akkumulierender ist). In beiden Fällen sollte die Überblenddauer dem Betrag der Differenz zwischen der alten und der neuen Delayzeit entsprechen. Während des Vorgangs sind weitere Delayzeitänderungen gesperrt.
Irgendwie bin ich mal darauf gekommen, dass es günstig ist, wenn ich beide Varianten kombiniere: Beim Verkürzen der Delayzeit nehme ich die erste Methode, beim Verlängern der Delayzeit nehme ich die zweite Methode.
Mittlerweile mache ich noch mehr als nur Delay mit dem Buffer, aber etwa so wie oben war mal der Grundgedanke.
 
  • Daumen hoch
M.i.a.u.: 2bit, amesser, _thomas_ und eine weitere Person
  • #46
Cool, genau solche Tipps finde ich spannend. Irgendwelche Elektroniktipps gibt es ja zuhauf, aber auf Deutsch über Audio DSP reden, dass ist selten finde ich, und auch schön mega nerdig.
 
  • Daumen hoch
M.i.a.u.: _thomas_
  • #47
Ich arbeite viel mit variablen Delays. Hier sind ein paar meiner Erfahrungen:
Es gibt zwei Möglichkeiten, die Delayzeit durch Überblenden störungsfrei zu ändern. Entweder man macht zwei Lesevorgänge pro Sample, oder man macht zwei Schreibvorgänge pro Sample. Bei der ersten Variante werden gelesenen Werte von 2 Adressen (alt/neu) anteilig kombiniert, bei der zweiten ein zu schreibender Wert auf zwei Adressen (alt/neu) anteilig verteilt (wobei der nachlaufende Schreibvorgang ein akkumulierender ist). In beiden Fällen sollte die Überblenddauer dem Betrag der Differenz zwischen der alten und der neuen Delayzeit entsprechen. Während des Vorgangs sind weitere Delayzeitänderungen gesperrt.
Irgendwie bin ich mal darauf gekommen, dass es günstig ist, wenn ich beide Varianten kombiniere: Beim Verkürzen der Delayzeit nehme ich die erste Methode, beim Verlängern der Delayzeit nehme ich die zweite Methode.
Mittlerweile mache ich noch mehr als nur Delay mit dem Buffer, aber etwa so wie oben war mal der Grundgedanke.
Warum interpolierst du nicht die Werte? Das würde doch auch gehen oder?
 
  • #50
Du stellt die Zeit von 2 auf 3 Sekunden ein. Die zwei Sekunden wurden bisher kontinuierlich beschrieben und wiedergegeben. Je nachdem, wo sich Write- und Read-Head gerade befinden, kann es zu Knacksern an Anfang und Ende des neuen roten Bereichs kommen. Nämlich dann, wenn der Read-Head sich vor dem Write-Head befinden. Welche Werte sich im roten Bereich befinden weiß man nicht. Extrem gesprochen, hast du im letzen Sample Vollausschlag und im ersten Sample des roten Bereichs eine 0, weil der Write-Head dort noch nicht war um das kontinuierliche Signal dort hineinzuschreiben. Das führt unweigerlich zu einem Knackser. Genau so am Ende
Du kannst auch die Sample Rate des Lese/Schreibkopfes gegeneinander verschieben, solange bis die gewünschte Zeitdifferenz erreicht wurde. So mache ich das bei meinem Delay Modul. Dort habe ich allerdings den Luxus, dass das sehr trivial ist, weil der Schreibkopf quasi direkt am ADC und der Lesekopf direkt am DAC hängt, da takte ich die beiden ADC/DAC jeweils unterschiedlich. In Software würde ich dann die Position des Lesekopfs im Ringpuffer in Fixpunkt speichern, z.B. Q16.8 die ersten 16 Bit ist die Position "n" im Ringpuffer, die weiteren 8 Bit dann die Überblendung zwischen Sample "n und n+1". Während der Zeitänderung läuft der Lesekopf dann z.B. mit Samplerate "1 + 1/256" oder "1 - 1/256" während der Schreibkopf immer mit "1" läuft.
 
  • Daumen hoch
M.i.a.u.: _thomas_ und 2bit
  • #52
Du kannst auch die Sample Rate des Lese/Schreibkopfes gegeneinander verschieben, solange bis die gewünschte Zeitdifferenz erreicht wurde. […]
Das ergibt einen Pitch-Shift Effekt, der sehr interessant sein kann. Ich nutze das in besonderer Form, nämlich mit verdoppelter Geschwindigkeit des Lese- oder Schreibkopfes (wieder je nachdem, ob verkürzt oder verlängert wird). Das schiebt dann um 1 Oktave.
 
  • Daumen hoch
M.i.a.u.: amesser
  • #53
Du musst erst hören, was eine mathematische Formel machen soll? Ich dachte man entscheidet sich immer für die, die man braucht um ein bestimmtes Ergebnis zu erreichen. :)
Hmm, du weist also beim Anblick einer mathematische Formel welchen Sound die erzeugt? Respekt!
Wenn Du erklärst, was das überhaupt sein soll, ist da sicher noch viel Platz dafür.

Mit was fangen wir an, mit Atari? ;)
Irgendwie bin ich zu doof das vollständig inklusive meiner Aussage zu zitieren. Egal:

Es gibt Algorithmen, die in Software sehr einfach sind und einem beim FPGA Kopfzerbrechen bereiten oder sehr viele Resourcen brauchen (z.B. Modulationsmatrizen) und umgekehrt. Im FPGA läuft alles ein bischen anders, da steckt man mehr Zeit in die Konzept für die Umsetzung und wählt dann halt auch eventuell andere Algorithmen als man in Software wählen würde. Eine einfache IIR Filter Stufe braucht z.B. selbst auf einer ARM CPU mit NEON 4 Takte / Sample, bei einem entsprechenden FIR benötigt es viel mehr Taps und damit noch viel mehr Takte / Sample. Dafür ist der IIR viel empfindlicher gegenüber Rechenungenauigkeiten. D.h. auf einer CPU mit Floating Point wäre der IIR wohl die bessere Wahl, auf einem FPGA oder einer CPU ohne FPU wohl eher der FIR. Von der Performance ist es beim FPGA bei beiden gleich, immer 1 Takt / Sample

Bei meinem FM Synth-Projekt takte ich aktuelle den FPGA mit gerade mal ~34MHz. Das reicht für ~160kHz Sample-Rate, 64 Voices a 4 Operatoren (Also 256 Wavetable-Oszillatoren, 256 Envelopes) Einen Leistungsengpass gibt es per Definition nie, weil eh immer alles läuft. Dafür raucht mein Kopf aktuell bezüglich Voice-Assigner, Velocity und Modulation.
 
  • Daumen hoch
M.i.a.u.: DanReed
  • #54
Während der Zeitänderung läuft der Lesekopf dann z.B. mit Samplerate "1 + 1/256" oder "1 - 1/256" während der Schreibkopf immer mit "1" läuft.
Ich arbeite komplett Block-basiert. Da dürfte das etwas schwierig werden. Aber vielleicht fehlt mir da auch noch etwas die Vorstellung, wie ich ein DSP-Objekt mit unterschiedlichen Ein- und Ausgabe-Geschwindigkeiten betreiben könnte.
Das ergibt einen Pitch-Shift Effekt
Ich stehe ja auf "Separation of Concerns". Der Ringpuffer soll ringpuffern. Fürs Pitch-Shifting habe ich was anderes. Der Granulator kann z. B. easy als (dann natürlich überkomplexer) Pitch-Shifter genutzt werden. Hier läuft es so, dass die Samples fürs Grain eingefroren werden, dann kann der Ringpuffer weiter puffern, ohne, dass sich da irgendwas in die Quere kommt und ich kann mit dem Grain anstellen was ich will, ohne igendwelche Faxen im Ringpuffer veranstalten zu müssen damit das save ist. Das sind mir die paar Zyklen für den Kopiervorgang wert.
Oder ist es ein rückgekoppeltes Delay? Dann wird es komplizierter.
Tatsächlich hat der Ringpuffer auch die Option, Feedback zu nutzen. Hier mal zum Spaß der gesamte Schreibprozess:
Code:
void RingBuffer::pushInput(const SignalBuffer &blockL, const SignalBuffer &blockR)
{
    for (size_t i = 0; i < DSP::BLOCKSIZE; ++i)
    {
        bufferL[writeIndexL + i] = blockL[i] + feedbackBufferL[i];
        bufferR[writeIndexR + i] = blockR[i] + feedbackBufferR[i];
    }

    // Next write index is the oldest block in buffer
    writeIndexL += DSP::BLOCKSIZE;
    writeIndexR += DSP::BLOCKSIZE;

    if (writeIndexL >= bufferSizeL)
    {
        writeIndexL = 0;
    }

    if (writeIndexR >= bufferSizeR)
    {
        writeIndexR = 0;
    }
}
Wobei blockL/R der Input ist. Linker und rechter Kanal können unterschiedliche Laufzeiten haben.

Warum kann das zu Problemen führen? Vielleicht, weil es sich hochschaukeln könnte? Wahrscheinlich ist es besser, das Feedback nicht in den neuen Puffer zu addieren.
Berichte mal nachher, ob du damit zufrieden bist.
Muss jetzt erstmal warten, bis die Kopfschmerztablette endlich wirkt. ;-)
 
  • #56
Warum kann das zu Problemen führen? Vielleicht, weil es sich hochschaukeln könnte? […]
Ja. Wobei lineares Überblenden eher zum „Runterschaukeln“ führt, denn es bewirkt in den meisten Fällen einen Energieverlust. Nimmst du dagegen die Alternative sin/cos, kommt es auf den Korrelationsgrad der 2 Signale an. Nur wenn sie unkorreliert sind, ist diese Überblendungsart energieneutral. Ich sage mal voraus, dass du dann bald einen Stabilisierungsmechanismus wirst haben wollen. Der ist möglich, aber aufwändig.
 
  • Daumen hoch
M.i.a.u.: _thomas_
  • #57
Wie kommt es beim FPGA zu 1T/sample beim FIR, wenn man dort z.B. 255 Taps nutzt?
Beim FPGA arbeitet man normalerweise in Pipelines. D.h. den (ältesten) Tap für Filter-Sample "n" würde man bereits bei Sample "n-254" berechnen und schiebt das Zwischenergebnis dann mit jedem Clock in die Nächste Stufe wo es dann weiter geht. D.h. die Berechnung des Filter Samples "n" beginnt quasi bereits mit Input Sample "n-254". Das entspricht dann der "Transposed FIR filter" Form. Das kann man eins-zu-eins so umsetzen, jedes "z-1" entspricht einem getaktetem Latch, Multiply/Add wäre dann bei mir ein DSP Slice. Bei 255 Stufen heißt das dann aber auch 255 DSP slices und Latches, das wäre schon ziemlich resourcenhungrig. Das mit dem Pipelines funktioniert natürlich auch wenn man mehrere Stimmen hat ( Die nacheinander gerechnet werden). Statt einem einzelnen Latch für das Zwischenergebniss kommt da dann ein kleiner Dual-Port RAM rein. Und wird entsprechend der Stimme adressiert.

Da ich hier aber z.B. pro Sample 4 Oszillatoren rechne, hätte ich sogar 4 Takte und man könnte das partiell sequentiell rechnen so das man immer 4 Taps sequentiell im gleichen DSP Slice rechnet, also "nur" noch ~64 slices.
 
  • #60
Wie mache ich das? Nehme ich Perlin-Noise oder baue ich mir einen Random-Walk um (smooth) einen virtuellen sich bewegenden Punkt zu erzeugen, zu dem die Sperlinge dann streben?

Was ist denn bitte für dich der Unterschied zwischen Perlin-Noise und deinem "Random-Walk"? Anders: wo kommt denn das "Random" her?

Waru nicht einfach Beides (z. B: per Strategy-Patten) implementieren und
1. selbst sehen, was besser zu sein scheint oder
2. einem geneigten Benutzer die Wahl überlassen?

Prinzipiell finde ich die Threadidee gut. Allerdings bin ich derzeit thematisch in anderen Gefilden unterwegs, die mich auch etwas Zeit kosten werden.
 

Neue Beiträge

News

Zurück
Oben