Bits und Bytes

Aus Synthesizer Wiki
Version vom 6. Januar 2007, 20:16 Uhr von MIK (Diskussion | Beiträge)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Um die genauen Abläufe innerhalb des MIDI-Protokolls zu verstehen, und vor allem, um zu wissen, auf welche verschiedenen Arten Zahlen in der digitalen Welt dargestellt werden können, sollen hier einige Grundlagen erläutert werden, um dieses Wissen aufzubauen.

Digitale Darstellung von Werten im Computer

Digital ist abgeleitet von dem lateinischen Wort "Digitus", der Finger, da nicht nur früher, sondern auch heute in Abwesenheit eines Taschrechners gelegentlich die Finger zum Rechnen herangezogen werden. Und auch, wenn Finger an für sich analoge Gerätschaften sind, geht es hier um die digitale Nutzung "an" oder "aus".

Einen Unterschied gibt es aber zwischen dem Menschen un dem Computern bei der Nutzung der Finger zum Zählen. Während unsere Finger zum Zählen alle die gleiche Wertigkeit haben, also 4 erhobene Finger den Wert 4 darstellen, geht der Computer hier sparsamer mit seinen Finger, die wir in Zukunft wieder ordentlich "Bits" nennen werden, um. Bits werden zusammengefasst zu Bytes (also der Hand, wenn man so will). Ein Byte hat 8 Bits. Um hier jetzt nicht nur von 0 bis 8 zählen zu können, hat jedes Bit in diesem Byte eine besondere Wertigkeit. Das unterste Bit, auch Bit 0 genannt, hat den Wert "1". Hiermit lassen sich Werte von 0 bis 1 darstellen, also wird als nächstes Bit (Bit 1) eines mit dem Wert "2" benötigt. Jetzt haben wir 2 Bits, eines kann 0 oder 2 bedeuten, eines 0 oder 1. Durch deren Addition können also die Werte 0, 1, 2 und 3 dargestellt werden, das nächste Bit (Bit 2) bekommt also den Wert 4, womit wir bei nun 3 Bits Werte von 0 bis 7 darstellen können, 8 Möglichkeiten also. Berechnet ist das einfach 2 ^ Anzahl Bits. Womit wir bei den 8 Bits genau 256 Möglichkeiten haben, Werte von 0 bis 255.

Wie man schon an der Numerierung der Bits sieht, fangen Computer immer bei 0 an zu zählen. Und es ist auch gut so. Nicht jeder kennt spontan die Antwort auf die Frage "welche Wertigkeit hat Bit 4?". Mathematisch kann diese Antwort aber einfach ermittelt werden - 2 ^ 4, also 2 * 2 * 2 * 2 = 16.

Und die negativen Zahlen? Jetzt wird es etwas kompliziert. Wir haben insgesamt nur 256 Möglichkeiten mit unseren 8 Bits. Die haben wir schon von 0 bis 255 verbraten. Also haben wir nichts mehr übrig für negative Zahlen. Also werden die gleichen 8 Bits an den Stellen, wo negative Zahlen benötigt werden, einfach ein wenig anders verwendet. Eine einfache Methode wäre die Verschiebung des Wertebereichs. Wenn wir von den 0 bis 255 einfach 128 abziehen (weils in Bits so ne schöne glatte Zahl ist, 2 ^ 7), dann haben wir einen Bereich von -128 bis 127. Das ist ja einfach. Zu einfach. Es funktioniert nämlich ganz problemlos, aber bringt andere Probleme mit sich, wenn an Stellen in einem Programm beide Arten von Zahlen verwendet werden sollen, die mit Vorzeichen und die ohne Vorzeichen. Daher arbeitet ein Computer heutzutage mit dem Standard, daß die Werte von 0 bis 127 in beiden Reihen gleich aussehen. Unterschiedlich wirds erst ab 128. Hier ist in der Reihe ohne Vorzeichen der Wert 128 gemeint. In der Reihe mit Vorzeichen jedoch -128. Also kommt direkt nach der 127 die -128, wenn man das so durchzählt. Wie unpraktisch. Es gibt aber an einer anderen Stelle wieder mehr Ordnung - wenn man bei -128 anfängt, zu zählen und bis -1 zählt, da sind dann alle Bits auf "an". Der nächste Wert wäre, da wir keine weiteren Bits haben, dann alle Bits "aus". Und das entspricht der 0. So, nun ist sicherlich der Zeitpunkt erreicht, wo es etwas unübersichtlich wird, daher wird nun in den nächsten Bildern verdeutlicht, wie so ein Byte genau "funktioniert".

Note to myself: bilder malen und hier einfügen :)

Ein Streifzug durch die Zahlensysteme

Wem jetzt alle Zahlen hier "krumm" vorkommen, weil wir ja Zahlen wie 10, 20, 100, 1000 als "glatt" betrachten, dem sei mit einem neuen Zahlensystem geholfen: dem Hexadezimalsystem. Das Hexa hat nichts mit dem Hexer zu tun, sondern steht schlicht und einfach für "6". Entgegen unserem Dezimalsystem, welches 10 verschiedene Werte pro Stelle umfasst, verwendet das Hexadezimalsystem 16 verschiedene Werte. Rechnet man nun herum, kommt man auf folgende Stellenwertigkeiten, zuerst im Dezimalsystem, dann im Hexadezimalsystem

10 ^ 0 = 1
10 ^ 1 = 10
10 ^ 2 = 100
10 ^ 3 = 1000

16 ^ 0 = 1
16 ^ 1 = 16
16 ^ 2 = 256
16 ^ 3 = 4096

Mehr brauchen wir im Moment nicht, mit diesen Stellenwertigkeiten kann man schon 16 bit darstellen, bei MIDI haben wir es höchstens mit 14 bit zu tun. Wo wir gerage bei Zahlensystemen sind...

2 ^ 0 = 1
2 ^ 1 = 2
2 ^ 2 = 4
2 ^ 3 = 8

Das haben wir doch vorhin im Prinzip schon gesehen. Richtig. Das Binärsystem, so heisst dieses Zahlensystem, wenn man die Bits einzeln schreiben will.

Der einzige Haken an der Sache ist nun, dass wir nur die Ziffern 0-9 kennen, was ist also mit den 6 neuen Werten für das Hexadezimalsystem? Ganz einfach, sie heissen A, B, C, D, E und F.

Im Prinzip kann man sich nun Zahlensysteme zusammen basteln, wie es einem Gefällt. Radix 26 z.B. mit "Ziffern" von A-Z, Radix 36 mit Ziffern von 0-9 und A-Z, man kann das Spiel recht weit treiben, die unterschiedlichsten Zahlensysteme sind im Einsatz. Und wenn man nun den deutschen Begriff "Radix" vom mathematischen Fachwort auf ein allgemein verständliches Wort umsetzt, kommt "Basis" heraus, englisch "base", und damit ist "base64" auch ein Zahlensystem. Dieses wird im Internet sehr viel verwendet, z.B. um Daten so zu codieren, dass sie sich mit einem Zeichenvorrat von 64 Zeichen darstellen lassen, egal, welchen Wertebereich die ursprünglichen Daten umfassten. Dass hier 64 verwendet wurde, liegt auch wieder an den Bits. 64 ist eine "glatte" Zahl für den Computer, sie entspricht genau dem Wertebereich, der mit 6 Bits darstellbar ist. Dadurch ist es sehr einfach, durch eben diese 64 zu teilen. Nimmt man ein Byte, und will es durch 64 teilen, sind die obersten beiden Bits des Bytes das Ergebnis (natürlich 6 bits nach rechts, also in Richtung Bit 0, geschoben), und die unteren 6 Bits der Rest.

All das klingt vielleicht etwas sehr abgeschweift, aber gerade bei SysEx kommt der Fall sehr oft vor, dass auf solche Arten Bits herumgewuchtet werden müssen, um mit den 7 zur Verfügung stehenden Bits für Daten alles abbilden zu können, was man so übertragen möchte. Und dazu gibt es die unterschiedlichsten Varianten, wo das Byte, welches übertragen werden soll, "durchgesägt" wird, je nachdem, wie viel Arbeit sich die Firmware des Zielgerätes machen möchte, um seine Bytes wieder zusammen zu setzen.

Apropos Firmware - diese ist immer in kompletten Bytes vorzufinden (intern sind das vielleicht sogar 16 oder 32 Bits, mit denen gearbeitet wird, dabei werden mehrere Bytes zusammen gefasst). Um diese effizient zu übertragen, werden z.B. 7 volle Bytes hergenommen, bei allen die Köpfe (also Bit 7, das höchste Bit) abgeschnitten, diese 7 gekürzten Bytes raus geschickt, und danach die 7 abgeschnittenen Bits in einem weiteren MIDI-Byte übertragen. Dies ist die effizienteste Art, 8bit-Daten via MIDI zu übertragen.

Für den nächsten Abschnitt ist es noch wichtig, wie hexadezimale Zahlen zu erkennen sind. Dazu gibt es mehrere Varianten, wovon die Folgenden die gängigsten sind:

0xff
ein vorangestelltes "0x" kennzeichnet die Hexadezimalzahl. Hauptsächlich in Programmiersprachen verwendet, C, C++, Java als Beispiele.
FFh
alternativ auch ffh, FFH, ffH, es spielt keine rolle, ob die Zeichen groß oder klein sind. Diese Schreibweise ist schon etwas betagter, findet sich aber in einigen MIDI-Dokumentationen bei den SysEx-Definitionen. In diesem Falle also ein der Zahl folgendes "h" oder "H" als Kennzeichnung.
$ff
auch schon etwas betagt, das vorangestellte Dollarzeichen kennzeichnet die Zahl als hexadezimal.

Generell ist es übrigens gleichgültig, ob die "Ziffern" A-F groß oder klein geschrieben werden.

Ein paar Übungen

Bevor es nun ans SysEx-Rechnen geht, schauen wir uns mal noch ein paar kleine Rechnungen mit hexadezimalen Zahlen an.

rechne die Zahl $5e ins Dezimalsystem um
Rechenweg: die rechte Stelle hat die Wertigkeit 1 (16 ^ 0), die linke die Wertigkeit 16 (16 ^ 1). Das E hat den Wert 14. Weil nach der 9 das A kommt, also den Wert 10 hat, B ist 11, C ist 12, D ist 13, E ist 14 und F ist 15. Also haben wir für diese Zahl folgendes zu rechnen: 5 * 16 + 14 = 94. Wer es nicht glaubt, schaltet seinen Windows/Mac-Rechner auf "Wissenschaftlich" oder "Programmierer" um und kann dann zwischen hexadezimalen und dezimalen Zahlen umrechnen.

So, jetzt den automatischen Umrechner aber wieder weg, hier gehts weiter:

rechne die Zahl 123 ins Hexadezimalsystem um
Rechenweg: die dritte Stelle von rechts im Hexadezimalsystem entspricht 256 (16 ^ 2), also können wir das ignorieren, fangen wir mit der zweiten Stelle von rechts mit der Wertigkeit 16 (16 ^ 1) an und dividieren unsere 123 dadurch. Das Ergebnis ist 7 (die Nachkommastellen hier bitte wegwerfen, nichts runden!). Da ein Taschenrechner meistens nicht den Rest anzeigt, ist jetzt nur der im Vorteil, der auf dem Papier klassisch dividiert hat, er kennt den Rest schon. Der Rest muss ihn ausrechnen, indem er die 7 * 16 von den 123 substrahiert, danach lautet der Rest lautet 11. Also haben wir unsere beiden Stellen, 7 und 11, im Hexadezimalsystem bedeutet das dann 0x7b.

Da war doch noch was mit negativen Zahlen? Jetzt wirds fies!

rechne die Zahl aah (vorzeichenbehaftet 8bit) ins Dezimalsystem um
Rechenweg: Wir wissen aufgrund des Bit7, dass es sich um eine negative Zahl handelt. Wir wissen, dass 80h -128 ist, 81h ist -127, das geht weiter bis ffh, was -1 ist. Also können wir relativ einfach rechnen, indem wir das Bit7 weglassen, und den Rest zu -128 dazu addieren. Bei aah wäre das dann 2ah zum Rechnen. 2ah ist 2 * 16 ^ 1 + 10 * 16 ^ 0 = 2 * 16 + 10 * 1 = 32 + 10 = 42. Und jetzt addieren wir -128, bzw. substrahieren 128. Das Ergebnis sind -86. Um das jetzt mit dem Taschenrechner nachzuvollziehen, muss die hexadezimale Zahl "aa" möglicherweise mit "f"s aufgefüllt werden, damit der Rechner auch eine negative Zahl erkennt, weil er möglicherweise nicht nur mit 8 bit, sondern mit 16, 32, oder gar 64bit arbeitet. Der Windows-Rechner ist übrigens scheinbar generell zu doof dazu, aber wenn man die -86 nach hexadezimal umrechnet, bekommt man die "AA" mit nem haufen führender "F"s raus.

So, nun kann jeder für sich noch ein wenig experimentieren, und vielleicht auch einfach herausfinden, wieso man bei negativen Zahlen so viele 1-Bits links anflanschen kann, wie man möchte.