Andreas Kortke, Berlin 1991

Kurzreferenz des Betriebssystems MuSys für eine eigene Hardware

>MuSys ist die informatische Umsetzung der algebraischen Musiktheorie von R. Nowotny. Die darin enthaltenen Konstruktionen sind als Datenstrukturen und Funktionen in der Programmiersprache "C" ausgeführt. Nachfolgend wird das Programmsystem strukturell und inhaltlich beschrieben.

Das System gliedert sich in folgende Programmdateien:

MusicDef.h - Definition grundlegender Konstanten und Datenstrukturen, sowie Deklaration systemübergreifender Variablen.

MuSys.c - enthält Funktionen für die Behandlung von Noten, Notenfolgen und Motiven.

Brueche.c - enthält Funktionen für das Rechnen mit "echten Brüchen" und arithmetische Hilfsmittel.

Tonarten.c - enthält Funktionen für die Arbeit mit Tonarten, Tonartfolge, Tonartverwandtschaften und Motiven.

MusicIo.c - enthält Funktionen für die Ein- und Ausgabe von Notenfolgen und Musikstücken.

Oktaven.c - Behandlung von Oktaven.

Phrasen.c - Behandlung rhythmischer Phrasen und Folgen rhythmischer Phrasen.

Skalen.c - Funktionen zur Behandlung der Skalenlehre, sowie zur Arbeit mit Akkorden, Akkordfolgen und Figuration.

Stilist.c - genrespezifische Funktionen zur Beachtung musikästhetischer Grundsätze.

Analyse.c - beinhaltet eine Test- und Analysefunktion zur Begutachtung von Zwischenergebnissen.

Demonstraton:
Vierstim.c - komponiert einen vierstimmigen Satz.
Fuge.c - komponiert eine zweistimmige Fuge in strenger Form.
JazzPar.c - komponiert zweistimmige Jazz- Etüden.
Cantus.c - komponiert einen "cantus firmus".

Weiterhin existieren verschiedene Datenstrukturen - "musikalische Elemente".
Alle Elemente der Musiktheorie sind in speziellen C-Variablen, Datenstrukturen oder Funktionen realisiert.

1. Noten

Zur Darstellung von Noten ist in "MusicDef.h" die Struktur "Note" deklariert. Sie enthält eine weitere Struktur "Br". Mit einer Struktur "Br" lässt sich ein echter Bruch aus Zähler- und Nennerkomponente darstellen. In der Struktur "Note" repräsentiert der Bruch den Notenwert. Weiter enthält die Notenstruktur ein Element "N" für die Angabe der Tonhöhe (Nummer des Halbtons: 0 entspricht c) und das Element "O", die Oktavnummer der Note.
Diese drei Elemente beschreiben eine einzelne Note vollständig.

2.Notenfolgen

Um nun Sequenzen von Noten (Melodien u.s.w.) bilden zu können ist eine weitere C- Konstruktion erforderlich. Es handelt sich um eine Struktur, die man allgemein als Kettenglied bezeichnen kann. Diese Struktur "Notenfolge" enthält drei Zeiger auf Objekte des selben Typs, zwei "short" Elemente und ein Feld von Notenstrukturen, dessen Elementanzahl durch den Konstantwert "SEG" bestimmt wird.

Diese Art der Verkettung von Einzelelementen oder Segmenten (Feldern) von Einzelelementen wird im System noch wiederholt auftreten. Die im Kettenglied (Struktur Notenfolge) enthaltenen Zeigerelemente zeigen auf das vorhergehende Kettenglied (*Prev), das nachfolgende Kettenglied (*Next) und das letzte Kettenglied (*Last). Der Zeiger "*Last" hat nur im ersten Kettenglied einen
gültigen Wert. Im ersten Kettenglied hat "*Prev" und im letzten Glied "*Next" den Wert Null.
In einer eingliedrigen Kette ist *Next und *Prev gleich Null und *Last zeigt auf dieses, erste Glied. Operiert wird mit solchen Ketten immer durch den Zeiger auf das erste Glied, in unserem Fall: "struct Notenfolge *". Das "short" Element "First" der Struktur Notenfolge gibt die Nummer der 1. Note des Kettengliedes
innerhalb der Kette an. Im ersten Kettenglied hat es den Wert Null.
Das Element "Len" gibt die Anzahl der im Kettenglied gültigen Noteneintragungen an. Die Addition von "First" und "Len" des letzten Kettengliedes ergibt die Anzahl der in der Kette vorhandenen Elemente (Noten). Für die Arbeit mit Notenfolge existieren in der Programmdatei "MuSys.c" einige Grundfunktionen,
die sinngemäß bei allen Kettentypen (Tonartfolge, Phrasenfolge u.s.w.) Anwendung finden.

1. OpenNf() Öffnen einer Notenfolgen-Kette.

Ist der Übergabeparameter gleich Null, so wird eine neue Notenfolgenkette eingerichtet und ein Zeiger auf diese zurückgegeben. Ist der Parameter ein gültiger Zeiger auf eine Notenfolgen-Struktur, so wird diese um ein Glied verlängert. Im Fehlerfall wird ein Nullpointer zurück gegeben.

2. CloseNf() Schließt die spezifizierte Notenfolge.

Speicher wird freigegeben, die Notenfolge existiert nach Aufruf dieser Funktion nicht mehr!

3. NfSegment() Systeminterne Funktion, vom Anwender normalerweise nicht benötigt. Sie liefert den Zeiger des Kettengliedes der spezifizierten Note.

4. AddNote() An die spezifizierte Notenfolge wird eine Note angefügt. Sollte kein Platz im letzten Kettenglied sein, so wird die Kette um ein Glied verlängert. Normalerweise wird der Zeiger auf die Notenstruktur zurückgegeben, in die eine neue Note eingetragen wurde. Im Fehlerfall wird ein Nullpointer zurückgegeben.

5. LastNote() Liefert die Anzahl der Noten in einer Notenfolge.

6. GetNote() Liefert den Zeiger auf die spezifizierte Note der Notenfolge, im Fehlerfall einen Nullpointer.

7. PutNote() Überschreibt die spezifizierte Note der Notenfolge mit den Werten der übergebenen Notenstruktur. Existiert die spezifizierte Note nicht in der Notenfolge, so wird diese entsprechend verlängert.

3. Scores

Komplette Musikstücke werden durch die Datenstruktur "Score" dargestellt. Diese Struktur ist ebenfalls ein Kettenglied, das heißt, sie enthält die nötigen Zeigerelemente. Jedes Kettenglied stellt eine zeitlich verzögerte Melodie, oder eine Stimme einer Polyphonie dar. Hierzu enthält jede Struktur "Score" einen Zeiger auf eine Notenfolge, die Struktur eines Bruches als zeitlichen Anfangsoffset und eine Tonartstruktur "Haupttonart". Des weiteren existieren die Variablen "Tempo" (Spieltempo [0...255]), "MidiKanal" x*[1...16] für Midiausgabe, "Attack" - Anschlagzeit [0...127], "Release"- Abklingzeit [0...127], "Volume"- Gesamtlautstärke [0...255]. Für den Umgang mit Score- Strukturen existieren die Funktionen:

1. AddScore() Eröffnen oder Erweitern einer Score- Kette.

2. CloseScore() Schließen einer Score- Kette.

Insbesondere bei Ein-/Ausgabefunktionen sind die Parameter vom Typ "struct Score *".

4.Tonarten

Ähnlich wie für Noten existieren Datenstrukturen für Tonarten und Tonartfolgen. Die Elemente einer Tonartstruktur sind vier Variable: "Gt"- Grundton (c,cis,...,h) und "Tg"- Tongeschlecht (Dur,moll,...).
Der Grundton ist analog zu den entsprechenden Noten codiert. Tonartverwandtschaften sind als Funktionen mit Operanden vom Typ "struct Tonart" in "Tonarten.c" definiert. Die Komponenten "Ia" und "Ie" sind Indizes, die den Abschnitt in einer korrespondierenden Notenfolge bestimmen, in dem diese Tonart gültig ist. Der Index "Ie" zeigt jedoch nicht auf die letzte Note der jeweiligen
Tonart, sondern auf die erste Note der nächsten Tonart. So ist "Ie" einer Tonart gleich "Ia" der nächsten Tonart. Das hat Konsequenzen bei der Gestaltung von Programmschleifen und Abbruchbedingungen.
Eine Tonartfolge- Struktur beinhaltet wie die Notenfolge- Struktur auch, drei Zeigervariablen und zwei "short" Variablen "First" und "Len", sowie ein Feld von Tonartstrukturen mit "SEG" Elementen. Für den Umgang mit Tonartstrukturen und Tonartfolgen existieren in "Tonarten.c" folgende Funktionen, deren Funktion sinngemäß den Funktionen für Noten und Notenfolgen entspricht: OpenTf(),
CloseTf(), TfSegment(), AddTonart(), GetTonart(), LastTonart().
Weiterhin gibt es Funktionen für die Tonartanalyse von Notenfolgen (Tonarten(), Tonartzahl(), GetTonartTabelle(), Rnd_Tonart(), Tonart1(), Tonart2(), Tonartanalyse()), sowie fr die Arbeit mit Tonartverwandtschaften (RndTonartverwandtschaft(), Verwandtonart(), Verwandtschaft()) und die Funktion GetTonartI(), die die Tonart zu einem bestimmten Notenindex liefert.
Die Funktion "Leiterton()" liefert die Leitertonnummer einer Note bei gegebener Tonart, die Funktion "Note()" liefert zu gegebenem Leiterton und Tonart die entsprechende Note. Diese Funktionen benutzen das zweidimensionale integer- Feld "TonartSteps[][]", welches zu jedem Tongeschlecht die Folge der Halbtonschritte
enthält, um die Tonleitern korrekt zu bilden. In das zweidimensionale integer- Feld "TonartTest[][]" werden, durch einen Aufruf der Funktion "Tonarten()", die für einen Notenfolgenabschnitt in Frage kommenden Tonarten eingetragen. Das Feld enthält ein Element für jede Tonart. Hat ein Element einen Wert größer 0, so ist diese Tonart fr den untersuchten Notenfolgenabschnitt möglich.
Aus den möglichen Tonarten kann dann mit weiteren Funktionen (Tonart1().Tonart2()...)eine ausgewählt werden. Die Funktion "GetTonartTabelle(n)" liefert die n.te gültige Tonart aus der Tabelle. Funktionen, deren Rückgabewert vom Typ "struct Tonart" ist, signalisieren einen Fehler als Rückgabe: Tonart- Grundton gleich "note_p".

>

5. Rhythmische Phrasen

Rhythmische Elemente stellen die "Phrasen" dar. Es handelt sich ganz allgemein um Folgen von Noten, bei denen die wesentlichen Informationen im Notenwert liegen und die nur den Zustand "Pause" oder "reguläre Note" kennen. In der Programmdatei "Phrasen.c" sind wieder die bekannten Funktionen: OpenPf(), ClosePf(), PfSegment(), AddPhrase(), GetPhrase(), LastPhrase(), PutPhrase()
und GetPhraseI() realisiert. Weiterhin enth"lt sie eine Tabelle "Standard Phrasen" (StdPhrasen[]) mit vordefinierten Rhythmen, eine Tabelle für den Austausch von Phrasen (Kasten) und dazugehörige Funktionen (Kasten_Nr(), MakeSammelKasten(), NeuPhrase() und Phrasenaustausch()). Die Funktionen für die
Phrasenanalyse von Notenfolgen heißen: Phrasentest() und Phrasenanalyse(). Außerdem existiert eine Funktion Motivwahl(), die zu einer gegebenen rhythmischen Phrase ein Motiv in der angegebenen Tonart wählt.

6. Oktaven

Die Programmdatei "Oktaven.c" enthält Funktionen für die Bestimmung von Oktavwerten nach einfachen Kriterien.

7. Ein-/Ausgabe von Notenfolgen und Musikstücken (Scores)

Für die Ein-/Ausgabe von Notenfolgen und Scores gibt es mehrere Möglichkeiten, die je nach Verwendung des Systems zur Anwendung kommen, bzw. noch um weitere Arten ergänzt werden müssen. Realisiert sind die Ein-/Ausgabe in einer unstandardisierten Textnotation (InMelodie(), PrMelodie(), LoadAscii() und SaveScore()) die folgendermaßen beschrieben ist: [n/m]N[O][, oder .]
wobei [n/m] ein Notenwert bedeutet, der, wenn er weggelassen wird gleich dem Notenwert der vorhergehenden Note bzw. "1/1" gesetzt wird. "N" repräsentiert die eigentliche Note als Textkürzel ("c", "cis","d","dis","e", "f", "fis", "g", "gis","a","b","h","p").
Schließlich [O] ein optionaler Oktavwert, der, wenn er weggelassen wird, gleich dem Oktavwert der vorhergehenden Note bzw. "1" gesetzt wird. Mehrere Noten werden durch Kommata getrennt, ein Punkt beendet die Notenfolge.
Eine weitere Ein-/Ausgabe Möglichkeit ist die Arbeit mit standardisierten Dateiformaten für Musikstücke. Dabei stehen je nach Rechnersystem unterschiedliche Formate zur Verfügung.
Je nach Verfügbarkeit einer Midi- Schnittstelle kann man ein Musikstück direkt über ein angeschlossenes Midi- Instrument spielen, die entsprechende Funktion heißt "Play()".

8. Test- und Analysefunktion

Die Programmdatei "Analyse.c" enthält eine Funktion "Analyse()", mit der es möglich ist, Notenfolgen, dazugehörige Tonart- und Rhythmusphrasenabschnitte in einer Datei abzulegen. Die Datei wird mit einem Filepointer spezifiziert.
Im Programm muss ein Filepointer "fp_prot" global deklariert sein und einer Datei zugewiesen werden (bzw. Nullpointer). In dieser Datei werden alle signifikanten Zwischenergebnisse abgelegt, um nach dem Programmlauf eventuell den Kompositionsvorgang zu überprüfen.

>

9. Kompositionsprogramme

Die oben beschriebenen Funktionen und Datenstrukturen sind die Grundlage für Programme die spezielle Kompositionen ausführen können. Bisher wurden die Programme "vierstimmiger Satz (Vierstim.c)", "zweistimmige Fuge in strenger Form (Fuge.c", "Jazzparnaß (Jazzpar.c, Skalen.c)" und "Cantus Firmus (Cantus.c)" realisiert.

>