; ***************************************************************
; *
; * MIDI8031 Sprachsynthesizer (C) JP 1992
; *
; * Um dieses Programm nutzen zu koennen, muss zwischen
; * Portpin P1.0 (Buchsenleiste Pin 3) und +5 Volt
; * (Buchsenleiste Pin 2) ein Lautsprecher an-
; * geschlossen werden:
; *
; * (3) <----[R1=150 Ohm]-----+-----[L1=1 MiliHenry]-----+
; * 						  |                          | /|
; * zum               [C1=2.2 MikroFarad]               [ ] | Laut-
; * MIDI8031                  |                         [ ] | sprecher
; *                           |                          | \| 45 Ohm
; * (2) <---------------------+--------------------------+
; * 
; * Der Wiederstand des Lautsprechers sollte 45 Ohm betragen
; * Alternativ dazu geht auch eine 4-8 Ohm-Typ mit vorgeschaltetem
; * 20 Ohm-Wdst (nur eben viel leiser). Falls keine Spule zur
; * Verfuegung steht, kann sie durch einen 50 Ohm Wdst. ersetzt
; * werden. Allerdings ist dann das 8 KiloHertz PWM-Signal staerker
; * als (stoerendes) Pfeifen zu hoeren.
; *                                                          
; ***************************************************************

	.registers reg51.inc	; 8031-Registerdefinition

; *** Die Variable fenster bestimmt die Ablaufgeschwindigkeit
; *** der Sprache: Werte zwischen 14..128..256 sind erlaubt
; *** Der Normalwert ist 128

fenster = 128				; ( 0 = 256)

; *** Variablen Internes RAM, oberhalb BITFELD***
	.var_org $30		; Variablen-PC setzen

frq: 	.ds.b 6			; Frequenzen
vol: 	.ds.b 6			; Lautstaerken
pos: 	.ds.b 6			; Positionen im Sample
adko:	.ds.b 1			; Add.w. wg. mulu + 128 wg Timer
wert: 	.ds.b 1			; Laufende Summe
copy:	.ds.b 13		; Shiftbereich 6 frq/6 vol/adko
phopo:	.ds.b 2			; Roving Phonems Pointer L/H

stack:					; Ab hier das restliche RAM fuer den Stack


; *** Code: Ab hier beginnt das eigentliche Programm ***

	.text_org $8000

; *** 'Interruptbereich' wie EPROM ab Adresse 0 ***
		ljmp go

int0:	reti
		.ds.b 7
timer0:	setb P1.0			; Bit P1.0 setzen (PWM-Off)
		reti
		.ds.b 5
int1:	reti
		.ds.b 7
timer1:	reti
		.ds.b 7
serial:	reti
		.ds.b 7

; **** Hauptroutine ***
go:
	clr P3.5			; LED aus
	mov SP,#stack		; Stack starten

	mov phopo,#phono&255
	mov phopo+1,#phono/256

	acall play

	sjmp go

; **** Pulsplayer ***

play:
	mov copy,#0			; frq's Initialisieren
	mov copy+1,#0
	mov copy+2,#0
	mov copy+3,#0
	mov copy+4,#0
	mov copy+5,#0
	mov copy+6,#0		; vol's Initialisieren
	mov copy+7,#0
	mov copy+8,#0
	mov copy+9,#0
	mov copy+10,#0
	mov copy+11,#0
	mov copy+12,#192	; 128: (adko) Wandler


; *** say: Phonemsynthese ***
say:	
	mov pos,#0			; POS Initialisieren
	mov pos+1,#0
	mov pos+2,#0
	mov pos+3,#0
	mov pos+4,#0
	mov pos+5,#0

; * Interrupt TO an
	clr IE.1			; T0 Interrupt disablen
	setb TCON.4			; TR0 Timer 0 laeuft
	orl TMOD,#%11		; M0=3
	mov TL0,#0			; Timer resetten
	setb IE.7			; Gennerell Interrupts zulassen
	setb IE.1			; T0 Interrupt Ein

	mov DPTR,#sitab		; Auf Sinustabelle zeigen

	mov R7,#14			; Quickstart
	ajmp s0				; Hier geht's los

; **** Main-Synthese-Block Anfang ****
; **** In diesem Block wird ein Abtastwert errechnet,
; **** indem er aus 6 Frequenzkomponenten zusammengesetzt wird
s3:
	nr=0				; Index des Kanals		
	mov A,pos+nr		; 1 Position holen
	movc A,@A+DPTR		; 2 A=sin(posx)
	mov B,vol+nr		; 2 B=volx
	mul AB				; 4 Volume berechnen
	mov wert,B			; 1 A=sin(posx)*volx
	mov A,frq+nr		; 1 Frequenz holen
	add A,pos+nr		; 1 Index steppen
	mov pos+nr,A		; 1 merken

	nr=1
	mov A,pos+nr
	movc A,@A+DPTR
	mov B,vol+nr
	mul AB
	mov A,B
	add A,wert
	mov wert,A
	mov A,frq+nr
	add A,pos+nr
	mov pos+nr,A

	nr=2
	mov A,pos+nr
	movc A,@A+DPTR
	mov B,vol+nr
	mul AB
	mov A,B
	add A,wert
	mov wert,A
	mov A,frq+nr
	add A,pos+nr
	mov pos+nr,A

	nr=3
	mov A,pos+nr
	movc A,@A+DPTR
	mov B,vol+nr
	mul AB
	mov A,B
	add A,wert
	mov wert,A
	mov A,frq+nr
	add A,pos+nr
	mov pos+nr,A

	nr=4
	mov A,pos+nr
	movc A,@A+DPTR
	mov B,vol+nr
	mul AB
	mov A,B
	add A,wert
	mov wert,A
	mov A,frq+nr
	add A,pos+nr
	mov pos+nr,A

	nr=5
	mov A,pos+nr
	movc A,@A+DPTR
	mov B,vol+nr
	mul AB
	mov A,B

	add A,wert
	add A,adko			; Addition volume+Timer
	jnc s2				; Nicht oberer Anschlag
	mov A,#-1			; Maximum
s2: clr	P1.0			; +1 Lautsprecher an!
	mov TL0,A			; Spezial: Timer

	add A,#126			; Finden der Konstante durch Testreihe
	jc s6				; C: > als Minimum gewesen
	mov TL0,#133 		; Timer kurz aus
s6:
	
	mov A,frq+nr
	add A,pos+nr
	mov pos+nr,A
; **** Main-Synthese-Block Ende, 93 Zyklen ****

	djnz R7,s1			; 2
	mov R7,#fenster		; Anzahl Synthesebytes
s0:						; *** Start loop ***

	mov A,copy			; frq0>127: Ende
	jb ACC.7,s5			; Zu hohe Frq!
	mov frq,A			; sonst eintragen

	mov frq+1,copy+1
	mov frq+2,copy+2
	mov frq+3,copy+3
	mov frq+4,copy+4
	mov frq+5,copy+5
	mov vol,copy+6		; vol shiften
	mov vol+1,copy+7
	mov vol+2,copy+8
	mov vol+3,copy+9
	mov vol+4,copy+10
	mov vol+5,copy+11
	mov adko,copy+12	; adko shiften
	ajmp s3

; **** Fertig ****
s5:
	clr IE.1			; Interrupt Aus!
	setb P1.0			; Port: Strom aus!
	ret					; Fertig!

; *** Transportschleife (Daten->Copy) ***
s4:
	mov R6,#2			; R6: Wartezyklenzaehler
	djnz R6,!			; R6*2

	mov A,#copy+13		; 1
	clr C				; 1
	subb A,R7			; 1
	mov R0,A			; 1

	mov DPL,phopo		; 2 DPTR laden
	mov DPH,phopo+1		; 2
	clr A				; 1
	movc A,@A+DPTR 		; 2
	inc DPTR			; 2
	mov phopo,DPL		; 2 DPTR abspeichern
	mov phopo+1,DPH		; 2
	mov @R0,A			; 1
	mov DPTR,#sitab		; 2 Alte Tabelle

	ajmp s3

; **** Warteschleife/Arbeit? ****
s1:
	mov A,R7			; 1
	add A,#-14			; 1
	jnc s4				; 2
	
	mov R6,#12			; R6: Wartezyklenzaehler
	djnz R6,!			; R6*2

	ajmp s3				; fertig...

sitab:
	.hide					; Ab hier Unsichtbar...

	.ibytes sinus.img		; 256 * [0..128..255] Sinustabelle


; * Ab hier befinden sich die Sprachinformationen
phono:
; Die Anfangs-Glocke...
ad=150
v=255
	.dc.b 20,19,0,0,0,0,v,v/10,0,0,0,0,ad
	.dc.b 20,18,0,0,0,0,v/2,v/11,0,0,0,0,ad
	.dc.b 20,17,0,0,0,0,v/3,v/12,0,0,0,0,ad
	.dc.b 20,16,0,0,0,0,v/4,v/13,0,0,0,0,ad
	.dc.b 20,15,0,0,0,0,v/5,v/14,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/6,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/7,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/8,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/9,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/10,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/11,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/12,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/13,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/14,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/15,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/16,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/17,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/18,0,0,0,0,0,ad
	.dc.b 20,0,0,0,0,0,v/19,0,0,0,0,0,ad

	.dc.b 40,19,0,0,0,20,v,v/10,0,0,10,0,ad
	.dc.b 40,18,0,0,0,21,v/2,v/11,0,10,0,0,ad
	.dc.b 40,17,0,0,0,21,v/3,v/12,0,10,0,0,ad
	.dc.b 40,16,0,0,0,20,v/4,v/13,0,10,0,0,ad
	.dc.b 40,15,0,0,0,21,v/5,v/14,0,10,0,0,ad
	.dc.b 40,0,0,0,0,21,v/6,0,0,0,0,10,ad
	.dc.b 40,0,0,0,0,20,v/7,0,0,0,0,10,ad
	.dc.b 40,0,0,0,0,21,v/8,0,0,0,0,10,ad
	.dc.b 40,0,0,0,0,21,v/9,0,0,0,0,10,ad
	.dc.b 40,0,0,0,0,20,v/10,0,0,0,0,11,ad
	.dc.b 40,0,0,0,0,21,v/11,0,0,0,0,12,ad
	.dc.b 40,0,0,0,0,21,v/12,0,0,0,0,13,ad
	.dc.b 40,0,0,0,0,20,v/13,0,0,0,0,14,ad
	.dc.b 40,0,0,0,0,20,v/15,0,0,0,0,15,ad
	.dc.b 40,0,0,0,0,21,v/17,0,0,0,0,14,ad
	.dc.b 40,0,0,0,0,21,v/20,0,0,0,0,13,ad
	.dc.b 40,0,0,0,0,20,v/22,0,0,0,0,12,ad
	.dc.b 40,0,0,0,0,21,v/25,0,0,0,0,6,ad
	.dc.b 40,0,0,0,0,21,v/30,0,0,0,0,2,ad

	.dc.b 30,19,0,0,40,20,v,v/10,0,10,10,0,ad
	.dc.b 40,18,0,0,40,21,v/2,v/11,10,10,0,0,ad
	.dc.b 30,17,0,0,40,21,v/3,v/12,10,10,0,0,ad
	.dc.b 40,16,0,0,40,20,v/4,v/13,10,10,0,0,ad
	.dc.b 30,15,0,0,40,21,v/5,v/14,10,10,0,0,ad
	.dc.b 40,0,0,0,40,21,v/6,0,0,0,10,10,ad
	.dc.b 30,0,0,0,40,20,v/7,0,0,0,10,10,ad
	.dc.b 40,0,0,0,40,21,v/8,0,0,0,10,10,ad
	.dc.b 30,0,0,0,40,21,v/9,0,0,0,10,10,ad
	.dc.b 40,0,0,0,40,20,v/10,0,0,0,9,11,ad
	.dc.b 30,0,0,0,40,21,v/11,0,0,0,9,12,ad
	.dc.b 40,0,0,0,40,21,v/12,0,0,0,9,13,ad
	.dc.b 30,0,0,0,40,20,v/13,0,0,0,8,14,ad
	.dc.b 40,0,0,0,40,20,v/15,0,0,0,7,15,ad
	.dc.b 30,0,0,0,40,21,v/17,0,0,0,6,14,ad
	.dc.b 40,0,0,0,40,21,v/20,0,0,0,5,13,ad
	.dc.b 30,0,0,0,40,20,v/22,0,0,0,4,12,ad
	.dc.b 40,0,0,0,40,21,v/25,0,0,0,3,6,ad
	.dc.b 30,0,0,0,40,21,v/30,0,0,0,2,2,ad

	.dc.b 30,19,0,0,40,20,v,v/10,0,10,10,0,ad
	.dc.b 20,18,0,0,40,21,v/2,v/11,10,10,0,0,ad
	.dc.b 30,17,0,0,40,21,v/3,v/12,10,10,0,0,ad
	.dc.b 20,16,0,0,40,20,v/4,v/13,10,10,0,0,ad
	.dc.b 30,15,0,0,40,21,v/5,v/14,10,10,0,0,ad
	.dc.b 20,0,0,0,40,21,v/6,0,0,0,10,10,ad
	.dc.b 30,0,0,0,40,20,v/7,0,0,0,10,10,ad
	.dc.b 20,0,0,0,40,21,v/8,0,0,0,10,10,ad
	.dc.b 30,0,0,0,40,21,v/9,0,0,0,10,10,ad
	.dc.b 20,0,0,0,40,20,v/10,0,0,0,9,11,ad
	.dc.b 30,0,0,0,40,21,v/11,0,0,0,9,12,ad
	.dc.b 20,0,0,0,40,21,v/12,0,0,0,9,13,ad
	.dc.b 30,0,0,0,40,20,v/13,0,0,0,8,14,ad
	.dc.b 20,0,0,0,40,20,v/15,0,0,0,7,15,ad
	.dc.b 30,0,0,0,40,21,v/17,0,0,0,6,14,ad
	.dc.b 20,0,0,0,40,21,v/20,0,0,0,5,13,ad
	.dc.b 30,0,0,0,40,20,v/22,0,0,0,4,12,ad
	.dc.b 20,0,0,0,40,21,v/25,0,0,0,3,6,ad
	.dc.b 30,0,0,0,40,21,v/30,0,0,0,2,2,ad
	
	.ds.b 130				; Kleine Pause

; die Spektralinformation 'mm.p51' wurde mit SMSSEDIT erzeugt
; Alle 3 Dateien zusammen sind zu gross fuer ein 32KB-EPROM

; * 1.) MM: Ach, was muss man oft von boesen
;         Kindern hoeren oder lesen...
	.ibytes mm.p51	

; * 2.) POMMES: Vom alten Fritz dem Preussenkoenig
;             weiss man zwar viel doch viel zuwenig...
;	.ibytes pommes.p51


; * 2.) ZAHL1_10: Die Zahlen, auch als SMSSEDIT-Dateien...
;	.ibytes zahl1_10.p51

	.ds.b 130				; Kleine Pause
	.dc.b 255				; End-Zeichen
	