Soundsampler im Selbstbau: Sample mir's noch einmal Sam

Eine der interessantesten und vielseitigsten Einsatzmöglichkeiten von Computersystemen ist die Erfassung und Verarbeitung von analogen Meßdaten. Zu diesen zählt man digitale Filter, Speicheroszilloskope sowie die Erfassung von Tönen aller Art (Sound-Sampling genannt). Die gestiegenen Anforderungen bei der Meßgenauigkeit vieler physikalischer Vorgänge sind ohne die Meßerfassung durch einen Rechner nicht zu befriedigen. Aber auch die moderne Unterhaltungselektronik profitiert von solcher Technik. Die schon sehr verbreiteten CD-Player verdanken ihre hohe Qualitätsstufe der Digitaltechnik.

Allen diesen Anwendungsmöglichkeiten liegt das gleiche Prinzip zugrunde: die Umsetzung von elektrischen Spannungen als “Rohmaterial” in digitale Daten mittels mathematischer Berechnungen. Aber kein Rechner kann Analogsignale verarbeiten. Aus diesem Grund wird ein analoges Signal (stetiger Spannungsverlauf) an den Eingang eines Umsetzers, des sogenannten A/D-Wandlers geführt, der dann an seinem Ausgang dem Rechner ein digitales Signal in Form einer Zahlenkombination zur Verfügung stellt.

Bild 1: So sieht ein Analog~Signal aus

Das hier beschriebene “Sound Sampling” ermöglicht es, Sprache oder sogar ganze Musikstücke mit einem ATARI-ST zu digitalisieren, zu bearbeiten und über den Monitorlautsprecher wieder auszugeben. Selbstverständlich darf man von diesem Sound Sampler nicht HiFi-Qualität erwarten, aber um z.B. einen Programm-Vorspann noch mit Musik zu versehen, reicht sie aus.

Für den interessierten Anfänger, der noch nicht weiß, was ein Sound Sampler ist, oder was der Begriff ‘digitalisieren’ bedeutet, sollen diese jetzt erklärt werden. Was ein Sound-Sampler tut, ist schnell gesagt. Er wandelt die Signale, die ein handelsüblicher Kassettenrekorder, ein Radio oder ein ähnliches Gerät über den Kopfhörerausgang, den Lautsprecheranschluß oderein Mikrofon ausgeben (siehe Bild 1), in für den Computer verständliche Signale um. Da aber ein Computer nichts anderes versteht als Zahlen, muß ein solches Signal in Zahlen umgewandelt werden. Diese Aufgabe übernimmt ein sogenannter Analog-Digital-Wandler. Im Prinzip besteht ein Sound-Sampler aus nichts anderem als einem A/D-Um-setzer. Analog nennt man das Signal, das z.B. ein Kassettenrekorder ausgibt; digital das Signal, das vom Computer verstanden werden kann - Zahlen. Digitalisiert man also etwas, so wird ein Signal in ein für den Computer verständliches verwandelt.

Quantisierung & Abtastung

Bild 2: Quantisierung & Abtastung

Um ein Analogsignal (z. B. einen stetigen Spannungsverlauf) in ein digitales umzuwandeln, muß es in bestimmten Abständen abgetastet und dem Spannungswert zur Zeit der Abtastung ein Zahlenwert zugeordnet werden. Diesen Vorgang nennt man Quantisierung. Der zeitliche Abstand zwischen zwei Meßpunkten ( Umwandlungen) wird Abstastfrequenz genannt. Je höher sie ist, umso kürzer sind die immer gleichen Abstände, und desto besser ist die Wiedergabequalität vom Computer. Bild 2 soll dies verdeutlichen. Der schraffierte Teil zeigt die Ungenauigkeit, die bei höherer Abtastfrequenz immer kleiner wird. Die Erfassung eines Analogsignales bzw. seine Verarbeitung in einen digitalen Wert nimmt eine gewisse Zeit in Anspruch. Ändert sich während dieser Zeit das analoge Eingangssignal, so ist mit einem Fehler bei der Umsetzung zu rechnen. Abhilfe würde ein sogenannter “Sample and Hold” am Eingang des A/ D-Wandlers schaffen. Durch diesen Sample and Hold” wird die Eingangsspannung (Probe) für die Dauer der Umwandlung gespeichert, so daß sich das Eingangssignal ändern kann, ohne daß dies einen Einfluß auf die Analog/Digital-Wandlung hat. Ein solcher “Sample and Hold” ist bei dem hier vorgestellten Projekt nicht vorgesehen, da einerseits ein solcher Wandler sehr teuer ist, anderseits für unsere Anwendung ein “normaler” 8-Bit-Wandler vollkommen ausreicht. Ein weiterer wichtiger Faktor für die Qualität einer Digitalisierung ist die Auflösung, mit der das analoge Signal abgetastet (zerlegt) werden kann. Bei unserem 8-Bit-Wandler kann das Eingangssignal in 28 = 256 Schritte (Auflösungsstufen) unterteilt werden.

Beispiel: Ein Signal mit einer Amplitude von 1 Voltss kann mit einem 8-Bit-Wandler in 256 Spannungsstufen unterteilt werden, d.h. man hat eine Auflösung von 1/256 gleich 3,91 mV (Millivolt).

Da nun die meisten Computer von der Hardware her nicht in der Lage sind den Digitalisiervorgang durchzuführen, genügt es nicht, einfach die entsprechende Software einzuladen, sondern man muß sich auch einer entsprechenden Schnittstelle zur Außenwelt bedienen, die diese Arbeit erledigt. Ein solches Interface, einen “Sound Sampler” stellt die hier gezeigte Schaltung dar.

Die Hardware

Das Herz des Samplers ist ein etwa 35,-DM teurer A/D-Wandler mit der Bezeichnung ZN427, der problemlos erhältlich ist und auch ohne eine allzu aufwendige Zusatzschaltung auskommt. Der ZN427 ist ein bekannter, leistungsfähiger und schneller 8-Bit-Wandler, der zudem relativ preisgünstig ist. Die maximale Eingangsspannung beträgt 5 Volt, Hier nun die Beschreibung der Anschluß-Pins des ZN427:

Pin 1 Busy: wird während des Wandlungsvorganges auf Low gesetzt, damit der Rechner die Daten als ungültig erkennen kann.

Pin 2 Output Enable: bei Low gehen die Datenausgänge in den hochohmigen Zustand,

Pin 3 Clock-Eingang: regelt den internen Wandlungsvorgang, wobei pro Wert 9 Taktimpulse benötigt werden (8+1).

Pin 4 WR: Die Wandlung wird gestartet, wenn der Rechner diesen Eingang auf Low zieht.

Pin 5 R.ext.: hier liegt die negative Versorgungsspannung an.

Pin 6 U in: Eingang für die analogen Signale.

Pin 7 REFin: bestimmt als Referenzspannungseingang den Wandlungsbereich.

Pin 8 Refout: Ausgang für Referenzspannung (wird mit REFin verbunden).

Pin 9 GND: Masseeingang.

Pin 10 Vcc: Eingang für Spannungsversorgung von +5 Volt, die aus dem Joystickport abgenommen werden,

Pin 11-18 Ausgänge: Von denen aus die digitalen Daten an den Computer geschickt werden.

Die übrigen Bauteile der Schaltung dienen als Oszillatorstufe und der Erzeugung der negativen Versorgungsspannung. Da deren Zusammensetzung relativ einfach gehalten ist, erübrigt sich eine ausführliche Beschreibung.

Der Aufbau

Die gesamte Schaltung des A/D-Wandlers findet auf einer Platine von etwa 10x5 cm Platz, die nur einseitig beschichtet sein muß. Wer sich das Aufzeichnen des Layouts ersparen möchte, kann auch eine Loehrasterplatine verwenden. Die gedruckte Schaltung sieht jedoch besser aus, ist übersichtlicher und dadurch leichter zu bestücken,

Beim Einlöten der Bauteile dürften eigentlich keine Probleme entstehen, lediglich die beiden ICs sollten gesockelt werden.

Ist die Platine bestückt, verbindet man die Datenausgänge und die Strobe-Leitung sowie die Masse durch ein Flachbandkabel mit den entsprechenden Pins eines 25-poligen D-Sub-Steckers, der am Druckerport des ATARI-ST angeschlossen wird. Da dieser Port keine Versorgungsspannung liefert, greift man diese am Joystickport Pin Nr.7 ab. Hierbei ergibt sich allerdings das Problem der Steckverbindung, da die Serienstecker nicht in den Port passen, und bei Joystickkabeln der Pin 7 nicht belegt ist. Ich habe daher von einem Serienstecker die Blechummantelung abgenommen und die Kunststoffteile wieder zusammengeklebt. An Pin 7 liegen +5V an. Ein Stück Flachbandkabel, das blind an einige Pins angelötet wird, dient der Zugentlastung.

Bild 3 Der A D Wandler ZN427

Zum Schluß muß noch der Stecker für den Analogeingang angelötet werden. Da es hier verschiedene Typen und Größen gibt, muß man sich dabei nach dem individuellen Ausgabegerät (Kassettenrekorder, Stereoanlage) richten. Jedenfalls muß der Stecker in einen der Ausgänge passen. Ist nun das Gerät fertig zusammengebaut, so läßt es sich folgendermaßen testen:

Man schließt Versorgungsspannung und Analogeingang an und mißt mit einem Multimeter die Spannungswerte am Sockel des ZN427, dabei dürfen noch keine ICs eingesteckt sein.

Pin 2: 5V
Pin 5: -3V
Pin 6: 2,5V
Pin 9: 0V
Pin 10: 5V

An Pin 3 sollte das Oszilloskop eine Rechteckschwingung zeigen. Sind die Werte in Ordnung, steckt man die beiden Chips in die Sockel (auf die Kerbung achten) und schließt noch den D-Sub-Stecker am Druckerport an (im ausgeschalteten Zustand des Rechners), lädt die Software und ab geht die Post.

Da der Monitorlautsprecher des ATARI-ST hohe Töne nicht übertragen kann, erweist sich eine Abtastfrequenz von 20kHz als die beste Lösung, zumal damit bei reservierten 680 KByte stolze 35 Sekunden gesampelt werden können.

Bild 4: Der Schaltplan des Sound-Samplers

Die Software

Der Aufwand der bis hierhin getrieben wurde, ermöglicht es noch nicht, eine digitalisierte Stimme aus dem Lautsprecher des SM 124 hören zu können. Dafür benötigt man noch etwas Software, die die gesamten Informationen (Daten) richtig aufbereitet und wiedergibt. Das hier aufgelistete Assembler-Programm ist die minimale Version eines Sound-Samplers, um Geräusche, Stimmen oder auch Musik aufzunehmen bzw. wiedergeben zu können.

Dank des ausführlich dokumentierten Source Codes ist es wohl kaum nötig, die Arbeitsweise des Programms selbst zu erläutern. Auch das Auswahlmenü erklärt sich eigentlich von selbst. Dennoch soll auf dieses genauer eingegangen werden.

Mit F1 wird der Menüpunkt ‘Hören’ aufgerufen. Hier hat man die Möglichkeit, sich das zu sampelnde Stück schon einmal vorher anzuhören, ohne es gleich in den Speicher zu übernehmen. So lassen sich der beste Anfang und das beste Ende für das Stück leichter finden oder der Klang bei verschiedenen Frequenzen testen. Durch einen Druck auf die Space-Taste kehrt man wieder zum Auswahlmenü zurück.

Mit der F2-Taste kann man ein Stück aufnehmen. Zunächst wird das Stück lediglich gespielt, aber noch nicht in den Speicher übernommen. Durch einen Druck auf die Space-Taste beginnt der eigentliche Aufnahmevorgang. Auf diese Weise läßt sich der Anfang des Stückes sehr genau treffen. Dann wird solange aufgenommen, bis entweder der Speicher voll ist oder die Escape-Taste gedrückt wird. Das Stück wird dann im unteren Teil des Bildschirms als Graph dargestellt.

Stückliste IC1: ZN427
IC2: 14584
R1 390Q
R2 22K
R3 33K
R4 82K
R5 100K
Dl 1N4148
CI 100pF
C2, C3: 10pF
1 D-Sub-Stecker (25-polig)
1 Chinchstecker (Kopfhörer)
1 Joystickbuchse (für ST) 1 IC-Sockel 14 1 IC-Sockel 18

Bild 5: Der Layout- und der Bestückungsplan (Maßstab 1:1)

Mit F3 kann ein File von Diskette in den Speicher gelesen werden, um es dann abzuspielen. Es können übrigens auch Files geladen werden, die keine digitalisierte Musik enthalten. Es ist zwar relativ sinnlos, aber bestimmt interessant, wie sich das eine oder andere Programm ‘anhört’.

Durch F4 können die im Speicher befindlichen Daten auf Diskette abgespeichert werden. Sollte auf einer Diskette weniger Platz sein, als für die Daten benötigt werden, wird das File einfach um den entsprechenden Teil gekürzt und dann auf Diskette abgespeichert. Ein paar Bytes werden auf der Diskette immer noch freigelassen.

Durch einen Druck auf F5 kann das Sample abgespielt werden. Es wird so lange wiederholt, bis die Space-Taste gedrückt wird.

Mit F6 kann das Stück rückwärts gespielt werden. Auch hier wird so lange wiederholt, bis die Space Taste gedrückt wird.

Mit F7 läßt sich die Aufnahme- bzw. Hörfrequenz verändern. Diese kann in dem Bereich von 3 bis 22 liegen. Nach dem Programmstart ist sie auf 20 gesetzt. Bei 3 ist die Wiedergabequalität am schlechtesten, bei 22 am besten. Dieser Wert beeinflußt die Menüpunkte ‘Hören’ und ‘Aufnehmen'.

Mit der Funktionstaste F8 läßt sich die Abspielfrequenz verändern. Sie kann in einem Bereich von 3 bis 30 liegen. Dieser Wert beeinflußt die Abspielgeschwindigkeit der Menüpunkte Vorwärts- bzw. Rückwärtsspielen. 30 ist am schnellsten und 3 am langsamsten.

Über F9 läßt sich eine Diskette formatieren. Es gibt die Möglichkeit, entweder eine einseitige oder eine zweiseitige Diskette mit 10 Sektoren zu formatieren.

Mit F10 wird das Programm nach einer Sicherheitsabfrage verlassen.

Da das Programm sehr modular und Übersichtlich aufgebaut ist, dürfte es geübten Programmierern keine größere Schwierigkeiten bereiten, z.B. eine Funktion zur Definition von Blöcken oder andere, eigene Funktionen einzubauen.

; -----------------------------------
; ST Sound Sampler 1.0
; written 1988 by Martin Backschat, Bergstr.16, 8071 Hepberg
; mit IDEAL von OMIKRON ( ' z' zum Assemblieren und 'z,w sample.tos' zum Linken und Sichern)
; -----------------------------------
start:
	move.l 4(sp),a0 ; Basepage-Zeiger von Stack holen 
	move.l $c(a0),d0 ; Länge des benötigten Programmspeicher 
	add.l $14(a0),d0 ; aus Prg.-,Daten- und uninit. Datenteillänge 
	add.l $1c(a0),d0 ; berechnen
	add.l #$100,d0 ; + 256 Bytes Basepage
	move.l d0,-(sp) ; als Argument auf Stack
	pea (a0) ; Basis des Programmes
	pea $004a0000 ; SETBLOCK
	trap #1
	lea 12 (sp),sp
	;
	move.w # 4,-(sp)
	trap #$e ; Auflösung abfragen (0,1 Farbe/2 Mono)
	addq.l #2,sp
	subq.w #1,d0
	bpl.s nolowrez ; wenn niedrige Auflösung in mittlere schalten
	moveq.l #-1,d0
	move.w #1,-(sp)
	move.l d0,-(sp) ; Bildschirmlage unverändert lassen
	move.l d0,-(sp)
	move.w #5,-()sp)
	trap #$e Auflösung umschalten
	lea 12(sp),sp
	moveq.l #0,d0
nolowrez:
	move.w d0,rez ; 0 wenn Farbe 640x200, 1 wenn Mono 640x400
	.dc.w $a000 ; Grafikroutinen initialisieren
	move.l a0,lineavar ; Zeiger auf Grafikvariablen merken 
	move.w #1,24(a0) ; Alle Grafiken in Rot bzw. schwarz bei Mono
	moveq.l #-1,d0
	move.w d0,34(a0) Linienmuster ist durchzogene Linie
	move.w d0,32(a0)
	clr.w 36(a0) ; Schreibmodus a.Ersetzen stellen
	;
	clr.l -(sp)
	move.w #$20,-(sp)
	trap #1 ; i. den Supervisormodus wechseln
	addq.l #6, sp
	move.l d0, oldsp alten Stackzeiger merken 
	moveq.l #-1,d0
	move.l d0,-(sp) 
	move.w #$48,-(sp)
	trap #1 ; Anzahl d.freien Bytes abfragen
	addq.1 # 6, sp
	sub.l #5*1024,d0 ; 5 KB dem System übriglassen 
	move.l d0,freemem ; Anzahl der verfügbaren Bytes merken
	lea memtext(pc),a0 ; u.d.Benutzer i.Text einblenden
	move.l #$ffff,d7 
	move.l d0,d1 
	lsr.l #5,d1
	lsr.l #5,d1 ; /1024 daraus ergeben sich Anzahl KB 
	move.l #1000,d2 ; 4 stellige Zahl ausgeben 
	moveq.l #3,d3 
mainl:
	divu d2,d1
	moveq.l #'0',d4 ; in ASCII-Zeichen umwandeln
	add.b d1,d4
	move.b d4,(a0)+ ; in Text schreiben
	swap d1 ; Divisionsrest als neue Zahl verwenden
	and.l d7,d1 ; obere Langworthälfte löschen (für divu)
	divu #10,d2 ; auch den Divisor anpassen
	dbf d3,mainl ; solange, bis Zahl komplett ausgegeben
	move.l d0,-(sp) 
	move.w #$48,-(sp)
	trap #1 ; Verfügbaren Speicher reserv.
	addq.l #6,sp
	move.l d0,memadr ; Adresse d.Speicherblocks merken
	;
	clr.b $484 ; Tastenwiederholung u.-klick abschalten 
	pea siditab(pc) ; Sounddatentabeile
	move.w #$20,-(sp)
	trap #$e ; Soundchip auf Digitalmusik vorbereiten
	addq.l #6,sp
	;
	lea inittext (pc.) ,a0
	bsr print ; Bildschirm löschen
	;
menuloop:
	lea menutext (pc),a0
	bsr print ; Programmenü ausgeben
	bsr showgraf ; Graphen des Samples anzeigen 
menukey:
	bsr getkey ; Taste holen
	swap d0 ; Funktionstasten nur über Scancodes erreichbar
	moveq.l #$3b, d1
	cmp.w d1,d0 ; Taste zwischen F1 und F10?
	bmi.s menukey 
	;
	sub.w d1,d0 ; ansonsten aus Tastencode Offset formen
	lsl.w #2,d0
	lea cmdtab (pc),a0 ; Tabelle mit den Kommandoadressen 
	move.l 0(a0,d0),a0 ; Adresse d.gewünschten Kommandos holen
	jsr (a0) ; anspringen
	;
	bra. s menuloop ; wenn Kommando ausgeführt, dann wieder ins Menü

; Gibt den Text, auf den A0 zeigt, aus 
print:
	pea (a0)
	move.w #9, -(sp) 
	trap #1 ; PRINT TEXT
	addq.l #6,sp 
	rts

; Holt eine Taste (unteres D0.W ist ASCII, oberes DO ist Scancode) 
getkey:
	move.w #7, -(sp) 
	trap #1 
	addq.l #2,sp 
	rts

; Gibt eine Nachricht (Zeiger in A0) an den Anwender in Zeile 16 aus 
printmsg:
	pea (a0) ; Zeiger merken
	lea msg1text(pc),a0
	bsr print ; erstmal positionieren und Invers an

	move.l (sp)+,a0
	bsr print ; jetzt Nachricht ausgeben
	lea msg2text(pc),a0
	bra print ; und Invers ausschalten

; Löscht die Zeile 16, in der eine Nachricht steht 
clrmsg:
	lea clrmtext(pc),a0 
	bra print

; Berechnet in D0.L die ASCII-Zahleneingabe (die in 'in ptext' abgelegt ist) 
calctext:
	lea inptext(pc),a6 ; Hier steht die Zahleneingabe 
	moveq.l #0,d0 ; Startwert 0
calcloop:
	moveq.l #0,d1
	move.b (a6)+,d1 ; erstes Zeichen holen 
	cmp.w #'0',d1 ; ist Zeichen keine ASCII-Zahl, dann
	bmi.s calcend ; dies als Textende betrachten und 
	cmp.w #'9'+1,d1 ; stoppen
	bpl.s calcend
	sub.b #'0',d1 ; aus ASCII '0-9' die Zahl 0-9 berechnen
	mulu #10,d0 ; Zahl um eine 10erpotenz größer
	add.w d1,d0 ; Zahl zu Gesamtzahl addieren
	bra.s calcloop 
calcend: 
	rts

; holt Eingabe von Benutzer; zuvor Nachricht ausgeben, wobei das erste Byte 
; des Textzeigers die maximale Eingabelänge angibt 
gettext:
	moveq.l #0,d7
	move.l d7,d6
	move.b (a0)+,d7 ; Anzahl der erlaubten Eingaben
	pea (a0) ; Textzeiger merken
	lea get1text(pc),a0
	bsr print ; erstmal positionieren
	move.l (sp)+,a0
	bsr print ; Nachricht ausgeben
	lea inptext (pc),a6 ; ab hier wird Eingabe gespeichert
keyinpl:
	bsr getkey ; Taste holen
	cmp.b #$d,d0 ; wurde RETURN gedrückt?
	beq.s endgett ; ja, dann abbrechen 
	cmp.b #$8,d0 ; wurde BACKSPACE gedrückt?
	beq.s delgett ; ja, dann letztes Zeichen löschen
	cmp.b d6,d7 ; ist erlaubte Textlänge überschritten? 
	beq.s keyinpl ; ja, dann Taste einfach ignorieren
	move.b d0, (a6)+ ; ansonsten speichern
	addq.l #1,d6 ; Zeichenzähler erhöhen
	move.w d0,-(sp) 
	move.w #2,-(sp)
	trap #1 ; u.Zeichen auf Bildschirm ausgeben
	addq.1 #4,sp
	bra.s keyinpl ; nächstes Zeichen einlesen 
delgett: ; Einsprung für BACKSPACE-Taste
	tst.b d6 ; schon alle Zeichen gelöscht?
	beq.s keyinpl ; ja, dann ignorieren 
	subq.l #1,a6 ; ansonsten Zeichen a.Speicher löschen
	subq.l #1,d6 ; Zeichenzähler vermindern
	lea deltext(pc),a0
	bsr print ; u.Zeichen auf Bildschirm löschen
	bra.s keyinpl 
endgett: ; Einsprung für RETURN-Taste
	clr.b (a6) ; Eingabe mit $0-Kode beenden
	lea get2text(pc),a0 ; blink.Cursor ausschalten
	bsr print
	bra clrmsg ; Nachrichtenzeile löschen

	; Gibt Fehlernachricht in A0 aus und wartet auf eine Taste 
error:
	bsr printmsg ; Nachricht in A0 ausgeben
	bsr getkey ; auf Taste warten
	bra clrmsg ; Nachricht wieder löschen

; Liest digitale Daten vom Printerport ein. Hierbei 
; müssen Parameter wie folgt übergeben werden:

; D0.b = Scankode d.Taste, bei deren Druck frühzeitig abgebrochen werden soll 
; D1.w = Frq. in Hz (z.B. 22405 oder 8192); muss im Bereich 3000-22500 liegen 
; D2.b = Flag um zwischen Anhören (D2=0) und Aufnahme (D2=1) zu unterscheiden 
; A1 = Speicheradresse ab der die Daten beim Aufnehmen abgelegt werden sollen 
; A2 = bis zu dieser Adresse dürfen Daten abgelegt werden; wird diese Adresse 
; erreicht, wird abgebrochen

input:
	move.l a1,startadr ; Startadresse für später merken 
	bsr sndinit ; Timer für Frq.syncronisation init.
	;
	move.b #$e, (a5) ; ersten Strobe HIGH senden
	move.b (a5),d7 ; damit wird Digitizer gestartet
	or.b #$20,d7 ; Strobesignal in SID-Register 14 
	move.b d7,2(a5)
	move.b #7, (a5) ; Port B des Soundchips
	move.b (a5),d7 ; auf Eingabe schalten
	and.b #$7f,d7 
	move.b d7,2(a5)
	;
inploop:
	moveq.l #0,d6
	move.b #$f, (a5) ; Daten liegen an SID-Register 15 an 
	move.b (a5),d6 ; Daten auslesen
	;
	move.b #$e, (a5) 
	move.b (a5),d7
	and.b #$df,d7 ; Strobe LOW ausgeben
	move.b d7,2(a5) 
	move.b (a5),d7
	or.b #$20,d7 ; Strobe HIGH ausgeben
	move.b d7,2(a5) ; um Digitizer zu <takten>
	;
	tst.b d2 ; Ausnehmen oder nur anhören?
	beq.s norec
	move.b d6, (a1)+ ; über A1 speichern
	cmp.l a1,a2 ; Endadresse schon erreicht?
	beq.s inpend ; ja, dann abbrechen
norec:
	and.b #%11111100, d6 ; nur Bits 2-7 verwenden 
	move.w d6,d7 ; x3 nehmen um als Offset in
	add.w d6,d7 ; Lautsprechertabelle zu dienen
	add.w d6, d7
	movem.l 0(a3,d7),d5-d7 ; Lautsprecherdaten für alle 3 Kanäle
	movem.l d5-d7,(a5) ; holen und in SID-Register schreiben
	;
	cmp.b 2(a4),d0 ; Abbruchtaste gedrückt?
	beq.s inpend ; ja, dann abbrechen
inpsync:
	btst #4,$d(a6) ; solange warten, bis TIMER D
	beq.s inpsync ; runtergezählt hat (Syncronisation!) 
	bclr #4,$d(a6) ; TIMER D zurücksetzen
	bra inploop ; und nächste Daten einiesen
inpend: ; Einsprung für Abbrechen
	tst.b d2 ; wurde aufgenommen?
	beq. s inpend2
	sub.l startadr,a1 ; ja, dann die Länge des aufgenommenen 
	move.l a1,smpllen ; Bereiches festhalten 
inpend2:
	bra sndinit2 ; TIMER D wieder zurücksetzen

; Spielt digitale Daten im Speicher ab. Parameter werden wie folgt übergeben:
; D0.b = Scankode der Taste, bei deren Druck spielen abgebrochen werden soll 
; D1.w = Frq. in Hz (z.B. 22405 oder 8192); muss im Bereich 3000-30000 liegen 
; D2.b = Flag zur Unterscheidung ob vorwärts (D2=0)
; oder rückwärts (D2=1) gespielt werden soll
; D3. w = Anzahl der Wiederholungen
; A1 = Speicheradresse ab der d.digitalen Daten liegen
; A2 = Endadresse der digitalen Daten

play:
	subq.w #1,d3 ; Anzahl Wiederholungen f.DBF-Schleife 
	move.l a1,startadr ; Start- und Endadresse für 
	move.l a2,endadr ; Wiederholung merken 
	bsr sndinit ; TIMER D für Syncronisation init. 
	moveq.l #0,d4 
playloop:
	tst.b d2 ; vorwärts oder rückwärts spielen?
	bne. s playb
	move.b (a1)+,d4 ; vorwärts, über Startadresse A1
	cmp.l a1,a2 ; Daten lesen; Endadresse erreicht? 
	bne. s playfl ; nein...
	dbf d3,playfla ; wenn ja, Wiederholungszähler 
	bra.s playend ; vermindern und bei -1 abbrechen 
playfla:
	move.l startadr,a1 ; Startadresse A1 wieder zurücksetzen
playfl:
	bra. s playl
playb: ; Einsprung fürs Rückwärtsspielen
	move.b -(a2),d4 ; über Endadresse A2 Daten lesen
	cmp.l a1,a2 ; Startadresse schon erreicht?
	bne. s playl ; nein...ok
	dbf d3,playla ; wenn ja, dann Wiederholungszähler 
	bra.s playend ; vermindern und bei -1 abbrechen 
playla:
	move.l endadr,a2 ; Endadresse A2 wieder zurücksetzen 
playl:
	and.b #%11111100, d4 ; nur Bits 2-7 verwenden 
	move.w d4,d7 ; x3 um als Offset in
	add.w d4,d7 ; Lautsprechertabelle zu dienen
	add.w d4, d7
	movem.l 0(a3,d7),d5-d7 ; Lautsprecherdaten holen und 
	movem.l d5-d7,(a5) ; in Lautsprecher d.SID schreiben
	cmp.b 2(a4),d0 ; Abbruchtaste gedrückt?
	beq.s playend ; ja, dann abbrechen
playsync:
	btst #4,$d(a6) ; warten, bis TIMERD runtergezählt 
	beq.s playsync ; hat (Syncronisation!)
	bclr #4,$d(a6) ; TIMER D zurücksetzen
	bra playloop ; und weitermachen
playend: ; Einsprung fürs Abbrechen
	bra sndinit2 ; TIMER D zurücksetzen

; Initialisiert TIMER D und bereitet System auf Abspielen/Aufnehmen vor 
sndinit:
	move.w #$2700, sr ; ab jetzt kein IRQ mehr! 
	lea voldat(pc),a3 ; Lautsprechertabellenbasis in A3
	move.w #$fc00,a4 ; Tastatur-ACIA-Basis in A4
	move.w #$8800,a5 ; SID-Basis in A5 
	move.w #$fa00,a6 ; MFP-Basis in A6
	;
	move.l #2457600,d7 ; aus Hz-Zahl in D1.w Timerdaten
	divu d1,d7 ; berechnen mit Formel
	lsr.w #2,d7 ; TI-DATA x 4 = TAKT / HZ
	move.b d7,$25(a6) ; Timerstartwert
	move.b $ld(a6),d7 ; Vorteiler des TIMERs D
	and.b #$f0,d7 ; ist 4
	or.b #$01,d7 
	move.b d7,$ld(a6)
	bset #4,9(a6) ; TIMER D muss IRQ signalisieren
	rts ; können

; TIMER D zurücksetzen und System wieder normalisieren 
sndinit2:
move.b $1d(a6),d7
and.b #$f0,d7 ; TIMER D stoppen
move.b d7,$1d(a6) 
bclr #4,9(a6)
move.w #$2300,sr ; IRQs wieder erlauben 
rts

; Beendet nach Nachfrage das Programm 
quit:
	lea quittext(pc),a0
	bsr printmsg ; Nachfragetext ausgeben
quitkey:
	bsr getkey ; Taste holen
	cmp.b #'j',d0 ; wenn j für JA gedrückt, dann
	beq.s surequit ; abbrechen
	cmp.b #'J',d0 ; wenn J für JA gedrückt, dann
	beq.s surequit ; abbrechen, ansonsten wieder ins 
	bra clrmsg ; Menü zurückkehren
surequit:
	addq.l #4,sp ; Rücksprungadr d.JSR vom SP entfernen
	move.b #7,$484 ; Tastenwiederholung u.Klick einsch.
	move.l oldsp,-(sp) 
	move.w #$20,-(sp)
	trap #1 ; wieder in den USER-Modus zurück
	addq.1 #6, sp
	move.l memadr,-(sp) ; Basis d.reservierten Speichers 
	move.w #$49,-(sp)
	trap #1 ; belegten Speicher wieder freigeben
	addq.l #6,sp 
	clr.w -(sp)
	trap #1 ; Programm beenden

; Digital Sound vom Druckerport anhören 
listen:
	lea heartext(pc),a0
listenl:
	bsr printmsg ; Nachricht ausgeben
	moveq.l #$39,d0 ; Abbruchtaste ist SPACE 
	move.w recfrq,d1 ; z.Anhören Aufnahmefrq. verwenden 
	moveq.l #0,d2 ; Flag auf Anhören setzen
	bsr input ; Anhören
	bra clrmsg ; Nachricht löschen u.i.Menü zurück

; Digital Sound vom Druckerport aufnehmen 
record:
	lea recltext(pc),a0
	bsr listenl ; erstmal Anhören und bei SPACE
	lea rec2text(pc),a0 ; Aufnahme starten
	bsr printmsg
	moveq.l #$01,d0 ; bei Aufnahme ist ESC die Abbruchtaste
	move.w recfrq,d1 ; Aufnahmefrq.
	moveq.l #1,d2 ; Flag für Aufnehmen
	move.l memadr,a1 ; Startadresse, ab der aufgenommen wird
	move.l a1,a2
	add.l freemem,a2 ; Endadresse d.Speicherblocks
	bsr input ; Aufnehmen
	bra clrmsg ; Nachricht löschen und ins Menü

; Abspielfrq. neu setzen (Eingabe des Anwenders in KHz) 
setplay:
	lea setptext(pc),a0 ; Eingabetext
	move.l #playfrq,frqptr ; Zeiger a d.Abspielfrq ( . w) 
	moveq.l #30,d0 ; maximale Frq. ist 30 KHz
	bra.s setlabl
setrec:
	lea setrtext(pc),a0 ; Eingabetext
	move 1 #recfrq,frqptr ; Zeiger a d.Anfnamhefrq.(.w) 
	moveq.l #22,d0 ; maximale Frq. ist 22 KHz
setlabl:
	move w d0, -(sp) max . Frq. merken
	bsr gettext ; erstmal Benutzereingabe holen
	bsr calctext ; Eingabe i.Zahl in D0.W umwandeln
	move.w (sp)+,d1 max. Frq. zurückholen
	cmp w #3,d0 ; min.Frq. 3 KHz unterschritten
	blt. s seterr ; oder maximale Frq. 22/30 KHz
	cmp.w d1,d0 ; überschritten, dann
	bhi.s seterr ; Fehlermeldung ausgeben 
	mulu #1000,d0 ; aus KHz Hz machen (x1000) 
	move.l frqptr,a0 ; Zeiger auf Frequenz (.w) 
	move.w d0,(a0) ; Hz-Zahl speichern 
	rts ; und zurück ins Menü
seterr:
	lea setetext(pc),a0 ; Fehlermeldung ausgeben 
	bra error

; digitalen Sound im Speicher rückwärtsspielen 
playback:
	moveq.l #1,d2 ; Flag für rückwärts
	bra.s playsnd ; digitalen Sound im Speicher abspielen 
playforw:
	moveq.l #0,d2 ; Flag für vorwärts
playsnd:
	move.w d2,-(sp) ; Flag merken
	lea playtext(pc),a0 ; Nachricht ausgeben
	bsr printmsg
	moveq.l #$39,d0 ; Abbruchtaste ist SPACE 
	move.w playfrq,d1 ; Abspielfrquenz holen 
	move.w (sp)+,d2 ; Flag vor/rückwärts
	moveq.l #-1,d3 ; Anzahl d.Wiederhol, unendlich
	move.l memadr,a1 ; Startadresse des Sounds 
	move.l a1,a2
	add.l smpllen,a2 ; Endadresse des Sound-Speicherblocks 
	bsr play ; und abspielen
	bra clrmsg ; Nachricht löschen u.i.Menü zurück

; setzt das Laufwerk, wenn bei Filenameneingabe Laufwerksangabe vorkommt (A:...)
setdrv:
	cmp.b #':',inptext+1 ; kommt Laufwerksangabe vor? 
	bne.s setdrve ; nein, dann zurück
	moveq.l #0,d0
	move.b inptext,d0 ; Laufwerksnummer (A,B,C...) holen 
	and.b #%ll,d0 ; für Funktions in Nummern (0,1,2)
	subq.w #1,d0 ; umformen
	move.w d0,-(sp)
	move.w #$e,-(sp)
	trap #1 ; SET DRIVE
	addq.l #4,sp
setdrve: 
	rts

; Lädt eine Sample-Datei von Disk 
load:
	lea loadtext(pc) ,a0
	bsr gettext ; Dateinamen holen
	bsr setdrv ; ggf. Laufwerk setzen
	clr.w -(sp)
	pea inptext(pc)
	move.w #$3d, -(sp)
	trap #1 ; Datei öffnen
	addq.l #8,sp
	tst.l d0 ; Fehler beim Öffnen?
	bmi.s loaderr ; ja, dann Datei nicht gefunden..
	move.w d0,-(sp)
	move.l memadr, -(sp) ; Startadresse 
	move.l freemem,-(sp) ; Länge des Speicherblocks 
	move.w d0,-(sp)
	move.w #$3f,-(sp)
	trap #1 ; Datei einiesen
	lea 12(sp),sp
	move.l d0,smpllen ; Anzahl der eingelesene Bytes 
	move w #$3e,(sp) ; a1s Sample-Länge übernehmen 
	trap #1 ; Datei wieder schliessen
	addq.l #4,sp 
	rts 
loaderr:
	lea loadetxt(pc) ,a0 ; <File not found>-Fehlermeldung 
	bra error ; ausgeben

	; Speichert aktuelles Sample auf Disk 
save:
	lea savetext(pc),a0
	bsr gettext ; Dateiname holen
	bsr setdrv ; ggf. Laufwerk setzen
	clr.w -(sp)
	pea diskinfo(pc)
	move.w #$36,-(sp)
	trap #1 ; GET DISKINFO
	addq.l #8,sp
	move.l smpllen,d7 ; Länge des Samples 
	move.l diskinfo,d0 ; freie Clusters auf Disk 
	subq.l #2,d0
	mulu #1024,d0 ; -> freie Bytes auf Disk
	cmp.l d7,d0 ; zu wenig freie Bytes auf Disk?
	bmi.s saveerr ; ja, dann Sample einfach kürzen
saveerrl:
	clr.w -(sp) pea inptext(pc) 
	move.w #$3c,-(sp)
	trap #1 ; Datei auf Disk eröffnen
	addq.l #8,sp 
	move.w d0,-(sp)
	move.l memadr,-(sp) ; Startadresse des Samples
	move.l d7,-(sp) ; (angepasste) Länge des Samples
	move.w d0,-(sp) 
	move.w #$40,-(sp)
	trap #1 ; Sample auf Diskette speichern
	lea 12(sp),sp
	move.w #$3e,-(sp)
	trap #1 ; Datei schliessen
	addq.l #4,sp
	bra clrmsg ; und zurück ins Menü
saveerr: ; Einsprung, wenn Diskkapazität zu gering
	exg d0,d7 ; Samplelänge einfach anpassen
	lea saveetxt(pc),a0 ; Benutzermitteilung ü.Anpassung 
	bsr printmsg ; geben
	bra saveerrl ; und speichern...

; formatiert eine Diskette 1- oder 2-seitig mit 80 Tracks/10 Sektoren 
format:
	lea formtext(pc),a0
	bsr gettext ; Anzahl d.Seiten vom Benutzer holen bsr calctext ; in Zahl umwandeln (1 oder 2)
	move.l d0, d7
	subq.l #1,d7 ; 1/2 in 0/1 formen
	bmi formend ; bei unzulässiger Eingabe abbrechen 
	cmp.w #2,d7 
	bpl formend
	;
	lea formtpuf(pc),a6 ; Datenpuffer fürs Formatieren
	moveq.l #79,d6 ; beginnen mit Track 80
nexttr: ; Label für Trackzähler
	move.w d7, d5 
nextside: ; Label für Seitenzähler 
	clr.w -(sp) 
	move.l #$87654321,-(sp) 
	move.w #1,—(sp)
	move.w d5,-(sp)
	move.w d6,-(sp)
	move.w #10,-(sp)
	clr.w -(sp)
	clr.l -(sp)
	pea (a6) 
	move.w #10,-(sp)
	trap #$e ; Track D6/Seite D5 formatieren
	lea 26(sp),sp
	dbf d5,nextside ; Seitenzähler
	dbf d6,nexttr ; Trackzähler
	;
	bsr clrpuf ; Puffer löschen
	clr.w -(sp)
	moveq.l #2,d0 
	add.w d7,d0
	move.w d0,-(sp)
	move.l #$fffffff,-(sp) 
	pea (a6) 
	move w #18,-(sp)
	trap #$e ; Bootsektor initialisieren
	lea 14 (sp),sp
	;
	move.w #800,d0 ; Anzahl Sektoren auf Disk 
	addq 1 #1,d7
	mulu d7,d0 ; wenn 2-seitig, dann x2-> 1600 Skt.
	move.b d0,$13(a6) ; Anzahlen Sektoren im 8086 Format 
	lsr.w #8,d0 ; abspeichern (LOW-HIGH)
	move.b d0,$14(a6)
	move.b #10,$18(a6)	; Anzahl Sektoren/Track 
	moveq.l #1,d0 ; Puffer n.Sektor 1/Track Osichern
	bsr writesec
	bsr clrpuf			; Puffer löschen
	move.l #$f7ffff00, (a6) ; FAT initialisieren 
	moveq.l #7,d0		; Puffer nach Sektor 7 und 2
	bsr writesec
	moveq.l #2,d0 
	bra writesec
formend: 
	rts

; schreibt Sektor D0 auf Disk (Track 0/Seite 1) 
writesec:
	move.w #1,-(sp) ; nur einen Sektor schreiben
	clr.w -(sp)
	clr.w -(sp)
	move.w d0,-(sp) ; Sektornummer
	clr.w -(sp)
	clr.l -(sp)
	pea (a6)
	move.w # 9, -(sp)
	trap #$e		; Sektor schreiben
	lea 20(sp),sp
	rts
; Puffer für Track- und Sektorendaten löschen 
clrpuf:
	move.l a6,a0
	move.w #512/4,d0
clrpuf1:
	clr.l (a0)+ ; 512 Bytes löschen
	dbf d0, clrpuf1
	rts

; Zeigt den Grafen des Samples im Speicher an. Dieser wird in den Bildschirmzeilen 18-25 dargestellt.
; Die Pixelzeilen sind auflösungsabhängig, 
showgraf:
	lea clrgrtxt(pc),a0
	bsr print 			; Zeilen 18-25 löschen
	move.l lineavar,a6	; Basis der Grafikvariablen 
	lea 38(a6),a6		; Basis der XI,Y1/X2,Y2-Koordinaten 
	move.l memadr,a5	; Startadresse in A5
	move.l #640,d3		; Breite einer Pixelzeile
	move.l smpllen,d7	; Länge des Samples
	cmp.l d3,d7			; wenn Sample kürzer als 64 0 Bytes
	blt showend			; dann abbrechen
	divu d3,d7			; ansonsten Offset berechnen aus
	moveq.l #0,d6		; Formel OFFS = LEN/640
	move.w d6, (a6)		; Startkoordinaten X1 = 0
	move.w #18*16+56,d0 ; Y1 = Mittl.Zeile des Bereichs 
	tst.w rez			; Zeile 18-25
	bne.s highl			; da auflösungsabhängig, b.mittlerer 
	lsr.w #1,d0			; Auflösung Pixelzeile einfach
highl:					; halbieren
	move.w d0,2(a6)		; Y1 speichern
drgraf: 				; Einsprung für Spaltenzähler
	moveq.l #0,d5
	move.b (a5),d5		; Samplebyte auslesen
	lea 0(a5,d7),a5		; m.Offset z.nächsten Samplebyte
	lsr.b #2,d5			; nur Bit 2-7 verwenden
	move.b d5,d4		; Samplebyte liegt im Wertbereich 0-63
	lsr.b #2,d4			; wir haben aber 112 Pixelzeilen zur
	add.b d4,d5			; Verfügung, darum x1.75 nehmen 
	add.b d4,d5			; (1 + 1/4 + 1/4 + 1/4)
	add.b d4,d5
	add.w #18*16,d5		; Absolute Pixelzeile berechnen 
	tst.w rez
	bne.s highrez		; wenn mittlere Auflösung, dann
	lsr.w #1,d5			; einfach Höhe halbieren
highrez:
	move.w d6,4(a6)		; X2-Koordinate
	move w d5,6(a6)		; gerade berechnete Y2-Koordinate
	dc.w $a003 			; DRAW LINE
	move.w d6,(a6)		; End- werden Startkoordinaten 
	move.w d5.2(a6)
	addq.1 #1,d6		; X Koordinate erhöhen
	cmp.w d3,d6			; schon Endspalte 640 erreicht?
	blt drgraf			; nein, dann weitermachen
showend: 
	rts

; ----------------
; Datenteil
; ----------------

.data 
inittext:
	.dc.b $1b,"E",$1b,"f", 0 
menutext:
	.dc.b $1b,"Y",32+16,32+0,$1b,"d",$1b,"H"
	.dc.b " ",$1b,"p"," ST Sound Sampler - "
memtext: .dc.b "0000 KB frei ", $1b,"q",13,10,13,10 
	.dc.b " Software by M.Backschat -Hardware by F.Weiss",13,10 
	.dc.b 13,10,13,10
	.dc.b " F1.....Hören", 13, 10
	.dc.b " F2.....Aufnehmen", 13,10
	.dc.b " F3.....Sample laden", 13,10
	.dc.b " F4.....Sample sichern", 13, 10
	.dc.b " F5.....Vorwärts spielen",13,10
	.dc.b " F6.....Rückwärts spielen", 13, 10
	.dc.b " F7.....Aufnahme/Hörfrq. einstellen",13,10
	.dc.b " F8.....Abspielfrq. einstellen",13, 10
	.dc.b " F9.....Disk formatieren", 13,10
	.dc.b " F10....Ende!", 13,10,0

clrgrtxt:
	.dc.b $1b,"Y",32+18,32+0,$1b,"J",0 
get1text:
	.dc.b $1b,"Y",32+16,32+0,$1b,"e",0 
get2text:
	.dc.b $1b,"f", 0 
msg1text:
	.dc.b $1b,"Y",32+16,32+0, $1b, "p",0 
msg2text:
	.dc.b $1b,"q" ,0 
clrmtext:
	.dc.b $1b,"Y",32+16,32+0,$1b,"1",0 
deltext:
	.dc.b $1b,"D"," $1b,"D",0 
quittext:
	.dc.b " Programm verlassen (j/n)? ",0
heartext:
	.dc.b " SPACE zum Abbrechen ", 0 
recltext:
	.dc.b " SPACE zum Aufnahmestart ",0 
rec2text:
	.dc.b " ESC zum frühzeitigen Abbruch ",0 
setrtext:
	.dc.b 2
	.dc.b " Neue Aufnahme/Hörfrq. in KHz (3-22): ",0 
setptext:
	.dc.b 2
	.dc.b " Neue Abspielfrq. in KHz (3-30) : ",0 
setetext:
	.dc.b " Frq. war nicht im 3-22/30 KHz-Bereich! ",0 
playtext:
	.dc.b " SPACE zum Abbrechen (ansonsten Wiederholung)", 0
savetext:
	.dc.b 40
	.dc.b " Sample sichern unter: ",0 
saveetxt:
	.dc.b " Zu geringe Diskkapazität - Sample wird gekürzt! ", 0
loadtext:
	.dc.b 40
	.dc.b " Lade Sample mit Namen: ",0 
loadetxt:
	.dc.b " Kann Sample nicht finden' ",0 
formtext:
	.dc.b 1
	.dc.b " Anzahl Seiten (1,2,RETURN ist Abbruch): ",0 
	.even

; Kommandoadressen, die über F1-F10 aufrufbar sind 
cmdtab:
	.dc.l listen, record, load,save,playforw 
	.dc.1 playback, setrec, setplay,format,quit

; Lautsprecherdatentabelle 
voldat_

.dc.l $08000000,$09000000,$0a000000
.dc.l $08000000,$09000000,$0a000200
.dc.1 $08000000,$09000000,$0a000300
.dc.l $08000200,$09000200,$0a000200
.dc.l $08000500,$09000000,$0a000000
.dc.l $08000500,$09000200,$0a000000
.dc.l $08000600,$09000100,$0a000000
.dc.l $08000600,$09000200,$0a000100
.dc.l $08000700,$09000100,$0a000000
.dc.l $08000700,$09000200,$0a000000
.dc.l $08000700,$09000300,$0a000100
.dc.l $08000800,$09000000,$0a000000
.dc.l $08000800,$09000200,$0a000000
.dc.l $08000800,$09000300,$0a000100
.dc.l $08000800,$09000400,$0a000100
.dc.l $08000900,$09000000,$0a000000
.dc.l $08000900,$09000200,$0a000000
.dc.l $08000900,$09000300,$0a000100
.dc.l $08000900,$09000400,$0a000100
.dc.l $08000900,$09000500,$0a000000
.dc.l $08000900,$09000500,$0a000200
.dc.l $08000900,$09000600,$0a000000
.dc.l $08000900,$09000600,$0a000200
.dc.l $08000a00,$09000200,$0a000000
.dc.l $08000a00,$09000200,$0a000200
.dc.l $08000a00,$09000400,$0a000100
.dc.l $08000a00,$09000500,$0a000000
.dc.l $08000a00,$09000500,$0a000200
.dc.l $08000a00,$09000600,$0a000100
.dc.l $08000a00,$09000600,$0a000300
.dc.l $08000b00,$09000100,$0a000000
.dc.l $08000b00,$09000200,$0a000100
.dc.l $08000b00,$09000300,$0a000100
.dc.l $08000b00,$09000400,$0a000100
.dc.l $08000b00,$09000500,$0a000100
.dc.l $08000b00,$09000600,$0a000000
.dc.l $08000b00,$09000600,$0a000200
.dc.l $08000b00,$09000700,$0a000000
.dc.l $08000b00,$09000700,$0a000100
.dc.l $08000b00,$09000700,$0a000300
.dc.l $08000b00,$09000700,$0a000400
.dc.l $08000b00,$09000800,$0a000100
.dc.l $08000b00,$09000800,$0a000300
.dc.l $08000b00,$09000800,$0a000400
.dc.l $08000b00,$09000800,$0a000500
.dc.l $08000b00,$09000800,$0a000500
.dc.l $08000c00,$09000200,$0a000000
.dc.l $08000c00,$09000200,$0a000200
.dc.l $08000c00,$09000400,$0a000100
.dc.l $08000c00,$09000500,$0a000000
.dc.l $08000c00,$09000500,$0a000300
.dc.l $08000c00,$09000600,$0a000000
.dc.l $08000c00,$09000600,$0a000200
.dc.l $08000c00,$09000700,$0a000000
.dc.l $08000c00,$09000700,$0a000300
.dc.l $08000c00,$09000700,$0a000400
.dc.l $08000c00,$09000800,$0a000000
.dc.l $08000c00,$09000800,$0a000300
.dc.l $08000c00,$09000800,$0a000400
.dc.l $08000c00,$09000800,$0a000500
.dc.l $08000c00,$09000900,$0a000000
.dc.l $08000c00,$09000900,$0a000300
.dc.l $08000c00,$09000900,$0a000400
.dc.l $08000c00,$09000900,$0a000500

aiditab:

.dc.b 0,$ff,1,$ff,2,$ff,3,$ff,4,$ff,5,$ff,6,0,7,$3f 
.dc.b 8,0,9,0,10,0,$ff,0

recfrq:
	.dc.w 20000 
playfrq:
	.dc.w 20000 
smpllen:
	.dc.l 1

;----------------------
; Datanteil uninitialisiert

.bss
rez:
	.ds.w 1 
linaavar:
	.ds.l 1
oldsp:
	.ds.l 1
inptext:
	.ds.b 80
frqptr:
	.ds.l 1
memadr:
	.ds.l 1
freemem:
	.ds.l 1
startadr:
	.ds.l 1
endadr:
	.ds.l 1
diskinfo:
	.ds.l 4
formtpuf:
	.ds.b 9*1024

Das Assemblerlisting des Sound-Samplers


Martin Backschat
Aus: ST-Computer 08 / 1988, Seite 22

Links

Copyright-Bestimmungen: siehe Über diese Seite