erschienen in: GO64!
- Das Magazin für wahre Computerfreaks, Ausgaben 5-8/98
MIDI-Programmierkurs
von Rainer Buchty
Woran denkt man heute als erstes, wenn die Rede von Software-Sequencer
und Harddisk-Recording ist? Das ist eine Domäne der PCs und Macs,
welche hier dem Atari inzwischen den Rang weit abgelaufen haben. Daß
es aber mal eine Zeit vor dem Atari gab, als der C64 der
angesagte Musikcomputer war, kann sich heute kaum noch einer erinnern.
MIDI - was ist das überhaupt?
Fragt man mal so rum, was denn MIDI sei, so kommt fast todsicher die Antwort
"Das sind so Musikstücke..." - wer kann's dem durchschnittlichen PC-User
verübeln, kennt er den Begriff MIDI doch bestenfalls von dem nervigen
Gedudel, was einem von jeder zweiten Homepage mittlerweile entgegenschallt.
Eigentlich hat das aber damit gar nichts zu tun, denn MIDI ist kein spezielles
Dateiformat sondern beschreibt ein Interface zur Kommunikation von elektronischen
Musikinstrumenten untereinander. 1982 geschah nämlich etwas bis dato
recht außergewöhnliches - alle namhaften Hersteller von elektronischen
Musikinstrumenten setzen sich an einen Tisch, um einen herstellerübergreifenden
Standard zu schaffen, welcher es ermöglichen sollte, daß nicht
nur Geräte eines Herstellers untereinander kommunizieren können
sondern tatsächlich alle. Wer wie ich ein eigenes kleines Homerecording-Studio
sein eigenen nennt, kann sich das damalige Chaos nicht vorstellen. Im Gegensatz
zu heute, wo man die Geräte einfach über die MIDI-Schnittstelle
verbindet, hatte damals jeder Hersteller seinen eigenen Kommunikations"standard"
geschaffen - die natürlich untereinander höchst inkompatibel
waren. Dies betraf schon so grundlegende Sachen wie die Busstruktur (parallel
oder seriell, immerhin war man sich in dieser frühen Zeit zumindest
darüber einig, daß 8Bit das Maß aller Dinge sind - aber
das wissen wir 64er-Freaks ja schon :) und zeigte sich auch in den unterschiedlichen
Fähigkeiten der verschiedenen Bussysteme.
Die Revolution
1982 war es, wie gesagt, so weit. Das alte Chaos wurde abgelöst von
MIDI. MIDI ist übrigens eine Abkuerzung für Musical Instrument
Digital Interface. Hinter diesem unscheinbaren Kürzel verbirgt sich
nichts anderes als ein einfacher serieller Bus mit 31250 Bit/s Geschwindigkeit,
also ca. so schnell wie ein heutiges Analog-Modem bzw. halb so schnell
wie ISDN. Dieser Bus ist aufgeteilt in 16 adressierbare Kanäle, die
darauf verschickten Daten gliedern sich auf in kanalspezifische Befehle
und global Messages, d.h. Befehle, die auf gleichzeitig auf allen Kanälen
gelten.
Irgendwie scheint man vor 16 Jahren jedoch nicht so das rechte Gefühl
für die Notwendigkeit hoher Datenraten gehabt zu haben, denn aus heutiger
Sicht ist die Geschwindigkeit von MIDI hemmungslos unterdimensioniert -
aber das ist ISDN auch (wer mal so ein Ruckel-Bild gesehen hat, weiß
was ich meine). Aber damals steckte die elektronische Musik noch in den
Kinderschuhen und man dachte auch nie daran, daß es eine Musikrichtung
geben wird, bei der 180bpm kein Fehler bei der Programmierung sondern durchaus
gewollt ist :) Fairerweise muß man aber sagen, daß zur damaligen
Zeit auch noch von ganz anderen Voraussetzungen ausgegangen wurde. Man
wollte in erster Linie ein System schaffen, mit dem man mehrere Synthesizer
(Sampler gab es gerade so die ersten) miteinander vernetzen konnte, so
daß diese zentral gesteuert alle brav im Takt spielen. Die wenigen
100 Byte, die eine damalige Soundbank eines Synthesizers umfaßten,
fielen da auch nicht sehr ins Gewicht. Ganz anders heute: Ein einzelner
Synthesizersound kann leicht 4kB groß sein (z.B. eine 4AFM-Voice
des Yamaha SY77), eine komplette Soundbank von 64 Programmen kommt auf
mehrere 100kByte - und ein vernünftiges Sample ist auch hübsch
groß...
MIDI heute
Trotz aller Alterserscheinungen ist MIDI immer noch der Kommunikationsbus
unter Musikinstrumenten. Natürlich lädt heute keiner mehr seine
Samples über MIDI-Sample-Dump in seinen Maschinen, wozu haben die
Dinger alle SCSI (wer hätte damals gedacht, daß Sampler mal
interne Festplatten besitzen...), und Soundbänke auf dem Rechner zu
archivieren, ist ebenfalls out, denn jeder Synthesizer, der was auf sich
hält, hat ein Diskettenlaufwerk. Dennoch kann es dazu kommen, daß
der MIDI-Bus schlichtweg von der Fülle der Noten- und Controllerdaten
überlastet ist - abhilfe schaffen hier nur getrennte MIDI-Busse. Dies
bedeutet, daß man mehrere MIDI-Interfaces an einen Rechner anschließt,
so daß der einzelne Bus mit seinen 16 Kanälen entlastet wird.
Es gab zwar vor einiger Zeit Bestrebungen, einen neuen, schnelleren MIDI-Standard
zu entwickeln, aber offenbar ist die derzeitige Lösung befriedigend
genug, so daß dieser neue Standard vorerst nicht weiterverfolgt wird.
Ausblick
In diesem Teil ging es mehr um die Historie von MIDI, eine generelle Einführng.
Der nächste Teil befaßt sich zunächst mit den MIDI-Kommandos
und illustriert deren Einsatz an Beispielen in MIDIBASIC. Im dritten Teil
wird die Hardware des MIDI-Interfaces näher beleuchtet. Im vierten
und letzten Teil beleuchten wir die Programmierung des Interfaces in Assembler.
MIDI - das unbekannte Wesen (Teil 2)
Nachdem wir im letzten Teil auf die Geschichte von MIDI eingegangen sind,
wollen wir uns heute mit der Kommunikation über MIDI befassen.
Befehlsformate
Generell unterscheidet man zunächst zwischen kanalspezifischen und
system-weiten Befehlen. Wie schon im letzten Teil erläutert, zerfällt
der MIDI-Bus ja in 16 Kanäle - wie der Name vermuten läßt,
wirken kanalspezifische Befehle nur auf dem jeweiligen Kanal, wohingegen
die systemweiten Nachrichten global wirken. Daten stellen ebenfalls eine
eigene "Befehlsgruppe" dar - sie erkennt man daran, daß bei Datenbytes
stets das Bit 7 gelöscht ist. Messerscharf folgert man daraus, daß
pro Datenbyte auch nur 7 und nicht 8 Bit übertragen werden können,
so daß man 8Bit-Daten zur übertragung geeignet zerlegen muß.
Datenbyte
Doch zurück zu den Befehlen. Zunächst wollen wir uns die kanalspezifischen
Befehle ansehen. Diese beinhalten Kommandos wie Note-On/Note-Off (Taste
drücken und wieder loslassen), Controller (Spielhilfen), Program Change
(Klangprogrammumschaltung) und das Pitch-Bend-Wheel (Tonhöhenbeugungsrad
ist wirklich ein häßliches Wort). Einem kanalspezifischem Befehl
folgen ein bis zwei Datenbytes (ist in der Zwischenzeit kein anderer Befehl
gesendet worden, so verschickt man übrigens den Befehl nicht nochmal
sondern nur noch die Daten - zwar keine Datenkompression, aber immerhin).
So ein Befehlsbyte schaut folgendermaßen aus:
1 |
cmd |
cmd |
cmd |
chn |
chn |
chn |
chn |
Befehlsbyte
Zunächst erkennt man das gesetzte Bit 7, klar, es ist ja auch ein
Befehl. Die nächsten drei Bits geben den Befehl an, die untersten
vier Bit geben den zu verwendenden MIDI-Kanal an. Doch keine Regel ohne
Ausnahme - dieses Szenario gilt nur für kanalspezifische Befehle,
sind die drei Befehlsbits alle auf 1, so handelt es sich um eine systemweite
Nachricht und die untersten vier Bit werden nun nicht als Kanal sondern
als Befehl interpretiert.
Alles kanalisiert - die Kanaldaten
Hier kommt nun eine Auflistung aller kanalspezifischen Befehle mit kurzer
Erklärung. Damit man auch gleich damit rumspielen kann, sind die entsprechenden
MIDIBASIC-Befehle mitangegeben:
-
Note on ($9x)
Wie der Name vermuten läßt, schlägt man hiermit eine
Taste an. Die dem Befehl folgenden zwei Datenbytes geben die zu spielende
Taste sowie den Anschlag, sprich wie stark man auf die Taste haut, an.
Nachdem wir für die Daten nur 7 Bit zur Verfügung haben, sind
Tonumfang und Anschlagstärke auf 128 Werte (0-127) begrenzt. Eine
Differenz von 1 steht bei der Tonhöhe für einen Halbton, der
Wert 64 repräsentiert das C-3 - viel Spaß beim Tastenzählen
:)
MIDIBASIC-Befehl: on channel, key, velocity
-
Note off ($8x)
Das genaue Gegenteil von Note on - und verfügt ebenfalls über
zwei Datenbytes zur Angabe von Taste und "Anschlag", der hier allerdings
die Loslaßgeschwindigkeit darstellt. Dieser Befehl ist essentiell,
will man eine einmal gespielte Note auch wieder loslassen. Die Länge
der gespielten Note ergibt sich somit aus der Zeitdifferenz zwischen Note
on und Note off.
MIDIBASIC-Befehl: off channel, key, velocity
-
Aftertouch ($Ax, $Dx)
Aftertouch - das ist kein liebevoller Klaps auf den Po sondern vielmehr,
wie stark man auf eine Taste nach dem Anschlag drückt. Diesen gibt
es auch in zwei Varianten, nämlich channeled ($Cx) und polyphonic
($Ax). Im ersten Falle folgt dem Befehl nur ein Datenbyte, der Druckwert,
welches für alle Tasten auf diesem Kanal gilt. Der polyphone Aftertouch
hingegen ist auch tastenspezifisch, d.h. auf den Befehl folgen zwei Datenbytes,
nämlich die Taste und der Druckwert.
Channel-Aftertouch wird von jedem Synthesizer/Sampler verstanden und
auch (sofern er über eine Tastatur verfügt) gesendet. Polyphoner
Aftertouch jedoch wird von den wenigsten Geräten verstanden, noch
weniger senden ihn. Dies ist zwar vom Standpunkt der Industrie verständlich,
die die Hardware möglichst billig halten will, als Musiker hingegen
stört mich das ganz ungemein.
MIDIBASIC-Befehl: cpr channel,amount
(Channel-AT)
ppr channel,key, amount (polyphonic AT)
-
Controller ($Bx)
Die Controller sind sozusagen das Salz in der Suppe. All die schönen
Sachen wie getriggerte Filtersweeps, wie sie gerade im Dance-Bereich so
beliebt sind, wären ohne die Controller unmöglich. Eine Handvoll
der 127 möglichen Controller wurden mit der Schaffung des MIDI-Standards
definiert, leider hat man es versäumt, über die unbelegten Controller-Adressen
zu wachen - so daß hier Mitte der 80er ein regelrechter Wildwuchs
einsetzte.
Auch hier gilt: Nicht jeder Synthesizer versteht alle Controller. Bekannte
und genormte Controller sind beispielsweise das Modulationsrad (1), der
Breath-Controller (2), Modulations-Pedal (4) und Lautstärke (7). "Ubrigens
ist nicht jeder Controller regelbar, es gibt auch Schalter - beispielsweise
das Haltepedal (64). Bei Schaltern gilt: Der Wert 0 steht für aus,
127 für an.
MIDIBASIC-Befehl: ctrl channel, controller,
value
-
Program-Change ($Cx)
Mit diesem Befehl wird das aktuelle Klangprogramm umgeschalten. Nachdem
das Limit auf 127 Programme den Herstellern zu wenig erschien, gibt es
zusätzlich einen Controller, welcher zwischen Programmbänken
umschaltet
- dieser ist aber (hurra) herstellerspezifisch und nicht genormt.
MIDIBASIC-Befehl: prg channel, program
-
Pitch-Bend ($Ex)
Das deutsche Wortungetüm Tonhöhenbeugung beschreibt die Wirkung
dieses Befehls recht treffend - dennoch drehe ich lieber am Pitch-Bend-Wheel
als am Tonhöhenbeugungsrad. Da das Ohr doch sehr penibel sein kann
und gerade Tonsprünge sehr fein auflöst, hat man dem Pitch-Bend-Wheel
auch eine Auflösung von 14 Bit mitgegeben, folgerichtig hat der Pitch-Bend-Befehl
auch zwei Datenbytes, nämlich das LSB und das MSB. In ihrer unergründlichen
Weisheit haben jedoch einige Synthesizerhersteller beschlossen, hiervon
nur das MSB zu verwerten...
MIDIBASIC-Befehl: bend channel, value(0-16384)
Nachrichten fürs Volk
Neben den kanalgebundenen Befehlen gibt es auch noch die sog. system wide
messages. Diese teilen sich ihrerseits wieder auf in Real-Time- und Non-Real-Time-Messages.
Allen gemein ist, daß sie (fast) aus nur einem einzigen Byte bestehen,
es gibt (fast) keine zwingenden Datenbytes. Die NRT-Messages liegen hierbei
zwischen $F0 und $F7, Realtime-Messages ab $F8. Realtime heißt, daß
die Daten - nach Möglichkeit des jeweiligen Endgerätes - in Echtzeit
interpretiert werden müssen. Hierunter fallen beispielsweise die MIDI-Clocks
(es gibt deren zwei, eine für Play - $F8 - und eine für Pause
- $FD) sowie die Sequencer-Steuerbefehle Start ($FA), Continue ($FB) und
Stop ($FC). Die Befehle Active Sensing ($FE) und System Reset ($FF) nehmen
hierbei eine Sonderstellung ein und werden - mal wieder - nicht zwangsläufig
von allen Geräten auch wirklich verstanden.
Die NRT-Messages umfassen weitere Sequencer-Befehle, die jedoch nicht
in Echtzeit ausgeführt werden müssen (was auch nicht möglich
wäre), nämlich die taktgenaue Sequencer-Positionierung ($F2 gefolgt
von zwei Datenbytes, welche den Takt als 14Bit-Zahl LSB/MSB enthalten),
mit $F3 wird ein Song angewählt - hier reicht ein Datenbyte als Parameter.
Moderne Synthesizer verlieren zwar nicht ihre Stimmung wie die alten analogen,
jedoch gibt es aus historischen Gründen noch den Tune-Befehl ($F6),
welcher die Synthesizer dazu veranlassen soll, ihre Oszillatoren zu stimmen.
Nun zu einem echten Power-Befehl - dem System-Exclusive-Befehl ($F0).
Er leitet einen allgemeinen Datenblock ein, die folgenden zwei Bytes bezeichnen
das Ziel und die Herstellerkennung, alles danach ist nicht mehr spezifiziert
und kann so ziemlich alles beinhalten. Hiermit ist es beispielsweise möglich,
den Synthesizer komplett fernzubedienen, d.h. auch die Benutzeroberfläche.
Oder - wie im Falle des Yamaha SY77 - man erreicht sogar Funktionen, die
normalerweise gar nicht zugänglich sind. Typische Anwendungen des
SysEx-Dumps ist beispielsweise der Austausch von Klangprogrammen, Samples
oder auch Sequencer-Daten. Beendet wird solch eine "Ubertragung mit ($F7),
dem SysEx-Endekennzeichen.
Wer hiermit experimentieren will, kann unter MIDIBASIC folgende Befehle
nutzen:
-
out c, byte gibt ein beliebiges Byte (8 Bit!) auf Kanal
c aus. Bei Verwendung aller 8 Bits sollte der Kanal auf 0 gesetzt werden
-
x=usr(0) liest ein Byte aus dem Empfangspuffer
Na, raucht Euch der Kopf? Gut so. Freut Euch auf die nächste Folge,
wenn wir in die Hardware der MIDI-Interfaces eintauchen.
MIDI - was steckt dahinter? (Teil 3)
Sie wurden einst teuer verkauft, manche kamen gar komplett mit Sequencer-Software
als Modul - die Rede ist von den MIDI-Interfaces. Wie bei so vielen Dingen
in der Elektronik ist auch hier nicht verständlich, wieso ein Teil,
das einen Bauteilewert von gerade mal DM10,-- hat, fuer ein vielfaches
dieses Wertes verkauft wird - eigentlich ist in so einem Interface nämlich
gar nichts drin.
Die Zutaten
Jedes MIDI-Interface besteht im wesentlichen aus einem Sende/Empfangsbaustein
(UART genannt, ausgeschrieben bedeutet es Universal Asynchronous Receiver/Transmitter)
sowie etwas Elektronik drumherum, die dafür sorgen soll, daß
im ungünstigsten Falle lediglich diese (billige) Elektronik stirbt
und nicht der UART oder gar dahinter liegende Logik - bei der Entwicklung
des MIDI-Interfaces war Robustheit gefragt. Und ich kann es bestätigen,
man kann wirklich unter Betrieb die MIDI-Kabel umstecken, voll statischer
Elektrizität an die MIDI-Buchse fassen - es passiert nichts. (Das
passende Gegenbeispiel wäre der CIA 6526 - der geht ja schon beim
scharf anschauen kaputt...) Viel mehr ist es tatsächlich nicht, ein
UART, die Schutzelektronik (sogenannte Optokoppler) und das war's eigentlich
auch schon.
Close Up
Alle MIDI-Interfaces fuer den C64 verwenden den UART6850 als Schnittstellenbaustein.
An diesem hängt eine externe 2MHz-Takterzeugung, welche als Schrittmacher
fuer die serielle Schnittstelle des UART fungiert. Der serielle Ausgang
wird ueber Treiberbausteine gepuffert und direkt an die MIDI-Out-Buchse
geschickt. Das MIDI-In-Signal wird ueber einen Optokoppler galvanisch von
der Außenwelt getrennt und ggf. über eine MIDI-Thru-Buchse durchgeschleift
- tatsächlich sind so ziemlich alle MIDI-Interfaces fuer den C64 identisch,
meist unterscheiden sie sich nur in den verwendeten Optokopplern. Kommerziell
vertriebene MIDI-Interfaces gab es in Europa vornehmlich von C-LAB, Steinberg
und Jellinghaus, aus den USA schwappten auch Exemplare von Dr. T's und
Opcode über den großen Teich. Selbstbauprojekte wurden seinerzeit
in der Zeitschrift KEYBOARDS sowie
in diversen 64er-Sonderheften veröffentlicht.
Das MIDI-Interface wird über den I/O1-Bereich adressiert, liegt
also zwischen $DE00 und $DEFF. Dies hat historische Gründe, denn zum
damaligen Zeitpunkt war der I/O2-Bereich bereits von 80 Zeichen-Karten
bzw. dem CP/M-Modul besetzt. Ebenfalls im I/O2-Bereich liegt übrigens
die REU, so daß im Parallelbetrieb des MIDI-Interfaces mit einer
REU keine direkten Probleme auftreten sollten.
Was tut man nun, wenn die Lieblingshardware auch im I/O1-Bereich operiert
bzw. man im Besitz eines exotischen MIDI-Interfaces ist, das via I/O2 angesprochen
wird? Am einfachsten ist hier wohl eine kleine Modifikation des Interfaces,
hierbei hat man zwei Alternativen:
-
Änderung des Interface-Adreßraums von I/O1 auf I/O2
Tatsächlich gab es seinerzeit auch von einem Hersteller MIDI-Interfaces,
die im I/O2-Bereich lagen, so abwegig wäre die Idee also nicht. Allerdings
arbeitet das Gros der MIDI-Software nicht mit Interfaces im I/O2-Bereich
zusammen, man muß diese erst händisch patchen. Die stellt allerdings
kein größeres Problem dar, da man lediglich jedes Vorkommen
der Adressen $DE04 bis $DE07 durch $DF04 bis $DF07 ersetzen muß.
-
Ausdekodierung des I/O1-Bereiches
Ungleich aufwendiger wäre diese Variante, bei der man mit zusätzlicher
Hardware den I/O1-Bereich ausdekodiert und anstatt der I/O1-Leitung die
jeweilige Chipselect-Leitung an die "kollidierende Hardware" und das MIDI-Interface
gibt. Auch hier kommt man natürlich nicht umhin, bestehende Software
zu patchen.
Alles unter Controller
Ok, ich geb's zu, die Überschrift hab ich geklaut. Trotzdem geht es
jetzt ans eingemachte, denn so ein UART will schließlich auch programmiert
werden. Dazu hat das Ding vier Register. Warum diese ab der Adresse $DE04
liegen und nicht ab $DE00, wissen die Götter - immerhin wurde uns
Sterblichen die Bedeutung der einzelnen Register mitgeteilt:
(1) Das Control Register ($DE04)
Beim CR handelt es sich um ein Write-Only-Register, es hat folgenden
Aufbau
Bit |
Funktion |
7 |
Receive Interrupt Enable Bit |
6, 5 |
Transmit Control Bit |
4-2 |
Word Select Bits |
1, 0 |
Counter Divide Select |
Control Register
Beginnen wir zunächst mit dem Counter Divide Select. Mit diesen
zwei Bits wird die Taktrate der seriellen Schnittstelle des 6850 bestimmt,
folgende Teilerverhältnisse kann man einstellen:
Bitmuster |
Funktion |
00 |
1:1 |
01 |
1:16 |
10 |
1:64 (MIDI) |
11 |
Reset |
Counter Divide Select
Bei einem Takt von 2MHz ergeben sich also die Bitraten 2MBit/s, 125kBit/s
und 31.25kBit/s - wohlgemerkt, die Einheiten stehen hier zur Basis 10,
wie man das in Physik mal gelernt hat (man vergißt ja zu leicht,
daß 1k-irgendwas eben nicht 1024 Stück sind). Das Bitmuster
11 stellt hierbei kein Teilverhältnis ein, sondern setzt den 6850
zurück, man muß dieses Bitmuster explizit wieder lösen,
um den 6850 in einen arbeitsfähigen zustand zu bringen.
Mit den Word Select Bits werden Wortlänge, Parität und Anzahl
der Stop-Bits eingestellt. MIDI-Standard ist eine Wortlänge von 8
Bit, kein Parity-Check und 2 Stop-Bits, der Vollständigkeit halber
auch hier wieder alle möglichen Bitmuster mit Bedeutung:
Bitmuster |
Funktion |
000 |
7 Bits, gerade Parität, 2 Stopbits (7e2) |
001 |
7 Bits, ungerade Parität, 2 Stopbits (7o2) |
010 |
7 Bits, gerade Parität, 1 Stopbit (7e1) |
011 |
7 Bits, ungerade Parität, 1 Stopbit (7o2) |
100 |
8 Bits, keine Parität, 2 Stopbits (8n2, MIDI) |
101 |
8 Bits, keine Parität, 1 Stopbit (8n1) |
110 |
8 Bits, gerade Parität, 1 Stopbit (8e1) |
111 |
8 Bits, ungerade Parität, 1 Stopbit (8o1) |
Word Select
Die nächsten zwei Bits sind die Transmitter Control Bits. Mit diesen
kann eignestellt werden, ob das TDR-Bit des Status-Registers (s.u.) einen
Interrupt auslöst. Weiterhin kann der Request-to-Send Ausgang gesetzt
werden, allerdings ist diese Leitung für MIDI nicht genutzt, so daß
nur Bit 5 interessant ist: Soll ein Sende-Interrupt ausgelöst werden,
so setzt man dieses Bit auf 1, andernfalls auf 0. Bit 6 klemmt man - da
nicht benötigt - konsequent auf 0.
Kommen wir zu Bit 7, dem Receive Interrupt Enable-Bit. Hiermit kann
eingestellt werden, ob beim Empfang eines Datenbytes ein Interrupt ausgelöst
werden soll - hierzu setzt man dieses Bit auf 1, andernfalls auf 0.
(2) Das Transmit-Data-Register ($DE05)
Ist das TDRE-Bit des Status-Registers (s.u.) gesetzt, so kann man ein
Datenbyte in das TDR schreiben. Hierauf wird unmittelbar das TDRE-Bit gelöst
und bleibt solange gelöscht, bis die "Ubertragung des Datenbytes beendet
ist.
(3) Das Status-Register ($DE06)
Das Status-Register hat folgenden Aufbau:
Bitmuster |
Funktion |
Bit 7 |
Interrupt Register (IRQ) |
Bit 6 |
Parity Error (PE) |
Bit 5 |
Receiver Overrun (OVRN) |
Bit 4 |
Framing Error (FE) |
Bit 3 |
Clear to Send (CTS) |
Bit 2 |
Data Carrier Detect (DCD) |
Bit 1 |
Transmit Data Register Empty (TDRE) |
Bit 0 |
Receive Data Register Full (RDRF) |
Status Register
Interessant sind hierbei vornehmlich die ersten beiden Bits. Das RDRF-Bit
wird dann auf 1 gesetzt, wenn ein vollständiges Datenbyte empfangen
wurde. Wir ddieses Datenbyte gelesen, so wird das RDRF-Bit wieder auf 0
gesetzt, um anzuzeigen, daß der Inhalt des Receive Data Registers
nun nicht mehr gültig ist. Entsprechend wird das TDRE-Bit auf 1 gesetzt,
wenn alles zur "Ubertragung eines Datenbytes fertig ist. Wird ein Datenbyte
in das Transmit Data Register geschrieben, so wird dieses Bit auf 0 gesetzt,
um anzuzeiten, daß jetzt mit der "Ubertragung begonnen wurde und
kein neues Datenbyte in das Transmit Data-Register geschrieben werden darf.
Nach erfolgreicher Transmission wird das TDRE-Bit wieder auf 1 gesetzt.
(4) Das Receive Data Register ($DE07)
Aus diesem Register kann man ein empfangenes Datenbyte auslesen. Die
Gültigkeit des im RDR enthaltenen Bytes wird durch das gelöschte
(!) RDRF-Bit im Status-Register angezeigt.
Viel Theorie dieses Mal, aber keine Angst, im nächsten und gleichzeitig
letzten Teil wird es sehr praktisch - dort lernt Ihr grundlegende MIDI-Programmiertechniken
kennen. Und ich verspreche, ob Assembler-Freak oder BASIC-Fan, alle werden
auf ihre Kosten kommen.
Into deep - MIDI Programmierung in der Praxis (Teil 4)
Erfolgreich habt Ihr Euch nun durch die letzten 3 Teile des MIDI-Kurses
gekämpft. Eventuell habt Ihr sogar schon etwas mit dem MIDIBASIC rumgespielt
und folgendes festgestellt: Programmiert sich ja ganz nett, aber irgendwie
ist "timing-genau" in BASIC ein Fremdwort. Wen wundert's, ist Interrupt-Programmierung
ja auch nicht gerade das Haupteinsatzgebiet unseres geliebten
BASIC-Interpreters.
Aber da war doch noch die Programmiersprache der Gurus... Assembler.
(Einer der seltsamen Zufälle des Lebens bedingte just beim Schreiben
dieses Satzes, daß sich in der lokalen Chatbox, in der ich gerade
nebenbei online bin, ein User namens "Assembler" einloggt - life is strange,
isn't it?) Zurück zum Thema ... Letzte Folge habe ich Euch ja mit
den Registern des 6850 gequält - und in dieser Folge erfahrt Ihr sogar,
wie man sie verwendet.
Aktivieren wir zunächst mal das MIDI-Interface. Dies geschieht
in zwei Schritten - zuerst setzt man den 6850 zuröck, anschließend
stellt man den gewönschten Arbeitsmodus ein. Das sieht so aus:
init: LDA #$03 ; Reset
6850 STA $DE04
setup: LDA #$92 ; 31625Bit/s,
8N1, Receive Interrupt (#$12 för Polling)
STA $DE04
Will man - wie im obigen Beispiel - das Interface im Interruptbetrieb
nutzen, faßt man das ganze in SEI / CLI ein und verbiegt die Interruptvektoren
entsprechend.
Der 6850 weiß nun, auf einen MIDI-Datenstrom zu reagieren, aber
wie empfängt und sendet man denn nun Daten? Zunächst das Empfangen,
das empfangene Datenbyte steht anschließend im Akku:
rx: LDA $DE06 ; warten, ob neue Daten empfangen
wurden
LSR
BCC RX
LDA $DE07 ; ...und diese einlesen
...und hier das Senden. Das zu sendende Byte wird hierbei im X-Register
übergeben.
tx: LDA $DE06 ; warten, ob Sender bereit
LSR
LSR
BCC TX
STX $DE05 ; zu übertragendes
Datenbyte losschicken
Das war auch schon alles an Basis-Routinen. Nehmen wir einmal an, wir
wollten eine beliebige Note auf einem beliebigem Kanal mit beliebiger Anschlagstärke
(Falls das mein alter Deutschlehrer Dr. Hugenschmidt lesen sollte - ich
weiß: 3x 'beliebig' in einem Satz ist stilistisch unter aller Kanone!)
spielen, dann könnte das folgendermaßen aussehen:
play: LDA #$90
ORA channel
TAX
JSR tx
; tx ist natürlich mit RTS abgeschlossen
LDX key
JSR tx
LDX velocity
JSR tx
Läßt sich natürlich wie immer beliebig (schon wieder
dieses Wort) erweitern. Und wer sich jetzt beschwert, daß man hier
ja gar nicht in Rasterzeilen rechnen muß, dem sei gesagt, daß
das menschliche Ohr sehr empfindlich ist - und schon minimale Verzögerungen
deutlich hörbar sind. Schon 5ms Verzögerung machen sich akustisch
sehr bemerkbar - kalkuliert also Eure Ausgabe-Routinen sorgfältig
und wenn Ihr komplexe Arrangements bastelt, denkt an die relativ niedrige
Geschwindigkeit von MIDI und daran, daß eine Note zu spielen (Anschlag,
Loslassen) ganze sechs Bytes benötigt. Wir erinnern uns - 31250 Bit/s,
10 Bit pro übertragenem Datenbyte macht somit 3125 Bytes pro Sekunde.
Viel Luft bleibt da also nicht. Komischerweise sind aber die Bestrebungen
der Musikindustrie, einen neuen, besseren MIDI-Standard zu schaffen, offenbar
eingeschlafen.
Schlußwort
Das war also der vierte und letzte Teil des MIDI-Kurses. Ich hoffe mal,
er hat zumindest einige von Euch interessiert. Wie Anfang April auf der
Mailing-List diskutiert, kann man so ein MIDI-Interface natürlich
auch zu anderen Dingen vergewaltigen als nur zum MIDI-Daten-Übertragen,
z.B. könnte man damit auch einen einfachen 4-Draht-Kommunikationsbus
aufbauen. Nachdem es eigentlich fuer jedes System ein MIDI-Interface gibt,
ließe sich hiermit ein zwar langsames, aber durchaus hobbytaugliches
Netzwerk aufbauen.