ST-Ecke: appl_trecord und appl_tplay - und sie dreht sich doch...

Die lange totgeglaubten Routinen appl_trecord und appl_tplay führten auf den ‘alten’ STs zu den merkwürdigsten Ergebnissen. Unglaublich, aber wahr: Die Routinen funktionieren im neuen MEGA ST tatsächlich, zwar nicht ganz so, wie in den Dokumentationen beschrieben, aber das ist ja nebensächlich...

Zunächst wollen wir uns den Sinn der Routinen klarmachen. Appl_trecord und Appl_tplay sind Routinen des AES, die dazu dienen, die Ereignisse des GEM aufzuzeichnen, um sie später wieder ‘abspielen’ zu können. Zu diesem Zweck werden vier verschiedene Ereignisse unterschieden:

0) Timer-Ereignis:

Speichert die Zeit ab, die zwischen zwei anderen Ereignissen vergangen ist.

1) Maustasten-Ereignis:

Zeichnet auf, ob eine Maustaste gedrückt worden ist.

2) Maus-Ereignis:

Wird die Maus bewegt, werden die absoluten X- und Y-Koordinaten der Maus abgespeichert.

3) Tastatur-Ereignis:

Ist eine Taste gedrückt worden, wird der Tastaturcode des Zeichens abgespeichert.

Zum Aufzeichnen der Ereignisse wird die im folgenden beschriebene Routine APPL_TRECORD verwendet:

ap_trreturn = appl_trecord(buffer, evnt_num);

buffer: : Speicherbereich, in den die einzelnen Ereignisse geschrieben werden sollen ( benötigte Bytes: = Anzahl der Ereignisse x 8 -> siehe unten).

evnt_num: : Anzahl der Ereignisse, die aufgezeichnet werden sollen.

Um zu wissen, wieviel Speicherplatz wir für unsere Ereignisse reservieren müssen, schauen wir uns das Format an, in dem die Ereignisse von AES abgespeichert werden. Beim Erarbeiten der Parameter der Routine stellte sich leider heraus, daß die Originaldokumentation mal wieder nicht mit der Praxis übereinstimmt.

Format eines Ereignisses:

  1. LONG-Word: Dieses LONG-WORD (und nicht wie in der Originaldokumentation beschrieben: INTEGER-WORD) enthält das Ereignis. Die Ereignisse sind durchnumeriert, wobei

     Timer den Wert 0, 
     Maustasten den Wert 1, 
     Maus den Wert 2 
     und die Tastatur den Wert 3 
    

besitzen. Warum von den Programmierern der Routine dafür ein LONG-WORD reserviert worden ist, ist mir eine Rätsel. Ein Byte (!) hätte vollkommen gelangt. Auf diese Weise werden 3 (in Worten: drei) Bytes, die den Wert 0 enthalten, zusätzlich speicherverschwendend zu jedem Ereignis abgespeichert.

  1. LONG-Word: Diese vier Bytes enthalten abhängig von dem Ereignis ihren Eintrag ( Bei den Beispielen wird immer ein Wort dargestellt):

Timer: : Es wird im LONG-WORD die Anzahl der vergangenen 1/10-Sekunden abgespeichert. Dabei ist die Zeit maßgebend, die zwischen zwei Ereignissen vergangen ist.
Beispiel: 0 0 0 20 - Dieses Ereignis stellt eine Pause von 32 ( 20 ist hexadezimal) Millisekunden dar.

Maustasten: : Hier wird der Status der Maustasten vermerkt. Die Anzahl der Tastendrücke wird in den ersten zwei Worten und der Status ( 0 bedeutet Maustaste nicht gedrückt, 1 bedeutet Maustaste gedrückt) in den beiden letzten Worten abgespeichert.
Beispiel: 0 1 2 1 - Die linke Maustaste (1) wurde zweimal (2) gedrückt.

Maus: : Die beiden Wörter dienen dem Abspeichern der absoluten X-und Y-Koordinate der Maus. Die X-Koordinate ist im ersten Wort und die Y-Koordinate im zweiten Wort zu finden.
Beispiel: 0 2 30 A0 - Die Maus ist zur Koordinate (48/160) verschoben worden.

An der Auflistung erkennt man, daß man pro Ereignis acht Bytes reservieren muß. Um eine genaue Mausführung zu ermöglichen, wird natürlich jede Koordinatenverschiebung bei appl_trecord einzeln aufgezeichnet. Wird beispielsweise die Maus von der Koordinate (10,100) auf die Koordinate (110,100) langsam verschoben, so bedeutet dies 100 Ereignisse und damit 800 Bytes - Es lebe der MEGA-ST...Folgerung: Das Aufzeichnen von Daten, besonders wenn die Maus verwendet wird, ist äußerst speicherintensiv.

Unser Recorder braucht eine WIEDERGABE-Taste

Zur Wiedergabe der Ereignisse wird die Routine appl_tplay des AES verwendet, die wie folgt definiert ist:

ap_tpretum = appl_tplay(buffer, evnt_num, scale )

buffer: : Enthält wie bei appl_trecord die Adresse des Speicherbereichs, in dem die Ereignisse gespeichert sind. Der Puffer muß mindestens achtmal so groß sein wie evnt_num.

evntnum: : Dieser Parameter gibt die Anzahl der Ereignisse an, die abgespielt werden sollen.

scale: : Bei scale handelt es sich um einen Skalierungsfaktor, durch den die Geschwindigkeit angegeben wird ( Auf keinen Fall die Zahl Null verwenden!!! )

Ein Wort noch zu dem Parameter scale und der Zeitsteuerung. Entgegen der Ausführung wird der Zeiteintrag nicht (!) in tausendstel Sekunden sondern nur in zehntel Sekunden durchgeführt- dies ist eine wichtige Tatsache, denn es ist ja wohl ein relativ großer Unterschied, ob der Rechner eine Pause von einer oder von hundert Sekunden einlegt, nicht ?! In der Originaldokumentation findet man weiterhin unter dem Stichwort scale, daß der Wert 100 normale, der Wert 50 halbe und der Wert 200 doppelte Geschwindigkeit bedeutet. Leider ist auch dies falsch, aber keine Angst, das Rätsel ist gelöst. Die Routine teilt schlichtweg alle Zeitwerte durch den angegebenen Skalierungsfaktor. Was folgt daraus ? Keine Zeitsteuerung in der Ereignisliste, also auch keine Skalierungsmöglichkeit! Weiterhin ist es nicht sinnvoll, bei Zeitwerten die bespielsweise kleiner 10 sind, einen größeren Skalierungsfaktor als 10 zu verwenden, denn kleiner als 1 kann die Division nicht werden. Übrigens erklärt diese Vorgehensweise auch, warum appl_tplay bei einem Skalierungsfaktor von 0 abstürzt. Bei diesem Skalierungsfaktor wird der Ausnahmevektor “Division durch Null” ausgeführt, was bedeutet, daß der ‘intelligente’ Programmierer vergessen hat, die Division durch Null an der Skalierungsstelle abzufangen - nobody’s perfect. Beispiel 4 zeigt die verschiedenen Skalierungsmöglichkeiten.

Resümee

Alles in allem kann man behaupten, daß die Routinen ganz nützlich sein können, wenn man die richtigen Parameter verwendet. Ich glaube aber, daß ein Aufzeichnen weniger sinnvoll ist als das Erstellen eigener Ereignislisten, denn das Aufzeichnen verbraucht relativ viel Speicherplatz. Erstellt man eigene Listen, kann man gezielt Pausen setzen und auch mal ein paar Mauskoordinaten überspringen, um Speicherplatz zu sparen. Um Ihnen noch eine Idee mit auf den Weg zu geben: Durch ein entsprechendes Programm, das es ermöglicht, hilfreiche Listen zu erstellen, könnte über appl_tplay ein Demonstrationsprogramm generiert werden, daß zum Beispiel eigene Funktionen auf dem Desktop oder in anderen Programmen durchführt.

Noch ein klitzekleiner Tip am Schluß: Appl_tplay kann zum Setzen der Maus an eine bestimmte Stelle mißbraucht werden. Wie? Das wissen Sie ja jetzt... SH

/****************************************************/ 
/*                                                  */ 
/*    Dies ist ein Demonstration der Gem-Routine    */
/*                     APPL_TPLAY                   */
/*      die dem Abspielen von Ereignissen dient.    */
/*                ( Zeitsteuerung )                 */
/****************************************************/

int buffer[]={
0,2,10,10,	/* Maus (10,10) */
0,0,0,100,	/* 10 Sekunden */
0,2,20,10,	/* Maus (20,10) */
0,0,0,200,	/* 20 Sekunden */
0,2,30,10,	/* Maus (30,10) */
0,0,0,50,	/* 5 Sekunden */
0,2,40,10	/* Maus (40,10) */
};

main()
{

	int ap_ret; 
	int i;

	appl_init();

	printf("Bitte starten Sie jetzt ! (Taste drücken)\n"); 
	gemdos(7);

	appl_tplay(buffer,7,1);gemdos(7);

	/* 1:1-Geschwindigkeit */

	appl_exit();

}

/*****************************************************/ 
/*                                                   */ 
/*    Dies ist ein Demonstration der Gem-Routinen    */
/*            APPL_TRECORD und APPL_TPLAY            */
/* die dem Aufzeichnen und Abspielen von Ereignissen */
/* dienen                                            */
/*****************************************************/

char buffer[8*1000];

main ()
{

	int ap_ret; 

	appl_init();

	printf("Bitte zeichnen Sie jetzt auf! (Taste drücken)\n"); gemdos(7);

	/* Aufzeichnen von 1000 Ereignissen */

	ap_ret= appl_trecord(buffer,1000);
	printf("Alle Daten sind aufgezeichnet worden...\n");

	printf("Jetzt wird wiedergegeben.... (Taste drücken)\n"); gemdos(7) ;

	appl_tplay(buffer,1000,5);gemdos(7); 
	appl_tplay(buffer,1000,10);gemdos(7); 
	appl_tplay(buffer,1000,20);gemdos(7); 
	appl_tplay(buffer,1000,30);gemdos(7);

	appl_exit();

}

/*****************************************************/ 
/*                                                   */
/*     Dies ist ein Demonstration der Gem-Routine    */
/*                      APPL_TPLAY                   */
/*     die dem Abspielen von Ereignissen dient.      */
/*                    ( Skalierung )                 */
/*****************************************************/

int buffer[8*100};

main ()
{
	int ap_ret; 
	int i;

	appl_init();

	for (i=0; i<100*8; i+=8)
	{

		/* Maussteuerung */ 
		buffer[i]=0; /* Maus- */
		buffer[i+1]=2; /* Ereignis */
		buffer[i+2]=i/4; /* X-Inkrement */
		buffer[i+3]=50; /* Y-Koordinate	konstant */
		buffer[i+4]=0; /* Zeit- */
		buffer[i+5]=0; /* Ereignis */
		buffer[i+6]=0;
		buffer[i+7]=10; /* Zeit	=	10 */

	}

	printf("Bitte starten Sie jetzt! (Taste drücken)\n"); gemdos(7);

	appl_tplay(buffer,200,1);gemdos(7); /* 1:1 */
	appl_tplay(buffer,200,2);gemdos(7); /* 1:2 */
	appl_tplay(buffer,200,3);gemdos(7); /* 1:3 */
	appl_tplay(buffer,200,4);gemdos(7); /* 1:4 */
	appl_tplay(buffer,200,5);gemdos(7); /* 1:5 */
	appl_tplay(buffer,200,10);gemdos(7); /* 1:10 */

	appl_exit();

}

/*****************************************************/ 
/*                                                   */
/*    Dies ist ein Demonstration der Gem-Routine     */
/*                   APPL_TRECORD                    */
/*    die dem Aufzeichnen von Ereignissen dient      */
/*                                                   */
/*****************************************************/

char buffer[8*10];

main()
{

	int ap_ret; 
	char i;

	appl_init();

	printf("Bitte zeichnen Sie jetzt auf! (Taste drücken)\n"); gemdos(7);

	/* Aufzeichnen von 10 Ereignissen */

	ap_ret= appl_trecord(buffer,10);
	printf("Alle Daten sind aufgezeichnet worden..\n");

	/* Ausgeben des Buffers auf den Bildschirm */

	for (i=0; i<80; i+=2)
	{

		if (!(i% 16) )
			printf("\n");

		printf("%4x ",*(int*)(buffer+i));

	}

	gemdos(7); 

	appl_exit();

}


Aus: ST-Computer 04 / 1988, Seite 143

Links

Copyright-Bestimmungen: siehe Über diese Seite