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

Links

Copyright-Bestimmungen: siehe Über diese Seite