; ---------------------------------------------------------------------
;
;	SMUS-loader & SMUS-converter
;
;	code and comments by Martin Silbernagl 
;
;	last revision: 01/11/1988
;
; ---------------------------------------------------------------------

_LVOAllocMem		EQU	-$0c6	; exec LVOs
_LVOFreeMem		EQU	-$0d2
_LVOOpenLibrary		EQU	-$228
_LVOCloseLibrary	EQU	-$19e
_LVOOpen		EQU	-$01e	; dos LVOs
_LVOClose		EQU	-$024
_LVORead		EQU	-$02a
_LVOWrite		EQU	-$030
_LVOSeek		EQU	-$042
_LVODisplayAlert	EQU	-$05a	; intuition LVOs

START:
	MOVEM.L	D0-D7/A0-A6,-(A7)       ; Alle Register auf den Stack legen

GET_ARGS:
	LEA	NAME_IN,A1		; Adresse des SMUS Namens
	JSR	CALC_ARG		; Argument in Namen teilen
	LEA	NAME_OUT,A1		; Adresse des ASCII Namens
	JSR	CALC_ARG		; Argument in Namen teilen

OPEN_DOS:
	MOVEA.L	4,A6			; ExecBase nach A6
	LEA	DOS_NAME,A1		; Name der Library nach A1
	MOVEQ	#0,D0			; Version Number 0
	JSR	_LVOOpenLibrary(A6)	; DOS-Library öffnen
	TST.L	D0			; konnte sie nicht geöffnet werden?
	BNE.S	OK1			; wenn doch, dann nach OK2 springen
	MOVE.W	#0,ERRORN		; Fehler #0
	JSR	ERRORS			; Alert ausgeben
	JMP	END1			; Programm beenden
OK1:	MOVE.L	D0,DOS_BASE		; Adresse der DOS-library speichern
OPEN_IN:
	MOVE.L	#NAME_IN,D1		; Adresse des Namens nach D1
	MOVE.L	#1005,D2		; Modus = MODE_OLDFILE
	MOVE.L	D0,A6			; Adresse der DOS-library
	JSR	_LVOOpen(A6)		; file öffnen
	TST.L	D0			; kein Erfolg?
	BNE.S	OK2			; wenn doch, weitermachen
	MOVE.W	#1,ERRORN		; Fehler #1
	JSR	ERRORS			; Fehler ausgeben
	JMP	END2			; Programm beenden
OK2:	MOVE.L	D0,FILE_IN		; file-handle abspeichern
OPEN_OUT:
	MOVE.L	#NAME_OUT,D1		; Adresse des Namens nach D1
	MOVE.L	#1006,D2		; Modus = MODE_NEWFILE
	MOVE.L	DOS_BASE,A6		; Adresse der DOS-library
	JSR	_LVOOpen(A6)		; file öffnen
	TST.L	D0			; kein Erfolg?
	BNE.S	OK3			; wenn doch, weitermachen
	MOVE.W	#2,ERRORN		; Fehler #2
	JSR	ERRORS			; Fehler ausgeben
	JMP	END3			; Programm beenden

OK3:	MOVE.L	D0,FILE_OUT		; file-handle abspeichern
	
	MOVE.L	A7,ADR7			; Stackpointer retten
	JMP	CONV_SMUS		; SMUS-File umwandeln
SMUS_END:
	MOVEA.L	ADR7,A7			; Stackpointer wieder holen

	MOVE.L	DOS_BASE,A6		; DOS-base holen
	MOVE.L	FILE_OUT,D1		; file-handle nach D1 holen
	JSR	_LVOClose(A6)		; file schließen
END3:
	MOVE.L	DOS_BASE,A6		; DOS-base holen
	MOVE.L	FILE_IN,D1		; file-handle nach D1 holen
	JSR	_LVOClose(A6)		; file schließen
END2:
	MOVEA.L	DOS_BASE,A1		; DOS-base holen
	MOVEA.L	4,A6			; exec-base holen		
	JSR	_LVOCloseLibrary(A6)	; Bibliothek schließen
END1:
	MOVEM.L	(A7)+,D0-D7/A0-A6	; Alle Register vom Stack
	RTS				; Und das Pgm beenden



; ---------------------------------------------------------------------
;
; Ab hier steht die Fehlerausgaberoutine
;
; ---------------------------------------------------------------------

ERRORS:
	MOVEA.L	4,A6			; ExecBase nach A6
	LEA	INTUI_NAME,A1		; Name der Library nach A1
	MOVEQ	#0,D0			; Version Number 0
	JSR	_LVOOpenLibrary(A6)	; Intuition-Library öffnen
	TST.L	D0			; Nicht möglich zu öffnen ?
	BNE.S	OK_ERR			; wenn doch, dann ok_err
	RTS
OK_ERR:
	MOVE.L	D0,INTUI_BASE		; Adresse abspeichern
	MOVEA.L	D0,A6			; Adresse kopieren
	MOVEQ	#0,D0			; Alert Nummer 0
	MOVE.W	ERRORN,D2		; Nummer des Alerts holen	
	LSL.L	#2,D2			; D2 auf Word-Offset bringen
	LEA	ALERTS,A1		; Adresse der Vektor-table nach A1
	ADDA.L	D2,A1			; Adresse des Vektors nach A1
	MOVEA.L	(A1),A0			; Adresse des Strings nach A0
	MOVE.L	#24,D1			; Höhe = 24 Punkte
	JSR	_LVODisplayAlert(A6)	; Display it !
	MOVEA.L	INTUI_BASE,A1		; intuition's Basis holen
	MOVEA.L	4,A6			; exec's Basis holen		
	JSR	_LVOCloseLibrary(A6)	; Bibliothek schließen
	RTS



; ---------------------------------------------------------------------
;
; Ab hier steht die Routine zur Umwandlung der CLI Argumente
;
; ---------------------------------------------------------------------

CALC_ARG:				; A0 Baseline, A1 Ziel
	MOVE.B	(A0)+,D1		; Zeichen holen
	CMP.B	#" ",D1			; Space?
	BEQ.S	CALC_ARG		; dann überlesen
	MOVEQ	#62,D0			; max. 64 Zeichen pro Argument
	BRA.S	FIRST_TIME		; nächsten Teil überspringen

CHAR_BY_CHAR:
	MOVE.B	(A0)+,D1		; Zeichen holen
	CMP.B	#" ",D1			; Space?
	BEQ.S	ARG_END			; -> Argument zu Ende
FIRST_TIME:
	CMP.B	#$0a,D1			; Return?
	BEQ.S	ARG_END			; -> Argument zu Ende
	MOVE.B	D1,(A1)+		; Buchstabe in Zieladresse schr.
	DBRA	D0,CHAR_BY_CHAR		; Schleife
ARG_END:
	MOVE.B	#0,(A1)+		; String mit End-Null erzeugen
	RTS				; zurück



; ---------------------------------------------------------------------
;
; Ab hier steht der SMUS-loader
;
; ---------------------------------------------------------------------

CONV_SMUS:				; A0=Name A5=Ziel D6=X D7=Y
	JSR	READ_LONG		; lese ein Langwort nach D0
	CMP.L	#"FORM",D0		; FORM-Chunk?
	BEQ.S	FORM_FOUND		; wenn ja, dann weitermachen
	MOVEQ	#3,D0			; Fehler Nummer 3
	JMP	SMUS_ERROR		; und ausgeben
FORM_FOUND:
	JSR	READ_LONG		; FORM-Länge überlesen
	JSR	READ_LONG		; lese ein Langwort nach D0
	CMP.L	#"SMUS",D0		; SMUS-File?
	BEQ.S	SMUS_FOUND		; wenn ja, dann weitermachen
	MOVEQ	#4,D0			; Fehler Nummer 4
	JMP	SMUS_ERROR		; und ausgeben
SMUS_FOUND:
	JSR	READ_LONG		; lese ein Langwort nach D0
CHK_SHDR:
	CMP.L	#"SHDR",D0		; SMUS-Header?
	BNE.S	CHK_NAME		; nächsten Befehl überspringen
	JSR	SHDR_FOUND		; Header verarbeiten
	JMP	SMUS_FOUND		; nächsten Chunk bearbeiten
CHK_NAME:
	CMP.L	#"NAME",D0		; Name des Stücks?
	BNE.S	CHK_COPY		; nächsten Befehl überspringen
	JSR	NAME_FOUND		; NAMEN verarbeiten
	JMP	SMUS_FOUND		; nächsten Chunk bearbeiten
CHK_COPY:
	CMP.L	#"(c) ",D0		; Copyright?
	BNE.S	CHK_AUTH		; nächsten Befehl überspringen
	JSR	COPY_FOUND		; Header verarbeiten
	JMP	SMUS_FOUND		; nächsten Chunk bearbeiten
CHK_AUTH:
	CMP.L	#"AUTH",D0		; Name des Autors?
	BNE.S	CHK_ANNO		; nächsten Befehl überspringen
	JSR	AUTH_FOUND		; Header verarbeiten
	JMP	SMUS_FOUND		; nächsten Chunk bearbeiten
CHK_ANNO:
	CMP.L	#"ANNO",D0		; Notizen des Autors?
	BNE.S	CHK_INS1		; nächsten Befehl überspringen
	JSR	ANNO_FOUND		; Header verarbeiten
	JMP	SMUS_FOUND		; nächsten Chunk bearbeiten
CHK_INS1:
	CMP.L	#"INS1",D0		; Name eines Instruments?
	BNE.S	CHK_TRAK		; nächsten Befehl überspringen
	JSR	INS1_FOUND		; Header verarbeiten
	JMP	SMUS_FOUND		; nächsten Chunk bearbeiten
CHK_TRAK:
	CMP.L	#"TRAK",D0		; Name eines Instruments?
	BNE.S	SKIP_CHUNK		; nächsten Befehl überspringen
	JSR	TRAK_FOUND		; Header verarbeiten
	JMP	SMUS_FOUND		; nächsten Chunk bearbeiten
SKIP_CHUNK:
	JSR	READ_LONG		; Länge des Chunks holen
	JSR	SKIP_DATA		; Chunk überlesen
	JMP	SMUS_FOUND		; nächsten Chunk bearbeiten


SHDR_FOUND:
	JSR	READ_LONG		; Chunk-Länge lesen
	LEA	SHDR,A0			; Zieladresse
	JSR	READ_DATA		; Header lesen

	LEA	STR_TEMPO,A0		; Adresse des Strings
	JSR	PUT_TEXT		; ausgeben
	MOVEQ	#0,D0			; D0 ganz löschen
	MOVE.W	SHDR,D0			; Tempo in 512teln pro min holen
	JSR	LONG_TO_HEX		; und ausgeben
	MOVE.B	#$0a,D0			; code von "Return" nach D0
	JSR	PUT_BYTE		; und ausgeben

	LEA	STR_SPEED,A0		; Adresse des Strings
	JSR	PUT_TEXT		; ausgeben
	MOVE.W	SHDR,D1			; Tempo in 512teln pro min holen
	LSR.W	#2,D1			; auf 128tel pro min bringen
	MULU	#3,D1			; auf Interrupts pro min bringen
	DIVU	#60,D1			; Interrupts pro sec berechnen
	MOVE.L	#715909,D0		; D1 mit Counterfrequenz laden
	DIVU	D1,D0			; druch die Interruptfrequenz teilen
	ANDI.L	#$0000ffff,D0		; Divisionsrest ausblenden
	JSR	LONG_TO_HEX		; und ausgeben
	MOVE.B	#$0a,D0			; code von "Return" nach D0
	JSR	PUT_BYTE		; und ausgeben

	LEA	STR_VOLUME,A0		; Adresse des Strings
	JSR	PUT_TEXT		; ausgeben
	MOVEQ	#0,D0			; D0 ganz löschen
	MOVE.B	SHDR+2,D0		; Volumen nach D0
	LSR.B	#1,D0			; ins AMIGA-Format bringen
	JSR	LONG_TO_HEX		; und ausgeben
	MOVE.B	#$0a,D0			; code von "Return" nach D0
	JSR	PUT_BYTE		; und ausgeben

	LEA	STR_TRACKS,A0		; Adresse des Strings
	JSR	PUT_TEXT		; ausgeben
	MOVEQ	#0,D0			; D0 ganz löschen
	MOVE.B	SHDR+3,D0		; Anzahl der Tracks nach D0
	JSR	LONG_TO_HEX		; und ausgeben
	MOVE.B	#$0a,D0			; code von "Return" nach D0
	JSR	PUT_BYTE		; und ausgeben
	RTS				; zurück

SUB_FOUND:
	JSR	PUT_TEXT		; Text ausgeben
	JSR	READ_LONG		; Chunk-Länge lesen
	MOVE.W	D0,D1			; D0 kopieren
	BTST	#0,D1			; ungerade Chunklänge?
	BNE.S	FOUND_LOOP		; wenn ja, eins zum Zähler addieren
	SUBQ.L	#1,D1			; zum Zähler machen
FOUND_LOOP:
	JSR	READ_BYTE		; ein Zeichen lesen
	BEQ.S	FOUND_PAD_BYTE		; wenn=0, dann Pad-Byte
	JSR	PUT_BYTE		; Zeichen wieder schreiben
	DBRA	D1,FOUND_LOOP		; ganzen Text ausgeben
FOUND_PAD_BYTE:
	RTS

NAME_FOUND:
	LEA	STR_NAME,A0		; Adresse des Strings
	JSR	SUB_FOUND		; Hauptarbeit machen
	LEA	STR_NAME2,A0		; Adresse des Strings
	JSR	PUT_TEXT		; Text ausgeben
	RTS

COPY_FOUND:
	LEA	STR_COPY,A0		; Adresse des Strings
	JSR	SUB_FOUND		; Hauptarbeit machen
	LEA	STR_COPY2,A0		; Adresse des Strings
	JSR	PUT_TEXT		; Text ausgeben
	RTS

AUTH_FOUND:
	LEA	STR_AUTH,A0		; Adresse des Strings
	JSR	SUB_FOUND		; Hauptarbeit machen
	LEA	STR_AUTH2,A0		; Adresse des Strings
	JSR	PUT_TEXT		; Text ausgeben
	RTS

ANNO_FOUND:
	LEA	STR_ANNO,A0		; Adresse des Strings
	JSR	SUB_FOUND		; Hauptarbeit machen
	LEA	STR_ANNO2,A0		; Adresse des Strings
	JSR	PUT_TEXT		; Text ausgeben
	RTS

INS1_FOUND:
	JSR	READ_LONG		; Chunk-Länge lesen
	BTST	#0,D0			; ungerade Chunklänge?
	BEQ.S	EVEN_LENGTH		; wenn nicht -> überspringen
	ADDQ.L	#1,D0			; eins zur Länge addieren
EVEN_LENGTH:
	LEA	INS1,A0			; Zieladresse
	JSR	READ_DATA		; Daten lesen
	CLR.B	(A0,D0)			; Null an den String hängen

	LEA	STR_INS1,A0		; Adresse des Strings
	JSR	PUT_TEXT		; ausgeben
	MOVEQ	#0,D0			; D0 ganz löschen
	MOVE.B	INS1,D0			; Adresse der Nummer des Instr.
	JSR	LONG_TO_HEX2		; und ausgeben
	LEA	STR_INS12,A0		; Adresse des Strings
	JSR	PUT_TEXT		; ausgeben
	LEA	INS1+4,A0		; Adresse des Namens
	JSR	PUT_TEXT		; ausgeben
	LEA	STR_INS13,A0		; Adresse des Strings
	JSR	PUT_TEXT		; ausgeben
	RTS				; zurück

TRAK_FOUND:
	CLR.W	COUNTER			: Datenzähler löschen
	LEA	STR_TRAK,A0		; Adresse des Strings
	JSR	PUT_TEXT		; und ausgeben
	MOVE.L	TRACK_NUMBER,D0		; Nummer des Tracks
	JSR	LONG_TO_HEX2		; Nummer ausgeben
	ADDQ.L	#1,TRACK_NUMBER		; einen Track weiter gehen
	LEA	STR_TRAK2,A0		; Adresse des Strings
	JSR	PUT_TEXT		; und ausgeben

	JSR	READ_LONG		; Länge des Chunks holen
	LSR.L	#1,D0			; durch zwei teilen (=Anz. Words)
	SUBQ.L	#1,D0			; zum Schleifenzähler machen
	MOVE.L	D0,D1			; Länge kopieren
DO_TRACK:
	MOVEQ	#0,D0			; D0 löschen
	JSR	READ_BYTE		; ein Byte einlesen
	CMP.B	#127,D0			; mit höchstem Wert vergleichen
	BHI.S	NO_NOTE			; wenn größer, dann keine Note
CHORDED:
	MOVEQ	#0,D4			; D4 löschen
	DIVU	#12,D0			; D0 durch 12(Töne) teilen
	MOVE.B	D0,D4			; Oktave abspeichern
	LSL.L	#8,D4			; um ein Byte nach oben schieben
	SWAP	D0			; Rest der Div. nach unten holen
	MOVE.B	D0,D4			; Nummer des Tons abspeichern
	MOVEQ	#7,D3			; D3 setzen (Datenwort)
	JSR	READ_BYTE		; ein Byte lesen
	MOVE.B	D0,D5			; D0 zwischenspeichern
	ANDI.W	#$0007,D5		; Notenlänge berechnen
	LSL.W	#1,D5			; Wordoffset berechnen
	LEA	LENGTH,A0		; Adresse der Längentabelle
	MOVE.W	(A0,D5),D2		; Laenge nach D2 holen
	BTST	#3,D0			; punktierte Note?
	BEQ.S	NOT_DOTTED		; wenn nicht, dann weiter
	MULU	#3,D2			; mal drei nehmen
	LSR.W	#1,D2			; und durch zwei teilen
NOT_DOTTED:
	BTST	#4,D0			; Triolen ?
	BEQ.S	NO_TRIPLET		; wenn nicht, dann weiter
	LSL.W	#1,D2			; mal zwei teilen
	DIVU	#3,D2			; durch drei teilen
NO_TRIPLET:
	BTST	#6,D0			; Note gebunden ?
	BEQ.S	NOT_TIED		; wenn nicht, dann weiter
	MOVEQ	#7,D3			; Hüllk. und Wave nicht starten
NOT_TIED:
	BTST	#7,D0			; Note aus einem Akkord ?
	BEQ.S	NOT_CHORDED		; wenn nicht, dann weiter
	JSR	READ_BYTE		; nächste Note holen
NOT_CHORDED:
	MOVEQ	#0,D0			; D0 löschen
	MOVE.W	D3,D0			; Eventword nach D0
	JSR	PUT_EVENT		; und das Event ausgeben
	MOVEQ	#0,D0			; D0 löschen
	MOVE.W	D2,D0			; Länge nach D0
	JSR	PUT_EVENT		; und die Länge ausgeben
	MOVEQ	#0,D0			; D0 löschen
	MOVE.W	D4,D0			; Tonhöhe nach D0
	JSR	PUT_EVENT		; und die Tonhöhe ausgeben
	DBRA	D1,DO_TRACK		; nächsten Event abarbeiten
	JMP	END_TRAK		; beenden
NO_NOTE:
	CMP.B	#128,D0			; Pause ?
	BNE.S	NO_REST			; wenn nicht, dann überspringen
	JSR	READ_BYTE		; ein Byte lesen
	ANDI.W	#$0007,D0		; Pausenlänge berechnen
	LSL.W	#1,D0			; Wordoffset berechnen
	LEA	LENGTH,A0		; Adresse der Längentabelle
	MOVE.W	(A0,D0),D2		; Laenge nach D2 holen
	BTST	#3,D0			; punktierte Pause?
	BEQ.S	NOT_DOTTED2		; wenn nicht, dann weiter
	MULU	#3,D2			; mal drei nehmen
	LSR.W	#1,D2			; und durch zwei teilen
NOT_DOTTED2:
	BTST	#4,D0			; Triolen ?
	BEQ.S	NO_TRIPLET2		; wenn nicht, dann weiter
	LSL.W	#1,D2			; mal zwei teilen
	DIVU	#3,D2			; durch drei teilen
NO_TRIPLET2:
	MOVEQ	#0,D0			; D0 löschen
	JSR	PUT_EVENT		; Event ausgeben
	MOVEQ	#0,D0			; D0 löschen
	MOVE.W	D2,D0			; Länge nach D0
	JSR	PUT_EVENT		; und die Länge ausgeben
	DBRA	D1,DO_TRACK		; nächsten Event abarbeiten
	JMP	END_TRAK		; beenden
NO_REST:
	CMP.B	#129,D0			; Instrument neu setzen ?
	BNE.S	UNKNOWN			; wenn nicht, dann überspringen
	JSR	READ_BYTE		; Nummer des Instruments lesen
	MOVEQ	#0,D2			; D2 löschen
	MOVE.B	D0,D2			; D0 zwischenspeichern
	MOVE.L	#$18,D0			; Hüllk. & Wellenf. neu setzen
	JSR	PUT_EVENT		; Event ausgeben
	MOVEQ	#0,D0			; Länge des Events: 0
	JSR	PUT_EVENT		; Event ausgeben
	MOVE.L	D2,D0			; Nummer des Ins. zurückholen
	JSR	PUT_EVENT		; Nummer der Wellenf. ausgeben
	JSR	PUT_EVENT		; Nummer der Hüllkurve ausg.
	DBRA	D1,DO_TRACK		; nächtes Event bearbeiten
	JMP	END_TRAK		; beenden
UNKNOWN:
	JSR	READ_BYTE		; zweites Byte überlesen
	DBRA	D1,DO_TRACK		; nächtes Event bearbeiten
END_TRAK:
	MOVE.L	#$8000,D0		; Flag für "Ende" setzen
	JSR	PUT_EVENT		; und ausgeben
	RTS


SHDR:
	DC.W	0	; Tempo in 512teln pro Minute
	DC.B	0	; Lautstärke (von 0 bis 127)
	DC.B	0	; Anzahl der Tracks insgesamt
INS1:
	DC.B	0	; Nummer des Instruments
	DC.B	0	; Art des Instruments (0=Normal 1=MIDI)
	DC.B	0,0	; MIDI-Kanal und MIDI-Preset, wenn Art=1
	DS.B	256	; Platz für den Namen des Instruments

TRACK_NUMBER:
	DC.L	0

LENGTH:
	DC.W	384,192,96,48,24,12,6,3


STR_TEMPO:	DC.B	"TEMPO:		DC.W	",0
STR_SPEED:	DC.B	"SPEED:		DC.W	",0
STR_VOLUME:	DC.B	"VOLUME:		DC.W	",0
STR_TRACKS:	DC.B	"TRACKS:		DC.W	",0
STR_NAME:	DC.B	"NAME:		DC.B	",34,0
STR_NAME2:	DC.B	34,",0",10,"	EVEN",10,0
STR_COPY:	DC.B	"COPYRIGHT:	DC.B	",34,"(c) ",0
STR_COPY2:	DC.B	34,",0",10,"	EVEN",10,0
STR_AUTH:	DC.B	"AUTHOR:	DC.B	",34,0
STR_AUTH2:	DC.B	34,",0",10,"	EVEN",10,0
STR_ANNO:	DC.B	"ANNOTATIONS:	DC.B	",34,0
STR_ANNO2:	DC.B	34,",0",10,"	EVEN",10,0
STR_INS1:	DC.B	"INSTRUMENT",0
STR_INS12:	DC.B	":	DC.B	",34,0
STR_INS13:	DC.B	34,",0",10,"	EVEN",10,0
STR_TRAK:	DC.B	10,"TRACK",0
STR_TRAK2:	DC.B	":",10,0
STR_EVENT:	DC.B	"	DC.W	",0
	EVEN

READ_LONG:
	MOVE.L	A0,-(A7)		; A0 auf den Stack legen
	MOVEQ	#4,D0			; ein Langwort lesen
	LEA	LONG_B,A0		; Adresse des Buffers
	JSR	READ_DATA		; Langwort in den Buffer lesen
	MOVE.L	LONG_B,D0		; Langwort nach D0 holen
	MOVEA.L	(A7)+,A0		; A0 vom Stack holen
	RTS				; zurück
LONG_B:	DC.L	0			; hier kommt das Langw. hinein

READ_BYTE:
	MOVE.L	A0,-(A7)		; A0 auf den Stack legen
	MOVEQ	#1,D0			; ein Byte lesen
	LEA	BYTE_B,A0		; Adresse des Buffers
	JSR	READ_DATA		; Langwort in den Buffer lesen
	MOVE.B	BYTE_B,D0		; Langwort nach D0 holen
	MOVEA.L	(A7)+,A0		; A0 vom Stack holen
	RTS				; zurück
BYTE_B:	DC.W	0			; hier kommt das Langw. hinein

PUT_BYTE:
	MOVEM.L	A0/D0,-(A7)		; A0 und D0 auf den Stack legen
	MOVE.B	D0,BYTE_R		; In den Buffer legen
	MOVEQ	#1,D0			; ein Langwort lesen
	LEA	BYTE_R,A0		; Adresse des Buffers
	JSR	PUT_DATA		; Byte schreiben
	MOVEM.L	(A7)+,A0/D0		; A0 und D0 vom Stack holen
	RTS				; zurück
BYTE_R:	DC.W	0			; hier kommt das Langw. hinein

PUT_TEXT:				; A0 Textadresse
	MOVE.L	D0,-(A7)		; D0 auf den Stack legen
PUT_TEXT_LOOP:				; A0 Textadresse
	MOVE.B	(A0)+,D0		; ein Byte holen
	BEQ.S	END_PUT_TEXT		; wenn gleich Null -> Textende
	JSR	PUT_BYTE		; ins ASCII-File ausgeben
	BRA.S	PUT_TEXT_LOOP		; nächtes Zeichen
END_PUT_TEXT:
	MOVE.L	(A7)+,D0		; D0 vom Stack holen
	RTS	

PUT_EVENT:				; D0 Event
	MOVEM.L	D0/A0,-(A7)		; Register auf den Stack legen
	TST.W	COUNTER			; Zähler prüfen
	BNE.S	EVENTS_NOT_ZERO		; schon einer ausgegeben -> Sprung
	LEA	STR_EVENT,A0		; Adresse des Strings
	JSR	PUT_TEXT		; Anfang der Zeile ausgeben
	BRA.S	SKIP_TEST		; Test auf Zeilenende übersringen
EVENTS_NOT_ZERO:
	MOVE.W	D0,-(A7)		; D0 auf den Stack
	MOVE.B	#",",D0			; Komma nach D0
	JSR	PUT_BYTE		; und ausgeben
	MOVE.W	(A7)+,D0		; D0 vom Stack
	CMP.W	#12,COUNTER		; Zeilenende?
	BNE.S	SKIP_TEST		; nächsten Teil auslassen	
	MOVE.W	#0,COUNTER		; Zähler auf -1 setzen
	JSR	LONG_TO_HEX		; Event ausgeben
	MOVE.B	#$0a,D0			; "Return" nach D0
	JSR	PUT_BYTE		; und ausgeben
	MOVEM.L	(A7)+,D0/A0		; Register vom Stack holen
	RTS				; beenden
SKIP_TEST:
	ADDQ.W	#1,COUNTER		; Counter um eins erhöhen
	JSR	LONG_TO_HEX		; Event augeben
	MOVEM.L	(A7)+,D0/A0		; Register vom Stack holen
	RTS				; beenden

LONG_TO_HEX:				; D0: Zahl die umgewandelt wird
	MOVEM.L	D0-D4/A0,-(A7)		; Register auf den Stack legen
	MOVE.L	D0,D2			; Zahl sichern
	MOVE.B	#"$",D0			; mit Dollarzeichen laden
	JSR	PUT_BYTE		; und ausgeben
	BRA.S	NO_DOLLARS_MAN		; nächsten Teil überspringen
LONG_TO_HEX2:
	MOVEM.L	D0-D4/A0,-(A7)		; Register auf den Stack legen
	MOVE.L	D0,D2			; Zahl sichern
NO_DOLLARS_MAN:
	MOVEQ	#0,D3			; Flag für Nullstellen löschen
	LEA	HEX_DATA,A0		; Adresse der Zeichentabelle
	MOVEQ	#7,D4			; max. 8 Zeichen
CONV_LOOP:
	ROL.L	#4,D2			; zurechtschieben
	MOVE.W	D2,D1			; D2 kopieren
	ANDI.W	#$000f,D1		; nur untersten 4 Bits lassen
	MOVE.B	(A0,D1),D0		; entsprechende Ziffer holen
	CMP.B	#"0",D0			; handelt sich's um 'ne Null?
	BNE.S	CONV_NOT_ZERO		; wenn nicht, nächsten Teil überspr.
	TST.B	D3			; Bis jetzt nur Nullen?
	BEQ.S	NO_CHAR			; dann nichts ausgeben
CONV_NOT_ZERO:
	MOVEQ	#-1,D3			; Flag setzen
	JSR	PUT_BYTE		; einen Buchstaben ausgeben
NO_CHAR:
	DBRA	D4,CONV_LOOP		; Schleife
	TST.B	D3			; Alles nur Nullen?
	BNE.S	NUM_EXISTS		; wenn nicht, dann weiter
	MOVE.B	#"0",D0			; D0 mit "0" laden
	JSR	PUT_BYTE		; ausgeben
NUM_EXISTS:
	MOVEM.L	(A7)+,D0-D4/A0		; Register auf den Stack legen
	RTS

HEX_DATA:	DC.B	"0123456789ABCDEF"
	EVEN

READ_DATA:				; A0=Ziel D0=Länge
	MOVEM.L	D0-D4/A0-A1/A6,-(A7)	; Register auf den Stack
	MOVE.L	FILE_IN,D1		; Adresse des file-handles
	MOVE.L	A0,D2			; Zieladresse des Reads
	MOVE.L	D0,D3			; Anzahl der zu lesenden Bytes
	MOVE.L	D0,D4			; Kopie der Anzahl machen
	MOVEA.L	DOS_BASE,A6		; DOS-Base nach A6
	JSR	_LVORead(A6)		; und lesen
	CMP.L	D4,D0			; gewünschte Anzahl gelesen?
	BEQ.S	READ_DATA_OK		; wenn ja, dann weiter
	MOVEM.L	(A7)+,D0-D4/A0-A1/A6	; Register auf den Stack
	JMP	SMUS_END		; Lader beenden
READ_DATA_OK:
	MOVEM.L	(A7)+,D0-D4/A0-A1/A6	; Register auf den Stack
	RTS	

PUT_DATA:				; A0=Ziel D0=Länge
	MOVEM.L	D0-D4/A0-A1/A6,-(A7)	; Register auf den Stack
	MOVE.L	FILE_OUT,D1		; Adresse des file-handles
	MOVE.L	A0,D2			; Quelle der Daten
	MOVE.L	D0,D3			; Anzahl der zu schreibenden Bytes
	MOVE.L	D0,D4			; Kopie der Anzahl machen
	MOVEA.L	DOS_BASE,A6		; DOS-Base nach A6
	JSR	_LVOWrite(A6)		; und schreiben
	CMP.L	D4,D0			; gewünschte Anzahl gelesen?
	BEQ.S	PUT_DATA_OK		; wenn ja, dann weiter
	MOVEM.L	(A7)+,D0-D4/A0-A1/A6	; Register auf den Stack
	JMP	SMUS_END		; Lader beenden
PUT_DATA_OK:
	MOVEM.L	(A7)+,D0-D4/A0-A1/A6	; Register auf den Stack
	RTS	

SKIP_DATA:				; A0=Ziel D0=Länge
	MOVEM.L	D0-D3/A0-A1/A6,-(A7)	; Register auf den Stack
	MOVE.L	FILE_IN,D1		; Adresse des file-handles
	MOVE.L	D0,D2			; Anz. der zu überlesenden Bytes
	MOVEQ	#0,D3			; Von der aktuellen r/w-position aus
	MOVEA.L	DOS_BASE,A6		; DOS-Base nach A6
	JSR	_LVOSeek(A6)		; Bytes überlesen
	CMPI.L	#-1,D0			; gewünschte Anzahl überlesen?
	BNE.S	SKIP_DATA_OK		; wenn ja, dann weiter
	MOVEM.L	(A7)+,D0-D3/A0-A1/A6	; Register auf den Stack
	JMP	SMUS_END		; Lader beenden
SKIP_DATA_OK:
	MOVEM.L	(A7)+,D0-D3/A0-A1/A6	; Register auf den Stack
	RTS	

SMUS_ERROR:				; D0=Fehlernummer
	MOVE.W	D0,ERRORN		; Fehlernummer 
	JSR	ERRORS			; und ausgeben
	ADDQ.L	#4,A7			; Stack maipulieren
	RTS				; zwei Ebenen zurück


; ---------------------------------------------------------------------
;
; Ab hier stehen der unsere Variablen und Zwischenspeicher
;
; ---------------------------------------------------------------------

INTUI_BASE:	DC.L	0		; Adresse der intuition-library
DOS_BASE:	DC.L	0		; Adresse der dos-library
FILE_IN:	DC.L	0		; Adresse des SMUS File-Handles
FILE_OUT:	DC.L	0		; Adresse des ASCII File-Handles
ERRORN:		DC.W	0		; Nummer der Fehlermeldung
COUNTER:	DC.W	0		; Nummer des nächsten Tracks
ADR7:		DC.L	0		; Zwischenspeicher für A7
ALERTS:		DC.L    ALERT0,ALERT1	; Adressen der Alert-Texte
		DC.L	ALERT2,ALERT3
		DC.L	ALERT4
NAME_IN:	DS.B	64		; Platz für den Namen des in-files
NAME_OUT:	DS.B	64		; Platz für den Namen des out-files
DOS_NAME:	DC.B	"dos.library",0
GFX_NAME:	DC.B	"gfx.library",0	
INTUI_NAME:	DC.B	"intuition.library",0
ALERT0:		DC.B	0,16,16,"Fehler #0: kann DOS-library nicht öffnen",0,0
ALERT1:		DC.B	0,16,16,"Fehler #1: kann Input-file nicht öffnen",0,0
ALERT2:		DC.B	0,16,16,"Fehler #2: kann Output-file nicht öffnen",0,0
ALERT3:		DC.B	0,16,16,"Fehler #3: Input ist kein IFF/FORM-file",0,0
ALERT4:		DC.B	0,16,16,"Fehler #4: IFF-file ist kein SMUS-file",0,0

       END
