Auf der TOS-Disk: Schreckprogramm »Django«

Nachdem wir in der letzten Ausgabe den Desktop verzauberten, geht's heute gefährlicher zu: Unser heutiges Gimmick-Programm bringt Sie in Lebensgefahr.

Um in den vollen Genuß des heutigen Gimmick-Programms »Django« zu kommen, muß ich Sie bitten, etwas zu tun, was andere Autoren in Ihren Artikeln niemals tun würden: Ich bitte Sie, diesen Artikel nicht sofort ganz durchzulesen. Sie bringen sich sonst selbst um eine hübsche Überraschung. Setzen Sie sich vor Ihren ST, schalten Sie ihn an und legen Sie die TOS-Diskette dieser Ausgabe ins Laufwerk. Dann starten Sie das Programm DJANGO.PRG, das Sie im Ordner PROGRAME finden. Wie Sie sehen, sehen Sie jetzt nichts besonderes. Das soll auch so sein, denn es dauert ab Programmstart etwa fünf Minuten, bis sich das Programm bemerkbar macht.

Lassen Sie also den ST jetzt erst einmal laufen, ohne die Maus oder irgendeine Taste zu bewegen, und lesen Sie die anderen interessanten Artikel dieser TOS-Ausgabe. Sehr wichtig: Drehen Sieden Lautstärkeregler am Monitor voll auf. In fünf Minuten lesen Sie dann beim nächsten Absatz weiter. Bis gleich!

Sie haben gemogelt, oder? Na gut. Jetzt bewegen Sie doch mal Ihre Maus. Und? Haben Sie den Anschlag überlebt? Wenn ja, dann erkläre ich Ihnen mal, wie man so etwas programmiert.

Wie das letzte Gimmick-Programm, so entstand auch dieses mit dem Megamax-Modula-2. Die Modulumgebung ist im wesentlichen gleich geblieben: Die Funktionen der Module MSSYSTEMS, MSGRAPHICS und MSINIT beschrieb ich bereits in der letzten Ausgabe. Deren Quelltexte befanden sich auf der letzten Diskette, weshalb Sie diesmal nur die übersetzten Module vorfinden. Für alle, die die letzte Ausgabe verpaßt haben: Das Modul MSINIT dient als Pre-Initmodul beim Linken und ersetzt das Modul M2Init des Megamax-Systems. Es sorgt dafür, daß das Programm resident im Speicher verbleibt. Neu hinzugekommen ist das Modul MSSOUNDS, mit dem Sie die digitalen Klänge abspielen. DJANGO.TXT ist das eigentliche Programmodul.

Klangvolle Effekte

Ein wesentlicher Effekt des Gimmick-Programms Django liegt in den passenden Geräuschen. Dazu habe ich Klänge von einer Vertonungs-CD digitalisiert (der Schluß ist von der CD Jon & Vangelis »The Friends of Mr. Cairo«). Das Modul MSSounds stellt eine Funktion zur Verfügung, die einen im Speicher befindlichen Klang abspielt. Dabei handelt es sich um die Prozedur »StartSound«. Genau genommen kann diese Prozedur sogar zwei Digitalklänge gleichzeitig abspielen. Als Parameter verlangt sie eine Adresse, die auf den Start der Klangdaten zeigt, und einen beliebigen CARDINAL-Wert, der die Priorität des abzuspielenden Klanges bestimmt. Letzteres hat folgenden Grund: Startet die Prozedur StartSound einen neuen Klang, so untersucht die Prozedur zunächst, ob einer der beiden Tonkanäle frei ist. Sind beide Tonkanäle bereits aktiv, so entscheidet der Prioritätsparameter, welchen Tonkanal er belegt. Findet die Prozedur einen aktiven Tonkanal, dessen Priorität gleich oder kleiner ist als die des neuen Sounds, dann bricht sie den dort ablaufenden Klang ab und benutzt den Kanal für den neuen Klang. Dieses Vorgehen ist besonders bei Spielen notwendig, in denen gewisse Geräusche für den Spielablauf unterschiedlich wichtig sind.

Ab und zu ist es auch wichtig, längere Klänge nicht zu unterbrechen. Das Django-Programm macht davon keinen Gebrauch. Wichtig wäre sie erst für ein späteres Gimmick, oder wenn Sie eine eigene Variation des Programms entwickeln. Die Prozedur StartSound bereitet lediglich die digitale Tonausgabe vor. Für die Klangausgabe benötigen wir einen regelmäßigen Interrupt. Der MFP-Baustein des Atari besitzt vier verschiedene Timer, die regelmäßige Interrupts erzeugen. Wir verwenden den Timer A, da das Betriebssystem die anderen Timer benutzt. Für die Ausgabe der digitalen Töne existieren zwei verschiedene Interruptroutinen: einmal die Interruptroutine, die einen Digitalklang ausgibt (Label YMOneSoundlRQ), zum anderen eine Interruptroutine, die zwei Digitalklänge gleichzeitig ausgibt (Label YMTwoSoundIRQ). Beide Interruptroutinen sind in der Prozedur StartSound enthalten. Dies ist zulässig, da diese Routinen nicht von Modula aus aufgerufen werden. Eine dritte Interruptroutine (YMOffSoundIRQ) dient lediglich dazu, den Timer A wieder abzuschalten, falls keine Tonausgabe mehr erfolgt. Spielen wir einen neuen Klang ab, untersucht StartSound, ob dieser aufgrund seiner Priorität überhaupt starten kann. Wenn ja, dann legt StartSound fest, auf welchem Tonkanal die Ausgabe stattfindet und welchen Interrupt sie benutzt. Je nachdem, ob nun ein Kanal oder beide Kanäle belegt sind, verwenden wir die Interruptroutinen YMOneSoundIRQ oder YMTwoSoundIRQ. Die Adresse der Interruptroutine schreiben wir direkt in den Interruptvektor (Adresse $ 134). Um später wieder eine Prioritätsentscheidung durchzuführen, merken wir uns für jeden Kanal die aktuelle Priorität. Dazu verwenden wir die beiden Variablen SoundPrioOfChannelA bzw. SoundPrioOfChannelB. Den Zeiger auf die abzuspielenden Daten merken wir uns in einer Adresse in der Nähe der Interrupt-Routine, so daß wir sie zur Geschwindigkeitsoptimierung auch PC-relativ adressieren können. Am Ende der Soundinitialisierung starten wir Timer A, der mit ca. 9 KFHz arbeitet. Die Geschwindigkeit des Interrupts wird beim Programmstart mit der Prozedur SetSampleFrequency definiert. Der Wert für das Delay-Register des Timer A (Variable TimerADelay) berechnet sich innerhalb dieser Prozedur nach der Formel: TimerADelay=614400/Hz.

Optimierung der Geschwindigkeit

Da der Sound-Interrupt 9000 Mal pro Sekunde aufgerufen wird, muß die Interruptroutine sehr schnell arbeiten. Jeder CPU-Zyklus, den wir hier mehr verbrauchen, schlägt bei der Rechenzeit des übrigen Systems mit dem Faktor 9000 zu Buche. Aus diesem Grund verwenden wir für das Erkennen des Sound-Endes einen besonderen Trick: Die Klangdaten besitzen keine Null-Werte, da eine Null das Ende markiert. Somit benötigen wir statt aufwendigen Adressvergleichen nur einen BEQ-Befehl, um das Ende des Klanges festzustellen. Jeder Sound-Interrupt erhöht die Zeiger auf die aktuellen Klangdaten und liest einen neuen Klangwert aus dem Speicher. Bei der Interruptroutine YMTwoSoundIRQ mischen wir die Klangdaten beider Kanäle. Dazu addieren wir beide Werte und achten darauf, daß das Ergebnis innerhalb der Dynamikgrenzen ($00 und $ FF) bleibt.

Anschließend geben wir den Klang aus, indem wir die drei verschiedenen Lautstärkeregister - für jeden der drei YM-Chip-Tonkanäle eins - auf eine bestimmte Lautstärke setzen. Die Tonkanäle arbeiten logarithmisch. Wir benötigen eine Tabelle (YM I AB), die für jede der 256 gewünschten linearen Lautsprecherpositionen die Registereinstellungen des YM-Chip angibt. Die im Programm verwendete Tabelle ist die derzeit beste, die ich kenne. Sie wurde von Jürgen Piscol (bekannt durch das Programm »Soundmachine ST«) mit einem Oszilloskop ausgemessen und besitzt die ideale Dynamik. Um ein Register im Soundchip zu beschreiben, selektieren wir es zuvor. Dazu schreiben wir die gewünschte Registernummer in die Speicherstelle $FF8800. Anschließend setzen wir den neuen Registerwert durch einen Schreibzugriff auf die Adresse $FF8802. Da die beiden Zieladressen ($FF8800/$FF8802) direkt hintereinander liegen, können wir anstatt zweier MOVE.B-Befehle einen MOVE.L-Befehl verwenden. Das höchstwertige Byte bezeichnet die Registernummer, das zweitwertige Byte den Lautstärkewert.

Da wir den Sound »nebenbei« abspielen, müssen wir darauf achten, daß das Betriebssystem und andere Programme nicht die Register des YM-Chips verändern (z. B. bei einem Tastaturklick). Der ganze Trick mit der digitalen Soundausgabe funktioniert nur, wenn alleTongeneratoren ausgeschaltet sind. Es bleibt somit nichts anderes übrig, als ständig die Tongeneratoren im Interrupt auszuschalten. Andernfalls verbliebe von unserem schönen Sound bei einem Tastaturklick nur noch ein häßliches Geräusche und Gepiepe. Eine letzte Schwierigkeit gibt es am Ende eines Klanges. Bei der Routine YMOneSoundIRQ schalten wir einfach den Timer A ab. Bei der Routine YMTwoSoundIRQ müssen wir jedoch den verbleibenden Klang eventuell auf den Kanal A legen und auf die Routine YMOneSoundIRQ umschalten.

Vom Schuß zum Fall

Der Ablauf des Gimmicks wird - wie bereits bei unserem letzten Gimmick-Programm MAGIC - bei jedem VBL-Interrupt durch Aufruf der Prozedur Make-Picture gesteuert. Er läßt sich in acht Phasen unterteilen, wie diese in dem Aufzählungstyp DjangoPhase-Type aufgelistet sind:

Sie können das Programm auch auf eine nutzvollere Funktion hin ausbauen. Wie wär's z. B. mit einem Bildschirmschoner, der sich auf diese effektvolle Weise anmeldet. Wenn Sie die PEXEC-Funktion und die Diskettenfunktionen abfangen, können Sie auch eine BackUp-Warnung geben, z. B. »It's time to backup!« Zu guter Letzt noch eine Bitte: Es ist sehr neckisch, das Programm auf dem Computer eines ahnungslosen Freundes zu installieren. Die Schadenfreude wird unermeßlich groß sein. Aber nehmen Sie dabei bitte Rücksicht auf die Leute, die einem solchen Schock nicht gewachsen sind. In der nächsten Ausgabe werden wir dem Mauscursor die physikalischen Gesetze beibringen. (ba)


Meinolf Amekudzi
Aus: TOS 08 / 1990, Seite 81

Links

Copyright-Bestimmungen: siehe Über diese Seite