Sompyler: Projektvorstellung, Entwicklungsstand und -einblicke, Tutorials, Audiosnippets

GegenKlang

GegenKlang

Alles gut? Nicht viel, doch genug.
Dieser Post soll mein DIY-Projekt vorstellen und eine kleine Einführung geben. Vorab sei zum schnellen Hinnavigieren auf die Inhalte der folgenden, jeweils einen Meilenstein der Weiterentwicklung dokumentierenden Posts verwiesen:
  1. 9.3.19: Beethovens Mondscheinsonate, 1. Satz.
  2. 26.5.19: Mondscheinsonate, vollständig
  3. 16.4.21: Vorstellung einer Webapp namens Neusician, die Zugriff auf eine Sompyler-Installation auf meinem Server gibt. Anmeldung für Interessierte durch mich (PN).
  4. 16.4.22: Demovideo meines textbasierten Workflows, schließt ab mit einer synthetisch modellierten Interpretation von Franz Schuberts "Auf dem Wasser zu singen".
  5. 11.1.23: REST-Schnittstelle der Webapplikation, enthält Link zu einer kleinen Demo.
  6. 14.1.23: dt. Dokumentation der Taktnotation: Takt, Stimme, Stammnoten und Tongruppen; Akkorde und Skalen; benannte Figuren; Großtakte, Taktgruppen, Werteketten mit dem Senkrechtstrich.
  7. 17.2.24: Präambel, Stimmen, Instrumente, ihre Spezifikation, abschließend Beispiele.
  8. 23.2.24: Takteigenschaften, stimmübergreifende und stimmbezogene.
~ ~~ Ende der Vorrede ~~ ~​

Sompyler ist ein Offline-Synthesizer. Von außen betrachtet ein klassisches Unixtool, das ohne grafische Benutzeroberflache auskommt. Na gut, eher sollte ich sagen, der Entwickler hat halt andere Prioritäten. Shit in, Fehlermeldungen und/oder Shit out, bzw. Data-by-somebody-knowing-how in, hearable music & sound out. Also ziemlich puristisch, nerdig. Und warum das Programm so heißt wie es heißt, sollte auch klar sein: Compiler, Namenspaten, arbeiten ganz ähnlich.

Eingabedaten sind im strikt hierarchischen YAML-Format. Sie umfassen Noten und Instrumentdefinitionen. Richtig gelesen: Nicht nur die Töne (nebst Rhythmus und Dynamik), sondern auch wie das Instrument klingt, formuliert man in Textform. Sompyler braucht also keine Soundfonts, Wavetables oder Granulars, sondern macht das alles selbst locker flockig aus dem Prozessor, wobei ggf. mehrere Kerne benutzt werden.

Sompyler ist also ähnlich wie CSound, dafür aber von der schnöden Mathematik aufwärts selbstgemacht, was mich mit einigem Stolz hier auftreten lässt, als hätte ich das Rad gerade neu erfunden.

Sompyler ist in Python programmiert. Ich arbeite daran seit März dieses Jahres. Die Berechnung von Bézierkurven (etwa für A(D)SR-Hüllkurven, Wellenformen, frequenzstatisch-relative Amplitudenmaxima) lässt sich durch einmalige Kompilierung in Maschinensprache massiv beschleunigen, aber Echtzeitbetrieb ist bestimmt nicht drin, nun, irgendeinen Tod muss man nun mal sterben. Dafür werden Additive Synthese, FM, AM und Waveshaping unterstützt. Die Klangfarbe lässt sich abhängig von Tonhöhe, Betonung und instrumentspezifischen Eigenschaften der Note variieren.

Ich arbeite zur Zeit am liebsten am Klavierton. Und jetzt, zur Adventszeit, an verschiedenen Weihnachtsliedern, von denen ich jeden Adventssonntag eines auf meine Seite mit Sompyler-Demos stelle: https://neusik.de - die Domain ist ein Kunstwort aus Nerd und Musik, na gut, auch "neu" und "noise" kann mit assoziiert werden.

Das Projekt ist Open-Source (GPL). Der Code ist verfügbar auf GitHub: https://gitlab.com/flowdy/sompyler.
 
Zuletzt bearbeitet:
Hallo,

es ist an der Zeit, mal etwas Hörbares zu präsentieren, das mit dem Sompyler gemacht wurde. Es handelt sich um eine Eigenkomposition von mir. Die Noten sind "from scratch" über Monate hinweg in MuseScore entstanden und händisch in das von Sompyler erwartete YAML-Format überführt. Das war mir eine extrem gute Übung im Notenlesen. MIDI importieren kann der Sompyler nämlich nicht, und das Feature steht auch nicht in meiner Roadmap (will sagen, einen Importer zu schreiben überlasse ich etwaigen freiwilligen Dritten).


Weitere Links zum Stück:
  1. Das Sompyler-Pendant zur Common Music Notation: YAML-Textformat. Nicht nur Takte, instrumentgebundene Takte, Akkorde mit ihren Offsets zum Taktbeginn, Elementarnoten mit ihren Längen, ggf. Gewichten und instrumentspezifischen Merkmalen werden notiert, sondern auch notenübergreifende Angaben zur Betonungsstruktur und -stärke, Dynamik und Tempo werden definiert. Außerdem ganz oben auch, welche Instrumente wo auf der Stereobühne stehen.
  2. Instrumentdefinition, ditto
  3. Definition der Tonfrequenzberechnung und der Tonnamen gemäß des MIDI-Standards. Die Definition der Töne selbst ist flexibel gestaltet, um auch andere, nichtwestliche Tonsysteme zu unterstützen. Wobei die Intervalle hier noch statisch sind. Geplant ist, auch unregelmäßige Intervalle sowohl auf Ebene der Tonskala als auch auf Ebene einzelner Instrumente zu unterstützen.
 

Anhänge

  • anfaengerstueck_1.mp3
    2 MB · Aufrufe: 978
Zuletzt bearbeitet:
Von Soundcloud bin ich wieder abgekommen. Die haben nen Uploadfilter, der angeschlagen hat, obwohl ich explizit geschrieben habe, dass das Mozarts Rondo alla turca ist, der Autor sich also seit 250 Jahren nicht mehr für die Fremdnutzungen interessiert und eh jeder weiß, dass das Rondo vom Mozart ist. Trotzdem hat da wohl irgendein Scan angeschlagen und Soundcloud hat ja ach so vollautomatisch angenommen, ich hätte irgendeine Wald-und-Wiesen-Interpretin, die ich gar nicht kenne, kopiert. Soviel zu automatischen Uploadfiltern, nö, kein Bock darauf.

Will mein Zeug nur wohldosiert bis gar nicht mehr zu veröffentlichen. Ich mache ja nicht nur eigene Kompositionen damit, sondern auch Sachen unter Copyright, da mach ich das natürlich eh nicht publik, nur für mich selbst (originäre "Hausmusik"), geb das allenfalls vielleicht mal Freunden/Bekannten bei Besuchen auf die Ohren.
Zumal: Wenn ich irgendwo MP3s hochlade und Freunden sage, hey hört mal, dann tun die das auf ihrem Smartphone. Auf deren Meinung zum Klang kann ich dann beim besten Willen nix geben.

Also hier mal einen Beethoven – Op. 27 Nr. 2, Sonate ähnlich einer Fantasie, volkstümlich auch "Mondscheinsonate" genannt, 1. Satz Adagio sostenuto. Der Klang ist eine Erfindung von mir.



Für die Umsetzung der Komposition habe ich mir die Sheets aus der IMSLP heruntergeladen und händisch in eine YAML-Textdefinition umgesetzt, trainiert ganz gut das Notenlesen, aber das allein hat natürlich nicht viel mit Musikmachen zu tun. Es ist eben eine Klangstudie zum einen und eine Übung im Notenlesen zum anderen, aber das "Musikmachen" zu nennen – zumindest nicht ohne eine Prise Salz ...

Hier mal, wie der Klang als YAML-Text aussieht:
p1: { S: '3:100;1,92;2,80;4,55!;5,86!;35,85;56,84;98,82;154,77' }
p2: { S: '2:100;1,100;2,90;3,89;4,88!;35,87;56,83;98,75;140,60' }
R: '0.2:1;1,1;2,0'
PROFILE:
- { A: '0.1:1,2;2,3', V: 100, S: '@p1' }
- [ 76, 67, 52] # dBFS-Level der Teiltöne bzw. %dB, da positiv
- { V: 48, A: '0.07:1,1', S: { '@p1': 2, '@p2': 3 } }
- [ 50, 51, 46, 34, 44, 43 ]
- { V: 41, A: '0.05:1,1;2,3', S: '@p2' }
SPREAD: [
1, 2, 3, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 10, 11, 12, 11, 13,
13, 13, 14, 14, 15, 15, 15, 17, 16, 17, 17, 18, 18, 19, 19, 20
]
RAILSBACK_CURVE: [27, 4187, '-8+240;0,0;1,8;2,8;13,8;14,8;15,16'] # Oktavstreckung


So eine Datei kann man einfach im Texteditor bearbeiten. Während man probiert, baut sich eine Ahnung auf davon, was man wie ändern, wo man was hinzufügen muss, damit er der Klangvorstellung noch mehr entspricht. Das ist vergleichbar damit, wenn der "konventionelle" Synthetiker an irgendwelchen Potis dreht, Reglern dreht, Patchkabel steckt. An dieser Arbeitsweise ist nichts falsch, versteh mich niemand falsch oder möge dass als Angriff werden, sie spricht mich als programming nerd, dessen liebstes Werkzeug ein versatiler professioneller Texteditor (in meinem Fall vim, wenn den jemand kennt) ist, einfach nicht so an. Und die Ganzzahlen da oben ergeben auch keine Brüche im Envelope oder so, sind nur Koordinaten der Stützpolygone, die bei der Bézier-Bernstein-Approximation die berechnete Kurve umfassen.

Und hier mal ein paar Noten:

title: Sonata Op. 27 No. 2 – Sonata quasi una Fantasia ("Moonlight sonata")
author: L. v. Beethoven

stage: { p: '1|1 0 piano2' }

---
# P01 L1 M1 [1]
_meta: { stress_pattern: '1,0,1,0;1,0,0;1,0,0,0', ticks_per_minute: 960, upper_stress_bound: 80, lower_stress_bound: 75 }
p: { 0: [G#3 4, C#3 48 1-30, C#2 48 1-30], 4: C#4 4, 8: E4 4, 12: G#3 4, 16: C#4 4, 20: E4 4, 24: G#3 4, 28: C#4 4, 32: E4 4, 36: G#3 4, 40: C#4 4, 44: E4 4 }
 

Anhänge

  • moonlight.mp3
    3,2 MB · Aufrufe: 1.788
Coole Sache!
Höre ich da Aliasing aus meinen PC Lautsprechern?
 
Von Soundcloud bin ich wieder abgekommen. Die haben nen Uploadfilter, der angeschlagen hat, obwohl ich explizit geschrieben habe, dass das Mozarts Rondo alla turca ist, der Autor sich also seit 250 Jahren nicht mehr für die Fremdnutzungen interessiert und eh jeder weiß, dass das Rondo vom Mozart ist. Trotzdem hat da wohl irgendein Scan angeschlagen und Soundcloud hat ja ach so vollautomatisch angenommen, ich hätte irgendeine Wald-und-Wiesen-Interpretin, die ich gar nicht kenne, kopiert. Soviel zu automatischen Uploadfiltern, nö, kein Bock darauf.

Will mein Zeug nur wohldosiert bis gar nicht mehr zu veröffentlichen. Ich mache ja nicht nur eigene Kompositionen damit, sondern auch Sachen unter Copyright, da mach ich das natürlich eh nicht publik, nur für mich selbst (originäre "Hausmusik"), geb das allenfalls vielleicht mal Freunden/Bekannten bei Besuchen auf die Ohren.
Zumal: Wenn ich irgendwo MP3s hochlade und Freunden sage, hey hört mal, dann tun die das auf ihrem Smartphone. Auf deren Meinung zum Klang kann ich dann beim besten Willen nix geben.

Also hier mal einen Beethoven – Op. 27 Nr. 2, Sonate ähnlich einer Fantasie, volkstümlich auch "Mondscheinsonate" genannt, 1. Satz Adagio sostenuto. Der Klang ist eine Erfindung von mir.



Für die Umsetzung der Komposition habe ich mir die Sheets aus der IMSLP heruntergeladen und händisch in eine YAML-Textdefinition umgesetzt, trainiert ganz gut das Notenlesen, aber das allein hat natürlich nicht viel mit Musikmachen zu tun. Es ist eben eine Klangstudie zum einen und eine Übung im Notenlesen zum anderen, aber das "Musikmachen" zu nennen – zumindest nicht ohne eine Prise Salz ...

Hier mal, wie der Klang als YAML-Text aussieht:
p1: { S: '3:100;1,92;2,80;4,55!;5,86!;35,85;56,84;98,82;154,77' }
p2: { S: '2:100;1,100;2,90;3,89;4,88!;35,87;56,83;98,75;140,60' }
R: '0.2:1;1,1;2,0'
PROFILE:
- { A: '0.1:1,2;2,3', V: 100, S: '@p1' }
- [ 76, 67, 52] # dBFS-Level der Teiltöne bzw. %dB, da positiv
- { V: 48, A: '0.07:1,1', S: { '@p1': 2, '@p2': 3 } }
- [ 50, 51, 46, 34, 44, 43 ]
- { V: 41, A: '0.05:1,1;2,3', S: '@p2' }
SPREAD: [
1, 2, 3, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 10, 11, 12, 11, 13,
13, 13, 14, 14, 15, 15, 15, 17, 16, 17, 17, 18, 18, 19, 19, 20
]
RAILSBACK_CURVE: [27, 4187, '-8+240;0,0;1,8;2,8;13,8;14,8;15,16'] # Oktavstreckung


So eine Datei kann man einfach im Texteditor bearbeiten. Während man probiert, baut sich eine Ahnung auf davon, was man wie ändern, wo man was hinzufügen muss, damit er der Klangvorstellung noch mehr entspricht. Das ist vergleichbar damit, wenn der "konventionelle" Synthetiker an irgendwelchen Potis dreht, Reglern dreht, Patchkabel steckt. An dieser Arbeitsweise ist nichts falsch, versteh mich niemand falsch oder möge dass als Angriff werden, sie spricht mich als programming nerd, dessen liebstes Werkzeug ein versatiler professioneller Texteditor (in meinem Fall vim, wenn den jemand kennt) ist, einfach nicht so an. Und die Ganzzahlen da oben ergeben auch keine Brüche im Envelope oder so, sind nur Koordinaten der Stützpolygone, die bei der Bézier-Bernstein-Approximation die berechnete Kurve umfassen.

Und hier mal ein paar Noten:

title: Sonata Op. 27 No. 2 – Sonata quasi una Fantasia ("Moonlight sonata")
author: L. v. Beethoven

stage: { p: '1|1 0 piano2' }

---
# P01 L1 M1 [1]
_meta: { stress_pattern: '1,0,1,0;1,0,0;1,0,0,0', ticks_per_minute: 960, upper_stress_bound: 80, lower_stress_bound: 75 }
p: { 0: [G#3 4, C#3 48 1-30, C#2 48 1-30], 4: C#4 4, 8: E4 4, 12: G#3 4, 16: C#4 4, 20: E4 4, 24: G#3 4, 28: C#4 4, 32: E4 4, 36: G#3 4, 40: C#4 4, 44: E4 4 }

Bei dem Thema werden wir bei allen Plattformen solche Filter vorfinden und es wird keine anderen mehr geben, so es sich um EU-Angebote handelt. Siehe aktuelle Reglung zu §13 - gibt's nen Thread zu, wird auch aktiv besprochen,..
Das die Uploadfilter alle schlecht sind ist auch allgemein bekannt, unzuverlässig und da die Plattformen keine Leute haben gibt es auch nur schlechtes oder gar kein Feedback an die Plattform und von ihr, man spricht idR mit Formularen, maximal!
 
Coole Sache!
Höre ich da Aliasing aus meinen PC Lautsprechern?
Dürfte kein Aliasing sein, da ich alle Frequenzen über der halben Sampling-Rate (Nyquist-Schwelle) gar nicht erst render. Oder reicht das nicht, um diese Artefakte auszuschließen?
 
_WIE_ schließt du denn aus, dass die Frequenzen über der Nyquist-Schwelle gerendert werden?

Ich stelle mir die Frage, da ich vor langer Zeit mal versucht habe einen Synthesizer zu programmiern, aber bereits an genau diesem Punkt gescheitert bin. In Gesprächen wurde mir von Experten immer wieder das Stichwort "Upsampling" genannt, aber in wie weit das nutzt, habe ich nicht richtig verstanden.

Ich meine es ging darum, dass man nach dem Upsamplen einen steilflankigeren Filter anwenden kann, so dass nach dem Downsampling weniger Zeugs übrig bleibt, was Aliasing hervorruft. Aaaaber, das wäre ja auch nur eine Entschärfung des Effekts und keine Beseitigung.

Mein Interesse an dem Thema besteht also weiterhin.
 
Zuletzt bearbeitet von einem Moderator:
Ganz einfach, wenn Grundfrequenz*Frequenzfaktor > Samplingrate / 2, beende die Schleife, so die Kurzfassung. Bei der additiven Soundsynthese – mein primäres, in diesem Beispiel sogar einziges Verfahren, nehme ich andere hinzu, werde ich wohl tatsächlich mit Aliasing konfrontiert – ist das eigentlich ziemlich trivial, ob es leider naiv ist, werde ich wohl jetzt von euch erfahren. Du sagst dem (Sompyler-)Instrument, du hättest gern das Klangereignis für die gegebene Note, d.h. ihren Eigenschaften, v.a. die Tonhöhe. Das Instrument bildet zunächst einen Soundgenerator, maßgeschneidert hinsichtlich diesen Eigenschaften gemäß seiner Definition. Ein Soundgenerator weiß nach der Berechnung etwaiger Abweichungen von den natürlichen Harmonischen genau, welche Frequenzen, besser gesagt, welche Faktoren der angefragten Grundfrequenz er rendern muss. Er durchläuft also ganz banal eine Liste von Frequenzen, schichtet eine auf die andere. Bei jedem Durchlauf prüft er zunächst, ob die Frequenz unter der Schwelle bleibt, andernfalls steigt er aus.

Also entweder filtern meine Ohren das Aliasing raus oder ich bin einfach noch auditiv unerfahren, oder ich bin schwerhörig. Letzteres haben mir die Ohrenärzte noch nicht bescheinigt, im Gegenteil höre ich überdurchschnittlich gut für mein Alter, wurde mir mehrmals bestätigt. Unabhängig davon interessiert mich natürlich, welche Schwächen mein Sound hat und wie ich ihnen (gern auch mit anderen Programmen) beikommen kann. Kannst du näher beschreiben, wo du meinst Aliasing zu hören. Vielleicht am Anfang der Klänge, im Attack? Denn dass der Attack rau und spitz klingt, und dann in den unteren Harmonischen einen steilen, aber kurzen Senker hinlegt, war künstlerische Absicht.

Oben gesagtes gilt wie gesagt nur für die additive Synthese, auf die ich mich in vorigem Beispiel beschränkt habe. Anders sieht es aus, wenn ich zum Beispiel Frequenzmodulation hinzunehme.

Hier mal ein anderes Instrument, mit dem dasselbe Stück gespielt wird. Die anfangs inharmonischen Obertöne harmonisiere ich graduell. Aliasing sollte es auch hier nicht geben:
 

Anhänge

  • moonlight_sonata2.mp3
    3,2 MB · Aufrufe: 833
Zuletzt bearbeitet:
Selbes Stück, aber vollständig d.h. alle drei Sätze, quasi "von Hand" aus dem gedruckten Urtext übersetzt – 8891 Noten bzw. 3810 Samples (Noten mit exakt gleichen Eigenschaften werden mit demselben Sample umesetzt). Da es sich um eine eine Klaviersonate handelt, klingt es mit andersartigen Klängen eben anders. Erkennt jemand das Vorbild (konventionelles Instrument), nach dem ich den Sound gestaltet habe? Darüber, dass ein Spieler oder Hersteller dies konventionellen Instruments allen Grund hat, über meinen Sound bestenfalls milde hinwegzulächeln, brauchen wir sicher nicht diskutieren, das ist mir schon klar.



Wer die Klavierversion hören möchte, muss die URL manuell aufrufen und das Anhängsel "_2" rausnehmen. Allerdings mache ich mir keine Illusionen, dass irgendwer das als Klavier anerkennt, für meine Ohren ist es jedenfalls eines, Betriebstaubheit sei dank.
 
Zuletzt bearbeitet:
dein verfahren ist grundsätzlich richtig.
wenn von beginn an alles bandlimited ist, können dinge wie eine lautstärkeänderung oder die summierung mehrerer signale das nicht mehr kaputtmachen.
 
Ich habe um den Sompyler eine kleine Server-App gestrickt, die sozusagen vermittelt zwischen mir, dem Nutzer, und dem Unix-Tool "Sompyler" auf dem Server. Läuft jetzt also im Browser.

Das Teil ist aber hinter einem schnöde browsergenerierten Login verborgen, und vom Design her auch recht rustikal funktional: https://demo.neusik.de/sompyle.

Öffentlich schalten will ich das nicht aus dem Grunde, dass ich Support- und Administrationsaufwand noch nicht recht abschätzen kann und die Sache nach hinten losgeht, wenn ich jetzt Nutzer reihenweise enttäusche. Womöglich gibt es noch Fehler, die ich alleine nicht blicke, und ich bin froh, dass das nicht öffentlich ist.

[... TL;TDRTA = Too long, they won't read that anyway ...]

Wer ausprobieren mag, wie extrem nerdig Klang- und MusikähNeusiksynthese geht: Den Log-in-Dialog kann man auch verwenden, um sich einen Account zu registrieren. Dazu bedarf es einmalig einer privat zu erfragenden Zeichenfolge plus einem Leerzeichen vor dem Passwort, im Anschluss nochmal ohne. Auch nach der Anmeldung gibt es Herausforderungen für deine Geduld.*

Am besten, ich stell hier ein Beispiel ein, so als Appetitmacher für Nerds mit Programmierambitionen und Abschreckung echter Musiker. Ohne Sounddatei im Anhang, da das Forum eh kein Ogg/Vorbis unterstützt, und natürlich um Druck zu erzeugen, oder zumindest um mir einzubilden, dass ich so neugierig mache.

YAML:
stage:
  i: '1|1 0'
instrument i:
  NOT_CHANGED_SINCE: 2021-04-18 09:31:18
  SPREAD: '20:1,3;3,0'
  VOLUMES: '20:100;1,75;2,80!;3,70;5,67'
  TIMBRE: '4800:100;2,85;3,103!;4,83;6,90!;7,84;8,80;9,85!;10,75;12,70;13,70'
  O: triangle
  R: '0.2:1;2,1;3,0'
  PROFILE:
    - match: 1
      A: '0.005:1,3;2,3;4,4'
      S: '2:20;1,17;3,15;7,14'
    - match: 20
      A: '0.012:1,1;3,2'
      S: '1.5:20;3,18;7,15'
    - match: 25
      A: '0.007:1,1;2,3'
      S: '1.3:1;1,0;2,0'
    - match: 2n
      FM: '3.2f@sawtooth;1:3'
    - match: 5n-3
      FM: '2.7f@sine;1:2'
  MORPH:
    - '1 1:1;1,1'
    - '25 2:1;1,1'
    - '3n 100;1,106;3,100'

---
_meta:
  stress_pattern: '2,0,1,0,0;1,0'
  ticks_per_minute: 210
  upper_stress_bound: 100
  lower_stress_bound: 94
  cut: 7
i:
  7:
    - 'Cs3&m oo+2o-'
    - E3 3

---

i: 'Cs4&m7 o_o-_o+_o+2 o-*3'

---
_meta:
  ticks_per_minute: '200;1,190;2,195'
  repeat_unmentioned_voices: true

Außerdem wollte ich nur mal meine neueste Entdeckung ausprobieren: YAML-Highlighting im Beitragseditor in einem XenForo-Board.


Da der Service eigentlich privat und nicht gewerblich ist, muss ich die Zahl probierender User überschaubar halten, um selbst mit großer Wahrscheinlichkeit zum Zuge zu kommen, wenn ich will und tatsächlich mal nicht auf meine lokale Instanz zugreifen kann. Daher gibt es neben technisch bedingten Einschränkungen auch ein paar "Schikanen", die auch der Gerechtigkeit zwischen mehreren Usern dienen sollen.
  1. Es kann sein, dass du dich neu anmelden musst, wenn dein Browser die Anmeldedaten vergessen hat. Es kann sein, dass die Anmeldung nicht funktioniert, nach frühestens einer Stunde ohne Aktion (Rendering-Request an Server) können User gelöscht werden. Dann hilft aber wieder der Trick mit den beiden Versuchen und der geheimen Zeichenfolge vor dem Nutzernahmen beim ersten. Diese Zeichenfolge behalte ich mir vor zu ändern, wenn es mir trotz der Schikanen insgesamt zu viele Anmeldungen von egal wem werden sollten, teile es aber nicht überall mit.
  2. Außerdem kann es sein, dass du nach dem ersten Klick auf "Sompyle" eine Fehlermeldung kriegst à la "Service currently unavailable". Was darunter steht, ist lesenswert. Falls nicht, bist du mindestens eine Stunde sicher vor diesem Fehler, oft länger. So lang ist die Reservierungszeit eines Workers, dann nach kann er einem anderen zugeteilt werden. Es gibt drei Worker. Bis zu 3 Usern können also gleichzeitig sompylen, natürlich dauert es dann für jeden bis zu drei mal so lange. Du kannst deine Position in der Warteschlange verbessern durch wiederholte Abfragen mit gleichmäßigen Abständen dazwischen. Abhängig von deiner Netzverbindung und der Auslastung der Route zum Server kann die beste Zeit zwischen zwei Versuchen durchaus Minuten betragen.
  3. Auch die Anzahl an Samples, die ein User insgesamt generieren kann, ist beschränkt, und zwar auf eine Milliarde. Das ist nicht viel. Die Samplingrate beträgt 44,1 kHz. Jede Hüllkurve und jede Modulation (von jedem Layer eines distinkten Tons) geht für sich in die Rechnung ein. Sobald dieses Quota aufgebraucht ist, muss er mindestens drei Stunden pausieren. Wenn er früher seinen Worker an einen anderen User verliert, da die Reservierungszeit abgelaufen ist, ist das hinreichend, dass er bei der nächsten Zuteilung eines Workers wieder volle Quota hat.
  4. Auch der Cache pro User und Worker ist limitiert auf 800MB. Wenn das ausgereizt ist, kann er dem abhelfen, indem er Änderungen an seinem Score zurücknimmt, also mehr Noten wiederverwendet. Hierzu kannst du auch Dynamik und Agogik reduzieren. Ein distinkter Ton wird für alle Noten mit den fließkommawertgenau gleichen Eigenschaften wiederverwendet.
  5. Die maximale Tracklänge ist begrenzt auf 16min 40, also 44,1 Millionen Stereosamples.
  6. Der eingegebene Score (Noten, instrumentdefinitionen, etc.) bleiben nur so lange auf dem Server gespeichert und ist per Button wiederherstellbar, wie der User einen Worker reserviert hat. Wird der an einen anderen User umgeschrieben, überschreibt dessen Eingabe den Speicher.
  7. Wer diese Einschränkungen nicht dulden möchte, und aber Python-Kenntnisse besitzt, kann sich gerne auf eigene Hardware eine Instanz installieren. Code, Dokumentation und gern auch eure Fragen und Fehlerberichte auf Gitlab.
 
Zuletzt bearbeitet:
Ich habe etwas Dokumentation im projekteigenen Wiki verfasst, die erstmals den Namen verdient, wie ich meine. Wann immer ich hier Sompyler code mit meinen Soundbeispielen gepostet habe, werdet ihr euch wohl gedacht haben, was schreibt der Kerl da, und warum, und ihr habt das sicher schulterzuckend überscrollt. Wohl denn, wehn es interessiert, der muss wohl ein Nerd mit Neigung zur deklarativen Programmierung sein. Viel Spaß damit, und (gerne deutsch-sprachige) Kommentare sind willkommen.
 
Noch ein Beispiel, 32 technoide Takte, ziemlich minimal, denn ich will ja, dass irgendwer den Text versteht und Verstehen setzt Überschauen voraus. Zwischenzeitlich noch etwas an der Kickdrum weitergewerkelt.

YAML:
stage:
  d: 1|1 0
  r: 1|1 4

instrument d:
  NOT_CHANGED_SINCE: '2021-06-23 07:22:53'
  A: '0.013:1,2;2,2'
  R: '0.35:1;1,0'
  FM: '4.7f[1;1,0;2,0];5:1'
  VOLUMES: '30:100;3,85;5,65'
  PROFILE:
  - match: 1
    S: '0.2:5;10,3;13,1;15,1;17,0'
    FV: '12;1,5!;5,5'
  - match: 10
    A: '0.01:1,1;2,1'
    FV: '3;1,1;5,1'
  - match: 25
    A: '0.002:1,1;2,1;4,1'
    S: '0.12:3;5,2;8,0'
    FV: '1;1,1;5,1'

instrument r:
  NOT_CHANGED_SINCE: '2021-06-20 09:00:00'
  character:
  - SPREAD: [0, 5, -3, 4, -2, -1, 3, 7, -6]
    A: '0.03:1,1'
    R: '0.3:1;2,1;3,0'
  - ATTR: pitch
    30:
      VOLUMES: '15:100;1,70;5,65'
      PROFILE:
        - match: 1
          S: '100;3,85;5,75'
        - match: 15
          S: '100;1,85;5,70'
    250:
      VOLUMES: '15:100;1,55;2,55;5,40'
      PROFILE:
        - match: 1
          S: '0.5:100;3,85;5,75'
        - match: 15
          S: '0.3:100;1,75;5,70'

---
_meta:
  stress_pattern: 3,1,2,0
  ticks_per_minute: 160
  lower_stress_bound: 97
  upper_stress_bound: 100
d: A1 oooo
r:
  - F1 oooo
  - D1 4 .o__..o_o__..o--__

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
d: A1 oooo
r:
  - F1 oooo
  - D1 4 .o__..o_o+7o=_..o-9__

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
d: A1 oooo
r:
  - F4 4 oo+4_. o_..*3
  - D1 4 .o__..o_o__..o--__

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }

---
_meta: { repeat_unmentioned_voices: true }
r:
  - F4 oo+4o--o--
  - D1 4 .o__..o_o+7o=_..o-9__ >rumble

---
_meta: { repeat_unmentioned_voices: true }
r: ['F4 oo+3o--o-5', <rumble]
---
_meta: { repeat_unmentioned_voices: true }
r: ['F4 oo+4o--o--', <rumble]

---
_meta: { repeat_unmentioned_voices: true }
r: ['F4 oo+3o--o-5', <rumble]
---
_meta: { repeat_unmentioned_voices: true }
r: ['F4 oo+4o--o--', <rumble]

---
_meta: { repeat_unmentioned_voices: true }
r: ['F4 oo+3o--o-5', <rumble]
---
_meta: { repeat_unmentioned_voices: true }
r: ['F4 oo+4o--o--', <rumble]
---
_meta: { repeat_unmentioned_voices: true }
r: ['F4 oo+3o--o-5', <rumble]

Ist das nicht cool, unsere Kinder von morgen müssen nicht mehr die einzelnen Frames von Youtube-Schminkvideos auf Höhlenwände pinseln (so ein Sonnensturm macht auch vor Google-Rechenzentren nicht halt), sondern nur noch diesen Text, dann ist wenigstens ein bisschen Musik in die Zukunft gerettet.

Soundupload gibts nicht, habe ja beschrieben, wie man daraus Audio machen kann. Na gut, will mal nicht so sein: wenn wer ne halbwegs aktuelle Spendenquittung für Ärzte ohne Grenzen, Greenpeace oder Unicef hochlädt ... :D

EDIT 2023-01-08: Oh, ich sehe gerade unten @sushiluv s Spende und meine ältere, aber verpeilterweise zusammenhanglose Antwort darauf, diese eben gelöscht. Hier das Synthat zu obigem Source code:
Anhang anzeigen techno.ogg
Schönen Sonntag
Neusiker.
 
Zuletzt bearbeitet:
Hier mal ein Video, nur ne Demo meines Workflows, annotiert in Schriftform. Musik gibt es am Ende auch, nämlich bei 48m09s.

 
Zuletzt bearbeitet:
Mein Beitrag zum Remix-Battle:
Dieser Track ist gänzlich ohne Synthesizergear entstanden, auch mein E-Piano hab ich dafür nicht angefasst. Eine DAW habe ich auch nicht benutzt. Ob ich das verwendete Programm als eine Art Text-DAW bezeichnen kann, habe ich Zweifel.

Ich habe den Track gescriptet und komplett offline berechnen lassen, was auf meinem 2013 gebraucht gekauften Businesslaptop (Core 2 Duo, 2.26GHz) eine halbe Stunde dauerte und ca. 300MB Arbeitsspeicher benötigte, sowie 117MB Festplattenplatz.
  1. Score-file, diese Datei wird dem Programm zum Fraß vorgeworfen.
  2. fh/sonor2, eine in ersterem referenzierte Klangdefinition, verwendet für die Noten aus der Feder von @spurkopf
In dem Script ist alles teils enthalten, teils referenziert, woraus am Ende die 2m:48s x 44.1KHz Stereosamples berechnet werden können. Die Skriptsprache habe ich entwickelt, allerdings auf Grundlage des Datenserialisierungsformats YAML. Mir war es wichtig, dass sie frei war von Konstrukten der imperativen Programmierung (etwa Bedingungen und Schleifen), alles sollte deklarativ sein, auch sollte es überwiegend Ganzzahlen geben. Angaben im kontinuierlichen Wertebereich sollten soweit möglich mit Verhältnissen ganzer Zahlen ausgedrückt oder anders aus ganzen Zahlen als Grundlagen berechnet werden. Ganzzahlen haben den Vorteil, dass mein Lieblingstexteditor VIM diese, wenn der Cursor darauf steht, inkrementieren und dekrementieren kann per Strg-A und Strg-X, ohne dass ich in den Editiermodus wechseln muss. Das ist der Betätigung von Fadern entfernt vergleichbar.

Die Skriptsprache listet hauptsächlich auf, welche Noten von welcher Stimme in welchem Takt und wann darin zu spielen sind. Musikalische Aspekte wie Betonung und Tempo, sowie auch die Dauernverhältnisse von Tönen etwa für den Swing-Rhythmus (hier 3 Onbeatlängen : 2 Offbeatlängen pro Zählzeit je ein Viertel identisch lang), sind von den Noten wegabstrahiert, in den taktbezogenen Metadaten. Denn auch wenn man einem einzelnen Ton anhören könnte, dass er Teil eines Swingstückes ist, bedeutet es nicht, dass Swing zu der einzelnen Note kodiert werden muss. Auch die Betonung muss nicht zu jeder einzelnen Note kodiert werden. Die Betonungsverhältnisse sowie etwaige dynamische Variationen lege ich lieber taktbezogen fest. Das Programm kann besser berechnen diese Verläufe auf den einzelnen Ton herunterrechnen. Ausnahmen von den taktweise definierten Verläufen, die bestimmte Töne betreffen, sollen nicht unmöglich sein. Aber eben Ausnahmen. Ein Musiker, der eine Tabellenkalkulation bemüht, ist auch für mich eine komische Vorstellung.

Im Script sind keine genauen Frequenzangaben enthalten. Nur Notenbezeichnungen wie "G#3". Das Mapping zu den Frequenzen existiert aber nicht in Form einer Liste oder so, aus Entsprechungen von Namen und Zahlen. Sondern es gibt im Installationsverzeichnis des Synthesizers eine Datei tones_de+en_euro.splt mit Angaben, aus denen dieses Mapping beim Start des Programms berechnet wird. Im Ergebnis ist es durch eine simple Angabe (s.u. "just5lim") möglich, die Musik mit reiner Stimmung zu rendern. Der Wettbewerbsbeitrag hatte noch die gleichstufige Stimmung, denn ich war mir unsicher, ob die reine passt.

Außerdem erst nach Einreichung des Wettbewerbsbeitrags habe ich auf jemandes Anregung hin den Bass (b) als eigenständige Stimme hinzugefügt.

Die Skriptdatei habe ich auf Englisch kommentiert. Persönliche Gewohnheit von mir, in Quelltexten kann ich nun mal leider kein Deutsch schreiben.

Spätestens wenn ihr euch fragt, warum ich nach den expliziten Notennamen Folgenoten in so einer kryptisch-kruden Kurzschreibweise angebe, muss ich wohl euch eine gute Erklärung schuldig bleiben. Hier der Versuch einer Erklärung: Eingedenk dessen ich absehbar eh der einzige Benutzer dieses Programms sein werde und ich daher meiner Vorliebe für einzelne Tastendrücke als Befehl ans System fröhnen kann, wurde es mir einfach zu öde, nachdem ich den ersten Satz der Beethoven'schen Mondscheinsonate durchexerziert hatte mit lauter expliziten Noten. Ich habe mich gefragt, wie Melodieläufe im Kopf eines Pianisten abgespeichert sein könnten und befand: kürzer. Jedenfalls nicht Note für Note.

Diese komprimierte Syntax umfasst Dinge wie relativ-kumulative Tonhöhenänderung (chromatisch, diatonisch oder harmoniegebunden, abhängig von bestimmten Anhängseln an die Ausgangsnote), Rückkehr zum Ausgangston, beliebige Längen, fingerpedalartige Überlängen, Wiederholungen, Klammergruppen, in denen alle Noten zusammen auf einen Tick komprimiert und ggf. wieder gemeinsam verlängert werden je nach Verlängerung, und natürlich Pausen. Neu angeschlagene Noten werden mit 'o' abgekürzt. Oder mit anderen Buchstaben. Diese Buchstaben werden als "Artikel" definiert: Assoziationen von Buchstaben mit Noteneigenschaftengruppen. Wird ein anderer Buchstabe als 'o' an einer Taktposition verwendet, wird die betreffende Note mit den jeweiligen Eigeschaften versehen. Wird diese Eigenschaft als Verlauf im Takt definiert, wird der letztendliche Wert abhängig von der Taktposition berechnet.
 
Warum hört sich der Remix-Thread-Beitrag "Swinging Wire Phones" eigentlich so schräg / in sich verstimmt an?
Hast Du den einzelnen Noten über den Sompyler nicht-harmonische, verstimmte Obertöne spendiert? Tuning war ja wie heute gewohnt und kann es daher eigentlich nicht sein?
 
Du meinst den, den ich zum Wettbewerb eingereicht habe, der auf SC liegt? Der korrigierte hat ja reine Stimmung und es kann sein, wenn du diesen hörst und dann die eingereichte Version, dass du das dann als Verstimmung wahrnimmst. Aber ja, die Obertöne der Drums vor allem und die des Basses sind nicht ganz harmonisch. Auch die mal mehr, mal weniger starke Frequenzmodulation könnte diese Wirkung haben, denn jeder Layer hat seine eigene, mit einer leicht abweichenden Modulationsfrequenz. Deine Ohren sind gewiss empfindlicher als meine.
 
Da Bearbeiten aktuell oder nicht mehr möglich ist, hier ein Addendum: Krumme Modulationsfrequenz (Faktoren der Trägerfrequenz) führen eh zu Inharmonischen. Der Modulationsindex fällt zwar schnell ab, das Anschlagsgeräusch bleibt aber inharmonisch.

YAML:
# [...]
  FM: "3.52f[0,2;1,1;3,1;4,0];1:5"

- ATTR: whe
  # Wenn der Note ein Parameter "whe" mitgegeben wird, ändere Klang wie folgt:
  10:
    VOLUMES: "10:110;1,92;2,97;4,90;7,85"
    PROFILE:
    - match: 1
      FM: "3.12f@triangle[2;1,1;3,1;4,0];1:2"
# [...]
    - match: 10
      FM: "3.27f[2;1,1;3,0];1:3"
 
Du meinst den, den ich zum Wettbewerb eingereicht habe, der auf SC liegt? Der korrigierte hat ja reine Stimmung und es kann sein, wenn du diesen hörst und dann die eingereichte Version, dass du das dann als Verstimmung wahrnimmst. Aber ja, die Obertöne der Drums vor allem und die des Basses sind nicht ganz harmonisch. Auch die mal mehr, mal weniger starke Frequenzmodulation könnte diese Wirkung haben, denn jeder Layer hat seine eigene, mit einer leicht abweichenden Modulationsfrequenz. Deine Ohren sind gewiss empfindlicher als meine.
Danke für die Info! Vermutlich kommt es dann durch die FM, denn ich empfinde die Töne in beiden Versionen als in sich etwas unrein.
Dieses leicht Verstimmte wirkte auf mich wie ein absichtlich eingesetztes Stilmittel, damit man beim Hören etwas irritiert wird, und es passte ja auch gut zum Wire Phones-Titel.
 
Leute, die sich nicht mit Linux, mit der Bash und mit "curl" oder Alternativen aus dem Werkzeugkasten eines REST-Entwicklers auskennen, werden in diesem Post vermutlich nur Bahnhof verstehen. Dafür sind sie auf dem Bereich der elektronischen Musik firmer als ich.

Der Webservice-Wrapper um den Sompyler, Neusician, kann jetzt auch via REST-API benutzt werden. Alles noch experimentell und in der Entwicklung befindlich, für nix Produktives also. Wer an dem "$SECRET" interessiert ist, von dem gleich eingangs die Rede ist (das ich immer dann ändere, wenn ich selber den Service kaum noch nutzen kann wegen zu vieler, d.h. aktuell mehr als 3 paralleler Zugriffe), möge sich per PN mit mir in Verbindung setzen.

Kleine Demo
 
Neben der REST-Schnittstelle arbeite ich ja auch, wie schon weiter oben im April '21 erzählt, an einer für Ottonormalnerd (etwa mich, spontan unterwegs) bedienbaren Webschnittstelle.

Auf meinem kleinen virtuellen Server im Netz betrieben, kann ich nun auch unterwegs im einfachen Webbrowser Musik machen. Jedes Billigsmartphone packt das, und die Sache geht nicht auf die Akkulaufzeit.

Audioschnittstellen im Webbrowser, wenn auch noch so W3C-standardisiert (WebAudio), lass ich links liegen, das kriegen bestimmt nicht alle Browser und Soundstacks richtig hin ohne Verrenkungen.
Das eigentliche Rendern der Audiodatei läuft auf dem Server, was bedeutet, dass ich nun bestimmt 99% meiner potenziellen Zielgruppe wegen Ungeduld vergraule. Denn wie bei der REST-Schnittstelle lasse ich auch hier nur bis zu 3 Arbeitspferdchen (CPU-zeitintensive Prozesse) laufen, einer pro User für eine Stunde reserviert, solltens mehr probieren, kommen die solange nicht durch -- Service temporarily unavailable + waiting rank. Ist insofern vertretbar, dass Sompyler und Neusician ja GPL-Software sind und auf eigener Hardware betrieben werden könnten.
Screenshot_20230127-094905.png
Die Syntax, die hier oben zu sehen ist, ist kein YAML. Diese optionale "write only" Kurzschreibweise habe ich in einem Anflug von Komplexitätsgeilheit als domänenspezifische inoffizielle Erweiterung von YAML realisiert, die auf Mobilgeräten leichter einzugeben ist als reines YAML oder JSON mit den vielen Einrückungen oder Klammern, und um in Foren und anderen fremden Seiten Sompyler-Scores in Codetags reinstreuen zu können, bin halt voll krass subversiv, ohne dort aufdringlich viel wertvollen Platz wegzunehmen (Spoilerblöcke sind mir, wo vorhanden, zu aufdringlich). Etwa so:
Code:
title: Freie Laute ;0solo: ;1character: ;1- A: 0.03:1,7*2;4,8 ;2R: 0.15:3;2,2;3,0 ;2VOLUMES: [100, 85, 92, 85, 87, 78, 65, 62, 59] ;1- ATTR: morphed ;2 10: ;3TIMBRE: 1500:100;3,67;5,89*2;10,75;12,73 ;3MORPH: ;3- 1 9;1,11;3,8 ;3- 9 6;1,4;2,5;3,4 ;3PROFILE: ;3- match: 1 ;4S: 2:100;4,80;10,85;13,70 ;3- match: 9 ;4S: 100;6,75;9,70 ;2 1: ;3TIMBRE: 1800:100;3,67;5,89!;10,85;12,73 ;3A: 0.01:1,4;2,5 ;3MORPH: ;3- 1 6;1,4;2,5;3,4 ;3- 9 9;1,10;3,8 ;3- 2n+1 2:10;1,11;2,9;3,10 ;0measures: ;1beats_per_minute: 67 ;1stress_pattern: 2,1;2,1,0;1,0 ;1upper_stress_bound: 100 ;1lower_stress_bound: 95 ;1elasticks_pattern: 3;2,3,1,2 | _articles: ;1o: { morphed: "3;1,10;4,1" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "3;1,10;4,1" } ;0 0: E2 o_.o+.=__o==_ | _articles: ;1o: { morphed: "3;1,10;4,1" } ;0 0: E2 o+_.=.o__o==_ | _articles: ;1o: { morphed: "3;1,10;4,1" } ;0 0: E2 o_.o.o__o+==_  | _articles: ;1o: { morphed: "3;1,10;4,1" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "3;1,10;4,1" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "3;1,10;4,1" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "3;1,10;4,1" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "7;2,8;5,1" } ;0 0: E2 o_.o.o__o++==_ | _articles: ;1o: { morphed: "7;2,8;5,1" } ;0 0: E2 o_.o+.o__o==_ | _articles: ;1o: { morphed: "7;2,8;5,1" } ;0 0: E2 o+_.=.o__o==_ | _articles: ;1o: { morphed: "7;2,8;5,1" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "7;2,8;5,1" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "7;2,8;5,1" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "7;2,8;5,1" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "7;2,8;5,1" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "1-10" } ;0_meta: ;1elasticks_pattern: 3;2,1,3,2 ;1elasticks_shape: 8;1,7 ;0 0: E2 o_.o.o__o+3==_ | _articles: ;1o: { morphed: "1-10" } ;0_meta: ;1elasticks_shape: 8;0,7;1,6 ;0 0: E2 o_.+.=__o==_ | _articles: ;1o: { morphed: "1-10" } ;0_meta: ;1elasticks_shape: 8;0,6;1,5 ;0 0: E2 o+_.=.o__o==_ | _articles: ;1o: { morphed: "1-10" } ;0 _meta: ;1elasticks_shape: 8;0,5;1,4 ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "1-10" } ;0_meta: ;1elasticks_shape: 8;0,4;1,3 ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "1-10" } ;0_meta: ;1elasticks_shape: 8;0,3;1,2 ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "1-10" } ;0_meta: ;1elasticks_shape: 8;0,2;1,1 ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "1-10" } ;0_meta: ;1elasticks_shape: 8;0,1;1,0 ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "L1;P3,4;1,5,6;1,4;U10" } ;0_meta: ;1elasticks_pattern: 3;2,3,1,2 ;1elasticks_shape: false ;0 0: E2 o_.o.o__o+4==_ | _articles: ;1o: { morphed: "L1;P3,4;1,5,6;1,4;U10" } ;0 0: E2 o_.+.=__o==_ | _articles: ;1o: { morphed: "L1;P3,4;1,5,6;1,4;U10" } ;0 0: E2 o+_.=.o__o==_ | _articles: ;1o: { morphed: "L1;P3,4;1,5,6;1,4;U10" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "L1;P3,4;1,5,6;1,4;U10" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "L1;P3,4;1,5,6;1,4;U10" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "L1;P3,4;1,5,6;1,4;U10" } ;0 0: E2 o_.o.o__o+==_ | _articles: ;1o: { morphed: "L1;P3,4;1,5,6;1,4;U10" } ;0 0: E2 o_.o.o__o+==_

Echtes YAML oder JSON geht aber auch.

Screenshot_20230127-100229~2.png
Vor der Verarbeitung wird diese "write only" Kurzschreibweise in richtiges YAML umgewandelt, um es auch lesen und ändern zu können. Ist halt nicht so nerdig, dafür komm ich auch damit zurecht, wenn ich mal alt und dement bin.

Ach ja, hier noch die generierte Audiodatei, nicht sehr einfallsreich allerdings: Nominell stets die (fast) gleichen Noten in jedem Takt, variiert nur in den Eigenschaften, die nicht notierbar sind. Könnte ich Musik, müsste ich dieses Unvermögen nicht sublimieren mit diesem ganzen Schmonz:

Anhang anzeigen freielaute.ogg
 
Zuletzt bearbeitet:

Takt, Stimme, Stammnoten und Tongruppen


Anforderungen, die die deklarative Sprache des "Sompylers" (engl. sowas wie Sompyler sound & music definition language) erfüllen soll:
  • schreib- und lesbar durch Erfahrene, wobei die Syntax "mitwächst" mit dem Erfahrungsstand, also Anfänger für Anfänger, Fortgeschrittene für Fortgeschrittene schreiben können.
  • eindeutig interpretierbar mit einem YAML-Parser (verwendeter Fremdcode, eingebunden als Abhängigkeit bei der Installation) und selbstverfassten sogenannten regulären Ausdrücken, die strukturierten Text weiter aufdröseln. Reguläre Ausdrücke sind ein Begriff aus der Informatik und im wesentlichen das Geheimnis hinter Software, die Text ohne viel Metainformationen verwerten kann, etwa deutsche und internationale Datumsangaben zugleich verstehen kann.

Am Anfang gabs nur die simple Notation:
Code:
voicename: # Muss in der Preambel, unter "stage" deklariert sein.
  0: B3 1 # B3 = h
  2: [A3 1, E3 1] # zwei Töne zu gleichen Zeit, als YAML-Liste, oder auch
  2:
  - A3 1 # das ist das "ausführlichere" Listenformat,
  - E3 # das lt. YAML-Spezifikation unterstützt wird. Länge 1 Tick implizit.
  2: # noch ausführlicher: Key/Value-Mappings
  - { pitch: A3, length: 1 } # diese Mappings können lt. YAML so ausgedrückt werden
  - pitch: E3  # oder auch so. Hier können auch instrumentspezifische Notenattribute angegeben werden.
    length: 1 # optional, wo eine "chain: ..." mit einer Tongruppe angegeben ist oder die Länge 1 Tick.
  4: C4 2 # bedeute: Nach 4 Ticks ab Taktanfang spiele das mittlere C 2 Ticks lang.

Daraus haben sich kürzere Varianten entwickelt.

Bevor wir diese behandeln, müssen wir aber eine Festlegung zu den Takten treffen, damit die Beispiele tatsächlich gerendert werden. Voreinstellung ist nur zu Einzelklangproben geeignet, 1/1 Taktart = 1 Tick = 1 Sekunde. Mehr als einen Tick würde die Software nicht akzeptieren, leere Folgetakte erwarten.
Das hierfür zentrale stress_pattern gibt an, wie stark die Ticks betont werden und wie viele Ticks der Takt überhaupt hat. Die Anzahl der Ziffern vor dem ersten Semikolon oder dem Ende des Strings, das sind die Beats und als solche nach dem Semikolon weiter unterteilbar, und bestimmt die Zeit, wie lange jeder Takt dauert, im Zusammenhang mit beats_per_minute. Neben "voicename:", natürlich nur exemplarisch so genannt, benötigt der erste Takt also noch:

Code:
_meta:
  stress_pattern: 2,1,1;2,0,1,0 # 3/4-Takt = 12 Sechzehntel
  # oder
  stress_pattern: 2,1;2,1,1;1,0 # 6/8-Takt = 12/16
  beats_per_minute: 90 # Beat = Viertel bzw. punktierte Viertel (3/8) die Minute
                          # jedenfalls gilt die gröbste Takteinteilung
  upper_stress_bound: 100 # Angabe in dBFS erhöht um 100
  lower_stress_bound: 94 # ebenso
  # [OT] Bsp. wie stark wird der Tick #9 in 6/8-Taktart betont?
  # [OT] #9 ist der der erste Sechzehntel-Tick im zweiten Achtel des zweiten punktierten Viertels in 6/8-Taktart, also 1 * (1/2) * (1/2) = 1/4 von 100 - 94 = 6, also 94 + 6/4 = 95,5 dBFS.
voicename: ...

Da ich mir ehrgeizigerweise zum Test nicht nur die Literatur aus meinem suspendierten Klavierunterricht, sondern darüberhinaus virtuose Literatur ausgesucht habe, war ich die Tipparbeit bald leid. So habe ich eine konzisere alternative Syntax als Erweiterung der Note entwickelt:

Code:
voicename: B3 6 o.--;-5.+8_

Sei die Syntax wie folgt erklärt:
  • Start-Offset 0 implizit, kann aber angegeben werden durch Einleitung "0:" eingerückt auf neuer Zeile. Ebenso kann der vorausgehende Spiegelstrich fehlen, wenn es sich nur um eine (Stamm-)Note für dieses Offset handelt. Aber vollständig:
    Code:
    voicename:
      0:
      - B3 6 o.--;-5.+8_
  • "6" (Ticks) gibt die Gesamtlänge an. Kann weggelassen werden, ersatzweise gilt die eigentliche Länge der Tongruppe.
  • "o" bedeutet eine Note ohne besondere Eigenschaften. Pitch und Stress aus dem Kontext. "o" ist der einzige vordefinierte Artikel. Folgende Angabe zur Stimme voicename ist daher unnötig:
    Code:
    voicename:
      _articles: # gilt für diesen Takt
        o: {} # muss nicht explizit angegeben werden
        # Beispiele für weitere Artikel:
        a: { add_stress: 2 }
        label: { surd: true } # mehrbuchstabig, daher nur zur Erweiterung für o, a, ... # wie "surd" den Klang ändert, bestimmt Instrumentenspezifikation.
        _all: { ... } # Ausgangsbasis für alle Artikel
    # "articles"-Mapping in "stage" vor dem ersten Takt, in der Definition von "voicename" dort, mit Geltung für alle Takte, sowie "articles" neben "stage" mit Geltung für alle Takte und Stimmen werden unterlegt. Artikeleigenschaften an dieser Stelle haben stimm- und taktgebunden Vorrang.
  • "." einen Tick Pause.
  • "--", alternativ "-2" gleiche Note (o) aber einen Ganzton / 2 Halbtöne tiefer.
  • ";" a) ohne Leerzeichen dahinter: folgender Ton tönt gleichzeitig mit dem letzten und ist genauso lang. b) Mit Leerzeichen dahinter bezieht sich die Gleichzeitigkeit auf alle Töne zwischen den umgebenden Klammern, bzw. Anfang und Ende der ganzen Tongruppe. Die "; "-separierten Teile müssen dabei von gleicher eigentlichen Länge sein. o.--; -5.+8_ würde nicht akzeptiert werden, der erste Teil wäre um einen Tick zu erweitern oder der zweite zu verkürzen.
  • "-5" Note eine Quarte tiefer (5 Halbtöne).
  • "+8" kleine Sext höher.
  • "_" Dauer der letzten Note um einer Tick verlängern. Folgt "_" nicht auf einen Artikel, einer schließenden Klammer oder eine Tonhöhenverschiebung, bewirkt sie einen erneuten Anschlag mit den Eigenschaften der letzten Note.
  • Vor "--", "-5", "+8" kann "o" stehen oder ein anderer sogenannter Artikel, ggf. erweitert um ":label", wobei label eine Artikelerweiterung mit längerem Bezeichner ist. Verwendete Artikel müssen definiert worden sein mit einem oder mehreren Notenattributen. Notenattribute dienen wiederum in Instrumentenspezifikationen zur Variabilisierung des Klangs, demnächst mehr dazu.
Die Längenangabe ("6 ") kann, muss aber nicht sein, wenn die Länge aus einer angehängten Tongruppe abgeleitet werden kann. Entspricht die Angabe nicht der eigentlichen Länge der Tongruppe, wird diese entsprechend gestreckt bzw. gestaucht. Besteht kein sauberes Teilungsverhältnis zwischen beiden Längen, weil ein Lese- oder Schreibfehler vorliegt, muss man das am Ergebnis hören. So genannte "N-tolen" können natürlich auch beabsichtigt sein. Eine unsaubere, resthaltige Teilung muss durch zwei Angaben explizit gemacht werden, sonst wertet die Software das als Notierungsfehler: z.B. "3:2" bei einer Triole, wobei 3 die eigentliche, 2 die effektive Länge angibt, entlehnt der traditionellen Notation.

Ist die Gruppennotation zu unübersichtlich, kann sie per Leerzeichen aufgesplittet werden. Einzelne durch Leerzeichen aufgesplittete Segmente können wiederholt werden durch anschließendes "*", ggf. mehrfach per "*3" oder "**", gar " * *" zur vertikalen visuellen Strukturierung, wobei beliebig Leerzeichen gesetzt werden können.

Klammern bewirken die Zusammenstauchung des Inhalts auf einen Tick. Um ihn auf die gewünschte Länge zu bringen, gibts zwei Möglichkeiten:
Code:
B3 (o. --;-5. +8_)* # 2 Ticks lang!
# oder mit Länge am Anfang
B3 12 (o. --;-5. +8_) * # 12 Ticks lang
# oder mit Längenanpassung der Klammerung
B3 (o. --;-5. +8_)_5 * # 12 Ticks lang

In den beiden ersten der drei Varianten könnten die Leerzeichen in der Klammer entfernt und auch die Klammern selbst weggelassen werden. So handelt es sich garantiert um 12 Ticks:
Code:
B3 o.--;-5.+8_* # 12 Ticks lang
Aber Achtung: die Note o im zweiten Durchlauf geht von der Tonhöhenänderung des ersten bzw. letzten Durchlaufs aus, liegt also auf Tonhöhe C4!
Dies kann entweder verhindert werden durch Klammerung (s.o.) oder durch "=" nach dem Artikel. Das Gleichheitszeichen anstelle von ±n bedeutet Tonhöhe zurücksetzen auf Stammnote oder, falls in einer Klammerung, der letzten Note vor der letzten öffnenden Klammer.

Klammerung hat den Vorteil, dass ihr auch direkt eine Zahl folgen kann, die angibt, wie viele Durchläufe ihres Inhalts in einen Tick passen sollen. Da Tondauern verkürzt werden können bis zur Attackzeit, dann nur noch weiterzusammengeschoben werden, egeben sich interessante Überlagerungseffekte.
Code:
B3 (o. --;-5. +8_)10*12
Dies notiert 10 Durchläufe à 6 Ticks zusammengestaucht auf einen Tick und dies zwölfmal. Wir haben hier schon bei 90bpm den Bereich des von Menschen spielbaren Bereichs verlassen und betreten den der Klangflächen. Dies erlaubt freie Klanggestaltung, ohne die Instrumentspezifikation anzufassen.

Schwirrt dir der Kopf, ist dir diese Notation noch immer zu unübersichtlich, können Stammnoten vorgezogen werden:
Code:
voicename: B3 o., A3 ; E3, C4 2
  • , (Komma, Leerzeichen, Stammnote) bedeutet "nachfolgend"
  • ; (Leer, ;, Leer, Stammnote) zeigt Gleichzeitigkeit von dem vorstehenden Teil ab dem letzten Komma oder dem Anfang, und dem Teil bis zum folgenden Komma oder dem Ende.
  • jeweils braucht die Längenangabe und/oder Tongruppe nur beim ersten Glied angegeben werden. Für die folgenden Glieder ohne diese Angabe wird sie implizit übernommen.

Skalen und Akkorde​


Eine einfache Stammnote notiert nicht nur ihren Ton, sondern auch verwandte Töne. Die Akkord- oder Skalentyp wird an den Tonnamen anghängt, das Trennzeichen "&" kann weggelassen, außer bei Durdrei- und vierklängen und wenn der Tonname auf einer Oktavnummer endet.

Schränkt die Stammnote den Zwölftonraum auf diese Art ein, bezieht sich die Tonhöhenänderung ±n jeweils auf den n-nächsten bzw. n-letzten Ton innhalb der Skala oder des Akkords, kann also jeweils einen, manchmal zwei Halbtöne überspringen.
  • "C4" notiert das mittlere C im Zwölftonraum.
    Code:
    C4 o +*4
    notiert 5 Töne, je 1 Tick, nämlich C4, C#4, D4, D#4 und E.
  • "C4&" impliziert das mittlere C im C-Dur-Dreiklang.
    Code:
    C4& o +*3++
    ist gleichbedeutend mit C4, E4, G4, C5, G5
  • "C4&m" oder "C4m" impliziert das C4 im Molldreiklang. Das & kann hier weggelassen werden.
    Code:
    C4m o +*3++
    : C4, Eb4, G4, C5, G5
  • Code:
    C4&7 o +*4
    (& muss hier sein, da es kein 47. C gibt) ist gleichbedeutend mit C4, E4, G4, Bb4, C5
  • Code:
    C4m9 o ++ +*4
    : C4, Eb4, G4, Bb4, C4, D4. Die None des Septnonen-Mollakkords wird zur Sekunde gradiert, deshalb müssen wir sie zunächst überspringen. Nicht ideal, aber technisch logischer.

Entsprechend weitere Akkordtypen: m7, &6, m6, &7b5, &m7b5, dim, dim7.

Unser Beispiel könnte man demnach auch so notieren:
Code:
A3m9 o+.=;-.++_

Komplette siebentönige Skalen​

Die Kürzel von Skalen fangen konventionell mit einem Großbuchstaben an. "&" kann stehts weggelassen werden, wenn der Tonname eine Oktavnummer enthält (angelsächsische Tonnamen).
  • Code:
    C4Mn o +*7
    : C4, D4, Eb4, F4, G4, Ab4, Bb4, C5
  • Code:
    C4Hm o +*7
    : C4, D4, Eb4, F4, G4, Ab4, B4, C5
  • Code:
    C4Mm7 o +*7
    : C4, Db4, Eb4, Fb4, Gb4, Ab4, Bb4, C5 (7. Modus von Des-Melodisch-Moll)
Hinter dem Tonnamen bzw. Akkord oder Skalenkürzel kann mit ±nk eine höhere oder niedrigere Stufe gewählt werden, von der zu starten ist, und zu der mittels = (außerhalb Klammerungen) zurückgekehrt werden kann:
Code:
C4m o+.=;-.++_, C4m+1k
: Wiederholt die gleiche Figur in der ersten Umkehrung des C-Mollakkords.

So lässt sich der 7. Modus von Melodisch-Moll (s.o.) auch ausdrücken mit: C4Mm-1k.

Aktuell werden folgende Skalentypen unterstützt: Mj = Dur (engl. Major), Do Dorisch, Ph Phrygisch, Ly Lydisch, Ml = Mixolydisch, Mn = Minor, Hm[2-7], Mm[2-7]) und Lc = Lokrisch. Diesen zweibuchstabigen Kürzel ließen sich ergänzen mit Aliases der Form Mj[2-7], der Mehrwert wäre indes fraglich.

Benannte Figuren​


Figuren können mit einem Namen versehen, sukzessive und in späteren Takten referenziert werden. Hinterm Ton oder einer Tongruppe lässt sich notieren: > ref – alle Noten und Tonkonglomerate mit diesem Anhängsel werden aggregiert in einer Figur "ref", die ab dem nächsten Takt referenziert werden kann mit < ref:
Code:
voicename:
  6: C4m o+.=;-.++_ >cfig

---
voicename: < cfig,cfig

Um eine benannte Figur in demselben Takt bereits referenzieren zu können, muss sie anders definiert werden:
Code:
voicename:
  cfig: C4m o+.=;-.++_
  6: <cfig

---
voicename: < cfig,cfig

Vorteil dieser Variante ist die Möglichkeit der Abstraktion vom Tonvorrat und die Referenz mit Ton oder Tonvorrat, indem statt der Stammnote "0" gesetzt wird, eine Art Platzhalter:
Code:
voicename:
  cfig: 0 o+.=;-.++_
  6: <cfig:C4m

---
voicename: < cfig:G3&7,cfig:C4m

Multi-Offsets​


Haben mehrere Offsets den gleichen Wert, können sie zu einem vereinigt werden. Alle vier folgenden Varianten sind im Ergebnis gleich:

Code:
2: B3 (o.--;-5.+8_)_, B3, B3, .2, B3

Code:
2: B3 (o.--;-5.+8_)_ * * .. (-.--;-5.+8_)_

Code:
bfig: B3 2 o.--;-5.+8_
2: <bfig
4: <bfig
6: <bfig
10: <bfig

Code:
2+2*2,10: B3 2 o.--;-5.+8_

Die Syntax für Multioffsets lässt sich wie folgt formalisieren: o1[+m[*n]][,o2...]*
Die Zahl am Anfang sowie jede Zahl hinterm Komma gibt das Offset ab Taktanfang an. +m kopiert den Inhalt von dort aus nach n Ticks später. *n, weglassbar (implizit =1) und nur möglich wenn +m angegeben, kopiert den Inhalt n-mal im gleichen Abstand m vom jeweils vorigen.

Großtakte und Taktgruppen​

Jedes YAML-Dokument, eingeleitet mit --- repräsentiert grundsätzlich einen Takt. Beginnt das Dokument mit der Angabe _loop: , gefolgt von einer ganzen Zahl über 0, so wird der Takt entsprechend oft iteriert.

Sind etwaige Werte von
  • Takteigenschaften, global oder stimmspezifisch
  • Attributen stimmspezifisch definierter Artikel
  • Offsets bzw. einzelne Elemente der Liste zu einem Offset
mehrteilig, wobei die einzelnen Segmente durch | (Leer, Senkrechtstrich, Leer) getrennt sind, so wird bei der Wiederholung durch alle Glieder dieser Wertekette rotiert.

Der Wert eines Segments kann auch sein: %n, wobei n die fortlaufende Nummer des eigentlichen Wertes in der Kette ist, zählt selber aber nicht als eigentlicher Wert.
Auch möglich sind "-" (false), "+" (true) und "" (none). Bei letzterem musst du zwischen den angrenzenden Senkrechtstrichen ein Leerzeichen setzen; was dagegen mehrere direkt aneineinander anschließende Senkrechtstriche bedeuten, erfährst du gleich.
Beginnt eine Wertekette mit einem Senkrechtstrich, impliziert der Undefiniert für den ersten Takt, das rechts von ihm stehende bezieht sich auf die nächsten. Nicht zu verwechseln ist ein Senkrechtstrich am Anfang mit dem Senkrechtstrich vor einem Zeilenumbruch, woraus der YAML-Parser (unabhängig von Sompyler) schließt, dass eine mehrzeilige Zeichenfolge folgt.
Endet die Wertekette mit einem Senkrechtstrich, impliziert dieser einen undefinierten Wert für den letzten Takt, das links davon stehende bezieht sich auf den vorletzten.

Code:
B3 o.--;-5.+8_, E4 | E4 4 | %1 | %1 | %1

Code:
B3 o.--;-5.+8_, E4 | E4 4 | %1 | **

* bedeutet: Wiederhole den letzten Takt ein mal. **, * * oder *2 bedeutet zweimal. || * bedeutet: Wiederhole die ganze Kette von Anfang an, oder, falls es davor noch einen weiteren doppelten Senkrechtstrich gibt, von dort an. Das gilt analog für Blocks von drei-, vier- oder wievielfachen Senkrechtstrichen auch immer. Sternchen hinter n Senkrechtstrichen wiederholen nur so viele Takte, wie diese durch eine Anzahl weniger als n eingeleitet sind.

Code:
B3 o.--;-5.+8_, E4 | E4 4 | %1 | ** || *

Reicht die angegebene Zahl hinter _loop: nicht für die längste Wertekette im Takt, so wird dies als Fehler gewertet und muss durch Erhöhung dieser Angabe oder durch Kürzung der längsten Werteketten korrigiert werden.

Kombiniert man mehrere unterschiedlich lange Werteketten, so lässt sich einiges faszinierende Quasichaos zu Gehör bringen. Ist die Wertekette zu einer Artikeleigenschaft etwa 3 Takte lang, die Wertekette zum Offset 0 dagegen vier, so erhält der vierte Takt die gleichen Werte derselben Eigenschaft vom selben Artikel wie der erste.
 
Zuletzt bearbeitet:
Im vorigen Post habe ich verschiedene Merkmale der Notensprache gezeigt, aber bisher ein zusammenhängendes Audiorendering schuldig geblieben. Bei so vielen kleinen Beispielen eignen sich einzelne Dateien für jedes einfach nicht. Wer versucht, die Takte schauend und hörend zuzuordnen? Im Anschluss den Score-Quelltext.

Keine Musik, nur Töne.
Anhang anzeigen tut.mp3
Gerendert mit https://demo.neusik.de/sompyle, smaller chamber hall:
Code:
stage:
  voicename: 1|1 0

instrument voicename:
  NOT_CHANGED_SINCE: 2024-02-07 21:16:52
  A: 0.012:1,5;6,5;7,6
  R: 0.3:1;1,1;2,0
  VOLUMES: 13:100;1,95;5,71
  PROFILE:
  - match: 1
    S: 0.5:20;1,19
  - match: 13
    S: 0.7:20;3,11;8,4

measures:
  stress_pattern: 2,1,1;2,0,1,0 # 3/4-Takt = 12 Sechzehntel
  # oder
  stress_pattern: 2,1;2,1,1;1,0 # 6/8-Takt = 12/16
  beats_per_minute: 90 # Beat = Viertel bzw. punktierte Viertel (3/8) die Minute
                       # jedenfalls gilt die gröbste Takteinteilung
  upper_stress_bound: 100 # Angabe in dBFS erhöht um 100
  lower_stress_bound: 94 # ebenso
  # [OT] Bsp. wie stark wird der Tick #9 in 6/8-Taktart betont?
  # [OT] #9 ist der der erste Sechzehntel-Tick im zweiten Achtel des zweiten punktierten Viertels in 6/8-Taktart, also 1 * (1/2) * (1/2) = 1/4 von 100 - 94 = 6, also 94 + 6/4 = 95,5 dBFS.

--- # 1 ab 0m00s00000f
voicename: # Muss in der Preambel, unter "stage" deklariert sein.
  0: B3 1 # B3 = h
  2: [A3 1, E3 1] # zwei Töne zu gleichen Zeit, als YAML-Liste, oder auch
  2:
  - A3 1 # das ist das "ausführlichere" Listenformat,
  - E3 # das lt. YAML-Spezifikation unterstützt wird. Länge 1 Tick implizit.
  2: # noch ausführlicher: Key/Value-Mappings
  - { pitch: A3, length: 1 } # diese Mappings können lt. YAML so ausgedrückt werden
  - pitch: E3  # oder auch so. Hier können auch instrumentspezifische Notenattribute angegeben werden.
    length: 1 # optional, wo eine "chain: ..." mit einer Tongruppe angegeben ist oder die Länge 1 Tick.
  4: C4 2 # bedeute: Nach 4 Ticks ab Taktanfang spiele das mittlere C 2 Ticks lang.

--- # 2 ab 0:01.33333 im Audiofile
voicename: B3 6 o.--;-5.+8_

--- # 3 ab 0:02.66667 im Audiofile (Abstand von 4/3~1.333s ist immer der gleiche, da sich weder Taktart noch Tempo ändert.)
voicename: B3 (o. --;-5. +8_)* # 2 Ticks lang!
# oder mit Länge am Anfang

--- # 4 ab 0:04.00000
voicename: B3 12 (o. --;-5. +8_) * # 12 Ticks lang

--- # 5 ab 0:05.33333
# oder mit Längenanpassung der Klammerung
voicename: B3 (o. --;-5. +8_)_5 * # 12 Ticks lang

--- # 6 ab 0:06.66667
voicename: B3 o.--;-5.+8_* # 12 Ticks lang

--- # 7 ab 0:08.00000
voicename: B3 (o. --;-5. +8_)10*12

--- # 8 ab 0:09.33333
voicename: C4 o +*4

--- # 9 ab 0:10.66667
voicename: C4& o +*3++

--- # 10 ab 0:12.00000
voicename: C4m o +*3++

--- # 11 ab 0:13.33333
voicename: C4&7 o +*4

--- # 12 ab  0:14.66667
voicename: C4m9 o ++ +*4

--- # 13 ab 0:16.00000
voicename: A3m9 o+.=;-.++_

--- # 14 ab 0:17.33333
voicename: C4Mn o +*7

--- # 15 ab 0:18.66667
voicename: C4Hm o +*7

--- # 16 ab 0:20.00000
voicename: C4Mm7 o +*7

--- # 17 ab 0:21.33333
voicename: C4m o+.=;-.++_, C4m+1k

--- # 18 ab 0:22.66667
voicename:
  6: C4m o+.=;-.++_ >cfig

--- # 19 ab 0:24.00000
voicename: < cfig,cfig

--- # 20 ab 0:25.33333
voicename:
  cfig: C4m o+.=;-.++_
  6: <cfig

--- # 21 ab 0:26.66667
voicename: < cfig,cfig

--- # 22 ab 0:28.00000
voicename:
  cfig: 0 o+.=;-.++_
  6: <cfig:C4m

--- # 23 ab 0:29.33333
voicename: < cfig:G3&7,cfig:C4m

--- # 24 ab 0:30.66667
voicename:
  2: B3 (o.--;-5.+8_)_, B3, B3, .2, B3

--- # 25 ab 0:32.00000
voicename:
  2: B3 (o.--;-5.+8_)_ * * .. (-.--;-5.+8_)_

--- # 26 ab 0:33.33333
voicename:
  bfig: B3 2 o.--;-5.+8_
  2: <bfig
  4: <bfig
  6: <bfig
  10: <bfig

--- # 27 ab 0:34.66667
voicename:
  2+2*2,10: B3 2 o.--;-5.+8_

--- # 28-35 ab 0:36.00000
_loop: 8
voicename: B3 o.--;-5.+8_, E4 | E4 4 | %1 | %1 | %1

--- # 36-43 ab 0:47.33333
_loop: 8
voicename: B3 o.--;-5.+8_, E4 | E4 4 | %1 | **

--- # 44-53 ab 0:57.33333
_loop: 10
voicename: B3 o.--;-5.+8_, E4 | E4 4 | %1 | ** || *
 
Zuletzt bearbeitet:

Präambel, Stimmen und Instrumente


Die Präambel besteht aus allen Zeilen vor der ersten Taktdefinition, das heißt, vor der ersten Dreistrichfolge (---).

Folgende Schlüssel haben spezielle Bedeutung, andere Schlüssel können jedoch beliebig vergeben werden als Metadaten zum Score (title, composer, interpreter, album, etc.):
  • stage: definiert alle Stimmen, denen in den Taktdefinitionen Noten zu Offsets und zu benannten Figuren zugewiesen werden können.
  • solo anstelle von stage enthält eine Instrumentspezifikation (oder einen Pfad zu einer extern gespeicherten Spezifikation), das zugleich die einzige Stimme bildet. In den Taktdefinitionen werden direkt die Offsets und die benannten Figuren angegeben, oder gleich die Noten an Offset 0.
  • room ist die Raumspezifikationen, falls die Töne verhallt werden sollen. scripts/sompyle muss dafür zusätzlich mit --room ohne Argument aufgerufen werden. Mit Argument oder ganz ohne diese Angabe wird eine eingebettete Raumdefinition ignoriert.
  • measures, enthält die Takteigenschaften, mit der jeder _meta-Schlüssel vervollständigt wird. Sie gelten also für alle Takte, die diese Eigenschaften nicht selber definieren.
  • articles: stimmübergreifende Noteneigenschaften
  • tuning: Angaben zur Stimmung, zu besonderen, also nicht vordefinierten Skalen und Akkordtypen.
  • instrument label: Instrumentdefinition für die Stimme label oder alle Stimmen mit label anstelle einer Pfadangabe.

Eine Stimmendefinition besteht entweder aus einem dreiteiligen Stringvoicename: L|R D instrument oder einem Mapping:
Code:
voicename:
  direction: L|R
  distance: D
  instrument: Pfad oder Name # optional
  articles: ... # optional
  tuning: ... # optional

voicename ist ein beliebiger eindeutiger Name, der in den Takten benutzt wird, um sich auf die definierte Stimme zu beziehen. L|R und D bestimmen die Position der Stimme im Raum. L ist die relative Lautstärke des linken Kanals zum rechten, bzw. R die relative Lautstärke des rechten Kanals zum linken. D gibt den n-ten hinteren Teil zwischen dem Zuhörer und der Raumgrenze an, vor dem die Stimme positioniert ist.

instrument ist eine optionale Angabe. Fehlt sie, erwartet die Software in der Präambel einen Schlüssel instrument voicenamemit den Daten, die das Instrument beschreiben. Ist instrument ein einfacher Name, etwa "abc", wird stattdessen ein Schlüssel instrument abc erwartet. Mehrere Stimmen können dieselbe Instrumentspezifikation verwenden. Enthält der Name Schrägstriche, hängt die Software implizit .splian und sucht nach diesem Dateipfad relativ zu zwei verschiedenen Orten: Im gleichen Pfad wie die Score-Datei und, nachrangig, in dem Verzeichnis lib/instruments der Sompyler-Installation. Beginnt die Angabe mit einem Schrägstrich, wird die Angabe als absoluter Pfad behandelt.

Ist die Beschreibung in der Score-Datei eingebettet, so verhindert die Angabe
Code:
instrument voicename:
  NOT_CHANGED_SINCE: YYYY-MM-DD HH:MM:SS
wenn das angegebene Datum in der Vergangenheit liegt, dass bereits gerenderte, zwischengespeicherte und weiterhin benötigte Einzeltöne neu gerendert werden.
Bei Instrumentspezifikationen in eigenen .spli-Dateien wird das Datum der letzten Änderung der Datei herangezogen.

Variationen​

Ein Instrument ohne Variabilität über Notenattribute besteht aus einer Variation, deren Eigenschaften direkt zum Instrumentschlüssel, ggf. nebengeordnet zur Angabe NOT_CHANGED_SINCE definiert werden können. Optional können die Eigenschaften zu einem Schlüssel characterdefiniert werden. character ist als übergeordneter Schlüssel nötig, sobald Notenattribute ins Spiel kommen, die das Instrument artikulatorische Freiheiten unterstützen lassen sollen. Alle Eigenschaften, die zum Tragen kommen sollen, wenn eine Note keine solchen Attribute nebst pitch, length und stress bestimmt (die aufgeführten sind immer vorhanden), bilden die Standardgruppe an Eigenschaften, die als erstes Listenelement zu definieren ist:

Code:
instrument voicename:
  NOT_CHANCED_SINCE: ...
  character:
  - ... # Standardgruppe
  - ATTR: attrname
    ...
  ...

Weitere Mappings, aufgeführt als zusätzliche Listenelemente enthalten grundsätzlich die Eigenschaft ATTR: attrname, wobei attrname ein frei zu wählender Name ist. attrname kann als Eigenschaft einer Note, einer Notengruppe oder eines Artikels verwendet werden:

Code:
- pitch: Eb5
  length: 3
  chain: ... # optionale Notengruppe
  attrname: ... # gilt für Note bzw. falls angegeben, alle Artikel in chain, die nicht mit attrname: false definiert sind

Code:
stage:
  voicename:
    ...
    articles:
      x:
        attrname: ...

Der Wert von ATTR, attrname, kann erweitert werden durch =one|two|three|...(die Zahlwörter sind an der Stelle nur exemplarisch).

Im einfachen Fall, dass dies nicht der Fall ist, muss das Notenattribut den Wert true (der YAML-Parser erlaubt auch die Synonyme yes und on, wobei die Groß/Kleinschreibung hier keine Rolle spielt), false (bzw. no, off) oder einen numerischen Wert besitzen. Hat es einen numerischen Wert, muss die Variation Eigenschaften unter numerischen Schlüsseln aufführen. Gibt es dann in der Variation gibt es einen exakt gleichen Schlüssel, so gelten schlicht die diesem zugeordneten Eigenschaften. Die gelten auch dann, wenn es im konkreten Fall der numerisch kleinste Schlüssel in der Variation ist, der vom Wert des Notenattributs noch unterboten wird; bzw. wenn es der größte Wert ist und der Wert des Notenattributs ist noch größer. Liegt der Wert des Notenattributs zwischen zwei numerischen Schlüsseln in der Variation, werden die Subvariationen gewichtet gemittelt. Als Wichtung beider Subvariationen dient das Verhältnis zwischen der jeweils eigenen Differenz zum Wert des Notenattributs und der Differenz der jeweils anderen Subvariation zum Wert des Notenattributs. Die Summe beider Gewichte ist somit stets 1.

In dem Fall einer attrname=...|...|...-Erweiterung werden die Eigenschaften aller in der Liste des entsprechenden Notenattributs angegebenen Variationen, die als Subvariation in diese unter den gleichen Schlüsseln eingehängt sind, übereinandergelegt, und zwar stets in der unter ATTR festgelegten Reihenfolge, unabhängig von der Reihenfolge der Werteliste zum Notenattributs.

Jede Variation kann die eigene Ausgestaltung mit untergeordneten Variationen erweitern, die wiederum von anderen Notenattributen abhängig sind. Diese untergeordneten Variationen sind als Liste unter dem Schlüssel variations zu definieren.

Eigenschaften einer Variation​


Jedes Instrument besteht mindestens aus der root variation, von der ggf. untergeordnete Variationen Eigenschaften erben.

Layer-Eigenschaften​

  • A: Attack shape
  • S: Decay/Sustain shape
  • T: Tail shape, intern wird das angewand zwischen Sustain und Release. Manchmal Prerelease genannt.
  • R: Release shape, A/S/T/R Fließkomma-Länge in Sekunden.
  • O: sine | square | sawtooth | triangle | noise | slopy
  • AM: Amplitude modulation
  • FM: Frequency modulation
  • FV: Frequency variation shape
  • WS: Wave shape

Shape - Polynominalkurven​

Die Länge der zu rendernden Kurve kommt zum Anfang, erkennbar daran, dass sie ein Doppelpunkt vom folgenden trennt. Handelt es sich um eine Fließkommazahl, bezieht sich diese als Faktor auf die Abtastrate, qua Voreinstellung also 44.100 Frames pro Sekunde.
Beginnt die Attack-Kurve folglich mit 0.025:...so wird der Maximalpegel in einer 40stel-Sekunde erreicht, also in 1103 Frames.
Ist die Länge nicht angegeben, nimmt die Software 1 Einheit an. Bei den Hüllkurvensegmenten ist die Einheit die Sekunde. Wenn sie fehlt, oft bei einer Sustainphase, die den Verlauf einer Sekunde beschreibt. Die Sustainphase wird allerdings stets so gekürzt oder verlängert mit der Steigung des originär letzten Kurvensegments, dass der Klang die Solllänge erreicht. Die Releasephase wird nicht mitgezählt.

Das erste folgende Glied bestimmt, falls in diesem keine zwei Zahlen von einander durch ein Komma getrennt sind, den vertikalen Startpunkt an x=0. Außerdem lässt sich dieses Element erweitern auf zwei Zahlen, die durch ihre Vorzeichen (+/-) getrennt sind. Die erste Zahl gibt den Sockel an, auf den alle y-Koordinaten aufaddiert werden. Die zweite Zahl gibt die Orientierung der Kurve nach oben oder unten an, sowie die Standardausdehnung zur Nulllinie. Beträgt sie etwa 5, so ist jede y-Koordinate der Folgeglieder, die ebenfalls 5 beträgt, effektiv 1,0 – wenn man mal den Sockelbetrag als 0 ansetzt. Jedes Folgeglied mit y=4 wird zu 0,8 normiert, jedes mit y=7 zu 1,4. Beträgt der Sockelbetrag, die erstere Zahl, -3, die zweitere wäre stattdessen zu rechnen (7 + -3) / 5 = 0,8. Ist der Sockelbetrag positiv, wird er auch auf die Standardausdehnung angewendet: (7 + +3) / (5 + +3) = 10/8 = 1,25!

Die nächsten Folgeglieder sind aufgebaut nach dem Schema x,y(*w|!). Auf das Koordinatenpaar x,y kann ein ganzzahliges Gewicht folgen (weggelassen implizit *1), unendliches Gewicht wird durch ein Ausrufezeichen signaliert: An dieser x-Position ist y exakt der nominelle Wert, nähert sich ihm nicht nur an. Im Sinne der Polynomberechnung entspricht das Gewicht der z-Koordinate.

Die Folgeglieder werden miteinander verbunden mit dem Semikolon.

Modulationen​

Definitionen von Modulationen sind aufgebaut nach dem Schema x(f|F)(@label)([Shape]);i:b. Die rundgeklammerten Teile sind optional. "f" multipliziert die Modulationsfrequenz x mit der Grundfrequenz, "F" dagegen mit der Frequenz des Layers. @label bezieht sich auf die Oszillation, deren Eigenschaften in der Eigenschaftsgruppe "label" definiert ist. i ist der Modulationsindex als Ganzzahl relativ zur Basis b.

Benannte Eigenschaftsgruppen​


Layereigenschaften können in beliebiger Zusammenstellung unter beliebigen Namen gruppiert werden. Eigenschaften anderer Gruppen derselben Variation können referenziert werden durch (z.B. Attack) A: @label– dies definiert, dass die geltende Attackphase bereits in der Gruppe "label" definiert worden ist. Reziproke und Zirkelbezüge werden als Fehler erkannt. Ist die Gruppe "label" nicht in der aktuellen Variation definiert, wird in der übergeordneten Variation nachgeguckt, und dann in der über-übergeordneten und so weiter.

Eine Gruppe kann den Schlüssel "other" haben. Der Wert ist der Name einer Gruppe, aus der andere definierte Eigenschaften zu beziehen sind.

Werte von O(szillator) werden, wenn sie von einem "@" eingeleitet sind, aus dieser Gruppe übernommen. Von "@@" eingeleitet, wird die Oszillator-Schwingung mit den darin definierten Modulationen AM und FM, mit FV und WS angereichert.

PROFILE​

Eigenschaften der Partialtöne oder besser gesagt "Layer" (Synonym in Sompyler-Terminologie: Sympartial), denn Partialtöne sind streng genommen nur Sinus-Schwingungen unter einer Hüllkurve.

Liste von "@label"-Angaben oder Mappings oder beides gemischt. Im ersteren Fall kann vor dem @ oder allein eine Ganzzahl stehen. Der Betrag steht in der Einheit dBFS + 100 und gilt zusätzlich zum Wert, der sich aus der VOLUMES-Kurve oder Liste an der entsprechenden Indexposition ergibt.

Ein Mapping kann ein Schlüssel "match" enthalten. Der Wert von "match" ist entweder eine Ganzzahl oder eine Teilbarkeitsregel nach dem Schema "mo", das zu lesen ist wie folgt: Eigenschaften gelten für alle Layer, deren Ordnungszahl nach Abzug von o noch größer ist als 0 aber kleiner ist als die Zahl aller Layer (maßgeblich ist die größte ganzzahlige match-Angabe), und ohne Rest teilbar ist durch m. Für alle Listenelemente ohne match-Angabe gilt implizit ein fortlaufendes Inkrement ab dem letzten Element mit ganzzahliger match-Angabe, oder 0. Der Buchstabe "n" wird als solcher erwartet.

Ist in einem Mapping "deviance" bestimmt, beziehen sich alle Eigenschaften auf einen zusätzlichen Layer mit einem Faktor der Grundtonfrequenz, der ausgehend von der Ordnungszahl soundso viele Cent weitere Abweichung von der harmonischen Obertonreihe beträgt – und zwar zusätzlich zu dem Wert, der sich aus dem entsprechenden Index der SPREAD-Kurve/Liste ergibt.

Eine zusätzliche bzw. abgezogene Stärke kann angegeben werden unter dem Schlüssel V. Bei vielen Tasteninstrumenten ist jeder 8. Teilton gedämpft. Das Mapping enthält entsprechend zwei Angaben, match: 8n und V: -30.

Auf alle weiteren Eigenschaften im Mapping eines Listen-Elements vom PROFILE trifft das zu den Eigenschaftsgruppen beschriebene zu.

Ist ein Listenelement als String angegeben, z.B. "2@label", so ist { V: 2, other: "@label" } lediglich das Mapping-Äquivalent.

TIMBRE​

Verstärkung und Dämpfung von Partialtönen in Abhängigkeit ihrer tatsächlichlichen Frequenz. Angegeben als Shape (Polynominalkurve(n)). Die Shape-Gesamtlänge bezieht sich auf das abgedeckte Spektrum 0 bis n Hz.

VOLUMES​

Angegeben als Liste von Werten (angegeben in der Einheit dBFS + 100) oder als Shape. Im letzteren Fall bezieht sich die ganzzahlige Längenangabe auf die Anzahl der Partialtöne.

MORPH​

Ähnlich PROFILE, nur können hier die gesamten Hüllkurven der Layer mit einem Shape multipliziert werden.

Das syntaktische Schema eines Listenelements: - match (w:)shape
  • match: s.o. bei PROFILE
  • w: optionales ganzzahliges Gewicht anstelle der Längenangabe eines shapes. Relevant bei der Mischung mehrerer Shapes, deren zugehörige Matches auf die Ordnungsnummer eines Layers zutreffen.
  • shape: Die Koordinaten beziehen sich auf die konkreten Gesamtlängen der betreffenen Layer.

SPREAD​

Abweichungen von der harmonischen Obertonreihe. Je Layer ein Wert in Cent. Ein Cent ist der 1200. Teil einer Oktave oder ein hundertstel Halbton.

RAILSBACK​

Stimmungskorrekturwerte pro Taste eines gedachten Klaviers, jeweils in Cent. Als Liste angegeben. Dabei geben die ersten beiden Werte dieser Liste die Frequenzspanne an, von wo bis wo sie gelten (0 bis 4186). Ist der dritte Wert eine Kurve, wird diese intern in eine Liste von 88 Werten umgewandelt. Sonst werden 88 Ganzzahlen in dieser Liste erwartet.

Wird häufig benötigt, wenn exzessiv von Frequenzmodulationen und SPREAD-Angaben Gebrauch gemacht wird. Die so verursachten Verstimmungen sollten nach Gehör berichtigt werden.

Beispiel​


Code:
solo:
  FM: 3f[1;1,0];1:2
  PROFILE:
  - match: 1
    V: 100
    A: 0.02:1,70;2,75;4,80;8,85;16,90;32,95
    S: 0.75:100;1,93;3,88;5,85
    R: 0.3:5;2,3;3,0
  - [92, 95, 93, 87, 85, 81, 75]
  - match: 9
    V: 71
    A: 0.025:1,3;2,4
    S: 0.75:100;1,93;3,83;5,82
    R: 0.3:4;2,4;3,0
    FV: 10;0,5;4,3;5,7
    O: slopy


---
Cs3
Anhang anzeigen mellowday.mp3
00001.snd.png

Code:
stage:
  left: 1|0 0 foo
  right: 0|1 0 foo
 
instrument foo:
  character:
  - FM: 3f[1;1,0];1:2
    PROFILE:
    - match: 1
      V: 100
      A: 0.025:1,3;2,4
      S: 0.75:100;1,93;3,88;5,85
      R: 0.35:3;2,3;3,0
    - [92, 95, 93, 87, 85, 81, 75]
    - match: 9
      A: 0.02:1,70;2,75;4,80;8,85;16,90;32,95
      V: 71
      S: 0.75:100;1,93;3,83;5,82
      R: 0.25:4;2,4;3,0
      FV: 10;0,5;4,3;5,7
      O: triangle
  - ATTR: fiber
    0:
      MORPH:
      - 3n 4:10;1,11;3,10
      - 1 1;1,1
      - 9 1;1,1
    100:
      MORPH:
      - 2n+1 5:8;4,7;5,8
      - 1 1;1,1
      - 9 1;1,1

articles:
  o: { fiber: 36 }
  f: { fiber: 90 }

---
left: Cs3 o

---
right: Cs3 f

---
left: Cs3 o
right: Cs3 f
Anhang anzeigen twotones.mp3 00006.snd.png00007.snd.png
 
Zuletzt bearbeitet:
In Arbeit:

Takteigenschaften​


Die Mehrzahl der Takteigenschaften bestimmen die mathematisch determinierten Eigenschaften von Tönen. Ohne sie wären zur Position und Dauern von Tönen Sekundenwerte anzugeben, ihre Intensität in dBFS. Bei der Verwendung ungleichstufiger Stimmungen müsste zu vielen Noten jeweils ein Pitchbend in Hertz festgelegt werden.

Zwar mag es etwas herausfordernd sein, relative ganzzahlige Werte in ihrem Kontext schätzend zu interpretieren – wenn dies einmal geübt ist, dürfte das Eintippen entschieden leichter von der Hand gehen. Profi-Texteditoren sind zudem in der Lage, Ganzzahlen unter der Eingabemarke im Text schrittweise zu inkrementieren (z.B.vim: Strg-A) und zu dekrementieren (Strg-Z), Fließkommazahlen dagegen nicht.

Eigenschaften, die wiederum Eigenschaften von Tönen beeinflussen (Länge, Intensität), beeinflussen in Abhängigkeit von der Instrumentenspezifikation der jeweiligen Stimme, auch seinen Klang. Das betrifft Instrumentenspezifikationen, die Variationen mit der Angabe ATTR: stress und/oder ATTR: lengthenthalten. Ersteres dürfte häufiger vorkommen als letzteres, denn die Länge eines Tons steht in der Natur ja noch nicht fest, wenn er angeschlagen wird.

stress_pattern​

Hiermit werden Takte in einzelne Ticks strukturiert, die jeweils ihre Stärke zugeordnet werden.
  • "4": eine einfache Zahl als Zeichenfolge in Anführungszeichen steht für die Anzahl an maximal betonten Noten im Text. Hier werden also vier Viertelnoten ohne Metrum (Betonungsunterschiede) angesetzt
  • "3,1,2,0": eine Gruppe von kommaseparierten Zahlen repräsentieren die Betonungen derselben Anzahl Noten im Takt. Die am schwächsten betonte Note hat eine Betonung von -3dBFS, da 3 auf der "Eins" in 0dBFS umgedeutet wird.
  • "4;3,1,2,0": Man könnte einen Takt mit vier Einsen definieren.
  • "3,1,2,0;4": Oder einen Takt mit vier mal vier, also 16 "Ticks", von den jede Vierergruppe dieselbe Betonung erhält
  • "4,2,3,1;2,0,1,0": Ebenfalls ein Takt aus Sechzehnteln, hier erhält jedes eine einzelne Betonung. Das letzte Sechzehntel hat keine Betonung, d.h. 8/8 von -4 dBFS Dämpfung, das vorletzte 1/2 * 1/4 = 1/8, also 7/8 von -4 = -3,5 dBFS, das 11. 1/2 * 3/4 = 3/8, d.h. 5/8 von -4 dBFS Dämpfung.
Die Angabe kann sowohl stimmübergreifend als auch stimmbezogen sein. Stimmbezogene Angaben müssen ebenso viele Ticks ergeben wie die aktuell geltende stimmübergreifende. Führt ein Takt ein stress_pattern mit geänderte Gesamtzahl an Ticks ein, so werden alle stimmbezogenen Definitionen zurückgesetzt.

beats_per_minute​

Das Tempo des Grundpulses, der den Rhythmus trägt.
  • 90: setzt das Tempo auf 90 Schläge pro Minute. Mit Schlägen ist die Einheit der ersten Unterteilung von stress_pattern. Das oben gegebene Pattern bestimmt vier Viertel, also vier Schläge pro Takt. 90 / 4 = 22,5 Takte pro Minute, bzw. 90 * 4 = 360 ticks = Sechzehntel pro Minute.
  • '85-90': Lineare Beschleunigung. Eine Note von 3 von 16 Ticks Länge (z.B. punktierte Sechzehntel) umfasst die Dauern jedes Ticks abhängig von der Startposition der Note, im folgenden s, so wäre die gesamte Dauer der Note
    Code:
    60/(85+(s+0)/16*(90-85)) + 60/(85+(s+1)/16*(90-85)) + 60/(85+(s+2)/16*(90-85))
    Sekunden lang.
  • '85;2,85;3,90': Definiert einen polynomialen, nicht-linearen Tempoverlauf mit der stärksten Beschleunigung ungefähr im dritten Drittel des Taktes. Die Berechnung der Dauer beliebig gesetzter punktierter Sechzehntel sei dir überlassen ;-) – oder der Software; die Plausibilität einer konkreten Einstellung einschätzen werden ohnehin deine Ohren und du.
Diese Angabe gilt stets für alle Stimmen. Stimmbezogen wird sie nicht unterstützt.

lower_stress_bound​

Definiert den dBFS-Pegel der unbetonten Noten im Takt. Falls undefiniert, gelten die Werte der ersten Unterteilung von stress_pattern direkt als die Subtrahenden derjenigen von upper_stress_bound. Ist auch diese Angabe nicht definiert, wird 100 = 0dBFS angesetzt. Sei stress_pattern "3,1,2,0", haben die Noten die Pegel 0, -2, -1 and -3dBFS.

  • '95': Die unbetonten Noten haben den Pegel -5 dBFS unabhängig von ihrer Position. Die anderen Noten werden betont relativ zu ihrem Level in diesem Dynamikkorridor. Das drittel Viertel bei Level 2 von 3 laut stress_pattern liegt demnach bei 95 + 2/3 * 5 - 100 = -1,666dBFS
  • '95-90': Der Dynamikkorridor der Noten verbreitert sich im Taktverlauf nach unten un -5dBFS.
  • '95;1,90;3,92': Polynomische Verläufe sind natürlich auch möglich. Der dynamische Unterschied der unbetonten Noten zur Eins vergrößert sich hier am Anfang des Taktes schnell, bleibt dann auf etwa gleichem Niveau und nähert sich zum Taktende wieder dem der betonten Noten an.
Die Angabe wird stimmübergreifend und stimmbezogen unterstützt, wie übrigens auch

upper_stress_bound​

Definiert den dBFS-Pegel der am stärksten betonten Note(n) im Takt, meist der Eins, die folgenden, weniger betonten entsprechend anteilig. Die Beispiele gelten analog zu lower_stress_bound, deswegen werden sie hier ausgelassen.

Festzuhalten ist, dass die Software überprüft und gegebenenfalls als Fehler anmahnt, wenn die Dynamik eines Ticks durch überschneidende Kurvenverläufe umgekehrt ist.

Auch ist festzuhalten, dass Instrumentenspezifikationen durch Einbeziehung des Attributs "stress" die Dynamik auch klanglich stützen können. Die Pegellautstärke wird davon unabhängig berechnet.

Nicht zuletzt unterstützen Artikeleigenschaften die Angabe neben statischen Werten, linearen Veränderungen (von-bis) "L...;P...;U...", wobei die Lücken analog zu lower_stress_bound, stress_pattern bzw. upper_stress_boundzu füllen sind. So können die Werte von gleitkommazahligen Attributen, die die Instrumentspezifikation unterstützt, ebenso muster- und verlaufsorientiert durch den Takt "schwanken" wie mal mehr, mal weniger starke Töne abhängig von ihrer Betonung.

elasticks_pattern​

Analog zu stress_pattern können die Dauern benachbarter Ticks relativ zueinander festgelegt werden. "4;3,1" bestimmt, dass jede erste eines Achtelpaars im 4/4-Takt punktiert sei, das zweite entsprechend eine Sechzehntel. So extrem wird normalerweise nicht geswingt. Man kann statt 3:1 jede andere Relation festlegen

Die Angabe wird stimmübergreifend und stimmbezogen unterstützt. Darüberhinaus gilt die Schlussbemerkung zu stress_pattern analog.

elasticks_shape​

Statt eine extreme Relation im elasticks_pattern abzuschwächen, kann man dies auch lokal tun durch einen Verlauf: 2;0,1;1,1 bei elasticks_pattern: "4;3,1" bewirkt das gleiche wie "4:5,3" (Von 3,1 ausgehend jeweils Verdopplung und Annäherung an die Mitte: 2*3-1=5, 2*1+1=3). Der Verlauf kann zum Beispiel der Phrasierungsgewohnheit Rechnung tragen, dass Sechzehntelketten eher gerade gespielt werden.

elasticks_shape empfiehlt sich eher als stimmbezogene Takteigenschaft.

tuning​

dient der Angabe, welche Ticks welchen Grundton und welchen Skalentyp haben sollen.

Verschiebungen des Stimmungsgrundtons erfordern immer ein Vorzeichen + oder -. Sie sind nur bei ungleichstufigen Stimmungen für die Berechnung der Grundtonfrequenzen der beteiligten Töne relevant. Bei danach optional angegebenem Skalentyp (z.B. mj für Dur/major, mn für natürliches Moll/minor, do für Dorisch oder mm7 für den siebten Modus des melodischen Moll) überprüft die Software, ob alle Noten auf einer bestimmten Tick-Position der jeweils aktuellen Skala angehören. Skalenfremde Töne werden als Fehler zurückgewiesen. Das ist allerdings kein vollständiger Ersatz für musikalisches Gehör.

Der Skalentyp kann ohne Grundton voran geändert werden. Dann muss natürlich auch das Vorzeichen entfallen.

Ticks, für die sowohl der Grundton als auch der Skalentyp gelten soll, der jeweils zuletzt angegeben wurde (möglicherweise in einem früheren Takt), sind mit einem schlichten Punkt zu repräsentieren. Eine Folge von Punkten kann mit ".n" (n sei die Anzahl) abgekürzt werden. Leerzeichen vor n sind nicht erlaubt, können sonst aber beliebig der visuellen Strukturierung dienen. Entspricht die Anzahl an Angaben und Punkten nicht der Anzahl an Ticks, wird das als Fehler gewertet und das Rendering abgebrochen.

Ist tuning nicht angegeben, gilt der Grundton und der Skalentyp, der zuletzt angegeben wurde in einem früheren Takt. Für den ersten Takt gilt in diesem Fall Grundton C – tatsächlich nur bei ungleichstufigen Stimmungen relevant – und chromatische Skala, in der alle 11 Töne erlaubt sind. Falls du später zu dieser Skala zurückkehren, also den Check deaktivieren möchtest, setze als Skalentyp chr.

cut​

Die Anzahl von Ticks, die bei Auftakten am Anfang fehlen (positive Ganzzahl). Schlusstakte desselben Formteils eines Stückes bekommen die gleiche Zahl minus der Gesamtzahl an Ticks des ersten vollständigen Taktes (negative Gz.), so dass ihre Länge plus die des Auftaktes eine normale Taktlänge ergeben.

offset_seconds​

Anzahl der Sekunden als Gleitkommazahl, die vor den Takt eingefügt werden sollen.

skip​

Hat ein Takt die Angabe skip: true (alternativ yes oder on), so werden dieser und etwaige Folgetakte bis ausschließlich dem nächsten Takt mit skip: false (no, off) übersprungen. Etwaige Takteigenschaften, die in den übersprungenen Takten definiert sind, werden in den Folgetakten übertragen. Dies ist aber nur der Fall, wenn:
  • Die Präambel keine Takteigenschaften definiert, also ein Schlüssel measuresenthält. Diese werden von den Takten vorzugsweise übernommen, statt den Eigeschaften des jeweils vorherigen Taktes.
  • Der nächste Takt mit skip: false die betreffenden Takteigenschaften für sich und etwaige Folgetakte überschreibt.

is_last​

Nach einem Takt mit der Angabe is_last: truewird die Verarbeitung aller Folgetakte übersprungen.
 
Zuletzt bearbeitet:
  • Daumen hoch
M.i.a.u.: TGN
Ich habe aus meinem Wettbewerbsbeitrag zum Techno Battle 2024, Chirring Crickets Rave, eine HTML-Seite erstellt, in der alle Ebenen klang- und synthesetechnisch in dem Stück durchleuchtet werden. Den Nerds viel Spaß. Wem das zu kompliziert ist, sei getröstet mit den vielen Dingen im Leben, die mir zu kompliziert, für die meisten aber völlig normal sind.
Die verlinkte Seite besteht aus vier Abteilungen:
  1. Audioplayer
  2. Source code (one-line + yaml)
  3. Informationen zu jeder Note
  4. Zu jeder Note gibts zudem einen Link zu noch mehr Informationen über ihre Klangerzeugung, samt Audioplayer für den einzelnen Ton und eine graphische Aufschlüsselung in der Zeit- und Frequenzdomäne, bei bestimmten Fragestellungen genauer als eine Wavelet-Spektralansicht.
Den einzeiligen konzisen Sourcecode habe ich in der Form intellektuell aus der YAML-Fassung abgeleitet. An dem Ziel, dass der umgekehrte Weg vom konzisen Format zu YAML maschinell möglich ist, arbeite ich zur Zeit. Dies hat nichts mit Sompyler zu tun, Sompyler liest nur YAML und JSON. Neusician, das Online-Webinterface zum Sompyler, konvertiert das eine ins andere Format und wird dabei auch noch andere Schmankerl können, an denen ich zur Zeit arbeite (pseudo-random music material injection).

Warum ich das einzeilige konzise Format entwickle? YAML kann nur in bestimmten Webseiten als YAML gepostet werden. Etwa in X-Posts und in Posts in vielen anderen sozialen Medien gibt es kein verbatim code mark up. Auch hier sind einzeilige Codes verbatim unauffälliger als ein YAML-Code-Block, den ich in ein grelles Spoilertag "Online Backup" einfassen muss, damit Leute nicht so viel scrollen müssen. ;-)
 
Zuletzt bearbeitet:
Achtung: Vom TE aus einem anderen Thread zum Thema Raumhall hierher "geschoben", da es um Grundsätzliches geht.

ich kann dir nicht wirklich folgen...
Sind in einem Thread GegenKlang (früher flow, dann Neusiker) und einseinsnull beteiligt, sehe ich schon die Moderatoren kichern und wetten, dass irgendwann der letzte Dritte sich genervt zurückzieht und bald zwei Drittel des ganzen Threadverlaufs nur noch wir beide ungestört aneinander vorbeireden. Im Hintergrund verticken die Moderatoren Popkorn, und bald hat der Admin seinen Maserati abbezahlt ... [/conspiracy] ;-)

Was ich meine ist auch zugleich der Grund, warum wir aneinander vorbeireden und ich trotzdem – manchmal – etwas für mich mitnehmen kann, also entspann dich, spiel mir Bälle zu, wenn du Lust hast und Muße, ansonsten eben nicht. Für mich geht es um nichts, das ist ein Spleen-Projekt.

Du redest von optimalen, speziellen Algorithmen mit effizienten signalmathematischen Formeln dahinter und du hast aus deiner Warte völlig recht. Du verstehst leider wiederum nicht meine Vorbehalte, dass diesen kritisch gegenüberstehe. Lieber hab ich eben eine überschaubare Zahl generischer Tools, die clever verknüpft ein fixes Ganzes bilden, eine Art Maschine, gebaut aus in der Konstruktion einfacheren Teilen, die (auch menschen-)lesbaren Text liest und Audio ausspuckt.

Dass das Audio kaum heutigen Qualitätsansprüchen genügen kann, ist schade, aber kein Grund, das Projekt aufzubohren zur x-tausendsten markttauglichen DAW. Grafik etwa ist mir wumpe, dass es screenreadertauglich ist, wäre mir wichtiger, das ist schwierig genug.

Ich möchte auch Leute einschließen, denen schwerfällt, Formeln mit vielen Variablen und Unterfunktionsaufrufen zu verstehen, da sie im abstrakten Denken weniger als die berühmten sieben Sachen im Arbeitsgedächtnis behalten können. Daher kann meine entwickelte DSL – domain specific language – keine Bedingungen, Schleifen und Unterfunktionsaufrufe in der Form, wie der Programmierer sie kennt, ganz zu schweigen von irgendwelchen Plug-ins, Mix-ins und vergleichbares Zeug.

Erweiterbarkeit ist Fluch und Segen zugleich. Gegen Plugins habe ich auch ziemlich viel emotional, sowohl gegen Plugins, die ich nutze, als auch nutzbar mache. Vermutlich ist sogar Eifersucht mit von der Partie, wie bei so vielem, das so passiert auf der Welt. Würde ich Plugin-Fähigkeit nachrüsten, könnte man auf viel Wissen und viele Fähigkeiten von außen zugreifen. Aber stünde auch in der Verantwortung, dass Plugin-Hersteller dafür entwickeln wollen und müsste das ewig supporten. Schon der Gedanke daran verdirbt es mir. Ohne Erweiterbarkeit halte ich mir viele Sorgen aus dem Kopf.

Ich kann derzeit und auf absehbare Zeit (d.h. bis an ihr Ende, wenn ich mir so die Nachrichten anguck) nur Polynome beschreiben, Schwingungen definieren, jeweils samplegenau annähern, Text parsen und Filter falten – vier grundsätzliche Operationen in universellen nicht darauf CPU-optimierter PC- und Cloudserver-Umgebungen, die meinetwegen CPU fressen, CO2 emittieren, Kätzchen töten oder was auch immer. Das ist meine Toolbox, und ja, sie ist bewusst monolithisch. Kommt mir also nicht mit Plugins!

Ich weiß also, dass ich mich einschränke und warum. Dass ich mich durch meinen Workflow auf eine Extension für Massendatenkalkulation namens numpy beschränke, um das Abhängigkeitenbouquet (Teil des Projekt-Footprints) überschaubar zu halten.

Wenn du von Filtern redest, denke ich an Faltung (wie gesagt: If you've got a hammer, everything looks like ... your thumb!), mit der man alle Filter umsetzen kann, eben ein Ansatz für vieles. Auch EQ und Passfilter, eigentlich ne Sonderform von EQ, würde ich so umsetzen wollen/müssen.

Je monolithischer das Projekt aber ist, desto kleiner muss es auch sein, damit das Ein-Mann-Freizeit-Projekt für mich überschaubar bleibt.

dann nimm dir doch für den binauralfilter teil ein sparta plug-in und rendere deine reflektionen vorher einzeln inclusive der richtungs-information.
Plugins wie das von dir erwähnte sparta sollen nicht zu meiner Toolbox gehören, da werfe ich eine "beyond my scope"-Exception und trete ein fürs Nein-sagen-dürfen. Wenn der Hall nach jemandes anderen, mal angenommen es wird je von nem anderen verwendet, nach dessen Ermessen qualitativ nicht genügt oder zu viel Rechenressourcen, CO2 oder kleine Kätzchen benötigt, soll er eben nicht genutzt werden, Punkt.
Was kein Problem ist, wo es Alternativen gibt: Sompyler kann nicht nur WAV, ogg, flac, mp3 u.a. Formate zum Import in andere Tools schreiben, sondern auch serialisierte Numpy-Datenstrukturen.

post scriptum: Vor etwaiger Antwort hierauf bitte überlegen, wo sie hin gehört. Grundsätzliches hier, Raumhall und meine Realisierung gehört in den Thread zur binauralen Klangpositionierung, der Quelle obiger Zitate.
 
Zuletzt bearbeitet:
Lieber hab ich eben eine überschaubare Zahl generischer Tools, die clever verknüpft ein fixes Ganzes bilden, eine Art Maschine, gebaut aus in der Konstruktion einfacheren Teilen, die (auch menschen-)lesbaren Text liest und Audio ausspuckt.

niemand zwingt dich raumreflektionen zu berechnen, indem du dein neusikerisches textformat in signal vectors überführst, die vo, DAC treiber gesynct werden, und dann einen allpassfilter aus combfilter kerneln in assembly implementierst, das ganze dann 4-fach hochsamplest und bikubisch interpolierst.

sich mal anzuschauen, wie man das "normalerweise" macht kann aber defintiv dabei helfen, das prinzip dahinter zu simplifizieren - oder auch heftig abzuändern - und in irgendeine andere welt zu übertragen.

Wenn du von Filtern redest, denke ich an Faltung

das ist eines dieser generellen probleme... man sagt A - und du denkst dabei an B. hmpf. ;/

ein allpass filter und ein tapping buffer sind enge verwandte, die machen im prinzip fast das gleiche, und das was die machen lässt sich recht einfach auch in data rate übertragen.

jetzt hör ich aber auf, denn alles was zum thema hall gehört, bleibt natürlich im hall thread.
 


News

Zurück
Oben