6. Musik und Sound

 

Sounds, aber auch die herausragenden Musikfähigkeiten, haben den C64 erst zu dem gemacht, was er ist: Der meistverkaufte Computer der 80-er und 90-er. Dies verdankt er vor allem dem SID-Soundchip. Deshalb gilt: Wer dem C64 Musik entlocken will, muss sich eingehend mit dem SID befassen. Leider stößt BASIC hierbei an seine Grenzen - wieder ein Grund mehr, sich nach dem BASIC-Kurs direkt der Assembler-Programmierung zu widmen. Vieles im Bereich Musik und Sound geht nämlich nicht ohne Maschinenprogramme.

 

6.1 Der SID-Soundchip

 

Der SID (dies ist die Abkürzung von Sound Interface Device) wurde von Michael Yannings Anfang der 80-er Jahre für Commodore entwickelt, um dem Anwender einen einfach zu programmierenden Synthesizer-Chip zur Verfügung zu stellen. Dieser Chip sollte möglichst einfach aufgebaut sein, aber dennoch effizient arbeiten. Heraus kann der SID, der beide Kriterien erfüllt: Der interne Aufbau ist eher schlicht, aber zusammen mit den Möglichkeiten, externe analoge Filter zu verwenden, und der sehr feinen Skalierbarkeit der Ausgabefrequenzen, leistet der SID in Ihrem C64 gute Dienste.

 

6.1.1 Interner Aufbau

 

Um den SID optimal zu programmieren, müssen Sie zunächst ein paar Dinge über den internen Aufbau wissen, und auch ein paar physikalische Grundlagen der Erzeugung von Tönen verstehen. Keine Angst, dies ist wirklich nicht schwer, und Sie müssen auch keine höhere Mathematik beherrschen (na gut, wenn Sie höhere Mathematik beherrschen, wird vieles einfacher). Sie müssen sich einfach zunächst nur einen Zähler vorstellen, der zu dem aktuellen Wert, der bei 0 beginnt, immer jeweils einen bestimmten Betrag addiert - beispielsweise 1. Auf diese Weise erhalten Sie die folgende Zahlenreihe:

 

0, 1, 2, 3, …

 

Stellen Sie sich nun vor, dass der Zähler eine Breite von 24 Bit besitzt, das heißt, dass der höchste Wert, den dieser Zähler annehmen kann, 224-1 ist. Wenn diese Zahl (224-1=16.777.215=$FFFFFF) erreicht ist, dann springt der Zähler wieder auf 0 zurück (dies nennt man dann einen Überlauf).

Angenommen, Sie haben nun die Möglichkeit, Zahlenwerte als Spannungen auszugeben, und diese Spannungen an den Audio-Eingang Ihres Monitors weiterzuleiten. Was würde nun geschehen, wenn Sie einen Zähler in eine Spannung umwandeln, und diese Spannung an den Audio-Ausgang weitergeben? Die Antwort ist, dass im Falle des hier beschriebenen Zählers nicht viel geschehen würde, weil sich der 24-Bit-Zähler, der in jedem Schritt immer nur um 1 erhöht wird, viel zu langsam ändert, als dass Ihr Ohr einen hörbaren Ton daraus machen könnte (naja, im Endeffekt erzeugt Ihr Gehirn die wahrnehmbaren Töne, nicht direkt Ihr Ohr). Aber wie können Sie das vorige Problem lösen, und hörbare Töne erzeugen? Die Antwort ist die Verwendung der Modulo-Funktion. Die Modulo-Funktion liefert den Rest einer Division. Wenn Sie Ihren 24-Bit-Zähler Modulo 4096 nehmen, dann erhalten Sie die folgende Zahlenreihe:

 

0, 1, 2, …, 4095, 0, 1, 2, …

 

Wenn Sie nun annehmen, dass zu Ihrem Zähler einmal pro Mikrosekunde der Wert 1 addiert wird, dann erhalten Sie schon 1.000.000/4.096=244,14 Durchläufe pro Sekunde. Dies ist schon schnell genug, um einen hörbaren Ton zu erzeugen. Und Sie haben noch mehr Glück: Der SID tut genau dies: Er wandelt genau solche Zähler durch einen internen DAC in Spannungen zwischen 0 und 3,3V um. Ein DAC (Digital/Analog Converter) ist ein elektronischer Baustein, der digitale Werte in analoge Spannungen umwandelt. Diese Spannungen können, wenn sie sich schnell genug ändern, dazu benutzt werden, hörbare Töne zu erzeugen. Hierzu werden die Spannungen an einen entsprechenden Verstärker-Baustein in Ihrem Monitor oder an eine Stereoanlage weitergegeben. Und Sie haben auch hier wieder Glück: Der SID generiert Line-Pegel, was nichts anderes bedeutet, als dass Sie den Ausgang des SID direkt in den Line-In-Eingang eines Verstärkers stecken können. Allerdings müssen Sie dazu einen entsprechenden Adapter im Internet bestellen, denn der alte C64 verwendet noch DIN- und keine Chinch-Stecker.

Aber was haben Sie nun von dem bisher Gesagten? Ganz einfach: Der SID besitzt drei Zähler, die unabhängig voneinander arbeiten, und zu denen auch andere Werte addiert werden können, als 1. Zusätzlich können die einzelnen Zähler auch in verschiedener Weise benutzt werden. Der SID kann nämlich aus einem der drei Ausgangszähler in der folgenden Weise die folgenden vier Wellenformen erzeugen:

 

Sägezahn-Wellenform

 

·     Addieren des Referenzwertes für den aktuellen Zähler zum aktuellen Zähler.

·     Verschiebung des aktuellen Zählers um 16 Bits nach rechts.

·     Weitergabe der verbleibenden 8 Bits an den DAC (dieser hat beim SID eine breite von 8 Bit).

 

Die Sägezahn-Wellenform ist also eine aufsteigende Zahlenfolge, die ab dem Wert 255 wieder bei 0 anfängt. Die Sägezahn-Wellenform hört sich auch rau an, und hat in der Tat etwas von einer Säge. Verwendet wird diese Wellenform unter anderem für Klavier-Sounds.

 

Dreieck-Wellenform

 

·     Addieren des Referenzwertes für den aktuellen Zähler zum aktuellen Zähler

·     Verschiebung des aktuellen Zählers um 12 Bits nach rechts. Dadurch entsteht ein 4096 mal langsamerer 12-Bit-Zähler.

·     Wenn das oberste Bit des neuen Zählers 0 ist, Weitergabe des um 3 Bits verschobenen neuen Zählers an den DAC

·     Wenn das oberste Bit des neuen Zählers 1 ist, Umdrehen sämtlicher Bits des neuen Zählers, und anschließendes Ausmaskieren des 12. Bits des neuen Zählers. Auch hier werden anschließend nur die Bits 11-4 des neuen Zählers an den DAC weitergereicht.

 

Die Dreieck-Wellenform ist also eine aufsteigende Zahlenfolge, die ab dem Wert 255 aber nicht wieder bei 0 anfängt, sondern anschließend zu einer absteigenden Zahlenfolge wird. Ab dem Wert 0 wird dann wieder mit einer aufsteigenden Zahlenfolge weitergemacht. Dieses Verhalten führt auf dem Oszilloskop zu einer Kurve, die wie ein Dreieck aussieht. Die Dreieck-Wellenform hört sich auch nicht rau an, sondern weich und harmonisch. Leider ist die Dreieck-Wellenform besonders für die unteren Oktaven sehr leise. Diese Wellenform wird für Gitarren-Sounds benutzt, oft auch zusammen mit SID-Filtern.

 

Rechteck-Wellenform

 

·     Addieren des Referenzwertes für den aktuellen Zähler zum aktuellen Zähler

·     Verschiebung des aktuellen Zählers um 12 Bits nach rechts. Dadurch entsteht ein 4096 mal langsamerer 12-Bit-Zähler.

·     Wenn der neue Zähler eine vorher definierte Grenze (die sog. Pulsbreite) unterschreitet, wird der Wert 255 an den DAC weitergegeben

·     Wenn der neue Zähler eine vorher definierte Grenze (die sog. Pulsbreite) überschreitet, wird der Wert 0 an den DAC weitergegeben

 

Die Rechteck-Wellenform springt dauernd zwischen den Werten 0 und 255 hin und her. Dieses Verhalten führt auf dem Oszilloskop zu einer Kurve, die wie ein Rechteck aussieht. Die Rechteck-Wellenform hört sich synthetisch an, etwa so, wie eine alte Videopac-Spielekonsole. Die Rechteck-Wellenform wird oft zusammen mit SID-Filtern benutzt, um z.B. Motorengeräusche nachzuahmen. Allerdings erzeugen Kolben bei der Explosion im Motor oft komplexe Wellenformen, die nicht naturgetreu vom SID nachgeahmt werden können.

 

Rauschen

 

Der SID kann auch aus einem Zähler mittels eines Algorithmus Pseudo-Zufallswerte generieren und an den DAC weiterleiten. Zufallswerte werden vom Ohr als Rauschen wahrgenommen. Rauschen kann zusammen mit einem ausklingenden Ton für Explosionen oder Wasser-Sounds benutzt werden.

 

6.2 Ausgabe von Tönen mit einer Stimme

 

Nun wollen wir den Kammerton A4 (440 Hz) ausgeben. Dazu benutzen wir den ersten der drei verfügbaren Zähler, die auch als die erste von drei Stimmen bezeichnet wird (Stimme 0). Damit Sie auf die einzelnen Zähler zugreifen können, blendet der SID seine Prozessorregister in den Speicher des C64 so ein, dass das erste Register (SID-Register Nr. 0) an der Adresse 54272 liegt.

 

6.2.1 Frequenzauswahl mit den SID-Registern

 

Der SID wird nun mit etwa 1 MHz getaktet, und läuft synchron zum 6510-Prozessor. Das bedeutet, dass im Falle der Sägezahn-Wellenform Ihr Ton nur mit 1/16 Hz ausgegeben wird, wenn Sie pro Mikrosekunde den Wert 1 zu dem entsprechenden Zähler addieren. Dies können Sie leicht ausrechnen: Von dem Zähler, der bis 16.777.215 zählt, werden nur die obersten 12 Bits für die Erzeugung der Wellenformen benutzt, dies entspricht dann nur noch 4.096 Zählerschritten pro Sekunde. Da jedoch die Sägezahnwellenform diesen neuen Zähler noch einmal auf einen Bereich zwischen 0 und 255 abbildet, erhalten Sie dann nur noch eine Frequenz von 256/4096=1/16 Hz. Wenn Sie dann zu dem ursprünglichen Zähler jede Mikrosekunde statt 1 den Wert 2 addieren, erhalten Sie eine Frequenz von 2/16 Hz. Für den Kammerton A4 ist also der in jedem Schritt zu addierende Wert 440/(1/16)=7040. Diesen Wert müssen Sie nun in die SID-Register Nr. 0 und 1 schreiben. Hierbei enthält dann SID-Register Nr. 0 das erste Byte des Wertes 7040 (Lo-Byte), und SID-Register Nr. 1 das zweite Byte des Wertes 7040 (Hi-Byte). Die zwei folgenden BASIC-Zeilen leisten dies nun:

 

10 SI=54272: F=7040

20 HI=INT(F/256): LO=F-256*HI

30 POKE SI+1,HI: POKE SI,LO

 

Wenn Sie die Zähler initialisiert haben, müssen Sie den Ton mit voller Lautstärke einschalten. Dies erreichen Sie, indem Sie den Wert 15 in SID-Register Nr. 24 schreiben:

 

40 POKE SI+24,15

 

Nun müssen Sie die Wellenform auswählen, die Sie verwenden wollen. Für die erste Stimme müssen Sie dazu einen der folgenden Werte in SID-Register Nr. 4 schreiben:

 

·     16 (Bit 4=1) für die Dreieck-Wellenform

·     32 (Bit 5=1) für die Sägezahn-Wellenform

·     64 (Bit 6=1) für die Rechteck-Wellenform

·     128 (Bit 7=1) für Rauschen

 

Sie schreiben also

 

50 POKE SI+4,32

 

und geben anschließend RUN ein. Leider geschieht nichts und Sie hören keinen Ton. Dies liegt daran, dass die Sache so einfach dann auch wieder nicht ist. Sie haben dem SID nämlich überhaupt nicht mitgeteilt, wann Ihr Kammerton A4 abgespielt werden soll, und erst recht nicht, wie lange. Soll der Ton gehalten werden? Soll der Ton anschwellen, oder sogar nachhallen? Zu diesem Zweck müssen Sie zusätzlich noch eine Hüllkurve angeben. Die Hüllkurve ist das, was den Ton selbst ausmacht. Ohne Definition einer Hüllkurve hören Sie deswegen nichts. Die Hüllkurve wird durch die folgenden 4 Parameter definiert:

 

·     Die Anschwellzeit A (attack), die angibt, wie lange der Ton braucht, um zu seiner vollen Lautstärke zu kommen.

·     Die Abschwellzeit D (decay), die angibt, wie lange der Ton braucht, um bis zu seinem Haltepegel abzuklingen.

·     Der Haltepegel S (sustain), der die Lautstärke eines eventuell gehaltenen Tons angibt (also der Haltepegel).

·     Die Ausklingzeit R (release), die die Nachklingzeit vom Haltepegel auf 0 angibt.

 

Das Einstellen der Hüllkurve, also die Programmierung des Hüllkurvengenerators, ist auf dem SID etwas speziell zu handhaben. Es wurde, um Platz zu sparen, das Startbit (das sog. Gate-Bit) für den Ton in Register Nr. 4 untergebracht. Sie müssen also den Ton zusammen mit der Wellenformauswahl starten. Auch die Werte für A, D, S und R müssen Sie in spezieller Weise handhaben, nämlich als einzelne Nibbles. So stehen z.B. bei der ersten Stimme (Stimme 0) die Werte für A und D im hohen bzw. niedrigen Nibble von SID-Register Nr. 5. Auch bei den Werten für S und R ist dies so, und S steht im hohen, und R im niedrigen Nibble von SID-Register Nr. 6. Dies bedeutet natürlich auch, dass Sie die Werte für A, D, S und R nicht direkt in Millisekunden eingeben können, sondern stattdessen folgende Tabelle verwenden müssen:

 

Attack-Zeit

 

Wert

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

Zeit (ms)

2

8

16

24

38

56

68

80

100

250

500

800

1000

3000

5000

8000

 

Decay/Release-Zeit

 

Wert

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

Zeit (ms)

6

24

48

72

114

168

204

240

300

750

1500

2400

3000

9000

15000

24000

 

Für das letzte Beispiel bedeutet dies: Sie müssen das Programm so abändern, dass Sie erst die Tonfrequenz auswählen, und dann die Hüllkurve erstellen. Um anschließend den Ton zu starten, und den SID in den Zyklus Attack/Decay/Sustain zu versetzen, müssen Sie zusammen mit der Wellenform das Gate-Bit (Bit 0 in SID-Register Nr. 4) auf 1 setzen. Dies führt dann zu dem folgenden, einwandfrei laufenden Programm:

 

16-A440

10 SI=54272: F=7040: POKE SI+24,15

20 HI=INT(F/256): LO=F-256*HI

30 POKE SI+1,HI: POKE SI,LO

40 POKE SI+5,10: POKE SI+6,0: REM A=0, D=10, D=0, R=0

50 POKE SI+4,32

60 POKE SI+4,33

 

An dem letzten Beispiel sehen Sie sehr schön, wie die Tonausgabe durch das Gate-Bit gesteuert wird: Wenn das Gate-Bit 0 ist, geht der SID in die Release-Phase über (die hier nicht verwendet wird), wenn das Gate-Bit 1 ist, geht der SID in die Attack-Phase über, der nahtlos die Decay- und die Sustain-Phase folgen. Wenn dann der Wert für S und R=0 ist, dann kann der Ton durch Setzen des Gate-Bits auf 0 direkt gestoppt werden. Da der SID unabhängig vom Hauptprozessor läuft, benutzen viele Spiele die oben verwendete Technik, S und R auf 0 zu setzen, um Melodien im Hintergrund abzuspielen. Allerdings werden bei Spielen oft Maschinenprogramme benutzt, die die SID-Register viel schneller beschreiben können, als BASIC.

 

6.2.2 Die SID-Register (Quelle: https://www.c64-wiki.de/wiki/SID)

 

Wie auch schon im Falle des VIC möchte ich Ihnen nun eine Zusammenstellung sämtlicher Register des SID vorstellen. Auch diese Tabelle werden Sie wahrscheinlich in Zukunft noch oft benötigen.

 

SID-Register

Adresse

Bedeutung

0

54272

Frequenz Stimme 0 Lo-Byte

1

54273

Frequenz Stimme 0 Hi-Byte

2

54274

Rechteck-Pulsbreite Stimme 0 Lo-Byte

3

54275

Rechteck-Pulsbreite Stimme 0 Hi-Nibble

4

54276

Wellenform Stimme 0 und SID-Status-Register**

Bit 7: Rauschen

Bit 6: Rechteck

Bit 5: Sägezahn

Bit 4: Dreieck

Ein gesetztes Wellenform-Bit wählt die Wellenform aus, es kann nur immer eine Wellenform ausgewählt werden, wobei das höchste Bit, das gesetzt ist, entscheidet, welche Wellenform benutzt wird.

Bit 3: Testbit

Erst Testbit auf 1 setzen, dann auslesen. Wenn das Testbit noch 1 ist, ist der SID OK.

Bit 2: Ring-Modus

Ist dieses Bit 1, können mehrere SID-Chips im Verbund arbeiten. Wenn die Verbindung erfolgreich ist, ist das Sync-Bit (Bit 1) gesetzt.

Bit 0: Gate-Flag

1=ADS-Phase einleiten

0=Release-Phase einleiten

5

54277

Hi-Nibble: Attack-Zeit für Stimme 0

Lo-Nibble: Decay-Zeit für Stimme 0

6

54278

Hi-Nibble: Sustain (Haltepegel) für Stimme 0

Lo-Nibble: Release-Zeit für Stimme 0 (Gate 0=0)

7

54279

Frequenz Stimme 1 Lo-Byte

8

54280

Frequenz Stimme 1 Hi-Byte

9

54281

Rechteck-Pulsbreite Stimme 1 Lo-Byte

10

54282

Rechteck-Pulsbreite Stimme 1 Hi-Nibble

11

54283

Wellenform Stimme 1 (Bit 1-3 unbenutzt)

Wellenform- und Gate-Bits stimmen mit Stimme 0 überein

12

54284

Hi-Nibble: Attack-Zeit für Stimme 1

Lo-Nibble: Decay-Zeit für Stimme 1

13

54285

Hi-Nibble: Sustain (Haltepegel) für Stimme 1

Lo-Nibble: Release-Zeit für Stimme 1 (Gate 1=0)

14

54286

Frequenz Stimme 2 Lo-Byte

15

54287

Frequenz Stimme 2 Hi-Byte

16

54288

Rechteck-Pulsbreite Stimme 2 Lo-Byte

17

54289

Rechteck-Pulsbreite Stimme 2 Hi-Nibble

18

54290

Wellenform Stimme 2 (Bit 1-3 unbenutzt)

Wellenform- und Gate-Bits stimmen mit Stimme 0 überein

19

54291

Hi-Nibble: Attack-Zeit für Stimme 2

Lo-Nibbe: Decay-Zeit für Stimme 2

20

54292

Hi-Nibble: Sustain (Haltepegel) für Stimme 2

Lo-Nibble: Release-Zeit für Stimme 2 (Gate 2=0)

21

54293

Grenzfrequenz für den SID-Filter (Lo-Byte)*

22

54294

Grenzfrequenz für den SID-Filter (Hi-Byte)*

23

54295

Hi-Nibble: Resonanz (Stärke) des SID-Filters

Lo-Nibble: Gefilterte Stimmen (Bit 0-2), aber immer nur eine einzige

Bit 3: Externer Filter (einschalten=1), z.B. über eine Subgruppe am Mischpult

(Ist Bit 3 gesetzt, so werden sämtliche Stimmen gefiltert)

24

54296

Lo-Nibble: Lautstärke 0-15 für alle Stimmen

Hi-Nibble: Filtermodus (es kann immer nur ein einziger Filter aktiv sein)

Bit 7: Ausschalten von Stimme 2

Bit 6: Wählen des Hochpassfilters (1=an)

Bit 5: Wählen des Bandpassfilters (1=an)

Bit 4:  Wählen des Tiefpassfilters (1=an)

25

54297

X-Koordinate (0-255) eines Paddles oder einer Maus, wenn dieses Gerät angeschlossen ist, ansonsten 0

26

54298

Y-Koordinate (0-255) eines Paddles oder einer Maus, wenn dieses Gerät angeschlossen ist, ansonsten 0

27

54299

Oszillator-Register für Stimme 2:

Hier erscheinen die 8-Bit-Werte, die Stimme 2 an den DAC weitergibt. Wenn Stimme 2 ausgeschaltet wurde, dann werden hier bei Auswahl der Rauschen-Wellenform Pseudo-Zufallszahlen erzeugt.

28

54300

Hüllkurven-Geber für Stimme 2:

Hier erscheint der aktuelle Lautstärke-Wert, den der Hüllkurvengenerator gerade für Stimme 2 benutzt. Mit schnellen Maschinensprache-Routinen kann man diesen Wert auslesen, und mit den Frequenzregistern für die anderen Stimmen koppeln. Auf diese Weise können interessante Effekte programmiert werden.

 

* Die Grenzfrequenz des SID-Filters hängt davon ab, mit welchem externen Kondensator man den SID beschaltet. Beim C64 ist die Grenzfrequenz ungefähr mit dem binären 12-Bit-Wert identisch, den Sie in die SID-Register 21 und 22 eintragen. Wenn Sie also hier den Wert 1000 eintragen (SID-Register Nr. 21=232, SID-Register Nr. 22=3), dann erhalten Sie auch ungefähr eine Grenzfrequenz von 1000 Hz. Da jede Stimme ein eigenes Filter-Bit besitzt, kann der SID-Filter für jede Stimme unabhängig benutzt werden, allerdings gelten die Filtereinstellungen global. Das heißt, dass nicht Stimme 0 den Hochpassfilter, und Stimme 1 den Tiefpassfilter benutzen kann.

 

** Das SID-Status-Register ist entgegen der Angaben in der Dokumentation des SID durch MOS Technology Inc. nur ein einziges Mal vorhanden, und nicht für jede Stimme separat. Das heißt, dass nur mit dem SID-Register Nr. 4 (und nicht mit SID-Register Nr. 11 und 18) der SID z.B. in den Ring-Modus versetzt werden kann. Auch das Test-Flag gibt es, wie auch das Sync-Bit, nur in SID-Register Nr. 4.

 

6.3    Abspielen von Songs

 

Kommen wir nun zum ersten Beispiel. In diesem Listing wird ein einfacher Song abgespielt, den Sie in ähnlicher Weise auch immer wieder im Internet antreffen, z.B. auf www.poke-53280.com, wo ich dann dieses Listing auch herhabe.

 

17-SIMPLESONG

10 SI=54272

20 POKE SI+24,15: REM VOLLE LAUTSTAERKE

30 POKE SI+5,9:POKE SI+6,0:REM KLAVIER

40 READ HF,LF,L:IF HF<0 THEN END

50 POKE SI,LF:POKE SI+1,HF

60 POKE SI+4,33:REM GATE-BIT=1 STARTET DEN TON (ADS-PHASE)

70 FOR T=1 TO L:NEXT T:REM WARTESCHLEIFE FUER DEN TON

80 POKE SI+4,32:REM GATE-BIT=0 STARTET DIE R-PHASE

90 FOR T=0 TO 50:NEXT T:REM TON ETWAS AUSKLINGEN LASSEN

100 GOTO 40

110 DATA 25,177,250,28,214,250

120 DATA 25,177,250,25,177,250

130 DATA 25,177,125,28,214,125

140 DATA 32,94,250,25,177,250

150 DATA 28,214,250,19,63,250

160 DATA 19,63,250,19,63,250

170 DATA 21,154,125,24,125,63

180 DATA 25,177,250,24,63,125

190 DATA 19,63,250,-1,-1,-1

 

Im letzten Beispiel wird nur der Wert für Decay benutzt (D=9), nicht aber der Wert für Attack (A=0), Sustain (D=0) und Release (R=0). Dies bedeutet, dass der Ton sofort präsent ist, und innerhalb von 0,75 Sekunden vollständig abschwellt. Deshalb muss in Zeile 30 auch nur der Wert 9 in SID-Register Nr. 5 eingetragen werden, SID-Register Nr. 6 wird dagegen auf 0 gesetzt. Natürlich müssen Sie auch beim SID vorher in Zeile 10 die Basisadresse durch die Anweisung SI=54272 festlegen, denn sonst können Sie nicht anhand der Nummer auf die Register zugreifen. Anders, als beim VIC, müssen Sie den SID allerdings dadurch initialisieren, dass Sie in Zeile 20 das Lautstärkeregister auf den Wert 15 setzen, denn sonst hören Sie keinen Ton.

 

Nach der Initialisierung der SID-Register muss der Song in einer Schleife (Zeile 40-100) abgespielt werden. Der Song selbst steht in DATA-Zeilen (Zeile 110-190). Der Song besitzt nur eine Stimme, und die Werte für die Frequenzangaben für die einzelnen Noten wurden in diesem Beispiel so in den DATA-Zeilen abgelegt, dass sie direkt in die SID-Register geschrieben werden können. Zeile 40 liest diese Daten nun als Dreierpäckchen der Form {Hi-Byte (HF), Lo-Byte (LF), Länge (L)} aus, und schreibt Lo- und Hi-Byte in SID-Register Nr. 0 und 1. SID-Register Nr. 0 enthält das Lo-Byte, und SID-Register Nr. 1 das Hi-Byte für die Frequenzangabe für Stimme 0. So erhalten Sie einen gültigen 16-Bit-Wert, der für den Zähler der ersten Stimme benutzt werden kann. In Zeile 60 wird nun die Sägezahn-Wellenform zusammen mit einem gesetzten Gate-Bit in SID-Register Nr. 4 eingetragen, wodurch auch gleich der Ton gestartet wird. Da der Ton sofort auf 0 abschwillt, kann das Programm direkt nach Starten des Tons in eine Warteschleife (Zeile 70) eintreten. Wie lange diese Schleife läuft, bestimmt das dritte Byte des zuvor ausgelesenen Dreierpäckchens (also die Variable L). Nach der Warteschleife für die Notendauer wird das Gate-Bit in SID-Register Nr. 4 wieder gelöscht, und der Ton wird in Zeile 90 noch etwas nachklingen lassen. Diese Zeile wurde eingefügt, damit zwischen zwei gleichen Noten eine kleine Pause ist. Ohne diese Pause würde man zwei hintereinander folgende gleiche Noten als eine einzige Note wahrnehmen.

 

Der Song endet, wenn für Frequenz und Länge der Wert -1 aus den DATA-Zeilen gelesen wird. Diese Werte werden für die SID-Register nicht verwendet, und können deshalb als Stopp-Marker dienen. Kommen wir nun zum nächsten Beispiel. Das Listing ist mit dem vorigen Listing identisch, demonstriert Ihnen aber durch einen Fortschrittsbalken, dass der SID wirklich unabhängig von Ihrem Hauptprogramm arbeitet.

 

18-SIMPLESONG2

10 SI=54272:K=0:PRINT"[SHIFT+CLR/HOME]SPIELE SONG"

20 POKE SI+24,15:REM VOLLE LAUTSTAERKE

30 POKE SI+5,9:POKE SI+6,0:REM KLAVIER

40 READ HF,LF,L:IF HF<0 THEN END

50 POKE SI,LF:POKE SI+1,HF

60 POKE SI+4,32:POKE SI+4,33

70 FOR T=1 TO L

80 POKE 1064+(K/10),46:K=K+1

90 NEXT T

100 GOTO 40

110 DATA 25,177,25,28,214,25

120 DATA 25,177,25,25,177,25

130 DATA 25,177,12,28,214,12

140 DATA 32,94,25,25,177,25

150 DATA 28,214,25,19,63,25

160 DATA 19,63,25,19,63,25

170 DATA 21,154,12,24,63,12

180 DATA 25,177,25,24,63,12

190 DATA 19,63,25,-1,-1,-1

 

Die Warteschleife in Zeile 70-90 wartet nicht nur die Zeit L, die Sie bei der Notendauer angeben, sondern schreibt auch gleichzeitig einen Fortschrittsbalken in Form von Pünktchen in die zweite Zeile Ihres Bildschirms. Hierdurch müssen Sie jedoch die Längenangabe für Ihre Noten durch 10 teilen, was leider ein reiner Erfahrungswert ist.

 

6.3.1 Notenwerte in Frequenzen umrechnen

 

Vielleicht gefallen Ihnen die letzten Beispiele nicht so wirklich. Zugegeben: Mir auch nicht! Aber das ist auch kein Wunder, denn ich habe die letzten Beispiele bewusst so gewählt, weil sie eben Unzulänglichkeiten enthalten. Die größte Unzulänglichkeit ist, dass Sie Ihre Noten nicht direkt in Ihren DATA-Zeilen angeben können, z.B. durch die Anzahl der Halbtonschritte ab einem bestimmten tiefsten, gerade noch hörbaren Ton. Dieser tiefste, gerade noch hörbare Ton ist auf dem SID beispielsweise 8,176 Hz und entspricht dem Ton C1, der noch einmal um zwei Oktaven erniedrigt wird.

Wählen wir nun den tiefst möglichen Ton, der auf dem SID einer Frequenz von 8,176 Hz entspricht, als Ausgangspunkt einer Abbildungsfunktion von Notenwerten auf eine Frequenz in Hz. Sie denken vielleicht nun, dass dies nicht so schwer sein kann, denn im Endeffekt müssen Sie ja nur eine simple Geradengleichung der Form

 

y=ax+b

 

aufstellen, und für b=8,176 Hz, sowie für a Ihren Notenwert (gemessen in Halbtonschritten) einsetzen. Leider ist es aber so, dass sich in jeder neuen Oktave die Frequenz verdoppelt, und Sie es dann auch niemals schaffen, eine lineare Abstufung zwischen den Noten zu erhalten. Das menschliche Ohr hört also logarithmisch, deshalb benötigen sie auch die folgende Gleichung, um Noten auf Frequenzen abzubilden:

 

F(x)=a0*2x/12

 

F(x) ist hier die Frequenz, gemessen in Hz, und a0 ist die Frequenz des tiefsten Tons, den Sie auf Ihrem wie immer gearteten Instrument spielen können. Die Variable x beschreibt dann die Anzahl der Schritte, die Sie ab dem Ton a0 gehen müssen, um zu Ihrer gewünschten Note zu gelangen.

Natürlich können Sie schon sehr gut BASIC, und es ist für Sie deshalb ein Leichtes, eine FOR-Schleife zu erstellen, die die Frequenzwerte für die einzelnen Noten in einem Array ablegt. Dieses Array müssen Sie anschließend nur noch auslesen. Und da Sie wissen, dass die Frequenzwerte in Schritten von 1/16 Hz in die SID-Register 0 und 1 eingetragen werden müssen, können Sie diese dann auch direkt in POKE-Anweisungen einbauen.

Leider liegt der Teufel wie immer im Detail, denn der SID ist, wie auch der VIC, fest mit dem Speicher des C64 verbunden. Schlimmer noch: Der SID wird über den Prozessortakt gesteuert, und diesen Prozessortakt gibt im Endeffekt der VIC vor. Der VIC gibt also den Takt an, und dies ist auch gut so: Wenn der VIC nicht den Takt angeben würde, dann würde auch das Fernsehbild nicht korrekt mit dem Rasterstrahl synchronisiert. Und Sie sähen dann auch… Genau: Gar nichts! Aber auch dies ist nicht alles: Es gibt zusätzlich noch verschiedene Fernsehnormen. Die Fernsehnorm, die der C64 von Haus aus verwendet, ist die amerikanische NTSC-Norm (National Television System Company Standard). Ein NTSC-Bild besteht aus 480 Zeilen mit 720 Spalten, und wird mit 60 Hz Bildrate aufgebaut. Der VIC (und auch der SID) läuft dann mit 975,5 kHz Taktfrequenz. Wenn Sie allerdings in Deutschland leben, dann benutzen Sie wahrscheinlich die PAL-Fernsehnorm (Phase Alternate Line Imaging) mit 576 Zeilen und 720 Spalten, was dann dazu führt, dass Ihr SID mit 982,5 kHz getaktet wird. Wenn Sie es also sehr genau nehmen, dann müssen Sie die Frequenztabelle für Ihre Noten noch entsprechend korrigieren, je nachdem, welche Fernsehnorm Sie verwenden. Das nächste Listing tut genau dies: Es erzeugt eine Frequenztabelle für Ihre Notenwerte (C/-1 ist mit 8,176 Hz der tiefste Ton), und wählt für diese anschließend die PAL-Fernsehnorm aus (wenn Sie einen amerikanischen NTSC-C64 verwenden, müssen Sie Zeile 11 entsprechend anpassen). Anschließend wird der Song mit Notenwerten, anstatt mit SID-Register-Werten abgespielt.

 

19-SIMPLESONG3

10 SI=54272:K=0:PRINT"[SHIFT+CLR/HOME]SPIELE SONG"

11 FF=982.5:REM FREQUENZ DES CPU IN MHZ (PAL=982.5, NTSC=975.5)

12 FF=16*(1000/FF)

15 DIM NT(110)

16 FOR I=0 TO 109:NT(I)=INT(FF*(8.176*2^(I/12))):NEXT I

20 POKE SI+24,15:REM VOLLE LAUTSTAERKE

30 POKE SI+5,9:POKE SI+6,0:REM KLAVIER

40 READ NO,L:IF NO<0 THEN END

45 NO=NT(NO)

50 POKE SI+1,NO/256:POKE SI,NO-256*INT(NO/256)

60 POKE SI+4,32:POKE SI+4,33

70 FOR T=1 TO L

80 POKE 1064+(K/10),46:K=K+1

90 NEXT T

100 GOTO 40

110 DATA 71,25,73,25,71,25,71,25,71,12,73,12,75,25,71,25,73,25,66,25

120 DATA 66,25,66,25,68,12,70,12,71,25,70,12,66,25,-1,-1

 

Im Array NT (note table) stehen hier Werte zwischen 0 und 65535, es wird also das Hi- und das Lo-Byte zu einem einzigen Wert zusammengefasst. Natürlich muss dann das Hi-Byte und das Lo-Byte in Zeile 50 wieder getrennt, und anschließend korrekt in die SID-Register Nr. 0 und 1 geschrieben werden. Die Notentabelle selbst wird in Zeile 16 durch die Formel F(x)=a0*2I/12 berechnet (I ist hier der Schleifenzähler), allerdings müssen die einzelnen Frequenzwerte noch zusätzlich mit dem Faktor FF skaliert werden (der für einen PAL-C64 FF=1000/982.5 ist). In die Notentabelle passen 110 Frequenzwerte, danach ist der zulässige Wertebereich von 0-65535 überschritten. Der Song selbst verwendet aus dieser Tabelle allerdings nur die Oktaven zwischen C3 und C5.

 

6.3.2 Verwenden mehrerer Stimmen

 

Das nächste Beispiel spielt nun den Song aus dem letzten Beispiel mit mehreren Stimmen ab. Hierbei sind sämtliche Noten sämtlicher Stimmen identisch, Ihr Song sollte also auf diese Weise dreimal lauter klingen, als im Beispiel davor.

 

20-ESGEHTNICHT

10 SI=54272:K=0:SA=8192:PRINT"[SHIFT+CLR/HOME]SPIELE SONG"

11 FF=982.5:REM FREQUENZ DES CPU IN MHZ (PAL=982.5, NTSC=975.5)

12 FF=16*(1000/FF)

15 DIM NT(110):DIM NP(3):DIM NZ(3,2)

16 FOR I=0 TO 109:NT(I)=INT(FF*(8.176*2^(I/12))):NEXT I

20 POKE SI+24,15:REM VOLLE LAUTSTAERKE

30 POKE SI+5,9:POKE SI+6,0:REM STIMME 0

31 POKE SI+12,9:POKE SI+13,0:REM STIMME 1

32 POKE SI+19,9:POKE SI+20,0:REM STIMME 2

35 VO=0:NP(0)=8192

40 READ NO,L:IF NO<0 THEN GOTO 60

45 POKE SA,NO:POKE SA+1,L:SA=SA+2

60 POKE SA,255:POKE SA+1,255:SA=SA+2

70 VO=VO+1:IF VO=3 THEN GOTO 90

80 NP(VO)=SA:GOTO 40

90 CL=TI:REM COMPUTERUHR NACH CL UEBERTRAGEN

100 IF (TI-CL)=0 THEN GOTO 100

110 FOR I=0 TO 2

120 NZ(I,0)=NZ(I,0)+CL:IF NZ(I,0)>NZ(I,1) THEN NO=PEEK(NP(I)):VO=I: GOSUB 2000

130 NEXT I

140 IF NO=-1 THEN END

150 CL=TI:GOTO 100

1000 REM *** STIMME 0 ***

1010 DATA 71,25,73,25,71,25,71,25,71,12,73,12,75,25,71,25,73,25,66,25

1020 DATA 66,25,66,25,68,12,70,12,71,25,70,12,66,25,-1,-1

1030 REM *** STIMME 1 ***

1040 DATA 71,25,73,25,71,25,71,25,71,12,73,12,75,25,71,25,73,25,66,25

1050 DATA 66,25,66,25,68,12,70,12,71,25,70,12,66,25,-1,-1

1060 REM *** STIMME 2 ***

1070 DATA 71,25,73,25,71,25,71,25,71,12,73,12,75,25,71,25,73,25,66,25

1080 DATA 66,25,66,25,68,12,70,12,71,25,70,12,66,25,-1,-1

2000 REM *** NOTENSPIELER ***

2001 IF NO=255 THEN RETURN

2002 IF NO=0 THEN GOTO 2040:REM 0=PAUSE

2005 NO=NT(NO)

2010 OF=7*VO:REM OFFSET FUER STIMME

2020 POKE SI+OF+1,NO/256:POKE SI+OF,NO-(256*INT(NO/256))

2030 POKE SI+OF+4,32:POKE SI+OF+4,33

2040 NP(VO)=NP(VO)+1

2050 NZ(VO,1)=PEEK(NP(VO))

2060 NZ(VO,0)=0:NP(VO)=NP(VO)+1

2070 RETURN

 

Ich habe nun das letzte Listing bewusst nicht ausgiebig kommentiert, und auch bewusst den Namen „es geht nicht“ gewählt. Sie sollen auch das letzte Beispiel nur mit RUN ausführen. Wundern Sie sich bitte nicht darüber, dass nach einiger Zeit ein Song erklingt, bei dem die Noten der einzelnen Stimmen verzögert abgespielt werden, obwohl sämtliche Stimmen durch die Computeruhr synchronisiert werden, und auch alle die gleichen Noten enthalten. Versuchen Sie auch bitte, den Fehler im Programm zu finden, und studieren den Code ausgiebig. Doch ich versichere Ihnen: Wie Sie es auch anstellen, Sie bekommen es mit BASIC nicht hin, die einzelnen Gate-Bits für Ihre Stimmen gleichzeitig einzuschalten, so, dass Sie keine Verzögerung im Anschlag der Noten wahrnehmen. Dies liegt einfach daran, dass der POKE-Befehl zu langsam arbeitet. Selbst, wenn Sie die Computeruhr benutzen, um den Anschlagzeitpunkt für die einzelnen Noten zu bestimmen, ändert dies nichts an der Tatsache, dass Sie allein mit BASIC keine mehrstimmigen Stücke wiedergeben können. Auch hier brauchen Sie wieder Maschinensprache-Routinen.

 

6.4 Wirklich synchrone Stimmen

 

Wie schon gesagt, können Sie wirklich synchrone Stimmen in einem Musikstück nur durch Maschinensprache erreichen. Die Synchronisierung der Stimmen wird hier dadurch erreicht, dass der Player an den Timer-Interrupt gebunden wird, der normalerweise genau 60-mal in der Sekunde vom Kernal aufgerufen wird. Das heißt dann auch, dass der Player bei jedem Aufruf immer nur ein kleines Stückchen Ihres Songs abspielt. Da aber der Player so schnell hintereinander immer wieder aufgerufen wird, klingt die Wiedergabe sehr flüssig, und die Stimmen sind dann auch synchron. Dies heißt natürlich nun auch folgendes: Sie sind nun mit BASIC an die Grenze des Machbaren gestoßen, und müssen Maschinensprache lernen, wenn Sie noch mehr aus Ihrem SID herausholen wollen.