Pure Data | Organelle | Max/MSP | Q&A

Tommi

|||||||||
An anderer Stelle hatte ich @banalytic und @sushiluv ja mal versprochen ein paar Worte zu meinen Erfahrungen und auch meinen Tools zu schreiben die ich für meinen C&G Organelle entwickelt habe. Vorab eine Bitte:

Ich habe jetzt nicht so viel Freizeit wie ich gern hätte. Das Thema ist allerdings nicht mit zwei oder drei Worten erklärt. Daher bitte ich darum, dass ich erstmal meine Tools und mein Vorgehen beschreibe und erst dann den Thread für Fragen und Kommentare freigeben würde. So würden die Beschreibungen der einzelnen Komponenten zusammen bleiben und nicht zwischen diversen Beiträgen stecken. Für eure Geduld bedanke ich mich schon mal im Voraus. Allerdings könnte es auch etwas dauern bis ich fertig bin. Ich würde dann Bescheid sagen wenn ich fertig bin.

Zum Hintergrund:


https://www.youtube.com/watch?v=I9_3CfRm8GE


Das kreative Chaos. Kann man machen. Aber wenn man einen Fehler im Patch hat sind Suche und Korrektur doch ziemlich aufwändig. Bei mir sieht ein komplexer Patch auf oberster Ebene eher so aus:

1636134430554.png

Auf den darunter liegenden Ebenen aber auch nicht viel anders. Ziel ist es, Komplexität zu vermeiden und bestimmte Aufgaben/Funktionen durch dedizierte Komponenten (oder auch Services) dem Gesamt-Patch zur Verfügung zu stellen. Hört sich komplizierter an als es ist. Und das ist genau der Punkt den ich hier erklären werde.

Dies hier ist der Startbildschirm:

2021110518364500.jpg

Und kurz noch zum Hintergrund des Patches: Mir ging es hier im Polyrythmik/Synkopen. Benutzt habe ich hier einen 12-Ton-Sequencer (eine Oktave, Schönberg/Webern, serielle Musik) der mir, unterschiedlich transformiert, einfach erstmal Noten zur Verfügung stellt. Die Idee hatte Tim (Sohn 1), daher taucht sein Name auch auf dem Bildschirm (im Folgenden "Page") auf. Tim hat auch drei Tonfolgen am Klavier entwickelt die ich dann in Form von Midi-Noten dem Sequencer zur Verfügung stelle.

Im Wesentlichen geht hier um diese Komponenten:

1636135762470.png
  • declare -path: Einbindung des Unterordners lib in dem alle referenzierten/benötigten Komponenten liegen
  • midiScv: stellt MIDI-Funktionen in Form von Events bereits
  • auxSvc: stellt Funktionen für den AUX-Button bereit
  • pageSvc: stellt Funktionen für die Verwaltung von Screens/Pages bereit
  • knobSvc: stellt Funktionen für die vier Potis bereit
  • bangSvc: stellt einen synchronisierten Startprozess des Patches zur Verfügung
In den folgenden Beiträgen werde ich diese erklären und auch Anwendungsbeispiele liefern. Nebenbei kommen dann wahrschienlich auch noch ein paar Infos zu anderen Komponenten wie Clock und Oszillatoren, etc...
 
Zuletzt bearbeitet:
Diese Komponenten heißen übrigens alles irgendwas mit "Svc" am Ende. Svc ist die Abkürzung für "Service".

Erstmal zu einer einfachen Sache, dem midiSvc. Die MIDI-Implementierung für den Organelle weicht von der Standardimplementierung in PD ab. Auf dem PC funktioniert der midiSvc deswegen nicht. Dieser benutzt das Objekt "notes" (siehe "pd MIDI" in mother.pd) und nicht z.B. das wesentlich mächtigere "notein". Der Organelle lässt MIDI-Events rein wie raus leider nur auf einen Kanal zu. Was wirklich sehr schade ist. Ansonsten würde mir der Organelle die Möglichkeit bieten alle möglichen externen Geräte zu steuern. Was so aber leider nicht möglich ist.

Der midiSvc stellt folgende Events bereit:
  • midiNote: wird ausgelöst wenn eine Taste auf dem internen oder externen Keyboard gedrückt oder losgelassen wird und enthält den MIDI-Wert der Note
  • midiTrigNote: wird ausgelöst wenn eine Taste auf dem internen oder externen Keyboard gedrückt wird und enthält den MIDI-Wert der Note
  • midiVelocity: enthält einen Wert von 0 bis 127 für die Stärke des Anschlags; ist der Wert größer 0 wurde die Taste gedrückt; ist der Wert 0 wurde die Taste losgelassen; nutzt man das Keyboard des Organelle beträgt dieser Wert immer 100
  • midiNoteOn: wird gefeuert wenn eine Taste des internen/externen Keyboards gedrückt wird
  • midiNoteOff: wird gefeuert wenn eine Taste des internen/externen Keyboards losgelassen wird
Beispiel mit "midiTrigNote" und "midiVelocity":

1636148494619.png

Hier empfange ich den MIDI-Notenwert des Organelle-Keyboards indem ich "midiTrigNote" auffange (r = receive, hier 69) und wandle die Note mittels "mtof" in die entsprechende Frequenz (440 Hz) um und gebe diese Frequenz an einen Oszillator weiter.

Eine Berechnung auf dem Audiosignal 1636146485590.png wendet die in "midiVelocity" übergebene Anschlagstärke auf die Amplitude des vom Oszillator ausgegebenen Signals an. Ziemlich viele Dinge in PD und auch dem Organelle spielen sich zwischen 0 und 1 ab. So auch die Lautstärke. 0 entspricht "aus" und 1 entspricht der maximalen Lautstärke. Die Anschlagstärke kann aber zwischen 0 und 127 liegen. Wenn man diesen Wert direkt so anwenden würde wäre das Audiosignal also total übersteuert. Also teilt man den Wert einfach durch 127 und landet so wieder zwischen 0 (keine Taste gedrückt) und 1 (maximale Anschlagstärke).

1636146485590.png nimmt also die vom Oszillator erzeugte Amplitude und multipliziert diese mit dem anliegenden Wert aus "midiVelocity" geteilt durch 127. Bei einer Anschlagstärke von z.B. 50 ist dies dann 1 * 0.39 (50/127), also knappe 40 Prozent der maximalen Lautstärke.

"osc-sin-fm~" ist ein einfacher FM-Oszillator. In den ersten Eingang geht die Frequenz aus "mtof". Eingang zwei und drei bestimmen die Form der Frequenzmodulation. Der vierte Eingang stellt den Glide in Millisekunden ein.

1636147023540.png

1636147203406.png ist ein in PD fest eingebauter Trigger der beim Laden des Patches gefeuert wird und initialisiert Parameter (oder Eingang) zwei, drei und vier mit den angegebenen Werten 1, 2 und 100.

Das war's mit dem midiSvc. Das Projekt hängt an diesem Beitrag. Wer den Patch nicht auf dem Organelle ausprobieren kann oder möchte muss in lib/midiSvc.pd das 1636147873701.png gegen z.B. "notein" austauschen. Zusätzlich muss

1636149112641.png

gegen

1636149145851.png

ausgetauscht werden.
 

Anhänge

  • midiSvc.zip
    1,7 KB · Aufrufe: 8
Zuletzt bearbeitet:
Das schaut noch chaotischer aus als SunVox.
Eigentlich ist es nicht chaotisch wenn man auf ein paar Dinge achtet. Es ist nun mal ein Ereignisbasiertes System in dem Audio- und Datenströme durch den Patch laufen. Im Grunde ziemlich analog zu Modular. Und die Verbinder sind die Strippen im Eurorack.

Ich zitiere mich noch mal selbst:
Daher bitte ich darum, dass ich erstmal meine Tools und mein Vorgehen beschreibe und erst dann den Thread für Fragen und Kommentare freigeben würde.

Die nächste einfache Sache ist der "auxSvc". Hier wird Funktionalität für den AUX-Buttons implementiert.

Hintergrund: Ich dachte so bei mir, dass die sehr eingeschränkten interaktiven Möglichkeiten des Organelle doch eigentlich erweitert werden müssten und habe mir ein Beispiel an Elektron genommen und kann mit dem auxSvc jetzt jeden Knopf mit (aktuell) bis zu vier Funktionen belegen. Auch das Keyboard.

Der auxSvc sendet folgende Ereignisse:
  • auxState: entweder 1 wenn AUX gedrückt wird oder 0, wenn AUX nicht gedrückt ist (LED weiß oder aus)
  • auxOn: triggert nur wenn AUX gedrückt wird (LED weiß)
  • auxOff: triggert nur, wenn AUX losgelassen wird (LED aus)
  • altFunc1: zwei Mal innerhalb 600ms drücken, 1 oder 0, aktiviert alternative Funktion 1 (LED rot)
  • altFunc2: drei Mal innerhalb 600ms drücken, 1 oder 0, aktiviert alternative Funktion 2 (LED grün)
  • altFunc3: vier Mal innerhalb 600ms drücken, 1 oder 0, aktiviert alternative Funktion 3 (LED blau)
Die alternativen Funktionen werden deaktiviert indem man ein Mal AUX drückt. Da ist leider noch eine kleine Race Condition enthalten die dafür sorgt, dass die LED u.U. den falschen Status anzeigt. Das passiert aber nur wenn man zu hektisch hin und her schaltet. Mit einem Druck auf AUX resetet man aber immer alles.

Beispiel:

Dieser Patch gibt den aktuellen Status des AUX-Buttons auf dem Screen aus.

1636192484320.png

Initialisierung des Screens und des Status. "s" bedeutet "senden". Hier: sende eine 0 an "init". Mittels "r init" (r = receive, siehe unten) kann dieser Wert dann überall im Patch empfangen und weiter verarbeitet werden.

1636193463876.png

Nachricht auf dem Screen ob AUX nun gedrückt wird oder nicht. Einmal mit "auxOn" und "auxOff" und einmal mit "auxState":

1636193507959.png

Wer 1636193616549.png noch nicht kennt: Moses teilte im alten Testament das Wasser und genau das macht dieses Objekt auch. Jeder eingehende Wert (der hier aus auxState nur 0 oder 1 sein kann) wird auf den linken Ausgang geschickt wenn er kleiner als der angegebene Teilerwert (hier 1) ist. Ist der Wert gleich oder größer als der für moses angegebene Wert wird er an den rechten Ausgang weiter geleitet. Der linke Ausgang gibt dass "AUX OF" auf der zweiten Display-Zeile aus weil es nur 0 sein kann. Der rechte Ausgang gibt dann "AUX ON" aus.

Zuletzt noch die alternativen Funktionen:

1636194724266.png

Das "init" kommt ja vom "loadbang" beim Laden des Patches und enthält eine 0. Ich gebe hier also eine 0 in den linken Eingang von moses. 0 im Eingang bedeutet, dass der linke Ausgang von moses diese dann wieder ausgibt. Die 0 selbst verwende ich in deisem Fall aber nicht. Ich gebe nur "ALT 1 OFF" auf dem Screen in Zeile 3 aus.

Der Rest ist dann einfach: "altFunc1" schickt mir entweder eine 1 (aktiviert) oder eine 0 (deaktiviert) und moses teilt das dann wieder.

Ans Eingemachte geht es dann in den nächsten Beiträgen. Da kann man dann auch sehen, wie alles zwar nicht voneinander abhängt, aber trotzdem zusammen hängt.

Der Patch befindet sich wieder im Anhang.
 

Anhänge

  • auxSvc.zip
    3 KB · Aufrufe: 6
Ich sehe gerade, dass ich einen Moderator um Ruhe gebeten habe... Sorry ;-)

Noch schnell, bevor es endgültig richtig losgeht, hier noch die Lösung zu einem typischen Problem in Eventbasierten Umgebungen: wann wird überhaupt ein Event ausgelöst? Und was ist, wenn ich auf eine bestimmte Reihenfolge angewiesen bin?

PD selbst stellt dazu ein Objekt "Trigger" bereit: 1636215726584.png. Hier werden die Ausgänge von links nach rechts in Reihenfolge abgefeuert. Das ist wichtig weil in PD immer der ganz linke Eingang die Ausführung einer Funktion triggert. Aber was ist, wenn ich auf die anderen Eingängen vorher noch Daten senden will? Ich muss es synchronisieren. Erst werden alle anderen "kalten" Eingänge getriggert, und dann erst der ganz linke "heiße" Eingang.

Aber was mache ich, wenn das über mehrere sogenannte Sub-Patches/Komponenten stattfinden soll? Dafür existiert der "bangSvc". Dieser definiert unterschiedliche Startphasen des Patches. So könnten z.B. als Erstes immer die Patch-Daten initialisiert werden und dann erst der Bildschirm. Genau so ist das bei mir auch aufgebaut. Details dazu kommen aber erst später. Hier geht's mehr ums Konzept.

Beispiel:

Hier der Vergleich zu "loadbang" welches beim Laden des Patches ausgeführt wird. Was wird schlussendlich im Display Zeile 1 dargestellt? Das kann man nicht vorhersagen weil man nicht weiß in welcher Reihenfolge die Werte 1 - 5 an das Display gesendet werden.

Nutzt man aber "loadbangN", z.B. 1636216156129.png kann man sicher sein, dass dieser Bang immer als allererstes gesendet wird. Anschließend dann 1636216195748.png usw. In diesem Patch steht also immer die 5 auf dem Screen in Zeile 2.

1636216026496.png

Später wird man sehen, dass der Screen im mit "loadbang4" initialisiert wird.
 

Anhänge

  • bangSvc.zip
    3,3 KB · Aufrufe: 5
Sorry fürs reinposten. Sehr spannend und danke für den Aufwand. Ich würde nur gerne anmerken, dass PD meines Wissens von rechts nach links abarbeitet, so wie Max.
 
dass PD meines Wissens von rechts nach links abarbeitet, so wie Max
In PD scheint es eher so zu sein, dass es in der Reihenfolge ausgeführt wird in der die Verbinder erstellt werden. Was ja auch Sinn ergibt weil es in der Reihenfolge ja anscheinend auch im Quellcode angelegt wird:

2021110811071800.jpg

Die 2 habe ich als letztes mit dem loadbang verbunden. Ich will jetzt aber auch nicht zu nerdig werden. In größeren Patches kann das loadbang schon ein Problem darstellen da es meist an vielen Stellen verwendet werden muss und Abhängigkeiten nicht berücksichtigt werden können. Und man weiß nie, in welcher Reihenfolge ausgeführt wird.
 
Weiter geht es jetzt mit diesen beiden: 1636895891488.png

Knobs (die Potis, nicht der Encoder) und Pages (also Seiten auf dem Screen) machen nur gemeinsam Sinn. Mehr oder weniger. Der knobSvc empfängt vom pageSvc die aktuell ausgewählte Seite und stellt entsprechende Events bereit mit denen man ganz simpel interaktive Aktionen auf einer Seite darstellen kann ohne dass man sich aufwändig um die Verwaltung der Seiten kümmern muss.

Der gesamte Patch (10 Pages):

1636896133657.png

Mit dem Patch kann man a) eben 10 Seiten anzeigen und b) ein bisschen mit den Potis spielen was dann ebenfalls angezeigt wird. Details dazu folgen aber gleich auch noch.

2021111413524900.jpg

Der pageSvc empfängt zwei Parameter: die zu verwaltende Seitenanzahl (hier 10) sowie die Anweisung, ob der Screen bei einem Wechsel der Seite gelöscht werden soll. 1 bedeutet: löschen, 0 bedeutet: nicht löschen. Diese beiden Parameter stehen ebenfalls als Inlets (also Eingänge) zur Verfügung um sie zur Laufzeit eines Patches ändern zu können.

Durch den pageSvc können bis zu 20 Pages verwaltet werden. Natürlich noch eine viel höhere Anzahl, aber ich habe bei 20 Schluss gemacht. Wer mehr möchte muss aber nur den Patch anpassen.

Es bestehen zwei Möglichkeiten Pages anzusteuern:

1. Mittels AUX und Knob 1

Während man die AUX-Taste drückt kann man über das Drehen von Poti 1 die Seiten anspringen:

2021111413531400.jpg

Auf welcher Seite man sich befindet wird in der obersten Zeile links neben der Batterieanzeige des Screens für ca. eine Sekunde angezeigt:

2021111413525700.jpg

2. Mittels AUX und dem Keyboard:

Drückt man AUX und eine der unteren Keyboardtasten (beginnend beim unteren C) kann man direkt auf eine Seite springen. Dies ist aber nur bis zur Seite 10 möglich.

2021111413530500.jpg

2021111413532500.jpg

Nachdem der Patch komplett initialisiert wurde (siehe auch"loadbang") wird die erste Seite auf 1636897709955.png automatisch angezeigt. Darum muss man sich also nicht kümmern.

Und wie genau funktioniert nun der Patch?

Man bindet "knobSvc" und "pageSvc" ein. Auch diese liegen im Unterverzeichnis "lib" des Patches. Damit steht die Funktionalität auch schon bereit. Am Beispiel der ersten Seite erkläre ich was man damit in diesem Patch machen kann:

1636897587171.png

Wird vom pageSvc 1636897770334.png getriggert wird eine Nachricht 1636897818812.png auf 1636897845492.png, also der ersten Displayzeile, ausgegeben. Natürlich kann/sollte mittels "switchPageX" die Seite komplett initialisiert werden. Da ich momentan aber noch keine echten Daten verwalte (dazu in einem späteren Beitrag wesentlich mehr) gebe ich hier stellvertretend einfach mal die Seitennummer aus.

Damit weiß aber gleichzeitig auch der knobSvc, dass ich mich auf Seite 1 in meiner Benutzerschnittstelle befinde. Dieser empfängt nämlich die aktuell ausgewählte Seitennummer vom pageSvc. Normalerweise ist es ziemlich kompliziert die vier Potis an eine Anzeigeseite eines Patches zu "binden". Hier wird aber vom knobSvc einfach über 1636898060947.png der Wert des Potis empfangen. Seite 1, Poti 1. Ganz einfach wie ich finde.

Der Wert des Potis (0 - 1) wird dann umgerechnet. Der erste Poti wird 1636898331851.png genommen. Poti 2 1636898356775.png, usw. usf. Und da hier immer Fließkommazahlen gesendet werden wandle ich mit 1636898442620.png (i = integer) diesen Wert in eine natürliche Zahl (inklusive 0) um. Dann erzeuge ich aus diesem Wert noch eine Nachricht 1636898696298.png. Das "$1" ist ein Platzhalter für den Wert der oben ankommt. Und das gebe ich dann einfach auf der Zeile 2 aus: 1636898748633.png.

Ich hoffe, dass der Rest des Patches dann so ziemlich selbsterklärend ist.

Ich hatte erst überlegt ob ich die Anwahl der Seiten nicht vielleicht über den Encoder lösen soll. Aber: Schaut man sich in diesem Patch (egal auf welcher Seite, funktionieren ja alle gleich) mal Poti 3 und 4 an merkt man wie schwierig es ist einen exakten Wert anzufahren. Selbst mit noch so viel Feingefühl ist es unmöglich Werte korrekt einzustellen. Das liegt einfach an der Multiplikation der Werte die von den Potis kommen. Man stelle sich einen Filter vor den man exakt einstellen möchte. Der hat eine Range von 0 - 10000. Und da den "Sweetspot" zu treffen ist bei der Auflösung welche die Potis dann noch bieten quasi unmöglich.

Für genau dieses Problem habe ich mir den Encoder frei gehalten. Das wird dann so aussehen, dass man mit dem Poti einen Wert ungefähr anfahren kann um dann mittels Encoder die Feineinstellung vorzunehmen. Was eigentlich ja ein ziemliche Krücke ist. Das allerdings erfordert ein komplett neues Konzept für die Benutzerschnittstelle (im Kopf allerdings schon alles fertig). Auch wird so die Verwaltung der Pages aufwändiger als es momentan der Fall ist.

Ob ich das umsetzen werden weiß ich aber noch nicht. Ich bin mir einfach nicht sicher ob der Organelle bei mir bleiben wird. Trennen konnte ich mich bis jetzt allerdings auch noch nicht. Da steckt halt einiges an Potential drin. Das aber auch sehr aufwändig zu erreichen ist...

Es existiert aber ja bereits eine Lösung mit der man "alternative" Multiplikatoren angeben kann. Auch dazu werde ich dann in Zukunft noch kommen.

Der Patch hängt, wie immer, an dem Beitrag. Wenn ihr Fragen habt könnt ihr die gerne stellen.

Weitergehen wird es hier wahrscheinlich erst wieder in 3-5 Wochen da ich mich solange in einem weit entfernten Land aufhalten werde. Und der Organelle wird mich nicht begleiten. Vielleicht habe ich die Woche aber auch noch Zeit für einen weiteren Abschnitt.
 

Anhänge

  • pageSvc.zip
    9,8 KB · Aufrufe: 2
Zuletzt bearbeitet:
Wie schnell doch ein Jahr vergeht...

Ich bin mir nicht sicher, ob das hier von jemandem genutzt wurde. Daher habe ich nicht noch mehr Zeit investieren wollen. Sollte noch Interesse an einem kleinen Patch vorhanden sein der das alles mal praktisch anwendet bin ich gern bereit noch mal in die Tasten zu hauen.

Bis dahin habe ich aber selbst eine Frage:

Ich baue mir gerade selbst alle möglichen Effekte zusammen. Aber an einer Sache verzweifle ich gerade. Die eigentlich einfache Distortion hat, zumindest in meiner Idee, ein Problem.

Wie funktioniert die Distortion? Ganz einfach: PD legt die maximale Lautstärke ja als nummerischen Wert 1 fest. Das sind 100 Prozent. Wenn ich also das eingehende Signal extrem verstärke (inlet dist, den moses ignoriert mal einfach, war ein Test) und dann wieder bei 1 abschneide (clip) kommt unten eine wunderbare Verzerrung raus.

Aber: Das Ganze funktioniert natürlich nur, wenn das Eingangssignal auch eine Amplitude von > 1 hat. Weil da sonst ja nichts clipt.

Also war mein Plan, ein Eingangssignal welches nicht clipt weil kleiner 1 mindestens auf 1.5/-1.5 zu bringen.

1669504172742.png

expr 1 dient als Threshold für die Lautstärke. Alles über 10% oder unter -10% wird durchgelassen. Alles andere wird genullt. Das funktioniert auch. Der Grund für den Threshold war dann Stufe 2:

expr 2 Nimmt alles was zwischen 0.1 und < 1.5 und bringt es auf 1.5
expr 3 Nimmt alles was zwischen -0.1 und > -1.5 und bringt es auf -1.5

Klappt auch alles ganz wunderbar. Nur wenn expr 1 eine 0 (also keine Amplitude) ausgibt geht der Ausgang von expr 3 auf -1.5:

1669504312619.png

Zu erkennen am PD-Oszilloskop an dieser durchgehenden Linie. Der rote Pfeil zeigt den Level. Da es keine Schwingung ist hört man natürlich nichts. Aber schön finde ich das jetzt nicht gerade. Vor allem auch deswegen nicht, weil ich es nicht nachvollziehen kann. Die Rechnung in expr 3 müsste doch korrekt sein.

Sieht jemand den Fehler? Oder gibt es dafür eine andere Erklärung?
 
vorne weg: ich kann das kaum lesen, Distortion würde ich nicht als Clipper und einen Clipper auch anders aufbaue.

Dann, wenn ichs richtig lese,
expr1: $vl < 0.1 | $vl > 0.1 ist immer true auser $vl = 0.1
2 und 3 : $vl < 1.5 && $vl > 0.1 ist [B]immer false[/B], da die Bedingung unmöglich ist

Für mich evtl ein Indiz dass du grad ne Pause brauchst, sowas passier nachts...

Edit: Denkfehler meinerseits, in der dritten fehlt aber wohl ein minus vor 0.1

davon ab, versuch es mit abs

Edit: wenn du aus dem Signal brute force ein aliastes Rechteck machen willst, einfach :
sign x
 
Zuletzt bearbeitet von einem Moderator:
Aber: Das Ganze funktioniert natürlich nur, wenn das Eingangssignal auch eine Amplitude von > 1 hat. Weil da sonst ja nichts clipt.

der erste teil der anwort wird dir nicht gefallen: wenn man DSP programmieren will, muss man wissen wie es geht!


doch jetzt zum logischen problem mit dem pegel.

was z.b. bei dynamikeffekten durchaus relevant sein kann und dort auch zu kopfzerbrechen (oder zu autogain modi) führen kann.

bei clipping oder bei verzerrern oder bei waveshaping sollte es hingegen kein problem sein.

zunächst mal hast du da ja eine hardware. d.h. die amplitude kann niemals größer als +-1 sein. ein clipper hätte dann sinnvollerweise einen parameter, der den clipping wert von 1 bis auf 0 runterschiebt - und gleichzeitig hinterher den pegel des ergebnisses wieder entsprechend anhebt.

1669525821024.png

das funktioniert so mit clipping, mit irgendwelchen fuzzes und overdrives, und wenn du das mit tanh, atan & co machen willst, dann musst du zwar noch mit pi multiplizieren, aber das prinzip mit der pegelveränderung ist immer das gleiche.

tu dir das nicht an, mit anderen ranges als normalisiert (-1 bis 1) zu arbeiten.

außer du rechnest gleich alles in db um, dann kann es auch okay sein mit "over" zu hantieren weil man dann wenigstens weiß, was man tut.

expr 1 dient als Threshold für die Lautstärke.

hmmm...nö.

um peak oder power zu bearbeiten... musst du peak oder power messen.

du misst hier nur die samplewerte jedes einzelnen samples. (oder vectors)

dein "noisegate" läuft also mit up/down zeiten von 0.22 millisekunden, und das klirrt wie die hölle.

bzw. für den fall, dass es größere vectoren als 1 sind: mindestens müsstest du die wertesprünge, die hinten rauskommen glätten.

expr 2 Nimmt alles was zwischen 0.1 und < 1.5 und bringt es auf 1.5
expr 3 Nimmt alles was zwischen -0.1 und > -1.5 und bringt es auf -1.5

wozu auch immer...

Da es keine Schwingung ist hört man natürlich nichts.

als faustregel empfehle ich dringend, als testsignale nicht signale zu nehmen, die vollkommen andere eigenschaften haben wie musik-signale.

selbst mit rauschen und cosinus kann man böse überraschungen erleben, wenn man messen/steuern/regeln schaltkreise damit testen will.

ein statischer wert hat hier meines erachtes nichts zu suchen. du kannst zwar die funktion damit testen, eine funktionierende funktion sagt aber trotzdem nichts darüber aus, ob das was man machen will so überhaupt geht. :)

Die Rechnung in expr 3 müsste doch korrekt sein.

sofern ich halbwegs verstanden habe, was du machen willst, dürften die alle 3 "falsch" sein, weil du offenbar davon ausgehst, dass audio signale unipolar sind.

schon die erste expression scheitert daran: "wenn input ist größer als 0.1 gibt ihn aus, wenn kleiner, dann nicht?"

was erwartest du davon? schau dir das ding mal isoliert mit cheri cheri lady als input in einem scope an und vergleiche es gegen den input.

was du also mindestens machen willst ist

1.) den negativen bereich auch zu bearbeiten, und

2.) vermutlich wär es auch besser das nicht mit dem cpu-teuren if zu machen sondern rein arithmetisch:

expr ((input <= -0.1) || (input >= 0.1)) * input

3.) funktioniert das nicht mit musiksignalen, sondern du müsstest schon mindestes mal den peak im verlauf messen und glätten.
 
Zuletzt bearbeitet:
der erste teil der anwort wird dir nicht gefallen: wenn man DSP programmieren will, muss man wissen wie es geht!
Das ist schon okay. Erst in man Anfänger, irgendwann kann man es dann. Ist ja überall so. Ich bin, was mein Wissen über DSP angeht bei vielleicht 5%. ;-)
du misst hier nur die samplewerte jedes einzelnen samples. (oder vectors)
Richtig. Was aber hier meiner Meinung nach auch vollkommen ausreicht. Es kommt ja nicht auf Genauigkeit an.
um peak oder power zu bearbeiten... musst du peak oder power messen.
Richtig, ist hier aber nicht notwendig. Und vermutlich auch ziemlich aufwändig. Aber ich werde das mal mitnehmen weil es mich interessiert.
sofern ich halbwegs verstanden habe, was du machen willst, dürften die alle 3 "falsch" sein, weil du offenbar davon ausgehst, dass audio signale unipolar sind.
Wenn ich davon ausginge, dass Audiosignale unipolar seien hätte ich den negativen Anteil des Signals der Samplingwerte außer Acht gelassen. expr 3 enthält einen Bug den @mooncast entdeckt hat.
als faustregel empfehle ich dringend, als testsignale nicht signale zu nehmen, die vollkommen andere eigenschaften haben wie musik-signale.
Das Testsignal kam von einer Gitarre.
vermutlich wär es auch besser das nicht mit dem cpu-teuren if zu machen
Werde ich mal testen. Danke für den Hinweis. So viel teuer wird es aber wahrscheinlich nicht sein.
Für mich evtl ein Indiz dass du grad ne Pause brauchst, sowas passier nachts
Ja, war spät und ich bin auch nicht mehr der Jüngste ;-)
Edit: Denkfehler meinerseits, in der dritten fehlt aber wohl ein minus vor 0.1
Korrekt. Das war der Bug. Son Scheiß. Um den habe ich herum gebaut. Danke! Hurra, jetzt funktioniert's!! Die Korrektur hat auch gleich noch ein paar andere Problemchen beseitigt. Topp!

Auch wenn man ein Fuzz so vielleicht nicht baut, finde ich das, gemessen am Aufwand, sehr brauchbar. Das nächste Mal werde ich euch den Fehler aber anders präsentieren. Den ganzen Patch zu zeigen macht keinen Sinn da viel zu kompliziert.

Vielen Dank euch beiden! Ihr habt mir wahrscheinlich den Sonntag gerettet...
 
bei 1 abschneide (clip) kommt unten eine wunderbare Verzerrung raus.
also soo schoen finde ich das standard-clipping als verzerrung auch nicht...
aber ich kann ja den grundlegenden wunsch verstehen, dass man den (beim clipping) unverzerrten
bereich auch irgendwie behandeln moechte.
das hier genannte fuehrt aber eher zu einer rechteckwelle, die man mit "sign"
(expr~ oder selber bauen) tatsaechlich billiger bekaeme.
ueblicherweise macht man das zerren mit irgendeiner (eher nichtlinearen)
funktion. statt alles auserhalb des bereiches einfach wegzuclippen staucht man es eben zusammen.
mein lieblings-soft-clipping ist ja input2=input/abs(input)+1, kostet nur eine division.
aber tanh ist natuerlich auch sehr schoen.
vielleicht softclipping mit hartem clipping xfaden? (also linear statt 1/x), vielleichgt waere
das klanglich ein guter kompromiss?
 
also soo schoen finde ich das standard-clipping als verzerrung auch nicht...
Also mir gefällt es ganz gut. Befriedigend reicht mir als Amateur vollkommen aus. Was mir am Clipping nicht gefällt sind die in manchen Situationen auftretenden Klangartefakte. Ein digitales Krisseln/Rauschen. Das hört sich teilweise nicht so gut an.

Ja, das wird durch das Clipping logischerweise mehr oder weniger zu einem Rechteck.

Hätte nicht gedacht, dass ausgerechnet das gezielte "Zerstören" eines Audiosignals eine komplizierte Angelegenheit ist. Aber es soll sich ja schließlich gut anhören. Und da wird's echt schwierig.

Aber ich werde das mal zum Anlass nehmen und mich in das Thema DSP etwas tiefer einarbeiten. Ist schon spannend. Und ob PD für ein Fuzz das richtige Tool ist... Da bin ich mir nicht sicher. Interessanterweise findet man im PD Patch-Storage auch fast nichts dazu.
ueblicherweise macht man das zerren mit irgendeiner (eher nichtlinearen)
funktion.
Dann schaue ich mal danach...

Machbar scheint es aber zu sein:

https://youtu.be/yglTYu4WBnk
 
Zuletzt bearbeitet:
Richtig. Was aber hier meiner Meinung nach auch vollkommen ausreicht. Es kommt ja nicht auf Genauigkeit an.

das probem ist halt, dass eine so schnelle amplitudenänderung gewisse auswirkungen auf das spektrum hat, um es mal ganz vorsichtig auszudrücken.

Wenn ich davon ausginge, dass Audiosignale unipolar seien hätte ich den negativen Anteil des Signals der Samplingwerte außer Acht gelassen. expr 3

also ich sehe schon in der ersten formel keine negative zahl.

ich denke, dass das, was du da mit diesen expressions versuchst, mit dem üblichen(sic) tanh() viel einfacher zu erledigen wäre. auch das lässt die unteren zwei drittel der amplitude nahezu unberührt - und ganz oben clippt es dann.

dein clip~ kannst du auch einfach in die expressions mit rein schreiben, da ist ja einfach nur min(max(...)...)

bezüglich des begriffs "distortion" möchte ich dir ansonsten recht geben, dass clipping durchaus eine form von verzerrung ist. ob es die ist, die für gitarre wie ein gitarrenverzerrer klingt, ist dann noch mal eine andere frage.
 
Aber ich werde das mal zum Anlass nehmen und mich in das Thema DSP etwas tiefer einarbeiten. Ist schon spannend. Und ob PD für ein Fuzz das richtige Tool ist... Da bin ich mir nicht sicher. Interessanterweise findet man im PD Patch-Storage auch fast nichts dazu.
ich empfehl dir das Book von Miller Pucket.
Gibt es als .pdf.
Das handelt vieles ab, und die Beispiele sind in Pure Data.

Warum sollte PD nicht für Distortion geeignet sein?

Weiter könntest Du nach "Infinite Linear Oversampling" googlen, das ist eine Methode wie man das Aliasing runter kriegt, und als Beispiel ist auch Hard Clipping gewählt.

Ansonsten ist Oversampling sinnvoll bzw notwendig, das wird in PD aber vermutlich etwas umständlich sein. Man interpoliert den Eingang um aus einem Sample zB 4 oder 8 zu machen, und muss das dann am Ende wieder downsamplen.
Je nachdem wie die Obertöne der Verzerrung abfallen muss man aber sehr hoch oversamplen.

Im Nord Lead scheint eine sehr simple Distortion relativ effektiv, dabei wird nur der positive Teil der Wella ab einem Schwellenwert einfach weniger verstärkt, so scheint es zumindest.
Das erzeugt dann gerade und ungerade Obertöne was anders klingt als symmetrische Distortion.
 
Warum sollte PD nicht für Distortion geeignet sein?

weil´s bei ihm nicht geht. :)

aber scherz beiseite: bei MSP sind schon seit 25 jahren fertige binary objekte für overdrive, fold and wrap, waveshaping, sowie bitrate- und samplingrate reducing dabei. das einzige, was es noch nicht ganz so lange gibt sind binary ops für signal.

vermutlich gibt es das zeug auch in der ein oder anderen pd distribution, aber im detail kenne ich mich damit nicht aus.

auch in supercollider stehen dir operators wie .distort .cubed .clip .pow .tanh usw. zur verfügung, auch resampling oder bitwise spielereien sind realtiv einfach mit 2-3 ops zu realisieren, weil es keinen grund gibt, so etwas großartig selbst zu machen.

ein richtig gutes analog modelled fuzz ist dann eine andere hausnummer, da kommt dann noch so viel anderes zeug dazu, dass man auch gleich alles selbst machen kann.
 
weil´s bei ihm nicht geht. :)

Da muss ich auch widersprechen. Ich habe gute Erfahrungen mit pow~ 0.5 gemacht. Allerdings klingt das nur dann gut, wenn die Quadratwurzel erst ab einem gewissen Pegel einsetzt. Das habe ich so gelöst - (das Signal wird in eine positive und eine negative Halbwelle aufgeteilt weil eine Wurzel aus negativen Zahlen hier nicht geht.)

Overdrive_Screenshot.png

Die clip~ Objekte werden hier gerade NICHT für hörbares Clipping eingesetzt, sondern sie trennen die Kurve des Signals in mehrere Bereiche auf, die nachher nahtlos, ohne Nebengeräusche, wieder zusammengefügt werden.
 
das sieht doch schon viel besser aus als diese tommi-nösen expressions.

aber vielleicht hat er die lieber? dann kann er das ja jetzt alles in eine zeile schreiben.
 
bei deiner methode ist diese *$f2, funktion, /$f2, korrekt, und bei dem pow patch geht das in der theorie genauso. aber der wertebreich ist halt viel geringer (du kannst hier schon ein musiksignal mit peak 0.8 auf peak 0.95 bringen, aber der effekt ist halt insgesamt sehr dezent)

bei der methode von tonerzeuger musst du andernfalls aufpassen, dass keine "knicke" (ergo aliasing) entstehen, wenn du da etwas verschiebst oder die amplitude änderst.
außerdem benutzt er einen funktionierenden trick um die offsets der 3 teilsignale automatisch immer wieder zu 0 zu akkumulieren. das geht so nur wenn alles auf 0.5 steht. um hier irgendwas verschieben zu könnten würdest du erst mal statt dem clip einfach eine kombination aus >= und moses verwenden, dann ist sind die teilsignale in der "nicht benutzt phase" immer gleich null und du kannst sie bedenkenlos zusammenstöpseln.

ab einer gewissen komplexizität würde ich die ganze funktion in ein lookup table schreiben, das ist am billigsten.

tanh soll ja recht dicht am verhalten von elektrischen geräten wie mischpulten sein und gilt eher als "sättigung" als denn als verzerrer. also sei doch einfach mutig und kombiniere das tanh dingens es mit ein bischen folding irgendwo knapp unterm limit. so als option jedenfalls.

wenn du irgendwo max patches ergooglest, aufpassen, dort sind die inlets von [pow~] vertauscht (das aber nur in MSP, nicht in MAX oder gen)
 
was hat das mit deinem sin() eigentlich auf sich? um eine tanh funktion zu erhalten sollte es ausreichen mit pi zu multiplizieren. radians clippen nicht, die fahren karussell...
 
Zuletzt bearbeitet:
@ tommi: Danke für die Overdriveblumen :)
Die Intensität steuere ich "old school" wie der Gitarrist auch durch die Höhe des Eingangspegels, den Ausgangspegel muss ich natürlich anpassen.


kann auch durch fast beliebige Werte zwischen 0 und 1 ersetzt werden. 0.1 entspricht z.B. der 10. Wurzel, verformt das Signal ziemlich krass und klingt wie eine "harte" Verzerrung - eher Transistormäßig. 0.8 Klingt deutlich weicher, bei 1 wird gar nix mehr verformt und Output=Input.

Auch asymmetrische Verzerrung ist kein Problem, sowohl der Schwellwert (clip~ Werte anpassen) als auch der pow~ Wert lässt sich ja pro Halbwelle einstellen. Damit kann man viel Zeit verbringen.
 
Expressions mit "if" hab ich noch nie ausprobiert. Echt cool. Ist das eine universelle Ausdrucksform, so wie sie z.B. in der UNIX/Linux Shell benutzt wird? In Excel hab ich sowas auch schon gesehen.

BTW find ich es klasse, dass wir hier mal Pure Data Lösungen besprechen, Ich wollte mich nicht außerdem im Pure Data Forum anmelden.
 
was hat das mit deinem sin() eigentlich auf sich? um eine tanh funktion zu erhalten sollte es ausreichen mit pi zu multiplizieren. radians clippen nicht, die fahren karussell...

besser noch mal ohne rätselsprech.

du versuchst mit sin() das aufsplitten des bipolaren wertebereichs zu verhindern, und das auch mit erfolg.

"normales" soft clipping vs. das, was du machst:

1672578918785.png

entspricht so ungefähr: expr ($f1>=0)*(-(tanh($f1*-2*pi))) + ($f1<0)*(tanh($f1*2*pi)))


dadurch verursachst du aber neue probleme, weil die transferfunktion jetzt nicht mehr bei 1.0 clippt sondern sich endlos wiederholt.

sobald das eingangssignal amplituden größer als pi/2 (das sind +2.9db!) hat kommt da nur noch digitaler datenmüll hinten raus.

du willst aber sicherlich, dass das ganze beim übersteuern des virtuellen mischpults auch noch funktioniert und nicht nur zwischen -1 und 1.

auch die tanh funktion erst ab einem gewissen schwellenwert zu starten geht so nicht mehr so gut. verzerrung beginnt ja im echten leben normalerweise überhaupt erst oberhalb von +0 db...
 
Zuletzt bearbeitet:
Ich muss halt dazu sagen, dass ich (noch) nicht so wirklich trigonometrisch denke. Das muss erst noch kommen.

Ich nutze halt einen Funktionsplotter:

1672656190178.png

Das was du schreibst muss ich mir also erstmal noch etwas erarbeiten. Ich kann allerdings sagen, dass diese von mir genutzte expr für mich ganz gut funktioniert.

Expressions mit "if" hab ich noch nie ausprobiert
Eine ziemlich elegante Möglichkeit um negative und positive Anteile der Samples zu behandeln. Hier z.B. in einem Wellenfalter:

Ist $v1 > 1 wird der über 1/unter -1 liegende Anteil nach unten/oben geklappt (2/-2 - $v1) oder eben nicht.

1672658139060.png
 
Ich muss halt dazu sagen, dass ich (noch) nicht so wirklich trigonometrisch denke. Das muss erst noch kommen.

keine sorge, ich kann das auch nicht und das muss man meiner meinung auch gar nicht.

ich habe, überspitzt gesagt, sogar dreisatz und einfache logik erst durchs programmieren gelernt und kann es auch nur für max oder für DSP, und sicher nicht mit kreide an der tafel so wie der mathe prof. das macht.

Ich nutze halt einen Funktionsplotter:

...der halt nur bis 1 geht.

und deine lösung ist zweifelsfrei sehr elegant und ressourcenschonend und wird auch funktionieren, wenn du nichts anderes als diese funktion in dein organelle lädst, da ja vom wandler nur -1 bis 1 reinkommt.

aber als building block für "soft clip" - den du schon bald in anderem kontext verwenden möchtest, wo du noch anderen code davor hast, z.b. einen lautstärkeregler - wäre es komplett dyfunktional.

rein theoretisch könnte ich mich irren und das yadegari object verwendet eine japanische spezialversion von sin(), die nicht folded. :P das wäre dann allerdings sehr merkwürdig.

sinus von zahl größer als pi/2 soll ja die maximale amplitude von 1. halten, die werte gehen ab $f2 > ~1.6 aber endlos rauf und runter.

1672661244063.png
 
@Tommi
Ich habe auch expr~ Objekte bisher nicht benutzt, weil es in der Pure-Data-Hilfe heißt, die könnten sehr CPU-hungrig sein. Wie sind denn da deine Erfahrungen?

einseinsnull schrieb:
sinus von zahl größer als pi/2 soll ja die maximale amplitude von 1. halten, die werte gehen ab $f2 > ~1.6 aber endlos rauf und runter.
Dieses Rauf und Runter ist völlig korrekt, die Sinusfunktion setzt sich ab 360° bzw. 2 pi einfach fort - sie wiederholt sich im Abstand von 2 pi.
 


News

Zurück
Oben