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 z.B. 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), was
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 Sound-Beispiele
Musik ist nur die eine Seite
des SID-Soundchips, Sounds sind die andere. Nicht nur Spiele leben von Sounds,
auch Anwendungen werden z.B. durch Klicks bei der Auswahl von Funktionen
„aufgepeppt“. Sounds sind im Gegensatz zu Musik nur kurze Geräusche, die
meistens auch abhängig von einem Ereignis abgespielt werden - dies können Sie
dann auch mit dem langsamen BASIC erreichen. Wenn Sie z.B. einen Kämpfer durch
ein Labyrinth steuern, dann können Sie bei jedem Schritt einen dumpfen Klick
wiedergeben. Wenn Sie dann mit einem Monster zusammenstoßen, können Sie auch
hier einen entsprechenden Sound wiedergeben.
Sounds sind im
Gegensatz zu Musik zwar auch mit BASIC, aber trotzdem sehr viel schwerer zu
programmieren, auch wenn sie nur kurz erklingen. Das liegt vor Allem daran,
dass Sounds oft den gesamten SID ausreizen müssen, um bestimmte Effekte zu
erzielen. Während Sie also für Musik „nur“ Noten oder Partituren lesen müssen,
und Sie oft schon mit einem normalen Klavierklang sehr weit kommen (wenn Sie
dann mit Assembler einen präzisen Notenplayer umsetzen können), erfordern
Sounds, dass Sie sich mit sämtlichen SID-Registern gut auskennen. Ferner gibt
es auch kein Patentrezept für Sounds. Sie können z.B. für diese, genau wie bei
Musikstücken auch, Interrupt-Routinen verwenden. Meistens verwenden sogar
Sounds und Musikstücke die gleiche Interrupt-Routine, was manchmal sehr
komplizierte Assembler-Programme erfordert. Andererseits können Sie auch nur
die Musikstücke im Hintergrund abspielen, und die Sounds stattdessen abhängig
von bestimmten Variablen machen, wie z.B. der y-Position des Spielers: Wenn
sich der Spieler im Sprung nach oben bewegt, wird ein aufsteigender Ton
erzeugt, wenn der Spieler im Sprung nach unten fällt, wird ein absteigender Ton
erzeugt. Auch die Frequenz eines Motorgeräusches kann z.B. vom aktuellen Gang
anhängig sein, oder sogar direkt von einer Geschwindigkeitsvariablen für das
Scrolling-Tempo.
Die Programmierung von
Sounds erfordert also sehr viel Erfahrung und Übung, deshalb kann ich Ihnen
auch nur Beispiele für Unterprogramme angeben (aufzurufen mit GOSUB), die immer
wieder so oder so ähnlich eingesetzt werden können. Das ausgiebig kommentierte
nächste Listing enthält eine Sammlung beliebter Sound-Effekte, die Sie mit der
entsprechenden Taste aus einem Menü auswählen können.
21-SOUNDDEMO
5 SI=54272:POKE
SI+24,15
10 POKE 53280,0:POKE
53281,0:PRINT"[CTRL+WHT][SHIFT+CLR/HOME]";
20
PRINT" * * * SOUND-DEMO * *
*"
30
PRINT
40
PRINT"AUSWAHL MIT FOLGENDEN TASTEN:"
50
PRINT"1:EXPLOSION"
60
PRINT"2:DUMPFE EXPLOSION"
70
PRINT"3:MOTORENBRUMMEN (BENZINER)"
80
PRINT"4:MOTORENBRUMMEN (DIESEL)"
90
PRINT"5:RAUMSCHIFFANTRIEB"
100
PRINT"6:SPRUNG"
110
PRINT"7:FALL INS WASSER"
120
PRINT"8:WASSERRAUSCHEN"
130
PRINT"9:KURZES TUTEN"
140
PRINT"0:KURZER CLICK"
150
PRINT"F1:SCHRITT"
160
PRINT"F2:FALL INS BODENLOSE"
170
PRINT"F3:LASERSCHUSS"
180
PRINT"F4:PROGRAMM BEENDEN"
190 GET A$:IF
A$="" THEN 190
200 IF A$="1" THEN GOSUB 1000
210 IF A$="2" THEN GOSUB 1100
220 IF A$="3" THEN GOSUB 1200
230 IF A$="4" THEN GOSUB 1300
240 IF A$="5" THEN GOSUB 1400
250 IF A$="6" THEN GOSUB 1500
260 IF A$="7" THEN GOSUB 1600
270 IF A$="8" THEN GOSUB 1700
280 IF A$="9" THEN GOSUB 1800
290 IF A$="0" THEN GOSUB 1900
300 IF A$="[F1]" THEN GOSUB 2000
310 IF A$="[F2]" THEN GOSUB 2100
320 IF A$="[F3]" THEN GOSUB 2200
330 IF A$="[F4]" THEN END
340 GOTO 190
1000 REM *** EXPLOSION ***
1010 POKE SI+5,11:POKE
SI+6,0
1020 POKE SI,0:POKE
SI+1,5
1030 POKE SI+4,128:POKE
SI+4,129
1040 RETURN
1100 REM *** DUMPFE EXPLOSION ***
1110 POKE SI+5,11:POKE
SI+6,0
1120 POKE SI,0:POKE
SI+1,2
1130 POKE SI+4,128:POKE
SI+4,129
1140 RETURN
1200 REM *** MOTOR (BENZIN) ***
1210
POKE SI+2,0:POKE SI+3,8:REM RECHTECKWELLE MIT 50%
PULSBREITE
1220 POKE SI+5,0:POKE
SI+6,255
1230 POKE SI,0:POKE
SI+1,1
1240 POKE SI+4,64:POKE
SI+4,65
1250 RETURN
1300 REM *** MOTOR (DIESEL) ***
1310
POKE SI+2,0:POKE SI+3,12:REM RECHTECKWELLE MIT 75%
PULSBREITE
1320 POKE SI+5,0:POKE
SI+6,255
1330 POKE SI,0:POKE
SI+1,1
1340 POKE SI+4,64:POKE
SI+4,65
1350 RETURN
1400 REM *** RAUMSCHIFF ***
1410 POKE SI+5,0:POKE
SI+6,255
1420 POKE SI,0:POKE
SI+1,5
1430 POKE SI+4,128:POKE
SI+4,129
1440 RETURN
1500 REM *** SPRUNG ***
1510 POKE SI+5,0:POKE
SI+6,255
1520 POKE SI,0:POKE
SI+1,1
1530 POKE SI+4,16:POKE
SI+4,17
1540 FOR I=1 TO 75:POKE
SI+1,I:NEXT I
1550 FOR I=75 TO 1 STEP -1:POKE
SI+1,I: NEXT I
1560 POKE SI+5,0:POKE
SI+6,0
1570 RETURN
1600 REM *** FALL INS WASSER ***
1610 POKE SI+5,170:POKE
SI+6,170
1620 POKE SI,0:POKE
SI+1,50:POKE SI+4,118
1630 POKE SI+4,129
1640 FOR I=1 TO 500:NEXT
I
1650 POKE SI+4,128
1660 RETURN
1700 REM *** WASERRAUSCHEN ***
1710 POKE SI+5,0:POKE
SI+6,255
1720 POKE SI,0:POKE
SI+1,100
1730 POKE SI+4,128:POKE
SI+4,129
1740 RETURN
1800 REM *** KURZES TUTEN ***
1810 POKE SI+5,0:POKE
SI+6,255: POKE SI+2,0:POKE SI+3,8
1820 POKE SI,0:POKE
SI+1,20
1830 POKE SI+4,64:POKE
SI+4,65
1840 FOR I=0 TO 50:NEXT
I
1850 POKE SI+5,0:POKE
SI+6,0
1860 RETURN
1900 REM *** KURZER CLICK ***
1910 POKE SI+5,3:POKE
SI+6,0
1920 POKE SI,0:POKE
SI+1,150
1930 POKE SI+4,128:POKE
SI+4,129
1940 RETURN
2000 REM *** SCHRITT ***
2010 POKE SI+5,5:POKE
SI+6,0
2020 POKE SI,0:POKE
SI+1,10
2030 POKE SI+4,128:POKE
SI+4,129
2040 RETURN
2100 REM *** FALL INS BODENLOSE ***
2110 POKE SI+5,0:POKE
SI+6,255
2120 POKE SI,0:POKE
SI+1,150
2130 POKE SI+4,16:POKE
SI+4,17
2140 FOR I=150 TO 1 STEP -1
2150 POKE SI,0:POKE
SI+1,I
2160 FOR J=1 TO 10:NEXT
J
2170 NEXT I
2180 RETURN
2200 REM *** LASERSCHUSS ***
2210 POKE SI+5,0:POKE
SI+6,255
2220 POKE SI,0:POKE
SI+1,150
2230 POKE SI+4,128:POKE
SI+4,129
2240 FOR I=150 TO 0 STEP -1
2250 POKE SI,0:POKE
SI+1,I
2260 NEXT I
2270
POKE SI+5,6:POKE SI+6,0
2280
RETURN
In Zeile 5 wird
erst einmal der SID initialisiert, indem die Basisadresse SI auf 54272,
und die Lautstärke auf 100% gesetzt wird. Anschließend wird in Zeile 10
für das Menü ein schwarzer Hintergrund mit weißer Schrift ausgewählt. In den Zeilen
20-180 wird dann das Menü mit Hilfe von PRINT-Befehlen auf dem
Bildschirm ausgegeben. In Zeile 190 wartet das Programm auf eine Taste,
und ruft in den Zeilen 200-330 je nach vorher betätigter Taste ein
entsprechendes Unterprogramm auf, das den ausgewählten Sound abspielt. Die
Sound-Routinen werden nun ausführlich erklärt.
Explosion (Zeile
1000-1040, Taste 1)
In Zeile 1010
wird mit POKE SI+5,11:POKE SI+6,0 Attack=0 gesetzt, was bedeutet, dass der Ton sofort präsent
ist. Decay wird hier auf 11, und Sustain und Release auf 0 gesetzt. Der Ton
schwillt sofort ab, und hat auch keinen Haltepegel. In Zeile 1020 wird
nun mit POKE SI,0:POKE SI+1,5 eine Frequenz von
etwa 50 Hz ausgewählt, die zusammen mit der Rauschen-Wellenform einen sehr
dumpfen Ton ergibt. Zusammen mit einem Decay-Wert von 11 ergibt sich nun der
Eindruck einer Explosion, die nur langsam ausklingt. In Zeile 1030 wird
nun der Sound durch POKE SI+4,128:POKE SI+4,129
gestartet. Da Sustain und Release den Wert 0 haben, wird der Sound erst
gestoppt (Gate=0) und anschließend direkt danach wieder gestartet (Gate=1). In Zeile
1040 (RETURN-Anweisung) kehrt das Unterprogramm zum Hauptprogramm
zurück, während der Ton weiter abgespielt wird.
dumpfe Explosion (Zeile
1100-1140, Taste 2)
Die dumpfe Explosion,
die bei der Vernichtung sehr großer Raumschiffe abgespielt werden kann (bzw.
nach Besiegen eines Endgegners), ist identisch mit dem Unterprogramm in Zeile
1000-1040 (normale Explosion), außer dass in Zeile 1120 nur eine
Frequenz von 20 Hz ausgewählt wird. Der Ton ist also um 2,5 Oktaven tiefer, und
deshalb sehr dumpf und laut.
Benzinmotor (Zeile
1200-1250)
Motorkolben erzeugen
normalerweise bei der Explosion des Kraftstoffgemisches sehr komplexe
Klangmuster. Diese Klangmuster kann der SID nicht darstellen, jedoch kann die
Explosion im Kolben sehr gut durch die Rechteckwelle angenähert werden. Im
Endeffekt bilden Sie an dieser Stelle einen idealen Motor ab: Das Gemisch
zündet, und sofort danach erfolgt genau eine Umdrehung, die auch nur ein ganz
kurzes Geräusch erzeugt. Um die Rechteckwelle zu benutzen, muss in Zeile
1210 durch POKE SI+2,0:POKE SI+3,8 die Pulsbreite
(also der Bereich, in dem die Lautstärke 100% beträgt) ausgewählt werden. Eine
Pulsbreite von 50 Prozent (das ist der Wert 2048, ausgedrückt auch hier wieder
durch Lo- und Hi-Byte) erzeugt an dieser Stelle einen Klang, der einem
Benzinmotor ähnelt (Erfahrungswert!). Um den Eindruck eines kontinuierlich
laufenden Motors zu erzeugen, wird nun mit den folgenden Zeilen ein Dauerton
erzeugt:
1220 POKE SI+5,0:POKE
SI+6,255
1230 POKE SI,0:POKE
SI+1,1
Attack und Decay ist an dieser
Stelle 0, der Ton ist also sofort präsent. Allerdings ist Sustain=15 und
Release=15, wodurch der SID direkt nach dem Start des Tones auf einer
Lautstärke von 100% „hängenbleibt“. Die Frequenz des Tones ist mit etwa 15 Hz
sehr niedrig und entspricht dem Standgas eines Motors. Wenn Sie eine andere
Drehzahl wünschen, müssen Sie entsprechend in SID-Register Nr. 0 und 1
einen anderen Wert eintragen. In Zeile 1240 starten Sie den Sound nun
durch POKE SI+4,64:POKE SI+4,65, wodurch die
Rechteck-Wellenform ausgewählt wird. Zeile 1250 kehrt mit RETURN
aus dem Unterprogramm zurück, während der Ton weiter abgespielt wird.
Dieselmotor (Zeile
1300-1350)
Da der Dieselmotor nur
eine andere Bauart eines Motors mit einem anderen Kraftstoff ist, entspricht
dieses Unterprogramm dem Unterprogramm in Zeile 1200-1250, außer dass
hier die Pulsbreite der Rechteck-Welle 75% beträgt. Dadurch hört sich der Ton
dumpfer und tiefer an, und „nagelt“ auch, so, wie man es von Dieselmotoren
gewohnt ist.
Raumschiff (Zeile
1400-1440)
Diesen Sound kennen Sie
bereits: Es wird ein tiefes Rauschen erzeugt, und in Zeile 1410 durch POKE
SI+5,0:POKE SI+6,255 als Dauerton ausgegeben (Atack=0, Decay=0, Sustain=15, Release=15). Die Frequenz
wird in Zeile 1420 durch POKE SI,0:POKE
SI+1,5 festgelegt und in Zeile 1430 durch POKE SI+4,128:POKE
SI+4,129 auf die Wellenform „Rauschen“ eingestellt. Die RETURN-Anweisung
in Zeile 1440 kehrt danach zum Hauptprogramm zurück, während der Ton weiter
abgespielt wird.
Sprung (Zeile
1500-1570)
Dieser Sound kann nicht
im Hintergrund abgespielt werden, deshalb kehrt die RETURN-Anweisung in Zeile
1570 erst zum Hauptprogramm zurück, nachdem der komplette Sound abgespielt
wurde. Auch für den Sprung wird in Zeile 1510 mit POKE SI+5,0:POKE SI+6,255 ein Dauerton erzeugt, der nur mit 15 Hz
startet (Zeile 1520), und sich anschließend ändert. Zu diesem Zweck wird
zunächst in Zeile 1530 durch POKE SI+4,16:POKE
SI+4,17 die Dreieck-Wellenform ausgewählt, und gleichzeitig das Gate-Bit
auf 1 gesetzt. Hierdurch ist der Ton sofort präsent, klingt aber nicht aus.
Dies ist auch der Trick, der bei der Simulation eines Sprunges benutzt wird:
Sie können die Frequenz ändern, während der Ton abgespielt wird. Dies geschieht
in den folgenden zwei Schleifen:
1540 FOR I=1 TO 75:POKE
SI+1,I:NEXT I
1550 FOR I=75 TO 1 STEP -1:POKE
SI+1,I:NEXT I
Einmal steigt die
Frequenz an (auf etwa 1200 Hz), und anschließend fällt sie wieder ab (auf die
Ausgangsfrequenz von 15 Hz). Da BASIC-Schleifen sehr langsam sind, wird hier
nur das Hi-Byte für das Frequenzregister geändert. Wenn der Sound vollständig
abgespielt wurde, muss der Dauerton wieder aufgehoben werden, bevor das
Unterprogramm zum Hauptprogramm zurückkehrt. Dies leisten die folgenden Zeilen:
1560
POKE SI+5,0:POKE SI+6,0
1570
RETURN
Fall ins Wasser (Zeile
1600-1660)
Wenn Sie von einem
Sprungbrett ins Wasser springen, erzeugen Sie einen etwas komplexeren Klang,
als bei einer Explosion: Erstens erzeugen Sie ein relativ hohes Rauschen, und
zweitens verdrängen Sie das Wasser, während Sie in dieses eintauchen. Das
bedeutet, dass Sie einen anschwellenden Ton programmieren müssen, der dann
auch, nachdem Sie in das Wasser eingetaucht sind, noch einige Zeit anhält.
Natürlich muss nach der Haltephase der Sound ausklingen. Für den Fall in das
Wasser habe ich nun Attack, Decay, Sustain und
Release auf 10 gesetzt, und die Frequenz auf den Ton A5 (880 Hz, PAL-Version)
gesetzt. Dies leisten die folgenden BASIC-Zeilen:
1610 POKE SI+5,170:POKE
SI+6,170
1620 POKE SI,0:POKE
SI+1,50:POKE SI+4,118
Die Werte in den SID-Registern
Nr. 5 und 6 kommen auf die folgende Weise zustande: Das hohe Nibble
hat den Wert 10, was in BASIC dem Wert 16*10=160 entspricht. Dazu wird
noch das niedrige Nibble mit dem Wert 10 addiert, macht zusammen
16*10+10=170.
Der Sound durchläuft
sämtliche Phasen des ADSR-Zyklus, deshalb muss dieser in Zeile 1630
durch Setzen des Gate-Bits mit POKE SI+4,129 gestartet werden (hier wird
dann auch gleichzeitig die Rauschen-Wellenform ausgewählt). Nun schwillt der
Ton an, klingt ab, und verbleibt anschließend eine viertel Sekunde lang auf dem
Sustain-Pegel (62,5%). Um dies zu gewährleisten, wird die folgende Warteschleife
verwendet:
1640
FOR I=1 TO 500:NEXT I
Erst nach der Warteschleife
wird der Release-Zyklus gestartet, indem in Zeile 1650 mit POKE
SI+4,128 das Gate-Bit auf 0 gesetzt wird. In Zeile 1660 kehrt dann
das Unterprogramm mit RETURN zum Hauptprogramm zurück.
Wasserrauschen (Zeile
1700-1740)
Sie können nicht nur
ins Wasser springen, sondern sich auch außerhalb des Wassers befinden. In
diesem Fall hören Sie (z.B. wenn Sie neben einem
Wasserfall stehen) einen kontinuierlichen hohen Ton (in diesem Fall ist es ein
hoher Dauerton mit etwa 1500 Hz). Dieser wird mit den folgenden BASIC-Zeilen
erzeugt
1710 POKE SI+5,0:POKE
SI+6,255
1720 POKE SI,0:POKE
SI+1,100
Auch bei diesem Sound
kehrt das Unterprogramm direkt nach der Initialisierung mit den folgenden
BASIC-Zeilen sofort zum Hauptprogramm zurück:
1730
POKE SI+4,128:POKE SI+4,129
1740
RETURN
Viele Spiele, vor Allem
Adventures, verwenden ähnliche Zeilen, um einen Raum mit Hintergrundgeräuschen
„aufzupeppen“. Vor Allem Wasserfälle kommen deshalb oft in Adventures vor.
Kurzes Tuten (Zeile
1800-1860)
Nicht nur Spiele,
sondern auch Anwendungen benutzen Sounds, um bestimmte Zustände anzuzeigen. So
werden z.B. Tastatureingaben manchmal von einem kurzen Ton begleitet. Ein
solches kurzes Tuten erzeugt das Unterprogramm in Zeile 1800-1860. Das
Tuten besteht aus zwei Teilen. Der erste Teil erzeugt mit den folgenden
BASIC-Zeilen einen Dauerton mit einer Rechteck-Wellenform:
1810 POKE SI+5,0:POKE
SI+6,255:POKE SI+2,0:POKE SI+3,8
1820 POKE SI,0:POKE
SI+1,20
1830 POKE SI+4,64:POKE
SI+4,65
Anschließend tritt das
Programm in die folgende kurze Warteschleife ein:
1840
FOR I=0 TO 50:NEXT I
Die Warteschleife sorgt
dafür, dass der Ton eine kurze Zeit hörbar ist, allerdings dürfen Sie nicht zu
lange warten, sonst wird Ihre Eingaberoutine zu langsam. Nach der Warteschleife
wird der Sound mit folgenden Zeilen gestoppt:
1850
POKE SI+5,0:POKE SI+6,0
1860
RETURN
Sie setzen hier
A=D=S=R=0, sodass der Sound sofort ausklingt, und der SID anschließend auch
sofort wieder auf eine Änderung des Gate-Bits wartet. Man nennt diese Phase
auch manchmal IDLE-Phase, was aber nicht ganz korrekt ist, weil der SID
im Endeffekt nie „faul“ ist und nichts tut.
Kurzer Click (Zeile
1900-1940)
Bei einem kurzen Click,
der entweder bei einem Schritt, oder aber auch z.B. bei Berühren einer Bande
ausgelöst werden kann, können Sie keine Warteschleife ausführen, weil Sie
vielleicht nachher noch andere Ereignisse abfragen müssen. Deshalb geht das Click-Beispiel
einen ähnlichen Weg, wie der Klavier-Sound: Es wird in Zeile 1910 durch POKE
SI+5,3:POKE SI+6,0 nur ein Decay-Wert definiert, Attack, Sustain und Release sind 0. Ein Wert von D=3 ist
sehr gering, und bewirkt, dass der Click gerade mal 0,1 Sekunden lang
abgespielt wird. Dies ist kurz, reicht aber aus, um ein Geräusch wahrzunehmen.
Die Frequenz wird an dieser Stelle in Zeile 1920 durch POKE SI,0:POKE SI+1,150 sehr hoch eingestellt, was den Klang
dann noch einmal deutlicher zutage treten lässt. Der Click benutzt dann auch
die Rauschen - Wellenform (Zeile 1930). Auch dieses Unterprogramm kehrt
in Zeile 1940 unverzüglich zum Hauptprogramm zurück. Allerdings kann es
geschehen, dass besonders ältere Menschen über 70 Ihren Klick-Sound nicht
wahrnehmen können (zu hohe Frequenz, zu kurze Dauer).
Schritt (Zeile
2000-2040)
In diesem Unterprogramm
wird bewusst ein Sound erzeugt, der zu einem Schritt passt, den z.B. ein
Kämpfer in einem Labyrinth-Spiel bei jeder Joystick-Bewegung ausführt. Dieses
Beispiel ist identisch mit dem Unterprogramm in Zeile 1900-1940,
allerdings ist hier die Tonfrequenz eine Oktave tiefer, und auch der Ton klingt
etwas länger aus.
Fall ins Bodenlose
(Zeile 2100-2180)
Dieser Fall besitzt
keinen Startpunkt am unteren Ende der Frequenzskala, wie z.B. der Sprung -
dieser Fall geht einfach ins Bodenlose. Wie auch schon beim Sprung, wird mit
den folgenden BASIC-Zeilen ein Dauerton erzeugt:
2110 POKE SI+5,0:POKE
SI+6,255
2120 POKE SI,0:POKE
SI+1,150
2130
POKE SI+4,16:POKE SI+4,17
Die hier gewählte Wellenform
ist die Dreieck-Wellenform, und die Frequenz wird auch hier während der
Tonausgabe geändert. Allerdings dauert der Fall länger, als ein Sprung, deshalb
wird hier die folgende verschachtelte Schleife verwendet:
2140 FOR I=150 TO 1 STEP -1
2150 POKE SI,0:POKE
SI+1,I
2160 FOR J=1 TO 10:NEXT
J
2170
NEXT I
Die äußere Schleife
ändert das Hi-Byte für den Frequenzwert im Bereich von 150 bis 0, die innere
Schleife führt dann zusätzlich zur Frequenzänderung eine kleine Warteschleife
aus. Erst durch diese Maßnahme wird der Sprung zum langsamen Fallen. Erst nach Abspielen
des kompletten Sounds kehrt das Unterprogramm in Zeile 2180 zum Hauptprogramm
zurück.
Laserschuss (Zeile
2200-2280)
Auch der Laserschuss
verwendet einen Dauerton, der variiert wird, allerdings wird die
Rauschen-Wellenform anstatt der Dreieck-Wellenform verwendet.
6.5 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.