Dem Klang auf der Spur (Teil 9)

In diesem Teil wird gezeigt, wie man dreistimmige Musikstücke programmgesteuert, schnell und zeitexakt auf dem C 64 wiedergeben kann. So ganz nebenbei erfahren Sie eine Menge über die Interrupttechnik.

Zunächst einige Grundlagen zum Sequenzer. Unter einem Sequenzer versteht man ein Gerät oder Programm, das einen Synthesizer mit einer vorprogrammierten Tonfolge ansteuert. Die zentrale Rolle spielt dabei das genaue Einhalten eines programmierbaren Zeitmaßes.

Musikstücke werden üblicherweise in Takte von etwa 1 bis 4 Sekunden Länge eingeteilt. Am gebräuchlichsten ist der 4/4-Takt, der die Länge einer ganzen Note hat. Andere gebräuchliche Taktarten sind 2/4, 3/4, 6/8, 4/4, 5/4, 3/2. Diese Angaben betreffen allerdings nur die Zählweise der Takte und nicht das Tempo eines Musikstücks. So sind zum Beispiel 3/4- und 6/8-Takt bis auf die Zählweise vollkommen identisch.

Die Notenlängen werden in Bruchteilen der ganzen Note angegeben:

Es kommen auch ungeradzahlige Vielfache dieser Notenlängen vor. Durch Punktierung kennzeichnet man die Verlängerung einer Note um die Hälfte ihrer ursprünglichen Länge:

Alle diese Notenlängen passen in ein Raster, welches eine ganze Note in 16 oder 32 gleiche Zeitabschnitte teilt. Es werden aber häufig auch sogenannte Triolen (Drittelnoten) eingesetzt. Zum Beispiel Achteltriolen,

das sind drei gleichlange Noten mit der Länge einer Viertelnote. Aus diesem Grund sollte das Zeitraster (die Anzahl der Zeitabschnitte, in die der Sequenzer eine ganze Note einteilt) auch den Faktor 3 enthalten. Ein sinnvolles Zeitraster ist zum Beispiel 96 (= 3x32).

Das Tempo wird in der Musik in Schlägen pro Minute (beats per minute: bpm) gemessen. Ein Schlag entspricht dabei einer Viertelnote. Der sinnvolle Bereich für dieses Maß liegt bei etwa 40 bis 240 bpm. Beim schnellen Tempo 240 bpm dauert eine ganze Note genau eine Sekunde. Der Sequenzer muß dann 96 Schritte pro Sekunde ausführen.

Programmtechnik

Ein Sequenzer ist von der zu erbringenden Funktion her eigentlich ein sehr einfaches Programm. Seine Leistungen sind schnell aufgezählt:

Diese Steuerungen müssen zeitgenau und unabhängig voneinander für drei Stimmen erfolgen. Darüber hinaus wären einige Zusatzfunktionen sinnvoll:

Es soll zunächst ein einfacher Basis-Sequenzer entwickelt werden, der sich dann leicht um die genannten Zusatzfunktionen erweitern läßt. Die Erweiterungen sollen über Vektoren, also ohne Änderung des Grundprogramms, an dieses angeschlossen werden können.

Ein Sequenzer ist, ähnlich wie der in dieser Reihe veröffentlichte Modulator, ein Programm, das in regelmäßigen Zeitabständen eine Leistung erbringen muß. Der Aufruf per Interrupt, ausgelöst durch einen Zeitgeber, bietet sich also auch hier an. Jeder CIA (Complex Interface Adapter) ist mit zwei 16-Bit-Timern ausgestattet, die sich für diese Aufgabe eignen. Timer A in CIA1 wird bereits für den Systeminterrupt eingesetzt. Ein Systeminterrupt findet konstant 60-mal pro Sekunde statt und kann mit dem Aufruf eines Modulatorschritts gekoppelt werden.

Musik per Interrupt

Die Aufruffrequenz der Sequenzer-Schritte soll dagegen im Bereich von zirka 20-100 Hz, abhängig vom Tempo des Musikstücks, variabel sein. (Man erinnere sich: 240 bpm entsprechen 96 Hz bei einem Zeitraster von 96 Schritten pro ganzer Note.) Das legt den Einsatz eines weiteren unabhängigen Timers nahe. In Frage kommen dafür:

Die Auswahl des Timers ist willkürlich. Im vorliegenden Programm wird Timer B in CIA1 eingesetzt. Dadurch bleiben die Timer in CIA 2 noch vollkommen frei für Zwecke, die nichts mit der Musikprogrammierung zu tun haben müssen. Da nun Timer A und Timer B beide unabhängig voneinander Interrupts auslösen können, muß die angesprungene Interrupt-Serviceroutine die Interrupt-Quelle ermitteln, also feststellen, welcher Timer den Interrupt ausgelöst hat und abhängig davon weiterverzweigen. Zu diesem Zweck wird im sogenannten Interrupt-Control-Register (ICR) $DC0D bei einem Timer-A-Interrupt Bit 0 und bei einem Timer-B-Interrupt Bit 1 gesetzt.

Programmierung des CIA

Zur Steuerung von CIA-Interrupts dient das schon erwähnte Interrupt-Control-Register (ICR) $DC0D. Dieses Register hat zwei Funktionen, je nachdem, ob schreibend oder lesend darauf zugegriffen wird. Bei Lesezugriff zeigt es an, ob, und wenn ja, woher ein Interrupt ausgelöst wurde. Zugleich wird das Register gelöscht und die Interrupt-Anforderung zurückgenommen (Die IRQ-Leitung geht von low auf high). Die Bits 0-4 sind dabei verschiedenen Interruptquellen zugeordnet. Uns interessieren hier nur die Bits 0 und 1, welche zu den Timer-Interrupts gehören. Durch einen Schreibzugriff wird dagegen ein Masken-Register angesprochen. Damit lassen sich die Interruptquellen einzeln freigeben oder sperren. Die Bits 0-4 kann man einzeln setzen oder zurücksetzen. Ist im geschriebenen Byte Bit 7 gesetzt, wird jedes mit einer 1 beschriebene Bit gesetzt, während die anderen Bits unverändert bleiben. Ist Bit 7 rückgesetzt, so wird jedes mit einer 1 beschriebene Bit zurückgesetzt, während die anderen Bits wieder unverändert bleiben. Gesetzte Bits ermöglichen eine Interrupterzeugung durch die jeweilige Quelle. Die Freigabe der Interrupterzeugung durch Timer B sieht also so aus: LDA #%10000010 STA $DD0D ;ICR Bit 1 setzen

Der Timer selbst wird durch drei Register gesteuert.

Das Registerpaar TIMER B ($DC06/$DC07) liefert bei Lesezugriff den aktuellen 16-Bit-Zählerstand. Dieser Wert wird kontinuierlich heruntergezählt. Bei Erreichen von Null stoppt der Timer entweder (One-Shot-Mode) oder lädt einen Wert aus einem Timer-Latch (Latch = Zwischenspeicher) nach und zählt von neuem herunter (Continous Mode). Bei diesem Timer-Unterlauf wird ein Interrupt erzeugt, wenn Bit 1 im ICR gesetzt ist. Ein Schreibzugriff auf TIMERA bezieht sich dagegen auf das 16-Bit-Latch. Mit dem Latch-Wert kann man die Zeit zwischen zwei Interrupts im Bereich von 1 bis 65535 Mikrosekunden steuern.

Das Register CRB (Control Register B, $DC0F) steuert die Betriebsart des Timers (Start/Stop, One Shot/Continous, u.a.)

Durch LDA #%00010001 STA $DD0E wird der Zählerstand mit dem Latch-Wert geladen und der Timer gestartet.

Die Interrupt-Service-Routine

Sie fragt zunächst ab, ob der Interrupt von Timer A (Systeminterrupt, Modulatorschritt) oder von Timer B (Sequenzerschritt) kommt. Bei einer möglichen gleichzeitigen Interruptanforderung durch beide Timer, wird der Timer-B-Interrupt bevorzugt behandelt. Das hat folgende Gründe:

Da das ICR beim Lesen gelöscht wird, muß sein Inhalt zwischengespeichert werden, damit beim Auftreten von zwei Interrupts die Behandlung des niedriger priorisierten Timer-A-Interrupts nachgeholt werden kann.

Bei Auftreten eines Interrupts wird immer das Interrupt-Bit im CPU-Statusregister gesetzt, damit die CPU nicht gleich wieder unterbrochen werden kann. Da die IRQ-Leitung so lange auf Low-Pegel bleibt, bis die CPU durch Auslesen des CIA-ICR die Interruptanforderung löscht, würde sich das System ohne gesetztes Interrupt-Bit durch einen Dauerinterrupt aufhängen. Es steht dem Programmierer allerdings frei, nach dem Auslesen des ICR das Interrupt-Bit durch den Befehl CLI (Clear Interrupt-Flag) zurückzusetzen, um damit das Programm wieder unterbrechbar zu machen. Beim vorliegenden Programm bleibt bei einem Sequenzer-Schritt das Interrupt-Bit gesetzt, während es zur Abarbeitung eines Timer-A-Interrupts rückgesetzt wird. Dadurch kann die CPU auch dann durch einen Timer-B-Interrupt unterbrochen werden.

Das Betriebssystem und das Programm Modulator machen beide intensiven Gebrauch von der Zero-Page. Die Inhalte der Zero-Page-Speicherplätze dürfen von einem interruptgetriebenen Programm nicht verändert werden. Das Sequenzer-Programm belegt daher nur zwei Zero-Page-Speicherplätze ($FE,$FF). Ihre Inhalte werden bei Programmbeginn zwischengespeichert und bei Programmende restauriert.

Die verwendeten Datenstrukturen

Um ein Musikstück in eine computergerechte Form zu bringen, muß man im wesentlichen die Tonhöhe und die Länge der einzelnen Noten codieren. Beim Einsatz mehrerer, verschieden klingender Stimmen, muß man außerdem jede Note eindeutig einer Stimme zuordnen. Die hier verwendete Datenstruktur (Bild 1) verfolgt mit ihrem etwas komplizierten Aufbau zwei Ziele:

Bild 1. Sequenzer-Datenstruktur

Tracks

Die Steueranweisungen werden für die drei Stimmen getrennt in drei sogenannten Tracks (Tonspuren) gespeichert. Ein Track ist eine zusammenhängende Folge von 1-Byte-Kommandos. Das häufigste Kommando dürfte das Ton-Kommando sein. Die Tonhöhe wird aus einer Oktav-Nummer und einer Tonnummer (siehe Bild 2), die in den beiden Nibbles (=Halbbytes) eines Bytes stehen, ermittelt. Das Programm benötigt dazu lediglich eine Tabelle der Frequenzen der höchsten Oktave. Die Frequenzen der niedrigeren Oktaven werden durch Teilung durch Zweierpotenzen errechnet. Eine Division durch 2 wird durch einen einfachen Rechts-Shift realisiert. Die Dauer des Tones ist nicht Bestandteil des Ton-Kommandos. Sie wird durch das Zeit-Kommando voreingestellt. Da häufig mehrere Töne mit gleicher Länge aufeinanderfolgen, genügt ein einziges Zeit-Kommando (ein oder zwei Bytes), um die Tonlänge (siehe Bild 3) einzustellen. Dabei wird zwischen einer GATE-ON- und einer GATE-OFF-Phase unterschieden, deren Längen zusammengenommen die gewünschte Tonlänge ergeben.

Beispiel:

Bild 3. Tonlängen bei 96 Schritten pro Ganzton

Das entspricht einer kurz angeschlagenen Achtelnote (bei 96 Zeitschritten pro ganzer Note). Die GATE-ON-Zeit ist im Bereich 1-96, die GATE-OFF-Zeit im Bereich 0-30 einstellbar. Der Sequenzer setzt nach Ablauf der GATE-ON-Zeit das GATE-Bit der entsprechenden Stimme im SID zurück und wartet dann die GATE-OFF-Zeit ab. Ist diese 0, so wird natürlich sofort der nächste Ton gespielt. Man kann aber auch explizit Pausen programmieren (Code $EF). Ihre Länge ist die Summe aus GATE-ON- und GATE-OFF-Zeit.

Der Code $00 ist zur Kennzeichnung für das Track-Ende vorgesehen. Die Codes $F8 bis $FF sind für Sonderfunktionen reserviert, die für eine spätere Erweiterung des Sequenzers gedacht sind. Angesprungen werden sie über eine Tabelle von Vektoren, die im Moment nur in den Programmteil zur Ausführung des nächsten Kommandos führen, also nichts bewirken. Sinnvolle Sonderfunktionen sind:

Diese Sonderfunktionen werden den Sequenzer in der nächsten Folge ergänzen.

Sequenzen

Für jede der drei Stimmen gibt es eine Folge von Kommandos, einen Track. Die drei Tracks werden zu einer Sequenz zusammengefaßt. Eine Sequenz ist hier ein zusammenhängender Abschnitt eines Musikstücks, der einen einzigen Ton, einen Takt oder auch das ganze Stück umfassen kann. Den drei Tracks gehen drei Zeiger auf die Track-Startadressen voran. Obwohl es sich aus Gründen der Übersichtlichkeit empfiehlt, die Sequenzen wie in Bild 1 zusammenhängend in der Folge Zeiger-Track 1, -Track 2, -Track 3 zu speichern, besteht dazu kein Zwang. Es müssen lediglich die drei Track-Zeiger einer Sequenz und die Tracks in sich zusammenhängen.

Sequenzfolge-Liste

Um eine Sequenz zu wiederholen, muß man sie nicht zweimal programmieren, sondern kann sie wie ein Unterprogramm mehrmals aufrufen. Die Sequenzfolge-Liste enthält dazu die Startadressen der Sequenzen in der Reihenfolge, in der diese gespielt werden sollen. Dabei können die gleichen Adressen natürlich mehrfach auftreten. Unter der Startadresse einer Sequenz wird hier die Adresse des Zeigers auf Track 1 verstanden. Die Sequenzfolge-Liste enthält für jede Sequenz außer dem Zeiger noch ein drittes Byte, das für spätere Erweiterungen vorgesehen ist. Drei Nullen schließen die Liste ab.

Flexibilität durch Steuerflags und Vektoren

Im Normalfall wird man die drei Tracks einer Sequenz gleich lang programmieren. Macht man dagegen die Tracks unterschiedlich lang, so wiederholt das Programm die kürzeren Tracks so lange, bis der längste Track zu Ende gespielt ist. Erst dann geht das Programm zur nächsten Sequenz über. Dieses Verhalten kann bei manchen Musikstücken nützlich sein. Das MSE-Listing 2 enthält einen Musik-Datensatz, bei dem in der zweiten Sequenz der dritte Track aus nur vier Tönen besteht, die fortlaufend wiederholt werden.

Normalerweise hält der Sequenzer an, wenn alle Sequenzen gemäß Sequenzfolge-Liste durchgespielt sind. Nach dem Anhalten wird auch der Interruptvektor auf seinen ursprünglichen Wert zurückgestellt. Eine 1 im Flag REPMODUS bewirkt, daß das ganze Stück endlos wiederholt wird.

Eine 1 im Flag SEQMODUS bewirkt, daß die aktuelle Sequenz endlos wiederholt wird. Auch hier ist der längste Track der Sequenz maßgeblich.

Eine 1 im Flag LEGATO bewirkt, daß die GATE-Bits in den SID-Steuerregister nicht zurückgesetzt werden. Dadurch klingen die Töne gebunden. Dazu muß allerdings ein Sustain-Pegel ungleich Null eingestellt sein, sonst ist überhaupt nichts hörbar.

An allen wichtigen Stellen des Sequenzers wird der Programmfluß über Vektoren weitergeleitet. Damit soll die Möglichkeit, das Programm nachträglich leicht zu erweitern, offengehalten werden. Die Vektoren für die acht Sonderfunktionen wurden schon erwähnt. Außer diesen acht gibt es noch drei weitere Vektoren:

Das vorliegende Sequenzerprogramm (Listing 1) belegt den Speicherbereich $C480-$C778. $C480 = 50304 ist gleichzeitig auch die Startadresse (SYS 50304). Tabelle 1 faßt die wichtigsten Routinen, Variablen und Vektoren des Sequenzer-Programms zusammen.

Routinen, Variablen, Vektoren

$C480 JMP TEST Teststart, Zeiger initialisieren, die wichtigsten SID-Parameter setzen, Sequenzer starten.
$C49E SIDCR (3 Byte) SID-Control-Register-Bytes mit zurückgesetztem GATE-Bit
$C4A8 LEGATO (0 Byte) Flag 0 = normaler Betrieb
Flag 1 = kein GATE-OFF
$C4A9 SEQMODUS (1 Byte) Flag 0 = ganzes Stück spielen
Flag 1 = Sequenz wiederholen
$C4AA REPMODUS (1 Byte) Flag 0 = Stück einmal wieder spielen
Flag 1 = Stück immer wieder spielen
$C4C3 FUNCTION (8*2 Byte) Vektoren für Sonderfunktionen
$C4D3 TONVEKTOR (2 Byte) Vektor zur Weiterverarbeitung der Frequenz bei Ton an
$C4D5 EXTRAVEKTOR (2 Byte) Vektor für Zusatzaktion bei jedem Sequenzer-Schritt
$C4D7 IRQAVEKTOR (2 Byte) Vektor für Timer-A-Interrupt
$C4D9 START Sequenzer starten (Es werden keine Zeiger initialisiert).
$C51E IRQSERVICE Anlaufpunkt für alle IRQ-Interrupts.
$C67D NEXTAKT Dorthin sollten alle Sonderfunktionen zurückspringen
$C716 STOP Sequenzer unterbrechen/ausschalten. Er kann mit START jederzeit neu gestartet werden.
$C739 TEST siehe $C480
Tabelle 1. Die wichtigsten Routinen, Varianten und Vektoren des Sequenzers.

Das Programmieren von Musikstücken mit Hilfe der Tabelle 2 ist noch etwas mühsam. Ein Editor in der nächsten Ausgabe wird diese Arbeit erleichtern. Mit dem Datensatz aus Listing 2 (»Kobold« aus den »Lyrischen Stücken« von Edvard Grieg) kann man den Sequenzer testen.

Kommandoformate innerhalb der Tracks

Kommando Interpretation
%0000 0000 Track-Ende
%0ttt tttt Zeitvorgabe t = 1...96 GATE-ON-Zeit: t=m
t = 97...127 GATE-OFF-Zeit: t-97
%1mmm nnnn nächster Ton m = 0...6 Oktave
n = 0...11 Tonnummer
n = 12...15 Pause
%1110 1111 Pause (Standardcode $EF)
%1111 1fff Sonderfunktion f = 0...7 Funktionsnummer
Tabelle 2. So programmiert man einen »Track«.

Die Verschmelzung des Sequenzers und des Modulators zu einer funktionellen Einheit wird in der nächsten Folge behandelt.

(Thomas Krätzig/tr)
PROGRAMM : SEQUENCER      C480 C77A
-----------------------------------
C480 : 4C 39 C7 FF 00 00 00 C8   EC
C488 : 0C C8 E0 C8 FD C8 20 C9   84
C490 : 43 C9 18 18 18 00 00 00   43
C498 : 0D 0D 0D 00 00 00 20 20   30
C4A0 : 20 01 02 04 00 00 00 00   42
C4A8 : 00 00 01 1E 86 18 8E 8B   27
C4B0 : 96 7E 9F FA A8 06 B3 AC   AF
C4B8 : BD F3 C8 E6 D4 8F E1 F8   C1
C4C0 : EE 2E FD 7D C6 7D C6 7D   63
C4C8 : C6 7D C6 7D C6 7D C6 7D   1C
C4D0 : C6 7D C6 FC C6 95 C5 31   38
C4D8 : EA AD 14 03 8D D7 C4 AD   04
C4E0 : 15 03 8D D8 C4 A9 1E 8D   22
C4E8 : 14 03 A9 C5 8D 15 03 A9   82
C4F0 : E0 8D 06 DC A9 2E 8D 07   04
C4F8 : DC A9 82 8D 0D DC A9 11   7C
C500 : 8D 0F DC 60 AE 84 C4 BD   F6
C508 : 8D C4 85 FF BD 8C C4 85   B7
C510 : FE A0 00 B1 FE FE 8C C4   38
C518 : D0 03 FE 8D C4 60 AD 0D   FB
C520 : DC 48 29 02 D0 03 4C A1   45
C528 : C5 A5 FE 48 A5 FF 48 A5   4F
C530 : 01 29 FE 85 01 AD 0D DC   A2
C538 : A2 0E 8E 85 C4 A2 04 8E   C4
C540 : 84 C4 A2 02 8E 83 C4 20   68
C548 : 4D C6 CE 83 C4 30 12 CE   D0
C550 : 84 C4 CE 84 C4 AD 85 C4   D4
C558 : 38 E9 07 8D 85 C4 4C 47   37
C560 : C5 AD A7 C4 C9 07 D0 0C   AE
C568 : AD A9 C4 D0 07 20 DF C5   B1
C570 : 90 C6 B0 1E A2 00 BD A4   BE
C578 : C4 F0 03 20 B3 C5 A2 01   6F
C580 : BD A4 C4 F0 03 20 B3 C5   6A
C588 : A2 02 BD A4 C4 F0 03 20   4F
C590 : B3 C5 6C D5 C4 A5 01 09   8B
C598 : 01 85 01 68 85 FF 68 85   AE
C5A0 : FE 68 0D 0D DC 29 01 F0   B4
C5A8 : 04 58 6C D7 C4 68 A8 68   F1
C5B0 : AA 68 40 8E 83 C4 8A 0A   0D
C5B8 : 8D 84 C4 0A 0A 38 ED 83   1B
C5C0 : C4 8D 85 C4 AD 8A C4 85   92
C5C8 : FE AD 8B C4 85 FF AC 84   2C
C5D0 : C4 B1 FE 99 8C C4 C8 B1   D5
C5D8 : FE 99 8C C4 4C 7D C6 AD   86
C5E0 : 88 C4 18 69 03 8D 88 C4   46
C5E8 : 90 03 EE 89 C4 AD 88 C4   4C
C5F0 : 85 FE AD 89 C4 85 FF A0   4B
C5F8 : 00 B1 FE 8D 8A C4 C8 B1   97
C600 : FE F0 31 8D 8B C4 85 FF   69
C608 : AD 8A C4 85 FE A0 00 B1   34
C610 : FE 99 8C C4 C8 C0 06 D0   E3
C618 : F6 A9 00 8D 98 C4 8D 99   AE
C620 : C4 8D 9A C4 8D A7 C4 A9   66
C628 : 01 8D 9B C4 8D 9C C4 8D   5B
C630 : 9D C4 18 60 AD AA C4 F0   67
C638 : 0F AD 86 C4 8D 88 C4 AD   E3
C640 : 87 C4 8D 89 C4 4C ED C5   B0
C648 : 20 16 C7 38 60 AE 83 C4   7F
C650 : BD 98 C4 F0 22 DE 98 C4   AD
C658 : F0 01 60 AD A8 C4 D0 0B   A1
C660 : BD 9E C4 29 FE AE 85 C4   C8
C668 : 9D 04 D4 AE 83 C4 BD 95   93
C670 : C4 F0 0A 9D 9B C4 60 DE   02
C678 : 9B C4 F0 01 60 AE 83 C4   E5
C680 : A9 00 9D A4 C4 20 04 C5   0E
C688 : C9 00 D0 12 AE 83 C4 AD   3D
C690 : A7 C4 1D A1 C4 8D A7 C4   F6
C698 : A9 01 9D A4 C4 60 10 15   77
C6A0 : C9 F8 90 29 29 07 0A AA   77
C6A8 : BD C3 C4 85 FE BD C4 C4   A3
C6B0 : 85 FF 6C FE 00 C9 61 B0   65
C6B8 : 09 AE 83 C4 9D 92 C4 4C   AC
C6C0 : 7D C6 E9 61 AE 83 C4 9D   9C
C6C8 : 95 C4 4C 7D C6 A8 AE 83   F5
C6D0 : C4 BD 92 C4 9D 98 C4 98   93
C6D8 : 29 0F C9 0C 90 01 60 0A   23
C6E0 : AA 98 4A 4A 4A 4A A8 BD   C7
C6E8 : AC C4 85 FE BD AB C4 C0   05
C6F0 : 0E F0 06 46 FE 6A C8 D0   C9
C6F8 : F6 6C D3 C4 AE 85 C4 9D   17
C700 : 00 D4 A5 FE 9D 01 D4 AE   46
C708 : 83 C4 BD 9E C4 09 01 AE   26
C710 : 85 C4 9D 04 D4 60 A9 00   D6
C718 : 8D 0F DC A9 02 8D 0D DC   14
C720 : AD 9E C4 8D 00 D4 8D 07   EA
C728 : D4 8D 0E D4 AD D7 C4 8D   A9
C730 : 14 03 AD D8 C4 8D 15 03   5F
C738 : 60 78 A5 FE 48 A5 FF 48   60
C740 : AD 86 C4 8D 88 C4 AD 87   88
C748 : C4 8D 89 C4 20 ED C5 90   77
C750 : 02 B0 1E A9 08 A2 49 8D   3D
C758 : 05 D4 8E 06 D4 8D 0C D4   BF
C760 : 8E 0D D4 8D 13 D4 8E 14   96
C768 : D4 A9 0F 8D 18 D4 20 D9   E3
C770 : C4 68 85 FF 68 85 FE 58   29
C778 : 60 60                     25
Listing 1. Der Sequenzer. Bitte mit dem MSE eingeben.
PROGRAMM : MUSIK          C800 C951
-----------------------------------
C800 : 15 C8 00 31 C8 00 31 C8   82
C808 : 00 A4 C8 00 A4 C8 00 E9   F1
C810 : C8 00 00 00 00 1B C8 21   17
C818 : C8 27 C8 60 61 EF 48 EF   49
C820 : 00 60 61 EF 48 EF 00 0C   C3
C828 : 6D 93 9A 93 8A 93 9A 93   4F
C830 : 00 37 C8 69 C8 9D C8 18   F8
C838 : 61 EF 0C BA 24 EF 0C BA   53
C840 : 24 EF 0C 6D BA B6 B6 BA   BE
C848 : B9 B5 B5 B9 18 61 B9 48   84
C850 : EF 0C C3 24 EF 0C C3 24   71
C858 : EF 0C 6D C3 BB BB C3 C2   4F
C860 : BA BA C2 18 61 C2 30 EF   F8
C868 : 00 0C 61 B3 B5 B6 B5 B3   8C
C870 : B5 B6 B5 B3 B5 6D B6 B3   6D
C878 : B3 B6 B5 B0 B0 B5 18 61   E6
C880 : B5 30 EF 0C B8 BA BB BA   90
C888 : B8 BA BB BA B8 BA 6D BB   72
C890 : B8 B8 BB BA B5 B5 BA 18   0F
C898 : 61 BA 30 EF 00 0C 6D 8A   8C
C8A0 : 93 9A 93 00 AA C8 B8 C8   CB
C8A8 : DE C8 18 61 EF 79 D1 D1   D2
C8B0 : C8 C8 C6 C6 C1 61 C1 00   95
C8B8 : 0C 61 C6 C8 CA C8 C6 C8   DF
C8C0 : 18 CA 0C C1 C3 C5 C3 C1   76
C8C8 : C3 18 C5 0C BB C1 C3 C1   E7
C8D0 : BB C1 18 C3 0C B6 B8 BA   B9
C8D8 : B8 B6 B8 18 BA 00 18 61   EB
C8E0 : EF 48 79 B6 B1 AB 61 A6   74
C8E8 : 00 EF C8 08 C9 2C C9 18   68
C8F0 : 61 EF 60 EF EF EF EF 06   A9
C8F8 : 67 9A A5 AA AA B5 BA BA   24
C900 : C5 18 61 CA EF EF EF 00   C1
C908 : 0C 61 A5 A6 A8 A6 A5 EF   39
C910 : A6 A5 A3 EF A5 A3 A1 EF   4D
C918 : A3 A1 A0 EF 60 EF 0C A3   AF
C920 : A1 9B 3C EF 60 95 18 B5   1A
C928 : EF EF EF 00 0C 61 95 96   5A
C930 : 98 96 95 EF 96 95 93 EF   BB
C938 : 95 93 91 EF 93 91 90 EF   E1
C940 : 60 EF 0C 93 91 8B 3C EF   54
C948 : 60 8A 18 AA EF EF EF 00   87
C950 : 12                        C5
Listing 2. Ein Musik-Demo. Bitte mit dem MSE eingeben.

PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →