Wie ich Daten in einem unbekannten Format von Magnetband wiederherstellte

Vorgeschichte

Da ich ein Liebhaber von Retro-Hardware bin, habe ich einmal einen ZX Spectrum+ von einem Verkäufer in Großbritannien gekauft. Im Lieferumfang des Computers selbst habe ich mehrere Audiokassetten mit Spielen (in der Originalverpackung mit Anleitung) sowie auf Kassetten aufgenommene Programme ohne besondere Kennzeichnung erhalten. Überraschenderweise waren die Daten von 40 Jahre alten Kassetten gut lesbar und ich konnte fast alle Spiele und Programme von ihnen herunterladen.

Wie ich Daten in einem unbekannten Format von Magnetband wiederherstellte

Allerdings habe ich auf einigen Kassetten Aufnahmen gefunden, die eindeutig nicht vom ZX Spectrum-Computer stammen. Sie klangen völlig anders und starteten im Gegensatz zu den Aufnahmen vom genannten Computer nicht mit einem kurzen BASIC-Bootloader, der normalerweise in den Aufnahmen aller Programme und Spiele vorhanden ist.

Das verfolgte mich schon seit einiger Zeit – ich wollte unbedingt herausfinden, was sich in ihnen verbirgt. Wenn Sie das Audiosignal als Folge von Bytes lesen könnten, könnten Sie nach Zeichen oder irgendetwas suchen, das den Ursprung des Signals anzeigt. Eine Art Retro-Archäologie.

Jetzt, wo ich mir die Etiketten auf den Kassetten selbst angeschaut habe, muss ich lächeln

Die Antwort lag die ganze Zeit direkt vor meinen Augen
Auf dem Etikett der linken Kassette steht der Name des TRS-80-Computers und direkt darunter der Name des Herstellers: „Hergestellt von Radio Shack in den USA“.

(Wenn Sie die Intrige bis zum Ende behalten möchten, verraten Sie sich nicht den Spoiler)

Vergleich von Audiosignalen

Lassen Sie uns zunächst die Audioaufnahmen digitalisieren. Sie können sich anhören, wie es klingt:


Und wie immer klingt die Aufnahme vom ZX Spectrum-Computer:


In beiden Fällen steht zu Beginn der Aufnahme ein sogenannter Pilotton - ein Ton der gleichen Frequenz (in der ersten Aufnahme ist er sehr kurz <1 Sekunde, aber unterscheidbar). Der Pilotton signalisiert dem Computer, sich auf den Datenempfang vorzubereiten. In der Regel erkennt jeder Computer nur seinen „eigenen“ Pilotton an der Form des Signals und seiner Frequenz.

Es ist notwendig, etwas über die Signalform selbst zu sagen. Beim ZX Spectrum ist die Form beispielsweise rechteckig:

Wie ich Daten in einem unbekannten Format von Magnetband wiederherstellte

Wenn ein Pilotton erkannt wird, zeigt der ZX Spectrum abwechselnd rote und blaue Balken am Bildschirmrand an, um anzuzeigen, dass das Signal erkannt wurde. Der Pilotton endet Synchronimpuls, was dem Computer signalisiert, mit dem Datenempfang zu beginnen. Es zeichnet sich durch eine kürzere Dauer aus (im Vergleich zum Pilotton und den nachfolgenden Daten) (siehe Abbildung)

Nachdem der Synchronimpuls empfangen wurde, zeichnet der Computer jeden Anstieg/Abfall des Signals auf und misst dessen Dauer. Wenn die Dauer kleiner als ein bestimmter Grenzwert ist, wird Bit 1 in den Speicher geschrieben, andernfalls 0. Die Bits werden in Bytes zusammengefasst und der Vorgang wird wiederholt, bis N Bytes empfangen werden. Die Nummer N wird normalerweise aus dem Header der heruntergeladenen Datei entnommen. Die Ladesequenz ist wie folgt:

  1. Pilotton
  2. Header (feste Länge), enthält die Größe der heruntergeladenen Daten (N), Dateinamen und Typ
  3. Pilotton
  4. die Daten selbst

Um sicherzustellen, dass die Daten korrekt geladen werden, liest der ZX Spectrum die sogenannten Paritätsbyte (Paritätsbyte), das beim Speichern einer Datei durch XOR-Verknüpfung aller Bytes der geschriebenen Daten berechnet wird. Beim Lesen einer Datei berechnet der Computer das Paritätsbyte aus den empfangenen Daten und zeigt bei Abweichung vom gespeicherten Ergebnis die Fehlermeldung „R-Band-Ladefehler“ an. Streng genommen kann der Computer diese Meldung früher ausgeben, wenn er beim Lesen einen Puls nicht erkennen kann (fehlt oder seine Dauer nicht bestimmten Grenzwerten entspricht).

Sehen wir uns nun an, wie ein unbekanntes Signal aussieht:

Wie ich Daten in einem unbekannten Format von Magnetband wiederherstellte

Dies ist der Pilotton. Die Form des Signals unterscheidet sich erheblich, aber es ist klar, dass das Signal aus sich wiederholenden kurzen Impulsen einer bestimmten Frequenz besteht. Bei einer Abtastfrequenz von 44100 Hz beträgt der Abstand zwischen den „Peaks“ etwa 48 Abtastwerte (was einer Frequenz von ~918 Hz entspricht). Merken wir uns diese Zahl.

Schauen wir uns nun das Datenfragment an:

Wie ich Daten in einem unbekannten Format von Magnetband wiederherstellte

Wenn wir den Abstand zwischen einzelnen Impulsen messen, stellt sich heraus, dass der Abstand zwischen „langen“ Impulsen immer noch ~48 Samples und zwischen kurzen – ~24 beträgt. Mit etwas Blick in die Zukunft möchte ich sagen, dass sich am Ende herausstellte, dass vom Anfang bis zum Ende der Datei kontinuierlich „Referenz“-Impulse mit einer Frequenz von 918 Hz folgen. Es kann davon ausgegangen werden, dass wir bei der Datenübertragung einen zusätzlichen Impuls zwischen den Referenzimpulsen als Bit 1 betrachten, andernfalls als 0.

Was ist mit dem Synchronisationsimpuls? Schauen wir uns den Anfang der Daten an:

Wie ich Daten in einem unbekannten Format von Magnetband wiederherstellte

Der Pilotton endet und die Daten beginnen sofort. Wenig später konnten wir nach der Analyse verschiedener Audioaufnahmen feststellen, dass das erste Datenbyte immer dasselbe ist (10100101b, A5h). Der Computer beginnt möglicherweise mit dem Lesen von Daten, nachdem er diese empfangen hat.

Sie können auch auf die Verschiebung des ersten Referenzimpulses unmittelbar nach dem letzten 1. im Sync-Byte achten. Es wurde viel später bei der Entwicklung eines Datenerkennungsprogramms entdeckt, als die Daten am Anfang der Datei nicht stabil gelesen werden konnten.

Versuchen wir nun, einen Algorithmus zu beschreiben, der eine Audiodatei verarbeitet und Daten lädt.

Daten werden geladen

Schauen wir uns zunächst einige Annahmen an, um den Algorithmus einfach zu halten:

  1. Wir berücksichtigen nur Dateien im WAV-Format;
  2. Die Audiodatei muss mit einem Pilotton beginnen und darf am Anfang keine Stille enthalten
  3. Die Quelldatei muss eine Abtastrate von 44100 Hz haben. In diesem Fall ist der Abstand zwischen den Referenzimpulsen von 48 Proben bereits bestimmt und wir müssen ihn nicht programmgesteuert berechnen;
  4. Das Beispielformat kann beliebig sein (8/16 Bit/Gleitkomma) – da wir es beim Lesen in das gewünschte Format konvertieren können;
  5. Wir gehen davon aus, dass die Quelldatei nach der Amplitude normalisiert ist, was das Ergebnis stabilisieren sollte;

Der Lesealgorithmus sieht wie folgt aus:

  1. Wir lesen die Datei in den Speicher ein und konvertieren gleichzeitig das Beispielformat in 8 Bit;
  2. Bestimmen Sie die Position des ersten Impulses in den Audiodaten. Dazu müssen Sie die Anzahl der Proben mit der maximalen Amplitude berechnen. Der Einfachheit halber berechnen wir es einmal manuell. Speichern wir es in der Variablen prev_pos.
  3. Addiere 48 zur Position des letzten Impulses (pos := prev_pos + 48)
  4. Da eine Erhöhung der Position um 48 nicht garantiert, dass wir die Position des nächsten Referenzimpulses erreichen (Banddefekte, instabiler Betrieb des Bandlaufwerks usw.), müssen wir die Position des Pos-Impulses anpassen. Nehmen Sie dazu ein kleines Datenstück (pos-8; pos+8) und ermitteln Sie darauf den maximalen Amplitudenwert. Die dem Maximum entsprechende Position wird in pos gespeichert. Hier ist 8 = 48/6 eine experimentell ermittelte Konstante, die garantiert, dass wir das richtige Maximum bestimmen und andere Impulse, die sich möglicherweise in der Nähe befinden, nicht beeinflussen. In sehr schlimmen Fällen, wenn der Abstand zwischen den Impulsen viel kleiner oder größer als 48 ist, können Sie eine erzwungene Suche nach einem Impuls implementieren, aber im Rahmen des Artikels werde ich dies im Algorithmus nicht beschreiben;
  5. Im vorherigen Schritt müsste außerdem überprüft werden, ob der Referenzimpuls überhaupt gefunden wurde. Das heißt, wenn Sie einfach nach dem Maximum suchen, ist dies keine Garantie dafür, dass der Impuls in diesem Segment vorhanden ist. In meiner neuesten Implementierung des Leseprogramms überprüfe ich die Differenz zwischen den maximalen und minimalen Amplitudenwerten eines Segments und zähle, wenn sie einen bestimmten Grenzwert überschreitet, das Vorhandensein eines Impulses. Es stellt sich auch die Frage, was zu tun ist, wenn der Referenzimpuls nicht gefunden wird. Es gibt zwei Möglichkeiten: Entweder sind die Daten beendet und es folgt Stille, oder es handelt sich um einen Lesefehler. Wir werden dies jedoch weglassen, um den Algorithmus zu vereinfachen.
  6. Im nächsten Schritt müssen wir das Vorhandensein eines Datenimpulses (Bit 0 oder 1) feststellen, dazu nehmen wir die Mitte des Segments (prev_pos;pos) middle_pos gleich middle_pos := (prev_pos+pos)/2 und Berechnen wir in einer Nachbarschaft middle_pos auf dem Segment (middle_pos-8;middle_pos +8) die maximale und minimale Amplitude. Wenn die Differenz mehr als 10 beträgt, schreiben wir Bit 1 in das Ergebnis, andernfalls 0. 10 ist eine experimentell ermittelte Konstante;
  7. Speichern Sie die aktuelle Position in prev_pos (prev_pos := pos)
  8. Wiederholen Sie den Vorgang ab Schritt 3, bis wir die gesamte Datei gelesen haben.
  9. Das resultierende Bit-Array muss als Satz von Bytes gespeichert werden. Da wir beim Lesen das Sync-Byte nicht berücksichtigt haben, darf die Anzahl der Bits kein Vielfaches von 8 sein und auch der erforderliche Bit-Offset ist unbekannt. Bei der ersten Implementierung des Algorithmus wusste ich nichts von der Existenz des Sync-Bytes und habe daher einfach 8 Dateien mit unterschiedlich vielen Offset-Bits gespeichert. Einer davon enthielt korrekte Daten. Im endgültigen Algorithmus entferne ich einfach alle Bits bis A5h, wodurch ich sofort die richtige Ausgabedatei erhalte

Algorithmus in Ruby für Interessierte
Ich habe Ruby als Sprache zum Schreiben des Programms gewählt, weil... Ich programmiere die meiste Zeit darauf. Die Option ist nicht leistungsstark, aber die Aufgabe, die Lesegeschwindigkeit so schnell wie möglich zu machen, lohnt sich nicht.

# Используем gem 'wavefile'
require 'wavefile'

reader = WaveFile::Reader.new('input.wav')
samples = []
format = WaveFile::Format.new(:mono, :pcm_8, 44100)

# Читаем WAV файл, конвертируем в формат Mono, 8 bit 
# Массив samples будет состоять из байт со значениями 0-255
reader.each_buffer(10000) do |buffer|
  samples += buffer.convert(format).samples
end

# Позиция первого импульса (вместо 0)
prev_pos = 0
# Расстояние между импульсами
distance = 48
# Значение расстояния для окрестности поиска локального максимума
delta = (distance / 6).floor
# Биты будем сохранять в виде строки из "0" и "1"
bits = ""

loop do
  # Рассчитываем позицию следующего импульса
  pos = prev_pos + distance
  
  # Выходим из цикла если данные закончились 
  break if pos + delta >= samples.size

  # Корректируем позицию pos обнаружением максимума на отрезке [pos - delta;pos + delta]
  (pos - delta..pos + delta).each { |p| pos = p if samples[p] > samples[pos] }

  # Находим середину отрезка [prev_pos;pos]
  middle_pos = ((prev_pos + pos) / 2).floor

  # Берем окрестность в середине 
  sample = samples[middle_pos - delta..middle_pos + delta]

  # Определяем бит как "1" если разница между максимальным и минимальным значением на отрезке превышает 10
  bit = sample.max - sample.min > 10
  bits += bit ? "1" : "0"
end

# Определяем синхро-байт и заменяем все предшествующие биты на 256 бит нулей (согласно спецификации формата) 
bits.gsub! /^[01]*?10100101/, ("0" * 256) + "10100101"

# Сохраняем выходной файл, упаковывая биты в байты
File.write "output.cas", [bits].pack("B*")

Erlebe die Kraft effektiver Ergebnisse

Nachdem ich mehrere Varianten des Algorithmus und der Konstanten ausprobiert hatte, hatte ich das Glück, etwas äußerst Interessantes zu erhalten:

Wie ich Daten in einem unbekannten Format von Magnetband wiederherstellte

Den Zeichenketten nach zu urteilen haben wir also ein Programm zum Zeichnen von Diagrammen. Der Programmtext enthält jedoch keine Schlüsselwörter. Alle Schlüsselwörter werden als Bytes kodiert (jeder Wert > 80h). Jetzt müssen wir herausfinden, welcher Computer aus den 80er Jahren Programme in diesem Format speichern konnte.

Tatsächlich ist es einem BASIC-Programm sehr ähnlich. Der ZX Spectrum-Computer speichert Programme in ungefähr demselben Format im Speicher und speichert Programme auf Band. Für alle Fälle habe ich die Schlüsselwörter überprüft Tisch. Allerdings war das Ergebnis offensichtlich negativ.

Ich habe auch die BASIC-Schlüsselwörter des beliebten Atari, Commodore 64 und mehrerer anderer Computer dieser Zeit überprüft, für die ich Dokumentation finden konnte, jedoch ohne Erfolg – ​​mein Wissen über die Arten von Retro-Computern erwies sich als nicht so umfassend.

Dann beschloss ich zu gehen Die Liste, und dann fiel mein Blick auf den Namen des Herstellers Radio Shack und den Computer TRS-80. Das sind die Namen, die auf den Etiketten der Kassetten standen, die auf meinem Tisch lagen! Ich kannte diese Namen vorher nicht und war mit dem TRS-80-Computer nicht vertraut, daher schien es mir, dass Radio Shack ein Hersteller von Audiokassetten wie BASF, Sony oder TDK war und der TRS-80 die Wiedergabezeit war. Warum nicht?

Computer Tandy/Radio Shack TRS-80

Es ist sehr wahrscheinlich, dass die betreffende Audioaufnahme, die ich am Anfang des Artikels als Beispiel angegeben habe, auf einem Computer wie diesem erstellt wurde:

Wie ich Daten in einem unbekannten Format von Magnetband wiederherstellte

Es stellte sich heraus, dass dieser Computer und seine Varianten (Modell I/Modell III/Modell IV usw.) einst sehr beliebt waren (natürlich nicht in Russland). Bemerkenswert ist, dass der verwendete Prozessor ebenfalls Z80 war. Für diesen Computer können Sie im Internet finden viel Information. In den 80er Jahren wurden Computerinformationen verbreitet Zeitschriften. Im Moment gibt es mehrere Emulatoren Computer für verschiedene Plattformen.

Ich habe den Emulator heruntergeladen trs80gp und zum ersten Mal konnte ich sehen, wie dieser Computer funktionierte. Natürlich unterstützte der Computer keine Farbausgabe; die Bildschirmauflösung betrug nur 128 x 48 Pixel, aber es gab viele Erweiterungen und Modifikationen, die die Bildschirmauflösung erhöhen konnten. Es gab auch viele Optionen für Betriebssysteme für diesen Computer und Optionen zur Implementierung der BASIC-Sprache (die im Gegensatz zum ZX Spectrum bei einigen Modellen nicht einmal ins ROM „geflasht“ wurde und jede Option einfach von einer Diskette geladen werden konnte das Betriebssystem selbst)

Habe ich auch gefunden Nützlichkeit um Audioaufnahmen in das von Emulatoren unterstützte CAS-Format zu konvertieren, aber aus irgendeinem Grund war es nicht möglich, damit Aufnahmen von meinen Kassetten zu lesen.

Nachdem ich das CAS-Dateiformat herausgefunden hatte (es stellte sich heraus, dass es sich nur um eine Bit-für-Bit-Kopie der Daten vom Band handelte, die ich bereits zur Hand hatte, mit Ausnahme des Headers mit dem Vorhandensein eines Synchronisierungsbytes), erstellte ich eine Ich habe einige Änderungen an meinem Programm vorgenommen und konnte eine funktionierende CAS-Datei ausgeben, die im Emulator (TRS-80 Modell III) funktionierte:

Wie ich Daten in einem unbekannten Format von Magnetband wiederherstellte

Die neueste Version des Konvertierungsdienstprogramms mit automatischer Bestimmung des ersten Impulses und des Abstands zwischen Referenzimpulsen habe ich als GEM-Paket entworfen, der Quellcode ist verfügbar unter Github.

Abschluss

Der Weg, den wir gegangen sind, erwies sich als eine faszinierende Reise in die Vergangenheit, und ich bin froh, dass ich am Ende die Antwort gefunden habe. Unter anderem:

  • Ich habe das Format zum Speichern von Daten im ZX Spectrum herausgefunden und die integrierten ROM-Routinen zum Speichern/Lesen von Daten von Audiokassetten studiert
  • Ich habe mich mit dem TRS-80-Computer und seinen Varianten vertraut gemacht, das Betriebssystem studiert, Beispielprogramme angeschaut und hatte sogar die Möglichkeit, Maschinencodes zu debuggen (schließlich sind mir alle Z80-Mnemoniken bekannt).
  • Ich habe ein vollwertiges Dienstprogramm zum Konvertieren von Audioaufnahmen in das CAS-Format geschrieben, das Daten lesen kann, die vom „offiziellen“ Dienstprogramm nicht erkannt werden

Source: habr.com

Kommentar hinzufügen