Dem Klang auf der Spur, Teil 4
Der SID ist einer der vielseitigsten Sound-Chips auf dem Markt. Dennoch kann man mit ein paar Tricks Klänge mit mehr Volumen, Weichheit und Komplexität erzeugen. Der hier vorgestellte Modulator ist der Kern eines in den nächsten Folgen zu entwickelnden, interruptgesteuerten Synthesizer- und Sequenzerprogramms mit professionellen Ansprüchen.
Die Beschreibung der Register des Synthesizer-Chips SID 6581 wird hier abgeschlossen. Es wird das Programm »Modulator« vorgestellt, das die Fähigkeiten des SID stark erweitern wird. »Modulator« ist interruptgetrieben und läuft daher parallel zu anderen Programmen.
Fiitersteuerung
Das Filter des SID wurde in seiner Funktion in Teil 3 schon beschrieben. Gesteuert werden diese Funktionen über den Inhalt der vier Register 21-24. (Wir beziehen uns hier auf Tabelle 1 aus dem 64'er, Ausgabe 2/85, Seite 153.) Die Grenzfrequenz (auch Eck- oder Mittenfrequenz, je nach Filtermodus) wird über eine ll-Bit-Größe in den Registern 21 und 22 beeinflußt. Die Grenzfrequenz läßt sich im Bereich 30 Hz bis 12 kHz einstellen. Etwas ungewohnt ist die Verteilung der 11 Bits auf die beiden Register: 3 niederwertige und 8 höherwertige. Da man die Filterfrequenz bei weitem nicht so fein steuern muß wie die Oszillatorfrequenz, kann man sich hier auf Register 22 beschränken. Man wird dann Register 21 zum Beispiel fest mit 0 besetzen.
Filterresonanz (Register 23 Bit 4-7)
Die Filterresonanz kann über 4 Bits in 16 Stufen eingestellt werden. Man muß dabei aber die vier im selben Register angesiedelten Bits FILTEX, FILTER 3, 2 und 1 im Auge behalten, damit man sie nicht versehentlich mit nicht beabsichtigten Werten belegt.
Die Schalter FILTER 1, 2, 3 und FILTEX
Ist das Bit im FILTER 1 auf 0 gesetzt, wird das Signal von Stimme 1 am Filter vorbei direkt zum DCA geleitet, wo es ungefiltert zum gesamten Ausgangssignal zugemischt wird. Hat FILTER 1 den Wert 1, so gelangt Stimme 1 gefiltert zum Ausgang. Das gleiche gilt bei FILTER 2 und 3 entsprechend für Stimme 2 und 3. FILTEX bestimmt, ob ein externes Eingangssignal gefiltert oder ungefiltert zum Ausgang gemischt wird. Dieses externe Signal kann über Pin 26 an den SID gelegt werden. Dieser Eingang ist beim C 64 über einen 10-µF-Kondensator an Pin 5 (Audio in) der Audio/Video-Buchse herausgeführt. Nach SID-Spezifikationen sollte das Signal einen Gleichspannungsanteil von 6 V haben und eine Wechselspannungsamplitude von 3 V nicht überschreiten. Ein solches Signal könnte zum Beispiel von einem weiteren SID aus einem zweiten C 64 stammen.
AUS (Register 24 Bit 7)
Wird dieses Bit auf 1 und gleichzeitig FILTER 3 auf 0 gesetzt, erscheint Stimme 3 nicht am Ausgang. Stimme 3 kann dann zum Beispiel Stimme 1 synchronisieren oder ringmodulieren, ohne selbst hörbar zu sein.
Hochpaß (Bit 6), Bandpaß (Bit 5) und Tiefpaß (Bit 4)
Ist eines dieser Bits gesetzt, verhält sich das Filter als Hoch-Band- oder Tiefpaß. Die Funktionen sind additiv, das heißt, daß man auch mit mehreren gleichzeitig gesetzten Bits ein sinnvolles Filter erhält. So ergeben zum Beispiel Hoch- und Tiefpaß zusammen eine Bandsperre, ein Filter, das alles bis auf einen schmalen Frequenzbereich durchläßt. Die Bandsperre (englisch Notch) ist sozusagen das Gegenstück zum Bandpaß. Es muß mindestens eines dieser Bits gesetzt sein, damit das Filter überhaupt wirksam wird.
Lautstärke (Register 24, Bit 0-3)
Über diese Bits wird die Gesamtlautstärke des SID in 16 Stufen von stumm = 0 bis maximal = 15 eingestellt. Meistens wird man 15 wählen, weil dann der Störabstand des SID-Signals am besten ist.
Die Leseregister
Potentiometer X und Y (Register 25 und 26)
An Pin 24 (entsprechend X) und Pin 23 (entsprechend Y) des SID könne RC-Glieder angeschlossen werden. Dabei sind die beiden Pins jeweils mit einem Kondensator mit Masse und mit einem Potentiometer mit +5 V zu verbinden. Im SID werden durch Messungen der RC-Zeitkonstanten (das sind die Zeiten, in denen die Kondensatoren über die Potentiometer auf eine bestimmte Spannung aufgeladen werden) 8-Bit-Digitalwerte abgeleitet, die den Stellungen der Potentiometer entsprechen. Diese 8-Bit-Werte sind über die Register 25 und 26 von der CPU lesbar. Die Messungen werden alle 512 Systemtaktzyklen wiederholt. Bei einer Taktfrequenz von 1 MHz sind das knapp 2 000 Messungen pro Sekunde. Die SID-Potentiometer-Anschlüsse sind an den Joystickports gemultiplext herausgeführt. Es können dort bis zu vier Potentiometer angeschlossen werden, zum Beispiel in Form zweier Steuerknüppel, wie man sie von Funkfernsteuerungen her kennt. Damit wäre eine viel feinfühligere Steuerung möglich als mit Joysticks, doch das soll nicht Gegenstand dieser Reihe sein.
Oszillator 3 (Register 27)
Über dieses Register kann zu jedem Zeitpunkt der Digitalwert der zu Stimme 3 gehörenden Kurvenform gelesen werden. Man kann diese Werte zur Modulation anderer Parameter verwenden, wie in Teil 3 schon erwähnt wurde. Weil dadurch aber Stimme 3 meistens nicht mehr direkt brauchbar ist (man würde sie durch AUS = 1 unhörbar machen), werden wir hier einen anderen Weg gehen. Zu Modulationen brauchbare Kurven kann man auch rein softwaremäßig errechnen. Das Verfahren ist zwar aufwendiger, aber auch viel leistungsfähiger.
Hüllkurve 3 (Register 28)
Auch der aktuelle Wert des zu Stimme 3 gehörenden Hüllkurvengenerators ist über dieses Register abgreifbar und kann so zu Modulationszwecken genutzt werden. Auch diese Funktion werden wir softwaremäßig nachbilden, damit uns Stimme 3 samt Hüllkurve weiterhin voll zur Verfügung steht.
Das Modulator-Konzept
Die Lebendigkeit von Naturklängen resultiert aus ihrer Unregelmäßigkeit. Keine zwei Perioden gleichen sich wie ein Ei dem anderen. Naturklänge weisen immer Schwankungen in der Lautstärke und in der Tonhöhe auf. Es soll zwar nicht unser Ziel sein, mit dem C 64 Naturklänge nachzumachen (dazu ist der SID-Chip bei weitem nicht in der Lage), man kann aber durch Modulation von SID-Parametern Klänge mit mehr Komplexität, Weichheit und Volumen erzeugen. Zur Modulation geeignete Parameter sind Frequenz, Lautstärke, Filterfrequenz und die Pulsweite bei Rechteckklängen. Da die Pulsweite die spektrale Zusammensetzung eines Rechteckklanges beeinflußt, moduliert man durch die Pulsweite eigentlich die Klangfarbe. Modulation von Frequenz (Vibrato) und Lautstärke (Tremolo) sind auch bei natürlichen Instrumenten zu beobachten. Die Modulation der Filterfrequenz ist dagegen ein typischer Synthesizereffekt. Bild 1 zeigt das Funktionsschema des erweiterten SID-Chips in unserem Konzept. Der rechte untere Teil stellt vereinfacht den SID dar, wie er in der letzten Folge auf Bild 1 schon beschrieben wurde. Nur dieser Teil des Schemas ist in der Hardware realisiert, die anderen Funktionsblöcke werden durch Software verwirklicht. Zuerst sollen die Blöcke funktionell beschrieben werden. Anschließend wird etwas über ihre Ansteuerung gesagt. Im nächsten Teil wird die softwaremäßige Realisierung besprochen. Neben Kenntnissen zur Verwirklichung weiterer Effekte werden dabei auch allgemein nützliche Informationen für Assembler-Programmierer anfallen.

Modulationsquellen und -Ziele
Als Quellen von Modulationssignalen stehen ein Hüllkurvengenerator und 7 LFOs (Low Frequency Oscillator) zur Verfügung. Der Hüllkurvengenerator, im folgenden EG (Envelope Generator) genannt, erzeugt eine Hüllkurve nach dem ADSR-Schema. Der Hüllkurvenverlauf kann zu jeder Zeit angehalten, zurückgesetzt oder sogar gespiegelt werden. Die 7 LFOs sind identisch aufgebaut. Sie können vier Kurvenformen erzeugen:
Dreieck TRIAN, aufsteigender Sägezahn SAWUP, abfallender Sägezahn SAWDOWN, Rechteck mit einstellbarer Pulsweite SQUARE
Auch bei den LFOs können die Kurvenverläufe jederzeit angehalten und zurückgesetzt werden. Des weiteren sind die Amplituden der Modulationssignale einstellbar. Über diese Amplitude wird die Stärke oder Tiefe, wie man auch sagt, der Modulation gesteuert.
Als Modulationsziele kommen vier Parameter in Frage:
- Frequenzen der drei Stimmen
- Pulsweiten der drei Stimmen
- Filtergrenzfrequenz
- Ausgangslautstärke.
Jede Modulationsquelle kann auf jedes Modulationsziel geschaltet werden. Dazu dient ein sogenannter Kreuzschienenverteiler. Man kann sich diesen als eine Anordnung von acht waagrechten (Zeilen) und acht senkrechten Drähten (Spalten) vorstellen. Dabei sind die Spalten mit den Modulationsquellen und die Zeilen mit den Modulationszielen verbunden. An den 64 Kreuzungspunkten befinden sich Buchsen, an denen man über Kurzschlußstecker beliebige Verbindungen von Modulationsquellen zu Modulationszielen herstellen kann. Dabei werden entlang einer Zeile die Signale von Modulationsquellen gemischt, wo an entsprechender Stelle ein Stecker sitzt.
Im Bild wird zum Beispiel die Frequenz von Stimme 1 durch LFO 0, LFO 3 und LFO 5 gleichzeitig moduliert. Die Filterfrequenz wird nur vom EG moduliert. Durch das Kreuzschienen-Konzept können Modulationsquellen auch mehrfach genutzt werden. So trägt im Bild zum Beispiel LFO 5 zur Modulation der Frequenz von Stimme 1 bei, moduliert die Pulsweite von Stimme 2 und dazu noch die Ausgangslautstärke.
Portamento
Bei fast jedem Synthesizer kann man die gespielten Tonhöhen »schleifen« lassen. Das heißt, daß bei zwei aufeinanderfolgenden, verschiedenen Tönen die Frequenz nicht unmittelbar wechselt, sondern in einstellbarer Zeit von der alten zur neuen Tonhöhe kontinuierlich gleitet. Der Portamento-Block verwirklicht dies für alle drei Stimmen. Dabei sind die Portamento-Raten der Stimmen unabhängig voneinander einstellbar.
Arbeitsweise von »Modulator«
»Modulator« (Listing 1) für sich allein ist noch kein abgeschlossenes Programm so wie der SID alleine noch kein vollständiger Synthesizer ist. SID 6581 und CPU 6510 bilden die hardwaremäßige Grundlage eines Synthesizers, der erst durch Software zum Leben erwacht. Das Steuerprogramm »Modulator« erweitert die Möglichkeiten dieser Hardware durch sinnvolle Effekte und ist als Kern eines später folgenden Synthesizer- und Sequenzerprogramms aufzufassen. Die Effektmöglichkeiten von Modulator allein sind allerdings schon so reichhaltig, daß sie für jede Spiele-Geräuschkulisse ausreichen dürften, solange man auf vollständige Melodien verzichtet.
Schritt für Schritt
Damit »Modulator« richtig arbeiten kann, muß es in regelmäßigen Zeitabständen immer wieder aufgerufen werden. Das Programm rechnet alle Modulationsquellen (LFOs und EG) Schritt für Schritt als Folge von Abtastwerten aus. Bei einem Aufruf wird dabei immer genau ein weiterer Abtastwert für alle aktiven Quellen errechnet. Ein Modulationsziel, zum Beispiel Frequenz Stimme 1 gewinnt das Programm dann dadurch, daß die Frequenzvorgabe für Stimme 1 entsprechend dem neuen (aktuellen) Wert der Modulationsquelle nach oben oder unten verschoben wird. Die so errechnete Größe wird dann von »Modulator« in die SID-Register geschrieben. Wenn man mit dem Modulator arbeitet, darf man also die zu modulierenden Größen nicht direkt in den SID schreiben (von dort könnten sie auch gar nicht mehr gelesen werden), sondern muß sie in andere, fest vereinbarte Speicherstellen schreiben, aus denen dann »Modulator« seine Vorgaben bezieht. Nun kann man das Programm nicht einfach in einer Schleife endlos aufrufen. Erstens könnte der Computer dabei nichts anderes mehr tun und zweitens wäre eine solche Aufruffolge zeitlich nicht regelmäßig.
Ein »Modulator«-Schritt benötigt zirka 1 bis 10 ms, je nachdem, wieviele Quellen aktiv sind und wieviele Ziele moduliert werden müssen. Es ist naheliegend, die Aufrufe von »Modulator«-Schritten nicht einem anderen Programm zu überantworten, sondern dazu einen programmierbaren Zeitgeber einzusetzen, der dann in völlig regelmäßiger Folge Aufrufe von »Modulator« auslöst.
Interrupts
Die beiden CIAs 6526 enthalten insgesamt vier Timer, die sich so programmieren lassen, daß sie in regelmäßigen Zeitabständen Interrupts auslösen. Zum Begriff Interrupt sei hier nur soviel gesagt: Ein Interrupt ist ein Unterprogrammsprung, der nicht von einem laufenden Programm ausgelöst wird, sondern von einem elektrischen Signal, das von außen an die CPU angelegt wird. Es kann dabei nicht vorhergesagt werden, an welcher Stelle im laufenden Programm ein Interrupt eintritt. Die CPU trägt dafür Sorge, daß sie nach Beendigung des durch den Interrupt aufgerufenen Programms an die Stelle im alten Programm zurückfindet, an der sie unterbrochen wurde. Normalerweise erzeugt Timer A von CIA 1 60mal in der Sekunde einen Interrupt, den sogenannten Systeminterrupt. Das dabei aufgerufene Programm fragt die Tastatur ab, läßt den Cursor blinken und aktualisiert die Werte der Zeitveriablen TI und TI$. In gleicher Weise wird nun auch »Modulator« aufgerufen. Da die SID-Parameter nicht kontinuierlich, sondern zeitlich gestuft moduliert werden, sollten die »Modulator«-Zeitschritte möglichst klein sein, damit die Abstufung unhörbar bleibt. Andererseits müssen die Zeitabstände zwischen zwei »Modulator«-Aufrufen mindestens so groß sein wie der Zeitbedarf eines Modulatorschritts, also mindestens 10 ms. Die Aufruffrequenz des Systeminterrupts von 16,6 ms erweist sich als ein guter Kompromiß. »Modulator« und Systeminterrupt-Programm kann man also durch denselben Interrupt auslösen. Bei 60 Modulationsschritten pro Sekunde ist eine zeitliche Quantelung bei der Klangqualität des SID nicht hörbar. Zum anderen bleibt der CPU zwischen den Schritten noch Zeit für andere Aufgaben. Werden alle Register bei »Modulator« gezogen, benötigt ein Schritt knapp 10 ms. Da das Systeminterrupt-Programm auch noch etwas Zeit benötigt, ergibt sich so eine CPU-Auslastung von zirka 70 Prozent. Man merkt das daran, daß alle anderen Vorgänge, zum Beispiel das Listen von Programmen stark verzögert ablaufen, wenn der Modulator voll aktiv ist. Man wird in der Praxis allerdings selten alle Modulationsmöglichkeiten gleichzeitig ausnützen.
Timesharing
Alle Programme, die selbst nicht interruptgetrieben sind, laufen problemlos quasiparallel zusammen mit »Modulator«. Mit dem Problem mehrerer konkurrierender Interrupts werden wir uns in einer späteren Folge im Zusammenhang mit dem Sequenzerprogramm befassen. Die CPU-Belastung durch den Modulator kann man leicht ermitteln, da das Programm bei jedem Schritt seine eigene Laufzeit mißt.
Ansteuerung von »Modulator«
Um sich mit dem Programm vertraut zu machen, sollte man es bei der Lektüre gleich ausprobieren. Zunächst muß man das Programm mit Hilfe des MSE (in dieser Ausgabe) in den Speicher bringen. Man kann nun mit Hilfe eines Monitors, oder komfortabler, mit dem Testprogramm zu »Modulator« (siehe Listing 2) die Modulationsmöglichkeiten ausprobieren. »Modulator« wird mit SYS 12 x 4096 + 1033 aktiviert. Von da an verbraucht das Programm Rechenzeit, egal ob etwas hörbar ist oder nicht. Abgeschaltet wird Modulator mit SYS 12 x 4096 + 1046. »Modulator« wird wie der SID über Registerinhalte gesteuert. Der Inhalt von 73 Speicherstellen nimmt Einfluß auf »Modulator« und darüber hinaus auch auf den SID. Im Registerschema in Bild 2 kann man zwischen Steuerparametern und dynamischen Parametern unterscheiden. Steuerparameter werden von »Modulator« nur gelesen. Über sie wird das Programm gesteuert. Dynamische Parameter werden ständig verändert. Durch Auslesen dieser Werte kann man beobachen, wie »Modulator« arbeitet. Man kann diese Register natürlich auch beschreiben. Dadurch greift man direkt in die Arbeit von »Modulator« ein. Für weitere Spezialeffekte kann das sinnvoll sein. Mehr davon im nächsten Teil.

Da die meisten SID-Register von »Modulator« gesteuert werden, muß man nur noch wenige direkt ansprechen. Es sind dies:
- Die Kontrollregister: 4, 11, 18
- ADSR-Register: 5, 6, 12, 13, 19, 20
- Resonanz/Filter: 23
- Die Leseregister: 25, 26, 27, 28
Die anderen SID-Register findet man mit ähnlichem Aufbau unter den Steuerparametern von »Modulator«. Das Basic-Testprogramm enthält einen vollständigen Parametersatz für SID und »Modulator« in den Zeilen 20 bis 41. Diese Zeilen sind so gestaltet, daß sie mit LIST -41 gerade einen Bildschirm füllen. Die DATA-Zeilen sind mit Kommentaren durchsetzt, so daß man den Zusammenhang mit dem Registerschema in Bild 2 leicht herstellen kann. Beim Testprogramm geht man am besten so vor:
- Modulator laden
- Testprogramm laden
- LIST -41
Jetzt kann man den Parametersatz studieren und verändern.
- Cursor auf die Zeile mit READY bringen
- RUN (SPACE), (SPACE)
Dadurch bleibt der DATA-Block am Bildschirm stehen. Nach einiger Zeit wird die Dauer eines »Modulator«-Schrittes und die daraus resultierende CPU-Belastung angezeigt. Jetzt kann man mit den Tasten F1, F3, F5 Stimme 1, 2, oder 3 auswählen und über die oberen beiden Tastenreihen einen Ton erklingen lassen. Der Ton klingt so lange weiter, bis mit der SPACE-Taste das GATE-Bit der gewählten Stimme zurückgesetzt wird. Das GATE-Bit des Software-EG wird ebenfalls gesetzt und rückgesetzt. Das einfache Basic-Programm reagiert nicht gerade flott, es ist aber auch nur zum Experimentieren mit »Modulator«-Klangbildern gedacht, nicht für virtuoses Spiel. Mit RUN/STOP wird das Programm abgebrochen. Während »Modulator« weiterarbeitet, kann man die Parameter in den DATA-Zeilen ändern, um das Programm neu zu starten.
Die Parameter
Es gibt zunächst drei identische Blöcke für die drei Stimmen. Frequenz F und Pulsweite PW sind die gleichen 16 (beziehungsweise 12)-Bit-Größen wie beim SID. Das Byte PORTA steuert das Tempo, mit dem verschiedene Tonhöhen ineinander übergehen:
PORTA = 1 | sehr langsam |
PORTA = 255 | sehr schnell |
PORTA = 0 | kein Portamento |
FP ist ein dynamischer Wert. Er enthält die aktuelle Frequenz, die gemäß der PORTA-Rate immer in Richtung F gezogen wird, bis F und FP übereinstimmen.
FILT enthält, wie beim SID, die Grenzfrequenz in der Aufteilung: 3 niederwertige Bits und 8 höherwertige Bits.
MOD/LAUT entspricht genau dem SID-Register 24.
Der Kreuzschienen-Verteiler wird durch 8 Bytes realisiert. Ein Byte entspricht einer Zeile im KSV (Kreuzschienenverteiler). Die 8 Bitpositionen entsprechen den Spalten des KSV. Eine 1 an Bitposition N in Byte M entspricht einem Kurzschlußstecker an Spalte N und Zeile M.
Die sieben LFOs werden durch sieben gleichartige Blöcke gesteuert.
LFOF Mit 16 Bit kann die LFO-Frequenz sehr fein im Bereich 0-60 Hz eingestellt werden. Oberhalb von 10 Hz ergeben sich Aliasing-Effekte über die in der nächsten Folge noch etwas gesagt werden wird.
LFOP Dieses Byte steuert die Pulsweite, wenn als Kurvenform SQARE gewählt wurde. LFOP = 128 ergibt ein symmetrisches Rechteck.
LFOA steuert die Amplitude des LFO-Signals. LFOA = 103 entspricht übrigens einer Frequenzmodulation um eine Oktave. LFOA = 0 ist nicht sinnvoll, da der LFO dann kein Ausgangssignal liefert, aber Rechenzeit verbraucht.
LFOC Dieses Steuerbyte bestimmt Kurvenform und Betriebsart des LFO gemäß Tabelle. RUN ist die normale Betriebsart, HOLD hält den letzten aktuellen Kurvenwert fest und RESET setzt den Kurvenwert in die Neutralstellung 0. In den Betriebsarten HOLD und RESET benötigen die LFOs sehr wenig Rechenzeit. Man sollte daher nicht benötigte LFOs in HOLD oder RESET »betreiben«.
Der EG-Steuerblock enthält die gewohnten ADSR-Parameter. A soll sich im Bereich 0..128, alle anderen im vollen Bereich 0..255 bewegen.
EGA Auch die Amplitude der ADSR-Kurve ist steuerbar.
EGC steuet die Betriebsart. Für HOLD und RESET gilt hier das oben Gesagte (auch in Bezug auf die Rechenzeit). GATE hat hier die gleiche Funktion wie auch im SID. Mit ± kann man zwischen einer positiven und negativen Hüllkurve umschalten.
Es folgen sieben dynamische LFO-Blöcke, deren Registerinhalte den aktuellen Kurvenverlauf wiederspiegeln. In SAWUP befinden sich die Werte des aufsteigenden Sägezahn mit maximaler Amplitude. Aus ihnen werden die anderen Kurvenformen abgeleitet. In KURVE steht der aktuelle Wert der gewählten Kurvenform.
Entsprechendes gilt für die Register E und EKURVE im dynamischen Hüllkurvenblock. Die Flagge EPHASE wird benötigt, um zwischen ATTACK und DECAY zu unterscheiden.
In der nächsten Folge wird das Source-Listing zu »Modulator« besprochen. Wenn man die Arbeitsweise des Programms kennt, kann man seine Möglichkeiten noch weiter ausschlachten, als das über die Steuerregister möglich ist. Außerdem werden wir konkrete Steuerparametersätze besprechen.
(Thomas Krätzig/aa)PROGRAMM : MODULATOR C075 C425 ----------------------------------- C075 : A9 00 A2 08 0A 26 FB 90 AB C07D : 07 18 65 FD 90 02 E6 FB 56 C085 : CA D0 F1 A8 8A A2 08 0A 3B C08D : 26 FC 90 07 18 65 FD 90 FC C095 : 02 E6 FC CA D0 F1 18 65 6A C09D : FB 85 FB 90 02 E6 FC 98 E8 C0A5 : 60 A5 FC 10 CB 38 A9 00 3E C0AD : E5 FB 85 FB A9 00 E5 FC 9D C0B5 : 85 FC 20 75 C0 85 02 38 20 C0BD : A9 00 E5 02 A8 A9 00 E5 C4 C0C5 : FB 85 FB A9 00 E5 FC 85 E5 C0CD : FC 98 60 A6 FE BD 24 C0 F2 C0D5 : 29 06 C9 04 F0 12 C9 06 C7 C0DD : F0 0F A9 00 9D 49 C0 9D 22 C0E5 : 4A C0 9D 4B C0 9D 4C C0 0C C0ED : 60 18 BD 49 C0 7D 20 C0 EC C0F5 : 9D 49 C0 85 FB BD 4A C0 70 C0FD : 7D 21 C0 9D 4A C0 85 FC A9 C105 : BD 24 C0 29 18 F0 27 C9 63 C10D : 08 F0 50 C9 10 F0 40 A5 AF C115 : FC DD 22 C0 90 09 38 A9 26 C11D : 00 FD 23 C0 38 B0 04 18 46 C125 : BD 23 C0 6A 9D 4C C0 A9 84 C12D : 00 6A 9D 4B C0 60 A5 FC D3 C135 : 10 13 A5 FB 49 FF 0A 85 7F C13D : FB A5 FC 49 FF 2A 49 80 EB C145 : 85 FC 4C 60 C1 06 FB 2A F8 C14D : 49 80 85 FC 4C 60 C1 A5 F1 C155 : FB 49 FF 85 FB A5 FC 49 19 C15D : FF 85 FC BD 23 C0 85 FD 60 C165 : 20 A6 C0 A6 FE A5 FB 9D 25 C16D : 4B C0 A5 FC 9D 4C C0 60 21 C175 : AD 48 C0 29 06 C9 04 F0 3C C17D : 15 C9 06 F0 12 A9 00 8D A0 C185 : 6C C0 8D 6D C0 8D 6E C0 16 C18D : 8D 6F C0 8D 70 C0 60 A9 95 C195 : 01 2C 48 C0 F0 52 2C 70 0A C19D : C0 D0 39 AD 6C C0 49 FF BB C1A5 : 85 FB AD 6D C0 49 FF 85 A2 C1AD : FC AD 43 C0 0A B0 05 85 AE C1B5 : FD 20 75 C0 18 AD 6C C0 5A C1BD : 65 FB 8D 6C C0 85 FB AD 94 C1C5 : 6D C0 65 FC 8D 6D C0 85 DE C1CD : FC C9 FF 90 47 A9 01 8D A1 C1D5 : 70 C0 D0 40 AD 6C C0 85 2E C1DD : FB 38 AD 6D C0 ED 45 C0 1F C1E5 : 85 FC AD 44 C0 4C FF C1 CE C1ED : A9 00 8D 70 C0 AD 6C C0 B4 C1F5 : 85 FB AD 6D C0 85 FC AD 18 C1FD : 46 C0 85 FD 20 75 C0 38 E5 C205 : AD 6C C0 E5 FB 8D 6C C0 34 C20D : 85 FB AD 6D C0 E5 FC 8D F3 C215 : 6D C0 85 FC AD 47 C0 85 06 C21D : FD 20 75 C0 A9 08 2C 48 BC C225 : C0 F0 10 38 A9 00 E5 FB 93 C22D : 8D 6E C0 A9 00 E5 FC 8D 95 C235 : 6F C0 60 A5 FB 8D 6E C0 38 C23D : A5 FC 8D 6F C0 60 49 FF E6 C245 : 85 02 A9 00 85 FB 85 FC 7E C24D : A0 08 46 02 B0 11 AA A5 4D C255 : FB 7D 4B C0 85 FB A5 FC C2 C25D : 7D 4C C0 85 FC 8A 38 69 B9 C265 : 04 88 D0 E6 60 A6 FE BD 71 C26D : 04 C0 D0 0D BD 00 C0 9D C1 C275 : 05 C0 BD 01 C0 9D 06 C0 FC C27D : 60 BD 01 C0 DD 06 C0 90 46 C285 : 3A D0 0B BD 00 C0 DD 05 29 C28D : C0 90 30 D0 01 60 38 BD 2B C295 : 00 C0 FD 05 C0 85 FB BD B9 C29D : 01 C0 FD 06 C0 85 FC BD E6 C2A5 : 04 C0 85 FD 20 75 C0 A6 28 C2AD : FE 38 BD 05 C0 65 FB 9D 3A C2B5 : 05 C0 BD 06 C0 65 FC 9D B1 C2BD : 06 C0 60 38 BD 05 C0 FD 45 C2C5 : 00 C0 85 FB BD 06 C0 FD 11 C2CD : 01 C0 85 FC BD 04 C0 85 39 C2D5 : FD 20 75 C0 A6 FE 18 BD 96 C2DD : 05 C0 E5 FB 9D 05 C0 BD BC C2E5 : 06 C0 E5 FC 9D 06 C0 60 32 C2ED : A9 1E 85 FE 20 D0 C0 38 E2 C2F5 : A5 FE E9 05 10 F4 20 75 48 C2FD : C1 A9 02 A2 0E 85 9B 86 F0 C305 : FE 20 6A C2 A6 9B BD 18 75 C30D : C0 D0 11 A6 FE BD 05 C0 C2 C315 : 9D 00 D4 BD 06 C0 9D 01 7E C31D : D4 4C 41 C3 20 43 C2 A6 55 C325 : FE BD 06 C0 85 FD 20 A6 B2 C32D : C0 A6 FE 18 BD 05 C0 65 D5 C335 : FB 9D 00 D4 BD 06 C0 65 73 C33D : FC 9D 01 D4 A6 9B BD 1B 57 C345 : C0 D0 11 A6 FE BD 02 C0 EE C34D : 9D 02 D4 BD 03 C0 9D 03 8B C355 : D4 4C 81 C3 20 43 C2 46 DC C35D : FC 66 FB 46 FC 66 FB 46 D3 C365 : FC 66 FB 46 FC 66 FB A6 9C C36D : FE 18 BD 02 C0 65 FB 9D 89 C375 : 02 D4 BD 03 C0 65 FC 29 2F C37D : 0F 9D 03 D4 8A 38 E9 07 D6 C385 : 85 FE C6 9B 30 03 4C 06 07 C38D : C3 AD 15 C0 8D 15 D4 AD B4 C395 : 1E C0 D0 09 AD 16 C0 8D 12 C39D : 16 D4 4C AE C3 20 43 C2 D6 C3A5 : 18 AD 16 C0 65 FC 8D 16 D2 C3AD : D4 AD 1F C0 D0 07 AD 17 62 C3B5 : C0 8D 18 D4 60 20 43 C2 76 C3BD : AD 17 C0 29 F0 85 02 A5 DA C3C5 : FC 4A 4A 4A 4A 18 6D 17 0C C3CD : C0 29 0F 05 02 8D 18 D4 1D C3D5 : 60 AD 04 DC AE 05 DC C9 C3 C3DD : 04 B0 01 E8 60 20 D6 C3 81 C3E5 : 8D 73 C0 8E 74 C0 20 ED D7 C3ED : C2 20 D6 C3 85 02 38 AD 92 C3F5 : 73 C0 E5 02 8D 71 C0 86 F6 C3FD : 02 AD 74 C0 E5 02 8D 72 94 C405 : C0 4C 31 EA 78 A9 E2 8D 10 C40D : 14 03 A9 C3 8D 15 03 58 C4 C415 : 60 78 A9 31 8D 14 03 A9 1B C41D : EA 8D 15 03 58 60 00 00 FC
10 rem-------------------------------- 11 rem rahmenprogramm zum test von 12 rem m o d u l a t o r 13 rem 14 rem thomas kraetzig februar 1985 15 rem-------------------------------- 20 rem sid f pw port wf a d s r 21 data 110, 50, 32, 64, 1,10, 8,10 22 data 220, 50, 48, 64, 1,10, 8,10 23 data 440, 50, 64, 32, 1,10, 8,10 24 : 25 rem filter f res filt mod laut 26 data 64, 12, 7, 1, 15 27 : 28 rem lfo f p a c f p a c 29 data 5000,128, 6, 6,7000,128, 6, 6 30 data 800,128,128, 6,9000,128, 8, 6 31 data 6000,128,103,30,1000,128,196, 6 32 data 15,128,128, 0 33 : 34 rem eg a d s r ega egc 35 data 20, 15, 32, 20, 128, 06 36 : 37 rem ksv 38 data 00000001,f1, 00000010,f2 39 data 00001000,f3, 00000100,pw1 40 data 00000000,pw2, 00000000,pw3 41 data 10000000,filt, 00000000,laut 245 : 250 b=12*4096 :rem basis fuer parameter 255 si=13*4096+1024 :rem sid-basis 260 : 265 rem datas einlesen, sid- und 270 rem modulator-register besetzen 275 : 280 for ss=0 to 2 :rem 3 stimmen 285 : 290 : rem frequenz 295 : read f:f=int(f*17.0284+0.5) 300 : hi=int(f/256):lo=f-256*hi 305 : poke b+7*ss,lo:poke b+1+7*ss,hi 310 : bf(ss)=f :rem basisfrequenz 315 : 320 : rem pulsweite 325 : read p:p=int(p*40.95+0.5) 330 : hi=int(p/256):lo=p-256*hi 335 : poke b+2+7*ss,lo 340 : poke b+3+7*ss,hi 345 : 350 : rem porta 355 : read p:poke b+4+7*ss,p 360 : 365 : rem wellenform 370 : read wf(ss):wf(ss)=wf(ss) and 254 375 : 380 : rem a d s r - huellkurve 385 : reada:readd:pokesi+7*ss+5,16*a+d 390 : reads:readr:pokesi+7*ss+6,16*s+r 395 : 400 next ss 405 : 410 rem filter, lautstaerke 415 read f:hi=int(f/8):lo=f-8*hi 420 poke b+21,lo:poke b+22,hi 425 read res:read filt 430 poke si+23,16*res+filt 435 read mod:read laut 440 poke b+23,16*mod+laut 445 : 450 rem lfo 455 for i=0 to 6 460 : read f:hi=int(f/256):lo=f-256*hi 465 : poke b+32+5*i,lo 470 : poke b+33+5*i,hi 475 : read p:poke b+34+5*i,p 480 : read a:poke b+35+5*i,a 485 : read c:poke b+36+5*i,c 490 next i 495 : 500 rem eg (a d s r) 505 for i=0 to 4:read x:poke b+67+i,x 510 next i 515 read ec :rem steuerbyte merken 520 ec=ec and 254:rem gate=0 525 poke b+72,ec 530 : 535 rem ksv 540 for i=0 to 7 545 : read a$:a=0 550 : for j=1 to 8 555 : a=2*a 560 : if mid$(a$,j,1)="1"then a=a+1 565 : next j 570 : poke b+24+i,a 575 : read a$ :rem ueberlesen 580 next i 585 : 590 rem eingabezeichen fuer noten 595 n$="q2w3er5t6y7ui9o0p@-*\^" 600 : 610 rem relative tonhoehen 615 dim th(21) 620 for i=0 to 21 625 : th(i)=2^(i/12) 630 next i 635 : 640 sys b+1024+9 :rem modulator starten 642 : 645 rem zeitmessung auswerten 650 t=peek(b+113)+256*peek(b+114) 655 t1=int(t/100)/10 660 t2=int(1000*t/16421)/10 665 print"zeitbedarf:";t1;"ms"; 670 print" auslastung:";t2;"%{up}{up}{up}"; 671 : 672 rem tasteneingaben auswerten 673 rem q-^ toene (weisse tasten) 674 rem 2-\ toene (schwarze tasten) 675 rem space gate aus 676 rem f1,2,3 stimme 1,2,3 677 : 680 s=0 685 get a$:if a$="" then 685 690 if a$<>" " then 715 695 poke b+72,ec :rem eg gate aus 700 poke si+4+7*s,wf(s):rem gate aus 705 goto 685 710 rem n$ nach eingabe durchsuchen 715 i=0 720 i=i+1:if i>=22 then 770 725 if a$<>mid$(n$,i,1) then 720 730 f=bf(s)*th(i-1) 735 hi=int(f/256):lo=f-256*hi 740 poke si+4+7*s,wf(s):rem gate aus 745 poke b+72,ec :rem eg gate aus 750 poke b+7*s,lo :poke b+1+7*s,hi 755 poke si+4+7*s,wf(s)+1 760 poke b+72,ec+1:rem eg gate an 765 goto 685 770 if a$="{f1}" then s=0 :rem f1,stimme 1 775 if a$="{f3}" then s=1 :rem f3,stimme 2 780 if a$="{f5}" then s=2 :rem f5,stimme 3 785 goto 685