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

Tommi
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:
Tommi
Tommi
|||
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: 2
Zuletzt bearbeitet:
marco93
marco93
Shnitzled in the Negev
Das schaut noch chaotischer aus als SunVox. Nach einer Woche wuerde ich da nicht mehr durchstreigen.
 
Tommi
Tommi
|||
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: 3
Tommi
Tommi
|||
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: 3
sushiluv
sushiluv
|||||||||
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.
 
Tommi
Tommi
|||
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.
 
Tommi
Tommi
|||
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: 0
Zuletzt bearbeitet:
 


Neueste Beiträge

News

Oben