STE-Soundbox, Teil 2: Das Microwire Interface

Neben den Möglichkeiten der Tonerzeugung mittels DMA stehen im STE noch eine Reihe von Funktionen für die Lautstärken- und Klangbeeinflussung zur Verfügung.

Diese werden mit einem Chip namens LMC 1992 verwirklicht, der über eine interne serielle Schnittstelle - das Microwire Interface - vom Programmierer angesprochen wird.

Funktionsvielfalt

Der LMC1992 ermöglicht das Einstellen folgender Parameter:

Die Gesamtlautstärke läßt sich von 0 dB (der höchsten Lautstärke) auf -80 dB absenken. Die Lautstärke der Kanäle kann getrennt zwischen 0 dB bis -40 dB eingestellt werden. Die Eckfrequenz der Filter für die Höhen bzw. Tiefen beträgt 15 kHz bzw. 50 Hz. Diese Frequenzen sind leider fest vorgegeben und können vom Benutzer nicht verändert werden. Der Regelbereich reicht von -12 dB bis +12 dB. Die Werte für die Lautstärken und die Filter können in Schritten zu 2 dB verändert werden.

Der LMC1992 ist über ein serielles Microwire Interface angekoppelt, welches im STE über zwei Hardware-Register angesprochen wird. Der Aufbau des seriellen Bit-Stroms, der über das Microwire Interface gesendet wird, ist Abb. 1 zu entnehmen. Das Adreßfeld muß immer mit der Adresse des LMC 1992 gefüllt sein, nämlich mit ‘10’. Theoretisch wäre es möglich, mit einem 2 Bit breiten Adreßfeld 4 verschiedene Bausteine zu adressieren - vielleicht darf man auf Erweiterungen des STE in naher Zukunft hoffen.

Das Datenfeld des Bit-Stroms besteht aus zwei Teilen: dem 3 Bit langen Kommando und den dazugehörenden Daten. Macht insgesamt 11 Bit, die pro Kommando an den LMC 1992 übertragen werden. Die Kommandos mit dem dazugehörenden Datenfeld sind in Abb. 2 aufgelistet.

Doch nun zurück zu den zwei Hardware-Registern. Es sind dies das Microwire-Datenregister (16 Bit, Adresse $FF8922) und das Microwire-Maskenregister(16 Bit, Adresse SFF8924).

Im Datenregister werden die 11 Bits des seriellen Bit-Stroms hinterlegt. Das Maskenregister dient der Kennzeichnung, welches der Bits im Datenregister gültig ist (zugehöriges Masken-Bit gesetzt) und welches Bit ignoriert werden soll (Masken-Bit gelöscht). Zu ignorierende Bits erscheinen nicht im Datenstrom.

Die Maske kennzeichnet demnach die 11 Bits aus dem 16-Bit-Datenregister, die für den seriellen Bit-Strom relevant sind. Ein Wert von $7F im Maskenregister bewirkt beispielsweise, daß die unteren 11 Bits des Datenregisters gesendet werden.

Das Maskenregister muß einmal zu Beginn gesetzt werden. Erscheint danach ein Wert im Datenregister, wird dieser sofort seriell gewandelt und über das Microwire Interface gesendet. Dazu werden die Werte im Daten- und im Maskenregister bitweise nach links geschoben. Ist das Bit des Maskenregisters 1, so wird das Bit des Datenregisters gesendet, andernfalls nicht. Das niederwertigste Bit des Maskenregisters wird anschließend mit dem hinausgeschobenen Bit gefüllt, das niederwertigste Bit im Datenregister wird gelöscht.

Das ganze passiert 16mal und dauert 16µs. Am Ende steht im Maskenregister wieder der alte Wert, das Datenregister ist gelöscht.

Zu beachten ist bei der ganzen Angelegenheit, daß vor Beschreiben des Datenregisters das Maskenregister ausgelesen und daraufhin überprüft wird, ob eine eventuelle vorige Übertragung abgeschlossen ist (16µs sind unter Umständen eine lange Zeit). Die Übertragung ist noch im Gange, wenn der Wert des Maskenregisters nicht mit dem zu Beginn eingetragenen Wert übereinstimmt. Für diesen Fall muß sich das Programm in eine Warteschleife begeben.

Ein kleines Bonbon

Ein Blick auf das deutlich gewachsene Assembler-Modul ‘SOUT.S’ zeigt, daß hier einige Funktionen dazugekommen sind. Als da wären:

Damit die Routinen nicht einfach so in der Luft hängen, habe ich im Listing ‘FKT_GEN.C’ einen Funktionsgenerator mit einstellbarer Kurvenform, Frequenz und Lautstärke realisiert.

Literatur
STE Developer Addendum

Abb. 1: Der Aufbau des 11 Bit langen seriellen Bit-Stroms
Abb. 2: Die Kommandos zur Lautstärken- und Klangbeeinflussung mit dem LMC1992
p:fkt_gen.prg = 
tcstart.o 
sout.s 
fkt_gen.c 
tcfltlib.lib 
tcstdlib.lib 
tctoslib.lib 
tcextlib.lib 
tcgemlib.lib

Project-Datei zu FKT_GEN.C


/* ----------------------------------------- */ /* FKT_GEN.C: Funktionsgenerator für den STE */ /* */ /* In Turbo-C 2.0 */ /* implementiert von Peter Engler */ /* ----------------------------------------- */ #include <stdio.h> #include <stdlib.h> #include <ext.h> #include <tos.h> #include <vdi.h> #include <aes.h> #include <math.h> #include "sout.h" #define MAX_FREQ 16000 /* Max. Frequenz: 16000 Hz */ #define MIN_FREQ 16 /* Min. Frequenz: 16 Hz */ #define MAX_LAUT 0 /* Max. Lautstarke: 0 dB */ #define MIN_LAUT -80 /* Min. Lautstarke: -80 dB */ /* Typdeklaration */ typedef struct { int wellenform; /* Wellenform (Sinus, Sägezahn, ... ) */ int freq, sw_freq; /* Frequenz, zug. Schrittweite */ int laut, sw_laut; /* Lautstärke, zug. Schrittweite */ int start; } EINSTELLUNG; /* Prototypen der im Modul verwendeten Funktionen */ int snd_alloc( SOUND *, unsigned long ); void snd_free( SOUND * ); void saegezahn( SOUND * ); void sinus( SOUND * }; void dreieck( SOUND * ); void rechteck( SOUND * ); void bildschirm_ausgabe( int, EINSTELLUNG * ); void frequenz_ausgabe( int, EINSTELLUNG * ); void lautstaerke_ausgabe( int, EINSTELLUNG * ); int eingabe_bearbeiten( int, EINSTELLUNG *, SOUND * ); int main( void ); /* Anlegen des Arrays fur die zu wandelnden Bytes */ int snd_alloc( SOUND *snd, unsigned long anz ) { /* Speicherplatz belegen */ snd -> s_ptr = (char *) malloc( anz ); /* Fehler aufgetreten */ if (! snd -> s_ptr) { snd -> anz_bytes = 0L; return( -1 ); } /* Anzahl Bytes des reservierten Bereichs */ snd -> anz_bytes = anz; /* Anzahl Bytes, die pro Sekunde gewandelt werden */ switch( snd -> mode_reg & 0x000F ) { case MOD_FR50K : snd -> bytes_pro_sekunde = 50066L; break; case MOD_FR25K : snd -> bytes_pro_sekunde = 25033L; break; case MOD_FR12K : snd -> bytes_pro_sekunde = 12517L; break; case MOD_FR6K : snd -> bytes_pro_sekunde = 6258L; break; default : snd -> bytes_pro_sekunde = 0L; break; } return ( 0 ); } /* Freigeben des Arrays der SOUND-Struktur */ void snd_free( SOUND *snd ) { free( snd -> s_ptr ); } /* Generieren der Werte für einen Sinus */ void sinus ( SOUND *snd ) { unsigned long bytes_pro_periode, index; char *h_ptr; h_ptr = snd -> s_ptr; /* Berechnen der Bytes, die pro Periode ausgegeben werden */ bytes_pro_periode = snd -> bytes_pro_sekunde / snd -> frequenz; if ((bytes_pro_periode % 2) == 1) bytes_pro_periode++; snd -> anz_bytes = bytes_pro_periode; /* Einträgen der Werte für den Sinus in die SOUND-Struktur */ for (index = 0; index < bytes_pro_periode, index++) { *h_ptr++ = (char) (127 * sin< 2.0 * M_PI * ((double) index) / (double) bytes_pro_periode) - 1); } } /* Generieren der Werte für einen Sägezahn */ void saegezahn( SOUND *snd ) { unsigned long bytes_pro_periode, index; char *h_ptr; h_ptr = snd -> s_ptr, /* Berechnen der Bytes, die pro Periode ausgegeben werden */ bytes_pro_periode = snd -> bytes_pro_sekunde / snd -> frequenz; if ((bytes_pro_periode % 2) = 1) bytes_pro_periode++; snd -> anz_bytes = bytes_pro_periode; /* Einträgen der Werte für den Sägezahn in die SOUND-Struktur */ for (index = 0; index < bytes_pro_periode; index++) { *h_ptr++ = (char) ( 255 * ((double) index) / ((double) bytes_pro_periode ) - 128); } } /* Generieren der Werte für ein Dreieck */ void dreieck( SOUND *snd ) { unsigned long bytes_pro_halbperiode, index; char *h_ptr; h_ptr = snd -> sjptr; /* Berechnen der Bytes, die pro Halbperiode ausgegeben werden */ bytes_pro_halbperiode = (snd -> bytes_pro_sekunde / snd -> frequenz) / 2L; if ((bytes_pro_halbperiode % 2) == 1) bytes_pro_halbperiode++; snd -> anz_bytes = bytes_pro_halbperiode * 2L; /* Eintragen der Werte fur das Dreieck in die SOUND-Struktur */ for (index = 0; index < bytes_pro_halbperiode,: index++) { *h_ptr++ = (char) ( 255 * ((double) index) /((double) bytes_pro_halbperiode ) - 128); } for (index = bytes_pro_halbperiode ; index > 0 ; index—-) { *h_ptr++ = (char) ( 255 * ((double) index) / ((double) bytes_pro_halbperiode ) - 128); } } /* Generieren der Werte für ein Rechteck */ void rechteck( SOUND *snd ) { unsigned long bytes_pro_halbperiode, index; char *h_ptr; h_ptr = snd -> s_ptr; /* Berechnen der Bytes, die pro Halbperiode ausgegeben werden */ bytes_pro_halbperiode = (snd -> bytes_prc_sekunde / snd -> frequenz) / 2L; if ((bytes_pro_halbperiode % 2) == 1) bytes_pro_halbper±ode++; snd -> anz_bytes = bytes_pro_halbperiode * 2L; /* Einträgen der Werte für das Rechteck in die SOUND-Struktur */ for (index = 0; index < bytes_pro_halbperiode, index++) { *h_ptr++ = (char) 127; } for (index = bytes_pro_halbperiode ; index > 0 ; index—-) { *h_ptr++ = (char) -128; } } int eingabe_bearbeiten( int handle, EINSTELLUNG * einst, SOUND *snd ) { /* Definition der Scancodes der verwendeten Tasten */ #define SINUS 31 #define DREIECK 32 #define SAEGEZAHN 21 #define RECHTECK 19 #define FR_EING 33 #define FR_MINUS 75 #define FR_PLUS 77 #define SCHR_WEITE 17 #define LT_EING 38 #define LT_MINUS 80 #define LT_PLUS 72 #define QUIT 16 #define F1 59 #define F10 68 int scan_code; int ret_code; ret_code = 0; /* Auf Zeichen von Tastatur warten */ while (! Cconis ( )); /* Zeichen einlesen (nur Scancode berücksichtigen) */ scan_code = ( Crawcin( ) >> 16 ); switch( scan_code ) { case QUIT : ret_code = -1; break; case F1 : einst -> start = 1; break; case F10 : snd_stop( ); einst -> start = 0; break; case SINUS : einst -> wellenform = SINUS; break; case DREIECK : einst -> wellenform = DREIECK; break; case SAEGEZAHN : einst -> wellenform = SAEGEZAHN; break; case RECHTECK : einst -> wellenform = RECHTECK; break; case FR_EING : { vs_curaddress( handle, 10, 18 ); v_eeol( handle ); /* Zeile ab Cursor löschen */ scanf( "%d", &(einst -> freq )); frequenz_ausgabe( handle, einst ); } break; case FR_MINUS : einst -> freq -= einst -> sw_freq; frequenz_ausgabe( handle, einst ); break; case FR_PLUS : einst -> freq += einst -> sw_freq; frequenz_ausgabe( handle, einst ); break; case SCHR_WEITE : /* Bei Schrittweite muß noch ein weiteres Zeichen eingelesen werden */ { int sc; /* Auf Zeichen von Tastatur warten */ while (! Cconis ( )); /* Zeichen einiesen (nur Scancode berücksichtigen) */ sc = ( Crawcin( ) >> 16 ); if (sc == FR_EING) { vs_curaddress( handle, 13, 39 ); v_eeol( handle ); /* Zeile ab Cursor loschen */ scanf( "%d", &(einst -> sw_freq ) ); frequenz_ausgabe( handle, einst ); } else if (sc == LT_EING) { vs_curaddress( handle, 20, 39 ); v_eeol( handle ); /* Zeile ab Cursor löschen */ scanf( "%d", &(einst -> sw_laut ) ); lautstaerke_ausgabe( handle, einst); } else fputc (7, stdout); } break; case LT_EING : { vs_curaddress( handle, 17, 18 ); v_eeol( handle ); /* Zeile ab Cursor löschen */ scanf( "%d", &(einst -> laut ) ); lautstaerke_ausgabe( handle, einst ); } break; case LT_MINUS : einst -> laut -= einst -> sw_laut; lautstaerke_ausgabe( handle, einst ); break; case LT_PLUS : einst -> laut += einst -> sw_laut; lautstaerke_ausgabe( handle, einst ); break; default : fputc( 7, stdout ); break; } /* Wurde nicht Q gedrückt, werden jetzt die Werte in die SOUND-Struktur geschrieben und ggf. ausgegeben */ if ( ! ret_code ) { /* Frequenz in SOUND-Struktur */ snd -> frequenz = einst -> freq; /* Abhängig von der gewünschten Wellenform werden jetzt die Werte berechnet */ switch( einst -> wellenform ) { case SINUS : sinus( snd ); break; case SAEGEZAHN : saegezahn( snd ); break; case DREIECK : dreieck( snd ); break; case RECHTECK : rechteck( snd ); break; default : snd_stop( ); einst -> start = 0; break, } /* Soll Ton ausgegeben werden ? */ if ( einst -> start ) { snd_laut( einst -> laut ); /* Lautstärke einst. */ snd_play( snd ); /* Ton ausgeben */ } } return( ret_code ); } /* Frequenzanzeige auf dem Auswahlbildschirm */ void frequenz_ausgabe( int handle, EINSTELLUNG * einst ) { char str[20]; /* Gültigkeit der Werte in einst prüfen */ if (einst -> freq > MAX_FREQ) einst -> freq = MAX_FREQ; else if (einst -> freq < MIN_FREQ) einst -> freq = MIN_FREQ; vs_curaddress( handle, 10, 18 ); /* Cursor setzen */ v_eeol( handle ); /* Zeile ab Cursor löschen */ sprintf ( str, "%d Hz", einst -> freq); /* Frequenz in str */ v_curtext( handle, str ); } /* Anzeige der Lautstärke auf dem Auswahlbildschirm */ void lautstaerke_ausgabe( int handle, EINSTELLUNG *einst ) { char str[20]; /* Gültigkeit der Werte in einst prüfen */ if (einst -> laut > MAX_LAUT) einst -> laut = MAX_LAUT; else if (einst -> laut < MIN_LAUT) einst -> laut = MIN_LAUT; vs_curaddress( handle, 17, 18 ); /* Cursor setzen */ v_eeol( handle ); /* Zeile ab Cursor löschen */ sprintf( str, "%d dB", einst -> laut); /* Lautstärke in str */ v_curtext( handle, str ); } /* Anzeige des Auswahlbildschirms */ void bildschirm_ausgabe( int handle, EINSTELLUNG *einst ) { char str[20]; /* Überschrift */ v_curhome( handle ); /* Cursor nach links oben */ v_rvon( handle ); /* Text invers */ v_curtext( handle, " Funktionsgenerator mit dem DMA-Soundchip " ); /* verfügbare Wellenformen */ v_rvon( handle ); /* Text invers */ vs_curaddress( handle, 5, 2 ); /* Cursor setzen */ v_curtext( handle, " Wellenformen :"); v_rvoff( handle ); v_curtext( handle, " S = Sinus, D = Dreieck, Z = Sägezahn, R = Rechteck" ); /* Frequenzauswahl */ v_rvon( handle ); /* Text invers */ vs_curaddress( handle, 10, 2 ); /* Cursor setzen */ v_curtext( handle, " Frequenz ....:""); v_rvoff( handle ); /* Text normal */ frequenz_ausgabe ( handle, einst ); vs_curaddress( handle, 11, 18 ); /* Cursor setzen */ v_curtext( handle, "F = Eingabe" ); vs_curaddress( handle, 12, 18 ); /* Cursor setzen */ v_curtext( handle, "Cursor left, right = schrittweise Änderung" ); vs_curaddress( handle, 13, 18 ); /* Cursor setzen */ v_curtext( handle, "WF = "); v_rvon( handle ); /* Text invers */ v_curtext( handle, "Schrittweite :"); v_rvoff( handle ); sprintf ( str, " %d Hz", einst -> sw_freq); /* Schrittweite in str */ v_curtext( handle, str ); /* Lautstärkewahl */ v_rvon( handle ); /* Text invers */ vs_curaddress( handle, 17, 2 ); /* Cursor setzen */ v_curtext( handle, " Laustärke ...:"); v_rvoff( handle ); /* Text normal */ lautstaerke_ausgabe( handle, einst ); vs_curaddress( handle, 18, 18 ); /* Cursor setzen */ v_curtext( handle, "L = Eingabe" ); vs_curaddress( handle, 19, 18 ); /* Cursor setzen */ v_curtext( handle, "Cursor up, down = schrittweise Änderung" ); vs_curaddress( handle, 20, 18 ); /* Cursor setzen */ v_curtext( handle, "WL = "); v_rvon( handle ); /* Text invers */ v_curtext( handle, "Schrittweite ); v_rvoff( handle ); sprintf ( str, " %d dB", einst -> sw_laut); /* Schrittweite in str */ v_curtext( handle, str ); vs_curaddress( handle, 24, 3 ); /* Cursor setzen */ v_rvon( handle ); v_curtext( handle, " F1 = Start, F10 = Stop " ); vs_curaddress( handle, 24, 69 ); /* Cursor setzen */ v_curtext( handle, " Q = Quit " ); v_rvoff( handle ); } int main( ) { SOUND snd; EINSTELLUNG einst = { SINUS, 440, 110, 0, 6, 0 } ; int handle, dummy; /* VDI-Handle holen und Bildschirm löschen */ handle = graf_handle( &dummy, &dummy, &dummy, &dummy ); v_clrwk( handle ); /* Textmodus einschalten */ v_enter_cur( handle ); /* 'mode_reg' immer vor 1. Aufruf von 'snd_alloc' setzen !! */ snd mode_reg = MOD_FR5OK | MOD_MONO; snd.control_reg = SND_IMMER; snd.frequenz = einst.freq; /* in Hz */ /* Array für den Frame anlegen */ if (snd_alloc( &snd, 65536L)) return(-1); snd_init( ); do { bildschirm_ausgabe( handle, &einst ); } while (! eingabe_bearbeiten( handle, &einst, &snd ) ); snd_stop( ); v_exit_cur( handle ); snd_free( &snd ); return( 0 ); }

/* SOUT.H: Headerdatei für das Assemblermodul SOUT.S */ /* Konstanten für das Sound-DMA-Control Register */ #define SND_STOP 0 #define SND_EINMAL 1 #define SND_IMMER 3 /* Konstanten für das Sound-Mode Register */ #define MOD_FR6K 0x0000 /* Samplingfrequenz: 6258 Hz */ #define MOD_FR12K 0x0001 /* 12517 Hz */ #define MOD_FR25K 0x0002 /* 25033 Hz */ #define MOD_FR50K 0x0003 /* 50066 Hz */ #define MOD_STEREO 0x0000 /* Stereo-Wiedergabe */ #define MOD_MONO 0x0080 /* Mono-Wiedergabe */ /* Konstanten für die Zumischung der Signale des GI-Soundchips */ #define GI_MIX 1 #define GI_NOMIX 2 #define VOL_12DB 0 /* Typdeklaration */ typedef struct { unsigned long anz_bytes; unsigned long bytes_pro_sekunde; int control_reg; int mode_reg; int frequenz; char *s_ptr; } SOUND; /* Prototypen der Assemblerfunktionen aus sout.s */ void snd_stop( void ); void snd_play( SOUND * ); void snd_laut( int ); void snd_links( int ); void snd_rechts( int ); void snd_hoehen( int ); void snd__tiefen ( int ); void snd_mix ( int ); void snd_init( void );

* ------------------------------------------------ * * --- SOUT.S : Routinen zur Programmierung der --- * * --- DMA-Soundchips --- * * —-- --- * * --- Zum Einbinden in Turbo-C 2.0, --- * * --- von Peter Engler --- * * ------------------------------------------------ * * --- Deklaration der Routinen . 10/1991 /1 129 GLOBL snd_stop GLOBL snd_play GLOBL snd_laut GLOBL snd_links GLOBL snd_rechts GLOBL snd_hoehen GLOBL snd_tiefen GLOBL snd_mix GLOBL snd_init * --- Adressen der DMA-Soundchipregister S_CNTRL EQU $FF8900 F_BASE EQU $FF8903 F_COUNT EQU $FFS908 F_END EQU $FF890F S_MODE EQU $FF8920 * --- Adressen der Microwireregister MW_DATA EQU $FF8922 MW_MASK EQU $FF8924 * --- Konstanten für die Microwirekommandos C_LAUT EQU $04C0 C_LINKS EQU $0540 C_RECHTS EQU $0500 C_HOEHEN EQU $0480 C_TIEFEN EQU $0440 C_MIX EQU $0400 * --- Daten DATA EVEN * --- Heap BSS EVEN * --- Speicher für Parameter reservieren SND_ADR: ds.l 1 LAUTST: ds.w 1 LINKS: ds.w 1 RECHTS: ds.w 1 HOEHEN: ds.w 1 TIEFEN: ds.w 1 MIX: ds.w 1 * --- Code TEXT EVEN * --- Aufruf von s_stop im Supervisormodus snd_stop: pea s_stop * Adresse von s_stop auf Stack move.w #$26,-(sp) * SUPEXEC trap #14 addq.l #6, sp rts * --- Aufruf von s_play im Supervisormodus snd_play: move.l a0,SND_ADR * Adresse der Struktur retten pea s_play * Adresse von s_stop auf Stack move.w #$26,-(sp) * SUPEXEC trap #14 * Xbios-Aufruf addq.l #6,sp * Stackpointer korrigieren rts * --- Aufruf von s_laut im Supervisormodus snd_laut: move.w d0,LAUTST * Parameter (Lautstärke) retten pea s_laut * Adresse von s_laut auf Stack move.w #$26,-(sp) * SUPEXEC trap #14 * Xbios-Aufruf addq.l #6,sp * Stackpointer korrigieren rts * --- Aufruf von s_links im Supervisormodus snd_links: move.w d0,LINKS * Parameter (Lautstärke links) retten pea s_links * Adresse von s_links auf Stack move.w #$26,-(sp) * SUPEXEC trap #14 * Xbios-Aufruf addq.l #6,sp * Stackpointer korrigieren rts * --- Aufruf von s_rechts im Supervisormodus snd_rechts: move.w d0,RECHTS * Parameter (Lautstärke rechts) retten pea s_rechts * Adresse von s_rechts auf Stack move.w #$26,-(sp) * SUPEXEC trap #14 * Xbios-Aufruf addq.l #6,sp * Stackpointer korrigieren rts * --- Aufruf von s_hoehen im Supervisormodus snd_hoehen: move.w d0,HOEHEN * Parameter (Hoehen) retten pea s_hoehen * Adresse von s_hoehen auf Stack move.w #$26,-(sp) * SUPEXEC trap #14 * Xbios-Aufruf addq.l #6,sp * Stackpointer korrigieren rts * --- Aufruf von s_tiefen im Supervisormodus snd_tiefen: move.w d0,TIEFEN * Parameter (Tiefen) retten pea s_tiefen * Adresse von s_tiefen auf Stack move.w #$26,-(sp) * SUPEXEC trap #14 * Xbios-Aufruf addq.l #6,sp * Stackpointer korrigieren rts * --- Aufruf von s_mix im Supervisormodus snd_mix: move.w d0,LAUTST * Parameter (Mix) retten pea s_mix * Adresse von s_mix auf Stack move.w #$26,-(sp) * SUPEXEC trap #14 * Xbios-Aufruf addq.l #6,sp * Stackpointer korrigieren rts * ---- Aufruf von s_init im Supervisormodus snd_init: pea s_init * Adresse von s_init auf Stack move.w #$26,-(sp) * SUPEXEC trap #14 * Xbios-Aufruf addq.l #6,sp * Stackpointer korrigieren rts * --- Stoppen der Tonausgabe s_stop: move.w #0, S_CNTRL * Sound-Control-Register löschen rts * --- Ton ausgeben. Der Ton wird durch die SOUND- * Struktur beschrieben s_play: movem.l d3/d4,-(sp) * d3 und d4 retten movea.l SND_ADR,a0 * Adresse der Sound-Struktur in a0 move.l (a0)+,d0 * Anzahl Bytes in d0 lea.l 4(a0),a0 * Auf 'control_reg' positionieren move.w (a0)+,d3 * 'control_reg' in d3 move.w (a0),d4 * 'mode_reg' in d4 lea.l 4(a0),a0 * Auf ’s_ptr' positionieren move.l (a0),d1 * Adresse der Bytes in d1 move.l d1,d2 * Adresse merken move.b d1,F_BASE+4 * Low-Byte eintragen asr.l #8,d1 * Mid-Byte holen move.b d1,F_BASE+2 * Mid-Byte eintragen asr.l #8,d1 * High-Byte holen move.b d1,F_BASE * High-Byte eintragen add.l d0,d2 * Frame-End berechnen move.b d2,F_END+4 * Low-Byte eintragen asr.l #8,d2 * Mid-Byte holen move.b d2,F_END+2 * Mid-Byte eintragen asr.l #8,d2 * High-Byte holen move.b d2,F_END * High-Byte eintragen move.w d4,S_MODE * Mode-Register setzen move.w d3,S_CNTRL * Sound ausgeben (Control-Register) movem.l (sp)+,d3/d4 * d3 und d4 restaurieren rts * --- Einstelien der Gesamtlautstarke s_laut: move.w LAUTST,d0 * Parameter in d0 add.w #80,d0 * Wert für Eintragung in Microwire - asr.w #1,d0 * Datenregister aufbereiten add.w #C_LAUT,d0 * Gesamtlautstärke setzen lt_wait: cmp.w #$07FF,MW_MASK * Warten bis voriger Zyklus bne lt_wait * abgeschlossen move.w d0,MW_DATA * Datenregister eintragen rts * --- Einstellen der Lautstärke des linken Kanals s_links: move.w LINKS,d0 * Parameter in d0 add.w #40,d0 * Wert für Eintragung in Microwire - asr.w #1,d0 * Datenregister aufbereiten add.w #C_LINKS,d0 * Lautstärke links setzen lk_wait: cmp.w #$07FF,MW_MASK * Warten bis voriger Zyklus bne lk_wait * abgeschlossen move.w d0,MW_DATA * Datenregister eintragen rts * --- Einstellen der Lautstarke des rechten Kanals s_rechts: move.w RECHTS,d0 * Parameter in d0 add.w #40,d0 * Wert für Eintragung in Microwire - asr.w #1,d0 * Datenregister aufbereiten add.w #C_RECHTS,d0 * Lautstärke rechts setzen rt_wait: cmp.w #$07FF,MW_MASK * Warten bis voriger Zyklus bne rt_wait * abgeschlossen move.w d0,MW_DATA * Datenregister eintragen rts * ---- Einstellen der Hoehen s_hoehen: move.w HOEHEN,d0 * Parameter in d0 add.w #12,d0 * Wert für Eintragung in Microwire - asr.w #1,d0 * Datenregister aufbereiten add.w #C_HOEHEN,d0 * Hoehen setzen ho_wait: cmp.w #$07FF,MW_MASK * Warten bis voriger Zyklus bne ho_wait * abgeschlossen move.w d0,MW_DATA * Datenregister eintragen rts * --- Einstellen der Tiefen s_tiefen: move.w TIEFEN,d0 * Parameter in d0 add.w #12,d0 * Wert für Eintragung in Microwire - asr.w #1,d0 * Datenregister aufbereiten add.w #C_TIEFEN,d0 * Tiefen setzen tf_wait: cmp.w #$07FF,MW_MASK * Warten bis voriger Zyklus bne tf_wait * abgeschlossen move.w d0,MW_DATA * Datenregister eintragen rts * --- Mischung mit GI-Soundchip festlegen s_mix: move.w MIX,d0 * Parameter in d0 add.w #C_MIX,d0 * Mischung festlegen mx_wait: cmp.w #$07FF,MW_MASK * Warten bis voriger Zyklus bne mx_wait * abgeschlossen move.w d0,MW_DATA * Datenregister eintragen rts * --- Initialisieren der Microwireregister s_init: move.w #0,MW_DATA * Microwire - Datenregister init. move.w #$07FF,MW_MASK * Microwire - Maskenregister setzen bsr s_stop * Ton ausschalten move.w #0,LAUTST * Gesamtlautstärke auf 0 dB bsr s_laut * setzen move.w #0,LINKS * Lautstärke links auf 0 dB bsr s_links * setzen move.w #0,RECHTS * Lautstärke rechts auf 0 dB bsr s_rechts * setzen move.w #0,HOEHEN * Höhen auf 0 dB bsr s_hoehen * setzen move.w #0,TIEFEN * Tiefen auf 0 dB bsr s_tiefen * setzen move.w #1,MIX * Keine Mischung mit GI-Chip bsr s_mix * rts END

Peter Engler
Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]